Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Marco Bubke
flatpak-qt-creator
Commits
8ecc80ec
Commit
8ecc80ec
authored
Jan 27, 2010
by
Erik Verbruggen
Browse files
Generalized ExpressionUnderCursor and got rid of duplicate code.
Done-with: Roberto Raggi
parent
bbb63c44
Changes
6
Hide whitespace changes
Inline
Side-by-side
src/libs/qmljs/qmljsinterpreter.cpp
View file @
8ecc80ec
...
...
@@ -166,7 +166,9 @@ public:
QmlObjectValue
::
QmlObjectValue
(
const
QMetaObject
*
metaObject
,
const
QString
&
qmlTypeName
,
int
majorVersion
,
int
minorVersion
,
Engine
*
engine
)
:
ObjectValue
(
engine
),
_metaObject
(
metaObject
),
_qmlTypeName
(
qmlTypeName
),
_majorVersion
(
majorVersion
),
_minorVersion
(
minorVersion
)
{}
{
setClassName
(
qmlTypeName
);
// ### TODO: we probably need to do more than just this...
}
QmlObjectValue
::~
QmlObjectValue
()
{}
...
...
src/plugins/qmljseditor/qmlcodecompletion.cpp
View file @
8ecc80ec
...
...
@@ -28,6 +28,7 @@
**************************************************************************/
#include "qmlcodecompletion.h"
#include "qmlexpressionundercursor.h"
#include "qmljseditor.h"
#include "qmlmodelmanagerinterface.h"
#include "qmllookupcontext.h"
...
...
@@ -97,77 +98,6 @@ static QIcon iconForColor(const QColor &color)
namespace
{
class
ExpressionUnderCursor
{
QTextCursor
_cursor
;
QmlJSScanner
scanner
;
public:
QString
operator
()(
const
QTextCursor
&
cursor
)
{
_cursor
=
cursor
;
QTextBlock
block
=
_cursor
.
block
();
const
QString
blockText
=
block
.
text
().
left
(
cursor
.
columnNumber
());
//qDebug() << "block text:" << blockText;
int
startState
=
block
.
previous
().
userState
();
if
(
startState
==
-
1
)
startState
=
0
;
else
startState
=
startState
&
0xff
;
const
QList
<
Token
>
originalTokens
=
scanner
(
blockText
,
startState
);
QList
<
Token
>
tokens
;
int
skipping
=
0
;
for
(
int
index
=
originalTokens
.
size
()
-
1
;
index
!=
-
1
;
--
index
)
{
const
Token
&
tk
=
originalTokens
.
at
(
index
);
if
(
tk
.
is
(
Token
::
Comment
)
||
tk
.
is
(
Token
::
String
)
||
tk
.
is
(
Token
::
Number
))
continue
;
if
(
!
skipping
)
{
tokens
.
append
(
tk
);
if
(
tk
.
is
(
Token
::
Identifier
))
{
if
(
index
>
0
&&
originalTokens
.
at
(
index
-
1
).
isNot
(
Token
::
Dot
))
break
;
}
}
else
{
//qDebug() << "skip:" << blockText.mid(tk.offset, tk.length);
}
if
(
tk
.
is
(
Token
::
RightParenthesis
)
||
tk
.
is
(
Token
::
RightBracket
))
++
skipping
;
else
if
(
tk
.
is
(
Token
::
LeftParenthesis
)
||
tk
.
is
(
Token
::
LeftBracket
))
{
--
skipping
;
if
(
!
skipping
)
tokens
.
append
(
tk
);
if
(
index
>
0
&&
originalTokens
.
at
(
index
-
1
).
isNot
(
Token
::
Identifier
))
break
;
}
}
if
(
!
tokens
.
isEmpty
())
{
QString
expr
;
for
(
int
index
=
tokens
.
size
()
-
1
;
index
>=
0
;
--
index
)
{
Token
tk
=
tokens
.
at
(
index
);
expr
.
append
(
QLatin1Char
(
' '
));
expr
.
append
(
blockText
.
midRef
(
tk
.
offset
,
tk
.
length
));
}
//qDebug() << "expression under cursor:" << expr;
return
expr
;
}
//qDebug() << "no expression";
return
QString
();
}
};
class
SearchPropertyDefinitions
:
protected
AST
::
Visitor
{
QList
<
AST
::
UiPublicMember
*>
_properties
;
...
...
@@ -714,20 +644,15 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
QTextCursor
tc
=
edit
->
textCursor
();
tc
.
setPosition
(
m_startPosition
-
1
);
ExpressionUnderCursor
expressionUnderCursor
;
const
QString
expression
=
expressionUnderCursor
(
tc
);
Qml
ExpressionUnderCursor
expressionUnderCursor
;
QmlJS
::
AST
::
ExpressionNode
*
expression
=
expressionUnderCursor
(
tc
);
//qDebug() << "expression:" << expression;
// Wrap the expression in a QML document.
QmlJS
::
Document
::
Ptr
exprDoc
=
Document
::
create
(
QLatin1String
(
"<expression>"
));
exprDoc
->
setSource
(
expression
);
exprDoc
->
parseExpression
();
if
(
exprDoc
->
expression
()
!=
0
)
{
if
(
expression
!=
0
)
{
Check
evaluate
(
&
interp
);
// Evaluate the expression under cursor.
const
Interpreter
::
Value
*
value
=
interp
.
convertToObject
(
evaluate
(
exprDoc
->
expression
()
,
scope
));
const
Interpreter
::
Value
*
value
=
interp
.
convertToObject
(
evaluate
(
expression
,
scope
));
//qDebug() << "type:" << interp.typeId(value);
if
(
value
&&
completionOperator
==
QLatin1Char
(
'.'
))
{
// member completion
...
...
@@ -744,10 +669,10 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
}
else
if
(
value
&&
completionOperator
==
QLatin1Char
(
'('
)
&&
m_startPosition
==
editor
->
position
())
{
// function completion
if
(
const
Interpreter
::
FunctionValue
*
f
=
value
->
asFunctionValue
())
{
QString
functionName
=
expression
;
int
indexOfDot
=
expression
.
lastIndexOf
(
QLatin1Char
(
'.'
));
QString
functionName
=
expression
UnderCursor
.
text
()
;
int
indexOfDot
=
functionName
.
lastIndexOf
(
QLatin1Char
(
'.'
));
if
(
indexOfDot
!=
-
1
)
functionName
=
expression
.
mid
(
indexOfDot
+
1
);
functionName
=
functionName
.
mid
(
indexOfDot
+
1
);
// Recreate if necessary
if
(
!
m_functionArgumentWidget
)
...
...
src/plugins/qmljseditor/qmlexpressionundercursor.cpp
View file @
8ecc80ec
...
...
@@ -30,11 +30,9 @@
#include "qmlexpressionundercursor.h"
#include <qmljs/parser/qmljsast_p.h>
#include <qmljs/parser/qmljsastvisitor_p.h>
#include <qmljs/parser/qmljsengine_p.h>
#include <qmljs/parser/qmljslexer_p.h>
#include <qmljs/parser/qmljsnodepool_p.h>
#include <qmljs/parser/qmljsparser_p.h>
#include <qmljs/qmljsscanner.h>
#include <QtGui/QTextBlock>
#include <QDebug>
...
...
@@ -43,162 +41,84 @@ using namespace QmlJS::AST;
namespace
QmlJSEditor
{
namespace
Internal
{
class
PositionCalculator
:
protected
Visitor
{
public:
Node
*
operator
()(
Node
*
ast
,
int
pos
)
{
_pos
=
pos
;
_expression
=
0
;
_offset
=
-
1
;
_length
=
-
1
;
Node
::
accept
(
ast
,
this
);
return
_expression
;
}
class
ExpressionUnderCursor
{
QTextCursor
_cursor
;
QmlJSScanner
scanner
;
int
offset
()
const
{
return
_offset
;
}
public:
ExpressionUnderCursor
()
:
start
(
0
),
end
(
0
)
{}
int
length
()
const
{
return
_length
;
}
int
start
,
end
;
protected:
bool
visit
(
FieldMemberExpression
*
ast
)
QString
operator
()(
const
QTextCursor
&
cursor
)
{
if
(
ast
->
identifierToken
.
offset
<=
_pos
&&
_pos
<=
ast
->
identifierToken
.
end
())
{
_expression
=
ast
;
_offset
=
ast
->
identifierToken
.
offset
;
_length
=
ast
->
identifierToken
.
length
;
}
_cursor
=
cursor
;
return
true
;
}
bool
visit
(
IdentifierExpression
*
ast
)
{
if
(
ast
->
firstSourceLocation
().
offset
<=
_pos
&&
_pos
<=
ast
->
lastSourceLocation
().
end
())
{
_expression
=
ast
;
_offset
=
ast
->
firstSourceLocation
().
offset
;
_length
=
ast
->
lastSourceLocation
().
end
()
-
_offset
;
}
QTextBlock
block
=
_cursor
.
block
();
const
QString
blockText
=
block
.
text
().
left
(
cursor
.
columnNumber
());
//qDebug() << "block text:" << blockText;
return
false
;
}
int
startState
=
block
.
previous
().
userState
();
if
(
startState
==
-
1
)
startState
=
0
;
else
startState
=
startState
&
0xff
;
bool
visit
(
UiImport
*
/*ast*/
)
{
return
false
;
}
const
QList
<
Token
>
originalTokens
=
scanner
(
blockText
,
startState
);
QList
<
Token
>
tokens
;
int
skipping
=
0
;
for
(
int
index
=
originalTokens
.
size
()
-
1
;
index
!=
-
1
;
--
index
)
{
const
Token
&
tk
=
originalTokens
.
at
(
index
);
bool
visit
(
UiQualifiedId
*
ast
)
{
if
(
ast
->
identifierToken
.
offset
<=
_pos
)
{
for
(
UiQualifiedId
*
iter
=
ast
;
iter
;
iter
=
iter
->
next
)
{
if
(
_pos
<=
iter
->
identifierToken
.
end
())
{
// found it
_expression
=
ast
;
_offset
=
ast
->
identifierToken
.
offset
;
if
(
tk
.
is
(
Token
::
Comment
)
||
tk
.
is
(
Token
::
String
)
||
tk
.
is
(
Token
::
Number
))
continue
;
for
(
UiQualifiedId
*
iter2
=
ast
;
iter2
;
iter2
=
iter2
->
next
)
{
_length
=
iter2
->
identifierToken
.
end
()
-
_offset
;
}
if
(
!
skipping
)
{
tokens
.
append
(
tk
);
break
;
if
(
tk
.
is
(
Token
::
Identifier
))
{
if
(
index
>
0
&&
originalTokens
.
at
(
index
-
1
).
isNot
(
Token
::
Dot
))
break
;
}
}
else
{
//qDebug() << "skip:" << blockText.mid(tk.offset, tk.length);
}
}
return
false
;
}
private:
quint32
_pos
;
Node
*
_expression
;
int
_offset
;
int
_length
;
};
class
ScopeCalculator
:
protected
Visitor
{
public:
QStack
<
Symbol
*>
operator
()(
const
Document
::
Ptr
&
doc
,
int
pos
)
{
_doc
=
doc
;
_pos
=
pos
;
_scopes
.
clear
();
_currentSymbol
=
0
;
Node
::
accept
(
doc
->
qmlProgram
(),
this
);
return
_scopes
;
}
protected:
virtual
bool
visit
(
Block
*
/*ast*/
)
{
// TODO
// if (_pos > ast->lbraceToken.end() && _pos < ast->rbraceToken.offset) {
// push(ast);
// Node::accept(ast->statements, this);
// }
return
false
;
}
virtual
bool
visit
(
UiObjectBinding
*
ast
)
{
if
(
ast
->
initializer
&&
ast
->
initializer
->
lbraceToken
.
offset
<
_pos
&&
_pos
<=
ast
->
initializer
->
rbraceToken
.
end
())
{
push
(
ast
);
Node
::
accept
(
ast
->
initializer
,
this
);
}
return
false
;
}
if
(
tk
.
is
(
Token
::
RightParenthesis
)
||
tk
.
is
(
Token
::
RightBracket
))
++
skipping
;
virtual
bool
visit
(
UiObjectDefinition
*
ast
)
{
if
(
ast
->
initializer
&&
ast
->
initializer
->
lbraceToken
.
offset
<
_pos
&&
_pos
<=
ast
->
initializer
->
rbraceToken
.
end
())
{
push
(
ast
);
Node
::
accept
(
ast
->
initializer
,
this
);
}
else
if
(
tk
.
is
(
Token
::
LeftParenthesis
)
||
tk
.
is
(
Token
::
LeftBracket
))
{
--
skipping
;
return
false
;
}
if
(
!
skipping
)
tokens
.
append
(
tk
);
virtual
bool
visit
(
UiArrayBinding
*
ast
)
{
if
(
ast
->
lbracketToken
.
offset
<
_pos
&&
_pos
<=
ast
->
rbracketToken
.
end
())
{
push
(
ast
);
Node
::
accept
(
ast
->
members
,
this
);
if
(
index
>
0
&&
originalTokens
.
at
(
index
-
1
).
isNot
(
Token
::
Identifier
))
break
;
}
}
return
false
;
}
private:
void
push
(
Node
*
node
)
{
SymbolFromFile
*
symbol
;
if
(
!
tokens
.
isEmpty
())
{
QString
expr
;
for
(
int
index
=
tokens
.
size
()
-
1
;
index
>=
0
;
--
index
)
{
Token
tk
=
tokens
.
at
(
index
);
expr
.
append
(
QLatin1Char
(
' '
));
expr
.
append
(
blockText
.
midRef
(
tk
.
offset
,
tk
.
length
));
if
(
_currentSymbol
)
{
symbol
=
_currentSymbol
->
findMember
(
node
);
}
else
{
symbol
=
_doc
->
findSymbol
(
node
);
}
start
=
tokens
.
first
().
begin
();
end
=
tokens
.
first
().
end
();
//qDebug() << "expression under cursor:" << expr;
return
expr
;
}
if
(
symbol
)
{
_currentSymbol
=
symbol
;
if
(
!
cast
<
UiArrayBinding
*>
(
node
))
_scopes
.
push
(
symbol
);
}
//qDebug() << "no expression";
return
QString
();
}
private:
Document
::
Ptr
_doc
;
quint32
_pos
;
QStack
<
Symbol
*>
_scopes
;
SymbolFromFile
*
_currentSymbol
;
};
}
}
...
...
@@ -207,101 +127,32 @@ using namespace QmlJSEditor;
using
namespace
QmlJSEditor
::
Internal
;
QmlExpressionUnderCursor
::
QmlExpressionUnderCursor
()
:
_expressionNode
(
0
),
_pos
(
0
),
_engine
(
0
),
_nodePool
(
0
)
{
}
QmlExpressionUnderCursor
::~
QmlExpressionUnderCursor
()
{
if
(
_engine
)
{
delete
_engine
;
_engine
=
0
;
}
if
(
_nodePool
)
{
delete
_nodePool
;
_nodePool
=
0
;
}
}
:
_expressionNode
(
0
),
_expressionOffset
(
0
),
_expressionLength
(
0
)
{}
void
QmlExpressionUnderCursor
::
operator
()(
const
QTextCursor
&
cursor
,
const
Document
::
Ptr
&
doc
)
QmlJS
::
AST
::
ExpressionNode
*
QmlExpressionUnderCursor
::
operator
()(
const
QTextCursor
&
cursor
)
{
if
(
_engine
)
{
delete
_engine
;
_engine
=
0
;
}
if
(
_nodePool
)
{
delete
_nodePool
;
_nodePool
=
0
;
}
_pos
=
cursor
.
position
();
_expressionNode
=
0
;
_expressionOffset
=
-
1
;
_expressionLength
=
-
1
;
_expressionScopes
.
clear
();
const
QTextBlock
block
=
cursor
.
block
();
parseExpression
(
block
);
if
(
_expressionOffset
!=
-
1
)
{
ScopeCalculator
calculator
;
_expressionScopes
=
calculator
(
doc
,
_expressionOffset
);
}
}
void
QmlExpressionUnderCursor
::
parseExpression
(
const
QTextBlock
&
block
)
{
int
textPosition
=
_pos
-
block
.
position
();
const
QString
blockText
=
block
.
text
();
if
(
textPosition
>
0
)
{
if
(
blockText
.
at
(
textPosition
-
1
)
==
QLatin1Char
(
'.'
))
--
textPosition
;
}
else
{
textPosition
=
0
;
}
ExpressionUnderCursor
expressionUnderCursor
;
_text
=
expressionUnderCursor
(
cursor
);
const
QString
text
=
blockText
.
left
(
textPosition
);
exprDoc
=
Document
::
create
(
QLatin1String
(
"<expression>"
));
exprDoc
->
setSource
(
_text
);
exprDoc
->
parseExpression
();
Node
*
node
=
0
;
_expressionNode
=
exprDoc
->
expression
()
;
if
(
UiObjectMember
*
binding
=
tryBinding
(
text
))
{
// qDebug() << "**** binding";
node
=
binding
;
}
else
if
(
Statement
*
stmt
=
tryStatement
(
text
))
{
// qDebug() << "**** statement";
node
=
stmt
;
}
else
{
// qDebug() << "**** none";
}
_expressionOffset
=
cursor
.
block
().
position
()
+
expressionUnderCursor
.
start
;
_expressionLength
=
expressionUnderCursor
.
end
-
expressionUnderCursor
.
start
;
if
(
node
)
{
PositionCalculator
calculator
;
_expressionNode
=
calculator
(
node
,
textPosition
);
_expressionOffset
=
calculator
.
offset
()
+
block
.
position
();
_expressionLength
=
calculator
.
length
();
}
return
_expressionNode
;
}
Statement
*
QmlExpressionUnderCursor
::
tryStatement
(
const
QString
&
text
)
ExpressionNode
*
QmlExpressionUnderCursor
::
expressionNode
()
const
{
_engine
=
new
Engine
();
_nodePool
=
new
NodePool
(
""
,
_engine
);
Lexer
lexer
(
_engine
);
Parser
parser
(
_engine
);
lexer
.
setCode
(
text
,
/*line = */
1
);
if
(
parser
.
parseStatement
())
return
parser
.
statement
();
else
return
0
;
return
_expressionNode
;
}
UiObjectMember
*
QmlExpressionUnderCursor
::
tryBinding
(
const
QString
&
text
)
{
_engine
=
new
Engine
();
_nodePool
=
new
NodePool
(
""
,
_engine
);
Lexer
lexer
(
_engine
);
Parser
parser
(
_engine
);
lexer
.
setCode
(
text
,
/*line = */
1
);
if
(
parser
.
parseUiObjectMember
())
{
UiObjectMember
*
member
=
parser
.
uiObjectMember
();
if
(
cast
<
UiObjectBinding
*>
(
member
)
||
cast
<
UiArrayBinding
*>
(
member
)
||
cast
<
UiScriptBinding
*>
(
member
))
return
member
;
else
return
0
;
}
else
{
return
0
;
}
}
src/plugins/qmljseditor/qmlexpressionundercursor.h
View file @
8ecc80ec
...
...
@@ -32,17 +32,9 @@
#include <qmljs/parser/qmljsastfwd_p.h>
#include <qmljs/qmljsdocument.h>
#include <qmljs/qmljssymbol.h>
#include <QStack>
#include <QTextBlock>
#include <QTextCursor>
namespace
QmlJS
{
class
Engine
;
class
NodePool
;
}
namespace
QmlJSEditor
{
namespace
Internal
{
...
...
@@ -50,15 +42,10 @@ class QmlExpressionUnderCursor
{
public:
QmlExpressionUnderCursor
();
virtual
~
QmlExpressionUnderCursor
();
void
operator
()(
const
QTextCursor
&
cursor
,
const
QmlJS
::
Document
::
Ptr
&
doc
);
QStack
<
QmlJS
::
Symbol
*>
expressionScopes
()
const
{
return
_expressionScopes
;
}
QmlJS
::
AST
::
ExpressionNode
*
operator
()(
const
QTextCursor
&
cursor
);
QmlJS
::
AST
::
Node
*
expressionNode
()
const
{
return
_expressionNode
;
}
QmlJS
::
AST
::
ExpressionNode
*
expressionNode
()
const
;
int
expressionOffset
()
const
{
return
_expressionOffset
;
}
...
...
@@ -66,20 +53,20 @@ public:
int
expressionLength
()
const
{
return
_expressionLength
;
}
QString
text
()
const
{
return
_text
;
}
private:
void
parseExpression
(
const
QTextBlock
&
block
);
QmlJS
::
AST
::
Statement
*
tryStatement
(
const
QString
&
text
);
QmlJS
::
AST
::
UiObjectMember
*
tryBinding
(
const
QString
&
text
);
void
tryExpression
(
const
QString
&
text
);
private:
QStack
<
QmlJS
::
Symbol
*>
_expressionScopes
;
QmlJS
::
AST
::
Node
*
_expressionNode
;
QmlJS
::
AST
::
ExpressionNode
*
_expressionNode
;
int
_expressionOffset
;
int
_expressionLength
;
quint32
_pos
;
QmlJS
::
Engine
*
_engine
;
QmlJS
::
NodePool
*
_nodePool
;
QmlJS
::
Document
::
Ptr
exprDoc
;
QString
_text
;
};
}
// namespace Internal
...
...
src/plugins/qmljseditor/qmlhoverhandler.cpp
View file @
8ecc80ec
...
...
@@ -39,6 +39,9 @@
#include <debugger/debuggerconstants.h>
#include <extensionsystem/pluginmanager.h>
#include <qmljs/qmljssymbol.h>
#include <qmljs/qmljsbind.h>
#include <qmljs/qmljscheck.h>
#include <qmljs/qmljsinterpreter.h>
#include <texteditor/itexteditor.h>
#include <texteditor/basetexteditor.h>
...
...
@@ -146,23 +149,23 @@ void QmlHoverHandler::updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, in
if
(
!
m_modelManager
)
return
;
QmlJSTextEditor
*
scriptE
dit
or
=
qobject_cast
<
QmlJSTextEditor
*>
(
editor
->
widget
());
if
(
!
scriptE
dit
or
)
QmlJSTextEditor
*
e
dit
=
qobject_cast
<
QmlJSTextEditor
*>
(
editor
->
widget
());
if
(
!
e
dit
)
return
;
const
Snapshot
snapshot
=
m_modelManager
->
snapshot
();
const
QString
fileName
=
editor
->
file
()
->
fileName
();
Document
::
Ptr
doc
=
snapshot
.
document
(
fileName
)
;
if
(
!
doc
)
return
;
// nothing to do
SemanticInfo
semanticInfo
=
edit
->
semanticInfo
();
Document
::
Ptr
qmlDocument
=
semanticInfo
.
document
;
if
(
qmlDocument
.
isNull
()
)
return
;
QTextCursor
tc
(
scriptE
dit
or
->
document
());
QTextCursor
tc
(
e
dit
->
document
());
tc
.
setPosition
(
pos
);
// We only want to show F1 if the tooltip matches the help id
bool
showF1
=
true
;
foreach
(
const
QTextEdit
::
ExtraSelection
&
sel
,
scriptE
dit
or
->
extraSelections
(
TextEditor
::
BaseTextEditor
::
CodeWarningsSelection
))
{
foreach
(
const
QTextEdit
::
ExtraSelection
&
sel
,
e
dit
->
extraSelections
(
TextEditor
::
BaseTextEditor
::
CodeWarningsSelection
))
{
if
(
pos
>=
sel
.
cursor
.
selectionStart
()
&&
pos
<=
sel
.
cursor
.
selectionEnd
())
{
showF1
=
false
;
m_toolTip
=