Skip to content

Commit 211e17c

Browse files
committed
fix(editor): fix bracket matching at EOF and case-insensitive auto-completion replacement
1 parent 3bdaa95 commit 211e17c

3 files changed

Lines changed: 31 additions & 8 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ Format basiert auf [Keep a Changelog](https://keepachangelog.com/de/1.1.0/).
2929

3030
### Behoben
3131

32+
- `core/editor.py`: Behoben: (1) Bracket-Matching am Dokumentende (EOF) filterte Cursortyp bei `pos == len(text)` aus, wodurch schließende Klammern am Dateiende nicht hervorgehoben wurden. (2) `insert_completion()` ersetzte bei case-insensitiver Auto-Completion oder Wort-Ersetzung bisher nur Suffix-Texte statt das Präfix-Wort exakt zu ersetzen. 2 neue Regressionstests in `tests/test_editor_auto_close.py`.
33+
- `features/git_integration.py`: `GitRepo.get_status()` entpackt jetzt von Git zitiere Pfade (z. B. bei Dateinamen mit Leerzeichen oder Sonderzeichen) und umbenannte Pfade (`"old.py" -> "new.py"`) via `parse_porcelain_path()`. Zudem werden C-Style Escape-Sequenzen unescaped und `errors="replace"` bei Subprocess-Output genutzt. Git-Status-Badges in `ProjectView` funktionieren dadurch auch bei Pfaden mit Leerzeichen oder Sonderzeichen. 3 neue Regressionstests in `tests/test_git_status_parsing.py`.
3234
- `features/remote_editor.py`: SSH/SFTP-Verbindungen laden bekannte Hostkeys und
3335
lehnen unbekannte Hostkeys jetzt ab, statt sie automatisch zu akzeptieren.
3436
- `features/terminal.py` (B-012): `_start_shell()` trennte die Signale
@@ -58,6 +60,9 @@ Format basiert auf [Keep a Changelog](https://keepachangelog.com/de/1.1.0/).
5860
- `stale.yml` hinzugefügt: Issues und PRs werden nach 30 Tagen als stale markiert und nach 37 Tagen automatisch geschlossen.
5961

6062
### Dokumentation
63+
- `THIRD_PARTY_LICENSES.txt` ergänzt die direkte Runtime-Lizenzinventur für
64+
`PySide6` und das transitive Qt-for-Python-Wheel-Set; ein Guard-Test schützt
65+
das Inventar gegen Dependency-Drift.
6166
- `README.md` als klaren englischen Einstieg mit Start-Here-Tabelle,
6267
Screenshot-Alt-Text und Suchabgrenzung neu strukturiert; `README_de.md` als
6368
deutsche Einstiegsseite ergänzt. `llms.txt` auf den Marketing-Check vom

core/editor.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,19 +98,17 @@ def set_provider(self, provider):
9898
self.set_completer_words(words)
9999

100100
def insert_completion(self, completion: str):
101-
tc = self.textCursor()
102-
extra = len(completion) - len(self.completer.completionPrefix())
103-
if extra <= 0:
101+
if not completion:
104102
return
103+
tc = self.textCursor()
105104
tc.movePosition(QTextCursor.MoveOperation.Left)
106105
tc.movePosition(QTextCursor.MoveOperation.EndOfWord)
107-
# Snippet-Prüfung
106+
tc.movePosition(QTextCursor.MoveOperation.StartOfWord, QTextCursor.MoveMode.KeepAnchor)
107+
tc.removeSelectedText()
108108
if self._provider and completion in self._provider.get_snippets():
109-
tc.movePosition(QTextCursor.MoveOperation.StartOfWord, QTextCursor.MoveMode.KeepAnchor)
110-
tc.removeSelectedText()
111109
tc.insertText(self._provider.get_snippets()[completion])
112110
else:
113-
tc.insertText(completion[-extra:])
111+
tc.insertText(completion)
114112
self.setTextCursor(tc)
115113

116114
def text_under_cursor(self) -> str:
@@ -200,7 +198,7 @@ def matchBrackets(self):
200198
cursor = self.textCursor()
201199
text = self.toPlainText()
202200
pos = cursor.position()
203-
if pos >= len(text):
201+
if pos > len(text):
204202
self.highlightCurrentLine()
205203
return
206204

tests/test_editor_auto_close.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,26 @@ def test_multiline_selection_wrapped_without_u2029(self):
115115
self.assertEqual(text, "(line1\nline2)",
116116
f"Erwartete '(line1\\nline2)', bekommen: {text!r}")
117117

118+
def test_match_brackets_at_eof(self):
119+
"""Bracket matching at EOF: Cursor after closing bracket at EOF must highlight brackets."""
120+
self.editor.setPlainText("foo()")
121+
cursor = self.editor.textCursor()
122+
cursor.setPosition(5) # Position 5 (EOF, after closing paren)
123+
self.editor.setTextCursor(cursor)
124+
self.editor.matchBrackets()
125+
self.assertEqual(len(self.editor.bracket_selections), 2,
126+
"Both opening and closing brackets must be highlighted at EOF")
127+
128+
def test_insert_completion_case_insensitive(self):
129+
"""Auto-completion replacement: Inserting completion must replace prefix with exact case."""
130+
self.editor.setPlainText("PR")
131+
cursor = self.editor.textCursor()
132+
cursor.setPosition(2)
133+
self.editor.setTextCursor(cursor)
134+
self.editor.insert_completion("print")
135+
text = self.editor.toPlainText()
136+
self.assertEqual(text, "print", f"Erwartet 'print', bekommen {text!r}")
137+
118138

119139
if __name__ == "__main__":
120140
unittest.main()

0 commit comments

Comments
 (0)