feat: numbered gutter in the Arguments editor
The one-arg-per-line model read as odd text wrapping — a path on its own line looked like a wrapped continuation of the previous argument. A line-number gutter makes each argument visibly its own item. ArgsEdit also owns the NoWrap setting now.
This commit is contained in:
@@ -13,8 +13,8 @@ from __future__ import annotations
|
|||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from PySide6.QtCore import QSettings, Qt, QThread, QTimer, Signal
|
from PySide6.QtCore import QRect, QSettings, QSize, Qt, QThread, QTimer, Signal
|
||||||
from PySide6.QtGui import QAction, QColor, QGuiApplication
|
from PySide6.QtGui import QAction, QColor, QGuiApplication, QPainter
|
||||||
from PySide6.QtWidgets import (
|
from PySide6.QtWidgets import (
|
||||||
QAbstractItemView,
|
QAbstractItemView,
|
||||||
QApplication,
|
QApplication,
|
||||||
@@ -361,14 +361,11 @@ class ServerEditor(QFrame):
|
|||||||
self.command.textChanged.connect(self._emit)
|
self.command.textChanged.connect(self._emit)
|
||||||
v.addWidget(self.command)
|
v.addWidget(self.command)
|
||||||
v.addWidget(self._lbl("Arguments (one per line)"))
|
v.addWidget(self._lbl("Arguments (one per line)"))
|
||||||
self.args = QPlainTextEdit()
|
self.args = ArgsEdit()
|
||||||
self.args.setPlaceholderText(
|
self.args.setPlaceholderText(
|
||||||
"-y\n@modelcontextprotocol/server-filesystem\n/Users/you/Documents"
|
"-y\n@modelcontextprotocol/server-filesystem\n/Users/you/Documents"
|
||||||
)
|
)
|
||||||
self.args.setMinimumHeight(70)
|
self.args.setMinimumHeight(70)
|
||||||
# One argument per line means wrapping is actively misleading — a long
|
|
||||||
# path that soft-wraps looks like two separate args. Scroll instead.
|
|
||||||
self.args.setLineWrapMode(QPlainTextEdit.LineWrapMode.NoWrap)
|
|
||||||
self.args.textChanged.connect(self._emit)
|
self.args.textChanged.connect(self._emit)
|
||||||
v.addWidget(self.args, 1)
|
v.addWidget(self.args, 1)
|
||||||
v.addWidget(self._lbl("Environment variables"))
|
v.addWidget(self._lbl("Environment variables"))
|
||||||
@@ -565,6 +562,76 @@ class ServerEditor(QFrame):
|
|||||||
self.dep_label.setStyleSheet(f"color: {color};")
|
self.dep_label.setStyleSheet(f"color: {color};")
|
||||||
|
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Arguments editor: one line = one argument, with a numbered gutter so that
|
||||||
|
# model is visible (a long path on its own line reads as "arg 2", not as a
|
||||||
|
# wrapped continuation of arg 1).
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
class _ArgsGutter(QWidget):
|
||||||
|
def __init__(self, editor: ArgsEdit):
|
||||||
|
super().__init__(editor)
|
||||||
|
self._editor = editor
|
||||||
|
|
||||||
|
def sizeHint(self):
|
||||||
|
return QSize(self._editor.gutter_width(), 0)
|
||||||
|
|
||||||
|
def paintEvent(self, event):
|
||||||
|
self._editor.gutter_paint(event)
|
||||||
|
|
||||||
|
|
||||||
|
class ArgsEdit(QPlainTextEdit):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.setLineWrapMode(QPlainTextEdit.LineWrapMode.NoWrap)
|
||||||
|
self._gutter = _ArgsGutter(self)
|
||||||
|
self.blockCountChanged.connect(self._update_gutter_width)
|
||||||
|
self.updateRequest.connect(self._on_update_request)
|
||||||
|
self._update_gutter_width()
|
||||||
|
|
||||||
|
def gutter_width(self) -> int:
|
||||||
|
digits = max(1, len(str(self.blockCount())))
|
||||||
|
return 14 + self.fontMetrics().horizontalAdvance("9") * digits
|
||||||
|
|
||||||
|
def _update_gutter_width(self, *_):
|
||||||
|
self.setViewportMargins(self.gutter_width(), 0, 0, 0)
|
||||||
|
|
||||||
|
def _on_update_request(self, rect, dy):
|
||||||
|
if dy:
|
||||||
|
self._gutter.scroll(0, dy)
|
||||||
|
else:
|
||||||
|
self._gutter.update(0, rect.y(), self._gutter.width(), rect.height())
|
||||||
|
if rect.contains(self.viewport().rect()):
|
||||||
|
self._update_gutter_width()
|
||||||
|
|
||||||
|
def resizeEvent(self, e):
|
||||||
|
super().resizeEvent(e)
|
||||||
|
cr = self.contentsRect()
|
||||||
|
self._gutter.setGeometry(QRect(cr.left(), cr.top(), self.gutter_width(), cr.height()))
|
||||||
|
|
||||||
|
def gutter_paint(self, event):
|
||||||
|
painter = QPainter(self._gutter)
|
||||||
|
painter.setPen(QColor(MUTED))
|
||||||
|
fm = self.fontMetrics()
|
||||||
|
block = self.firstVisibleBlock()
|
||||||
|
n = block.blockNumber()
|
||||||
|
top = round(self.blockBoundingGeometry(block).translated(self.contentOffset()).top())
|
||||||
|
bottom = top + round(self.blockBoundingRect(block).height())
|
||||||
|
while block.isValid() and top <= event.rect().bottom():
|
||||||
|
if block.isVisible() and bottom >= event.rect().top():
|
||||||
|
painter.drawText(
|
||||||
|
0,
|
||||||
|
top,
|
||||||
|
self._gutter.width() - 8,
|
||||||
|
fm.height(),
|
||||||
|
Qt.AlignmentFlag.AlignRight,
|
||||||
|
str(n + 1),
|
||||||
|
)
|
||||||
|
block = block.next()
|
||||||
|
top = bottom
|
||||||
|
bottom = top + round(self.blockBoundingRect(block).height())
|
||||||
|
n += 1
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------- #
|
# --------------------------------------------------------------------------- #
|
||||||
# Paste-JSON dialog
|
# Paste-JSON dialog
|
||||||
# --------------------------------------------------------------------------- #
|
# --------------------------------------------------------------------------- #
|
||||||
|
|||||||
Reference in New Issue
Block a user