forked from qt-creator/qt-creator
Initial support for emacs like fill-paragraph.
Merge-request: 882 Reviewed-by: Thorbjørn Lindeijer <thorbjorn.lindeijer@nokia.com>
This commit is contained in:
committed by
Thorbjørn Lindeijer
parent
4eda7c27f3
commit
f053ec8c14
@@ -3850,6 +3850,129 @@ void BaseTextEditor::format()
|
|||||||
cursor.endEditBlock();
|
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()
|
void BaseTextEditor::unCommentSelection()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -483,6 +483,7 @@ public:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
virtual void format();
|
virtual void format();
|
||||||
|
virtual void rewrapParagraph();
|
||||||
virtual void unCommentSelection();
|
virtual void unCommentSelection();
|
||||||
virtual void setFontSettings(const TextEditor::FontSettings &);
|
virtual void setFontSettings(const TextEditor::FontSettings &);
|
||||||
void setFontSettingsIfVisible(const TextEditor::FontSettings &);
|
void setFontSettingsIfVisible(const TextEditor::FontSettings &);
|
||||||
|
|||||||
@@ -141,6 +141,12 @@ void TextEditorActionHandler::createActions()
|
|||||||
advancedMenu->addAction(command, Core::Constants::G_EDIT_FORMAT);
|
advancedMenu->addAction(command, Core::Constants::G_EDIT_FORMAT);
|
||||||
connect(m_formatAction, SIGNAL(triggered(bool)), this, SLOT(formatAction()));
|
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 = new QAction(tr("&Visualize Whitespace"), this);
|
||||||
m_visualizeWhitespaceAction->setCheckable(true);
|
m_visualizeWhitespaceAction->setCheckable(true);
|
||||||
@@ -398,6 +404,7 @@ FUNCTION2(copyAction, copy)
|
|||||||
FUNCTION2(cutAction, cut)
|
FUNCTION2(cutAction, cut)
|
||||||
FUNCTION2(pasteAction, paste)
|
FUNCTION2(pasteAction, paste)
|
||||||
FUNCTION2(formatAction, format)
|
FUNCTION2(formatAction, format)
|
||||||
|
FUNCTION2(rewrapParagraphAction, rewrapParagraph)
|
||||||
FUNCTION2(selectAllAction, selectAll)
|
FUNCTION2(selectAllAction, selectAll)
|
||||||
FUNCTION(cleanWhitespace)
|
FUNCTION(cleanWhitespace)
|
||||||
FUNCTION(unCommentSelection)
|
FUNCTION(unCommentSelection)
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ private slots:
|
|||||||
void gotoAction();
|
void gotoAction();
|
||||||
void printAction();
|
void printAction();
|
||||||
void formatAction();
|
void formatAction();
|
||||||
|
void rewrapParagraphAction();
|
||||||
void setVisualizeWhitespace(bool);
|
void setVisualizeWhitespace(bool);
|
||||||
void cleanWhitespace();
|
void cleanWhitespace();
|
||||||
void setTextWrapping(bool);
|
void setTextWrapping(bool);
|
||||||
@@ -125,6 +126,7 @@ private:
|
|||||||
QAction *m_gotoAction;
|
QAction *m_gotoAction;
|
||||||
QAction *m_printAction;
|
QAction *m_printAction;
|
||||||
QAction *m_formatAction;
|
QAction *m_formatAction;
|
||||||
|
QAction *m_rewrapParagraphAction;
|
||||||
QAction *m_visualizeWhitespaceAction;
|
QAction *m_visualizeWhitespaceAction;
|
||||||
QAction *m_cleanWhitespaceAction;
|
QAction *m_cleanWhitespaceAction;
|
||||||
QAction *m_textWrappingAction;
|
QAction *m_textWrappingAction;
|
||||||
|
|||||||
@@ -60,8 +60,9 @@ const char * const CUT_LINE = "TextEditor.CutLine";
|
|||||||
const char * const DELETE_LINE = "TextEditor.DeleteLine";
|
const char * const DELETE_LINE = "TextEditor.DeleteLine";
|
||||||
const char * const DELETE_WORD = "TextEditor.DeleteWord";
|
const char * const DELETE_WORD = "TextEditor.DeleteWord";
|
||||||
const char * const SELECT_ENCODING = "TextEditor.SelectEncoding";
|
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_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_TEXT = "text/plain";
|
||||||
const char * const C_TEXTEDITOR_MIMETYPE_XML = "application/xml";
|
const char * const C_TEXTEDITOR_MIMETYPE_XML = "application/xml";
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user