command_line: allow external editor for writing
This commit is contained in:
parent
7b9a314481
commit
535ab0aa16
|
@ -4,7 +4,6 @@ import curses
|
||||||
import curses.ascii
|
import curses.ascii
|
||||||
import curses.textpad
|
import curses.textpad
|
||||||
import os
|
import os
|
||||||
import subprocess
|
|
||||||
import tempfile
|
import tempfile
|
||||||
from math import inf
|
from math import inf
|
||||||
|
|
||||||
|
@ -13,6 +12,7 @@ from bebop.bookmarks import (
|
||||||
)
|
)
|
||||||
from bebop.colors import ColorPair, init_colors
|
from bebop.colors import ColorPair, init_colors
|
||||||
from bebop.command_line import CommandLine
|
from bebop.command_line import CommandLine
|
||||||
|
from bebop.external import open_external_program
|
||||||
from bebop.history import History
|
from bebop.history import History
|
||||||
from bebop.links import Links
|
from bebop.links import Links
|
||||||
from bebop.mouse import ButtonState
|
from bebop.mouse import ButtonState
|
||||||
|
@ -428,15 +428,6 @@ class Browser:
|
||||||
save_bookmark(self.current_url, title)
|
save_bookmark(self.current_url, title)
|
||||||
self.reset_status()
|
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):
|
def edit_page(self):
|
||||||
"""Open a text editor to edit the page source.
|
"""Open a text editor to edit the page source.
|
||||||
|
|
||||||
|
@ -463,6 +454,7 @@ class Browser:
|
||||||
delete_source_after = True
|
delete_source_after = True
|
||||||
|
|
||||||
command.append(source_filename)
|
command.append(source_filename)
|
||||||
self.open_external_program(command)
|
open_external_program(command)
|
||||||
if delete_source_after:
|
if delete_source_after:
|
||||||
os.unlink(source_filename)
|
os.unlink(source_filename)
|
||||||
|
self.refresh_windows()
|
||||||
|
|
|
@ -3,12 +3,21 @@
|
||||||
import curses
|
import curses
|
||||||
import curses.ascii
|
import curses.ascii
|
||||||
import curses.textpad
|
import curses.textpad
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
from bebop.external import open_external_program
|
||||||
from bebop.links import Links
|
from bebop.links import Links
|
||||||
|
|
||||||
|
|
||||||
class CommandLine:
|
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):
|
def __init__(self, window):
|
||||||
self.window = window
|
self.window = window
|
||||||
|
@ -78,6 +87,9 @@ class CommandLine:
|
||||||
ch = self.window.getch()
|
ch = self.window.getch()
|
||||||
if ch == -1:
|
if ch == -1:
|
||||||
raise EscapeCommandInterrupt()
|
raise EscapeCommandInterrupt()
|
||||||
|
else: # ALT keybinds.
|
||||||
|
if ch == ord("e"):
|
||||||
|
self.open_editor(self.gather())
|
||||||
self.window.nodelay(False)
|
self.window.nodelay(False)
|
||||||
return ch
|
return ch
|
||||||
|
|
||||||
|
@ -151,6 +163,27 @@ class CommandLine:
|
||||||
# Everything else could be a control character and should be processed.
|
# Everything else could be a control character and should be processed.
|
||||||
return ch
|
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):
|
class EscapeCommandInterrupt(Exception):
|
||||||
"""Signal that ESC has been pressed during command line."""
|
"""Signal that ESC has been pressed during command line."""
|
||||||
|
|
17
bebop/external.py
Normal file
17
bebop/external.py
Normal 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()
|
Reference in a new issue