Changeset View
Changeset View
Standalone View
Standalone View
src/document/katedocument.cpp
Show First 20 Lines • Show All 91 Lines • ▼ Show 20 Line(s) | 3028 | if (view->config()->autoBrackets() && chars.size() == 1) { | |||
---|---|---|---|---|---|
3039 | if (m_currentAutobraceClosingChar == typedChar && m_currentAutobraceRange) { | 3039 | if (m_currentAutobraceClosingChar == typedChar && m_currentAutobraceRange) { | ||
3040 | // do nothing | 3040 | // do nothing | ||
3041 | m_currentAutobraceRange.reset(nullptr); | 3041 | m_currentAutobraceRange.reset(nullptr); | ||
3042 | view->cursorRight(); | 3042 | view->cursorRight(); | ||
3043 | return true; | 3043 | return true; | ||
3044 | } | 3044 | } | ||
3045 | } | 3045 | } | ||
3046 | 3046 | | |||
3047 | editStart(); | ||||
3048 | | ||||
3047 | /** | 3049 | /** | ||
3048 | * selection around => special handling if we want to add auto brackets | 3050 | * special handling if we want to add auto brackets to a selection | ||
3049 | */ | 3051 | */ | ||
3050 | if (view->selection() && !closingBracket.isNull()) { | 3052 | if (view->selection() && !closingBracket.isNull()) { | ||
3051 | /** | 3053 | std::unique_ptr<KTextEditor::MovingRange> selectionRange(newMovingRange(view->selectionRange())); | ||
3052 | * add bracket at start + end of the selection | 3054 | const int startLine = qMax(0, selectionRange->start().line()); | ||
3053 | */ | 3055 | const int endLine = qMin(selectionRange->end().line(), lastLine()); | ||
3054 | KTextEditor::Cursor oldCur = view->cursorPosition(); | 3056 | const bool blockMode = view->blockSelection() && (startLine != endLine); | ||
3055 | insertText(view->selectionRange().start(), chars); | 3057 | if (blockMode) { | ||
3056 | view->slotTextInserted(view, oldCur, chars); | 3058 | if (selectionRange->start().column() > selectionRange->end().column()) { | ||
3059 | // Selection was done from right->left, requires special setting to ensure the new | ||||
3060 | // added brackets will not be part of the selection | ||||
3061 | selectionRange->setInsertBehaviors(MovingRange::ExpandLeft | MovingRange::ExpandRight); | ||||
3062 | } | ||||
3063 | // Add brackets to each line of the block | ||||
3064 | const int startColumn = qMin(selectionRange->start().column(), selectionRange->end().column()); | ||||
3065 | const int endColumn = qMax(selectionRange->start().column(), selectionRange->end().column()); | ||||
3066 | const KTextEditor::Range workingRange(startLine, startColumn, endLine, endColumn); | ||||
3067 | for (int line = startLine; line <= endLine; ++line) { | ||||
3068 | const KTextEditor::Range r(rangeOnLine(workingRange, line)); | ||||
3069 | insertText(r.end(), QString(closingBracket)); | ||||
3070 | view->slotTextInserted(view, r.end(), QString(closingBracket)); | ||||
3071 | insertText(r.start(), chars); | ||||
3072 | view->slotTextInserted(view, r.start(), chars); | ||||
3073 | } | ||||
3057 | 3074 | | |||
3058 | view->setCursorPosition(view->selectionRange().end()); | 3075 | } else { | ||
3059 | oldCur = view->cursorPosition(); | 3076 | // No block, just add to start & end of selection | ||
3060 | insertText(view->selectionRange().end(), QString(closingBracket)); | 3077 | insertText(selectionRange->end(), QString(closingBracket)); | ||
3061 | view->slotTextInserted(view, oldCur, QString(closingBracket)); | 3078 | view->slotTextInserted(view, selectionRange->end(), QString(closingBracket)); | ||
3079 | insertText(selectionRange->start(), chars); | ||||
3080 | view->slotTextInserted(view, selectionRange->start(), chars); | ||||
3081 | } | ||||
3062 | 3082 | | |||
3063 | /** | 3083 | // Refesh selection | ||
3064 | * expand selection | 3084 | view->setSelection(selectionRange->toRange()); | ||
3065 | */ | 3085 | view->setCursorPosition(selectionRange->end()); | ||
3066 | view->setSelection(KTextEditor::Range(view->selectionRange().start() + Cursor{0, 1}, | 3086 | | ||
3067 | view->cursorPosition() - Cursor{0, 1})); | 3087 | editEnd(); | ||
3068 | view->setCursorPosition(view->selectionRange().start()); | 3088 | return true; | ||
3069 | } | 3089 | } | ||
3070 | 3090 | | |||
3071 | /** | 3091 | /** | ||
3072 | * else normal handling | 3092 | * normal handling | ||
3073 | */ | 3093 | */ | ||
3074 | else { | 3094 | if (!view->config()->persistentSelection() && view->selection()) { | ||
3075 | editStart(); | 3095 | view->removeSelectedText(); | ||
3076 | 3096 | } | |||
3077 | if (!view->config()->persistentSelection() && view->selection()) { | | |||
3078 | view->removeSelectedText(); | | |||
3079 | } | | |||
3080 | 3097 | | |||
3081 | const KTextEditor::Cursor oldCur(view->cursorPosition()); | 3098 | const KTextEditor::Cursor oldCur(view->cursorPosition()); | ||
3082 | | ||||
3083 | const bool multiLineBlockMode = view->blockSelection() && view->selection(); | | |||
3084 | if (view->currentInputMode()->overwrite()) { | | |||
3085 | // blockmode multiline selection case: remove chars in every line | | |||
3086 | const KTextEditor::Range selectionRange = view->selectionRange(); | | |||
3087 | const int startLine = multiLineBlockMode ? qMax(0, selectionRange.start().line()) : view->cursorPosition().line(); | | |||
3088 | const int endLine = multiLineBlockMode ? qMin(selectionRange.end().line(), lastLine()) : startLine; | | |||
3089 | const int virtualColumn = toVirtualColumn(multiLineBlockMode ? selectionRange.end() : view->cursorPosition()); | | |||
3090 | | ||||
3091 | for (int line = endLine; line >= startLine; --line) { | | |||
3092 | Kate::TextLine textLine = m_buffer->plainLine(line); | | |||
3093 | Q_ASSERT(textLine); | | |||
3094 | const int column = fromVirtualColumn(line, virtualColumn); | | |||
3095 | KTextEditor::Range r = KTextEditor::Range(KTextEditor::Cursor(line, column), qMin(chars.length(), | | |||
3096 | textLine->length() - column)); | | |||
3097 | | ||||
3098 | // replace mode needs to know what was removed so it can be restored with backspace | | |||
3099 | if (oldCur.column() < lineLength(line)) { | | |||
3100 | QChar removed = characterAt(KTextEditor::Cursor(line, column)); | | |||
3101 | view->currentInputMode()->overwrittenChar(removed); | | |||
3102 | } | | |||
3103 | 3099 | | |||
3104 | removeText(r); | 3100 | const bool multiLineBlockMode = view->blockSelection() && view->selection(); | ||
3105 | } | 3101 | if (view->currentInputMode()->overwrite()) { | ||
3106 | } | 3102 | // blockmode multiline selection case: remove chars in every line | ||
3103 | const KTextEditor::Range selectionRange = view->selectionRange(); | ||||
3104 | const int startLine = multiLineBlockMode ? qMax(0, selectionRange.start().line()) : view->cursorPosition().line(); | ||||
3105 | const int endLine = multiLineBlockMode ? qMin(selectionRange.end().line(), lastLine()) : startLine; | ||||
3106 | const int virtualColumn = toVirtualColumn(multiLineBlockMode ? selectionRange.end() : view->cursorPosition()); | ||||
3107 | 3107 | | |||
3108 | if (multiLineBlockMode) { | 3108 | for (int line = endLine; line >= startLine; --line) { | ||
3109 | KTextEditor::Range selectionRange = view->selectionRange(); | 3109 | Kate::TextLine textLine = m_buffer->plainLine(line); | ||
3110 | const int startLine = qMax(0, selectionRange.start().line()); | 3110 | Q_ASSERT(textLine); | ||
3111 | const int endLine = qMin(selectionRange.end().line(), lastLine()); | 3111 | const int column = fromVirtualColumn(line, virtualColumn); | ||
3112 | const int column = toVirtualColumn(selectionRange.end()); | 3112 | KTextEditor::Range r = KTextEditor::Range(KTextEditor::Cursor(line, column), qMin(chars.length(), | ||
3113 | for (int line = endLine; line >= startLine; --line) { | 3113 | textLine->length() - column)); | ||
3114 | editInsertText(line, fromVirtualColumn(line, column), chars); | 3114 | | ||
3115 | // replace mode needs to know what was removed so it can be restored with backspace | ||||
3116 | if (oldCur.column() < lineLength(line)) { | ||||
3117 | QChar removed = characterAt(KTextEditor::Cursor(line, column)); | ||||
3118 | view->currentInputMode()->overwrittenChar(removed); | ||||
3115 | } | 3119 | } | ||
3116 | int newSelectionColumn = toVirtualColumn(view->cursorPosition()); | | |||
3117 | selectionRange.setRange(KTextEditor::Cursor(selectionRange.start().line(), fromVirtualColumn(selectionRange.start().line(), newSelectionColumn)) | | |||
3118 | , KTextEditor::Cursor(selectionRange.end().line(), fromVirtualColumn(selectionRange.end().line(), newSelectionColumn))); | | |||
3119 | view->setSelection(selectionRange); | | |||
3120 | } else { | | |||
3121 | chars = eventuallyReplaceTabs(view->cursorPosition(), chars); | | |||
3122 | insertText(view->cursorPosition(), chars); | | |||
3123 | } | | |||
3124 | 3120 | | |||
3125 | /** | 3121 | removeText(r); | ||
3126 | * auto bracket handling for newly inserted text | | |||
3127 | * we inserted a bracket? | | |||
3128 | * => add the matching closing one to the view + input chars | | |||
3129 | * try to preserve the cursor position | | |||
3130 | */ | | |||
3131 | bool skipAutobrace = closingBracket == QLatin1Char('\''); | | |||
3132 | if (highlight() && skipAutobrace) { | | |||
3133 | // skip adding ' in spellchecked areas, because those are text | | |||
3134 | skipAutobrace = highlight()->spellCheckingRequiredForLocation(this, view->cursorPosition() - Cursor{0, 1}); | | |||
3135 | } | 3122 | } | ||
3123 | } | ||||
3136 | 3124 | | |||
3137 | const auto cursorPos(view->cursorPosition()); | 3125 | if (multiLineBlockMode) { | ||
3138 | if (!skipAutobrace && (closingBracket == QLatin1Char('\''))) { | 3126 | KTextEditor::Range selectionRange = view->selectionRange(); | ||
3139 | // skip auto quotes when these looks already balanced, bug 405089 | 3127 | const int startLine = qMax(0, selectionRange.start().line()); | ||
3140 | Kate::TextLine textLine = m_buffer->plainLine(cursorPos.line()); | 3128 | const int endLine = qMin(selectionRange.end().line(), lastLine()); | ||
3141 | // RegEx match quote, but not excaped quote, thanks to https://stackoverflow.com/a/11819111 | 3129 | const int column = toVirtualColumn(selectionRange.end()); | ||
3142 | const int count = textLine->text().left(cursorPos.column()).count(QRegularExpression(QStringLiteral("(?<!\\\\)(?:\\\\\\\\)*\\\'"))); | 3130 | for (int line = endLine; line >= startLine; --line) { | ||
3143 | skipAutobrace = (count % 2 == 0) ? true : false; | 3131 | editInsertText(line, fromVirtualColumn(line, column), chars); | ||
3144 | } | | |||
3145 | if (!skipAutobrace && (closingBracket == QLatin1Char('\"'))) { | | |||
3146 | // ...same trick for double quotes | | |||
3147 | Kate::TextLine textLine = m_buffer->plainLine(cursorPos.line()); | | |||
3148 | const int count = textLine->text().left(cursorPos.column()).count(QRegularExpression(QStringLiteral("(?<!\\\\)(?:\\\\\\\\)*\\\""))); | | |||
3149 | skipAutobrace = (count % 2 == 0) ? true : false; | | |||
3150 | } | 3132 | } | ||
3133 | int newSelectionColumn = toVirtualColumn(view->cursorPosition()); | ||||
3134 | selectionRange.setRange(KTextEditor::Cursor(selectionRange.start().line(), fromVirtualColumn(selectionRange.start().line(), newSelectionColumn)) | ||||
3135 | , KTextEditor::Cursor(selectionRange.end().line(), fromVirtualColumn(selectionRange.end().line(), newSelectionColumn))); | ||||
3136 | view->setSelection(selectionRange); | ||||
3137 | } else { | ||||
3138 | chars = eventuallyReplaceTabs(view->cursorPosition(), chars); | ||||
3139 | insertText(view->cursorPosition(), chars); | ||||
3140 | } | ||||
3151 | 3141 | | |||
3152 | if (!closingBracket.isNull() && !skipAutobrace) { | 3142 | /** | ||
3153 | // add bracket to the view | 3143 | * auto bracket handling for newly inserted text | ||
3154 | const auto nextChar = view->document()->text({cursorPos, cursorPos + Cursor{0, 1}}).trimmed(); | 3144 | * we inserted a bracket? | ||
3155 | if (nextChar.isEmpty() || !nextChar.at(0).isLetterOrNumber()) { | 3145 | * => add the matching closing one to the view + input chars | ||
3156 | insertText(view->cursorPosition(), QString(closingBracket)); | 3146 | * try to preserve the cursor position | ||
3157 | const auto insertedAt(view->cursorPosition()); | 3147 | */ | ||
3158 | view->setCursorPosition(cursorPos); | 3148 | bool skipAutobrace = closingBracket == QLatin1Char('\''); | ||
3159 | m_currentAutobraceRange.reset(newMovingRange({cursorPos - Cursor{0, 1}, insertedAt}, | 3149 | if (highlight() && skipAutobrace) { | ||
3160 | KTextEditor::MovingRange::DoNotExpand)); | 3150 | // skip adding ' in spellchecked areas, because those are text | ||
3161 | connect(view, &View::cursorPositionChanged, | 3151 | skipAutobrace = highlight()->spellCheckingRequiredForLocation(this, view->cursorPosition() - Cursor{0, 1}); | ||
3162 | this, &DocumentPrivate::checkCursorForAutobrace, Qt::UniqueConnection); | 3152 | } | ||
3163 | 3153 | | |||
3164 | // add bracket to chars inserted! needed for correct signals + indent | 3154 | const auto cursorPos(view->cursorPosition()); | ||
3165 | chars.append(closingBracket); | 3155 | if (!skipAutobrace && (closingBracket == QLatin1Char('\''))) { | ||
3166 | } | 3156 | // skip auto quotes when these looks already balanced, bug 405089 | ||
3167 | m_currentAutobraceClosingChar = closingBracket; | 3157 | Kate::TextLine textLine = m_buffer->plainLine(cursorPos.line()); | ||
3158 | // RegEx match quote, but not excaped quote, thanks to https://stackoverflow.com/a/11819111 | ||||
3159 | const int count = textLine->text().left(cursorPos.column()).count(QRegularExpression(QStringLiteral("(?<!\\\\)(?:\\\\\\\\)*\\\'"))); | ||||
3160 | skipAutobrace = (count % 2 == 0) ? true : false; | ||||
3161 | } | ||||
3162 | if (!skipAutobrace && (closingBracket == QLatin1Char('\"'))) { | ||||
3163 | // ...same trick for double quotes | ||||
3164 | Kate::TextLine textLine = m_buffer->plainLine(cursorPos.line()); | ||||
3165 | const int count = textLine->text().left(cursorPos.column()).count(QRegularExpression(QStringLiteral("(?<!\\\\)(?:\\\\\\\\)*\\\""))); | ||||
3166 | skipAutobrace = (count % 2 == 0) ? true : false; | ||||
3167 | } | ||||
3168 | | ||||
3169 | if (!closingBracket.isNull() && !skipAutobrace ) { | ||||
3170 | // add bracket to the view | ||||
3171 | const auto nextChar = view->document()->text({cursorPos, cursorPos + Cursor{0, 1}}).trimmed(); | ||||
3172 | if (nextChar.isEmpty() || !nextChar.at(0).isLetterOrNumber()) { | ||||
3173 | insertText(view->cursorPosition(), QString(closingBracket)); | ||||
3174 | const auto insertedAt(view->cursorPosition()); | ||||
3175 | view->setCursorPosition(cursorPos); | ||||
3176 | m_currentAutobraceRange.reset(newMovingRange({cursorPos - Cursor{0, 1}, insertedAt}, | ||||
3177 | KTextEditor::MovingRange::DoNotExpand)); | ||||
3178 | connect(view, &View::cursorPositionChanged, | ||||
3179 | this, &DocumentPrivate::checkCursorForAutobrace, Qt::UniqueConnection); | ||||
3180 | | ||||
3181 | // add bracket to chars inserted! needed for correct signals + indent | ||||
3182 | chars.append(closingBracket); | ||||
3168 | } | 3183 | } | ||
3184 | m_currentAutobraceClosingChar = closingBracket; | ||||
3185 | } | ||||
3169 | 3186 | | |||
3170 | // end edit session here, to have updated HL in userTypedChar! | 3187 | // end edit session here, to have updated HL in userTypedChar! | ||
3171 | editEnd(); | 3188 | editEnd(); | ||
3172 | | ||||
3173 | // trigger indentation | | |||
3174 | KTextEditor::Cursor b(view->cursorPosition()); | | |||
3175 | m_indenter->userTypedChar(view, b, chars.isEmpty() ? QChar() : chars.at(chars.length() - 1)); | | |||
3176 | 3189 | | |||
3177 | /** | 3190 | // trigger indentation | ||
3178 | * inform the view about the original inserted chars | 3191 | KTextEditor::Cursor b(view->cursorPosition()); | ||
3179 | */ | 3192 | m_indenter->userTypedChar(view, b, chars.isEmpty() ? QChar() : chars.at(chars.length() - 1)); | ||
3180 | view->slotTextInserted(view, oldCur, chars); | | |||
3181 | } | | |||
3182 | 3193 | | |||
3183 | /** | 3194 | /** | ||
3184 | * be done | 3195 | * inform the view about the original inserted chars | ||
3185 | */ | 3196 | */ | ||
3197 | view->slotTextInserted(view, oldCur, chars); | ||||
3198 | | ||||
3186 | return true; | 3199 | return true; | ||
3187 | } | 3200 | } | ||
3188 | 3201 | | |||
3189 | void KTextEditor::DocumentPrivate::checkCursorForAutobrace(KTextEditor::View*, const KTextEditor::Cursor& newPos) { | 3202 | void KTextEditor::DocumentPrivate::checkCursorForAutobrace(KTextEditor::View*, const KTextEditor::Cursor& newPos) { | ||
3190 | if ( m_currentAutobraceRange && ! m_currentAutobraceRange->toRange().contains(newPos) ) { | 3203 | if ( m_currentAutobraceRange && ! m_currentAutobraceRange->toRange().contains(newPos) ) { | ||
3191 | m_currentAutobraceRange.clear(); | 3204 | m_currentAutobraceRange.clear(); | ||
3192 | } | 3205 | } | ||
3193 | } | 3206 | } | ||
▲ Show 20 Lines • Show All 91 Lines • Show Last 20 Lines |