Changeset View
Changeset View
Standalone View
Standalone View
src/document/katedocument.cpp
Show First 20 Lines • Show All 91 Lines • ▼ Show 20 Line(s) | |||||
109 | } | 109 | } | ||
110 | 110 | | |||
111 | template<class C, class E> | 111 | template<class C, class E> | ||
112 | static bool contains(const std::initializer_list<C> & list, const E& entry) | 112 | static bool contains(const std::initializer_list<C> & list, const E& entry) | ||
113 | { | 113 | { | ||
114 | return indexOf(list, entry) >= 0; | 114 | return indexOf(list, entry) >= 0; | ||
115 | } | 115 | } | ||
116 | 116 | | |||
117 | static inline QChar matchingStartBracket(QChar c, bool withQuotes) | 117 | static inline QChar matchingStartBracket(const QChar c) | ||
118 | { | 118 | { | ||
119 | switch (c.toLatin1()) { | 119 | switch (c.toLatin1()) { | ||
120 | case '}': return QLatin1Char('{'); | 120 | case '}': return QLatin1Char('{'); | ||
121 | case ']': return QLatin1Char('['); | 121 | case ']': return QLatin1Char('['); | ||
122 | case ')': return QLatin1Char('('); | 122 | case ')': return QLatin1Char('('); | ||
123 | case '\'': return withQuotes ? QLatin1Char('\'') : QChar(); | | |||
124 | case '"': return withQuotes ? QLatin1Char('"') : QChar(); | | |||
125 | } | 123 | } | ||
126 | return QChar(); | 124 | return QChar(); | ||
127 | } | 125 | } | ||
128 | 126 | | |||
129 | static inline QChar matchingEndBracket(QChar c, bool withQuotes) | 127 | static inline QChar matchingEndBracket(const QChar c, bool withQuotes = true) | ||
130 | { | 128 | { | ||
131 | switch (c.toLatin1()) { | 129 | switch (c.toLatin1()) { | ||
132 | case '{': return QLatin1Char('}'); | 130 | case '{': return QLatin1Char('}'); | ||
133 | case '[': return QLatin1Char(']'); | 131 | case '[': return QLatin1Char(']'); | ||
134 | case '(': return QLatin1Char(')'); | 132 | case '(': return QLatin1Char(')'); | ||
135 | case '\'': return withQuotes ? QLatin1Char('\'') : QChar(); | 133 | case '\'': return withQuotes ? QLatin1Char('\'') : QChar(); | ||
136 | case '"': return withQuotes ? QLatin1Char('"') : QChar(); | 134 | case '"': return withQuotes ? QLatin1Char('"') : QChar(); | ||
137 | } | 135 | } | ||
138 | return QChar(); | 136 | return QChar(); | ||
139 | } | 137 | } | ||
140 | 138 | | |||
141 | static inline QChar matchingBracket(QChar c, bool withQuotes) | 139 | static inline QChar matchingBracket(const QChar c) | ||
142 | { | 140 | { | ||
143 | QChar bracket = matchingStartBracket(c, withQuotes); | 141 | QChar bracket = matchingStartBracket(c); | ||
144 | if (bracket.isNull()) { | 142 | if (bracket.isNull()) { | ||
145 | bracket = matchingEndBracket(c, false); | 143 | bracket = matchingEndBracket(c, /*withQuotes=*/false); | ||
146 | } | 144 | } | ||
147 | return bracket; | 145 | return bracket; | ||
148 | } | 146 | } | ||
149 | 147 | | |||
150 | static inline bool isStartBracket(const QChar &c) | 148 | static inline bool isStartBracket(const QChar c) | ||
151 | { | 149 | { | ||
152 | return ! matchingEndBracket(c, false).isNull(); | 150 | return ! matchingEndBracket(c, /*withQuotes=*/false).isNull(); | ||
153 | } | 151 | } | ||
154 | 152 | | |||
155 | static inline bool isEndBracket(const QChar &c) | 153 | static inline bool isEndBracket(const QChar c) | ||
156 | { | 154 | { | ||
157 | return ! matchingStartBracket(c, false).isNull(); | 155 | return ! matchingStartBracket(c).isNull(); | ||
158 | } | 156 | } | ||
159 | 157 | | |||
160 | static inline bool isBracket(const QChar &c) | 158 | static inline bool isBracket(const QChar c) | ||
161 | { | 159 | { | ||
162 | return isStartBracket(c) || isEndBracket(c); | 160 | return isStartBracket(c) || isEndBracket(c); | ||
163 | } | 161 | } | ||
164 | 162 | | |||
165 | /** | 163 | /** | ||
166 | * normalize given url | 164 | * normalize given url | ||
167 | * @param url input url | 165 | * @param url input url | ||
168 | * @return normalized url | 166 | * @return normalized url | ||
▲ Show 20 Lines • Show All 182 Lines • ▼ Show 20 Line(s) | 2933 | { | |||
2952 | } | 2950 | } | ||
2953 | 2951 | | |||
2954 | /** | 2952 | /** | ||
2955 | * auto bracket handling for newly inserted text | 2953 | * auto bracket handling for newly inserted text | ||
2956 | * remember if we should auto add some | 2954 | * remember if we should auto add some | ||
2957 | */ | 2955 | */ | ||
2958 | QChar closingBracket; | 2956 | QChar closingBracket; | ||
2959 | if (view->config()->autoBrackets() && chars.size() == 1) { | 2957 | if (view->config()->autoBrackets() && chars.size() == 1) { | ||
2958 | const QChar typedChar = chars.at(0); | ||||
2960 | /** | 2959 | /** | ||
2961 | * we inserted a bracket? | 2960 | * we inserted a bracket? | ||
2962 | * => remember the matching closing one | 2961 | * => remember the matching closing one | ||
2963 | */ | 2962 | */ | ||
2964 | closingBracket = matchingEndBracket(chars[0], true); | 2963 | closingBracket = matchingEndBracket(typedChar); | ||
2965 | 2964 | | |||
2966 | /** | 2965 | /** | ||
2967 | * closing bracket for the autobracket we inserted earlier? | 2966 | * closing bracket for the autobracket we inserted earlier? | ||
2968 | */ | 2967 | */ | ||
2969 | if ( m_currentAutobraceClosingChar == chars[0] && m_currentAutobraceRange ) { | 2968 | if (m_currentAutobraceClosingChar == typedChar && m_currentAutobraceRange) { | ||
2970 | // do nothing | 2969 | // do nothing | ||
2971 | m_currentAutobraceRange.reset(nullptr); | 2970 | m_currentAutobraceRange.reset(nullptr); | ||
2972 | view->cursorRight(); | 2971 | view->cursorRight(); | ||
2973 | return true; | 2972 | return true; | ||
2974 | } | 2973 | } | ||
2975 | } | 2974 | } | ||
2976 | 2975 | | |||
2977 | /** | 2976 | /** | ||
▲ Show 20 Lines • Show All 76 Lines • ▼ Show 20 Line(s) | 3003 | else { | |||
3054 | 3053 | | |||
3055 | /** | 3054 | /** | ||
3056 | * auto bracket handling for newly inserted text | 3055 | * auto bracket handling for newly inserted text | ||
3057 | * we inserted a bracket? | 3056 | * we inserted a bracket? | ||
3058 | * => add the matching closing one to the view + input chars | 3057 | * => add the matching closing one to the view + input chars | ||
3059 | * try to preserve the cursor position | 3058 | * try to preserve the cursor position | ||
3060 | */ | 3059 | */ | ||
3061 | bool skipAutobrace = closingBracket == QLatin1Char('\''); | 3060 | bool skipAutobrace = closingBracket == QLatin1Char('\''); | ||
3062 | if ( highlight() && skipAutobrace ) { | 3061 | if (highlight() && skipAutobrace) { | ||
3063 | // skip adding ' in spellchecked areas, because those are text | 3062 | // skip adding ' in spellchecked areas, because those are text | ||
3064 | skipAutobrace = highlight()->spellCheckingRequiredForLocation(this, view->cursorPosition() - Cursor{0, 1}); | 3063 | skipAutobrace = highlight()->spellCheckingRequiredForLocation(this, view->cursorPosition() - Cursor{0, 1}); | ||
3065 | } | 3064 | } | ||
3066 | if (!closingBracket.isNull() && !skipAutobrace ) { | 3065 | | ||
3066 | const auto cursorPos(view->cursorPosition()); | ||||
3067 | if (!skipAutobrace && (closingBracket == QLatin1Char('\''))) { | ||||
3068 | // skip auto quotes when these looks already balanced, bug 405089 | ||||
3069 | Kate::TextLine textLine = m_buffer->plainLine(cursorPos.line()); | ||||
3070 | // RegEx match quote, but not excaped quote, thanks to https://stackoverflow.com/a/11819111 | ||||
3071 | const int count = textLine->text().left(cursorPos.column()).count(QRegularExpression(QStringLiteral("(?<!\\\\)(?:\\\\\\\\)*\\\'"))); | ||||
3072 | skipAutobrace = (count % 2 == 0) ? true : false; | ||||
3073 | } | ||||
3074 | if (!skipAutobrace && (closingBracket == QLatin1Char('\"'))) { | ||||
3075 | // ...same trick for double quotes | ||||
3076 | Kate::TextLine textLine = m_buffer->plainLine(cursorPos.line()); | ||||
3077 | const int count = textLine->text().left(cursorPos.column()).count(QRegularExpression(QStringLiteral("(?<!\\\\)(?:\\\\\\\\)*\\\""))); | ||||
3078 | skipAutobrace = (count % 2 == 0) ? true : false; | ||||
3079 | } | ||||
3080 | | ||||
3081 | if (!closingBracket.isNull() && !skipAutobrace) { | ||||
3067 | // add bracket to the view | 3082 | // add bracket to the view | ||
3068 | const auto cursorPos(view->cursorPosition()); | | |||
3069 | const auto nextChar = view->document()->text({cursorPos, cursorPos + Cursor{0, 1}}).trimmed(); | 3083 | const auto nextChar = view->document()->text({cursorPos, cursorPos + Cursor{0, 1}}).trimmed(); | ||
3070 | if ( nextChar.isEmpty() || ! nextChar.at(0).isLetterOrNumber() ) { | 3084 | if (nextChar.isEmpty() || !nextChar.at(0).isLetterOrNumber()) { | ||
3071 | insertText(view->cursorPosition(), QString(closingBracket)); | 3085 | insertText(view->cursorPosition(), QString(closingBracket)); | ||
3072 | const auto insertedAt(view->cursorPosition()); | 3086 | const auto insertedAt(view->cursorPosition()); | ||
3073 | view->setCursorPosition(cursorPos); | 3087 | view->setCursorPosition(cursorPos); | ||
3074 | m_currentAutobraceRange.reset(newMovingRange({cursorPos - Cursor{0, 1}, insertedAt}, | 3088 | m_currentAutobraceRange.reset(newMovingRange({cursorPos - Cursor{0, 1}, insertedAt}, | ||
3075 | KTextEditor::MovingRange::DoNotExpand)); | 3089 | KTextEditor::MovingRange::DoNotExpand)); | ||
3076 | connect(view, &View::cursorPositionChanged, | 3090 | connect(view, &View::cursorPositionChanged, | ||
3077 | this, &DocumentPrivate::checkCursorForAutobrace, Qt::UniqueConnection); | 3091 | this, &DocumentPrivate::checkCursorForAutobrace, Qt::UniqueConnection); | ||
3078 | 3092 | | |||
▲ Show 20 Lines • Show All 182 Lines • ▼ Show 20 Line(s) | 4073 | } else if (isBracket(right)) { | |||
4060 | bracket = right; | 4074 | bracket = right; | ||
4061 | } else if (isBracket(left)) { | 4075 | } else if (isBracket(left)) { | ||
4062 | range.setStart(KTextEditor::Cursor(range.start().line(), range.start().column() - 1)); | 4076 | range.setStart(KTextEditor::Cursor(range.start().line(), range.start().column() - 1)); | ||
4063 | bracket = left; | 4077 | bracket = left; | ||
4064 | } else { | 4078 | } else { | ||
4065 | return KTextEditor::Range::invalid(); | 4079 | return KTextEditor::Range::invalid(); | ||
4066 | } | 4080 | } | ||
4067 | 4081 | | |||
4068 | const QChar opposite = matchingBracket(bracket, false); | 4082 | const QChar opposite = matchingBracket(bracket); | ||
4069 | if (opposite.isNull()) { | 4083 | if (opposite.isNull()) { | ||
4070 | return KTextEditor::Range::invalid(); | 4084 | return KTextEditor::Range::invalid(); | ||
4071 | } | 4085 | } | ||
4072 | 4086 | | |||
4073 | const int searchDir = isStartBracket(bracket) ? 1 : -1; | 4087 | const int searchDir = isStartBracket(bracket) ? 1 : -1; | ||
4074 | uint nesting = 0; | 4088 | uint nesting = 0; | ||
4075 | 4089 | | |||
4076 | const int minLine = qMax(range.start().line() - maxLines, 0); | 4090 | const int minLine = qMax(range.start().line() - maxLines, 0); | ||
▲ Show 20 Lines • Show All 91 Lines • Show Last 20 Lines |