diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp index 189b9a505378cb477877b67ff7989d238b4b196f..b61236cdd95666b5d256b0e3ef17b1606270805e 100644 --- a/src/plugins/texteditor/basetexteditor.cpp +++ b/src/plugins/texteditor/basetexteditor.cpp @@ -3850,6 +3850,129 @@ void BaseTextEditor::format() cursor.endEditBlock(); } +void BaseTextEditor::rewrapParagraph() +{ + const int paragraphWidth = displaySettings().m_wrapColumn; + const QRegExp anyLettersOrNumbers = QRegExp("\\w"); + const int tabSize = tabSettings().m_tabSize; + + QTextCursor cursor = textCursor(); + cursor.beginEditBlock(); + + // Find start of paragraph. + + while (cursor.movePosition(QTextCursor::PreviousBlock, QTextCursor::MoveAnchor)) { + QTextBlock block = cursor.block(); + QString text = block.text(); + + // If this block is empty, move marker back to previous and terminate. + if (!text.contains(anyLettersOrNumbers)) { + cursor.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor); + break; + } + } + + cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::MoveAnchor); + + // Find indent level of current block. + + int indentLevel = 0; + QString text = cursor.block().text(); + + for (int i = 0; i < text.length(); i++) { + const QChar ch = text.at(i); + + if (ch == QLatin1Char(' ')) + indentLevel++; + else if (ch == QLatin1Char('\t')) + indentLevel += tabSize - (indentLevel % tabSize); + else + break; + } + + // If there is a common prefix, it should be kept and expanded to all lines. + // this allows nice reflowing of doxygen style comments. + QTextCursor nextBlock = cursor; + QString commonPrefix; + + if (nextBlock.movePosition(QTextCursor::NextBlock)) + { + QString nText = nextBlock.block().text(); + int maxLength = qMin(text.length(), nText.length()); + + for (int i = 0; i < maxLength; ++i) { + const QChar ch = text.at(i); + + if (ch != nText[i] || ch.isLetterOrNumber()) + break; + commonPrefix.append(ch); + } + } + + + // Find end of paragraph. + while (cursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor)) { + QString text = cursor.block().text(); + + if (!text.contains(anyLettersOrNumbers)) + break; + } + + + QString selectedText = cursor.selectedText(); + + // Preserve initial indent level.or common prefix. + QString spacing; + + if (commonPrefix.isEmpty()) { + spacing = tabSettings().indentationString(0, indentLevel); + } else { + spacing = commonPrefix; + indentLevel = commonPrefix.length(); + } + + int currentLength = indentLevel; + QString result; + result.append(spacing); + + // Remove existing instances of any common prefix from paragraph to + // reflow. + selectedText.remove(0, commonPrefix.length()); + commonPrefix.prepend(QChar::ParagraphSeparator); + selectedText.replace(commonPrefix, QLatin1String("\n")); + + // remove any repeated spaces, trim lines to PARAGRAPH_WIDTH width and + // keep the same indentation level as first line in paragraph. + QString currentWord; + + for (int i = 0; i < selectedText.length(); ++i) { + QChar ch = selectedText.at(i); + if (ch.isSpace()) { + if (!currentWord.isEmpty()) { + currentLength += currentWord.length() + 1; + + if (currentLength > paragraphWidth - indentLevel) { + currentLength = currentWord.length() + 1 + indentLevel; + result.append(QChar::ParagraphSeparator); + result.append(spacing); + } + + result.append(currentWord); + result.append(QLatin1String(" ")); + currentWord.clear(); + } + + continue; + } + + currentWord.append(ch); + } + result.append(QChar::ParagraphSeparator); + + cursor.insertText(result); + cursor.endEditBlock(); +} + void BaseTextEditor::unCommentSelection() { } diff --git a/src/plugins/texteditor/basetexteditor.h b/src/plugins/texteditor/basetexteditor.h index 9fb764aae2f1ebc68e2240ae6bd39e642e0f04a8..cc8df867c5c20ebec023263a307824297f1c9991 100644 --- a/src/plugins/texteditor/basetexteditor.h +++ b/src/plugins/texteditor/basetexteditor.h @@ -483,6 +483,7 @@ public: public slots: virtual void format(); + virtual void rewrapParagraph(); virtual void unCommentSelection(); virtual void setFontSettings(const TextEditor::FontSettings &); void setFontSettingsIfVisible(const TextEditor::FontSettings &); diff --git a/src/plugins/texteditor/texteditoractionhandler.cpp b/src/plugins/texteditor/texteditoractionhandler.cpp index ff6933cabe18a321f5878e5d8cd21cbb342bd53e..abf81e0b5767be2333e3df55841382dcfb986d43 100644 --- a/src/plugins/texteditor/texteditoractionhandler.cpp +++ b/src/plugins/texteditor/texteditoractionhandler.cpp @@ -141,6 +141,12 @@ void TextEditorActionHandler::createActions() advancedMenu->addAction(command, Core::Constants::G_EDIT_FORMAT); connect(m_formatAction, SIGNAL(triggered(bool)), this, SLOT(formatAction())); + m_rewrapParagraphAction = new QAction(tr("&Rewrap Paragraph"), this); + command = am->registerAction(m_rewrapParagraphAction, TextEditor::Constants::REWRAP_PARAGRAPH, m_contextId); + //command->setDefaultKeySequence(QKeySequence(tr("Alt+Q"))); (No default key sequence for now.) + advancedMenu->addAction(command, Core::Constants::G_EDIT_FORMAT); + connect(m_rewrapParagraphAction, SIGNAL(triggered(bool)), this, SLOT(rewrapParagraphAction())); + m_visualizeWhitespaceAction = new QAction(tr("&Visualize Whitespace"), this); m_visualizeWhitespaceAction->setCheckable(true); @@ -398,6 +404,7 @@ FUNCTION2(copyAction, copy) FUNCTION2(cutAction, cut) FUNCTION2(pasteAction, paste) FUNCTION2(formatAction, format) +FUNCTION2(rewrapParagraphAction, rewrapParagraph) FUNCTION2(selectAllAction, selectAll) FUNCTION(cleanWhitespace) FUNCTION(unCommentSelection) diff --git a/src/plugins/texteditor/texteditoractionhandler.h b/src/plugins/texteditor/texteditoractionhandler.h index c782ff9b8388a4715e832b33a78c02e08feac812..a184ac6e44269fad53200d9588c20f5d44eef743 100644 --- a/src/plugins/texteditor/texteditoractionhandler.h +++ b/src/plugins/texteditor/texteditoractionhandler.h @@ -91,6 +91,7 @@ private slots: void gotoAction(); void printAction(); void formatAction(); + void rewrapParagraphAction(); void setVisualizeWhitespace(bool); void cleanWhitespace(); void setTextWrapping(bool); @@ -125,6 +126,7 @@ private: QAction *m_gotoAction; QAction *m_printAction; QAction *m_formatAction; + QAction *m_rewrapParagraphAction; QAction *m_visualizeWhitespaceAction; QAction *m_cleanWhitespaceAction; QAction *m_textWrappingAction; diff --git a/src/plugins/texteditor/texteditorconstants.h b/src/plugins/texteditor/texteditorconstants.h index 18d194929876ce02370f0df44e79288598dd85c6..8b83ea27a13bc975363ecf78f8425a446c6b66d1 100644 --- a/src/plugins/texteditor/texteditorconstants.h +++ b/src/plugins/texteditor/texteditorconstants.h @@ -60,8 +60,9 @@ const char * const CUT_LINE = "TextEditor.CutLine"; const char * const DELETE_LINE = "TextEditor.DeleteLine"; const char * const DELETE_WORD = "TextEditor.DeleteWord"; const char * const SELECT_ENCODING = "TextEditor.SelectEncoding"; +const char * const REWRAP_PARAGRAPH = "TextEditor.RewrapParagraph"; const char * const GOTO_OPENING_PARENTHESIS = "TextEditor.GotoOpeningParenthesis"; -const char * const GOTO_CLOSING_PARENTHESIS = "TextEditor.GotoOpeningParenthesis"; +const char * const GOTO_CLOSING_PARENTHESIS = "TextEditor.GotoClosingParenthesis"; const char * const C_TEXTEDITOR_MIMETYPE_TEXT = "text/plain"; const char * const C_TEXTEDITOR_MIMETYPE_XML = "application/xml";