summaryrefslogtreecommitdiff
path: root/src/plugins/python/pythonindenter.cpp
diff options
context:
space:
mode:
authorDavid Schulz <david.schulz@qt.io>2019-07-15 12:50:29 +0200
committerDavid Schulz <david.schulz@qt.io>2019-07-17 06:21:23 +0000
commit3213e12ce7411efd05a544645aaa1ecd74e533a2 (patch)
treeae7187904453f530d4660832ff834371905cefaf /src/plugins/python/pythonindenter.cpp
parent2778a5adab13a16f4a6b3cda0980fa3b4f2b3a5e (diff)
downloadqt-creator-3213e12ce7411efd05a544645aaa1ecd74e533a2.tar.gz
rename PythonEditor plugin to Python
The plugin does not only contain a pure editor, but all kind of support for a programming language like project and run support. Change-Id: I1251367c8db2e7a54986415ffc5b860cb210de3c Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Diffstat (limited to 'src/plugins/python/pythonindenter.cpp')
-rw-r--r--src/plugins/python/pythonindenter.cpp127
1 files changed, 127 insertions, 0 deletions
diff --git a/src/plugins/python/pythonindenter.cpp b/src/plugins/python/pythonindenter.cpp
new file mode 100644
index 0000000000..dff38907ee
--- /dev/null
+++ b/src/plugins/python/pythonindenter.cpp
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+#include "pythonindenter.h"
+#include "pythonscanner.h"
+
+#include <texteditor/tabsettings.h>
+
+#include <algorithm>
+
+namespace Python {
+
+static bool isEmptyLine(const QString &t)
+{
+ return std::all_of(t.cbegin(), t.cend(), [] (QChar c) { return c.isSpace(); });
+}
+
+static inline bool isEmptyLine(const QTextBlock &block)
+{
+ return isEmptyLine(block.text());
+}
+
+static QTextBlock previousNonEmptyBlock(const QTextBlock &block)
+{
+ QTextBlock result = block;
+ while (result.isValid() && isEmptyLine(result))
+ result = result.previous();
+ return result;
+}
+
+PythonIndenter::PythonIndenter(QTextDocument *doc)
+ : TextEditor::TextIndenter(doc)
+{}
+
+/**
+ * @brief Does given character change indentation level?
+ * @param ch Any value
+ * @return True if character increases indentation level at the next line
+ */
+bool PythonIndenter::isElectricCharacter(const QChar &ch) const
+{
+ return ch == ':';
+}
+
+int PythonIndenter::indentFor(const QTextBlock &block,
+ const TextEditor::TabSettings &tabSettings,
+ int /*cursorPositionInEditor*/)
+{
+ QTextBlock previousBlock = block.previous();
+ if (!previousBlock.isValid())
+ return 0;
+
+ // When pasting in actual code, try to skip back past empty lines to an
+ // actual code line to find a suitable indentation. This prevents code from
+ // not being indented when pasting below an empty line.
+ if (!isEmptyLine(block)) {
+ const QTextBlock previousNonEmpty = previousNonEmptyBlock(previousBlock);
+ if (previousNonEmpty.isValid())
+ previousBlock = previousNonEmpty;
+ }
+
+ QString previousLine = previousBlock.text();
+ int indentation = tabSettings.indentationColumn(previousLine);
+
+ if (isElectricLine(previousLine))
+ indentation += tabSettings.m_indentSize;
+ else
+ indentation = qMax<int>(0, indentation + getIndentDiff(previousLine, tabSettings));
+
+ return indentation;
+}
+
+/// @return True if electric character is last non-space character at given string
+bool PythonIndenter::isElectricLine(const QString &line) const
+{
+ if (line.isEmpty())
+ return false;
+
+ // trim spaces in 'if True: '
+ int index = line.length() - 1;
+ while (index > 0 && line[index].isSpace())
+ --index;
+
+ return isElectricCharacter(line[index]);
+}
+
+/// @return negative indent diff if previous line breaks control flow branch
+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 && jumpKeywords.contains(sc.value(tk)))
+ return -tabSettings.m_indentSize;
+ if (tk.format() != Internal::Format_Whitespace)
+ break;
+ }
+ return 0;
+}
+
+} // namespace Python