From 3645aa1a217ad8fc87709390e78d4a7aace10784 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Fri, 3 Dec 2010 21:05:58 +0100 Subject: [PATCH 1/8] Added example AST and XML for that --- example_ast.py | 172 +++++++++ example_ast.xml | 990 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1162 insertions(+) create mode 100644 example_ast.py create mode 100644 example_ast.xml diff --git a/example_ast.py b/example_ast.py new file mode 100644 index 0000000..09b78b3 --- /dev/null +++ b/example_ast.py @@ -0,0 +1,172 @@ +a = a and a +a = a or b + +def some_class(foo, bar): + attr1 = 3 + attr2 = 5 + attr3 = 'str' + +some_instance = some_class() +some_instance.attr1 +some_instance.attr2 +some_instance.some_method() + +#comment +""" +multiline comment +foo +bar +""" + +import sys +import random + +import PyQt4.QtCore + +print sys + +def simple_func(foo): + # usage comment, bla, param:foo + pass + +def function(foo): + """ docstring + more + more more + >>> test + >>> test + """ + return foo + +try: + pass +except Exception as e: + print e + +def func(foo, bar, baz, bang, foobang, foobar, foobazbar, foobazbarbang): + return foobang + print foo + print foobazbarbang + + if foobazbar < 5: + pass + +def another_function(param): + print param + +a = 5 + +bar = a == a +a != a +a < a +a <= a +a > a +a >= a +a is a +a is not a +a not in a +a in a + +a = a + 1 +a = a - 1 +a = a * 1 +a = a / 1 +a = a % 1 +a = a ^ 1 +a = a & 1 +a = a | 1 +a = a ** 1 +a = a >> 1 +a = a << 1 + +a = not a +a = +a +a = -a +a = ~a + +a = b[1:2:3][2] +extended = a[1:2, 2:3] + +i += 3 +i += j + +print 3 if 5 < 7 else 4 + +from random import random + +print random + +random(foo=3) + +a = lambda x: x**2 + +@staticmethod +@classmethod +def genfunc(): + yield foo + +for target1, target2 in some_dict.iteritems(): + print target1, target2 + +pi = 3.1415 + +foo = 1, 2 +bar = (1, 2) + +with open('f') as foo: + pass + +global IMAGLOBALVARIABLE +IMAGLOBALVARIABLE = 0 +try: + a = 3 / 0 +except ZeroDivisionError as err: + raise ValueError +else: + do_something() +finally: + BAM + +if 3 and 5: + pass + +for i in xrange(20): + pass + +while True: + break + continue + +del foo + +import random +random.random(3, 5) + +somelist = [1, 2, 3, 4, 5] +somedict = { 'key1' : 'value1', key2: value2 } + +print somelist[...] +print somelist[1:] +print somelist[:20] +print somelist[1:20] +print somelist[1:20:2] + +class bar(parent): + pass + +if foo in bar and 3 < 5: + pass + +a = [x*2 for x in xrange(20)] + +variable.variable2.variable3 = 15 +def function(param1, param2, param3, *paramstar, **paramdstar): + pass + return param1 * param2 + +assert False +if not 3: + pass + +if 3 * 5 == 7: + pass diff --git a/example_ast.xml b/example_ast.xml new file mode 100644 index 0000000..fb10791 --- /dev/null +++ b/example_ast.xml @@ -0,0 +1,990 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From a84ff96e7d1d03ad63c22160e2f6a0680c1703ea Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 5 Dec 2010 12:55:12 +0100 Subject: [PATCH 2/8] Fixed compiler warnings which aren't actually problems --- codecompletion/pythoncodecompletioncontext.cpp | 2 +- codecompletion/pythoncodecompletionworker.cpp | 2 +- duchain/contextbuilder.cpp | 6 +++--- duchain/declarationbuilder.cpp | 2 +- parser/ast.cpp | 2 +- parser/astbuilder.cpp | 6 +++--- parser/astbuilder.h | 2 +- parser/pythondriver.cpp | 2 +- pythonparsejob.cpp | 18 ++++++++++++------ 9 files changed, 24 insertions(+), 18 deletions(-) diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index 3336495..8f4ffb3 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -29,7 +29,7 @@ typedef QPair DeclarationDepthPair; namespace Python { -QList PythonCodeCompletionContext::completionItems(bool& abort, bool fullCompletion) +QList PythonCodeCompletionContext::completionItems(bool& /*abort*/, bool /*fullCompletion*/) { QList items; DUChainReadLocker lock(DUChain::lock()); diff --git a/codecompletion/pythoncodecompletionworker.cpp b/codecompletion/pythoncodecompletionworker.cpp index e367eb9..bd6abbd 100644 --- a/codecompletion/pythoncodecompletionworker.cpp +++ b/codecompletion/pythoncodecompletionworker.cpp @@ -17,7 +17,7 @@ PythonCodeCompletionWorker::PythonCodeCompletionWorker(PythonCodeCompletionModel } -KDevelop::CodeCompletionContext* PythonCodeCompletionWorker::createCompletionContext(KDevelop::DUContextPointer context, const QString& contextText, const QString& followingText, const KDevelop::CursorInRevision& position) const +KDevelop::CodeCompletionContext* PythonCodeCompletionWorker::createCompletionContext(KDevelop::DUContextPointer context, const QString& contextText, const QString& /*followingText*/, const KDevelop::CursorInRevision& position) const { PythonCodeCompletionContext* completionContext = new PythonCodeCompletionContext(context, contextText, position, 0); return completionContext; diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index ed27bc6..da166a9 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -103,7 +103,7 @@ void ContextBuilder::setEditor(PythonEditorIntegrator* editor) ContextBuilder::m_editor = editor; } -void ContextBuilder::setEditor(ParseSession* session) +void ContextBuilder::setEditor(ParseSession* /*session*/) { PythonEditorIntegrator* e = new PythonEditorIntegrator(/*session*/); //m_identifierCompiler = new IdentifierCompiler(e->parseSession()); @@ -147,7 +147,7 @@ void ContextBuilder::addImportedContexts() } } -void ContextBuilder::openContextForStatementList( const QList& l, DUContext::ContextType type) +void ContextBuilder::openContextForStatementList( const QList& l, DUContext::ContextType /*type*/) { if ( l.count() > 0 ) { @@ -229,7 +229,7 @@ void ContextBuilder::visitImport(ImportAst* node) { foreach ( AliasAst* name, node->names ) { // for "import ... as", use the as thingy, use the module name otherwise - Identifier* variableDeclarationName = name->asName ? name->asName->identifier : name->name; +// Identifier* variableDeclarationName = name->asName ? name->asName->identifier : name->name; # TODO check this KUrl moduleFilePath = findModulePath(name->name->value); if ( ! moduleFilePath.isValid() ) continue; diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index f6db5c6..cb9b02c 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -249,7 +249,7 @@ void DeclarationBuilder::visitAssignment(AssignmentAst* node) void DeclarationBuilder::visitClassDefinition( ClassDefinitionAst* node ) { kDebug() << "opening class definition"; - ClassDeclaration* classDec = new ClassDeclaration(editorFindRange(node->body.first(), node->body.last()), currentContext()); +// ClassDeclaration* classDec = new ClassDeclaration(editorFindRange(node->body.first(), node->body.last()), currentContext()); openDeclaration( node->name, node ); eventuallyAssignInternalContext(); diff --git a/parser/ast.cpp b/parser/ast.cpp index ae04f59..6eeeca3 100644 --- a/parser/ast.cpp +++ b/parser/ast.cpp @@ -136,7 +136,7 @@ ExceptionHandlerAst::ExceptionHandlerAst(Ast* parent): Ast(parent, Ast::Exceptio } -ExecAst::ExecAst(Ast* parent): StatementAst(parent, Ast::ExecAstType), body(0), locals(0), globals(0) +ExecAst::ExecAst(Ast* parent): StatementAst(parent, Ast::ExecAstType), body(0), globals(0), locals(0) { } diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 49b60b8..f5303eb 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -138,7 +138,7 @@ CodeAst* AstBuilder::parseXmlAst(QString xml) return codeAst; } -void AstBuilder::parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::TokenType token = QXmlStreamReader::Invalid) { +void AstBuilder::parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::TokenType /*token = QXmlStreamReader::Invalid*/) { bool nodeAdded = false; while ( ! xmlast->atEnd() && ! xmlast->hasError() ) { @@ -165,7 +165,7 @@ void AstBuilder::parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::Tok } // this will push a parent onto the stack - nodeAdded = parseAstNode(currentElementName, currentElementText, currentElementAttributes); + nodeAdded = parseAstNode(currentElementName, /*currentElementText,*/ currentElementAttributes); // we might need ElementText some day if ( ! nodeAdded ) { m_isRealNodeMap.append(false); continue; @@ -198,7 +198,7 @@ void AstBuilder::parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::Tok } } -bool AstBuilder::parseAstNode(QString name, QString text, const QList< QXmlStreamAttribute >& attributes) +bool AstBuilder::parseAstNode(QString name, /*QString text, */ const QList< QXmlStreamAttribute >& attributes) { Ast* ast; diff --git a/parser/astbuilder.h b/parser/astbuilder.h index 4441405..478d444 100644 --- a/parser/astbuilder.h +++ b/parser/astbuilder.h @@ -53,7 +53,7 @@ class AstBuilder CodeAst* parseXmlAst(QString xml); QString getXmlForFile(KUrl filename, const QString& contents); void parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::TokenType token); - bool parseAstNode(QString name, QString text, const QList& attributes); + bool parseAstNode(QString name, /*QString text, */const QList& attributes); KDevelop::TopDUContext* m_topContext; diff --git a/parser/pythondriver.cpp b/parser/pythondriver.cpp index 15c4556..9bfe9c4 100644 --- a/parser/pythondriver.cpp +++ b/parser/pythondriver.cpp @@ -70,7 +70,7 @@ void Driver::setCurrentDocument(KUrl url) m_currentDocument = url; } -QPair Driver::parse( Python::CodeAst* ast ) +QPair Driver::parse( Python::CodeAst* /* ast */) { AstBuilder pythonparser; QPair matched; diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index eb8e6d8..6dc4e74 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -148,18 +148,18 @@ void ParseJob::run() m_duContext = builder.build(filename, m_ast); setDuChain(m_duContext); + UseBuilder usebuilder( &editor ); + usebuilder.buildUses(m_ast); + { DUChainWriteLocker lock(DUChain::lock()); + m_duContext->clearProblems(); ParsingEnvironmentFilePointer parsingEnvironmentFile = m_duContext->parsingEnvironmentFile(); parsingEnvironmentFile->clearModificationRevisions(); parsingEnvironmentFile->setModificationRevision(contents().modification); DUChain::self()->updateContextEnvironment(m_duContext, parsingEnvironmentFile.data()); - m_duContext->clearProblems(); } - UseBuilder usebuilder( &editor ); - usebuilder.buildUses(m_ast); - kDebug() << "----Parsing Succeded---***"; if ( m_parent && m_parent->codeHighlighting() ) { @@ -181,7 +181,7 @@ void ParseJob::run() static const IndexedString langString("python"); file->setLanguage(langString); m_duContext = new TopDUContext(document(), RangeInRevision(0, 0, INT_MAX, INT_MAX), file); - DUChain::self()->addDocumentChain(m_duContext); +// DUChain::self()->addDocumentChain(m_duContext); } { m_duContext->parsingEnvironmentFile()->clearModificationRevisions(); @@ -189,13 +189,19 @@ void ParseJob::run() m_duContext->clearProblems(); DUChain::self()->updateContextEnvironment(m_duContext, m_duContext->parsingEnvironmentFile().data()); } - + foreach ( ProblemPointer p, m_session->m_problems ) { kDebug() << "Added problem to context"; m_duContext->addProblem(p); } setDuChain(m_duContext); } + + DUChainWriteLocker lock(DUChain::lock()); + if ( ! DUChain::self()->chainForDocument(document()) && m_duContext ) { + DUChain::self()->addDocumentChain(m_duContext); + } + } ParseSession *ParseJob::parseSession() const From 0f089164e1d5dcbaf566dc80aea34fc1452ec840 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 5 Dec 2010 13:15:08 +0100 Subject: [PATCH 3/8] Added RegEx for member access code completion --- .../pythoncodecompletioncontext.cpp | 21 ++++++++++++++----- pythonparsejob.cpp | 10 ++++----- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index 8f4ffb3..cac5d02 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -51,16 +51,19 @@ QList PythonCodeCompletionContext::completionItems(bo items << CompletionTreeItemPointer( item ); } } + else if ( m_operation == PythonCodeCompletionContext::MemberAccessCompletion ) { + // we don't have type support, so we cannot support completing mebers yet. But we can at least prevent kdevelop from opening a pointless + // popup with completion items you don't want + } else { QList declarations = m_duContext->allDeclarations(CursorInRevision::invalid(), m_duContext->topContext()); - Declaration* currentDeclaration; + DeclarationPointer currentDeclaration; int count = declarations.length(); for ( int i = 0; i < count; i++ ) { - currentDeclaration = declarations.at(i).first; - kDebug() << "Adding item: " << currentDeclaration->identifier().identifier().str(); - DeclarationPointer ptr(currentDeclaration); - NormalDeclarationCompletionItem* item = new NormalDeclarationCompletionItem(ptr, KDevelop::CodeCompletionContext::Ptr(this)); + currentDeclaration = DeclarationPointer(declarations.at(i).first); + kDebug() << "Adding item: " << currentDeclaration.data()->identifier().identifier().str(); + NormalDeclarationCompletionItem* item = new NormalDeclarationCompletionItem(currentDeclaration, KDevelop::CodeCompletionContext::Ptr(this)); kDebug() << item->declaration().data()->identifier().identifier().str(); items << CompletionTreeItemPointer(item); } @@ -218,6 +221,14 @@ PythonCodeCompletionContext::PythonCodeCompletionContext(DUContextPointer contex return; } + QRegExp attributeAccess("(.*)\n[\\s]*(.*)\\.$"); + attributeAccess.setMinimal(true); + bool is_attributeAccess = attributeAccess.exactMatch(currentLine); + if ( is_attributeAccess ) { + m_operation = PythonCodeCompletionContext::MemberAccessCompletion; + return; + } + QRegExp noCompletionPossible("(.*)\n[\\s]*(class|def)[\\s]*$"); noCompletionPossible.setMinimal(true); bool is_noCompletionPossible = noCompletionPossible.exactMatch(currentLine); diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index 6dc4e74..a02f0bf 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -181,7 +181,7 @@ void ParseJob::run() static const IndexedString langString("python"); file->setLanguage(langString); m_duContext = new TopDUContext(document(), RangeInRevision(0, 0, INT_MAX, INT_MAX), file); -// DUChain::self()->addDocumentChain(m_duContext); + DUChain::self()->addDocumentChain(m_duContext); } { m_duContext->parsingEnvironmentFile()->clearModificationRevisions(); @@ -197,10 +197,10 @@ void ParseJob::run() setDuChain(m_duContext); } - DUChainWriteLocker lock(DUChain::lock()); - if ( ! DUChain::self()->chainForDocument(document()) && m_duContext ) { - DUChain::self()->addDocumentChain(m_duContext); - } +// DUChainWriteLocker lock(DUChain::lock()); +// if ( ! DUChain::self()->chainForDocument(document()) && m_duContext ) { +// DUChain::self()->addDocumentChain(m_duContext); +// } } From 125409d2d5851334ae60676c39c177bb44a21f7b Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Tue, 7 Dec 2010 23:37:51 +0100 Subject: [PATCH 4/8] Hopefully fixed ranges getting invalid now, finally --- pythonparsejob.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index a02f0bf..2077900 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -173,22 +173,18 @@ void ParseJob::run() { kWarning() << "===Failed==="; DUChainWriteLocker lock; - { - m_duContext = DUChain::self()->chainForDocument(document()); + m_duContext = DUChain::self()->chainForDocument(document()); + if ( m_duContext ) { + m_duContext->parsingEnvironmentFile()->clearModificationRevisions(); + m_duContext->clearProblems(); } - if ( ! m_duContext ) { + else { ParsingEnvironmentFile *file = new ParsingEnvironmentFile(document()); static const IndexedString langString("python"); file->setLanguage(langString); m_duContext = new TopDUContext(document(), RangeInRevision(0, 0, INT_MAX, INT_MAX), file); DUChain::self()->addDocumentChain(m_duContext); } - { - m_duContext->parsingEnvironmentFile()->clearModificationRevisions(); - m_duContext->parsingEnvironmentFile()->setModificationRevision(contents().modification); - m_duContext->clearProblems(); - DUChain::self()->updateContextEnvironment(m_duContext, m_duContext->parsingEnvironmentFile().data()); - } foreach ( ProblemPointer p, m_session->m_problems ) { kDebug() << "Added problem to context"; From 89ceff7443bdb89fc7d368ea2f8bd43d048a2454 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Wed, 8 Dec 2010 23:20:19 +0100 Subject: [PATCH 5/8] Added more advanced function autocompletion --- codecompletion/CMakeLists.txt | 1 + .../functiondeclarationcompletionitem.cpp | 28 +++++++++++++++++++ .../functiondeclarationcompletionitem.h | 23 +++++++++++++++ .../pythoncodecompletioncontext.cpp | 26 +++++++++++++++-- 4 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 codecompletion/functiondeclarationcompletionitem.cpp create mode 100644 codecompletion/functiondeclarationcompletionitem.h diff --git a/codecompletion/CMakeLists.txt b/codecompletion/CMakeLists.txt index 1231c12..7488a09 100644 --- a/codecompletion/CMakeLists.txt +++ b/codecompletion/CMakeLists.txt @@ -4,6 +4,7 @@ include_directories( ) set(completion_SRCS + functiondeclarationcompletionitem.cpp importfileitem.cpp pythoncodecompletioncontext.cpp pythoncodecompletionmodel.cpp diff --git a/codecompletion/functiondeclarationcompletionitem.cpp b/codecompletion/functiondeclarationcompletionitem.cpp new file mode 100644 index 0000000..912156d --- /dev/null +++ b/codecompletion/functiondeclarationcompletionitem.cpp @@ -0,0 +1,28 @@ + +#include +#include +#include +#include + +#include "functiondeclarationcompletionitem.h" +#include "navigation/navigationwidget.h" + +using namespace KDevelop; + +namespace Python { + +FunctionDeclarationCompletionItem::FunctionDeclarationCompletionItem(DeclarationPointer decl) : NormalDeclarationCompletionItem(decl) { } + +void FunctionDeclarationCompletionItem::executed(KTextEditor::Document* document, const KTextEditor::Range& word) +{ + kDebug() << "FunctionDeclarationCompletionItem executed"; + DUChainPointer decl = declaration().dynamicCast(); + Q_ASSERT(decl.data()); + kDebug() << "declaration data: " << decl.data(); + const QString suffix = "()"; + document->replaceText(word, decl.data()->identifier().toString() + suffix); +} + +FunctionDeclarationCompletionItem::~FunctionDeclarationCompletionItem() { } + +} \ No newline at end of file diff --git a/codecompletion/functiondeclarationcompletionitem.h b/codecompletion/functiondeclarationcompletionitem.h new file mode 100644 index 0000000..2efa1a8 --- /dev/null +++ b/codecompletion/functiondeclarationcompletionitem.h @@ -0,0 +1,23 @@ +#ifndef FUNCTIONDECLARATIONCOMPLETIONITEM_H +#define FUNCTIONDECLARATIONCOMPLETIONITEM_H + +#include +#include + +using namespace KDevelop; + +namespace Python { + +class FunctionDeclarationCompletionItem : public KDevelop::NormalDeclarationCompletionItem +{ + +public: + FunctionDeclarationCompletionItem(DeclarationPointer decl); + virtual ~FunctionDeclarationCompletionItem(); + + virtual void executed(KTextEditor::Document* document, const KTextEditor::Range& word); +}; + +} + +#endif // FUNCTIONDECLARATIONCOMPLETIONITEM_H diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index cac5d02..8985aed 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -16,6 +16,8 @@ #include "navigation/navigationwidget.h" #include "importfileitem.h" +#include "functiondeclarationcompletionitem.h" + #include #include #include @@ -23,14 +25,19 @@ #include #include +#include + using namespace KDevelop; typedef QPair DeclarationDepthPair; namespace Python { -QList PythonCodeCompletionContext::completionItems(bool& /*abort*/, bool /*fullCompletion*/) +QList PythonCodeCompletionContext::completionItems(bool& abort, bool /*fullCompletion*/) { + if ( abort ) + return QList(); + QList items; DUChainReadLocker lock(DUChain::lock()); @@ -56,14 +63,27 @@ QList PythonCodeCompletionContext::completionItems(bo // popup with completion items you don't want } else { - QList declarations = m_duContext->allDeclarations(CursorInRevision::invalid(), m_duContext->topContext()); + if ( abort ) { + return QList(); + } + QList declarations = m_duContext->allDeclarations(m_position, m_duContext->topContext()); DeclarationPointer currentDeclaration; int count = declarations.length(); for ( int i = 0; i < count; i++ ) { + if ( abort ) { + return items; + } currentDeclaration = DeclarationPointer(declarations.at(i).first); kDebug() << "Adding item: " << currentDeclaration.data()->identifier().identifier().str(); - NormalDeclarationCompletionItem* item = new NormalDeclarationCompletionItem(currentDeclaration, KDevelop::CodeCompletionContext::Ptr(this)); + NormalDeclarationCompletionItem* item; + if ( currentDeclaration.data()->abstractType() && currentDeclaration.data()->abstractType().constData()->whichType() == AbstractType::TypeFunction ) { + kDebug() << "Adding function declaration item"; + item = new FunctionDeclarationCompletionItem(currentDeclaration); + } + else { + item = new NormalDeclarationCompletionItem(currentDeclaration, KDevelop::CodeCompletionContext::Ptr(this)); + } kDebug() << item->declaration().data()->identifier().identifier().str(); items << CompletionTreeItemPointer(item); } From 15649bf71540d9adcb293c795419304ed9204a59 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Thu, 9 Dec 2010 15:58:49 +0100 Subject: [PATCH 6/8] More autocompletion --- codecompletion/functiondeclarationcompletionitem.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/codecompletion/functiondeclarationcompletionitem.cpp b/codecompletion/functiondeclarationcompletionitem.cpp index 912156d..bd8aecd 100644 --- a/codecompletion/functiondeclarationcompletionitem.cpp +++ b/codecompletion/functiondeclarationcompletionitem.cpp @@ -2,12 +2,15 @@ #include #include #include -#include + +#include +#include #include "functiondeclarationcompletionitem.h" #include "navigation/navigationwidget.h" using namespace KDevelop; +using namespace KTextEditor; namespace Python { @@ -20,7 +23,14 @@ void FunctionDeclarationCompletionItem::executed(KTextEditor::Document* document Q_ASSERT(decl.data()); kDebug() << "declaration data: " << decl.data(); const QString suffix = "()"; + int skip = 2; // place cursor behind bracktes + if ( decl.data()->defaultParametersSize() != 0 ) { + skip = 1; // place cursor in brackets if there's parameters + } document->replaceText(word, decl.data()->identifier().toString() + suffix); + if ( View* view = document->activeView() ) { + view->setCursorPosition( Cursor(word.end().line(), word.end().column() + skip) ); + } } FunctionDeclarationCompletionItem::~FunctionDeclarationCompletionItem() { } From d1a221d98f1c7700f244ac0bc398e6c274983582 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Thu, 9 Dec 2010 22:51:30 +0100 Subject: [PATCH 7/8] Keyword items for code completion --- codecompletion/CMakeLists.txt | 1 + codecompletion/keyworditem.cpp | 47 +++++++++++++++++++ codecompletion/keyworditem.h | 22 +++++++++ .../pythoncodecompletioncontext.cpp | 19 +++++++- codecompletion/pythoncodecompletioncontext.h | 3 +- example_ast.py | 8 ++++ 6 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 codecompletion/keyworditem.cpp create mode 100644 codecompletion/keyworditem.h diff --git a/codecompletion/CMakeLists.txt b/codecompletion/CMakeLists.txt index 7488a09..2cdef3d 100644 --- a/codecompletion/CMakeLists.txt +++ b/codecompletion/CMakeLists.txt @@ -4,6 +4,7 @@ include_directories( ) set(completion_SRCS + keyworditem.cpp functiondeclarationcompletionitem.cpp importfileitem.cpp pythoncodecompletioncontext.cpp diff --git a/codecompletion/keyworditem.cpp b/codecompletion/keyworditem.cpp new file mode 100644 index 0000000..0ed0c13 --- /dev/null +++ b/codecompletion/keyworditem.cpp @@ -0,0 +1,47 @@ +#include "keyworditem.h" +#include +#include +#include +#include +#include + +using namespace KDevelop; +using namespace KTextEditor; + +namespace Python { + +Python::KeywordItem::KeywordItem(KDevelop::CodeCompletionContext::Ptr context, QString keyword) : NormalDeclarationCompletionItem ( DeclarationPointer(), context, 0 ) +{ + m_keyword = keyword; +} + +void Python::KeywordItem::execute ( KTextEditor::Document* document, const KTextEditor::Range& word ) +{ + document->replaceText(word, m_keyword); +} + +QVariant KeywordItem::data ( const QModelIndex& index, int role, const KDevelop::CodeCompletionModel* model ) const +{ + switch (role) { + case KDevelop::CodeCompletionModel::IsExpandable: + return QVariant(false); + case Qt::DisplayRole: + if (index.column() == KTextEditor::CodeCompletionModel::Name) { + return QVariant(m_keyword); + } else { + return QVariant(""); + } + break; + case KTextEditor::CodeCompletionModel::ItemSelected: + return QVariant(""); + case KTextEditor::CodeCompletionModel::InheritanceDepth: + return QVariant(0); + default: + //pass + break; + } + + return NormalDeclarationCompletionItem::data(index, role, model); +} + +} diff --git a/codecompletion/keyworditem.h b/codecompletion/keyworditem.h new file mode 100644 index 0000000..488153d --- /dev/null +++ b/codecompletion/keyworditem.h @@ -0,0 +1,22 @@ +#ifndef KEYWORDITEM_H +#define KEYWORDITEM_H + +#include + +using namespace KDevelop; + +namespace Python { + +class KeywordItem : public NormalDeclarationCompletionItem +{ + +public: + KeywordItem(KDevelop::CodeCompletionContext::Ptr context, QString keyword); + virtual void execute ( KTextEditor::Document* document, const KTextEditor::Range& word ); + virtual QVariant data ( const QModelIndex& index, int role, const KDevelop::CodeCompletionModel* model ) const; + QString m_keyword; +}; + +} + +#endif // KEYWORDITEM_H diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index 8985aed..75bfe43 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -6,9 +6,9 @@ #include "pythoncodecompletioncontext.h" -#include #include #include +#include #include #include @@ -26,6 +26,8 @@ #include #include +#include +#include "keyworditem.h" using namespace KDevelop; @@ -63,6 +65,13 @@ QList PythonCodeCompletionContext::completionItems(bo // popup with completion items you don't want } else { + if ( m_operation == PythonCodeCompletionContext::NewStatementCompletion ) { + QStringList keywordItems; + keywordItems << "def" << "class" << "lambda" << "global" << "print"; + foreach ( const QString& current, keywordItems ) { + items << CompletionTreeItemPointer(new KeywordItem(KDevelop::CodeCompletionContext::Ptr(this), current)); + } + } if ( abort ) { return QList(); } @@ -230,6 +239,14 @@ PythonCodeCompletionContext::PythonCodeCompletionContext(DUContextPointer contex return; } + QRegExp newStatementCompletion("(.*)\n[\\s]*$"); + newStatementCompletion.setMinimal(true); + bool isNewStatementCompletion = newStatementCompletion.exactMatch(currentLine); + if ( isNewStatementCompletion ) { + m_operation = PythonCodeCompletionContext::NewStatementCompletion; + return; + } + QRegExp importfile("(.*)\n[\\s]*import[\\s]*$"); importfile.setMinimal(true); bool is_importfile = importfile.exactMatch(currentLine); diff --git a/codecompletion/pythoncodecompletioncontext.h b/codecompletion/pythoncodecompletioncontext.h index 5af62a3..45123f8 100644 --- a/codecompletion/pythoncodecompletioncontext.h +++ b/codecompletion/pythoncodecompletioncontext.h @@ -24,7 +24,8 @@ class KDEVPYTHONCOMPLETION_EXPORT PythonCodeCompletionContext : public KDevelop: MemberAccessCompletion, DefaultCompletion, ImportSubCompletion, - NoCompletion + NoCompletion, + NewStatementCompletion }; PythonCodeCompletionContext(DUContextPointer context, const QString& text, const KDevelop::CursorInRevision& position, int depth); diff --git a/example_ast.py b/example_ast.py index 09b78b3..68b3113 100644 --- a/example_ast.py +++ b/example_ast.py @@ -51,6 +51,14 @@ def func(foo, bar, baz, bang, foobang, foobar, foobazbar, foobazbarbang): if foobazbar < 5: pass +func(sys) +simple_func() + +def func_without_param(): + pass + +func_without_param() + def another_function(param): print param From 22d211b079905de5dff90657c4c1b10c7f35282c Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Thu, 9 Dec 2010 22:58:29 +0100 Subject: [PATCH 8/8] Don't display trivial completion items on full completion --- codecompletion/pythoncodecompletioncontext.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index 75bfe43..61b0a25 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -35,7 +35,7 @@ typedef QPair DeclarationDepthPair; namespace Python { -QList PythonCodeCompletionContext::completionItems(bool& abort, bool /*fullCompletion*/) +QList PythonCodeCompletionContext::completionItems(bool& abort, bool fullCompletion) { if ( abort ) return QList(); @@ -65,7 +65,8 @@ QList PythonCodeCompletionContext::completionItems(bo // popup with completion items you don't want } else { - if ( m_operation == PythonCodeCompletionContext::NewStatementCompletion ) { + // it's stupid to display a 3-letter completion item on manually invoked code completion and makes everything look crowded + if ( m_operation == PythonCodeCompletionContext::NewStatementCompletion && ! fullCompletion ) { QStringList keywordItems; keywordItems << "def" << "class" << "lambda" << "global" << "print"; foreach ( const QString& current, keywordItems ) {