Skip to content

Commit

Permalink
Port generic portions of reformat code action to base class
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Mar 20, 2023
1 parent 069f1a6 commit 7b61080
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 0 deletions.
25 changes: 25 additions & 0 deletions python/gui/auto_generated/codeeditors/qgscodeeditor.sip.in
Expand Up @@ -128,6 +128,13 @@ Set the widget title
Returns the associated scripting language.

.. versionadded:: 3.30
%End

virtual Qgis::ScriptLanguageCapabilities languageCapabilities() const;
%Docstring
Returns the associated scripting language capabilities.

.. versionadded:: 3.32
%End

static QString languageToString( Qgis::ScriptLanguage language );
Expand Down Expand Up @@ -412,6 +419,15 @@ Clears the entire persistent history of commands run in the editor.
Stores the commands executed in the editor to the persistent history file.

.. versionadded:: 3.30
%End

void reformatCode();
%Docstring
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

signals:
Expand Down Expand Up @@ -501,6 +517,15 @@ This method provides an opportunity for subclasses to add additional non-standar
actions to the context menu.

.. versionadded:: 3.30
%End

virtual QString reformatCodeString( const QString &string, bool &ok /Out/, QString &error /Out/ ) const;
%Docstring
Applies code reformatting to a ``string`` and returns the result.

This is only supported for editors which return the Qgis.ScriptLanguageCapability.Reformat capability from :py:func:`~QgsCodeEditor.languageCapabilities`.

.. versionadded:: 3.32
%End

};
Expand Down
110 changes: 110 additions & 0 deletions src/gui/codeeditors/qgscodeeditor.cpp
Expand Up @@ -21,6 +21,7 @@
#include "qgsgui.h"
#include "qgscodeeditorcolorschemeregistry.h"
#include "qgscodeeditorhistorydialog.h"
#include "qgsstringutils.h"

#include <QLabel>
#include <QWidget>
Expand All @@ -31,6 +32,7 @@
#include <Qsci/qscistyle.h>
#include <QMenu>
#include <QClipboard>
#include <QScrollBar>

QMap< QgsCodeEditorColorScheme::ColorRole, QString > QgsCodeEditor::sColorRoleToSettingsKey
{
Expand Down Expand Up @@ -377,6 +379,11 @@ Qgis::ScriptLanguage QgsCodeEditor::language() const
return Qgis::ScriptLanguage::Unknown;
}

Qgis::ScriptLanguageCapabilities QgsCodeEditor::languageCapabilities() const
{
return Qgis::ScriptLanguageCapabilities();
}

QString QgsCodeEditor::languageToString( Qgis::ScriptLanguage language )
{
switch ( language )
Expand Down Expand Up @@ -542,6 +549,12 @@ void QgsCodeEditor::populateContextMenu( QMenu * )

}

QString QgsCodeEditor::reformatCodeString( const QString &string, bool &ok, QString & ) const
{
ok = false;
return string;
}

void QgsCodeEditor::updatePrompt()
{
if ( mInterpreter )
Expand All @@ -562,6 +575,103 @@ void QgsCodeEditor::setInterpreter( QgsCodeInterpreter *newInterpreter )
updatePrompt();
}

// Find the source substring index that most closely matches the target string
int findMinimalDistanceIndex( const QString &source, const QString &target )
{
const int index = std::min( source.length(), target.length() );

const int d0 = QgsStringUtils::levenshteinDistance( source.left( index ), target );
if ( d0 == 0 )
return index;

int refDistanceMore = d0;
int refIndexMore = index;
if ( index < source.length() - 1 )
{
while ( true )
{
const int newDistance = QgsStringUtils::levenshteinDistance( source.left( refIndexMore + 1 ), target );
if ( newDistance <= refDistanceMore )
{
refDistanceMore = newDistance;
refIndexMore++;
if ( refIndexMore == source.length() - 1 )
break;
}
else
{
break;
}
}
}

int refDistanceLess = d0;
int refIndexLess = index;
if ( index > 0 )
{
while ( true )
{
const int newDistance = QgsStringUtils::levenshteinDistance( source.left( refIndexLess - 1 ), target );
if ( newDistance <= refDistanceLess )
{
refDistanceLess = newDistance;
refIndexLess--;
if ( refIndexLess == 0 )
break;
}
else
{
break;
}
}
}

if ( refDistanceMore < refDistanceLess )
return refIndexMore;
else
return refIndexLess;
}

void QgsCodeEditor::reformatCode()
{
if ( !( languageCapabilities() & Qgis::ScriptLanguageCapability::Reformat ) )
return;

int line = 0;
int index = 0;
getCursorPosition( &line, &index );
const QString textBeforeCursor = text( 0, positionFromLineIndex( line, index ) );

const QString originalText = text();

bool ok = false;
QString error;
const QString newText = reformatCodeString( originalText, ok, error );
if ( !ok )
{
if ( !error.isEmpty() )
{
// TODO raise
}
}

if ( originalText == newText )
return;

// try to preserve the cursor position and scroll position
const int oldScrollValue = verticalScrollBar()->value();
const int linearPosition = findMinimalDistanceIndex( newText, textBeforeCursor );

beginUndoAction();
selectAll();
removeSelectedText();
insert( newText );
lineIndexFromPosition( linearPosition, &line, &index );
setCursorPosition( line, index );
verticalScrollBar()->setValue( oldScrollValue );
endUndoAction();
}

QStringList QgsCodeEditor::history() const
{
return mHistory;
Expand Down
25 changes: 25 additions & 0 deletions src/gui/codeeditors/qgscodeeditor.h
Expand Up @@ -168,6 +168,13 @@ class GUI_EXPORT QgsCodeEditor : public QsciScintilla
*/
virtual Qgis::ScriptLanguage language() const;

/**
* Returns the associated scripting language capabilities.
*
* \since QGIS 3.32
*/
virtual Qgis::ScriptLanguageCapabilities languageCapabilities() const;

/**
* Returns a user-friendly, translated name of the specified script \a language.
*
Expand Down Expand Up @@ -430,6 +437,15 @@ class GUI_EXPORT QgsCodeEditor : public QsciScintilla
*/
bool writeHistoryFile();

/**
* Applies code reformatting to the editor.
*
* This is only supported for editors which return the Qgis::ScriptLanguageCapability::Reformat capability from languageCapabilities().
*
* \since QGIS 3.32
*/
void reformatCode();

signals:

/**
Expand Down Expand Up @@ -514,6 +530,15 @@ class GUI_EXPORT QgsCodeEditor : public QsciScintilla
*/
virtual void populateContextMenu( QMenu *menu );

/**
* Applies code reformatting to a \a string and returns the result.
*
* This is only supported for editors which return the Qgis::ScriptLanguageCapability::Reformat capability from languageCapabilities().
*
* \since QGIS 3.32
*/
virtual QString reformatCodeString( const QString &string, bool &ok SIP_OUT, QString &error SIP_OUT ) const;

private:

void setSciWidget();
Expand Down

0 comments on commit 7b61080

Please sign in to comment.