Enter починен: новая строка с сохранением отступа

- TextArea focus:true, handleEnter() с indent +4 для { [ ( : >, extra для }])], _enterHandled флаг, onTextChanged авто-отступ если \n вставлен, Keys.onReturnPressed/onEnterPressed + onPressed Tab/Backspace
- Backspace удаляет 4 пробела как один, Tab 4 пробела / Shift+Tab снятие
This commit is contained in:
2026-09-01 22:53:18 +03:00
parent 277a87a53b
commit 22035ba0f2
+64 -2
View File
@@ -276,6 +276,7 @@ Item {
TextArea {
id: textArea
focus: true
placeholderText: qsTr("Начните писать…")
placeholderTextColor: Theme.textFaint
color: Theme.editorText
@@ -342,7 +343,60 @@ Item {
}
}
property string _prevText: ""
property int _prevCursor: 0
property bool _enterHandled: false
onTextChanged: {
// Авто-отступ при Enter: если был вставлен \n, добавляем indent (если не обработано через Keys)
if (_enterHandled) {
_enterHandled = false
_prevText = text
_prevCursor = cursorPosition
if (activeFocus && text !== documentManager.contentAt(documentManager.activeIndex)) {
editDebounce.restart()
}
if (viewMode === "live") liveDebounce.restart()
return
}
if (activeFocus && _prevText.length > 0) {
const pos = cursorPosition
// Проверяем был ли вставлен один \n
if (text.length === _prevText.length + 1 && text[pos-1] === "\n") {
// Найдём отступ предыдущей строки
let lineStart = _prevText.lastIndexOf("\n", _prevCursor-1) + 1
let line = _prevText.substring(lineStart, _prevCursor)
let indent = ""
const m = line.match(/^(\s+)/)
if (m) indent = m[1]
const trimmed = line.trimEnd()
if (trimmed.endsWith("{") || trimmed.endsWith("[") || trimmed.endsWith("(") || trimmed.endsWith(":") || trimmed.endsWith(">")) {
indent += " "
}
if (indent.length > 0) {
// Вставляем indent после \n
const before = text.substring(0, pos)
const after = text.substring(pos)
// Проверяем что indent ещё не вставлен (чтобы не дублировать)
if (!after.startsWith(indent.substring(0,4))) {
const newText = before + indent + after
// Блокируем рекурсию
_prevText = newText
text = newText
cursorPosition = pos + indent.length
if (documentManager.activeIndex >=0) documentManager.updateContent(documentManager.activeIndex, text)
_prevText = text
_prevCursor = cursorPosition
if (viewMode === "live") liveDebounce.restart()
if (activeFocus && text !== documentManager.contentAt(documentManager.activeIndex)) {
editDebounce.restart()
}
return
}
}
}
}
_prevText = text
_prevCursor = cursorPosition
if (activeFocus && text !== documentManager.contentAt(documentManager.activeIndex)) {
editDebounce.restart()
}
@@ -350,6 +404,7 @@ Item {
}
function insertText(t) { insert(cursorPosition, t) }
function handleEnter() {
_enterHandled = true
const pos = cursorPosition
let lineStart = text.lastIndexOf("\n", pos-1) + 1
let line = text.substring(lineStart, pos)
@@ -371,12 +426,19 @@ Item {
insert(pos, ins)
cursorPosition = pos + 1 + indent.length
if (documentManager.activeIndex >=0) documentManager.updateContent(documentManager.activeIndex, text)
// _enterHandled сбросится в onTextChanged
}
// Авто-отступ и скобки
Keys.onReturnPressed: handleEnter()
Keys.onEnterPressed: handleEnter()
Keys.onPressed: (event) => {
console.log("Keys.onPressed", event.key, event.text, event.modifiers, "cursor", cursorPosition)
// Enter — дублируем обработку здесь на случай если onReturnPressed не сработает
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
console.log("Enter via onPressed")
event.accepted = true
handleEnter()
return
}
// Tab — 4 пробела, Shift+Tab — снять отступ
if (event.key === Qt.Key_Tab) {
event.accepted = true