diff --git a/src/plugins/coreplugin/coreconstants.h b/src/plugins/coreplugin/coreconstants.h index 4122b1afb51ec36abd685448824295c49e8610f0..a21e52ab06149a07f3de5b0464ea3f0e1850173c 100644 --- a/src/plugins/coreplugin/coreconstants.h +++ b/src/plugins/coreplugin/coreconstants.h @@ -180,6 +180,7 @@ const char * const G_EDIT_OTHER = "QtCreator.Group.Edit.Other"; // advanced edit menu groups const char * const G_EDIT_FORMAT = "QtCreator.Group.Edit.Format"; +const char * const G_EDIT_REFORMAT = "QtCreator.Group.Edit.Reformat"; const char * const G_EDIT_COLLAPSING = "QtCreator.Group.Edit.Collapsing"; const char * const G_EDIT_FONT = "QtCreator.Group.Edit.Font"; const char * const G_EDIT_EDITOR = "QtCreator.Group.Edit.Editor"; diff --git a/src/plugins/duieditor/duicodeformatter.cpp b/src/plugins/duieditor/duicodeformatter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..feb88982f8f21f4db8f0487e26bd25786700a8c9 --- /dev/null +++ b/src/plugins/duieditor/duicodeformatter.cpp @@ -0,0 +1,92 @@ +#include "duicodeformatter.h" +#include "qmljsast_p.h" + +using namespace DuiEditor::Internal; +using namespace QmlJS; +using namespace QmlJS::AST; + +DuiCodeFormatter::DuiCodeFormatter() +{ +} + +DuiCodeFormatter::~DuiCodeFormatter() +{ +} + +bool DuiCodeFormatter::visit(QmlJS::AST::UiProgram *ast) +{ + Node::accept(ast->imports, this); + + if (ast->imports && ast->members) + newline(); + + Node::accept(ast->members, this); + + return false; +} + +QString DuiCodeFormatter::operator()(QmlJS::AST::UiProgram *ast, const QString &originalSource, const QList<QmlJS::AST::SourceLocation> &comments, int start, int end) +{ + m_result.clear(); + m_result.reserve(originalSource.length() * 2); + m_originalSource = originalSource; + m_start = start; + m_end = end; + + Node::acceptChild(ast, this); + + return m_result; +} + +bool DuiCodeFormatter::visit(UiImport *ast) +{ + append("import "); + append(ast->fileNameToken); + + if (ast->versionToken.isValid()) { + append(' '); + append(ast->versionToken); + } + + if (ast->asToken.isValid()) { + append(" as "); + append(ast->importIdToken); + } + + if (ast->semicolonToken.isValid()) + append(';'); + + newline(); + + return false; +} + +bool DuiCodeFormatter::visit(UiObjectDefinition *ast) +{ + indent(); + Node::accept(ast->qualifiedTypeNameId, this); + append(' '); + Node::accept(ast->initializer, this); + newline(); + + return false; +} + +bool DuiCodeFormatter::visit(QmlJS::AST::UiQualifiedId *ast) +{ + for (UiQualifiedId *it = ast; it; it = it->next) { + append(it->name->asString()); + + if (it->next) + append('.'); + } + + return false; +} + +bool DuiCodeFormatter::visit(QmlJS::AST::UiObjectInitializer *ast) +{ + append(ast->lbraceToken.offset, ast->rbraceToken.end() - ast->lbraceToken.offset); + + return false; +} diff --git a/src/plugins/duieditor/duicodeformatter.h b/src/plugins/duieditor/duicodeformatter.h new file mode 100644 index 0000000000000000000000000000000000000000..71077dfbef4fda730325aad89945d0516d2ec35f --- /dev/null +++ b/src/plugins/duieditor/duicodeformatter.h @@ -0,0 +1,82 @@ +#ifndef DUICODEFORMATTER_H +#define DUICODEFORMATTER_H + +#include <QString> + +#include "qmljsastfwd_p.h" +#include "qmljsastvisitor_p.h" +#include "qmljsengine_p.h" + +namespace DuiEditor { +namespace Internal { + +class DuiCodeFormatter: protected QmlJS::AST::Visitor +{ +public: + DuiCodeFormatter(); + ~DuiCodeFormatter(); + + QString operator()(QmlJS::AST::UiProgram *ast, const QString &originalSource, const QList<QmlJS::AST::SourceLocation> &comments, int start = -1, int end = -1); + +protected: + virtual bool visit(QmlJS::AST::UiProgram *ast); +// virtual bool visit(UiImportList *ast); + virtual bool visit(QmlJS::AST::UiImport *ast); +// virtual bool visit(UiPublicMember *ast); +// virtual bool visit(UiSourceElement *ast); + virtual bool visit(QmlJS::AST::UiObjectDefinition *ast); + virtual bool visit(QmlJS::AST::UiObjectInitializer *ast); +// virtual bool visit(UiObjectBinding *ast); +// virtual bool visit(UiScriptBinding *ast); +// virtual bool visit(UiArrayBinding *ast); +// virtual bool visit(UiObjectMemberList *ast); +// virtual bool visit(UiArrayMemberList *ast); + virtual bool visit(QmlJS::AST::UiQualifiedId *ast); +// virtual bool visit(UiSignature *ast); +// virtual bool visit(UiFormalList *ast); +// virtual bool visit(UiFormal *ast); +// +// virtual void endVisit(UiProgram *ast); +// virtual void endVisit(UiImport *ast); +// virtual void endVisit(UiPublicMember *ast); +// virtual void endVisit(UiSourceElement *ast); +// virtual void endVisit(UiObjectDefinition *ast); +// virtual void endVisit(UiObjectInitializer *ast); +// virtual void endVisit(UiObjectBinding *ast); +// virtual void endVisit(UiScriptBinding *ast); +// virtual void endVisit(UiArrayBinding *ast); +// virtual void endVisit(UiObjectMemberList *ast); +// virtual void endVisit(UiArrayMemberList *ast); +// virtual void endVisit(UiQualifiedId *ast); +// virtual void endVisit(UiSignature *ast); +// virtual void endVisit(UiFormalList *ast); +// virtual void endVisit(UiFormal *ast); + +private: + void append(char c) { m_result += c; } + void append(char *s) { m_result += s; } + void append(const QString &s) { m_result += s; } + void append(const QmlJS::AST::SourceLocation &loc) { m_result += textAt(loc); } + void append(int pos, int len) { append(textAt(pos, len)); } + + QString textAt(const QmlJS::AST::SourceLocation &loc) const + { return textAt(loc.offset, loc.length); } + + QString textAt(int pos, int len) const + { return m_originalSource.mid(pos, len); } + + void indent() { if (m_indentDepth) append(QString(' ', m_indentDepth)); } + void newline() { append('\n'); } + +private: + QString m_result; + QString m_originalSource; + int m_start; + int m_end; + unsigned m_indentDepth; +}; + +} // namespace Internal +} // namespace DuiEditor + +#endif // DUICODEFORMATTER_H diff --git a/src/plugins/duieditor/duieditor.cpp b/src/plugins/duieditor/duieditor.cpp index 97bd6940d42bc441a9c2411eb6a1a8a5cc40f12e..7e29259abb60a4155be4a34932fa0700b56fb0c4 100644 --- a/src/plugins/duieditor/duieditor.cpp +++ b/src/plugins/duieditor/duieditor.cpp @@ -34,12 +34,14 @@ #include "duidocument.h" #include "duimodelmanager.h" -#include "rewriter_p.h" - #include "qmljsastvisitor_p.h" #include "qmljsast_p.h" #include "qmljsengine_p.h" +#include "rewriter_p.h" + +#include "navigationtokenfinder.h" + #include <coreplugin/icore.h> #include <coreplugin/actionmanager/actionmanager.h> #include <extensionsystem/pluginmanager.h> @@ -67,7 +69,6 @@ enum { using namespace QmlJS; using namespace QmlJS::AST; - namespace DuiEditor { namespace Internal { @@ -702,6 +703,35 @@ void ScriptEditor::createToolBar(ScriptEditorEditable *editable) toolBar->insertWidget(actions.first(), m_methodCombo); } +TextEditor::BaseTextEditor::Link ScriptEditor::findLinkAt(const QTextCursor &cursor, bool resolveTarget) +{ + Link link; + + if (!m_modelManager) + return link; + + const Snapshot snapshot = m_modelManager->snapshot(); + DuiDocument::Ptr doc = snapshot.document(file()->fileName()); + if (!doc) + return link; + + NavigationTokenFinder finder; + if (finder(doc->program(), cursor.position(), resolveTarget)) { + link.fileName = file()->fileName(); + link.pos = finder.linkPosition(); + link.length = finder.linkLength(); + link.line = finder.targetLine(); + link.column = finder.targetColumn() - 1; + } + + return link; +} + +void ScriptEditor::reformat(QTextDocument *, QTextBlock block) +{ + // TODO (EV) +} + void ScriptEditor::contextMenuEvent(QContextMenuEvent *e) { QMenu *menu = createStandardContextMenu(); diff --git a/src/plugins/duieditor/duieditor.h b/src/plugins/duieditor/duieditor.h index 583153a12ed1a95044f796c1ed132ef2e2c20376..9e73fae908c5b7e79f0a14b009b77f748fc35b2b 100644 --- a/src/plugins/duieditor/duieditor.h +++ b/src/plugins/duieditor/duieditor.h @@ -131,6 +131,8 @@ protected: void contextMenuEvent(QContextMenuEvent *e); TextEditor::BaseTextEditorEditable *createEditableInterface(); void createToolBar(ScriptEditorEditable *editable); + TextEditor::BaseTextEditor::Link findLinkAt(const QTextCursor &cursor, bool resolveTarget = true); + virtual void reformat(QTextDocument *doc, QTextBlock block); private: virtual bool isElectricCharacter(const QChar &ch) const; diff --git a/src/plugins/duieditor/duieditor.pro b/src/plugins/duieditor/duieditor.pro index 4d37e3fbf0f413454f61907774392326e4fd0a0c..6a400aa9480abf8b98db6a589fa756fbb03eaf4c 100644 --- a/src/plugins/duieditor/duieditor.pro +++ b/src/plugins/duieditor/duieditor.pro @@ -19,7 +19,9 @@ HEADERS += duieditor.h \ duicompletionvisitor.h \ duimodelmanagerinterface.h \ duieditor_global.h \ - duimodelmanager.h + duimodelmanager.h \ + duicodeformatter.h \ + navigationtokenfinder.h SOURCES += duieditor.cpp \ duieditorfactory.cpp \ duieditorplugin.cpp \ @@ -30,5 +32,7 @@ SOURCES += duieditor.cpp \ duidocument.cpp \ duicompletionvisitor.cpp \ duimodelmanagerinterface.cpp \ - duimodelmanager.cpp + duimodelmanager.cpp \ + duicodeformatter.cpp \ + navigationtokenfinder.cpp RESOURCES += duieditor.qrc diff --git a/src/plugins/duieditor/duieditorplugin.cpp b/src/plugins/duieditor/duieditorplugin.cpp index 774907c8a747a0140a3518ae461e620c01a1ad01..b4923418f2c007413f2533a35f7ddde89d62d366 100644 --- a/src/plugins/duieditor/duieditorplugin.cpp +++ b/src/plugins/duieditor/duieditorplugin.cpp @@ -113,8 +113,10 @@ bool DuiEditorPlugin::initialize(const QStringList & /*arguments*/, QString *err m_actionHandler = new TextEditor::TextEditorActionHandler(DuiEditor::Constants::C_DUIEDITOR, TextEditor::TextEditorActionHandler::Format + | TextEditor::TextEditorActionHandler::Reformat | TextEditor::TextEditorActionHandler::UnCommentSelection | TextEditor::TextEditorActionHandler::UnCollapseAll); + m_actionHandler->initializeActions(); m_completion = new DuiCodeCompletion(); addAutoReleasedObject(m_completion); diff --git a/src/plugins/duieditor/navigationtokenfinder.cpp b/src/plugins/duieditor/navigationtokenfinder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b52178f2396f3c2b8d5b93848a190f77d6b84214 --- /dev/null +++ b/src/plugins/duieditor/navigationtokenfinder.cpp @@ -0,0 +1,281 @@ +#include <QDebug> + +#include "qmljsast_p.h" +#include "qmljsengine_p.h" + +#include "navigationtokenfinder.h" + +using namespace QmlJS; +using namespace QmlJS::AST; +using namespace DuiEditor::Internal; + +bool NavigationTokenFinder::operator()(QmlJS::AST::UiProgram *ast, int position, bool resolveTarget) +{ + _resolveTarget = resolveTarget; + _scopes.clear(); + _pos = position; + _linkPosition = -1; + _targetLine = -1; + + Node::accept(ast, this); + + if (resolveTarget) + return targetFound(); + else + return linkFound(); +} + +bool NavigationTokenFinder::visit(QmlJS::AST::IdentifierExpression *ast) +{ + if (linkFound()) + return false; + + if (ast->identifierToken.offset <= _pos && _pos <= ast->identifierToken.end()) { + _linkPosition = ast->identifierToken.offset; + _linkLength = ast->identifierToken.length; + + if (Node *node = findDeclarationInScopes(ast->name)) + rememberStartPosition(node); + } + + return false; +} + +bool NavigationTokenFinder::visit(QmlJS::AST::UiArrayBinding *ast) +{ + if (linkFound()) + return false; + + Node::accept(ast->members, this); + + return false; +} + +bool NavigationTokenFinder::visit(QmlJS::AST::UiPublicMember *ast) +{ + if (linkFound()) + return false; + + Node::accept(ast->expression, this); + + return false; +} + +bool NavigationTokenFinder::visit(QmlJS::AST::Block *ast) +{ + _scopes.push(ast); + + if (linkFound()) + return false; + + return true; +} + +void NavigationTokenFinder::endVisit(QmlJS::AST::Block *) +{ + _scopes.pop(); +} + +bool NavigationTokenFinder::visit(QmlJS::AST::UiObjectBinding *ast) +{ + _scopes.push(ast); + + if (linkFound()) + return false; + + Node::accept(ast->qualifiedTypeNameId, this); + Node::accept(ast->initializer, this); + + return false; +} + +void NavigationTokenFinder::endVisit(QmlJS::AST::UiObjectBinding *) +{ + _scopes.pop(); +} + +bool NavigationTokenFinder::visit(QmlJS::AST::UiObjectDefinition *ast) +{ + _scopes.push(ast); + + if (linkFound()) + return false; + + return true; +} + +void NavigationTokenFinder::endVisit(QmlJS::AST::UiObjectDefinition *) +{ + _scopes.pop(); +} + +bool NavigationTokenFinder::visit(QmlJS::AST::UiQualifiedId *ast) +{ + if (linkFound()) + return false; + + if (ast->identifierToken.offset <= _pos) { + for (UiQualifiedId *iter = ast; iter; iter = iter->next) { + if (_pos <= iter->identifierToken.end()) { + _linkPosition = ast->identifierToken.offset; + + for (UiQualifiedId *iter2 = ast; iter2; iter2 = iter2->next) + _linkLength = iter2->identifierToken.end() - _linkPosition; + + if (Node *node = findDeclarationInScopes(ast)) + rememberStartPosition(node); + + return false; + } + } + } + + return false; +} + +bool NavigationTokenFinder::visit(QmlJS::AST::UiScriptBinding *ast) +{ + if (linkFound()) + return false; + + Node::accept(ast->statement, this); + + return false; +} + +bool NavigationTokenFinder::visit(QmlJS::AST::UiSourceElement * /*ast*/) +{ + return false; +} + +void NavigationTokenFinder::rememberStartPosition(QmlJS::AST::Node *node) +{ + if (UiObjectMember *om = dynamic_cast<UiObjectMember*>(node)) { + _targetLine = om->firstSourceLocation().startLine; + _targetColumn = om->firstSourceLocation().startColumn; + } else if (VariableDeclaration *vd = cast<VariableDeclaration*>(node)) { + _targetLine = vd->identifierToken.startLine; + _targetColumn = vd->identifierToken.startColumn; + } else { + qWarning() << "Found declaration of unknown type as a navigation target"; + } +} + +static inline bool isId(QmlJS::AST::UiQualifiedId *ast) +{ + return !(ast->next) && ast->name->asString() == "id"; +} + +static inline QString idToString(QmlJS::AST::Statement *stmt) +{ + if (ExpressionStatement *e = cast<ExpressionStatement*>(stmt)) + if (IdentifierExpression *i = cast<IdentifierExpression*>(e->expression)) + return i->name->asString(); + + return QString::null; +} + +static QmlJS::AST::Node *findDeclaration(const QString &nameId, QmlJS::AST::UiObjectMember *m) +{ + if (UiPublicMember *p = cast<UiPublicMember*>(m)) { + if (p->name->asString() == nameId) + return p; + } else if (UiObjectBinding *o = cast<UiObjectBinding*>(m)) { + if (!(o->qualifiedId->next) && o->qualifiedId->name->asString() == nameId) + return o; + } else if (UiArrayBinding *a = cast<UiArrayBinding*>(m)) { + if (!(a->qualifiedId->next) && a->qualifiedId->name->asString() == nameId) + return a; + } else if (UiScriptBinding *s = cast<UiScriptBinding*>(m)) { + if (isId(s->qualifiedId) && nameId == idToString(s->statement)) + return s; + } + + return 0; +} + +static QmlJS::AST::Node *findDeclaration(const QString &nameId, QmlJS::AST::UiObjectMemberList *l) +{ + for (UiObjectMemberList *iter = l; iter; iter = iter->next) + if (Node *n = findDeclaration(nameId, iter->member)) + return n; + + return 0; +} + +static QmlJS::AST::Node *findDeclaration(const QString &nameId, QmlJS::AST::Statement *s) +{ + if (VariableStatement *v = cast<VariableStatement*>(s)) { + for (VariableDeclarationList *l = v->declarations; l; l = l->next) { + if (l->declaration->name->asString() == nameId) + return l->declaration; + } + } + + return 0; +} + +static QmlJS::AST::Node *findDeclaration(const QString &nameId, QmlJS::AST::StatementList *l) +{ + for (StatementList *iter = l; iter; iter = iter->next) + if (Node *n = findDeclaration(nameId, iter->statement)) + return n; + + return 0; +} + +static QmlJS::AST::Node *findDeclarationAsDirectChild(const QString &nameId, QmlJS::AST::Node *node) +{ + if (UiObjectBinding *binding = cast<UiObjectBinding*>(node)) { + return findDeclaration(nameId, binding->initializer->members); + } else if (UiObjectDefinition *def = cast<UiObjectDefinition*>(node)) { + return findDeclaration(nameId, def->initializer->members); + } else if (Block *block = cast<Block *>(node)) { + return findDeclaration(nameId, block->statements); + } else { + return 0; + } +} + +static QmlJS::AST::Node *findDeclarationInNode(QmlJS::AST::UiQualifiedId *qualifiedId, QmlJS::AST::Node *node) +{ + if (!qualifiedId || !node) + return node; + else + return findDeclarationInNode(qualifiedId->next, findDeclarationAsDirectChild(qualifiedId->name->asString(), node)); +} + +QmlJS::AST::Node *NavigationTokenFinder::findDeclarationInScopes(QmlJS::NameId *nameId) +{ + if (!_resolveTarget) + return 0; + + const QString nameAsString = nameId->asString(); + + foreach (QmlJS::AST::Node *scope, _scopes) { + Node *result = findDeclarationAsDirectChild(nameAsString, scope); + + if (result) + return result; + } + + return 0; +} + +QmlJS::AST::Node *NavigationTokenFinder::findDeclarationInScopes(QmlJS::AST::UiQualifiedId *qualifiedId) +{ + if (!_resolveTarget) + return 0; + + const QString nameAsString = qualifiedId->name->asString(); + qDebug() << "findDecl. for id part" << nameAsString; + + foreach (QmlJS::AST::Node *scope, _scopes) { + Node *result = findDeclarationAsDirectChild(nameAsString, scope); + + if (result) + return findDeclarationInNode(qualifiedId->next, result); + } + + return 0; +} diff --git a/src/plugins/duieditor/navigationtokenfinder.h b/src/plugins/duieditor/navigationtokenfinder.h new file mode 100644 index 0000000000000000000000000000000000000000..ab8c23c0d42eb810b7821e40b1a7a54aaf8fc7a6 --- /dev/null +++ b/src/plugins/duieditor/navigationtokenfinder.h @@ -0,0 +1,63 @@ +#ifndef NAVIGATIONTOKENFINDER_H +#define NAVIGATIONTOKENFINDER_H + +#include <QStack> +#include <QString> + +#include "qmljsastvisitor_p.h" + +namespace QmlJS { + class NameId; +} // namespace QmlJS + +namespace DuiEditor { +namespace Internal { + +class NavigationTokenFinder: protected QmlJS::AST::Visitor +{ +public: + bool operator()(QmlJS::AST::UiProgram *ast, int position, bool resolveTarget); + + bool targetFound() const { return _targetLine != -1; } + bool linkFound() const { return _linkPosition != -1; } + + int linkPosition() const { return _linkPosition; } + int linkLength() const { return _linkLength; } + int targetLine() const { return _targetLine; } + int targetColumn() const { return _targetColumn; } + +protected: + virtual bool visit(QmlJS::AST::Block *ast); + virtual bool visit(QmlJS::AST::IdentifierExpression *ast); + virtual bool visit(QmlJS::AST::UiArrayBinding *ast); + virtual bool visit(QmlJS::AST::UiPublicMember *ast); + virtual bool visit(QmlJS::AST::UiObjectBinding *ast); + virtual bool visit(QmlJS::AST::UiObjectDefinition *ast); + virtual bool visit(QmlJS::AST::UiQualifiedId *ast); + virtual bool visit(QmlJS::AST::UiScriptBinding *ast); + virtual bool visit(QmlJS::AST::UiSourceElement *ast); + + virtual void endVisit(QmlJS::AST::Block *); + virtual void endVisit(QmlJS::AST::UiObjectBinding *); + virtual void endVisit(QmlJS::AST::UiObjectDefinition *); + +private: + QmlJS::AST::Node *findDeclarationInScopes(QmlJS::AST::UiQualifiedId *ast); + QmlJS::AST::Node *findDeclarationInScopes(QmlJS::NameId *id); + + void rememberStartPosition(QmlJS::AST::Node *node); + +private: + bool _resolveTarget; + quint32 _pos; + int _linkPosition; + int _linkLength; + int _targetLine; + int _targetColumn; + QStack<QmlJS::AST::Node*> _scopes; +}; + +} // namespace Internal +} // namespace DuiEditor + +#endif // NAVIGATIONTOKENFINDER_H diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp index 59c55fcb2d4f056dcfff985b054cd980225f0fa0..511c4af88ef9f4b6bde691e3da6e5c5a60de1e7c 100644 --- a/src/plugins/texteditor/basetexteditor.cpp +++ b/src/plugins/texteditor/basetexteditor.cpp @@ -3242,6 +3242,10 @@ void BaseTextEditor::indentBlock(QTextDocument *, QTextBlock, QChar) { } +void BaseTextEditor::reformatBlock(QTextDocument *, QTextBlock) +{ +} + void BaseTextEditor::indent(QTextDocument *doc, const QTextCursor &cursor, QChar typedChar) { if (cursor.hasSelection()) { @@ -3256,6 +3260,20 @@ void BaseTextEditor::indent(QTextDocument *doc, const QTextCursor &cursor, QChar } } +void BaseTextEditor::reformat(QTextDocument *doc, const QTextCursor &cursor) +{ + if (cursor.hasSelection()) { + QTextBlock block = doc->findBlock(qMin(cursor.selectionStart(), cursor.selectionEnd())); + const QTextBlock end = doc->findBlock(qMax(cursor.selectionStart(), cursor.selectionEnd())).next(); + do { + reformatBlock(doc, block); + block = block.next(); + } while (block.isValid() && block != end); + } else { + reformatBlock(doc, cursor.block()); + } +} + BaseTextEditor::Link BaseTextEditor::findLinkAt(const QTextCursor &, bool) { return Link(); @@ -3987,6 +4005,14 @@ void BaseTextEditor::format() cursor.endEditBlock(); } +void BaseTextEditor::reformat() +{ + QTextCursor cursor = textCursor(); + cursor.beginEditBlock(); + reformat(document(), cursor); + cursor.endEditBlock(); +} + void BaseTextEditor::rewrapParagraph() { const int paragraphWidth = displaySettings().m_wrapColumn; diff --git a/src/plugins/texteditor/basetexteditor.h b/src/plugins/texteditor/basetexteditor.h index 17a67d3b0a9bd4bde8cdc329cad1db02f32ee01d..556df22488dfebc618124c9177eafe40e8149256 100644 --- a/src/plugins/texteditor/basetexteditor.h +++ b/src/plugins/texteditor/basetexteditor.h @@ -482,6 +482,7 @@ public: public slots: virtual void format(); + virtual void reformat(); virtual void rewrapParagraph(); virtual void unCommentSelection(); virtual void setFontSettings(const TextEditor::FontSettings &); @@ -509,6 +510,11 @@ protected: // Indent at cursor. Calls indentBlock for selection or current line. virtual void indent(QTextDocument *doc, const QTextCursor &cursor, QChar typedChar); + // Reformats/prettyprints a text block based on previous line. Default does nothing + virtual void reformatBlock(QTextDocument *doc, QTextBlock block); + // Reformat/prettyprint the current document. + virtual void reformat(QTextDocument *doc, const QTextCursor &cursor); + struct Link { Link(const QString &fileName = QString(), diff --git a/src/plugins/texteditor/texteditoractionhandler.cpp b/src/plugins/texteditor/texteditoractionhandler.cpp index 2cabc7caa32473732a55caeda2b17d3920e81e53..bf80d2987b772e4d9932c11ed9470dcd5183d786 100644 --- a/src/plugins/texteditor/texteditoractionhandler.cpp +++ b/src/plugins/texteditor/texteditoractionhandler.cpp @@ -65,6 +65,7 @@ TextEditorActionHandler::TextEditorActionHandler(const QString &context, m_cleanWhitespaceAction(0), m_textWrappingAction(0), m_unCommentSelectionAction(0), + m_reformatAction(0), m_unCollapseAllAction(0), m_collapseAction(0), m_expandAction(0), @@ -183,6 +184,12 @@ void TextEditorActionHandler::createActions() connect(m_unCommentSelectionAction, SIGNAL(triggered()), this, SLOT(unCommentSelection())); advancedMenu->addAction(command, Core::Constants::G_EDIT_FORMAT); + m_reformatAction = new QAction(tr("&Reformat"), this); + command = am->registerAction(m_reformatAction, Constants::REFORMAT, m_contextId); + command->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+F"))); + connect(m_reformatAction, SIGNAL(triggered()), this, SLOT(reformatAction())); + advancedMenu->addAction(command, Core::Constants::G_EDIT_REFORMAT); + m_cutLineAction = new QAction(tr("Cut &Line"), this); command = am->registerAction(m_cutLineAction, Constants::CUT_LINE, m_contextId); command->setDefaultKeySequence(QKeySequence(tr("Shift+Del"))); @@ -318,11 +325,11 @@ void TextEditorActionHandler::updateActions(UpdateMode um) m_pasteAction->setEnabled(um != ReadOnlyMode); m_formatAction->setEnabled((m_optionalActions & Format) && um != ReadOnlyMode); m_unCommentSelectionAction->setEnabled((m_optionalActions & UnCommentSelection) && um != ReadOnlyMode); + m_reformatAction->setEnabled((m_optionalActions & Reformat) && um != ReadOnlyMode); m_moveLineUpAction->setEnabled(um != ReadOnlyMode); m_moveLineDownAction->setEnabled(um != ReadOnlyMode); m_formatAction->setEnabled((m_optionalActions & Format)); - m_unCommentSelectionAction->setEnabled((m_optionalActions & UnCommentSelection)); m_unCollapseAllAction->setEnabled((m_optionalActions & UnCollapseAll)); m_visualizeWhitespaceAction->setChecked(m_currentEditor->displaySettings().m_visualizeWhitespace); if (m_textWrappingAction) { @@ -407,6 +414,7 @@ FUNCTION2(copyAction, copy) FUNCTION2(cutAction, cut) FUNCTION2(pasteAction, paste) FUNCTION2(formatAction, format) +FUNCTION2(reformatAction, reformat) FUNCTION2(rewrapParagraphAction, rewrapParagraph) FUNCTION2(selectAllAction, selectAll) FUNCTION(cleanWhitespace) diff --git a/src/plugins/texteditor/texteditoractionhandler.h b/src/plugins/texteditor/texteditoractionhandler.h index ca9a878ca1e544646f3228cb1d1454aaabb0b871..b64c7e868e539c10d178749e9f6f35006a9e5169 100644 --- a/src/plugins/texteditor/texteditoractionhandler.h +++ b/src/plugins/texteditor/texteditoractionhandler.h @@ -54,7 +54,8 @@ public: None = 0, Format = 1, UnCommentSelection = 2, - UnCollapseAll = 4 + UnCollapseAll = 4, + Reformat = 8 }; TextEditorActionHandler(const QString &context, uint optionalActions = None); @@ -91,6 +92,7 @@ private slots: void gotoAction(); void printAction(); void formatAction(); + void reformatAction(); void rewrapParagraphAction(); void setVisualizeWhitespace(bool); void cleanWhitespace(); @@ -131,6 +133,7 @@ private: QAction *m_cleanWhitespaceAction; QAction *m_textWrappingAction; QAction *m_unCommentSelectionAction; + QAction *m_reformatAction; QAction *m_unCollapseAllAction; QAction *m_collapseAction; QAction *m_expandAction; diff --git a/src/plugins/texteditor/texteditorconstants.h b/src/plugins/texteditor/texteditorconstants.h index f0f5d43f6b24152ee5f148d3df66b747283df85a..6f9aec0bb1a5da28a3769fc45db1f4dc1e3255ec 100644 --- a/src/plugins/texteditor/texteditorconstants.h +++ b/src/plugins/texteditor/texteditorconstants.h @@ -40,6 +40,7 @@ const char * const VISUALIZE_WHITESPACE = "TextEditor.VisualizeWhitespace"; const char * const CLEAN_WHITESPACE = "TextEditor.CleanWhitespace"; const char * const TEXT_WRAPPING = "TextEditor.TextWrapping"; const char * const UN_COMMENT_SELECTION = "TextEditor.UnCommentSelection"; +const char * const REFORMAT = "TextEditor.Reformat"; const char * const COLLAPSE = "TextEditor.Collapse"; const char * const EXPAND = "TextEditor.Expand"; const char * const UN_COLLAPSE_ALL = "TextEditor.UnCollapseAll";