diff --git a/src/plugins/pythoneditor/pythoneditor.cpp b/src/plugins/pythoneditor/pythoneditor.cpp index 17e75880d80..20acd639184 100644 --- a/src/plugins/pythoneditor/pythoneditor.cpp +++ b/src/plugins/pythoneditor/pythoneditor.cpp @@ -26,8 +26,8 @@ #include "pythoneditor.h" #include "pythoneditorconstants.h" #include "pythoneditorplugin.h" -#include "tools/pythonindenter.h" -#include "tools/pythonhighlighter.h" +#include "pythonindenter.h" +#include "pythonhighlighter.h" #include #include @@ -44,15 +44,15 @@ PythonEditorFactory::PythonEditorFactory() { setId(Constants::C_PYTHONEDITOR_ID); setDisplayName(QCoreApplication::translate("OpenWith::Editors", Constants::C_EDITOR_DISPLAY_NAME)); - addMimeType(QLatin1String(Constants::C_PY_MIMETYPE)); + addMimeType(Constants::C_PY_MIMETYPE); setEditorActionHandlers(TextEditorActionHandler::Format | TextEditorActionHandler::UnCommentSelection | TextEditorActionHandler::UnCollapseAll); - setDocumentCreator([]() { return new TextDocument(Constants::C_PYTHONEDITOR_ID); }); - setIndenterCreator([]() { return new PythonIndenter; }); - setSyntaxHighlighterCreator([]() { return new PythonHighlighter; }); + setDocumentCreator([] { return new TextDocument(Constants::C_PYTHONEDITOR_ID); }); + setIndenterCreator([] { return new PythonIndenter; }); + setSyntaxHighlighterCreator([] { return new PythonHighlighter; }); setCommentStyle(Utils::CommentDefinition::HashStyle); setParenthesesMatchingEnabled(true); setMarksVisible(true); diff --git a/src/plugins/pythoneditor/pythoneditor.h b/src/plugins/pythoneditor/pythoneditor.h index 914b28000aa..96bcc8c03b0 100644 --- a/src/plugins/pythoneditor/pythoneditor.h +++ b/src/plugins/pythoneditor/pythoneditor.h @@ -32,8 +32,6 @@ namespace Internal { class PythonEditorFactory : public TextEditor::TextEditorFactory { - Q_OBJECT - public: PythonEditorFactory(); }; diff --git a/src/plugins/pythoneditor/pythoneditor.pro b/src/plugins/pythoneditor/pythoneditor.pro index f758f758b1e..8a9ad3188c7 100644 --- a/src/plugins/pythoneditor/pythoneditor.pro +++ b/src/plugins/pythoneditor/pythoneditor.pro @@ -10,15 +10,14 @@ HEADERS += \ pythoneditorplugin.h \ pythoneditor.h \ pythoneditorconstants.h \ - tools/pythonhighlighter.h \ - tools/pythonindenter.h \ - tools/lexical/pythonformattoken.h \ - tools/lexical/pythonscanner.h \ - tools/lexical/sourcecodestream.h + pythonhighlighter.h \ + pythonindenter.h \ + pythonformattoken.h \ + pythonscanner.h \ SOURCES += \ pythoneditorplugin.cpp \ pythoneditor.cpp \ - tools/pythonhighlighter.cpp \ - tools/pythonindenter.cpp \ - tools/lexical/pythonscanner.cpp + pythonhighlighter.cpp \ + pythonindenter.cpp \ + pythonscanner.cpp diff --git a/src/plugins/pythoneditor/pythoneditor.qbs b/src/plugins/pythoneditor/pythoneditor.qbs index fa99a59472b..2bfa0d536b1 100644 --- a/src/plugins/pythoneditor/pythoneditor.qbs +++ b/src/plugins/pythoneditor/pythoneditor.qbs @@ -18,18 +18,10 @@ QtcPlugin { "pythoneditorconstants.h", "pythoneditorplugin.cpp", "pythoneditorplugin.h", "pythoneditorplugin.qrc", - ] - } - - Group { - name: "Tools" - prefix: "tools/" - files: [ - "lexical/pythonformattoken.h", - "lexical/pythonscanner.h", "lexical/pythonscanner.cpp", - "lexical/sourcecodestream.h", "pythonhighlighter.h", "pythonhighlighter.cpp", "pythonindenter.cpp", "pythonindenter.h" + "pythonformattoken.h", + "pythonscanner.h", "pythonscanner.cpp" ] } } diff --git a/src/plugins/pythoneditor/pythoneditorplugin.cpp b/src/plugins/pythoneditor/pythoneditorplugin.cpp index d5d4f51053f..84f8a40918f 100644 --- a/src/plugins/pythoneditor/pythoneditorplugin.cpp +++ b/src/plugins/pythoneditor/pythoneditorplugin.cpp @@ -26,7 +26,7 @@ #include "pythoneditorplugin.h" #include "pythoneditor.h" #include "pythoneditorconstants.h" -#include "tools/pythonhighlighter.h" +#include "pythonhighlighter.h" #include #include @@ -65,139 +65,6 @@ using namespace ProjectExplorer; using namespace PythonEditor::Constants; using namespace Utils; -/******************************************************************************* - * List of Python keywords (includes "print" that isn't keyword in python 3 - ******************************************************************************/ -static const char *const LIST_OF_PYTHON_KEYWORDS[] = { - "and", - "as", - "assert", - "break", - "class", - "continue", - "def", - "del", - "elif", - "else", - "except", - "exec", - "finally", - "for", - "from", - "global", - "if", - "import", - "in", - "is", - "lambda", - "not", - "or", - "pass", - "print", - "raise", - "return", - "try", - "while", - "with", - "yield" -}; - -/******************************************************************************* - * List of Python magic methods and attributes - ******************************************************************************/ -static const char *const LIST_OF_PYTHON_MAGICS[] = { - // ctor & dtor - "__init__", - "__del__", - // string conversion functions - "__str__", - "__repr__", - "__unicode__", - // attribute access functions - "__setattr__", - "__getattr__", - "__delattr__", - // binary operators - "__add__", - "__sub__", - "__mul__", - "__truediv__", - "__floordiv__", - "__mod__", - "__pow__", - "__and__", - "__or__", - "__xor__", - "__eq__", - "__ne__", - "__gt__", - "__lt__", - "__ge__", - "__le__", - "__lshift__", - "__rshift__", - "__contains__", - // unary operators - "__pos__", - "__neg__", - "__inv__", - "__abs__", - "__len__", - // item operators like [] - "__getitem__", - "__setitem__", - "__delitem__", - "__getslice__", - "__setslice__", - "__delslice__", - // other functions - "__cmp__", - "__hash__", - "__nonzero__", - "__call__", - "__iter__", - "__reversed__", - "__divmod__", - "__int__", - "__long__", - "__float__", - "__complex__", - "__hex__", - "__oct__", - "__index__", - "__copy__", - "__deepcopy__", - "__sizeof__", - "__trunc__", - "__format__", - // magic attributes - "__name__", - "__module__", - "__dict__", - "__bases__", - "__doc__" -}; - -/******************************************************************************* - * List of python built-in functions and objects - ******************************************************************************/ -static const char *const LIST_OF_PYTHON_BUILTINS[] = { - "range", - "xrange", - "int", - "float", - "long", - "hex", - "oct" - "chr", - "ord", - "len", - "abs", - "None", - "True", - "False" -}; - namespace PythonEditor { namespace Internal { @@ -275,7 +142,7 @@ public: PythonProjectFile(PythonProject *parent, QString fileName) : m_project(parent) { setId("Generic.ProjectFile"); - setMimeType(QLatin1String(PythonMimeType)); + setMimeType(PythonMimeType); setFilePath(FileName::fromString(fileName)); } @@ -405,12 +272,12 @@ PythonRunConfiguration::PythonRunConfiguration(Target *parent, Core::Id id) : m_enabled(true) { Environment sysEnv = Environment::systemEnvironment(); - const QString exec = sysEnv.searchInPath(QLatin1String("python")).toString(); - m_interpreter = exec.isEmpty() ? QLatin1String("python") : exec; + const QString exec = sysEnv.searchInPath("python").toString(); + m_interpreter = exec.isEmpty() ? "python" : exec; addExtraAspect(new LocalEnvironmentAspect(this, LocalEnvironmentAspect::BaseEnvironmentModifier())); - addExtraAspect(new ArgumentsAspect(this, QStringLiteral("PythonEditor.RunConfiguration.Arguments"))); - addExtraAspect(new TerminalAspect(this, QStringLiteral("PythonEditor.RunConfiguration.UseTerminal"))); + addExtraAspect(new ArgumentsAspect(this, "PythonEditor.RunConfiguration.Arguments")); + addExtraAspect(new TerminalAspect(this, "PythonEditor.RunConfiguration.UseTerminal")); setDefaultDisplayName(defaultDisplayName()); } @@ -426,25 +293,23 @@ PythonRunConfiguration::PythonRunConfiguration(Target *parent, PythonRunConfigur QVariantMap PythonRunConfiguration::toMap() const { QVariantMap map(RunConfiguration::toMap()); - map.insert(QLatin1String(MainScriptKey), m_mainScript); - map.insert(QLatin1String(InterpreterKey), m_interpreter); + map.insert(MainScriptKey, m_mainScript); + map.insert(InterpreterKey, m_interpreter); return map; } bool PythonRunConfiguration::fromMap(const QVariantMap &map) { - m_mainScript = map.value(QLatin1String(MainScriptKey)).toString(); - m_interpreter = map.value(QLatin1String(InterpreterKey)).toString(); + m_mainScript = map.value(MainScriptKey).toString(); + m_interpreter = map.value(InterpreterKey).toString(); return RunConfiguration::fromMap(map); } QString PythonRunConfiguration::defaultDisplayName() const { QString result = tr("Run %1").arg(m_mainScript); - if (!m_enabled) { - result += QLatin1Char(' '); - result += tr("(disabled)"); - } + if (!m_enabled) + result += ' ' + tr("(disabled)"); return result; } @@ -527,7 +392,7 @@ class PythonRunConfigurationFactory : public IRunConfigurationFactory public: PythonRunConfigurationFactory() { - setObjectName(QLatin1String("PythonRunConfigurationFactory")); + setObjectName("PythonRunConfigurationFactory"); } QList availableCreationIds(Target *parent, CreationMode mode) const override @@ -655,7 +520,7 @@ bool PythonProject::saveRawList(const QStringList &rawList, const QString &fileN if (!saver.hasError()) { QTextStream stream(saver.file()); foreach (const QString &filePath, rawList) - stream << filePath << QLatin1Char('\n'); + stream << filePath << '\n'; saver.setResult(&stream); } bool result = saver.finalize(ICore::mainWindow()); @@ -834,7 +699,7 @@ Project::RestoreResult PythonProject::fromMap(const QVariantMap &map, QString *e const QList runConfigs = t->runConfigurations(); foreach (const QString &file, m_files) { // skip the 'project' file - if (file.endsWith(QLatin1String(".pyqtc"))) + if (file.endsWith(".pyqtc")) continue; const Id id = idFromScript(file); bool alreadyPresent = false; @@ -875,7 +740,7 @@ QHash sortFilesIntoPaths(const QString &base, const QSet oldFileList) const QString &filePath = it.key(); QStringList components; if (!filePath.isEmpty()) - components = filePath.split(QLatin1Char('/')); + components = filePath.split('/'); FolderNode *folder = findFolderByName(components, components.size()); if (!folder) folder = createFolderByName(components, components.size()); @@ -916,7 +781,7 @@ void PythonProjectNode::refresh(QSet oldFileList) QList fileNodes; foreach (const QString &file, it.value()) { FileType fileType = SourceType; // ### FIXME - if (file.endsWith(QLatin1String(".qrc"))) + if (file.endsWith(".qrc")) fileType = ResourceType; FileNode *fileNode = new FileNode(FileName::fromString(file), fileType, /*generated = */ false); @@ -932,7 +797,7 @@ void PythonProjectNode::refresh(QSet oldFileList) const QString &filePath = it.key(); QStringList components; if (!filePath.isEmpty()) - components = filePath.split(QLatin1Char('/')); + components = filePath.split('/'); FolderNode *folder = findFolderByName(components, components.size()); QList fileNodes; @@ -968,7 +833,7 @@ FolderNode *PythonProjectNode::createFolderByName(const QStringList &components, QString folderName; for (int i = 0; i < end; ++i) { folderName.append(components.at(i)); - folderName += QLatin1Char('/'); + folderName += '/'; } const QString component = components.at(end - 1); @@ -993,7 +858,7 @@ FolderNode *PythonProjectNode::findFolderByName(const QStringList &components, i QString folderName; for (int i = 0; i < end; ++i) { folderName.append(components.at(i)); - folderName += QLatin1Char('/'); + folderName += '/'; } FolderNode *parent = findFolderByName(components, end - 1); @@ -1003,7 +868,7 @@ FolderNode *PythonProjectNode::findFolderByName(const QStringList &components, i const QString baseDir = filePath().toFileInfo().path(); foreach (FolderNode *fn, parent->subFolderNodes()) { - if (fn->filePath().toString() == baseDir + QLatin1Char('/') + folderName) + if (fn->filePath().toString() == baseDir + '/' + folderName) return fn; } return 0; @@ -1080,15 +945,15 @@ void PythonRunControl::start() { emit started(); if (m_interpreter.isEmpty()) { - appendMessage(tr("No Python interpreter specified.") + QLatin1Char('\n'), Utils::ErrorMessageFormat); + appendMessage(tr("No Python interpreter specified.") + '\n', Utils::ErrorMessageFormat); emit finished(); } else if (!QFileInfo::exists(m_interpreter)) { - appendMessage(tr("Python interpreter %1 does not exist.").arg(QDir::toNativeSeparators(m_interpreter)) + QLatin1Char('\n'), + appendMessage(tr("Python interpreter %1 does not exist.").arg(QDir::toNativeSeparators(m_interpreter)) + '\n', Utils::ErrorMessageFormat); emit finished(); } else { m_running = true; - QString msg = tr("Starting %1...").arg(QDir::toNativeSeparators(m_interpreter)) + QLatin1Char('\n'); + QString msg = tr("Starting %1...").arg(QDir::toNativeSeparators(m_interpreter)) + '\n'; appendMessage(msg, Utils::NormalMessageFormat); StandardRunnable r; @@ -1132,7 +997,7 @@ void PythonRunControl::processExited(int exitCode, QProcess::ExitStatus status) msg = tr("%1 exited with code %2") .arg(QDir::toNativeSeparators(m_interpreter)).arg(exitCode); } - appendMessage(msg + QLatin1Char('\n'), Utils::NormalMessageFormat); + appendMessage(msg + '\n', Utils::NormalMessageFormat); emit finished(); } @@ -1149,20 +1014,9 @@ void PythonRunConfigurationWidget::setInterpreter(const QString &interpreter) static PythonEditorPlugin *m_instance = 0; -/// Copies identifiers from array to QSet -static void copyIdentifiers(const char * const words[], size_t bytesCount, QSet &result) -{ - const size_t count = bytesCount / sizeof(const char * const); - for (size_t i = 0; i < count; ++i) - result.insert(QLatin1String(words[i])); -} - PythonEditorPlugin::PythonEditorPlugin() { m_instance = this; - copyIdentifiers(LIST_OF_PYTHON_KEYWORDS, sizeof(LIST_OF_PYTHON_KEYWORDS), m_keywords); - copyIdentifiers(LIST_OF_PYTHON_MAGICS, sizeof(LIST_OF_PYTHON_MAGICS), m_magics); - copyIdentifiers(LIST_OF_PYTHON_BUILTINS, sizeof(LIST_OF_PYTHON_BUILTINS), m_builtins); } PythonEditorPlugin::~PythonEditorPlugin() @@ -1175,7 +1029,7 @@ bool PythonEditorPlugin::initialize(const QStringList &arguments, QString *error Q_UNUSED(arguments) Q_UNUSED(errorMessage) - MimeDatabase::addMimeTypes(QLatin1String(":/pythoneditor/PythonEditor.mimetypes.xml")); + MimeDatabase::addMimeTypes(":/pythoneditor/PythonEditor.mimetypes.xml"); addAutoReleasedObject(new PythonProjectManager); addAutoReleasedObject(new PythonEditorFactory); @@ -1184,28 +1038,13 @@ bool PythonEditorPlugin::initialize(const QStringList &arguments, QString *error // Initialize editor actions handler // Add MIME overlay icons (these icons displayed at Project dock panel) - const QIcon icon = QIcon::fromTheme(QLatin1String(C_PY_MIME_ICON)); + const QIcon icon = QIcon::fromTheme(C_PY_MIME_ICON); if (!icon.isNull()) Core::FileIconProvider::registerIconOverlayForMimeType(icon, C_PY_MIMETYPE); return true; } -QSet PythonEditorPlugin::keywords() -{ - return m_instance->m_keywords; -} - -QSet PythonEditorPlugin::magics() -{ - return m_instance->m_magics; -} - -QSet PythonEditorPlugin::builtins() -{ - return m_instance->m_builtins; -} - } // namespace Internal } // namespace PythonEditor diff --git a/src/plugins/pythoneditor/pythoneditorplugin.h b/src/plugins/pythoneditor/pythoneditorplugin.h index ae2634c188a..db733f7bd2c 100644 --- a/src/plugins/pythoneditor/pythoneditorplugin.h +++ b/src/plugins/pythoneditor/pythoneditorplugin.h @@ -41,14 +41,10 @@ class PythonEditorPlugin : public ExtensionSystem::IPlugin public: PythonEditorPlugin(); - virtual ~PythonEditorPlugin(); + ~PythonEditorPlugin() override; - virtual bool initialize(const QStringList &arguments, QString *errorMessage); - virtual void extensionsInitialized() {} - - static QSet keywords(); - static QSet magics(); - static QSet builtins(); + bool initialize(const QStringList &arguments, QString *errorMessage) override; + void extensionsInitialized() override {} private: QSet m_keywords; diff --git a/src/plugins/pythoneditor/tools/lexical/pythonformattoken.h b/src/plugins/pythoneditor/pythonformattoken.h similarity index 82% rename from src/plugins/pythoneditor/tools/lexical/pythonformattoken.h rename to src/plugins/pythoneditor/pythonformattoken.h index 9ae0d4c21cd..6f1da963b7e 100644 --- a/src/plugins/pythoneditor/tools/lexical/pythonformattoken.h +++ b/src/plugins/pythoneditor/pythonformattoken.h @@ -25,8 +25,6 @@ #pragma once -#include - namespace PythonEditor { namespace Internal { @@ -53,16 +51,14 @@ class FormatToken public: FormatToken() {} - FormatToken(Format format, size_t position, size_t length) - :m_format(format) - ,m_position(int(position)) - ,m_length(int(length)) + FormatToken(Format format, int position, int length) + : m_format(format), m_position(position), m_length(length) {} - inline Format format() const { return m_format; } - inline int begin() const { return m_position; } - inline int end() const { return m_position + m_length; } - inline int length() const { return m_length; } + Format format() const { return m_format; } + int begin() const { return m_position; } + int end() const { return m_position + m_length; } + int length() const { return m_length; } private: Format m_format; diff --git a/src/plugins/pythoneditor/tools/pythonhighlighter.cpp b/src/plugins/pythoneditor/pythonhighlighter.cpp similarity index 86% rename from src/plugins/pythoneditor/tools/pythonhighlighter.cpp rename to src/plugins/pythoneditor/pythonhighlighter.cpp index d0a870acf79..fd3562f7753 100644 --- a/src/plugins/pythoneditor/tools/pythonhighlighter.cpp +++ b/src/plugins/pythoneditor/pythonhighlighter.cpp @@ -34,7 +34,7 @@ */ #include "pythonhighlighter.h" -#include "lexical/pythonscanner.h" +#include "pythonscanner.h" #include #include @@ -62,21 +62,20 @@ namespace Internal { PythonHighlighter::PythonHighlighter() { - static QVector categories; - if (categories.isEmpty()) { - categories << TextEditor::C_NUMBER - << TextEditor::C_STRING - << TextEditor::C_KEYWORD - << TextEditor::C_TYPE - << TextEditor::C_FIELD - << TextEditor::C_JS_SCOPE_VAR - << TextEditor::C_OPERATOR - << TextEditor::C_COMMENT - << TextEditor::C_DOXYGEN_COMMENT - << TextEditor::C_TEXT - << TextEditor::C_VISUAL_WHITESPACE - << TextEditor::C_STRING; - } + static const QVector categories = { + TextEditor::C_NUMBER, + TextEditor::C_STRING, + TextEditor::C_KEYWORD, + TextEditor::C_TYPE, + TextEditor::C_FIELD, + TextEditor::C_JS_SCOPE_VAR, + TextEditor::C_OPERATOR, + TextEditor::C_COMMENT, + TextEditor::C_DOXYGEN_COMMENT, + TextEditor::C_TEXT, + TextEditor::C_VISUAL_WHITESPACE, + TextEditor::C_STRING + }; setTextFormatCategories(categories); } @@ -102,7 +101,7 @@ void PythonHighlighter::highlightBlock(const QString &text) */ static bool isImportKeyword(const QString &keyword) { - return keyword == QLatin1String("import") || keyword == QLatin1String("from"); + return keyword == "import" || keyword == "from"; } /** diff --git a/src/plugins/pythoneditor/tools/pythonhighlighter.h b/src/plugins/pythoneditor/pythonhighlighter.h similarity index 96% rename from src/plugins/pythoneditor/tools/pythonhighlighter.h rename to src/plugins/pythoneditor/pythonhighlighter.h index 6f78a46624e..778d3727b29 100644 --- a/src/plugins/pythoneditor/tools/pythonhighlighter.h +++ b/src/plugins/pythoneditor/pythonhighlighter.h @@ -37,10 +37,8 @@ class PythonHighlighter : public TextEditor::SyntaxHighlighter public: PythonHighlighter(); -protected: - void highlightBlock(const QString &text); - private: + void highlightBlock(const QString &text) override; int highlightLine(const QString &text, int initialState); void highlightImport(Internal::Scanner &scanner); }; diff --git a/src/plugins/pythoneditor/tools/pythonindenter.cpp b/src/plugins/pythoneditor/pythonindenter.cpp similarity index 83% rename from src/plugins/pythoneditor/tools/pythonindenter.cpp rename to src/plugins/pythoneditor/pythonindenter.cpp index 819772c74cf..70b431368cd 100644 --- a/src/plugins/pythoneditor/tools/pythonindenter.cpp +++ b/src/plugins/pythoneditor/pythonindenter.cpp @@ -24,28 +24,12 @@ ****************************************************************************/ #include "pythonindenter.h" -#include "lexical/pythonscanner.h" +#include "pythonscanner.h" #include -#include - namespace PythonEditor { -PythonIndenter::PythonIndenter() -{ - m_jumpKeywords << QLatin1String("return") - << QLatin1String("yield") - << QLatin1String("break") - << QLatin1String("continue") - << QLatin1String("raise") - << QLatin1String("pass"); -} - -PythonIndenter::~PythonIndenter() -{ -} - /** * @brief Does given character change indentation level? * @param ch Any value @@ -53,7 +37,7 @@ PythonIndenter::~PythonIndenter() */ bool PythonIndenter::isElectricCharacter(const QChar &ch) const { - return (ch == QLatin1Char(':')); + return ch == ':'; } int PythonIndenter::indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings) @@ -81,7 +65,7 @@ bool PythonIndenter::isElectricLine(const QString &line) const // trim spaces in 'if True: ' int index = line.length() - 1; - while ((index > 0) && line[index].isSpace()) + while (index > 0 && line[index].isSpace()) --index; return isElectricCharacter(line[index]); @@ -91,10 +75,13 @@ bool PythonIndenter::isElectricLine(const QString &line) const int PythonIndenter::getIndentDiff(const QString &previousLine, const TextEditor::TabSettings &tabSettings) const { + static const QStringList jumpKeywords = { + "return", "yield", "break", "continue", "raise", "pass" }; + Internal::Scanner sc(previousLine.constData(), previousLine.length()); forever { Internal::FormatToken tk = sc.read(); - if ((tk.format() == Internal::Format_Keyword) && m_jumpKeywords.contains(sc.value(tk))) + if (tk.format() == Internal::Format_Keyword && jumpKeywords.contains(sc.value(tk))) return -tabSettings.m_indentSize; if (tk.format() != Internal::Format_Whitespace) break; diff --git a/src/plugins/pythoneditor/tools/pythonindenter.h b/src/plugins/pythoneditor/pythonindenter.h similarity index 92% rename from src/plugins/pythoneditor/tools/pythonindenter.h rename to src/plugins/pythoneditor/pythonindenter.h index c44a0024399..baee5ce78fe 100644 --- a/src/plugins/pythoneditor/tools/pythonindenter.h +++ b/src/plugins/pythoneditor/pythonindenter.h @@ -26,27 +26,21 @@ #pragma once #include -#include namespace PythonEditor { class PythonIndenter : public TextEditor::Indenter { public: - PythonIndenter(); - virtual ~PythonIndenter() override; + PythonIndenter() {} +private: bool isElectricCharacter(const QChar &ch) const override; - int indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings) override; -protected: bool isElectricLine(const QString &line) const; int getIndentDiff(const QString &previousLine, const TextEditor::TabSettings &tabSettings) const; - -private: - QStringList m_jumpKeywords; }; } // namespace PythonEditor diff --git a/src/plugins/pythoneditor/tools/lexical/pythonscanner.cpp b/src/plugins/pythoneditor/pythonscanner.cpp similarity index 50% rename from src/plugins/pythoneditor/tools/lexical/pythonscanner.cpp rename to src/plugins/pythoneditor/pythonscanner.cpp index b8def85018a..89ce77d3321 100644 --- a/src/plugins/pythoneditor/tools/lexical/pythonscanner.cpp +++ b/src/plugins/pythoneditor/pythonscanner.cpp @@ -24,25 +24,15 @@ ****************************************************************************/ #include "pythonscanner.h" -#include "../../pythoneditorconstants.h" -#include "../../pythoneditorplugin.h" -#include -#include +#include "pythoneditorconstants.h" +#include "pythoneditorplugin.h" namespace PythonEditor { namespace Internal { Scanner::Scanner(const QChar *text, const int length) - : m_src(text, length) - , m_state(0) - , m_keywords(PythonEditorPlugin::keywords()) - , m_magics(PythonEditorPlugin::magics()) - , m_builtins(PythonEditorPlugin::builtins()) -{ -} - -Scanner::~Scanner() + : m_text(text), m_textLength(length), m_state(0) { } @@ -58,9 +48,9 @@ int Scanner::state() const FormatToken Scanner::read() { - m_src.setAnchor(); - if (m_src.isEnd()) - return FormatToken(Format_EndOfBlock, m_src.anchor(), 0); + setAnchor(); + if (isEnd()) + return FormatToken(Format_EndOfBlock, anchor(), 0); State state; QChar saved; @@ -77,33 +67,33 @@ FormatToken Scanner::read() QString Scanner::value(const FormatToken &tk) const { - return m_src.value(tk.begin(), tk.length()); + return QString(m_text + tk.begin(), tk.length()); } FormatToken Scanner::onDefaultState() { - QChar first = m_src.peek(); - m_src.move(); + QChar first = peek(); + move(); - if (first == QLatin1Char('\\') && m_src.peek() == QLatin1Char('\n')) { - m_src.move(); - return FormatToken(Format_Whitespace, m_src.anchor(), 2); + if (first == '\\' && peek() == '\n') { + move(); + return FormatToken(Format_Whitespace, anchor(), 2); } - if (first == QLatin1Char('.') && m_src.peek().isDigit()) + if (first == '.' && peek().isDigit()) return readFloatNumber(); - if (first == QLatin1Char('\'') || first == QLatin1Char('\"')) + if (first == '\'' || first == '\"') return readStringLiteral(first); - if (first.isLetter() || (first == QLatin1Char('_'))) + if (first.isLetter() || first == '_') return readIdentifier(); if (first.isDigit()) return readNumber(); - if (first == QLatin1Char('#')) { - if (m_src.peek() == QLatin1Char('#')) + if (first == '#') { + if (peek() == '#') return readDoxygenComment(); return readComment(); } @@ -120,10 +110,10 @@ FormatToken Scanner::onDefaultState() */ void Scanner::checkEscapeSequence(QChar quoteChar) { - if (m_src.peek() == QLatin1Char('\\')) { - m_src.move(); - QChar ch = m_src.peek(); - if (ch == QLatin1Char('\n') || ch.isNull()) + if (peek() == '\\') { + move(); + QChar ch = peek(); + if (ch == '\n' || ch.isNull()) saveState(State_String, quoteChar); } } @@ -133,45 +123,43 @@ void Scanner::checkEscapeSequence(QChar quoteChar) */ FormatToken Scanner::readStringLiteral(QChar quoteChar) { - QChar ch = m_src.peek(); - if (ch == quoteChar && m_src.peek(1) == quoteChar) { + QChar ch = peek(); + if (ch == quoteChar && peek(1) == quoteChar) { saveState(State_MultiLineString, quoteChar); return readMultiLineStringLiteral(quoteChar); } while (ch != quoteChar && !ch.isNull()) { checkEscapeSequence(quoteChar); - m_src.move(); - ch = m_src.peek(); + move(); + ch = peek(); } if (ch == quoteChar) clearState(); - m_src.move(); - return FormatToken(Format_String, m_src.anchor(), m_src.length()); + move(); + return FormatToken(Format_String, anchor(), length()); } /** - reads multi-line string literal, surrounded by ''' or """ sequencies + reads multi-line string literal, surrounded by ''' or """ sequences */ FormatToken Scanner::readMultiLineStringLiteral(QChar quoteChar) { for (;;) { - QChar ch = m_src.peek(); + QChar ch = peek(); if (ch.isNull()) break; - if (ch == quoteChar - && (m_src.peek(1) == quoteChar) - && (m_src.peek(2) == quoteChar)) { + if (ch == quoteChar && peek(1) == quoteChar && peek(2) == quoteChar) { clearState(); - m_src.move(); - m_src.move(); - m_src.move(); + move(); + move(); + move(); break; } - m_src.move(); + move(); } - return FormatToken(Format_String, m_src.anchor(), m_src.length()); + return FormatToken(Format_String, anchor(), length()); } /** @@ -179,71 +167,110 @@ FormatToken Scanner::readMultiLineStringLiteral(QChar quoteChar) */ FormatToken Scanner::readIdentifier() { - QChar ch = m_src.peek(); - while (ch.isLetterOrNumber() || (ch == QLatin1Char('_'))) { - m_src.move(); - ch = m_src.peek(); - } - QString value = m_src.value(); + static const QSet keywords = { + "and", "as", "assert", "break", "class", "continue", "def", "del", "elif", + "else", "except", "exec", "finally", "for", "from", "global", "if", "import", + "in", "is", "lambda", "not", "or", "pass", "print", "raise", "return", "try", + "while", "with", "yield" + }; + // List of Python magic methods and attributes + static const QSet magics = { + // ctor & dtor + "__init__", "__del__", + // string conversion functions + "__str__", "__repr__", "__unicode__", + // attribute access functions + "__setattr__", "__getattr__", "__delattr__", + // binary operators + "__add__", "__sub__", "__mul__", "__truediv__", "__floordiv__", "__mod__", + "__pow__", "__and__", "__or__", "__xor__", "__eq__", "__ne__", "__gt__", + "__lt__", "__ge__", "__le__", "__lshift__", "__rshift__", "__contains__", + // unary operators + "__pos__", "__neg__", "__inv__", "__abs__", "__len__", + // item operators like [] + "__getitem__", "__setitem__", "__delitem__", "__getslice__", "__setslice__", + "__delslice__", + // other functions + "__cmp__", "__hash__", "__nonzero__", "__call__", "__iter__", "__reversed__", + "__divmod__", "__int__", "__long__", "__float__", "__complex__", "__hex__", + "__oct__", "__index__", "__copy__", "__deepcopy__", "__sizeof__", "__trunc__", + "__format__", + // magic attributes + "__name__", "__module__", "__dict__", "__bases__", "__doc__" + }; + + // List of python built-in functions and objects + static const QSet builtins = { + "range", "xrange", "int", "float", "long", "hex", "oct" "chr", "ord", + "len", "abs", "None", "True", "False" + }; + + QChar ch = peek(); + while (ch.isLetterOrNumber() || ch == '_') { + move(); + ch = peek(); + } + + const QString v = QString(m_text + m_markedPosition, length()); Format tkFormat = Format_Identifier; - if (value == QLatin1String("self")) + if (v == "self") tkFormat = Format_ClassField; - else if (m_builtins.contains(value)) + else if (builtins.contains(v)) tkFormat = Format_Type; - else if (m_magics.contains(value)) + else if (magics.contains(v)) tkFormat = Format_MagicAttr; - else if (m_keywords.contains(value)) + else if (keywords.contains(v)) tkFormat = Format_Keyword; - return FormatToken(tkFormat, m_src.anchor(), m_src.length()); + return FormatToken(tkFormat, anchor(), length()); } inline static bool isHexDigit(QChar ch) { - return (ch.isDigit() - || (ch >= QLatin1Char('a') && ch <= QLatin1Char('f')) - || (ch >= QLatin1Char('A') && ch <= QLatin1Char('F'))); + return ch.isDigit() + || (ch >= 'a' && ch <= 'f') + || (ch >= 'A' && ch <= 'F'); } inline static bool isOctalDigit(QChar ch) { - return (ch.isDigit() && ch != QLatin1Char('8') && ch != QLatin1Char('9')); + return ch.isDigit() && ch != '8' && ch != '9'; } inline static bool isBinaryDigit(QChar ch) { - return (ch == QLatin1Char('0') || ch == QLatin1Char('1')); + return ch == '0' || ch == '1'; } inline static bool isValidIntegerSuffix(QChar ch) { - return (ch == QLatin1Char('l') || ch == QLatin1Char('L')); + return ch == 'l' || ch == 'L'; } FormatToken Scanner::readNumber() { - if (!m_src.isEnd()) { - QChar ch = m_src.peek(); - if (ch.toLower() == QLatin1Char('b')) { - m_src.move(); - while (isBinaryDigit(m_src.peek())) - m_src.move(); - } else if (ch.toLower() == QLatin1Char('o')) { - m_src.move(); - while (isOctalDigit(m_src.peek())) - m_src.move(); - } else if (ch.toLower() == QLatin1Char('x')) { - m_src.move(); - while (isHexDigit(m_src.peek())) - m_src.move(); + if (!isEnd()) { + QChar ch = peek(); + if (ch.toLower() == 'b') { + move(); + while (isBinaryDigit(peek())) + move(); + } else if (ch.toLower() == 'o') { + move(); + while (isOctalDigit(peek())) + move(); + } else if (ch.toLower() == 'x') { + move(); + while (isHexDigit(peek())) + move(); } else { // either integer or float number return readFloatNumber(); } - if (isValidIntegerSuffix(m_src.peek())) - m_src.move(); + if (isValidIntegerSuffix(peek())) + move(); } - return FormatToken(Format_Number, m_src.anchor(), m_src.length()); + return FormatToken(Format_Number, anchor(), length()); } FormatToken Scanner::readFloatNumber() @@ -254,26 +281,26 @@ FormatToken Scanner::readFloatNumber() State_FRACTION, State_EXPONENT } state; - state = (m_src.peek(-1) == QLatin1Char('.')) ? State_FRACTION : State_INTEGER; + state = (peek(-1) == '.') ? State_FRACTION : State_INTEGER; for (;;) { - QChar ch = m_src.peek(); + QChar ch = peek(); if (ch.isNull()) break; if (state == State_INTEGER) { - if (ch == QLatin1Char('.')) + if (ch == '.') state = State_FRACTION; else if (!ch.isDigit()) break; } else if (state == State_FRACTION) { - if (ch == QLatin1Char('e') || ch == QLatin1Char('E')) { - QChar next = m_src.peek(1); - QChar next2 = m_src.peek(2); + if (ch == 'e' || ch == 'E') { + QChar next = peek(1); + QChar next2 = peek(2); bool isExp = next.isDigit() - || (((next == QLatin1Char('-')) || (next == QLatin1Char('+'))) && next2.isDigit()); + || ((next == '-' || next == '+') && next2.isDigit()); if (isExp) { - m_src.move(); + move(); state = State_EXPONENT; } else { break; @@ -284,15 +311,15 @@ FormatToken Scanner::readFloatNumber() } else if (!ch.isDigit()) { break; } - m_src.move(); + move(); } - QChar ch = m_src.peek(); - if ((state == State_INTEGER && (ch == QLatin1Char('l') || ch == QLatin1Char('L'))) - || (ch == QLatin1Char('j') || ch == QLatin1Char('J'))) - m_src.move(); + QChar ch = peek(); + if ((state == State_INTEGER && (ch == 'l' || ch == 'L')) + || (ch == 'j' || ch =='J')) + move(); - return FormatToken(Format_Number, m_src.anchor(), m_src.length()); + return FormatToken(Format_Number, anchor(), length()); } /** @@ -300,12 +327,12 @@ FormatToken Scanner::readFloatNumber() */ FormatToken Scanner::readComment() { - QChar ch = m_src.peek(); - while (ch != QLatin1Char('\n') && !ch.isNull()) { - m_src.move(); - ch = m_src.peek(); + QChar ch = peek(); + while (ch != '\n' && !ch.isNull()) { + move(); + ch = peek(); } - return FormatToken(Format_Comment, m_src.anchor(), m_src.length()); + return FormatToken(Format_Comment, anchor(), length()); } /** @@ -313,12 +340,12 @@ FormatToken Scanner::readComment() */ FormatToken Scanner::readDoxygenComment() { - QChar ch = m_src.peek(); - while (ch != QLatin1Char('\n') && !ch.isNull()) { - m_src.move(); - ch = m_src.peek(); + QChar ch = peek(); + while (ch != '\n' && !ch.isNull()) { + move(); + ch = peek(); } - return FormatToken(Format_Doxygen, m_src.anchor(), m_src.length()); + return FormatToken(Format_Doxygen, anchor(), length()); } /** @@ -326,9 +353,9 @@ FormatToken Scanner::readDoxygenComment() */ FormatToken Scanner::readWhiteSpace() { - while (m_src.peek().isSpace()) - m_src.move(); - return FormatToken(Format_Whitespace, m_src.anchor(), m_src.length()); + while (peek().isSpace()) + move(); + return FormatToken(Format_Whitespace, anchor(), length()); } /** @@ -336,13 +363,13 @@ FormatToken Scanner::readWhiteSpace() */ FormatToken Scanner::readOperator() { - const QString EXCLUDED_CHARS = QLatin1String("\'\"_#"); - QChar ch = m_src.peek(); + static const QString EXCLUDED_CHARS = "\'\"_#"; + QChar ch = peek(); while (ch.isPunct() && !EXCLUDED_CHARS.contains(ch)) { - m_src.move(); - ch = m_src.peek(); + move(); + ch = peek(); } - return FormatToken(Format_Operator, m_src.anchor(), m_src.length()); + return FormatToken(Format_Operator, anchor(), length()); } void Scanner::clearState() diff --git a/src/plugins/pythoneditor/tools/lexical/pythonscanner.h b/src/plugins/pythoneditor/pythonscanner.h similarity index 77% rename from src/plugins/pythoneditor/tools/lexical/pythonscanner.h rename to src/plugins/pythoneditor/pythonscanner.h index 0b8dea5800b..d1633a7de28 100644 --- a/src/plugins/pythoneditor/tools/lexical/pythonscanner.h +++ b/src/plugins/pythoneditor/pythonscanner.h @@ -26,10 +26,8 @@ #pragma once #include "pythonformattoken.h" -#include "sourcecodestream.h" #include -#include namespace PythonEditor { namespace Internal { @@ -39,8 +37,8 @@ namespace Internal { */ class Scanner { - Scanner(const Scanner &other); - void operator =(const Scanner &other); + Scanner(const Scanner &other) = delete; + void operator=(const Scanner &other) = delete; public: enum State { @@ -50,7 +48,6 @@ public: }; Scanner(const QChar *text, const int length); - ~Scanner(); void setState(int state); int state() const; @@ -75,11 +72,26 @@ private: void saveState(State state, QChar savedData); void parseState(State &state, QChar &savedData) const; - SourceCodeStream m_src; + void setAnchor() { m_markedPosition = m_position; } + void move() { ++m_position; } + int length() const { return m_position - m_markedPosition; } + int anchor() const { return m_markedPosition; } + bool isEnd() const { return m_position >= m_textLength; } + + QChar peek(int offset = 0) const + { + int pos = m_position + offset; + if (pos >= m_textLength) + return QLatin1Char('\0'); + return m_text[pos]; + } + + const QChar *m_text; + const int m_textLength; + int m_position = 0; + int m_markedPosition = 0; + int m_state; - const QSet m_keywords; - const QSet m_magics; - const QSet m_builtins; }; } // namespace Internal diff --git a/src/plugins/pythoneditor/tools/lexical/sourcecodestream.h b/src/plugins/pythoneditor/tools/lexical/sourcecodestream.h deleted file mode 100644 index 7c8183b453e..00000000000 --- a/src/plugins/pythoneditor/tools/lexical/sourcecodestream.h +++ /dev/null @@ -1,95 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include - -namespace PythonEditor { -namespace Internal { - -class SourceCodeStream -{ -public: - SourceCodeStream(const QChar *text, int length) - :m_text(text) - ,m_textLength(length) - ,m_position(0) - ,m_markedPosition(0) - {} - - inline void setAnchor() - { - m_markedPosition = m_position; - } - - inline void move() - { - ++m_position; - } - - inline int length() const - { - return m_position - m_markedPosition; - } - - inline int anchor() const - { - return m_markedPosition; - } - - inline bool isEnd() const - { - return m_position >= m_textLength; - } - - inline QChar peek(int offset = 0) const - { - int pos = m_position + offset; - if (pos >= m_textLength) - return QLatin1Char('\0'); - return m_text[pos]; - } - - inline QString value() const - { - const QChar *start = m_text + m_markedPosition; - return QString(start, length()); - } - - inline QString value(int begin, int length) const - { - return QString(m_text + begin, length); - } - -private: - const QChar *m_text; - const int m_textLength; - int m_position; - int m_markedPosition; -}; - -} // namespace Internal -} // namespace PythonEditor