Commit 822de6c1 authored by Christian Kamm's avatar Christian Kamm

QmlJS: Introduce a new indenter that works similarly to the new C++ one.

Done-with: Thomas Hartmann
parent f6232260
......@@ -56,6 +56,11 @@ OTHER_FILES += \
$$PWD/parser/qmljs.g
contains(QT, gui) {
SOURCES += $$PWD/qmljsindenter.cpp
HEADERS += $$PWD/qmljsindenter.h
SOURCES += \
$$PWD/qmljsindenter.cpp \
$$PWD/qmljscodeformatter.cpp
HEADERS += \
$$PWD/qmljsindenter.h \
$$PWD/qmljscodeformatter.h
}
This diff is collapsed.
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#ifndef QMLJSCODEFORMATTER_H
#define QMLJSCODEFORMATTER_H
#include "qmljs_global.h"
#include "qmljsscanner.h"
#include <QtCore/QChar>
#include <QtCore/QStack>
#include <QtCore/QList>
#include <QtCore/QVector>
#include <QtCore/QPointer>
QT_BEGIN_NAMESPACE
class QTextDocument;
class QTextBlock;
QT_END_NAMESPACE
namespace QmlJS {
class QMLJS_EXPORT CodeFormatter
{
Q_GADGET
public:
CodeFormatter();
virtual ~CodeFormatter();
// updates all states up until block if necessary
// it is safe to call indentFor on block afterwards
void updateStateUntil(const QTextBlock &block);
// calculates the state change introduced by changing a single line
void updateLineStateChange(const QTextBlock &block);
int indentFor(const QTextBlock &block);
void setTabSize(int tabSize);
void invalidateCache(QTextDocument *document);
protected:
virtual void onEnter(int newState, int *indentDepth, int *savedIndentDepth) const = 0;
virtual void adjustIndent(const QList<Token> &tokens, int lexerState, int *indentDepth) const = 0;
class State;
class BlockData
{
public:
BlockData();
QStack<State> m_beginState;
QStack<State> m_endState;
int m_indentDepth;
int m_blockRevision;
};
virtual void saveBlockData(QTextBlock *block, const BlockData &data) const = 0;
virtual bool loadBlockData(const QTextBlock &block, BlockData *data) const = 0;
virtual void saveLexerState(QTextBlock *block, int state) const = 0;
virtual int loadLexerState(const QTextBlock &block) const = 0;
public: // must be public to make Q_GADGET introspection work
enum StateType {
invalid = 0,
topmost_intro, // The first line in a "topmost" definition.
top_qml, // root state for qml
top_js, // root for js
objectdefinition_or_js, // file starts with identifier
multiline_comment_start,
multiline_comment_cont,
import_start, // after 'import'
import_maybe_dot_or_version_or_as, // after string or identifier
import_dot, // after .
import_maybe_as, // after version
import_as,
property_start, // after 'property'
default_property_start, // after 'default'
property_type, // after first identifier
property_list_open, // after 'list' as a type
property_maybe_initializer, // after
signal_start, // after 'signal'
signal_maybe_arglist, // after identifier
signal_arglist_open, // after '('
function_start, // after 'function'
function_arglist_open, // after '(' starting function argument list
function_arglist_closed, // after ')' in argument list, expecting '{'
binding_or_objectdefinition, // after an identifier
binding_assignment, // after :
objectdefinition_open, // after {
expression,
expression_continuation, // at the end of the line, when the next line definitely is a continuation
expression_maybe_continuation, // at the end of the line, when the next line may be an expression
expression_or_objectdefinition, // after a binding starting with an identifier ("x: foo")
paren_open, // opening ( in expression
bracket_open, // opening [ in expression
bracket_element_start, // after starting bracket_open or after ',' in bracket_open
bracket_element_maybe_objectdefinition, // after an identifier in bracket_element_start
ternary_op, // The ? : operator
jsblock_open,
empty_statement, // for a ';', will never linger
if_statement, // After 'if'
maybe_else, // after the first substatement in an if
else_clause, // The else line of an if-else construct.
condition_open, // Start of a condition in 'if', 'while', entered after opening paren
condition_paren_open, // After an lparen in a condition
substatement, // The first line after a conditional or loop construct.
substatement_open, // The brace that opens a substatement block.
return_statement, // After 'return'
statement_with_condition, // After the 'for', 'while', 'catch', ... token
statement_with_condition_paren_open, // While inside the (...)
statement_with_block, // try, finally
do_statement, // after 'do'
do_statement_while_paren_open, // after '(' in while clause
switch_statement, // After 'switch' token
case_start, // after a 'case' or 'default' token
case_cont, // after the colon in a case/default
};
Q_ENUMS(StateType)
protected:
// extends Token::Kind from qmljsscanner.h
// the entries until EndOfExistingTokenKinds must match
enum TokenKind {
EndOfFile,
Keyword,
Identifier,
String,
Comment,
Number,
LeftParenthesis,
RightParenthesis,
LeftBrace,
RightBrace,
LeftBracket,
RightBracket,
Semicolon,
Colon,
Comma,
Dot,
Delimiter,
EndOfExistingTokenKinds,
Break,
Case,
Catch,
Continue,
Debugger,
Default,
Delete,
Do,
Else,
Finally,
For,
Function,
If,
In,
Instanceof,
New,
Return,
Switch,
This,
Throw,
Try,
Typeof,
Var,
Void,
While,
With,
Import,
Signal,
On,
As,
List,
Property,
Question,
PlusPlus,
MinusMinus,
};
TokenKind extendedTokenKind(const QmlJS::Token &token) const;
struct State {
State()
: savedIndentDepth(0)
, type(0)
{}
State(quint8 ty, quint16 savedDepth)
: savedIndentDepth(savedDepth)
, type(ty)
{}
quint16 savedIndentDepth;
quint8 type;
bool operator==(const State &other) const {
return type == other.type
&& savedIndentDepth == other.savedIndentDepth;
}
};
State state(int belowTop = 0) const;
const QVector<State> &newStatesThisLine() const;
int tokenIndex() const;
int tokenCount() const;
const Token &currentToken() const;
const Token &tokenAt(int idx) const;
int column(int position) const;
bool isBracelessState(int type) const;
bool isExpressionEndState(int type) const;
void dump() const;
private:
void recalculateStateAfter(const QTextBlock &block);
void saveCurrentState(const QTextBlock &block);
void restoreCurrentState(const QTextBlock &block);
QStringRef currentTokenText() const;
int tokenizeBlock(const QTextBlock &block);
void turnInto(int newState);
bool tryInsideExpression(bool alsoExpression = false);
bool tryStatement();
void enter(int newState);
void leave(bool statementDone = false);
void correctIndentation(const QTextBlock &block);
private:
static QStack<State> initialState();
QStack<State> m_beginState;
QStack<State> m_currentState;
QStack<State> m_newStates;
QList<Token> m_tokens;
QString m_currentLine;
Token m_currentToken;
int m_tokenIndex;
// should store indent level and padding instead
int m_indentDepth;
int m_tabSize;
};
} // namespace QmlJS
#endif // QMLJSCODEFORMATTER_H
......@@ -33,8 +33,8 @@
#include "qmljseditorplugin.h"
#include "qmljsmodelmanager.h"
#include "qmloutlinemodel.h"
#include "qmljseditorcodeformatter.h"
#include <qmljs/qmljsindenter.h>
#include <qmljs/qmljsbind.h>
#include <qmljs/qmljscheck.h>
#include <qmljs/qmljsdocument.h>
......@@ -1276,15 +1276,25 @@ bool QmlJSTextEditor::isClosingBrace(const QList<Token> &tokens) const
return false;
}
static QmlJSEditor::QtStyleCodeFormatter setupCodeFormatter(const TextEditor::TabSettings &ts)
{
QmlJSEditor::QtStyleCodeFormatter codeFormatter;
codeFormatter.setIndentSize(ts.m_indentSize);
codeFormatter.setTabSize(ts.m_tabSize);
return codeFormatter;
}
void QmlJSTextEditor::indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar)
{
TextEditor::TabSettings ts = tabSettings();
QmlJSIndenter indenter;
indenter.setTabSize(ts.m_tabSize);
indenter.setIndentSize(ts.m_indentSize);
Q_UNUSED(doc)
Q_UNUSED(typedChar)
const TextEditor::TabSettings &ts = tabSettings();
QmlJSEditor::QtStyleCodeFormatter codeFormatter = setupCodeFormatter(ts);
const int indent = indenter.indentForBottomLine(doc->begin(), block.next(), typedChar);
ts.indentLine(block, indent);
codeFormatter.updateStateUntil(block);
const int depth = codeFormatter.indentFor(block);
ts.indentLine(block, depth);
}
TextEditor::BaseTextEditorEditable *QmlJSTextEditor::createEditableInterface()
......
......@@ -26,7 +26,8 @@ HEADERS += \
qmljscomponentfromobjectdef.h \
qmljsoutline.h \
qmloutlinemodel.h \
qmltaskmanager.h
qmltaskmanager.h \
qmljseditorcodeformatter.h
SOURCES += \
qmljscodecompletion.cpp \
......@@ -46,7 +47,8 @@ SOURCES += \
qmljsoutline.cpp \
qmloutlinemodel.cpp \
qmltaskmanager.cpp \
qmljsquickfixes.cpp
qmljsquickfixes.cpp \
qmljseditorcodeformatter.cpp
RESOURCES += qmljseditor.qrc
OTHER_FILES += QmlJSEditor.pluginspec QmlJSEditor.mimetypes.xml
This diff is collapsed.
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#ifndef QMLJSEDITORCODEFORMATTER_H
#define QMLJSEDITORCODEFORMATTER_H
#include "qmljseditor_global.h"
#include <texteditor/basetextdocumentlayout.h>
#include <qmljs/qmljscodeformatter.h>
namespace QmlJSEditor {
class QMLJSEDITOR_EXPORT QtStyleCodeFormatter : public QmlJS::CodeFormatter
{
public:
QtStyleCodeFormatter();
void setIndentSize(int size);
protected:
virtual void onEnter(int newState, int *indentDepth, int *savedIndentDepth) const;
virtual void adjustIndent(const QList<QmlJS::Token> &tokens, int lexerState, int *indentDepth) const;
virtual void saveBlockData(QTextBlock *block, const BlockData &data) const;
virtual bool loadBlockData(const QTextBlock &block, BlockData *data) const;
virtual void saveLexerState(QTextBlock *block, int state) const;
virtual int loadLexerState(const QTextBlock &block) const;
private:
int m_indentSize;
class QmlJSCodeFormatterData: public TextEditor::CodeFormatterData
{
public:
QmlJS::CodeFormatter::BlockData m_data;
};
};
} // namespace QmlJSEditor
#endif // QMLJSEDITORCODEFORMATTER_H
TEMPLATE = app
CONFIG += qt warn_on console depend_includepath
QT += testlib network
SRCDIR = ../../../../../src
#DEFINES += QML_BUILD_STATIC_LIB
#include($$SRCDIR/../qtcreator.pri)
include($$SRCDIR/libs/qmljs/qmljs-lib.pri)
include($$SRCDIR/libs/utils/utils-lib.pri)
#LIBS += -L$$IDE_LIBRARY_PATH
SOURCES += \
tst_codeformatter.cpp \
$$SRCDIR/plugins/qmljseditor/qmljseditorcodeformatter.cpp \
$$SRCDIR/plugins/texteditor/basetextdocumentlayout.cpp
HEADERS += \
$$SRCDIR/plugins/qmljseditor/qmljseditorcodeformatter.h \
$$SRCDIR/plugins/texteditor/basetextdocumentlayout.h \
INCLUDEPATH += $$SRCDIR/plugins $$SRCDIR/libs
TARGET=tst_$$TARGET
This diff is collapsed.
TEMPLATE = subdirs
SUBDIRS += lookup
SUBDIRS += lookup codeformatter
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment