command_line: allow external editor for writing

This commit is contained in:
dece 2021-04-17 21:54:11 +02:00
parent 7b9a314481
commit 535ab0aa16
3 changed files with 54 additions and 12 deletions

View file

@ -4,7 +4,6 @@ import curses
import curses.ascii
import curses.textpad
import os
import subprocess
import tempfile
from math import inf
@ -13,6 +12,7 @@ from bebop.bookmarks import (
)
from bebop.colors import ColorPair, init_colors
from bebop.command_line import CommandLine
from bebop.external import open_external_program
from bebop.history import History
from bebop.links import Links
from bebop.mouse import ButtonState
@ -428,15 +428,6 @@ class Browser:
save_bookmark(self.current_url, title)
self.reset_status()
def open_external_program(self, command):
"""Pauses the curses modes to open an external program."""
curses.nocbreak()
curses.echo()
subprocess.run(command)
curses.noecho()
curses.cbreak()
self.refresh_windows()
def edit_page(self):
"""Open a text editor to edit the page source.
@ -463,6 +454,7 @@ class Browser:
delete_source_after = True
command.append(source_filename)
self.open_external_program(command)
open_external_program(command)
if delete_source_after:
os.unlink(source_filename)
self.refresh_windows()

View file

@ -3,12 +3,21 @@
import curses
import curses.ascii
import curses.textpad
import os
import tempfile
from bebop.external import open_external_program
from bebop.links import Links
class CommandLine:
"""Basic and flaky command-line à la Vim, using curses module's Textbox."""
"""Basic and flaky command-line à la Vim, using curses module's Textbox.
I don't understand how to get proper pad-like behaviour, e.g. to scroll past
the window's right border when writing more content than the width allows.
Therefore I just added the M-e keybind to call an external editor and use
its content as result.
"""
def __init__(self, window):
self.window = window
@ -78,6 +87,9 @@ class CommandLine:
ch = self.window.getch()
if ch == -1:
raise EscapeCommandInterrupt()
else: # ALT keybinds.
if ch == ord("e"):
self.open_editor(self.gather())
self.window.nodelay(False)
return ch
@ -151,6 +163,27 @@ class CommandLine:
# Everything else could be a control character and should be processed.
return ch
def open_editor(self, existing_content=None):
"""Open an external editor and raise termination interrupt."""
try:
with tempfile.NamedTemporaryFile("w+t", delete=False) as temp_file:
if existing_content:
temp_file.write(existing_content)
temp_filepath = temp_file.name
except OSError:
return
command = ["vi", temp_filepath]
open_external_program(command)
try:
with open(temp_filepath, "rt") as temp_file:
content = temp_file.read()
os.unlink(temp_filepath)
except OSError:
return
raise TerminateCommandInterrupt(content)
class EscapeCommandInterrupt(Exception):
"""Signal that ESC has been pressed during command line."""

17
bebop/external.py Normal file
View file

@ -0,0 +1,17 @@
"""Call external commands."""
import curses
import subprocess
def open_external_program(command):
"""Call command as a subprocess, suspending curses rendering.
The caller has to refresh whatever windows it manages after calling this
method or garbage may be left on the screen.
"""
curses.nocbreak()
curses.echo()
subprocess.run(command)
curses.noecho()
curses.cbreak()