From c0a0c610500b8902093749bb1ba8ea25983b3240 Mon Sep 17 00:00:00 2001 From: Roberto Raggi <roberto.raggi@nokia.com> Date: Fri, 12 Nov 2010 17:11:20 +0100 Subject: [PATCH] Initial work on the code completion for GLSL files. --- src/plugins/glsleditor/glslcodecompletion.cpp | 267 ++++++++++++++++++ src/plugins/glsleditor/glslcodecompletion.h | 103 +++++++ src/plugins/glsleditor/glsleditor.pro | 6 +- src/plugins/glsleditor/glsleditorplugin.cpp | 18 +- 4 files changed, 385 insertions(+), 9 deletions(-) create mode 100644 src/plugins/glsleditor/glslcodecompletion.cpp create mode 100644 src/plugins/glsleditor/glslcodecompletion.h diff --git a/src/plugins/glsleditor/glslcodecompletion.cpp b/src/plugins/glsleditor/glslcodecompletion.cpp new file mode 100644 index 00000000000..359e4835207 --- /dev/null +++ b/src/plugins/glsleditor/glslcodecompletion.cpp @@ -0,0 +1,267 @@ +/************************************************************************** +** +** 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. +** +**************************************************************************/ +#include "glslcodecompletion.h" +#include "glsleditor.h" +#include <QtCore/QDebug> + +using namespace GLSLEditor; + +static const char *glsl_keywords[] = +{ // ### TODO: get the keywords from the lexer + "attribute", + "bool", + "break", + "bvec2", + "bvec3", + "bvec4", + "case", + "centroid", + "const", + "continue", + "default", + "discard", + "dmat2", + "dmat2x2", + "dmat2x3", + "dmat2x4", + "dmat3", + "dmat3x2", + "dmat3x3", + "dmat3x4", + "dmat4", + "dmat4x2", + "dmat4x3", + "dmat4x4", + "do", + "double", + "dvec2", + "dvec3", + "dvec4", + "else", + "false", + "flat", + "float", + "for", + "highp", + "if", + "in", + "inout", + "int", + "invariant", + "isampler1D", + "isampler1DArray", + "isampler2D", + "isampler2DArray", + "isampler2DMS", + "isampler2DMSArray", + "isampler2DRect", + "isampler3D", + "isamplerBuffer", + "isamplerCube", + "isamplerCubeArray", + "ivec2", + "ivec3", + "ivec4", + "layout", + "lowp", + "mat2", + "mat2x2", + "mat2x3", + "mat2x4", + "mat3", + "mat3x2", + "mat3x3", + "mat3x4", + "mat4", + "mat4x2", + "mat4x3", + "mat4x4", + "mediump", + "noperspective", + "out", + "patch", + "precision", + "return", + "sample", + "sampler1D", + "sampler1DArray", + "sampler1DArrayShadow", + "sampler1DShadow", + "sampler2D", + "sampler2DArray", + "sampler2DArrayShadow", + "sampler2DMS", + "sampler2DMSArray", + "sampler2DRect", + "sampler2DRectShadow", + "sampler2DShadow", + "sampler3D", + "samplerBuffer", + "samplerCube", + "samplerCubeArray", + "samplerCubeArrayShadow", + "samplerCubeShadow", + "smooth", + "struct", + "subroutine", + "switch", + "true", + "uint", + "uniform", + "usampler1D", + "usampler1DArray", + "usampler2D", + "usampler2DArray", + "usampler2DMS", + "usampler2DMSarray", + "usampler2DRect", + "usampler3D", + "usamplerBuffer", + "usamplerCube", + "usamplerCubeArray", + "uvec2", + "uvec3", + "uvec4", + "varying", + "vec2", + "vec3", + "vec4", + "void", + "while", + 0 +}; + +CodeCompletion::CodeCompletion(QObject *parent) + : ICompletionCollector(parent), + m_editor(0), + m_startPosition(-1), + m_restartCompletion(false) +{ + for (const char **it = glsl_keywords; *it; ++it) { + TextEditor::CompletionItem item(this); + item.text = QString::fromLatin1(*it); + m_keywordCompletions.append(item); + } +} + +CodeCompletion::~CodeCompletion() +{ +} + +TextEditor::ITextEditable *CodeCompletion::editor() const +{ + return m_editor; +} + +int CodeCompletion::startPosition() const +{ + return m_startPosition; +} + +bool CodeCompletion::supportsEditor(TextEditor::ITextEditable *editor) +{ + if (qobject_cast<GLSLTextEditor *>(editor->widget()) != 0) + return true; + + return false; +} + +bool CodeCompletion::triggersCompletion(TextEditor::ITextEditable *editor) +{ + Q_UNUSED(editor); + return false; +} + +int CodeCompletion::startCompletion(TextEditor::ITextEditable *editor) +{ + m_editor = editor; + + int pos = editor->position() - 1; + QChar ch = editor->characterAt(pos); + while (ch.isLetterOrNumber()) + ch = editor->characterAt(--pos); + + m_completions += m_keywordCompletions; + + m_startPosition = pos + 1; + return m_startPosition; +} + +void CodeCompletion::completions(QList<TextEditor::CompletionItem> *completions) +{ + const int length = m_editor->position() - m_startPosition; + + if (length == 0) + *completions = m_completions; + else if (length > 0) { + const QString key = m_editor->textAt(m_startPosition, length); + + filter(m_completions, completions, key); + + if (completions->size() == 1) { + if (key == completions->first().text) + completions->clear(); + } + } +} + +bool CodeCompletion::typedCharCompletes(const TextEditor::CompletionItem &item, QChar typedChar) +{ + Q_UNUSED(item); + Q_UNUSED(typedChar); + return false; +} + +void CodeCompletion::complete(const TextEditor::CompletionItem &item, QChar typedChar) +{ + Q_UNUSED(typedChar); + + QString toInsert = item.text; + + const int length = m_editor->position() - m_startPosition; + m_editor->setCurPos(m_startPosition); + m_editor->replace(length, toInsert); + + if (toInsert.endsWith(QLatin1Char('.')) || toInsert.endsWith(QLatin1Char('('))) + m_restartCompletion = true; +} + +bool CodeCompletion::partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems) +{ + return ICompletionCollector::partiallyComplete(completionItems); +} + +void CodeCompletion::cleanup() +{ + m_editor = 0; + m_completions.clear(); + m_restartCompletion = false; + m_startPosition = -1; +} + diff --git a/src/plugins/glsleditor/glslcodecompletion.h b/src/plugins/glsleditor/glslcodecompletion.h new file mode 100644 index 00000000000..d75c195e792 --- /dev/null +++ b/src/plugins/glsleditor/glslcodecompletion.h @@ -0,0 +1,103 @@ +/************************************************************************** +** +** 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 GLSLCODECOMPLETION_H +#define GLSLCODECOMPLETION_H + +#include <texteditor/icompletioncollector.h> + +namespace GLSLEditor { + +class CodeCompletion: public TextEditor::ICompletionCollector +{ + Q_OBJECT + +public: + CodeCompletion(QObject *parent = 0); + virtual ~CodeCompletion(); + + /* Returns the current active ITextEditable */ + virtual TextEditor::ITextEditable *editor() const; + virtual int startPosition() const; + + /* + * Returns true if this completion collector can be used with the given editor. + */ + virtual bool supportsEditor(TextEditor::ITextEditable *editor); + + /* This method should return whether the cursor is at a position which could + * trigger an autocomplete. It will be called each time a character is typed in + * the text editor. + */ + virtual bool triggersCompletion(TextEditor::ITextEditable *editor); + + // returns starting position + virtual int startCompletion(TextEditor::ITextEditable *editor); + + /* This method should add all the completions it wants to show into the list, + * based on the given cursor position. + */ + virtual void completions(QList<TextEditor::CompletionItem> *completions); + + /** + * This method should return true when the given typed character should cause + * the selected completion item to be completed. + */ + virtual bool typedCharCompletes(const TextEditor::CompletionItem &item, QChar typedChar); + + /** + * This method should complete the given completion item. + * + * \param typedChar Non-null when completion was triggered by typing a + * character. Possible values depend on typedCharCompletes() + */ + virtual void complete(const TextEditor::CompletionItem &item, QChar typedChar); + + /* This method gives the completion collector a chance to partially complete + * based on a set of items. The general use case is to complete the common + * prefix shared by all possible completion items. + * + * Returns whether the completion popup should be closed. + */ + virtual bool partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems); + + /* Called when it's safe to clean up the completion items. + */ + virtual void cleanup(); + +private: + QList<TextEditor::CompletionItem> m_completions; + QList<TextEditor::CompletionItem> m_keywordCompletions; + TextEditor::ITextEditable *m_editor; + int m_startPosition; + bool m_restartCompletion; +}; + +} // namespace GLSLEditor + +#endif // GLSLCODECOMPLETION_H diff --git a/src/plugins/glsleditor/glsleditor.pro b/src/plugins/glsleditor/glsleditor.pro index 6eb0334c2d2..1eb24f3c76a 100644 --- a/src/plugins/glsleditor/glsleditor.pro +++ b/src/plugins/glsleditor/glsleditor.pro @@ -15,7 +15,8 @@ glsleditorconstants.h \ glsleditoreditable.h \ glsleditorfactory.h \ glsleditorplugin.h \ - glslhighlighter.h + glslhighlighter.h \ + glslcodecompletion.h SOURCES += \ glsleditor.cpp \ @@ -23,7 +24,8 @@ glsleditoractionhandler.cpp \ glsleditoreditable.cpp \ glsleditorfactory.cpp \ glsleditorplugin.cpp \ - glslhighlighter.cpp + glslhighlighter.cpp \ + glslcodecompletion.cpp OTHER_FILES += GLSLEditor.mimetypes.xml RESOURCES += glsleditor.qrc diff --git a/src/plugins/glsleditor/glsleditorplugin.cpp b/src/plugins/glsleditor/glsleditorplugin.cpp index 2c8de088bd8..7608ab3b428 100644 --- a/src/plugins/glsleditor/glsleditorplugin.cpp +++ b/src/plugins/glsleditor/glsleditorplugin.cpp @@ -31,6 +31,7 @@ #include "glsleditor.h" #include "glsleditorconstants.h" #include "glsleditorfactory.h" +#include "glslcodecompletion.h" #include <coreplugin/icore.h> #include <coreplugin/coreconstants.h> @@ -107,6 +108,9 @@ bool GLSLEditorPlugin::initialize(const QStringList & /*arguments*/, QString *er m_editor = new GLSLEditorFactory(this); addObject(m_editor); + CodeCompletion *completion = new CodeCompletion(this); + addAutoReleasedObject(completion); + m_actionHandler = new TextEditor::TextEditorActionHandler(GLSLEditor::Constants::C_GLSLEDITOR_ID, TextEditor::TextEditorActionHandler::Format | TextEditor::TextEditorActionHandler::UnCommentSelection @@ -122,7 +126,7 @@ bool GLSLEditorPlugin::initialize(const QStringList & /*arguments*/, QString *er menu->setTitle(tr("GLSL")); am->actionContainer(Core::Constants::M_TOOLS)->addMenu(glslToolsMenu); - Core::Command *cmd; + Core::Command *cmd = 0; // Insert marker for "Refactoring" menu: Core::Context globalContext(Core::Constants::C_GLOBAL); @@ -137,10 +141,10 @@ bool GLSLEditorPlugin::initialize(const QStringList & /*arguments*/, QString *er contextMenu->addAction(cmd); // Set completion settings and keep them up to date -// TextEditor::TextEditorSettings *textEditorSettings = TextEditor::TextEditorSettings::instance(); -// completion->setCompletionSettings(textEditorSettings->completionSettings()); -// connect(textEditorSettings, SIGNAL(completionSettingsChanged(TextEditor::CompletionSettings)), -// completion, SLOT(setCompletionSettings(TextEditor::CompletionSettings))); + TextEditor::TextEditorSettings *textEditorSettings = TextEditor::TextEditorSettings::instance(); + completion->setCompletionSettings(textEditorSettings->completionSettings()); + connect(textEditorSettings, SIGNAL(completionSettingsChanged(TextEditor::CompletionSettings)), + completion, SLOT(setCompletionSettings(TextEditor::CompletionSettings))); error_message->clear(); @@ -170,8 +174,8 @@ void GLSLEditorPlugin::initializeEditor(GLSLEditor::GLSLTextEditor *editor) TextEditor::TextEditorSettings::instance()->initializeEditor(editor); // // auto completion -// connect(editor, SIGNAL(requestAutoCompletion(TextEditor::ITextEditable*, bool)), -// TextEditor::CompletionSupport::instance(), SLOT(autoComplete(TextEditor::ITextEditable*, bool))); + connect(editor, SIGNAL(requestAutoCompletion(TextEditor::ITextEditable*, bool)), + TextEditor::CompletionSupport::instance(), SLOT(autoComplete(TextEditor::ITextEditable*, bool))); // // quick fix // connect(editor, SIGNAL(requestQuickFix(TextEditor::ITextEditable*)), -- GitLab