bool TabSettings::guessSpacesForTabs(const QTextBlock &_block) const { if (m_tabPolicy == MixedTabPolicy && _block.isValid()) { const QTextDocument *doc = _block.document(); QVector<QTextBlock> currentBlocks(2, _block); // [0] looks back; [1] looks forward int maxLookAround = 100; while (maxLookAround-- > 0) { if (currentBlocks.at(0).isValid()) currentBlocks[0] = currentBlocks.at(0).previous(); if (currentBlocks.at(1).isValid()) currentBlocks[1] = currentBlocks.at(1).next(); bool done = true; foreach (const QTextBlock &block, currentBlocks) { if (block.isValid()) done = false; if (!block.isValid() || block.length() == 0) continue; const QChar firstChar = doc->characterAt(block.position()); if (firstChar == QLatin1Char(' ')) { return true; } else if (firstChar == QLatin1Char('\t')) { return false; } } if (done) break; } } return m_tabPolicy != TabsOnlyTabPolicy; }
ChangeListLevelCommand::ChangeListLevelCommand(const QTextCursor &cursor, ChangeListLevelCommand::CommandType type, int coef, KUndo2Command *parent) : KoTextCommandBase(parent), m_type(type), m_coefficient(coef), m_first(true) { setText(kundo2_i18n("Change List Level")); int selectionStart = qMin(cursor.anchor(), cursor.position()); int selectionEnd = qMax(cursor.anchor(), cursor.position()); QTextBlock block = cursor.block().document()->findBlock(selectionStart); bool oneOf = (selectionStart == selectionEnd); //ensures the block containing the cursor is selected in that case while (block.isValid() && ((block.position() < selectionEnd) || oneOf)) { m_blocks.append(block); if (block.textList()) { m_lists.insert(m_blocks.size() - 1, KoTextDocument(block.document()).list(block.textList())); Q_ASSERT(m_lists.value(m_blocks.size() - 1)); m_levels.insert(m_blocks.size() - 1, effectiveLevel(m_lists.value(m_blocks.size() - 1)->level(block))); } oneOf = false; block = block.next(); } }
void CodeFormatter::updateStateUntil(const QTextBlock &endBlock) { QStack<State> previousState = initialState(); QTextBlock it = endBlock.document()->firstBlock(); // find the first block that needs recalculation for (; it.isValid() && it != endBlock; it = it.next()) { BlockData blockData; if (!loadBlockData(it, &blockData)) break; if (blockData.m_blockRevision != it.revision()) break; if (previousState != blockData.m_beginState) break; if (loadLexerState(it) == -1) break; previousState = blockData.m_endState; } if (it == endBlock) return; // update everthing until endBlock for (; it.isValid() && it != endBlock; it = it.next()) { recalculateStateAfter(it); } // invalidate everything below by marking the state in endBlock as invalid if (it.isValid()) { BlockData invalidBlockData; saveBlockData(&it, invalidBlockData); } }
QString ToCGenerator::fetchBookmarkRef(const QTextBlock &block, KoTextRangeManager *textRangeManager) { QHash<int, KoTextRange *> ranges = textRangeManager->textRangesChangingWithin(block.document(), block.position(), block.position() + block.length(), block.position(), block.position() + block.length()); foreach (KoTextRange *range, ranges) { KoBookmark *bookmark = dynamic_cast<KoBookmark *>(range); if (bookmark) { return bookmark->name(); } }
int AutoCompleter::paragraphSeparatorAboutToBeInserted(QTextCursor &cursor) { QTextBlock block = cursor.block(); const QString text = block.text().trimmed(); if (text == "end" || text == "else" || text.startsWith("elsif") || text.startsWith("rescue") || text == "ensure") { Indenter indenter(const_cast<QTextDocument*>(block.document())); indenter.indentBlock(block, QChar(), tabSettings()); } return 0; // This implementation is buggy #if 0 const QString textFromCursor = text.mid(cursor.positionInBlock()).trimmed(); if (!textFromCursor.isEmpty()) return 0; if (Language::symbolDefinition.indexIn(text) == -1 && Language::startOfBlock.indexIn(text) == -1) { return 0; } int spaces = 0; for (const QChar c : text) { if (!c.isSpace()) break; spaces++; } QString indent = text.left(spaces); QString line; QTextBlock nextBlock = block.next(); while (nextBlock.isValid()) { line = nextBlock.text(); if (Language::endKeyword.indexIn(line) != -1 && line.startsWith(indent)) return 0; if (!line.trimmed().isEmpty()) break; nextBlock = nextBlock.next(); } int pos = cursor.position(); cursor.insertBlock(); cursor.insertText("end"); cursor.setPosition(pos); return 1; #endif }
// Add extra text in case of the empty line or the line starting with ')'. // Track such extra pieces of text in isInsideModifiedLine(). int forceIndentWithExtraText(QByteArray &buffer, const QTextBlock &block, bool secondTry) { const QString blockText = block.text(); int firstNonWhitespace = Utils::indexOf(blockText, [](const QChar &ch) { return !ch.isSpace(); }); int utf8Offset = Utils::Text::utf8NthLineOffset(block.document(), buffer, block.blockNumber() + 1); if (firstNonWhitespace > 0) utf8Offset += firstNonWhitespace; else utf8Offset += blockText.length(); const bool closingParenBlock = firstNonWhitespace >= 0 && blockText.at(firstNonWhitespace) == ')'; int extraLength = 0; if (firstNonWhitespace < 0 || closingParenBlock) { //This extra text works for the most cases. QByteArray dummyText("a;a;"); // Search for previous character QTextBlock prevBlock = block.previous(); bool prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty(); while (prevBlockIsEmpty) { prevBlock = prevBlock.previous(); prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty(); } if (closingParenBlock || prevBlock.text().endsWith(',')) dummyText = "&& a"; buffer.insert(utf8Offset, dummyText); extraLength += dummyText.length(); } if (secondTry) { int nextLinePos = buffer.indexOf('\n', utf8Offset); if (nextLinePos < 0) nextLinePos = buffer.size() - 1; if (nextLinePos > 0) { // If first try was not successful try to put ')' in the end of the line to close possibly // unclosed parentheses. // TODO: Does it help to add different endings depending on the context? buffer.insert(nextLinePos, ')'); extraLength += 1; } } return extraLength; }
int formattingRangeStart(const QTextBlock ¤tBlock, const QByteArray &buffer, int documentRevision) { QTextBlock prevBlock = currentBlock.previous(); while ((prevBlock.position() > 0 || prevBlock.length() > 0) && prevBlock.revision() != documentRevision) { // Find the first block with not matching revision. prevBlock = prevBlock.previous(); } if (prevBlock.revision() == documentRevision) prevBlock = prevBlock.next(); return Utils::Text::utf8NthLineOffset(prevBlock.document(), buffer, prevBlock.blockNumber() + 1); }
int indentationForBlock(const TextEditor::Replacements &toReplace, const QByteArray &buffer, const QTextBlock ¤tBlock) { const int utf8Offset = Utils::Text::utf8NthLineOffset(currentBlock.document(), buffer, currentBlock.blockNumber() + 1); auto replacementIt = std::find_if(toReplace.begin(), toReplace.end(), [utf8Offset](const TextEditor::Replacement &replacement) { return replacement.offset == utf8Offset - 1; }); if (replacementIt == toReplace.end()) return -1; int afterLineBreak = replacementIt->text.lastIndexOf('\n'); afterLineBreak = (afterLineBreak < 0) ? 0 : afterLineBreak + 1; return static_cast<int>(replacementIt->text.size() - afterLineBreak); }
static int findClosingConstruct(const QTextBlock &block) { if (!block.isValid()) return -1; TextBlockData *blockData = reinterpret_cast<TextBlockData*>(block.userData()); if (!blockData) return -1; if (blockData->bracketPositions.isEmpty()) return -1; const QTextDocument *doc = block.document(); int offset = block.position(); foreach (int pos, blockData->bracketPositions) { int absPos = offset + pos; if (doc->characterAt(absPos) == '{') { int matchPos = findClosingMatch(doc, absPos); if (matchPos >= 0) return matchPos; } } return -1; }
QHash<QTextList *, QString> KoTextWriter::saveListStyles(QTextBlock block, int to) { QHash<KoList *, QString> generatedLists; QHash<QTextList *, QString> listStyles; KoTextDocument document(block.document()); for (;block.isValid() && ((to == -1) || (block.position() < to)); block = block.next()) { QTextList *textList = block.textList(); if (!textList) continue; if (KoList *list = document.list(block)) { if (generatedLists.contains(list)) { if (!listStyles.contains(textList)) listStyles.insert(textList, generatedLists.value(list)); continue; } KoListStyle *listStyle = list->style(); bool automatic = listStyle->styleId() == 0; KoGenStyle style(automatic ? KoGenStyle::StyleListAuto : KoGenStyle::StyleList); listStyle->saveOdf(style); QString generatedName = d->context.mainStyles().lookup(style, listStyle->name(), KoGenStyles::AllowDuplicates); listStyles[textList] = generatedName; generatedLists.insert(list, generatedName); } else { if (listStyles.contains(textList)) continue; KoListLevelProperties llp = KoListLevelProperties::fromTextList(textList); KoGenStyle style(KoGenStyle::StyleListAuto); KoListStyle listStyle; listStyle.setLevelProperties(llp); listStyle.saveOdf(style); QString generatedName = d->context.mainStyles().lookup(style, listStyle.name()); listStyles[textList] = generatedName; } } return listStyles; }
void GoCodeFormatter::updateStateUntil(const QTextBlock &endBlock) { QStack<CodeState> previousState = initialState(); QTextBlock it = endBlock.document()->firstBlock(); // find the first block that needs recalculation while (it.isValid() && it != endBlock) { BlockData blockData; if (!loadBlockData(it, &blockData)) break; if (blockData.revision != it.revision()) break; if (previousState.isEmpty() || blockData.beginState.isEmpty() || previousState != blockData.beginState) break; if (TextEditor::TextDocumentLayout::lexerState(endBlock) == -1) break; previousState = blockData.endState; it = it.next(); } if (it == endBlock) // No need to recalculate return; // update everthing until endBlock while (it.isValid() && it != endBlock) { recalculateStateAfter(it); it = it.next(); } // invalidate everything below by marking the state in endBlock as invalid if (it.isValid()) { BlockData invalidBlockData; saveBlockData(&it, invalidBlockData); } }