Skip to content

Commit

Permalink
[console] Fix exception when running scripts (followup cce7aa7)
Browse files Browse the repository at this point in the history
and move responsibility for showing warning messages to QgsCodeEditor
base class, so that the same code can be used by other dialog script editors
  • Loading branch information
nyalldawson committed Oct 12, 2020
1 parent aaa813a commit 5c8013d
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 49 deletions.
61 changes: 12 additions & 49 deletions python/console/console_editor.py
Expand Up @@ -80,31 +80,18 @@ def eventFilter(self, obj, event):


class Editor(QgsCodeEditorPython): class Editor(QgsCodeEditorPython):


MARKER_NUM = 6

def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self.parent = parent self.parent = parent
# recent modification time # recent modification time
self.lastModified = 0 self.lastModified = 0
self.opening = ['(', '{', '[', "'", '"'] self.opening = ['(', '{', '[', "'", '"']
self.closing = [')', '}', ']', "'", '"'] self.closing = [')', '}', ']', "'", '"']

# List of marker line to be deleted from check syntax
self.bufferMarkerLine = []

self.settings = QgsSettings() self.settings = QgsSettings()


self.markerDefine(QgsApplication.getThemePixmap("console/iconSyntaxErrorConsole.svg"),
self.MARKER_NUM)

self.setMinimumHeight(120) self.setMinimumHeight(120)

self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)


# Annotations
self.setAnnotationDisplay(QsciScintilla.ANNOTATION_BOXED)

# Disable command key # Disable command key
ctrl, shift = self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16 ctrl, shift = self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16
self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl) self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl)
Expand Down Expand Up @@ -160,9 +147,9 @@ def contextMenuEvent(self, e):
QCoreApplication.translate("PythonConsole", "Hide Editor"), QCoreApplication.translate("PythonConsole", "Hide Editor"),
self.hideEditor) self.hideEditor)
menu.addSeparator() # ------------------------------ menu.addSeparator() # ------------------------------
syntaxCheck = menu.addAction(QgsApplication.getThemeIcon("console/iconSyntaxErrorConsole.svg"), syntaxCheckAction = menu.addAction(QgsApplication.getThemeIcon("console/iconSyntaxErrorConsole.svg"),
QCoreApplication.translate("PythonConsole", "Check Syntax"), QCoreApplication.translate("PythonConsole", "Check Syntax"),
self.syntaxCheck, 'Ctrl+4') self.syntaxCheck, 'Ctrl+4')
runSelected = menu.addAction(QgsApplication.getThemeIcon("console/mIconRunConsole.svg"), # spellok runSelected = menu.addAction(QgsApplication.getThemeIcon("console/mIconRunConsole.svg"), # spellok
QCoreApplication.translate("PythonConsole", "Run Selected"), QCoreApplication.translate("PythonConsole", "Run Selected"),
self.runSelectedCode, 'Ctrl+E') # spellok self.runSelectedCode, 'Ctrl+E') # spellok
Expand Down Expand Up @@ -218,7 +205,7 @@ def contextMenuEvent(self, e):
menu.addAction(QgsApplication.getThemeIcon("console/iconSettingsConsole.svg"), menu.addAction(QgsApplication.getThemeIcon("console/iconSettingsConsole.svg"),
QCoreApplication.translate("PythonConsole", "Options…"), QCoreApplication.translate("PythonConsole", "Options…"),
self.parent.pc.openSettings) self.parent.pc.openSettings)
syntaxCheck.setEnabled(False) syntaxCheckAction.setEnabled(False)
pasteAction.setEnabled(False) pasteAction.setEnabled(False)
pyQGISHelpAction.setEnabled(False) pyQGISHelpAction.setEnabled(False)
gist_menu.setEnabled(False) gist_menu.setEnabled(False)
Expand All @@ -237,7 +224,7 @@ def contextMenuEvent(self, e):
pyQGISHelpAction.setEnabled(True) pyQGISHelpAction.setEnabled(True)
if not self.text() == '': if not self.text() == '':
selectAllAction.setEnabled(True) selectAllAction.setEnabled(True)
syntaxCheck.setEnabled(True) syntaxCheckAction.setEnabled(True)
if self.isUndoAvailable(): if self.isUndoAvailable():
undoAction.setEnabled(True) undoAction.setEnabled(True)
if self.isRedoAvailable(): if self.isRedoAvailable():
Expand Down Expand Up @@ -461,7 +448,7 @@ def runScriptCode(self):
self.parent.pc.callWidgetMessageBarEditor(msgEditorBlank, 0, True) self.parent.pc.callWidgetMessageBarEditor(msgEditorBlank, 0, True)
return return


if self.syntaxCheck(fromContextMenu=False): if self.syntaxCheck():
if filename and self.isModified() and autoSave: if filename and self.isModified() and autoSave:
self.parent.save(filename) self.parent.save(filename)
elif not filename or self.isModified(): elif not filename or self.isModified():
Expand Down Expand Up @@ -496,16 +483,13 @@ def goToLine(self, objName, linenr):
self.setFocus() self.setFocus()


def syntaxCheck(self): def syntaxCheck(self):
eline = None
ecolumn = 0
edescr = ''
source = self.text() source = self.text()
self.clearWarnings()
try: try:
filename = self.parent.tw.currentWidget().path filename = self.parent.tw.currentWidget().path
if not filename: if not filename:
tmpFile = self.createTempFile() tmpFile = self.createTempFile()
filename = tmpFile filename = tmpFile
# source = open(filename, 'r').read() + '\n'
if isinstance(source, type("")): if isinstance(source, type("")):
source = source.encode('utf-8') source = source.encode('utf-8')
if isinstance(filename, type("")): if isinstance(filename, type("")):
Expand All @@ -514,37 +498,16 @@ def syntaxCheck(self):
compile(source, filename, 'exec') compile(source, filename, 'exec')
except SyntaxError as detail: except SyntaxError as detail:
eline = detail.lineno and detail.lineno or 1 eline = detail.lineno and detail.lineno or 1
eline -= 1
ecolumn = detail.offset and detail.offset or 1 ecolumn = detail.offset and detail.offset or 1
edescr = detail.msg edescr = detail.msg
if eline is not None:
eline -= 1 self.addWarning(eline, edescr)
for markerLine in self.bufferMarkerLine:
self.markerDelete(markerLine)
self.clearAnnotations(markerLine)
self.bufferMarkerLine.remove(markerLine)
if (eline) not in self.bufferMarkerLine:
self.bufferMarkerLine.append(eline)

self.setMarginWidth(1, "0000")
self.markerAdd(eline, self.MARKER_NUM)
font = self.lexerFont()
font.setItalic(True)
styleAnn = QsciStyle(-1, "Annotation",
QColor(255, 0, 0),
QColor(255, 200, 0),
font,
True)
self.annotate(eline, edescr, styleAnn)
self.setCursorPosition(eline, ecolumn - 1) self.setCursorPosition(eline, ecolumn - 1)
# self.setSelection(eline, ecolumn, eline, self.lineLength(eline)-1)
self.ensureLineVisible(eline) self.ensureLineVisible(eline)
# self.ensureCursorVisible()
return False return False
else:
self.setMarginWidth(1, 0) return True
self.markerDeleteAll()
self.clearAnnotations()
return True


def keyPressEvent(self, e): def keyPressEvent(self, e):
t = e.text() t = e.text()
Expand Down
18 changes: 18 additions & 0 deletions python/gui/auto_generated/codeeditors/qgscodeeditor.sip.in
Expand Up @@ -120,6 +120,24 @@ Returns the monospaced font to use for code editors.
%End %End




void addWarning( int lineNumber, const QString &warning );
%Docstring
Adds a ``warning`` message and indicator to the specified a ``lineNumber``.

.. seealso:: :py:func:`clearWarnings`

.. versionadded:: 3.16
%End

void clearWarnings();
%Docstring
Clears all warning messages from the editor.

.. seealso:: :py:func:`addWarning`

.. versionadded:: 3.16
%End

protected: protected:


bool isFixedPitch( const QFont &font ); bool isFixedPitch( const QFont &font );
Expand Down
34 changes: 34 additions & 0 deletions src/gui/codeeditors/qgscodeeditor.cpp
Expand Up @@ -27,6 +27,7 @@
#include <QFontDatabase> #include <QFontDatabase>
#include <QDebug> #include <QDebug>
#include <QFocusEvent> #include <QFocusEvent>
#include <Qsci/qscistyle.h>


QMap< QgsCodeEditorColorScheme::ColorRole, QString > QgsCodeEditor::sColorRoleToSettingsKey QMap< QgsCodeEditorColorScheme::ColorRole, QString > QgsCodeEditor::sColorRoleToSettingsKey
{ {
Expand Down Expand Up @@ -88,6 +89,13 @@ QgsCodeEditor::QgsCodeEditor( QWidget *parent, const QString &title, bool foldin
SendScintilla( SCI_SETMULTIPASTE, 1 ); SendScintilla( SCI_SETMULTIPASTE, 1 );
SendScintilla( SCI_SETVIRTUALSPACEOPTIONS, SCVS_RECTANGULARSELECTION ); SendScintilla( SCI_SETVIRTUALSPACEOPTIONS, SCVS_RECTANGULARSELECTION );


markerDefine( QgsApplication::getThemePixmap( "console/iconSyntaxErrorConsole.svg" ),
MARKER_NUMBER );
SendScintilla( SCI_SETMARGINTYPEN, 3, SC_MARGIN_SYMBOL );
SendScintilla( SCI_SETMARGINMASKN, 3, 1 << MARKER_NUMBER );
setMarginWidth( 3, 0 );
setAnnotationDisplay( QsciScintilla::AnnotationBoxed );

connect( QgsGui::instance(), &QgsGui::optionsChanged, this, [ = ] connect( QgsGui::instance(), &QgsGui::optionsChanged, this, [ = ]
{ {
setSciWidget(); setSciWidget();
Expand Down Expand Up @@ -443,3 +451,29 @@ void QgsCodeEditor::setCustomAppearance( const QString &scheme, const QMap<QgsCo
setSciWidget(); setSciWidget();
initializeLexer(); initializeLexer();
} }

void QgsCodeEditor::addWarning( const int lineNumber, const QString &warning )
{
setMarginWidth( 3, "000" );
markerAdd( lineNumber, MARKER_NUMBER );
QFont font = lexerFont();
font.setItalic( true );
const QsciStyle styleAnn = QsciStyle( -1, QStringLiteral( "Annotation" ),
lexerColor( QgsCodeEditorColorScheme::ColorRole::Error ),
QColor( 255, 200, 0 ), // TODO - expose as configurable color!
font,
true );
annotate( lineNumber, warning, styleAnn );
mWarningLines.push_back( lineNumber );
}

void QgsCodeEditor::clearWarnings()
{
for ( int line : mWarningLines )
{
markerDelete( line );
clearAnnotations( line );
}
setMarginWidth( 3, 0 );
mWarningLines.clear();
}
20 changes: 20 additions & 0 deletions src/gui/codeeditors/qgscodeeditor.h
Expand Up @@ -135,6 +135,22 @@ class GUI_EXPORT QgsCodeEditor : public QsciScintilla
*/ */
void setCustomAppearance( const QString &scheme = QString(), const QMap< QgsCodeEditorColorScheme::ColorRole, QColor > &customColors = QMap< QgsCodeEditorColorScheme::ColorRole, QColor >(), const QString &fontFamily = QString(), int fontSize = 0 ) SIP_SKIP; void setCustomAppearance( const QString &scheme = QString(), const QMap< QgsCodeEditorColorScheme::ColorRole, QColor > &customColors = QMap< QgsCodeEditorColorScheme::ColorRole, QColor >(), const QString &fontFamily = QString(), int fontSize = 0 ) SIP_SKIP;


/**
* Adds a \a warning message and indicator to the specified a \a lineNumber.
*
* \see clearWarnings()
* \since QGIS 3.16
*/
void addWarning( int lineNumber, const QString &warning );

/**
* Clears all warning messages from the editor.
*
* \see addWarning()
* \since QGIS 3.16
*/
void clearWarnings();

protected: protected:


bool isFixedPitch( const QFont &font ); bool isFixedPitch( const QFont &font );
Expand Down Expand Up @@ -188,7 +204,11 @@ class GUI_EXPORT QgsCodeEditor : public QsciScintilla
QString mFontFamily; QString mFontFamily;
int mFontSize = 0; int mFontSize = 0;


QVector< int > mWarningLines;

static QMap< QgsCodeEditorColorScheme::ColorRole, QString > sColorRoleToSettingsKey; static QMap< QgsCodeEditorColorScheme::ColorRole, QString > sColorRoleToSettingsKey;

static constexpr int MARKER_NUMBER = 6;
}; };


// clazy:excludeall=qstring-allocations // clazy:excludeall=qstring-allocations
Expand Down

0 comments on commit 5c8013d

Please sign in to comment.