Changeset View
Changeset View
Standalone View
Standalone View
src/buffer/katetextblock.cpp
Show First 20 Lines • Show All 144 Lines • ▼ Show 20 Line(s) | 92 | { | |||
---|---|---|---|---|---|
145 | 145 | | |||
146 | // no cursors in this block, no work to do.. | 146 | // no cursors in this block, no work to do.. | ||
147 | if (m_cursors.empty()) { | 147 | if (m_cursors.empty()) { | ||
148 | return; | 148 | return; | ||
149 | } | 149 | } | ||
150 | 150 | | |||
151 | // move all cursors on the line which has the text inserted | 151 | // move all cursors on the line which has the text inserted | ||
152 | // remember all ranges modified | 152 | // remember all ranges modified | ||
153 | QSet<TextRange *> changedRanges; | 153 | std::vector<TextRange *> changedRanges; | ||
anthonyfieroni: You can use unordered_set, so you don't need m_isCheckValidityRequired any more. It can be… | |||||
Actually no, that will be again a lot more expensive. cullmann: Actually no, that will be again a lot more expensive.
With the vector, you get one allocation… | |||||
154 | foreach (TextCursor *cursor, m_cursors) { | 154 | foreach (TextCursor *cursor, m_cursors) { | ||
155 | // skip cursors on lines in front of the wrapped one! | 155 | // skip cursors on lines in front of the wrapped one! | ||
156 | if (cursor->lineInBlock() < line) { | 156 | if (cursor->lineInBlock() < line) { | ||
157 | continue; | 157 | continue; | ||
158 | } | 158 | } | ||
159 | 159 | | |||
160 | // either this is simple, line behind the wrapped one | 160 | // either this is simple, line behind the wrapped one | ||
161 | if (cursor->lineInBlock() > line) { | 161 | if (cursor->lineInBlock() > line) { | ||
Show All 16 Lines | 167 | else { | |||
178 | cursor->m_line++; | 178 | cursor->m_line++; | ||
179 | 179 | | |||
180 | // patch column | 180 | // patch column | ||
181 | cursor->m_column -= position.column(); | 181 | cursor->m_column -= position.column(); | ||
182 | } | 182 | } | ||
183 | 183 | | |||
184 | // remember range, if any | 184 | // remember range, if any | ||
185 | if (cursor->kateRange()) { | 185 | if (cursor->kateRange()) { | ||
186 | changedRanges.insert(cursor->kateRange()); | 186 | cursor->kateRange()->m_isCheckValidityRequired = true; | ||
187 | changedRanges.push_back(cursor->kateRange()); | ||||
187 | } | 188 | } | ||
188 | } | 189 | } | ||
189 | 190 | | |||
190 | // check validity of all ranges, might invalidate them... | 191 | // we might need to invalidate ranges or notify about their changes | ||
191 | foreach (TextRange *range, changedRanges) { | 192 | for (TextRange *range : changedRanges) { | ||
193 | if (range->m_isCheckValidityRequired) { | ||||
192 | range->checkValidity(); | 194 | range->checkValidity(); | ||
195 | range->m_isCheckValidityRequired = false; | ||||
196 | } | ||||
193 | } | 197 | } | ||
194 | } | 198 | } | ||
195 | 199 | | |||
196 | void TextBlock::unwrapLine(int line, TextBlock *previousBlock, int fixStartLinesStartIndex) | 200 | void TextBlock::unwrapLine(int line, TextBlock *previousBlock, int fixStartLinesStartIndex) | ||
197 | { | 201 | { | ||
198 | // calc internal line | 202 | // calc internal line | ||
199 | line = line - startLine(); | 203 | line = line - startLine(); | ||
200 | 204 | | |||
Show All 40 Lines | 206 | if (line == 0) { | |||
241 | 245 | | |||
242 | // no cursors in this block and the previous one, no work to do.. | 246 | // no cursors in this block and the previous one, no work to do.. | ||
243 | if (m_cursors.empty() && previousBlock->m_cursors.empty()) { | 247 | if (m_cursors.empty() && previousBlock->m_cursors.empty()) { | ||
244 | return; | 248 | return; | ||
245 | } | 249 | } | ||
246 | 250 | | |||
247 | // move all cursors because of the unwrapped line | 251 | // move all cursors because of the unwrapped line | ||
248 | // remember all ranges modified | 252 | // remember all ranges modified | ||
249 | QSet<TextRange *> changedRanges; | 253 | std::vector<TextRange *> changedRanges; | ||
250 | foreach (TextCursor *cursor, m_cursors) { | 254 | foreach (TextCursor *cursor, m_cursors) { | ||
251 | // this is the unwrapped line | 255 | // this is the unwrapped line | ||
252 | if (cursor->lineInBlock() == 0) { | 256 | if (cursor->lineInBlock() == 0) { | ||
253 | // patch column | 257 | // patch column | ||
254 | cursor->m_column += oldSizeOfPreviousLine; | 258 | cursor->m_column += oldSizeOfPreviousLine; | ||
255 | 259 | | |||
256 | // remember range, if any | 260 | // remember range, if any | ||
257 | if (cursor->kateRange()) { | 261 | if (cursor->kateRange()) { | ||
258 | changedRanges.insert(cursor->kateRange()); | 262 | cursor->kateRange()->m_isCheckValidityRequired = true; | ||
263 | changedRanges.push_back(cursor->kateRange()); | ||||
259 | } | 264 | } | ||
260 | } | 265 | } | ||
261 | } | 266 | } | ||
262 | 267 | | |||
263 | // move cursors of the moved line from previous block to this block now | 268 | // move cursors of the moved line from previous block to this block now | ||
264 | QSet<TextCursor *> newPreviousCursors; | 269 | QSet<TextCursor *> newPreviousCursors; | ||
265 | foreach (TextCursor *cursor, previousBlock->m_cursors) { | 270 | foreach (TextCursor *cursor, previousBlock->m_cursors) { | ||
266 | if (cursor->lineInBlock() == lastLineOfPreviousBlock) { | 271 | if (cursor->lineInBlock() == lastLineOfPreviousBlock) { | ||
267 | cursor->m_line = 0; | 272 | cursor->m_line = 0; | ||
268 | cursor->m_block = this; | 273 | cursor->m_block = this; | ||
269 | m_cursors.insert(cursor); | 274 | m_cursors.insert(cursor); | ||
270 | 275 | | |||
271 | // remember range, if any | 276 | // remember range, if any | ||
272 | if (cursor->kateRange()) { | 277 | if (cursor->kateRange()) { | ||
273 | changedRanges.insert(cursor->kateRange()); | 278 | cursor->kateRange()->m_isCheckValidityRequired = true; | ||
279 | changedRanges.push_back(cursor->kateRange()); | ||||
274 | } | 280 | } | ||
275 | } else { | 281 | } else { | ||
276 | newPreviousCursors.insert(cursor); | 282 | newPreviousCursors.insert(cursor); | ||
277 | } | 283 | } | ||
278 | } | 284 | } | ||
279 | previousBlock->m_cursors = newPreviousCursors; | 285 | previousBlock->m_cursors = newPreviousCursors; | ||
280 | 286 | | |||
281 | // fixup the ranges that might be effected, because they moved from last line to this block | 287 | // fixup the ranges that might be effected, because they moved from last line to this block | ||
282 | foreach (TextRange *range, changedRanges) { | 288 | // we might need to invalidate ranges or notify about their changes | ||
289 | for (TextRange *range : changedRanges) { | ||||
This loop now crash in the unit test ./bin/bug313759 )It works again, if I use a QSet, at that one location. cullmann: This loop now crash in the unit test
./bin/bug313759
=)
It works again, if I use a QSet, at… | |||||
Ok, doesn't work due to the issue that we might delete the range via notifier in checkValidity() :P cullmann: Ok, doesn't work due to the issue that we might delete the range via notifier in checkValidity… | |||||
Noob question: Would QPointer help? if (range && range->isValidityCheckRequired()) { loh.tar: Noob question: Would QPointer help?
if (range && range->isValidityCheckRequired()) { | |||||
As it is no QObject, no ;=) Actually, I think all workaround might be even more expensive than the QSet. cullmann: As it is no QObject, no ;=) Actually, I think all workaround might be even more expensive than… | |||||
290 | if (range->m_isCheckValidityRequired) { | ||||
283 | // update both blocks | 291 | // update both blocks | ||
284 | updateRange(range); | 292 | updateRange(range); | ||
285 | previousBlock->updateRange(range); | 293 | previousBlock->updateRange(range); | ||
286 | } | | |||
287 | 294 | | |||
288 | // check validity of all ranges, might invalidate them... | 295 | // afterwards check validity | ||
289 | foreach (TextRange *range, changedRanges) { | | |||
290 | range->checkValidity(); | 296 | range->checkValidity(); | ||
297 | range->m_isCheckValidityRequired = false; | ||||
298 | } | ||||
291 | } | 299 | } | ||
292 | 300 | | |||
293 | // be done | 301 | // be done | ||
294 | return; | 302 | return; | ||
295 | } | 303 | } | ||
296 | 304 | | |||
297 | // easy: just move text to previous line and remove current one | 305 | // easy: just move text to previous line and remove current one | ||
298 | const int oldSizeOfPreviousLine = m_lines.at(line - 1)->length(); | 306 | const int oldSizeOfPreviousLine = m_lines.at(line - 1)->length(); | ||
Show All 29 Lines | |||||
328 | 336 | | |||
329 | // no cursors in this block, no work to do.. | 337 | // no cursors in this block, no work to do.. | ||
330 | if (m_cursors.empty()) { | 338 | if (m_cursors.empty()) { | ||
331 | return; | 339 | return; | ||
332 | } | 340 | } | ||
333 | 341 | | |||
334 | // move all cursors because of the unwrapped line | 342 | // move all cursors because of the unwrapped line | ||
335 | // remember all ranges modified | 343 | // remember all ranges modified | ||
336 | QSet<TextRange *> changedRanges; | 344 | std::vector<TextRange *> changedRanges; | ||
337 | foreach (TextCursor *cursor, m_cursors) { | 345 | foreach (TextCursor *cursor, m_cursors) { | ||
338 | // skip cursors in lines in front of removed one | 346 | // skip cursors in lines in front of removed one | ||
339 | if (cursor->lineInBlock() < line) { | 347 | if (cursor->lineInBlock() < line) { | ||
340 | continue; | 348 | continue; | ||
341 | } | 349 | } | ||
342 | 350 | | |||
343 | // this is the unwrapped line | 351 | // this is the unwrapped line | ||
344 | if (cursor->lineInBlock() == line) { | 352 | if (cursor->lineInBlock() == line) { | ||
345 | // patch column | 353 | // patch column | ||
346 | cursor->m_column += oldSizeOfPreviousLine; | 354 | cursor->m_column += oldSizeOfPreviousLine; | ||
347 | } | 355 | } | ||
348 | 356 | | |||
349 | // patch line of cursor | 357 | // patch line of cursor | ||
350 | cursor->m_line--; | 358 | cursor->m_line--; | ||
351 | 359 | | |||
352 | // remember range, if any | 360 | // remember range, if any | ||
353 | if (cursor->kateRange()) { | 361 | if (cursor->kateRange()) { | ||
354 | changedRanges.insert(cursor->kateRange()); | 362 | cursor->kateRange()->m_isCheckValidityRequired = true; | ||
363 | changedRanges.push_back(cursor->kateRange()); | ||||
355 | } | 364 | } | ||
356 | } | 365 | } | ||
357 | 366 | | |||
358 | // check validity of all ranges, might invalidate them... | 367 | // we might need to invalidate ranges or notify about their changes | ||
359 | foreach (TextRange *range, changedRanges) { | 368 | for (TextRange *range : changedRanges) { | ||
369 | if (range->m_isCheckValidityRequired) { | ||||
360 | range->checkValidity(); | 370 | range->checkValidity(); | ||
371 | range->m_isCheckValidityRequired = false; | ||||
372 | } | ||||
361 | } | 373 | } | ||
362 | } | 374 | } | ||
363 | 375 | | |||
364 | void TextBlock::insertText(const KTextEditor::Cursor &position, const QString &text) | 376 | void TextBlock::insertText(const KTextEditor::Cursor &position, const QString &text) | ||
365 | { | 377 | { | ||
366 | // calc internal line | 378 | // calc internal line | ||
367 | int line = position.line() - startLine(); | 379 | int line = position.line() - startLine(); | ||
368 | 380 | | |||
Show All 20 Lines | |||||
389 | 401 | | |||
390 | // no cursors in this block, no work to do.. | 402 | // no cursors in this block, no work to do.. | ||
391 | if (m_cursors.empty()) { | 403 | if (m_cursors.empty()) { | ||
392 | return; | 404 | return; | ||
393 | } | 405 | } | ||
394 | 406 | | |||
395 | // move all cursors on the line which has the text inserted | 407 | // move all cursors on the line which has the text inserted | ||
396 | // remember all ranges modified | 408 | // remember all ranges modified | ||
397 | QSet<TextRange *> changedRanges; | 409 | std::vector<TextRange *> changedRanges; | ||
398 | foreach (TextCursor *cursor, m_cursors) { | 410 | foreach (TextCursor *cursor, m_cursors) { | ||
399 | // skip cursors not on this line! | 411 | // skip cursors not on this line! | ||
400 | if (cursor->lineInBlock() != line) { | 412 | if (cursor->lineInBlock() != line) { | ||
401 | continue; | 413 | continue; | ||
402 | } | 414 | } | ||
403 | 415 | | |||
404 | // skip cursors with too small column | 416 | // skip cursors with too small column | ||
405 | if (cursor->column() <= position.column()) { | 417 | if (cursor->column() <= position.column()) { | ||
406 | if (cursor->column() < position.column() || !cursor->m_moveOnInsert) { | 418 | if (cursor->column() < position.column() || !cursor->m_moveOnInsert) { | ||
407 | continue; | 419 | continue; | ||
408 | } | 420 | } | ||
409 | } | 421 | } | ||
410 | 422 | | |||
411 | // patch column of cursor | 423 | // patch column of cursor | ||
412 | if (cursor->m_column <= oldLength) { | 424 | if (cursor->m_column <= oldLength) { | ||
413 | cursor->m_column += text.size(); | 425 | cursor->m_column += text.size(); | ||
414 | } | 426 | } | ||
415 | 427 | | |||
416 | // special handling if cursor behind the real line, e.g. non-wrapping cursor in block selection mode | 428 | // special handling if cursor behind the real line, e.g. non-wrapping cursor in block selection mode | ||
417 | else if (cursor->m_column < textOfLine.size()) { | 429 | else if (cursor->m_column < textOfLine.size()) { | ||
418 | cursor->m_column = textOfLine.size(); | 430 | cursor->m_column = textOfLine.size(); | ||
419 | } | 431 | } | ||
420 | 432 | | |||
421 | // remember range, if any | 433 | // we only need to trigger checkValidity later if the range has feedback or might be invalidated | ||
422 | if (cursor->kateRange()) { | 434 | if (cursor->kateRange() && (cursor->kateRange()->feedback() || cursor->kateRange()->start().line() == cursor->kateRange()->end().line())) { | ||
423 | changedRanges.insert(cursor->kateRange()); | 435 | cursor->kateRange()->m_isCheckValidityRequired = true; | ||
436 | changedRanges.push_back(cursor->kateRange()); | ||||
424 | } | 437 | } | ||
425 | } | 438 | } | ||
426 | 439 | | |||
427 | // check validity of all ranges, might invalidate them... | 440 | // we might need to invalidate ranges or notify about their changes | ||
428 | foreach (TextRange *range, changedRanges) { | 441 | for (TextRange *range : changedRanges) { | ||
442 | if (range->m_isCheckValidityRequired) { | ||||
429 | range->checkValidity(); | 443 | range->checkValidity(); | ||
444 | range->m_isCheckValidityRequired = false; | ||||
445 | } | ||||
430 | } | 446 | } | ||
431 | } | 447 | } | ||
432 | 448 | | |||
433 | void TextBlock::removeText(const KTextEditor::Range &range, QString &removedText) | 449 | void TextBlock::removeText(const KTextEditor::Range &range, QString &removedText) | ||
434 | { | 450 | { | ||
435 | // calc internal line | 451 | // calc internal line | ||
436 | int line = range.start().line() - startLine(); | 452 | int line = range.start().line() - startLine(); | ||
437 | 453 | | |||
Show All 25 Lines | |||||
463 | 479 | | |||
464 | // no cursors in this block, no work to do.. | 480 | // no cursors in this block, no work to do.. | ||
465 | if (m_cursors.empty()) { | 481 | if (m_cursors.empty()) { | ||
466 | return; | 482 | return; | ||
467 | } | 483 | } | ||
468 | 484 | | |||
469 | // move all cursors on the line which has the text removed | 485 | // move all cursors on the line which has the text removed | ||
470 | // remember all ranges modified | 486 | // remember all ranges modified | ||
471 | QSet<TextRange *> changedRanges; | 487 | std::vector<TextRange *> changedRanges; | ||
472 | foreach (TextCursor *cursor, m_cursors) { | 488 | foreach (TextCursor *cursor, m_cursors) { | ||
473 | // skip cursors not on this line! | 489 | // skip cursors not on this line! | ||
474 | if (cursor->lineInBlock() != line) { | 490 | if (cursor->lineInBlock() != line) { | ||
475 | continue; | 491 | continue; | ||
476 | } | 492 | } | ||
477 | 493 | | |||
478 | // skip cursors with too small column | 494 | // skip cursors with too small column | ||
479 | if (cursor->column() <= range.start().column()) { | 495 | if (cursor->column() <= range.start().column()) { | ||
480 | continue; | 496 | continue; | ||
481 | } | 497 | } | ||
482 | 498 | | |||
483 | // patch column of cursor | 499 | // patch column of cursor | ||
484 | if (cursor->column() <= range.end().column()) { | 500 | if (cursor->column() <= range.end().column()) { | ||
485 | cursor->m_column = range.start().column(); | 501 | cursor->m_column = range.start().column(); | ||
486 | } else { | 502 | } else { | ||
487 | cursor->m_column -= (range.end().column() - range.start().column()); | 503 | cursor->m_column -= (range.end().column() - range.start().column()); | ||
488 | } | 504 | } | ||
489 | 505 | | |||
490 | // remember range, if any | 506 | // we only need to trigger checkValidity later if the range has feedback or might be invalidated | ||
491 | if (cursor->kateRange()) { | 507 | if (cursor->kateRange() && (cursor->kateRange()->feedback() || cursor->kateRange()->start().line() == cursor->kateRange()->end().line())) { | ||
492 | changedRanges.insert(cursor->kateRange()); | 508 | cursor->kateRange()->m_isCheckValidityRequired = true; | ||
509 | changedRanges.push_back(cursor->kateRange()); | ||||
493 | } | 510 | } | ||
494 | } | 511 | } | ||
495 | 512 | | |||
496 | // check validity of all ranges, might invalidate them... | 513 | // we might need to invalidate ranges or notify about their changes | ||
497 | foreach (TextRange *range, changedRanges) { | 514 | for (TextRange *range : changedRanges) { | ||
515 | if (range->m_isCheckValidityRequired) { | ||||
498 | range->checkValidity(); | 516 | range->checkValidity(); | ||
517 | range->m_isCheckValidityRequired = false; | ||||
518 | } | ||||
499 | } | 519 | } | ||
500 | } | 520 | } | ||
501 | 521 | | |||
502 | void TextBlock::debugPrint(int blockIndex) const | 522 | void TextBlock::debugPrint(int blockIndex) const | ||
503 | { | 523 | { | ||
504 | // print all blocks | 524 | // print all blocks | ||
505 | for (int i = 0; i < m_lines.size(); ++i) | 525 | for (int i = 0; i < m_lines.size(); ++i) | ||
506 | printf("%4d - %4d : %4d : '%s'\n", blockIndex, startLine() + i | 526 | printf("%4d - %4d : %4d : '%s'\n", blockIndex, startLine() + i | ||
▲ Show 20 Lines • Show All 219 Lines • Show Last 20 Lines |
You can use unordered_set, so you don't need m_isCheckValidityRequired any more. It can be applied to other places as well.