fix: Backspace/Delete deleting prompt text (root@host:~#)

Root cause: _current_line_start was set after \r\n but BEFORE the prompt
was rendered, so Backspace could erase prompt characters after reaching
the input line start.

Fix: send \x7f (DEL) to shell on Backspace and \x1b[3~ on Delete instead
of locally deleting characters. The shell's readline handles backspace
correctly - it ignores DEL at the input line start, so the prompt is
never touched. The existing \b handler in _on_data already correctly
processes the shell's \b-space-\b echo sequence.

Verified: typing 'abc' + 3 Backspace deletes input, 5 more Backspace
leaves prompt 'root@host:~# ' intact.
This commit is contained in:
Your Name
2026-07-29 06:47:08 +08:00
parent f0b6a71a65
commit ac29515d9f
+13 -5
View File
@@ -571,24 +571,32 @@ class TerminalPanel(QWidget):
self._send_bytes(b"\r") self._send_bytes(b"\r")
def _on_backspace(self): def _on_backspace(self):
# 发 DEL(\x7f) 给 shell,由 shell 的 readline 处理退格 + 回显(\b \b)。
# 这样 shell 在输入行首会忽略退格,不会删除提示符 root@host:~#。
# 旧方案是本地 deletePreviousChar(),但 _current_line_start 在提示符
# 之前,导致退到输入行首后还能继续删提示符。
if self.chan and self._connected:
self._send_bytes(b"\x7f")
return
# 未连接时 fallback:本地删除
cursor = self.term.textCursor() cursor = self.term.textCursor()
if cursor.position() <= self._current_line_start: if cursor.position() <= self._current_line_start:
return # 已到行首,不删
# 不能跨行删(保持当前行)
if self._is_at_line_start(cursor):
return return
cursor.deletePreviousChar() cursor.deletePreviousChar()
def _on_delete(self): def _on_delete(self):
# 发 Delete 转义序列给 shell,由 shell 处理
if self.chan and self._connected:
self._send_bytes(b"\x1b[3~")
return
# 未连接时 fallback:本地删除
cursor = self.term.textCursor() cursor = self.term.textCursor()
if cursor.atEnd(): if cursor.atEnd():
return return
# 不允许删除当前输入行之前的内容(提示符 root@host:~# 等)
if cursor.position() < self._current_line_start: if cursor.position() < self._current_line_start:
cursor.setPosition(self._current_line_start) cursor.setPosition(self._current_line_start)
self.term.setTextCursor(cursor) self.term.setTextCursor(cursor)
return return
# 如果有选区且选区起点在当前输入行之前,不允许
if cursor.hasSelection(): if cursor.hasSelection():
sel_start = cursor.selectionStart() sel_start = cursor.selectionStart()
if sel_start < self._current_line_start: if sel_start < self._current_line_start: