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
|
||||
from pathlib import Path
|
||||
|
||||
from PySide6.QtCore import QSettings, Qt, QThread, QTimer, Signal
|
||||
from PySide6.QtGui import QAction, QColor, QGuiApplication
|
||||
from PySide6.QtCore import QRect, QSettings, QSize, Qt, QThread, QTimer, Signal
|
||||
from PySide6.QtGui import QAction, QColor, QGuiApplication, QPainter
|
||||
from PySide6.QtWidgets import (
|
||||
QAbstractItemView,
|
||||
QApplication,
|
||||
@@ -361,14 +361,11 @@ class ServerEditor(QFrame):
|
||||
self.command.textChanged.connect(self._emit)
|
||||
v.addWidget(self.command)
|
||||
v.addWidget(self._lbl("Arguments (one per line)"))
|
||||
self.args = QPlainTextEdit()
|
||||
self.args = ArgsEdit()
|
||||
self.args.setPlaceholderText(
|
||||
"-y\n@modelcontextprotocol/server-filesystem\n/Users/you/Documents"
|
||||
)
|
||||
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)
|
||||
v.addWidget(self.args, 1)
|
||||
v.addWidget(self._lbl("Environment variables"))
|
||||
@@ -565,6 +562,76 @@ class ServerEditor(QFrame):
|
||||
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
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
Reference in New Issue
Block a user