Repository: spyder-ide/spyder

Issue:
The linenumber is not displayed properly
## Description

### What steps will reproduce the problem?

<!--- You can use Markdown here --->
![스크린샷, 2022-02-09 21-19-44](https://user-images.githubusercontent.com/22970578/153200085-da596a42-49a2-4327-8374-7db0641e7754.png)

Hello!

Thank you for your efforts to speed up the editor.
However, The line number does not seem to be displayed normally in the latest version.

Please check it out.
Have a good day.



## Versions

* Spyder version: 5.3.0.dev0 15926c5e1
* Python version: 3.9.7
* Qt version: 5.12.9
* PyQt5 version: 5.12.3
* Operating System: Linux 5.4.0-97-generic

### Dependencies

```
# Mandatory:
atomicwrites >=1.2.0                  :  1.4.0 (OK)
chardet >=2.0.0                       :  4.0.0 (OK)
cloudpickle >=0.5.0                   :  2.0.0 (OK)
cookiecutter >=1.6.0                  :  1.7.2 (OK)
diff_match_patch >=20181111           :  20200713 (OK)
intervaltree >=3.0.2                  :  3.1.0 (OK)
IPython >=7.6.0;<8.0.0                :  7.31.1 (OK)
jedi >=0.17.2;<0.19.0                 :  0.18.1 (OK)
jellyfish >=0.7                       :  0.8.9 (OK)
jsonschema >=3.2.0                    :  3.2.0 (OK)
keyring >=17.0.0                      :  23.4.0 (OK)
nbconvert >=4.0                       :  6.3.0 (OK)
numpydoc >=0.6.0                      :  1.2 (OK)
parso >=0.7.0;<0.9.0                  :  0.8.3 (OK)
pexpect >=4.4.0                       :  4.8.0 (OK)
pickleshare >=0.4                     :  0.7.5 (OK)
psutil >=5.3                          :  5.8.0 (OK)
pygments >=2.0                        :  2.10.0 (OK)
pylint >=2.5.0                        :  2.12.2 (OK)
pyls_spyder >=0.4.0                   :  0.4.0 (OK)
pylsp >=1.3.2;<1.4.0                  :  1.4.0.dev0 (OK)
pylsp_black >=1.0.0                   :  1.0.0 (OK)
qdarkstyle =3.0.2                     :  3.0.2 (OK)
qstylizer >=0.1.10                    :  0.1.10 (OK)
qtawesome >=1.0.2                     :  1.0.3 (OK)
qtconsole >=5.2.1;<5.3.0              :  5.2.1 (OK)
qtpy >=1.5.0                          :  1.11.2 (OK)
rtree >=0.9.7                         :  0.9.7 (OK)
setuptools >=49.6.0                   :  58.0.4 (OK)
sphinx >=0.6.6                        :  4.4.0 (OK)
spyder_kernels >=2.2.1;<2.3.0         :  2.3.0.dev0 (OK)
textdistance >=4.2.0                  :  4.2.1 (OK)
three_merge >=0.1.1                   :  0.1.1 (OK)
watchdog >=0.10.3                     :  2.1.6 (OK)
xdg >=0.26                            :  0.27 (OK)
zmq >=17                              :  22.3.0 (OK)

# Optional:
cython >=0.21                         :  0.29.25 (OK)
matplotlib >=2.0.0                    :  3.5.0 (OK)
numpy >=1.7                           :  1.20.3 (OK)
pandas >=1.1.1                        :  1.3.5 (OK)
scipy >=0.17.0                        :  1.7.3 (OK)
sympy >=0.7.3                         :  1.9 (OK)

# Spyder plugins:
spyder_okvim.spyder.plugin 0.0.1.dev0 :  0.0.1-dev0 (OK)
```



Discussion:
Hey @ok97465, thanks for reporting! I can confirm this problem on Linux and I was about to report it.

@impact27, could you take a look at it? It seems the computations to determine line height are a bit off on Linux.

@dalthviz, could you post a screenshot of what do you see on Windows?
This is what I'm seeing on Windows (seems like the line numbers are aligned there):

![imagen](https://user-images.githubusercontent.com/16781833/153274367-dfec0424-e209-4925-9648-9b753640a6ae.png)

![imagen](https://user-images.githubusercontent.com/16781833/153274694-0de448ac-039c-4f5c-9623-e5411a1c0b01.png)

@dalthviz, could you put the cursor in a given line (not in the first ten) and upload another screenshot? I think the problem is with the current line.
![imagen](https://user-images.githubusercontent.com/16781833/153298150-2052f48b-4d33-4cd8-8f5f-7efddb3fb6f0.png)

Thanks @dalthviz! So things on Windows are working just fine.

@steff456, could post a similar screenshot on macOS?
On mac:
<img width="97" alt="Screenshot 2022-02-10 at 07 59 13" src="https://user-images.githubusercontent.com/6740194/153354374-c39458e7-303f-45ab-92b7-5943563c031c.png">

If you zoom in and out, does it fix it?
The font size appears to be the same. I think the issue is with the line spacing:
![2](https://user-images.githubusercontent.com/6740194/153356062-9c1c3d12-ee6b-4076-8c60-8efd4ea227f0.png)

You can check the height and leading by adding in `LineNumberArea::draw_linenumbers` below `font.setWeight(font.Normal)`:
```
from qtpy.QtGui import QFontMetricsF
fm = QFontMetricsF(font)
print(fm.lineSpacing(), fm.height(), fm.leading())
```
On mac I get `12.796875 12.796875 0.0`. Maybe the css sheet on linux adds 2px of leading to the editor?
There is a problem however that I can not find a way of adjusting the line spacing for QStaticText (see https://bugreports.qt.io/browse/QTBUG-3545).

Maybe using `QTextDocument.drawContents` would be more reliable? But this should be profiled.
Could you try: https://github.com/spyder-ide/spyder/pull/17321
```python
from qtpy.QtGui import QFontMetricsF
fm = QFontMetricsF(font)
print(fm.lineSpacing(), fm.height(), fm.leading())
````
The result of code is 16.0, 17.0, -1.0.


The font is supposed to be the same. I tried to match the stylesheet as that might affect the line spacing.
> Could you try: #17321

I'm sorry but the result of #17321 is the same.
> I'm sorry but the result of #17321 is the same.

Thanks for checking! What if you change the font? Maybe there is an issue with negative leading? Could you select a font without negative leading?
> 

You're right. Linenumber is working well when using some font. But It is not working when I use "JetBrains Mono", "Ubuntu mono", "Fira Mono".
From the picture above, the baseline to baseline disctance of the line number is 32px (=2 * 16) while the baseline to baseline distance of the text is 34px ( = 2 * 17). So it looks like the editor is somehow not respecting the leading of the font? One solution could be to remove the optimisation when the leading is negative. The editor will be slower but at least the line numbers will be aligned.

Resolving patch:
diff --git a/spyder/plugins/editor/panels/linenumber.py b/spyder/plugins/editor/panels/linenumber.py
--- a/spyder/plugins/editor/panels/linenumber.py
+++ b/spyder/plugins/editor/panels/linenumber.py
@@ -14,7 +14,7 @@
 
 # Third party imports
 from qtpy.QtCore import QSize, Qt, QPointF
-from qtpy.QtGui import QPainter, QColor, QStaticText
+from qtpy.QtGui import QPainter, QColor, QStaticText, QFontMetricsF
 
 # Local imports
 from spyder.utils.icon_manager import ima
@@ -86,7 +86,15 @@ def draw_pixmap(xleft, ytop, pixmap):
         icon_size = QSize(size, size)
 
         if self._margin:
-            self.draw_linenumbers(painter)
+            font = self.editor.font()
+            fm = QFontMetricsF(font)
+            if fm.leading() == 0:
+                self.draw_linenumbers(painter)
+            else:
+                # The editor doesn't care about leading, so each line
+                # must be drawn independently.
+                self.draw_linenumbers_slow(painter)
+
         for top, line_number, block in self.editor.visible_blocks:
             data = block.userData()
             if self._markers_margin and data:
@@ -145,7 +153,7 @@ def draw_linenumbers(self, painter):
         painter.setPen(self.linenumbers_color)
 
         if self.logicalDpiX() != self._static_text_dpi:
-            self._static_text_dpi = None
+            self._static_text_dpi = self.logicalDpiX()
             self._static_line_numbers = None
             self._static_active_line = None
 
@@ -155,7 +163,6 @@ def draw_linenumbers(self, painter):
         else:
             self._static_line_numbers = QStaticText(lines)
             self._static_line_numbers.prepare(font=font)
-            self._static_text_dpi = self.logicalDpiX()
 
         top = self.editor.visible_blocks[0][0]
         left = width - self._static_line_numbers.size().width()
@@ -190,6 +197,32 @@ def draw_linenumbers(self, painter):
             painter.drawStaticText(
                 QPointF(left, active_top), self._static_active_line)
 
+    def draw_linenumbers_slow(self, painter):
+        """
+        Slower way (2x) to draw line numbers.
+
+        This is necessary for some fonts.
+        """
+        font = self.editor.font()
+        font_height = self.editor.fontMetrics().height()
+        active_block = self.editor.textCursor().block()
+        active_line_number = active_block.blockNumber() + 1
+        for top, line_number, block in self.editor.visible_blocks:
+            if self._margin:
+                if line_number == active_line_number:
+                    font.setWeight(font.Bold)
+                    painter.setFont(font)
+                    painter.setPen(self.editor.normal_color)
+                else:
+                    font.setWeight(font.Normal)
+                    painter.setFont(font)
+                    painter.setPen(self.linenumbers_color)
+
+                painter.drawText(0, top, self.width(),
+                                 font_height,
+                                 int(Qt.AlignRight | Qt.AlignBottom),
+                                 str(line_number))
+
     def leaveEvent(self, event):
         """Override Qt method."""
         self.editor.hide_tooltip()


Test patch: