Skip to content

Commit

Permalink
Move responsibility for opening files in external editor to QgsCodeEd…
Browse files Browse the repository at this point in the history
…itorWidget

This allows the editor to be opened in a proper detached process,
avoiding the editor being closed when QGIS is exited.

Move to a blocklist for terminal text editors instead of the fragile
polling approach (which eg doesn't work if the editor is set to
pycharm)
  • Loading branch information
nyalldawson committed Jun 7, 2024
1 parent 7271220 commit 9559a26
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,14 @@ Sets the widget's associated file ``path``.

.. seealso:: :py:func:`filePath`
%End

bool openInExternalEditor();
%Docstring
Attempts to opens the script from the editor in an external text editor.

This requires that the widget has an associated :py:func:`~QgsCodeEditorWidget.filePath` set.

:return: ``True`` if the file was opened successfully.
%End

signals:
Expand Down
18 changes: 1 addition & 17 deletions python/console/console.py
Original file line number Diff line number Diff line change
Expand Up @@ -588,23 +588,7 @@ def reformatCode(self):

def openScriptFileExtEditor(self):
tabWidget = self.tabEditorWidget.currentWidget()
path = tabWidget.file_path()

editor_command = os.environ.get('EDITOR')
if editor_command:
child = subprocess.Popen([os.environ['EDITOR'], path])
try:
# let's see if the EDITOR drops out immediately....
child.wait(0.01)
rc = child.poll()
if rc:
# editor failed, use backup approach
QDesktopServices.openUrl(QUrl.fromLocalFile(path))
except subprocess.TimeoutExpired:
# looks like EDITOR started up successfully, all is good
pass
else:
QDesktopServices.openUrl(QUrl.fromLocalFile(path))
tabWidget.open_in_external_editor()

def openScriptFile(self):
settings = QgsSettings()
Expand Down
3 changes: 3 additions & 0 deletions python/console/console_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,9 @@ def set_file_path(self, path: str):
def file_path(self) -> Optional[str]:
return self._editor_code_widget.filePath()

def open_in_external_editor(self):
self._editor_code_widget.openInExternalEditor()

def modified(self, modified):
self.tab_widget.tabModified(self, modified)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,14 @@ Sets the widget's associated file ``path``.

.. seealso:: :py:func:`filePath`
%End

bool openInExternalEditor();
%Docstring
Attempts to opens the script from the editor in an external text editor.

This requires that the widget has an associated :py:func:`~QgsCodeEditorWidget.filePath` set.

:return: ``True`` if the file was opened successfully.
%End

signals:
Expand Down
37 changes: 37 additions & 0 deletions src/gui/codeeditors/qgscodeeditorwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
#include <QCheckBox>
#include <QShortcut>
#include <QGridLayout>
#include <QDesktopServices>
#include <QProcess>
#include <QFileInfo>
#include <QDir>

QgsCodeEditorWidget::QgsCodeEditorWidget(
QgsCodeEditor *editor,
Expand Down Expand Up @@ -346,6 +350,39 @@ void QgsCodeEditorWidget::setFilePath( const QString &path )
emit filePathChanged( mFilePath );
}

bool QgsCodeEditorWidget::openInExternalEditor()
{
if ( mFilePath.isEmpty() )
return false;

const QDir dir = QFileInfo( mFilePath ).dir();

bool useFallback = true;

const QString editorCommand = qgetenv( "EDITOR" );
if ( !editorCommand.isEmpty() )
{
const QFileInfo fi( editorCommand );
if ( fi.exists( ) )
{
const QString command = fi.fileName();
const bool isTerminalEditor = command.compare( QLatin1String( "nano" ), Qt::CaseInsensitive ) == 0
|| command.contains( QLatin1String( "vim" ), Qt::CaseInsensitive );

if ( !isTerminalEditor && QProcess::startDetached( editorCommand, {mFilePath}, dir.absolutePath() ) )
{
useFallback = false;
}
}
}

if ( useFallback )
{
QDesktopServices::openUrl( QUrl::fromLocalFile( mFilePath ) );
}
return true;
}

bool QgsCodeEditorWidget::findNext()
{
return findText( true, false );
Expand Down
9 changes: 9 additions & 0 deletions src/gui/codeeditors/qgscodeeditorwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,15 @@ class GUI_EXPORT QgsCodeEditorWidget : public QgsPanelWidget
*/
void setFilePath( const QString &path );

/**
* Attempts to opens the script from the editor in an external text editor.
*
* This requires that the widget has an associated filePath() set.
*
* \returns TRUE if the file was opened successfully.
*/
bool openInExternalEditor();

signals:

/**
Expand Down

0 comments on commit 9559a26

Please sign in to comment.