mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 18:54:09 -04:00
Remove obsolete/unused code
This commit is contained in:
parent
2470ee0ff2
commit
226a920b6b
@ -53,8 +53,6 @@ Everything after the -- is passed to the script.
|
|||||||
parser.add_option('--reinitialize-db', default=None,
|
parser.add_option('--reinitialize-db', default=None,
|
||||||
help=_('Re-initialize the sqlite calibre database at the '
|
help=_('Re-initialize the sqlite calibre database at the '
|
||||||
'specified path. Useful to recover from db corruption.'))
|
'specified path. Useful to recover from db corruption.'))
|
||||||
parser.add_option('-p', '--py-console', help=_('Run python console'),
|
|
||||||
default=False, action='store_true')
|
|
||||||
parser.add_option('-m', '--inspect-mobi', action='store_true',
|
parser.add_option('-m', '--inspect-mobi', action='store_true',
|
||||||
default=False,
|
default=False,
|
||||||
help=_('Inspect the MOBI file(s) at the specified path(s)'))
|
help=_('Inspect the MOBI file(s) at the specified path(s)'))
|
||||||
@ -230,9 +228,6 @@ def main(args=sys.argv):
|
|||||||
elif opts.viewer:
|
elif opts.viewer:
|
||||||
from calibre.gui_launch import ebook_viewer
|
from calibre.gui_launch import ebook_viewer
|
||||||
ebook_viewer(['ebook-viewer', '--debug-javascript'] + args[1:])
|
ebook_viewer(['ebook-viewer', '--debug-javascript'] + args[1:])
|
||||||
elif opts.py_console:
|
|
||||||
from calibre.utils.pyconsole.main import main
|
|
||||||
main()
|
|
||||||
elif opts.command:
|
elif opts.command:
|
||||||
sys.argv = args
|
sys.argv = args
|
||||||
exec(opts.command)
|
exec(opts.command)
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
#!/usr/bin/env python2
|
|
||||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
|
||||||
__docformat__ = 'restructuredtext en'
|
|
||||||
|
|
||||||
import sys, os
|
|
||||||
|
|
||||||
from calibre import prints as prints_, preferred_encoding, isbytestring
|
|
||||||
from calibre.utils.config import Config, ConfigProxy, JSONConfig
|
|
||||||
from calibre.utils.ipc.launch import Worker
|
|
||||||
from calibre.constants import __appname__, __version__, iswindows
|
|
||||||
from calibre.gui2 import error_dialog
|
|
||||||
|
|
||||||
# Time to wait for communication to/from the interpreter process
|
|
||||||
POLL_TIMEOUT = 0.01 # seconds
|
|
||||||
|
|
||||||
preferred_encoding, isbytestring, __appname__, __version__, error_dialog, \
|
|
||||||
iswindows
|
|
||||||
|
|
||||||
def console_config():
|
|
||||||
desc='Settings to control the calibre console'
|
|
||||||
c = Config('console', desc)
|
|
||||||
|
|
||||||
c.add_opt('theme', default='native', help='The color theme')
|
|
||||||
c.add_opt('scrollback', default=10000,
|
|
||||||
help='Max number of lines to keep in the scrollback buffer')
|
|
||||||
|
|
||||||
return c
|
|
||||||
|
|
||||||
prefs = ConfigProxy(console_config())
|
|
||||||
dynamic = JSONConfig('console')
|
|
||||||
|
|
||||||
def prints(*args, **kwargs):
|
|
||||||
kwargs['file'] = sys.__stdout__
|
|
||||||
prints_(*args, **kwargs)
|
|
||||||
|
|
||||||
class Process(Worker):
|
|
||||||
|
|
||||||
@property
|
|
||||||
def env(self):
|
|
||||||
env = dict(os.environ)
|
|
||||||
env.update(self._env)
|
|
||||||
return env
|
|
||||||
|
|
||||||
|
|
@ -1,521 +0,0 @@
|
|||||||
#!/usr/bin/env python2
|
|
||||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
|
||||||
__docformat__ = 'restructuredtext en'
|
|
||||||
|
|
||||||
import sys, textwrap, traceback, StringIO
|
|
||||||
from functools import partial
|
|
||||||
from codeop import CommandCompiler
|
|
||||||
|
|
||||||
from PyQt5.Qt import QTextEdit, Qt, QTextFrameFormat, pyqtSignal, \
|
|
||||||
QApplication, QColor, QPalette, QMenu, QActionGroup, QTimer
|
|
||||||
|
|
||||||
from pygments.lexers import PythonLexer, PythonTracebackLexer
|
|
||||||
from pygments.styles import get_all_styles
|
|
||||||
|
|
||||||
from calibre.utils.pyconsole.formatter import Formatter
|
|
||||||
from calibre.utils.pyconsole.controller import Controller
|
|
||||||
from calibre.utils.pyconsole.history import History
|
|
||||||
from calibre.utils.pyconsole import prints, prefs, __appname__, \
|
|
||||||
__version__, error_dialog, dynamic
|
|
||||||
|
|
||||||
class EditBlock(object): # {{{
|
|
||||||
|
|
||||||
def __init__(self, cursor):
|
|
||||||
self.cursor = cursor
|
|
||||||
|
|
||||||
def __enter__(self):
|
|
||||||
self.cursor.beginEditBlock()
|
|
||||||
return self.cursor
|
|
||||||
|
|
||||||
def __exit__(self, *args):
|
|
||||||
self.cursor.endEditBlock()
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
class Prepender(object): # {{{
|
|
||||||
'Helper class to insert output before the current prompt'
|
|
||||||
def __init__(self, console):
|
|
||||||
self.console = console
|
|
||||||
|
|
||||||
def __enter__(self):
|
|
||||||
c = self.console
|
|
||||||
self.opos = c.cursor_pos
|
|
||||||
cur = c.prompt_frame.firstCursorPosition()
|
|
||||||
cur.movePosition(cur.PreviousCharacter)
|
|
||||||
c.setTextCursor(cur)
|
|
||||||
|
|
||||||
def __exit__(self, *args):
|
|
||||||
self.console.cursor_pos = self.opos
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
class ThemeMenu(QMenu): # {{{
|
|
||||||
|
|
||||||
def __init__(self, parent):
|
|
||||||
QMenu.__init__(self, _('Choose theme (needs restart)'))
|
|
||||||
parent.addMenu(self)
|
|
||||||
self.group = QActionGroup(self)
|
|
||||||
current = prefs['theme']
|
|
||||||
alls = list(sorted(get_all_styles()))
|
|
||||||
if current not in alls:
|
|
||||||
current = prefs['theme'] = 'default'
|
|
||||||
self.actions = []
|
|
||||||
for style in alls:
|
|
||||||
ac = self.group.addAction(style)
|
|
||||||
ac.setCheckable(True)
|
|
||||||
if current == style:
|
|
||||||
ac.setChecked(True)
|
|
||||||
self.actions.append(ac)
|
|
||||||
ac.triggered.connect(partial(self.set_theme, style))
|
|
||||||
self.addAction(ac)
|
|
||||||
|
|
||||||
def set_theme(self, style, *args):
|
|
||||||
prefs['theme'] = style
|
|
||||||
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
|
|
||||||
class Console(QTextEdit):
|
|
||||||
|
|
||||||
running = pyqtSignal()
|
|
||||||
running_done = pyqtSignal()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def doc(self):
|
|
||||||
return self.document()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def cursor(self):
|
|
||||||
return self.textCursor()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def root_frame(self):
|
|
||||||
return self.doc.rootFrame()
|
|
||||||
|
|
||||||
def unhandled_exception(self, type, value, tb):
|
|
||||||
if type == KeyboardInterrupt:
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
sio = StringIO.StringIO()
|
|
||||||
traceback.print_exception(type, value, tb, file=sio)
|
|
||||||
fe = sio.getvalue()
|
|
||||||
prints(fe)
|
|
||||||
try:
|
|
||||||
val = unicode(value)
|
|
||||||
except:
|
|
||||||
val = repr(value)
|
|
||||||
msg = '<b>%s</b>:'%type.__name__ + val
|
|
||||||
error_dialog(self, _('ERROR: Unhandled exception'), msg,
|
|
||||||
det_msg=fe, show=True)
|
|
||||||
except BaseException:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def __init__(self,
|
|
||||||
prompt='>>> ',
|
|
||||||
continuation='... ',
|
|
||||||
parent=None):
|
|
||||||
QTextEdit.__init__(self, parent)
|
|
||||||
self.shutting_down = False
|
|
||||||
self.compiler = CommandCompiler()
|
|
||||||
self.buf = self.old_buf = []
|
|
||||||
self.history = History([''], dynamic.get('console_history', []))
|
|
||||||
self.prompt_frame = None
|
|
||||||
self.allow_output = False
|
|
||||||
self.prompt_frame_format = QTextFrameFormat()
|
|
||||||
self.prompt_frame_format.setBorder(1)
|
|
||||||
self.prompt_frame_format.setBorderStyle(QTextFrameFormat.BorderStyle_Solid)
|
|
||||||
self.prompt_len = len(prompt)
|
|
||||||
|
|
||||||
self.doc.setMaximumBlockCount(int(prefs['scrollback']))
|
|
||||||
self.lexer = PythonLexer(ensurenl=False)
|
|
||||||
self.tb_lexer = PythonTracebackLexer()
|
|
||||||
|
|
||||||
self.context_menu = cm = QMenu(self) # {{{
|
|
||||||
cm.theme = ThemeMenu(cm)
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
self.formatter = Formatter(prompt, continuation, style=prefs['theme'])
|
|
||||||
p = QPalette()
|
|
||||||
p.setColor(p.Base, QColor(self.formatter.background_color))
|
|
||||||
p.setColor(p.Text, QColor(self.formatter.color))
|
|
||||||
self.setPalette(p)
|
|
||||||
|
|
||||||
self.key_dispatcher = { # {{{
|
|
||||||
Qt.Key_Enter : self.enter_pressed,
|
|
||||||
Qt.Key_Return : self.enter_pressed,
|
|
||||||
Qt.Key_Up : self.up_pressed,
|
|
||||||
Qt.Key_Down : self.down_pressed,
|
|
||||||
Qt.Key_Home : self.home_pressed,
|
|
||||||
Qt.Key_End : self.end_pressed,
|
|
||||||
Qt.Key_Left : self.left_pressed,
|
|
||||||
Qt.Key_Right : self.right_pressed,
|
|
||||||
Qt.Key_Backspace : self.backspace_pressed,
|
|
||||||
Qt.Key_Delete : self.delete_pressed,
|
|
||||||
} # }}}
|
|
||||||
|
|
||||||
motd = textwrap.dedent('''\
|
|
||||||
# Python {0}
|
|
||||||
# {1} {2}
|
|
||||||
'''.format(sys.version.splitlines()[0], __appname__,
|
|
||||||
__version__))
|
|
||||||
|
|
||||||
sys.excepthook = self.unhandled_exception
|
|
||||||
|
|
||||||
self.controllers = []
|
|
||||||
QTimer.singleShot(0, self.launch_controller)
|
|
||||||
|
|
||||||
with EditBlock(self.cursor):
|
|
||||||
self.render_block(motd)
|
|
||||||
|
|
||||||
def shutdown(self):
|
|
||||||
dynamic.set('console_history', self.history.serialize())
|
|
||||||
self.shutting_down = True
|
|
||||||
for c in self.controllers:
|
|
||||||
c.kill()
|
|
||||||
|
|
||||||
def contextMenuEvent(self, event):
|
|
||||||
self.context_menu.popup(event.globalPos())
|
|
||||||
event.accept()
|
|
||||||
|
|
||||||
# Controller management {{{
|
|
||||||
@property
|
|
||||||
def controller(self):
|
|
||||||
return self.controllers[-1]
|
|
||||||
|
|
||||||
def no_controller_error(self):
|
|
||||||
error_dialog(self, _('No interpreter'),
|
|
||||||
_('No active interpreter found. Try restarting the'
|
|
||||||
' console'), show=True)
|
|
||||||
|
|
||||||
def launch_controller(self, *args):
|
|
||||||
c = Controller(self)
|
|
||||||
c.write_output.connect(self.show_output, type=Qt.QueuedConnection)
|
|
||||||
c.show_error.connect(self.show_error, type=Qt.QueuedConnection)
|
|
||||||
c.interpreter_died.connect(self.interpreter_died,
|
|
||||||
type=Qt.QueuedConnection)
|
|
||||||
c.interpreter_done.connect(self.execution_done)
|
|
||||||
self.controllers.append(c)
|
|
||||||
|
|
||||||
def interpreter_died(self, controller, returncode):
|
|
||||||
if not self.shutting_down and controller.current_command is not None:
|
|
||||||
error_dialog(self, _('Interpreter died'),
|
|
||||||
_('Interpreter dies while executing a command. To see '
|
|
||||||
'the command, click Show details'),
|
|
||||||
det_msg=controller.current_command, show=True)
|
|
||||||
|
|
||||||
def execute(self, prompt_lines):
|
|
||||||
c = self.root_frame.lastCursorPosition()
|
|
||||||
self.setTextCursor(c)
|
|
||||||
self.old_prompt_frame = self.prompt_frame
|
|
||||||
self.prompt_frame = None
|
|
||||||
self.old_buf = self.buf
|
|
||||||
self.buf = []
|
|
||||||
self.running.emit()
|
|
||||||
self.controller.runsource('\n'.join(prompt_lines))
|
|
||||||
|
|
||||||
def execution_done(self, controller, ret):
|
|
||||||
if controller is self.controller:
|
|
||||||
self.running_done.emit()
|
|
||||||
if ret: # Incomplete command
|
|
||||||
self.buf = self.old_buf
|
|
||||||
self.prompt_frame = self.old_prompt_frame
|
|
||||||
c = self.prompt_frame.lastCursorPosition()
|
|
||||||
c.insertBlock()
|
|
||||||
self.setTextCursor(c)
|
|
||||||
else: # Command completed
|
|
||||||
try:
|
|
||||||
self.old_prompt_frame.setFrameFormat(QTextFrameFormat())
|
|
||||||
except RuntimeError:
|
|
||||||
# Happens if enough lines of output that the old
|
|
||||||
# frame was deleted
|
|
||||||
pass
|
|
||||||
|
|
||||||
self.render_current_prompt()
|
|
||||||
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
# Prompt management {{{
|
|
||||||
|
|
||||||
@dynamic_property
|
|
||||||
def cursor_pos(self):
|
|
||||||
doc = '''
|
|
||||||
The cursor position in the prompt has the form (row, col).
|
|
||||||
row starts at 0 for the first line
|
|
||||||
col is 0 if the cursor is at the start of the line, 1 if it is after
|
|
||||||
the first character, n if it is after the nth char.
|
|
||||||
'''
|
|
||||||
|
|
||||||
def fget(self):
|
|
||||||
if self.prompt_frame is not None:
|
|
||||||
pos = self.cursor.position()
|
|
||||||
it = self.prompt_frame.begin()
|
|
||||||
lineno = 0
|
|
||||||
while not it.atEnd():
|
|
||||||
bl = it.currentBlock()
|
|
||||||
if bl.contains(pos):
|
|
||||||
return (lineno, pos - bl.position())
|
|
||||||
it += 1
|
|
||||||
lineno += 1
|
|
||||||
return (-1, -1)
|
|
||||||
|
|
||||||
def fset(self, val):
|
|
||||||
row, col = val
|
|
||||||
if self.prompt_frame is not None:
|
|
||||||
it = self.prompt_frame.begin()
|
|
||||||
lineno = 0
|
|
||||||
while not it.atEnd():
|
|
||||||
if lineno == row:
|
|
||||||
c = self.cursor
|
|
||||||
c.setPosition(it.currentBlock().position())
|
|
||||||
c.movePosition(c.NextCharacter, n=col)
|
|
||||||
self.setTextCursor(c)
|
|
||||||
break
|
|
||||||
it += 1
|
|
||||||
lineno += 1
|
|
||||||
|
|
||||||
return property(fget=fget, fset=fset, doc=doc)
|
|
||||||
|
|
||||||
def move_cursor_to_prompt(self):
|
|
||||||
if self.prompt_frame is not None and self.cursor_pos[0] < 0:
|
|
||||||
c = self.prompt_frame.lastCursorPosition()
|
|
||||||
self.setTextCursor(c)
|
|
||||||
|
|
||||||
def prompt(self, strip_prompt_strings=True):
|
|
||||||
if not self.prompt_frame:
|
|
||||||
yield u'' if strip_prompt_strings else self.formatter.prompt
|
|
||||||
else:
|
|
||||||
it = self.prompt_frame.begin()
|
|
||||||
while not it.atEnd():
|
|
||||||
bl = it.currentBlock()
|
|
||||||
t = unicode(bl.text())
|
|
||||||
if strip_prompt_strings:
|
|
||||||
t = t[self.prompt_len:]
|
|
||||||
yield t
|
|
||||||
it += 1
|
|
||||||
|
|
||||||
def set_prompt(self, lines):
|
|
||||||
self.render_current_prompt(lines)
|
|
||||||
|
|
||||||
def clear_current_prompt(self):
|
|
||||||
if self.prompt_frame is None:
|
|
||||||
c = self.root_frame.lastCursorPosition()
|
|
||||||
self.prompt_frame = c.insertFrame(self.prompt_frame_format)
|
|
||||||
self.setTextCursor(c)
|
|
||||||
else:
|
|
||||||
c = self.prompt_frame.firstCursorPosition()
|
|
||||||
self.setTextCursor(c)
|
|
||||||
c.setPosition(self.prompt_frame.lastPosition(), c.KeepAnchor)
|
|
||||||
c.removeSelectedText()
|
|
||||||
c.setPosition(self.prompt_frame.firstPosition())
|
|
||||||
|
|
||||||
def render_current_prompt(self, lines=None, restore_cursor=False):
|
|
||||||
row, col = self.cursor_pos
|
|
||||||
cp = list(self.prompt()) if lines is None else lines
|
|
||||||
self.clear_current_prompt()
|
|
||||||
|
|
||||||
for i, line in enumerate(cp):
|
|
||||||
start = i == 0
|
|
||||||
end = i == len(cp) - 1
|
|
||||||
self.formatter.render_prompt(not start, self.cursor)
|
|
||||||
self.formatter.render(self.lexer.get_tokens(line), self.cursor)
|
|
||||||
if not end:
|
|
||||||
self.cursor.insertBlock()
|
|
||||||
|
|
||||||
if row > -1 and restore_cursor:
|
|
||||||
self.cursor_pos = (row, col)
|
|
||||||
|
|
||||||
self.ensureCursorVisible()
|
|
||||||
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
# Non-prompt Rendering {{{
|
|
||||||
|
|
||||||
def render_block(self, text, restore_prompt=True):
|
|
||||||
self.formatter.render(self.lexer.get_tokens(text), self.cursor)
|
|
||||||
self.cursor.insertBlock()
|
|
||||||
self.cursor.movePosition(self.cursor.End)
|
|
||||||
if restore_prompt:
|
|
||||||
self.render_current_prompt()
|
|
||||||
|
|
||||||
def show_error(self, is_syntax_err, tb, controller=None):
|
|
||||||
if self.prompt_frame is not None:
|
|
||||||
# At a prompt, so redirect output
|
|
||||||
return prints(tb, end='')
|
|
||||||
try:
|
|
||||||
self.buf.append(tb)
|
|
||||||
if is_syntax_err:
|
|
||||||
self.formatter.render_syntax_error(tb, self.cursor)
|
|
||||||
else:
|
|
||||||
self.formatter.render(self.tb_lexer.get_tokens(tb), self.cursor)
|
|
||||||
except:
|
|
||||||
prints(tb, end='')
|
|
||||||
self.ensureCursorVisible()
|
|
||||||
QApplication.processEvents()
|
|
||||||
|
|
||||||
def show_output(self, raw, which='stdout', controller=None):
|
|
||||||
def do_show():
|
|
||||||
try:
|
|
||||||
self.buf.append(raw)
|
|
||||||
self.formatter.render_raw(raw, self.cursor)
|
|
||||||
except:
|
|
||||||
import traceback
|
|
||||||
prints(traceback.format_exc())
|
|
||||||
prints(raw, end='')
|
|
||||||
|
|
||||||
if self.prompt_frame is not None:
|
|
||||||
with Prepender(self):
|
|
||||||
do_show()
|
|
||||||
else:
|
|
||||||
do_show()
|
|
||||||
self.ensureCursorVisible()
|
|
||||||
QApplication.processEvents()
|
|
||||||
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
# Keyboard management {{{
|
|
||||||
|
|
||||||
def keyPressEvent(self, ev):
|
|
||||||
text = unicode(ev.text())
|
|
||||||
key = ev.key()
|
|
||||||
action = self.key_dispatcher.get(key, None)
|
|
||||||
if callable(action):
|
|
||||||
action()
|
|
||||||
elif key in (Qt.Key_Escape,):
|
|
||||||
QTextEdit.keyPressEvent(self, ev)
|
|
||||||
elif text:
|
|
||||||
self.text_typed(text)
|
|
||||||
else:
|
|
||||||
QTextEdit.keyPressEvent(self, ev)
|
|
||||||
|
|
||||||
def left_pressed(self):
|
|
||||||
lineno, pos = self.cursor_pos
|
|
||||||
if lineno < 0:
|
|
||||||
return
|
|
||||||
if pos > self.prompt_len:
|
|
||||||
c = self.cursor
|
|
||||||
c.movePosition(c.PreviousCharacter)
|
|
||||||
self.setTextCursor(c)
|
|
||||||
elif lineno > 0:
|
|
||||||
c = self.cursor
|
|
||||||
c.movePosition(c.Up)
|
|
||||||
c.movePosition(c.EndOfLine)
|
|
||||||
self.setTextCursor(c)
|
|
||||||
self.ensureCursorVisible()
|
|
||||||
|
|
||||||
def up_pressed(self):
|
|
||||||
lineno, pos = self.cursor_pos
|
|
||||||
if lineno < 0:
|
|
||||||
return
|
|
||||||
if lineno == 0:
|
|
||||||
b = self.history.back()
|
|
||||||
if b is not None:
|
|
||||||
self.set_prompt(b)
|
|
||||||
else:
|
|
||||||
c = self.cursor
|
|
||||||
c.movePosition(c.Up)
|
|
||||||
self.setTextCursor(c)
|
|
||||||
self.ensureCursorVisible()
|
|
||||||
|
|
||||||
def backspace_pressed(self):
|
|
||||||
lineno, pos = self.cursor_pos
|
|
||||||
if lineno < 0:
|
|
||||||
return
|
|
||||||
if pos > self.prompt_len:
|
|
||||||
self.cursor.deletePreviousChar()
|
|
||||||
elif lineno > 0:
|
|
||||||
c = self.cursor
|
|
||||||
c.movePosition(c.Up)
|
|
||||||
c.movePosition(c.EndOfLine)
|
|
||||||
self.setTextCursor(c)
|
|
||||||
self.ensureCursorVisible()
|
|
||||||
|
|
||||||
def delete_pressed(self):
|
|
||||||
self.cursor.deleteChar()
|
|
||||||
self.ensureCursorVisible()
|
|
||||||
|
|
||||||
def right_pressed(self):
|
|
||||||
lineno, pos = self.cursor_pos
|
|
||||||
if lineno < 0:
|
|
||||||
return
|
|
||||||
c = self.cursor
|
|
||||||
cp = list(self.prompt(False))
|
|
||||||
if pos < len(cp[lineno]):
|
|
||||||
c.movePosition(c.NextCharacter)
|
|
||||||
elif lineno < len(cp)-1:
|
|
||||||
c.movePosition(c.NextCharacter, n=1+self.prompt_len)
|
|
||||||
self.setTextCursor(c)
|
|
||||||
self.ensureCursorVisible()
|
|
||||||
|
|
||||||
def down_pressed(self):
|
|
||||||
lineno, pos = self.cursor_pos
|
|
||||||
if lineno < 0:
|
|
||||||
return
|
|
||||||
c = self.cursor
|
|
||||||
cp = list(self.prompt(False))
|
|
||||||
if lineno >= len(cp) - 1:
|
|
||||||
b = self.history.forward()
|
|
||||||
if b is not None:
|
|
||||||
self.set_prompt(b)
|
|
||||||
else:
|
|
||||||
c = self.cursor
|
|
||||||
c.movePosition(c.Down)
|
|
||||||
self.setTextCursor(c)
|
|
||||||
self.ensureCursorVisible()
|
|
||||||
|
|
||||||
def home_pressed(self):
|
|
||||||
if self.prompt_frame is not None:
|
|
||||||
mods = QApplication.keyboardModifiers()
|
|
||||||
ctrl = bool(int(mods & Qt.CTRL))
|
|
||||||
if ctrl:
|
|
||||||
self.cursor_pos = (0, self.prompt_len)
|
|
||||||
else:
|
|
||||||
c = self.cursor
|
|
||||||
c.movePosition(c.StartOfLine)
|
|
||||||
c.movePosition(c.NextCharacter, n=self.prompt_len)
|
|
||||||
self.setTextCursor(c)
|
|
||||||
self.ensureCursorVisible()
|
|
||||||
|
|
||||||
def end_pressed(self):
|
|
||||||
if self.prompt_frame is not None:
|
|
||||||
mods = QApplication.keyboardModifiers()
|
|
||||||
ctrl = bool(int(mods & Qt.CTRL))
|
|
||||||
if ctrl:
|
|
||||||
self.cursor_pos = (len(list(self.prompt()))-1, self.prompt_len)
|
|
||||||
c = self.cursor
|
|
||||||
c.movePosition(c.EndOfLine)
|
|
||||||
self.setTextCursor(c)
|
|
||||||
self.ensureCursorVisible()
|
|
||||||
|
|
||||||
def enter_pressed(self):
|
|
||||||
if self.prompt_frame is None:
|
|
||||||
return
|
|
||||||
if not self.controller.is_alive:
|
|
||||||
return self.no_controller_error()
|
|
||||||
cp = list(self.prompt())
|
|
||||||
if cp[0]:
|
|
||||||
try:
|
|
||||||
ret = self.compiler('\n'.join(cp))
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
if ret is None:
|
|
||||||
c = self.prompt_frame.lastCursorPosition()
|
|
||||||
c.insertBlock()
|
|
||||||
self.setTextCursor(c)
|
|
||||||
self.render_current_prompt()
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
self.history.enter(cp)
|
|
||||||
self.execute(cp)
|
|
||||||
|
|
||||||
def text_typed(self, text):
|
|
||||||
if self.prompt_frame is not None:
|
|
||||||
self.move_cursor_to_prompt()
|
|
||||||
self.cursor.insertText(text)
|
|
||||||
self.render_current_prompt(restore_cursor=True)
|
|
||||||
self.history.current = list(self.prompt())
|
|
||||||
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
|
|
@ -1,125 +0,0 @@
|
|||||||
#!/usr/bin/env python2
|
|
||||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
|
||||||
__docformat__ = 'restructuredtext en'
|
|
||||||
|
|
||||||
import os, cPickle, signal, time
|
|
||||||
from Queue import Queue, Empty
|
|
||||||
from multiprocessing.connection import Listener, arbitrary_address
|
|
||||||
from binascii import hexlify
|
|
||||||
|
|
||||||
from PyQt5.Qt import QThread, pyqtSignal
|
|
||||||
|
|
||||||
from calibre.utils.pyconsole import Process, iswindows, POLL_TIMEOUT
|
|
||||||
|
|
||||||
class Controller(QThread):
|
|
||||||
|
|
||||||
# show_error(is_syntax_error, traceback, self)
|
|
||||||
show_error = pyqtSignal(object, object, object)
|
|
||||||
# write_output(unicode_object, stdout or stderr, self)
|
|
||||||
write_output = pyqtSignal(object, object, object)
|
|
||||||
# Indicates interpreter has finished evaluating current command
|
|
||||||
interpreter_done = pyqtSignal(object, object)
|
|
||||||
# interpreter_died(self, returncode or None if no return code available)
|
|
||||||
interpreter_died = pyqtSignal(object, object)
|
|
||||||
|
|
||||||
def __init__(self, parent):
|
|
||||||
QThread.__init__(self, parent)
|
|
||||||
self.keep_going = True
|
|
||||||
self.current_command = None
|
|
||||||
|
|
||||||
self.out_queue = Queue()
|
|
||||||
self.address = arbitrary_address('AF_PIPE' if iswindows else 'AF_UNIX')
|
|
||||||
self.auth_key = os.urandom(32)
|
|
||||||
if iswindows and self.address[1] == ':':
|
|
||||||
self.address = self.address[2:]
|
|
||||||
self.listener = Listener(address=self.address,
|
|
||||||
authkey=self.auth_key, backlog=4)
|
|
||||||
|
|
||||||
self.env = {
|
|
||||||
'CALIBRE_SIMPLE_WORKER':
|
|
||||||
'calibre.utils.pyconsole.interpreter:main',
|
|
||||||
'CALIBRE_WORKER_ADDRESS':
|
|
||||||
hexlify(cPickle.dumps(self.listener.address, -1)),
|
|
||||||
'CALIBRE_WORKER_KEY': hexlify(self.auth_key)
|
|
||||||
}
|
|
||||||
self.process = Process(self.env)
|
|
||||||
self.output_file_buf = self.process(redirect_output=False)
|
|
||||||
self.conn = self.listener.accept()
|
|
||||||
self.start()
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
while self.keep_going and self.is_alive:
|
|
||||||
try:
|
|
||||||
self.communicate()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
pass
|
|
||||||
except EOFError:
|
|
||||||
break
|
|
||||||
self.interpreter_died.emit(self, self.returncode)
|
|
||||||
try:
|
|
||||||
self.listener.close()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def communicate(self):
|
|
||||||
if self.conn.poll(POLL_TIMEOUT):
|
|
||||||
self.dispatch_incoming_message(self.conn.recv())
|
|
||||||
try:
|
|
||||||
obj = self.out_queue.get_nowait()
|
|
||||||
except Empty:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
self.conn.send(obj)
|
|
||||||
except:
|
|
||||||
raise EOFError('controller failed to send')
|
|
||||||
|
|
||||||
def dispatch_incoming_message(self, obj):
|
|
||||||
try:
|
|
||||||
cmd, data = obj
|
|
||||||
except:
|
|
||||||
print 'Controller received invalid message'
|
|
||||||
print repr(obj)
|
|
||||||
return
|
|
||||||
if cmd in ('stdout', 'stderr'):
|
|
||||||
self.write_output.emit(data, cmd, self)
|
|
||||||
elif cmd == 'syntaxerror':
|
|
||||||
self.show_error.emit(True, data, self)
|
|
||||||
elif cmd == 'traceback':
|
|
||||||
self.show_error.emit(False, data, self)
|
|
||||||
elif cmd == 'done':
|
|
||||||
self.current_command = None
|
|
||||||
self.interpreter_done.emit(self, data)
|
|
||||||
|
|
||||||
def runsource(self, cmd):
|
|
||||||
self.current_command = cmd
|
|
||||||
self.out_queue.put(('run', cmd))
|
|
||||||
|
|
||||||
def __nonzero__(self):
|
|
||||||
return self.process.is_alive
|
|
||||||
|
|
||||||
@property
|
|
||||||
def returncode(self):
|
|
||||||
return self.process.returncode
|
|
||||||
|
|
||||||
def interrupt(self):
|
|
||||||
if hasattr(signal, 'SIGINT'):
|
|
||||||
os.kill(self.process.pid, signal.SIGINT)
|
|
||||||
elif hasattr(signal, 'CTRL_C_EVENT'):
|
|
||||||
os.kill(self.process.pid, signal.CTRL_C_EVENT)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_alive(self):
|
|
||||||
return self.process.is_alive
|
|
||||||
|
|
||||||
def kill(self):
|
|
||||||
self.out_queue.put(('quit', 0))
|
|
||||||
t = 0
|
|
||||||
while self.is_alive and t < 10:
|
|
||||||
time.sleep(0.1)
|
|
||||||
self.process.kill()
|
|
||||||
self.keep_going = False
|
|
||||||
|
|
@ -1,99 +0,0 @@
|
|||||||
#!/usr/bin/env python2
|
|
||||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
|
||||||
__docformat__ = 'restructuredtext en'
|
|
||||||
|
|
||||||
from PyQt5.Qt import QTextCharFormat, QFont, QBrush, QColor
|
|
||||||
|
|
||||||
from pygments.formatter import Formatter as PF
|
|
||||||
from pygments.token import Token, Generic, string_to_tokentype
|
|
||||||
|
|
||||||
class Formatter(object):
|
|
||||||
|
|
||||||
def __init__(self, prompt, continuation, style='default'):
|
|
||||||
if len(prompt) != len(continuation):
|
|
||||||
raise ValueError('%r does not have the same length as %r' %
|
|
||||||
(prompt, continuation))
|
|
||||||
|
|
||||||
self.prompt, self.continuation = prompt, continuation
|
|
||||||
self.set_style(style)
|
|
||||||
|
|
||||||
def set_style(self, style):
|
|
||||||
pf = PF(style=style)
|
|
||||||
self.styles = {}
|
|
||||||
self.normal = self.base_fmt()
|
|
||||||
self.background_color = pf.style.background_color
|
|
||||||
self.color = 'black'
|
|
||||||
|
|
||||||
for ttype, ndef in pf.style:
|
|
||||||
fmt = self.base_fmt()
|
|
||||||
fmt.setProperty(fmt.UserProperty, str(ttype))
|
|
||||||
if ndef['color']:
|
|
||||||
fmt.setForeground(QBrush(QColor('#%s'%ndef['color'])))
|
|
||||||
fmt.setUnderlineColor(QColor('#%s'%ndef['color']))
|
|
||||||
if ttype == Generic.Output:
|
|
||||||
self.color = '#%s'%ndef['color']
|
|
||||||
if ndef['bold']:
|
|
||||||
fmt.setFontWeight(QFont.Bold)
|
|
||||||
if ndef['italic']:
|
|
||||||
fmt.setFontItalic(True)
|
|
||||||
if ndef['underline']:
|
|
||||||
fmt.setFontUnderline(True)
|
|
||||||
if ndef['bgcolor']:
|
|
||||||
fmt.setBackground(QBrush(QColor('#%s'%ndef['bgcolor'])))
|
|
||||||
if ndef['border']:
|
|
||||||
pass # No support for borders
|
|
||||||
|
|
||||||
self.styles[ttype] = fmt
|
|
||||||
|
|
||||||
def get_fmt(self, token):
|
|
||||||
if type(token) != type(Token.Generic): # noqa
|
|
||||||
token = string_to_tokentype(token)
|
|
||||||
fmt = self.styles.get(token, None)
|
|
||||||
if fmt is None:
|
|
||||||
fmt = self.base_fmt()
|
|
||||||
fmt.setProperty(fmt.UserProperty, str(token))
|
|
||||||
return fmt
|
|
||||||
|
|
||||||
def base_fmt(self):
|
|
||||||
fmt = QTextCharFormat()
|
|
||||||
fmt.setFontFamily('monospace')
|
|
||||||
return fmt
|
|
||||||
|
|
||||||
def render_raw(self, raw, cursor):
|
|
||||||
cursor.insertText(raw, self.normal)
|
|
||||||
|
|
||||||
def render_syntax_error(self, tb, cursor):
|
|
||||||
fmt = self.get_fmt(Token.Error)
|
|
||||||
cursor.insertText(tb, fmt)
|
|
||||||
|
|
||||||
def render(self, tokens, cursor):
|
|
||||||
lastval = ''
|
|
||||||
lasttype = None
|
|
||||||
|
|
||||||
for ttype, value in tokens:
|
|
||||||
while ttype not in self.styles:
|
|
||||||
ttype = ttype.parent
|
|
||||||
if ttype == lasttype:
|
|
||||||
lastval += value
|
|
||||||
else:
|
|
||||||
if lastval:
|
|
||||||
fmt = self.styles[lasttype]
|
|
||||||
cursor.insertText(lastval, fmt)
|
|
||||||
lastval = value
|
|
||||||
lasttype = ttype
|
|
||||||
|
|
||||||
if lastval:
|
|
||||||
fmt = self.styles[lasttype]
|
|
||||||
cursor.insertText(lastval, fmt)
|
|
||||||
|
|
||||||
def render_prompt(self, is_continuation, cursor):
|
|
||||||
pr = self.continuation if is_continuation else self.prompt
|
|
||||||
fmt = self.get_fmt(Generic.Prompt)
|
|
||||||
if fmt is None:
|
|
||||||
fmt = self.base_fmt()
|
|
||||||
cursor.insertText(pr, fmt)
|
|
||||||
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
|||||||
#!/usr/bin/env python2
|
|
||||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
|
||||||
__docformat__ = 'restructuredtext en'
|
|
||||||
|
|
||||||
from collections import deque
|
|
||||||
|
|
||||||
class History(object): # {{{
|
|
||||||
|
|
||||||
def __init__(self, current, entries):
|
|
||||||
self.entries = deque(entries, maxlen=max(2000, len(entries)))
|
|
||||||
self.index = len(self.entries) - 1
|
|
||||||
self.current = self.default = current
|
|
||||||
self.last_was_back = False
|
|
||||||
|
|
||||||
def back(self, amt=1):
|
|
||||||
if self.entries:
|
|
||||||
oidx = self.index
|
|
||||||
ans = self.entries[self.index]
|
|
||||||
self.index = max(0, self.index - amt)
|
|
||||||
self.last_was_back = self.index != oidx
|
|
||||||
return ans
|
|
||||||
|
|
||||||
def forward(self, amt=1):
|
|
||||||
if self.entries:
|
|
||||||
d = self.index
|
|
||||||
if self.last_was_back:
|
|
||||||
d += 1
|
|
||||||
if d >= len(self.entries) - 1:
|
|
||||||
self.index = len(self.entries) - 1
|
|
||||||
self.last_was_back = False
|
|
||||||
return self.current
|
|
||||||
if self.last_was_back:
|
|
||||||
amt += 1
|
|
||||||
self.index = min(len(self.entries)-1, self.index + amt)
|
|
||||||
self.last_was_back = False
|
|
||||||
return self.entries[self.index]
|
|
||||||
|
|
||||||
def enter(self, x):
|
|
||||||
try:
|
|
||||||
self.entries.remove(x)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
self.entries.append(x)
|
|
||||||
self.index = len(self.entries) - 1
|
|
||||||
self.current = self.default
|
|
||||||
self.last_was_back = False
|
|
||||||
|
|
||||||
def serialize(self):
|
|
||||||
return list(self.entries)
|
|
||||||
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
|
|
@ -1,178 +0,0 @@
|
|||||||
#!/usr/bin/env python2
|
|
||||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
|
||||||
__docformat__ = 'restructuredtext en'
|
|
||||||
|
|
||||||
import sys, cPickle, os, binascii
|
|
||||||
from code import InteractiveInterpreter
|
|
||||||
from Queue import Queue, Empty
|
|
||||||
from threading import Thread
|
|
||||||
from binascii import unhexlify
|
|
||||||
from multiprocessing.connection import Client
|
|
||||||
from repr import repr as safe_repr
|
|
||||||
|
|
||||||
from calibre.utils.pyconsole import preferred_encoding, isbytestring, \
|
|
||||||
POLL_TIMEOUT
|
|
||||||
|
|
||||||
'''
|
|
||||||
Messages sent by client:
|
|
||||||
|
|
||||||
(stdout, unicode)
|
|
||||||
(stderr, unicode)
|
|
||||||
(syntaxerror, unicode)
|
|
||||||
(traceback, unicode)
|
|
||||||
(done, True iff incomplete command)
|
|
||||||
|
|
||||||
Messages that can be received by client:
|
|
||||||
(quit, return code)
|
|
||||||
(run, unicode)
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
def tounicode(raw): # {{{
|
|
||||||
if isbytestring(raw):
|
|
||||||
try:
|
|
||||||
raw = raw.decode(preferred_encoding, 'replace')
|
|
||||||
except:
|
|
||||||
raw = safe_repr(raw)
|
|
||||||
|
|
||||||
if isbytestring(raw):
|
|
||||||
try:
|
|
||||||
raw.decode('utf-8', 'replace')
|
|
||||||
except:
|
|
||||||
raw = u'Undecodable bytestring'
|
|
||||||
return raw
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
class DummyFile(object): # {{{
|
|
||||||
|
|
||||||
def __init__(self, what, out_queue):
|
|
||||||
self.closed = False
|
|
||||||
self.name = 'console'
|
|
||||||
self.softspace = 0
|
|
||||||
self.what = what
|
|
||||||
self.out_queue = out_queue
|
|
||||||
|
|
||||||
def flush(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def write(self, raw):
|
|
||||||
self.out_queue.put((self.what, tounicode(raw)))
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
class Comm(Thread): # {{{
|
|
||||||
|
|
||||||
def __init__(self, conn, out_queue, in_queue):
|
|
||||||
Thread.__init__(self)
|
|
||||||
self.daemon = True
|
|
||||||
self.conn = conn
|
|
||||||
self.out_queue = out_queue
|
|
||||||
self.in_queue = in_queue
|
|
||||||
self.keep_going = True
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
while self.keep_going:
|
|
||||||
try:
|
|
||||||
self.communicate()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
pass
|
|
||||||
except EOFError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def communicate(self):
|
|
||||||
if self.conn.poll(POLL_TIMEOUT):
|
|
||||||
try:
|
|
||||||
obj = self.conn.recv()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
self.in_queue.put(obj)
|
|
||||||
try:
|
|
||||||
obj = self.out_queue.get_nowait()
|
|
||||||
except Empty:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
self.conn.send(obj)
|
|
||||||
except:
|
|
||||||
raise EOFError('interpreter failed to send')
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
class Interpreter(InteractiveInterpreter): # {{{
|
|
||||||
|
|
||||||
def __init__(self, queue, local={}):
|
|
||||||
if '__name__' not in local:
|
|
||||||
local['__name__'] = '__console__'
|
|
||||||
if '__doc__' not in local:
|
|
||||||
local['__doc__'] = None
|
|
||||||
self.out_queue = queue
|
|
||||||
sys.stdout = DummyFile('stdout', queue)
|
|
||||||
sys.stderr = DummyFile('sdterr', queue)
|
|
||||||
InteractiveInterpreter.__init__(self, locals=local)
|
|
||||||
|
|
||||||
def showtraceback(self, *args, **kwargs):
|
|
||||||
self.is_syntax_error = False
|
|
||||||
InteractiveInterpreter.showtraceback(self, *args, **kwargs)
|
|
||||||
|
|
||||||
def showsyntaxerror(self, *args, **kwargs):
|
|
||||||
self.is_syntax_error = True
|
|
||||||
InteractiveInterpreter.showsyntaxerror(self, *args, **kwargs)
|
|
||||||
|
|
||||||
def write(self, raw):
|
|
||||||
what = 'syntaxerror' if self.is_syntax_error else 'traceback'
|
|
||||||
self.out_queue.put((what, tounicode(raw)))
|
|
||||||
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
def connect():
|
|
||||||
os.chdir(cPickle.loads(binascii.unhexlify(os.environ['ORIGWD'])))
|
|
||||||
address = cPickle.loads(unhexlify(os.environ['CALIBRE_WORKER_ADDRESS']))
|
|
||||||
key = unhexlify(os.environ['CALIBRE_WORKER_KEY'])
|
|
||||||
return Client(address, authkey=key)
|
|
||||||
|
|
||||||
def main():
|
|
||||||
out_queue = Queue()
|
|
||||||
in_queue = Queue()
|
|
||||||
conn = connect()
|
|
||||||
comm = Comm(conn, out_queue, in_queue)
|
|
||||||
comm.start()
|
|
||||||
interpreter = Interpreter(out_queue)
|
|
||||||
|
|
||||||
ret = 0
|
|
||||||
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
cmd, data = in_queue.get(1)
|
|
||||||
except Empty:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
if cmd == 'quit':
|
|
||||||
ret = data
|
|
||||||
comm.keep_going = False
|
|
||||||
comm.join()
|
|
||||||
break
|
|
||||||
elif cmd == 'run':
|
|
||||||
if not comm.is_alive():
|
|
||||||
ret = 1
|
|
||||||
break
|
|
||||||
ret = False
|
|
||||||
try:
|
|
||||||
ret = interpreter.runsource(data)
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
pass
|
|
||||||
except SystemExit:
|
|
||||||
out_queue.put(('stderr', 'SystemExit ignored\n'))
|
|
||||||
out_queue.put(('done', ret))
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return ret
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
@ -1,91 +0,0 @@
|
|||||||
#!/usr/bin/env python2
|
|
||||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
|
||||||
__docformat__ = 'restructuredtext en'
|
|
||||||
__version__ = '0.1.0'
|
|
||||||
|
|
||||||
from functools import partial
|
|
||||||
|
|
||||||
from PyQt5.Qt import QDialog, QToolBar, QStatusBar, QLabel, QFont, Qt, \
|
|
||||||
QApplication, QIcon, QVBoxLayout, QAction
|
|
||||||
|
|
||||||
from calibre.utils.pyconsole import dynamic, __appname__, __version__
|
|
||||||
from calibre.utils.pyconsole.console import Console
|
|
||||||
|
|
||||||
class MainWindow(QDialog):
|
|
||||||
|
|
||||||
def __init__(self,
|
|
||||||
default_status_msg=_('Welcome to') + ' ' + __appname__+' console',
|
|
||||||
parent=None):
|
|
||||||
QDialog.__init__(self, parent)
|
|
||||||
|
|
||||||
self.restart_requested = False
|
|
||||||
self.l = QVBoxLayout()
|
|
||||||
self.setLayout(self.l)
|
|
||||||
|
|
||||||
self.resize(800, 600)
|
|
||||||
geom = dynamic.get('console_window_geometry', None)
|
|
||||||
if geom is not None:
|
|
||||||
self.restoreGeometry(geom)
|
|
||||||
|
|
||||||
# Setup tool bar {{{
|
|
||||||
self.tool_bar = QToolBar(self)
|
|
||||||
self.tool_bar.setToolButtonStyle(Qt.ToolButtonTextOnly)
|
|
||||||
self.l.addWidget(self.tool_bar)
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
# Setup status bar {{{
|
|
||||||
self.status_bar = QStatusBar(self)
|
|
||||||
self.status_bar.defmsg = QLabel(__appname__ + _(' console ') +
|
|
||||||
__version__)
|
|
||||||
self.status_bar._font = QFont()
|
|
||||||
self.status_bar._font.setBold(True)
|
|
||||||
self.status_bar.defmsg.setFont(self.status_bar._font)
|
|
||||||
self.status_bar.addWidget(self.status_bar.defmsg)
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
self.console = Console(parent=self)
|
|
||||||
self.console.running.connect(partial(self.status_bar.showMessage,
|
|
||||||
_('Code is running')))
|
|
||||||
self.console.running_done.connect(self.status_bar.clearMessage)
|
|
||||||
self.l.addWidget(self.console)
|
|
||||||
self.l.addWidget(self.status_bar)
|
|
||||||
self.setWindowTitle(__appname__ + ' console')
|
|
||||||
self.setWindowIcon(QIcon(I('console.png')))
|
|
||||||
|
|
||||||
self.restart_action = QAction(_('Restart console'), self)
|
|
||||||
self.restart_action.setShortcut(_('Ctrl+R'))
|
|
||||||
self.addAction(self.restart_action)
|
|
||||||
self.restart_action.triggered.connect(self.restart)
|
|
||||||
self.console.context_menu.addAction(self.restart_action)
|
|
||||||
|
|
||||||
def restart(self):
|
|
||||||
self.restart_requested = True
|
|
||||||
self.reject()
|
|
||||||
|
|
||||||
def closeEvent(self, *args):
|
|
||||||
dynamic.set('console_window_geometry',
|
|
||||||
bytearray(self.saveGeometry()))
|
|
||||||
self.console.shutdown()
|
|
||||||
return QDialog.closeEvent(self, *args)
|
|
||||||
|
|
||||||
|
|
||||||
def show():
|
|
||||||
while True:
|
|
||||||
m = MainWindow()
|
|
||||||
m.exec_()
|
|
||||||
if not m.restart_requested:
|
|
||||||
break
|
|
||||||
|
|
||||||
def main():
|
|
||||||
QApplication.setApplicationName(__appname__+' console')
|
|
||||||
QApplication.setOrganizationName('Kovid Goyal')
|
|
||||||
app = QApplication([])
|
|
||||||
app
|
|
||||||
show()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
|||||||
#!/usr/bin/env python2
|
|
||||||
# vim:fileencoding=utf-8
|
|
||||||
from __future__ import (unicode_literals, division, absolute_import,
|
|
||||||
print_function)
|
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
|
||||||
|
|
||||||
# Dummy file for backwards compatibility with older plugins
|
|
||||||
from calibre.utils.search_query_parser import ParseException # noqa
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user