mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-07 00:15:48 -04:00
Move syntax checking capability to QgsCodeEditorPython
This commit is contained in:
parent
ac5f8da74e
commit
3312bf1ad2
@ -2590,7 +2590,8 @@ Qgis.ScriptLanguage.__doc__ = 'Scripting languages.\n\n.. versionadded:: 3.30\n\
|
||||
Qgis.ScriptLanguage.baseClass = Qgis
|
||||
# monkey patching scoped based enum
|
||||
Qgis.ScriptLanguageCapability.Reformat.__doc__ = "Language supports automatic code reformatting"
|
||||
Qgis.ScriptLanguageCapability.__doc__ = 'Script language capabilities.\n\nThe flags reflect the support capabilities of a scripting language.\n\n.. versionadded:: 3.32\n\n' + '* ``Reformat``: ' + Qgis.ScriptLanguageCapability.Reformat.__doc__
|
||||
Qgis.ScriptLanguageCapability.CheckSyntax.__doc__ = "Language supports syntax checking"
|
||||
Qgis.ScriptLanguageCapability.__doc__ = 'Script language capabilities.\n\nThe flags reflect the support capabilities of a scripting language.\n\n.. versionadded:: 3.32\n\n' + '* ``Reformat``: ' + Qgis.ScriptLanguageCapability.Reformat.__doc__ + '\n' + '* ``CheckSyntax``: ' + Qgis.ScriptLanguageCapability.CheckSyntax.__doc__
|
||||
# --
|
||||
Qgis.ScriptLanguageCapability.baseClass = Qgis
|
||||
Qgis.ScriptLanguageCapabilities.baseClass = Qgis
|
||||
|
@ -1592,6 +1592,7 @@ The development version
|
||||
enum class ScriptLanguageCapability
|
||||
{
|
||||
Reformat,
|
||||
CheckSyntax,
|
||||
};
|
||||
|
||||
typedef QFlags<Qgis::ScriptLanguageCapability> ScriptLanguageCapabilities;
|
||||
|
@ -427,6 +427,15 @@ Applies code reformatting to the editor.
|
||||
|
||||
This is only supported for editors which return the Qgis.ScriptLanguageCapability.Reformat capability from :py:func:`~QgsCodeEditor.languageCapabilities`.
|
||||
|
||||
.. versionadded:: 3.32
|
||||
%End
|
||||
|
||||
virtual bool checkSyntax();
|
||||
%Docstring
|
||||
Applies syntax checking to the editor.
|
||||
|
||||
This is only supported for editors which return the Qgis.ScriptLanguageCapability.CheckSyntax capability from :py:func:`~QgsCodeEditor.languageCapabilities`.
|
||||
|
||||
.. versionadded:: 3.32
|
||||
%End
|
||||
|
||||
|
@ -85,6 +85,9 @@ Updates the editor capabilities.
|
||||
.. versionadded:: 3.32
|
||||
%End
|
||||
|
||||
virtual bool checkSyntax();
|
||||
|
||||
|
||||
public slots:
|
||||
|
||||
void searchSelectedTextInPyQGISDocs();
|
||||
|
@ -2735,6 +2735,7 @@ class CORE_EXPORT Qgis
|
||||
enum class ScriptLanguageCapability : int
|
||||
{
|
||||
Reformat = 1 << 0, //!< Language supports automatic code reformatting
|
||||
CheckSyntax = 1 << 1, //!< Language supports syntax checking
|
||||
};
|
||||
Q_ENUM( ScriptLanguageCapability )
|
||||
|
||||
|
@ -224,16 +224,29 @@ void QgsCodeEditor::contextMenuEvent( QContextMenuEvent *event )
|
||||
QMenu *menu = createStandardContextMenu();
|
||||
menu->setAttribute( Qt::WA_DeleteOnClose );
|
||||
|
||||
if ( languageCapabilities() & Qgis::ScriptLanguageCapability::Reformat )
|
||||
if ( ( languageCapabilities() & Qgis::ScriptLanguageCapability::Reformat ) ||
|
||||
( languageCapabilities() & Qgis::ScriptLanguageCapability::CheckSyntax ) )
|
||||
{
|
||||
menu->addSeparator();
|
||||
}
|
||||
|
||||
if ( languageCapabilities() & Qgis::ScriptLanguageCapability::Reformat )
|
||||
{
|
||||
QAction *reformatAction = new QAction( tr( "Reformat Code" ), menu );
|
||||
reformatAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "console/iconFormatCode.svg" ) ) );
|
||||
reformatAction->setEnabled( !isReadOnly() );
|
||||
connect( reformatAction, &QAction::triggered, this, &QgsCodeEditor::reformatCode );
|
||||
menu->addAction( reformatAction );
|
||||
}
|
||||
|
||||
if ( languageCapabilities() & Qgis::ScriptLanguageCapability::Reformat )
|
||||
{
|
||||
QAction *syntaxCheckAction = new QAction( tr( "Check Syntax" ), menu );
|
||||
syntaxCheckAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "console/iconSyntaxErrorConsole.svg" ) ) );
|
||||
connect( syntaxCheckAction, &QAction::triggered, this, &QgsCodeEditor::checkSyntax );
|
||||
menu->addAction( syntaxCheckAction );
|
||||
}
|
||||
|
||||
populateContextMenu( menu );
|
||||
|
||||
menu->exec( mapToGlobal( event->pos() ) );
|
||||
@ -709,6 +722,11 @@ void QgsCodeEditor::reformatCode()
|
||||
endUndoAction();
|
||||
}
|
||||
|
||||
bool QgsCodeEditor::checkSyntax()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
QStringList QgsCodeEditor::history() const
|
||||
{
|
||||
return mHistory;
|
||||
|
@ -446,6 +446,15 @@ class GUI_EXPORT QgsCodeEditor : public QsciScintilla
|
||||
*/
|
||||
void reformatCode();
|
||||
|
||||
/**
|
||||
* Applies syntax checking to the editor.
|
||||
*
|
||||
* This is only supported for editors which return the Qgis::ScriptLanguageCapability::CheckSyntax capability from languageCapabilities().
|
||||
*
|
||||
* \since QGIS 3.32
|
||||
*/
|
||||
virtual bool checkSyntax();
|
||||
|
||||
signals:
|
||||
|
||||
/**
|
||||
|
@ -374,13 +374,13 @@ QString QgsCodeEditorPython::reformatCodeString( const QString &string )
|
||||
if ( settings.value( "pythonConsole/sortImports", true ).toBool() )
|
||||
{
|
||||
const QString defineSortImports = QStringLiteral(
|
||||
"def __qgis_sort_imports(str):\n"
|
||||
"def __qgis_sort_imports(script):\n"
|
||||
" try:\n"
|
||||
" import isort\n"
|
||||
" except ImportError:\n"
|
||||
" return '_ImportError'\n"
|
||||
" options={'line_length': %1, 'profile': '%2', 'known_first_party': ['qgis', 'console', 'processing', 'plugins']}\n"
|
||||
" return isort.code(str, **options)\n" )
|
||||
" return isort.code(script, **options)\n" )
|
||||
.arg( maxLineLength )
|
||||
.arg( formatter == QLatin1String( "black" ) ? QStringLiteral( "black" ) : QString() );
|
||||
|
||||
@ -415,13 +415,13 @@ QString QgsCodeEditorPython::reformatCodeString( const QString &string )
|
||||
const int level = settings.value( QStringLiteral( "pythonConsole/autopep8Level" ), 1 ).toInt();
|
||||
|
||||
const QString defineReformat = QStringLiteral(
|
||||
"def __qgis_reformat(str):\n"
|
||||
"def __qgis_reformat(script):\n"
|
||||
" try:\n"
|
||||
" import autopep8\n"
|
||||
" except ImportError:\n"
|
||||
" return '_ImportError'\n"
|
||||
" options={'aggressive': %1, 'max_line_length': %2}\n"
|
||||
" return autopep8.fix_code(str, options=options)\n" )
|
||||
" return autopep8.fix_code(script, options=options)\n" )
|
||||
.arg( level )
|
||||
.arg( maxLineLength );
|
||||
|
||||
@ -455,13 +455,13 @@ QString QgsCodeEditorPython::reformatCodeString( const QString &string )
|
||||
const bool normalize = settings.value( QStringLiteral( "pythonConsole/blackNormalizeQuotes" ), true ).toBool();
|
||||
|
||||
const QString defineReformat = QStringLiteral(
|
||||
"def __qgis_reformat(str):\n"
|
||||
"def __qgis_reformat(script):\n"
|
||||
" try:\n"
|
||||
" import black\n"
|
||||
" except ImportError:\n"
|
||||
" return '_ImportError'\n"
|
||||
" options={'string_normalization': %1, 'line_length': %2}\n"
|
||||
" return black.format_str(str, mode=black.Mode(**options))\n" )
|
||||
" return black.format_str(script, mode=black.Mode(**options))\n" )
|
||||
.arg( QgsProcessingUtils::variantToPythonLiteral( normalize ) )
|
||||
.arg( maxLineLength );
|
||||
|
||||
@ -621,12 +621,72 @@ void QgsCodeEditorPython::updateCapabilities()
|
||||
if ( !QgsPythonRunner::isValid() )
|
||||
return;
|
||||
|
||||
mCapabilities |= Qgis::ScriptLanguageCapability::CheckSyntax;
|
||||
|
||||
// we could potentially check for autopep8/black import here and reflect the capabilty accordingly.
|
||||
// (current approach is to to always indicate this capability and raise a user-friendly warning
|
||||
// when attempting to reformat if the libraries can't be imported)
|
||||
mCapabilities |= Qgis::ScriptLanguageCapability::Reformat;
|
||||
}
|
||||
|
||||
bool QgsCodeEditorPython::checkSyntax()
|
||||
{
|
||||
clearWarnings();
|
||||
|
||||
if ( !QgsPythonRunner::isValid() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const QString originalText = text();
|
||||
|
||||
const QString defineCheckSyntax = QStringLiteral(
|
||||
"def __check_syntax(script):\n"
|
||||
" try:\n"
|
||||
" compile(script.encode('utf-8'), '', 'exec')\n"
|
||||
" except SyntaxError as detail:\n"
|
||||
" eline = detail.lineno or 1\n"
|
||||
" eline -= 1\n"
|
||||
" ecolumn = detail.offset or 1\n"
|
||||
" edescr = detail.msg\n"
|
||||
" return '!!!!'.join([str(eline), str(ecolumn), edescr])\n"
|
||||
" return ''" );
|
||||
|
||||
if ( !QgsPythonRunner::run( defineCheckSyntax ) )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "Error running script: %1" ).arg( defineCheckSyntax ) );
|
||||
return true;
|
||||
}
|
||||
|
||||
const QString script = QStringLiteral( "__check_syntax(%1)" ).arg( QgsProcessingUtils::stringToPythonLiteral( originalText ) );
|
||||
QString result;
|
||||
if ( QgsPythonRunner::eval( script, result ) )
|
||||
{
|
||||
if ( result.size() == 0 )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
const QStringList parts = result.split( QStringLiteral( "!!!!" ) );
|
||||
if ( parts.size() == 3 )
|
||||
{
|
||||
const int line = parts.at( 0 ).toInt();
|
||||
const int column = parts.at( 1 ).toInt();
|
||||
addWarning( line, parts.at( 2 ) );
|
||||
setCursorPosition( line, column - 1 );
|
||||
ensureLineVisible( line );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "Error running script: %1" ).arg( script ) );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void QgsCodeEditorPython::searchSelectedTextInPyQGISDocs()
|
||||
{
|
||||
if ( !hasSelectedText() )
|
||||
|
@ -104,6 +104,8 @@ class GUI_EXPORT QgsCodeEditorPython : public QgsCodeEditor
|
||||
*/
|
||||
void updateCapabilities();
|
||||
|
||||
bool checkSyntax() override;
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user