Changeset View
Changeset View
Standalone View
Standalone View
src/completion/katewordcompletion.cpp
Show First 20 Lines • Show All 205 Lines • ▼ Show 20 Line(s) | |||||
206 | * Scan throughout the entire document for possible completions, | 206 | * Scan throughout the entire document for possible completions, | ||
207 | * ignoring any dublets and words shorter than configured and/or | 207 | * ignoring any dublets and words shorter than configured and/or | ||
208 | * reasonable minimum length. | 208 | * reasonable minimum length. | ||
209 | */ | 209 | */ | ||
210 | QStringList KateWordCompletionModel::allMatches(KTextEditor::View *view, const KTextEditor::Range &range) const | 210 | QStringList KateWordCompletionModel::allMatches(KTextEditor::View *view, const KTextEditor::Range &range) const | ||
211 | { | 211 | { | ||
212 | QSet<QString> result; | 212 | QSet<QString> result; | ||
213 | const int minWordSize = qMax(2, qobject_cast<KTextEditor::ViewPrivate *>(view)->config()->wordCompletionMinimalWordLength()); | 213 | const int minWordSize = qMax(2, qobject_cast<KTextEditor::ViewPrivate *>(view)->config()->wordCompletionMinimalWordLength()); | ||
214 | | ||||
215 | const bool blockSelection = view->blockSelection() && view->selection(); | ||||
216 | | ||||
214 | const int lines = view->document()->lines(); | 217 | const int lines = view->document()->lines(); | ||
215 | for (int line = 0; line < lines; line++) { | 218 | for (int line = 0; line < lines; line++) { | ||
216 | const QString &text = view->document()->line(line); | 219 | const QString &text = view->document()->line(line); | ||
217 | int wordBegin = 0; | 220 | int wordBegin = 0; | ||
218 | int offset = 0; | 221 | int offset = 0; | ||
219 | const int end = text.size(); | 222 | const int end = text.size(); | ||
220 | const bool cursorLine = view->cursorPosition().line() == line; | 223 | const bool cursorLine = view->cursorPosition().line() == line; | ||
221 | while (offset < end) { | 224 | while (offset < end) { | ||
222 | const QChar c = text.at(offset); | 225 | const QChar c = text.at(offset); | ||
223 | // increment offset when at line end, so we take the last character too | 226 | // increment offset when at line end, so we take the last character too | ||
224 | if ((! c.isLetterOrNumber() && c != QLatin1Char('_')) || (offset == end - 1 && offset++)) { | 227 | if ((! c.isLetterOrNumber() && c != QLatin1Char('_')) || (offset == end - 1 && offset++)) { | ||
225 | if (offset - wordBegin > minWordSize && (line != range.end().line() || offset != range.end().column())) { | 228 | if (offset - wordBegin > minWordSize && (line != range.end().line() || offset != range.end().column())) { | ||
226 | /** | 229 | /** | ||
227 | * don't add the word we are inside with cursor! | 230 | * Don't add the word we are inside with cursor! | ||
231 | * Handle completion with block selection, by not adding | ||||
232 | * the words the cursor is inside on each line in the selection | ||||
228 | */ | 233 | */ | ||
234 | if (blockSelection) { | ||||
235 | KTextEditor::Range selectionRange = view->selectionRange(); | ||||
236 | const int startLine = selectionRange.start().line(); | ||||
237 | const int endLine = selectionRange.end().line(); | ||||
238 | if ((line < startLine || line > endLine) || (view->cursorPosition().column() < wordBegin || view->cursorPosition().column() > offset)) { | ||||
239 | result.insert(text.mid(wordBegin, offset - wordBegin)); | ||||
240 | } | ||||
241 | } else { | ||||
229 | if (!cursorLine || (view->cursorPosition().column() < wordBegin || view->cursorPosition().column() > offset)) { | 242 | if (!cursorLine || (view->cursorPosition().column() < wordBegin || view->cursorPosition().column() > offset)) { | ||
230 | result.insert(text.mid(wordBegin, offset - wordBegin)); | 243 | result.insert(text.mid(wordBegin, offset - wordBegin)); | ||
231 | } | 244 | } | ||
232 | } | 245 | } | ||
246 | } | ||||
233 | wordBegin = offset + 1; | 247 | wordBegin = offset + 1; | ||
234 | } | 248 | } | ||
235 | if (c.isSpace()) { | 249 | if (c.isSpace()) { | ||
236 | wordBegin = offset + 1; | 250 | wordBegin = offset + 1; | ||
237 | } | 251 | } | ||
238 | offset += 1; | 252 | offset += 1; | ||
239 | } | 253 | } | ||
240 | } | 254 | } | ||
241 | return result.values(); | 255 | return result.values(); | ||
242 | } | 256 | } | ||
243 | 257 | | |||
244 | void KateWordCompletionModel::executeCompletionItem (KTextEditor::View *view | 258 | void KateWordCompletionModel::executeCompletionItem (KTextEditor::View *view | ||
245 | , const KTextEditor::Range &word | 259 | , const KTextEditor::Range &word | ||
246 | , const QModelIndex &index | 260 | , const QModelIndex &index | ||
247 | ) const | 261 | ) const | ||
248 | { | 262 | { | ||
249 | KTextEditor::ViewPrivate *v = qobject_cast<KTextEditor::ViewPrivate *> (view); | 263 | KTextEditor::ViewPrivate *v = qobject_cast<KTextEditor::ViewPrivate *> (view); | ||
264 | | ||||
265 | const bool blockSelection = v->blockSelection() && v->selection(); | ||||
266 | | ||||
267 | KTextEditor::Range range = blockSelection? KTextEditor::Range(word.start(), v->selectionRange().end()) : word; | ||||
268 | | ||||
250 | if (v->config()->wordCompletionRemoveTail()) { | 269 | if (v->config()->wordCompletionRemoveTail()) { | ||
270 | v->doc()->replaceText(range, m_matches.at(index.row()), blockSelection); | ||||
271 | v->doc()->editEnd(); | ||||
272 | | ||||
273 | if (blockSelection) { | ||||
274 | // get the block selection range after the above replaceText() | ||||
275 | KTextEditor::Range selectionRange = v->selectionRange(); | ||||
276 | const int selectionEndColumn = selectionRange.end().column(); | ||||
277 | v->doc()->editStart(); | ||||
278 | for (int i = selectionRange.start().line(); i <= selectionRange.end().line(); ++i) { | ||||
279 | const QString &line = v->doc()->line(i); | ||||
280 | int tailEnd = line.length(); | ||||
281 | for (int j = selectionEndColumn; j < tailEnd; ++j) { | ||||
282 | // Letters, numbers and underscore are part of a word! | ||||
283 | /// \todo Introduce configurable \e word-separators?? | ||||
284 | if (!line[j].isLetterOrNumber() && line[j] != QLatin1Char('_')) { | ||||
285 | tailEnd = j; | ||||
286 | } | ||||
287 | } | ||||
288 | v->doc()->removeText(KTextEditor::Range(KTextEditor::Cursor(i, selectionEndColumn), KTextEditor::Cursor(i, tailEnd)), blockSelection); | ||||
289 | } | ||||
290 | } else { | ||||
251 | int tailStart = word.end().column(); | 291 | int tailStart = word.end().column(); | ||
252 | const QString &line = view->document()->line(word.end().line()); | 292 | const QString &line = view->document()->line(word.end().line()); | ||
253 | int tailEnd = line.length(); | 293 | int tailEnd = line.length(); | ||
254 | for (int i = word.end().column(); i < tailEnd; ++i) { | 294 | for (int i = word.end().column(); i < tailEnd; ++i) { | ||
255 | // Letters, numbers and underscore are part of a word! | 295 | // Letters, numbers and underscore are part of a word! | ||
256 | /// \todo Introduce configurable \e word-separators?? | 296 | /// \todo Introduce configurable \e word-separators?? | ||
257 | if (!line[i].isLetterOrNumber() && line[i] != QLatin1Char('_')) { | 297 | if (!line[i].isLetterOrNumber() && line[i] != QLatin1Char('_')) { | ||
258 | tailEnd = i; | 298 | tailEnd = i; | ||
259 | } | 299 | } | ||
260 | } | 300 | } | ||
261 | 301 | | |||
262 | int sizeDiff = m_matches.at(index.row()).size() - (word.end().column() - word.start().column()); | 302 | int sizeDiff = m_matches.at(index.row()).size() - (word.end().column() - word.start().column()); | ||
263 | 303 | | |||
264 | tailStart += sizeDiff; | 304 | tailStart += sizeDiff; | ||
265 | tailEnd += sizeDiff; | 305 | tailEnd += sizeDiff; | ||
266 | 306 | | |||
267 | KTextEditor::Range tail(KTextEditor::Cursor(word.start().line(), tailStart), KTextEditor::Cursor(word.end().line(), tailEnd)); | 307 | KTextEditor::Range tail(KTextEditor::Cursor(word.start().line(), tailStart), KTextEditor::Cursor(word.end().line(), tailEnd)); | ||
268 | 308 | | |||
269 | view->document()->replaceText(word, m_matches.at(index.row())); | | |||
270 | v->doc()->editEnd(); | | |||
271 | v->doc()->editStart(); | 309 | v->doc()->editStart(); | ||
272 | view->document()->replaceText(tail, QString()); | 310 | view->document()->replaceText(tail, QString()); | ||
311 | } | ||||
273 | } else { | 312 | } else { | ||
274 | view->document()->replaceText(word, m_matches.at(index.row())); | 313 | v->doc()->replaceText(range, m_matches.at(index.row()), blockSelection); | ||
275 | } | 314 | } | ||
276 | } | 315 | } | ||
277 | 316 | | |||
278 | KTextEditor::CodeCompletionModelControllerInterface::MatchReaction KateWordCompletionModel::matchingItem(const QModelIndex & /*matched*/) | 317 | KTextEditor::CodeCompletionModelControllerInterface::MatchReaction KateWordCompletionModel::matchingItem(const QModelIndex & /*matched*/) | ||
279 | { | 318 | { | ||
280 | return HideListIfAutomaticInvocation; | 319 | return HideListIfAutomaticInvocation; | ||
281 | } | 320 | } | ||
282 | 321 | | |||
▲ Show 20 Lines • Show All 301 Lines • Show Last 20 Lines |