Bundle editor functions

This commit is contained in:
Florian Bruhin 2014-04-30 11:27:59 +02:00
parent 903d1876af
commit 545e63aa0e
2 changed files with 101 additions and 50 deletions

View File

@ -32,6 +32,7 @@ import qutebrowser.utils.message as message
import qutebrowser.commands.utils as cmdutils import qutebrowser.commands.utils as cmdutils
import qutebrowser.utils.webelem as webelem import qutebrowser.utils.webelem as webelem
import qutebrowser.config.config as config import qutebrowser.config.config as config
from qutebrowser.utils.misc import ExternalEditor
class CurCommandDispatcher(QObject): class CurCommandDispatcher(QObject):
@ -348,63 +349,19 @@ class CurCommandDispatcher(QObject):
if elem.isNull(): if elem.isNull():
message.error("No editable element focused!") message.error("No editable element focused!")
return return
oshandle, filename = mkstemp(text=True)
text = elem.evaluateJavaScript('this.value') text = elem.evaluateJavaScript('this.value')
if text: editor = ExternalEditor()
with open(filename, 'w') as f: editor.editing_finished.connect(self.on_editing_finished)
f.write(text) from qutebrowser.utils.debug import trace_lines; trace_lines(True)
proc = QProcess(self) editor.edit(text)
proc.finished.connect(partial(self.on_editor_closed, elem, oshandle,
filename))
proc.error.connect(partial(self.on_editor_error, oshandle, filename))
editor = config.get('general', 'editor')
executable = editor[0]
args = [arg.replace('{}', filename) for arg in editor[1:]]
logging.debug("Calling \"{}\" with args {}".format(executable, args))
proc.start(executable, args)
def _on_editor_cleanup(self, oshandle, filename): def on_editing_finished(self, text):
os.close(oshandle)
try:
os.remove(filename)
except PermissionError:
message.error("Failed to delete tempfile...")
def on_editor_closed(self, elem, oshandle, filename, exitcode,
exitstatus):
"""Write the editor text into the form field and clean up tempfile. """Write the editor text into the form field and clean up tempfile.
Callback for QProcess when the editor was closed. Callback for QProcess when the editor was closed.
""" """
logging.debug("Editor closed")
if exitcode != 0:
message.error("Editor did quit abnormally (status {})!".format(
exitcode))
return
if exitstatus != QProcess.NormalExit:
# No error here, since we already handle this in on_editor_error
return
if elem.isNull(): if elem.isNull():
message.error("Element vanished while editing!") message.error("Element vanished while editing!")
return return
with open(filename, 'r') as f: text = webelem.javascript_escape(text)
text = ''.join(f.readlines())
text = webelem.javascript_escape(text)
logging.debug("Read back: {}".format(text))
elem.evaluateJavaScript("this.value='{}'".format(text)) elem.evaluateJavaScript("this.value='{}'".format(text))
self._on_editor_cleanup(oshandle, filename)
def on_editor_error(self, oshandle, filename, error):
"""Display an error message and clean up when editor crashed."""
messages = {
QProcess.FailedToStart: "The process failed to start.",
QProcess.Crashed: "The process crashed.",
QProcess.Timedout: "The last waitFor...() function timed out.",
QProcess.WriteError: ("An error occurred when attempting to write "
"to the process."),
QProcess.ReadError: ("An error occurred when attempting to read "
"from the process."),
QProcess.UnknownError: "An unknown error occurred.",
}
message.error("Error while calling editor: {}".format(messages[error]))
self._on_editor_cleanup(oshandle, filename)

View File

@ -17,10 +17,17 @@
"""Other utilities which don't fit anywhere else.""" """Other utilities which don't fit anywhere else."""
import os
import logging
from functools import reduce from functools import reduce
from pkg_resources import resource_string from pkg_resources import resource_string
from tempfile import mkstemp
from PyQt5.QtCore import pyqtSignal, QProcess, QObject
import qutebrowser import qutebrowser
import qutebrowser.config.config as config
import qutebrowser.utils.message as message
def read_file(filename): def read_file(filename):
@ -46,3 +53,90 @@ def dotted_getattr(obj, path):
The object at path. The object at path.
""" """
return reduce(getattr, path.split('.'), obj) return reduce(getattr, path.split('.'), obj)
class ExternalEditor(QObject):
"""Class to simplify editing a text in an external editor."""
editing_finished = pyqtSignal(str)
def __init__(self, parent=None):
super().__init__(parent)
self.text = None
self.oshandle = None
self.filename = None
self.proc = None
def _cleanup(self):
os.close(self.oshandle)
try:
os.remove(self.filename)
except PermissionError:
message.error("Failed to delete tempfile...")
self.text = None
self.oshandle = None
self.filename = None
self.proc = None
def on_proc_closed(self, exitcode, exitstatus):
"""Write the editor text into the form field and clean up tempfile.
Callback for QProcess when the editor was closed.
Emit:
editing_finished: If process exited normally.
"""
logging.debug("Editor closed")
if exitcode != 0:
message.error("Editor did quit abnormally (status {})!".format(
exitcode))
return
if exitstatus != QProcess.NormalExit:
# No error here, since we already handle this in on_editor_error
return
with open(self.filename, 'r') as f:
text = ''.join(f.readlines())
logging.debug("Read back: {}".format(text))
self._cleanup()
self.editing_finished.emit(text)
def on_proc_error(self, error):
"""Display an error message and clean up when editor crashed."""
messages = {
QProcess.FailedToStart: "The process failed to start.",
QProcess.Crashed: "The process crashed.",
QProcess.Timedout: "The last waitFor...() function timed out.",
QProcess.WriteError: ("An error occurred when attempting to write "
"to the process."),
QProcess.ReadError: ("An error occurred when attempting to read "
"from the process."),
QProcess.UnknownError: "An unknown error occurred.",
}
message.error("Error while calling editor: {}".format(messages[error]))
self._cleanup()
def edit(self, text):
"""Edit a given text.
Args:
text: The initial text to edit.
Emit:
editing_finished with the new text if editing finshed successfully.
"""
if self.text is not None:
raise ValueError("Already editing a file!")
self.text = text
self.oshandle, self.filename = mkstemp(text=True)
if not text:
with open(self.filename, 'w') as f:
f.write(text)
self.proc = QProcess(self)
self.proc.finished.connect(self.on_proc_closed)
self.proc.error.connect(self.on_proc_error)
editor = config.get('general', 'editor')
executable = editor[0]
args = [arg.replace('{}', self.filename) for arg in editor[1:]]
logging.debug("Calling \"{}\" with args {}".format(executable, args))
self.proc.start(executable, args)