Skip to content

Commit

Permalink
tui: open log files in external application
Browse files Browse the repository at this point in the history
* Allow log files to be open in external applications.
* Tui will suspend whilst the external tool is open, and resume once it
  has closed.
* Options implemented are `$EDITOR`, `$GEDITOR`, `$PAGER` and `vim` as a
  backup.
  • Loading branch information
oliver-sanders committed Feb 14, 2025
1 parent f6c3d79 commit 853af33
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 20 deletions.
1 change: 1 addition & 0 deletions changes.d/6611.feat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Tui: Add ability to open log files in external tools. Configure your `$EDITOR`, `$GEDITOR` or `$PAGER` options to configure which tool is used.
87 changes: 86 additions & 1 deletion cylc/flow/tui/overlay.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@
"""

from functools import partial
import os
import re
import sys
from time import sleep

import urwid

Expand Down Expand Up @@ -413,6 +415,8 @@ def log(app, id_=None, list_files=None, get_log=None):
# display the actual log file itself
text_widget = urwid.Text('')

_filename = None

def open_menu(*_args, **_kwargs):
"""Open an overlay for selecting a log file."""
nonlocal app, id_
Expand Down Expand Up @@ -459,7 +463,8 @@ def open_log(*_, filename=None, close=False):
"""

nonlocal host_widget, file_widget, text_widget
nonlocal host_widget, file_widget, text_widget, _filename
_filename = filename
try:
host, path, text = get_log(filename)
except Exception as exc:
Expand All @@ -473,6 +478,67 @@ def open_log(*_, filename=None, close=False):
if close:
app.close_topmost()

def open_in_editor(*_, command):
"""Suspend Tui, open the file in an external utility, then restore Tui.
Args:
command:
The command to run as a list, e.g. 'gvim -f'.
This command must be blocking, the tui session will be
restored when the command exits.
"""
import shlex
from subprocess import Popen
import stat
import tempfile

Check warning on line 494 in cylc/flow/tui/overlay.py

View check run for this annotation

Codecov / codecov/patch

cylc/flow/tui/overlay.py#L491-L494

Added lines #L491 - L494 were not covered by tests

nonlocal _filename

try:
host, path, text = get_log(_filename)
except Exception as exc:
host_widget.set_text(f'Error: {exc}')
file_widget.set_text('')

Check warning on line 502 in cylc/flow/tui/overlay.py

View check run for this annotation

Codecov / codecov/patch

cylc/flow/tui/overlay.py#L498-L502

Added lines #L498 - L502 were not covered by tests
else:
host_widget.set_text(f'Host: {host}')
file_widget.set_text(f'Path: {path}')

Check warning on line 505 in cylc/flow/tui/overlay.py

View check run for this annotation

Codecov / codecov/patch

cylc/flow/tui/overlay.py#L504-L505

Added lines #L504 - L505 were not covered by tests

with tempfile.NamedTemporaryFile('w+') as temp_file:
# write the text into a temp file
temp_file.write(text)
temp_file.seek(0, 0)

Check warning on line 510 in cylc/flow/tui/overlay.py

View check run for this annotation

Codecov / codecov/patch

cylc/flow/tui/overlay.py#L509-L510

Added lines #L509 - L510 were not covered by tests

# make the file readonly to avoid confusion
os.chmod(temp_file.name, stat.S_IRUSR)

Check warning on line 513 in cylc/flow/tui/overlay.py

View check run for this annotation

Codecov / codecov/patch

cylc/flow/tui/overlay.py#L513

Added line #L513 was not covered by tests

# suspend Tui
app.loop.screen.stop()

Check warning on line 516 in cylc/flow/tui/overlay.py

View check run for this annotation

Codecov / codecov/patch

cylc/flow/tui/overlay.py#L516

Added line #L516 was not covered by tests

# open the file using the external tool (must be blocking)
print('Launching external tool, Tui will resume once it exits.')
try:
Popen(

Check warning on line 521 in cylc/flow/tui/overlay.py

View check run for this annotation

Codecov / codecov/patch

cylc/flow/tui/overlay.py#L519-L521

Added lines #L519 - L521 were not covered by tests
[*shlex.split(command), temp_file.name]
).wait() # nosec B603
# (this is running a command the user has configured)
except OSError as exc:

Check warning on line 525 in cylc/flow/tui/overlay.py

View check run for this annotation

Codecov / codecov/patch

cylc/flow/tui/overlay.py#L525

Added line #L525 was not covered by tests
# ensure any critical errors are visible to the user so
# that they have a chance to fix them
_sleep_time = 5
print(

Check warning on line 529 in cylc/flow/tui/overlay.py

View check run for this annotation

Codecov / codecov/patch

cylc/flow/tui/overlay.py#L528-L529

Added lines #L528 - L529 were not covered by tests
(
f'Error running {command} {temp_file.name}'
f'\n{exc}'
f'\nTui will resume in {_sleep_time} seconds'
),
file=sys.stderr
)
sleep(_sleep_time)

Check warning on line 537 in cylc/flow/tui/overlay.py

View check run for this annotation

Codecov / codecov/patch

cylc/flow/tui/overlay.py#L537

Added line #L537 was not covered by tests

# restore Tui
app.loop.screen.start()

Check warning on line 540 in cylc/flow/tui/overlay.py

View check run for this annotation

Codecov / codecov/patch

cylc/flow/tui/overlay.py#L540

Added line #L540 was not covered by tests

# load the default log file
if id_:
# NOTE: the kwargs are not provided in the overlay unit tests
Expand All @@ -489,6 +555,25 @@ def open_log(*_, filename=None, close=False):
'Select File',
on_press=open_menu,
),
urwid.Columns([
('pack', urwid.Text('Open in: ')),
*(
(
'pack',
urwid.Button(
label,
align='left',
on_press=partial(open_in_editor, command=command),
),
)
for label, command in (
('$EDITOR', os.environ.get('EDITOR', 'vim')),
('$GEDITOR', os.environ.get('GEDITOR', 'gvim -f')),
('$PAGER', os.environ.get('PAGER', 'less')),
('vim', 'vim'),
)
),
]),
urwid.Divider(),
text_widget,
]),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5">Error: Somethi</span><span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5">Error </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span>
<span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span>
<span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5">&lt;</span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5">Select File </span><span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5">Something went wrong :( </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5">&gt;</span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span>
<span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span>
<span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5">Open in: </span><span style="color:#000000;background:#e5e5e5">&lt;</span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5">$E</span><span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span>
<span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span>
<span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span>
<span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5">Error: Something went wrong :( </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span>
<span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span>
<span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5">&lt;</span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span><span style="color:#e5e5e5;background:#000000">S</span><span style="color:#000000;background:#e5e5e5">elect File </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5">&gt;</span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span>
<span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span>
<span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5">Open in: </span><span style="color:#000000;background:#e5e5e5">&lt;</span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5">$EDITOR</span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5">&gt;</span><span style="color:#000000;background:#e5e5e5">&lt;</span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5">$GEDITOR</span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5">&gt;</span><span style="color:#000000;background:#e5e5e5">&lt;</span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5">$PAGER</span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5">&gt;</span><span style="color:#000000;background:#e5e5e5">&lt;</span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5">vim</span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5">&gt;</span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span>
<span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span>
<span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span>
<span style="color:#000000;background:#e5e5e5"></span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"> </span><span style="color:#000000;background:#e5e5e5"></span>
Expand Down
Loading

0 comments on commit 853af33

Please sign in to comment.