Switch to tabs for indentation.
Instead of a mix of 2- and 4-space tabs just use actual tabs. ;-P
This commit is contained in:
@@ -16,17 +16,17 @@ import base64, os, io, zipfile
|
||||
|
||||
|
||||
def initialize(joy_home):
|
||||
Z.extractall(joy_home)
|
||||
Z.extractall(joy_home)
|
||||
|
||||
|
||||
def create_data(from_dir='./default_joy_home'):
|
||||
f = io.StringIO()
|
||||
z = zipfile.ZipFile(f, mode='w')
|
||||
for fn in os.listdir(from_dir):
|
||||
from_fn = os.path.join(from_dir, fn)
|
||||
z.write(from_fn, fn)
|
||||
z.close()
|
||||
return base64.encodestring(f.getvalue())
|
||||
f = io.StringIO()
|
||||
z = zipfile.ZipFile(f, mode='w')
|
||||
for fn in os.listdir(from_dir):
|
||||
from_fn = os.path.join(from_dir, fn)
|
||||
z.write(from_fn, fn)
|
||||
z.close()
|
||||
return base64.encodestring(f.getvalue())
|
||||
|
||||
|
||||
Z = zipfile.ZipFile(io.StringIO(base64.decodestring('''\
|
||||
@@ -103,4 +103,4 @@ AAAAAAAAAAAAtIH2BgAAZGVmaW5pdGlvbnMudHh0UEsFBgAAAAAFAAUAHgEAAF0OAAAAAA==''')))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(create_data())
|
||||
print(create_data())
|
||||
|
||||
+60
-60
@@ -23,10 +23,10 @@ repo = init_home(JOY_HOME)
|
||||
|
||||
_log = logging.getLogger(__name__)
|
||||
logging.basicConfig(
|
||||
format='%(asctime)-15s %(levelname)s %(name)s %(message)s',
|
||||
filename=os.path.join(JOY_HOME, 'thun.log'),
|
||||
level=logging.INFO,
|
||||
)
|
||||
format='%(asctime)-15s %(levelname)s %(name)s %(message)s',
|
||||
filename=os.path.join(JOY_HOME, 'thun.log'),
|
||||
level=logging.INFO,
|
||||
)
|
||||
_log.info('Starting with JOY_HOME=%s', JOY_HOME)
|
||||
|
||||
|
||||
@@ -39,73 +39,73 @@ from joy.utils.stack import stack_to_string
|
||||
cp = RawConfigParser()
|
||||
cp.optionxform = str # Don't mess with uppercase.
|
||||
with open(os.path.join(args.joy_home, 'thun.config')) as f:
|
||||
cp.readfp(f)
|
||||
cp.readfp(f)
|
||||
|
||||
|
||||
GLOBAL_COMMANDS = dict(cp.items('key bindings'))
|
||||
|
||||
|
||||
def repo_relative_path(path):
|
||||
return os.path.relpath(
|
||||
path,
|
||||
os.path.commonprefix((repo.controldir(), path))
|
||||
)
|
||||
return os.path.relpath(
|
||||
path,
|
||||
os.path.commonprefix((repo.controldir(), path))
|
||||
)
|
||||
|
||||
def commands():
|
||||
# pylint: disable=unused-variable
|
||||
# pylint: disable=unused-variable
|
||||
|
||||
def key_bindings(*args):
|
||||
commands = [ # These are bound in the TextViewerWidget.
|
||||
'Control-Enter - Run the selection as Joy code, or if there\'s no selection the line containing the cursor.',
|
||||
'F3 - Copy selection to stack.',
|
||||
'Shift-F3 - Cut selection to stack.',
|
||||
'F4 - Paste item on top of stack to insertion cursor.',
|
||||
'Shift-F4 - Pop and paste top of stack to insertion cursor.',
|
||||
]
|
||||
for key, command in GLOBAL_COMMANDS.items():
|
||||
commands.append('%s - %s' % (key.lstrip('<').rstrip('>'), command))
|
||||
print('\n'.join([''] + sorted(commands)))
|
||||
return args
|
||||
def key_bindings(*args):
|
||||
commands = [ # These are bound in the TextViewerWidget.
|
||||
'Control-Enter - Run the selection as Joy code, or if there\'s no selection the line containing the cursor.',
|
||||
'F3 - Copy selection to stack.',
|
||||
'Shift-F3 - Cut selection to stack.',
|
||||
'F4 - Paste item on top of stack to insertion cursor.',
|
||||
'Shift-F4 - Pop and paste top of stack to insertion cursor.',
|
||||
]
|
||||
for key, command in GLOBAL_COMMANDS.items():
|
||||
commands.append('%s - %s' % (key.lstrip('<').rstrip('>'), command))
|
||||
print('\n'.join([''] + sorted(commands)))
|
||||
return args
|
||||
|
||||
|
||||
def mouse_bindings(*args):
|
||||
print(dedent('''
|
||||
Mouse button chords (to cancel a chord, click the third mouse button.)
|
||||
def mouse_bindings(*args):
|
||||
print(dedent('''
|
||||
Mouse button chords (to cancel a chord, click the third mouse button.)
|
||||
|
||||
Left - Point, sweep selection
|
||||
Left-Middle - Copy the selection, place text on stack
|
||||
Left-Right - Run the selection as Joy code
|
||||
Left - Point, sweep selection
|
||||
Left-Middle - Copy the selection, place text on stack
|
||||
Left-Right - Run the selection as Joy code
|
||||
|
||||
Middle - Paste selection (bypass stack); click and drag to scroll.
|
||||
Middle-Left - Paste from top of stack, preserve
|
||||
Middle-Right - Paste from top of stack, pop
|
||||
Middle - Paste selection (bypass stack); click and drag to scroll.
|
||||
Middle-Left - Paste from top of stack, preserve
|
||||
Middle-Right - Paste from top of stack, pop
|
||||
|
||||
Right - Execute command word under mouse cursor
|
||||
Right-Left - Print docs of command word under mouse cursor
|
||||
Right-Middle - Lookup word (kinda useless now)
|
||||
'''))
|
||||
return args
|
||||
Right - Execute command word under mouse cursor
|
||||
Right-Left - Print docs of command word under mouse cursor
|
||||
Right-Middle - Lookup word (kinda useless now)
|
||||
'''))
|
||||
return args
|
||||
|
||||
|
||||
def reset_log(*args):
|
||||
log.delete('0.0', tk.END)
|
||||
print(__doc__)
|
||||
return args
|
||||
def reset_log(*args):
|
||||
log.delete('0.0', tk.END)
|
||||
print(__doc__)
|
||||
return args
|
||||
|
||||
|
||||
def show_log(*args):
|
||||
log_window.wm_deiconify()
|
||||
log_window.update()
|
||||
return args
|
||||
def show_log(*args):
|
||||
log_window.wm_deiconify()
|
||||
log_window.update()
|
||||
return args
|
||||
|
||||
|
||||
def grand_reset(s, e, d):
|
||||
stack = world.load_stack() or ()
|
||||
log.reset()
|
||||
t.reset()
|
||||
return stack, e, d
|
||||
def grand_reset(s, e, d):
|
||||
stack = world.load_stack() or ()
|
||||
log.reset()
|
||||
t.reset()
|
||||
return stack, e, d
|
||||
|
||||
return locals()
|
||||
return locals()
|
||||
|
||||
|
||||
STACK_FN = os.path.join(JOY_HOME, 'stack.pickle')
|
||||
@@ -125,19 +125,19 @@ FONT = get_font('Iosevka', size=14) # Requires Tk root already set up.
|
||||
log.init('Log', LOG_FN, repo_relative_path(LOG_FN), repo, FONT)
|
||||
t.init('Joy - ' + JOY_HOME, JOY_FN, repo_relative_path(JOY_FN), repo, FONT)
|
||||
for event, command in GLOBAL_COMMANDS.items():
|
||||
callback = lambda _, _command=command: world.interpret(_command)
|
||||
t.bind(event, callback)
|
||||
log.bind(event, callback)
|
||||
callback = lambda _, _command=command: world.interpret(_command)
|
||||
t.bind(event, callback)
|
||||
log.bind(event, callback)
|
||||
|
||||
|
||||
def main():
|
||||
sys.stdout, old_stdout = FileFaker(log), sys.stdout
|
||||
try:
|
||||
t.mainloop()
|
||||
finally:
|
||||
sys.stdout = old_stdout
|
||||
return 0
|
||||
sys.stdout, old_stdout = FileFaker(log), sys.stdout
|
||||
try:
|
||||
t.mainloop()
|
||||
finally:
|
||||
sys.stdout = old_stdout
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
main()
|
||||
|
||||
+132
-132
@@ -25,187 +25,187 @@ nothing = lambda event: None
|
||||
|
||||
|
||||
class MouseBindingsMixin(object):
|
||||
"""TextViewerWidget mixin class to provide mouse bindings."""
|
||||
"""TextViewerWidget mixin class to provide mouse bindings."""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self):
|
||||
|
||||
#Remember our mouse button state
|
||||
self.B1_DOWN = False
|
||||
self.B2_DOWN = False
|
||||
self.B3_DOWN = False
|
||||
#Remember our mouse button state
|
||||
self.B1_DOWN = False
|
||||
self.B2_DOWN = False
|
||||
self.B3_DOWN = False
|
||||
|
||||
#Remember our pending action.
|
||||
self.dothis = nothing
|
||||
#Remember our pending action.
|
||||
self.dothis = nothing
|
||||
|
||||
#We'll need to remember whether or not we've been moving B2.
|
||||
self.beenMovingB2 = False
|
||||
#We'll need to remember whether or not we've been moving B2.
|
||||
self.beenMovingB2 = False
|
||||
|
||||
#Unbind the events we're interested in.
|
||||
for sequence in (
|
||||
"<Button-1>", "<B1-Motion>", "<ButtonRelease-1>",
|
||||
"<Button-2>", "<B2-Motion>", "<ButtonRelease-2>",
|
||||
"<Button-3>", "<B3-Motion>", "<ButtonRelease-3>",
|
||||
"<B1-Leave>", "<B2-Leave>", "<B3-Leave>", "<Any-Leave>", "<Leave>"
|
||||
):
|
||||
self.unbind(sequence)
|
||||
self.unbind_all(sequence)
|
||||
#Unbind the events we're interested in.
|
||||
for sequence in (
|
||||
"<Button-1>", "<B1-Motion>", "<ButtonRelease-1>",
|
||||
"<Button-2>", "<B2-Motion>", "<ButtonRelease-2>",
|
||||
"<Button-3>", "<B3-Motion>", "<ButtonRelease-3>",
|
||||
"<B1-Leave>", "<B2-Leave>", "<B3-Leave>", "<Any-Leave>", "<Leave>"
|
||||
):
|
||||
self.unbind(sequence)
|
||||
self.unbind_all(sequence)
|
||||
|
||||
self.event_delete('<<PasteSelection>>') #I forgot what this was for! :-P D'oh!
|
||||
self.event_delete('<<PasteSelection>>') #I forgot what this was for! :-P D'oh!
|
||||
|
||||
#Bind our event handlers to their events.
|
||||
self.bind("<Button-1>", self.B1d)
|
||||
self.bind("<B1-Motion>", self.B1m)
|
||||
self.bind("<ButtonRelease-1>", self.B1r)
|
||||
#Bind our event handlers to their events.
|
||||
self.bind("<Button-1>", self.B1d)
|
||||
self.bind("<B1-Motion>", self.B1m)
|
||||
self.bind("<ButtonRelease-1>", self.B1r)
|
||||
|
||||
self.bind("<Button-2>", self.B2d)
|
||||
self.bind("<B2-Motion>", self.B2m)
|
||||
self.bind("<ButtonRelease-2>", self.B2r)
|
||||
self.bind("<Button-2>", self.B2d)
|
||||
self.bind("<B2-Motion>", self.B2m)
|
||||
self.bind("<ButtonRelease-2>", self.B2r)
|
||||
|
||||
self.bind("<Button-3>", self.B3d)
|
||||
self.bind("<B3-Motion>", self.B3m)
|
||||
self.bind("<ButtonRelease-3>", self.B3r)
|
||||
self.bind("<Button-3>", self.B3d)
|
||||
self.bind("<B3-Motion>", self.B3m)
|
||||
self.bind("<ButtonRelease-3>", self.B3r)
|
||||
|
||||
self.bind("<Any-Leave>", self.leave)
|
||||
self.bind("<Motion>", self.scan_command)
|
||||
self.bind("<Any-Leave>", self.leave)
|
||||
self.bind("<Motion>", self.scan_command)
|
||||
|
||||
def B1d(self, event):
|
||||
'''button one pressed'''
|
||||
self.B1_DOWN = True
|
||||
def B1d(self, event):
|
||||
'''button one pressed'''
|
||||
self.B1_DOWN = True
|
||||
|
||||
if self.B2_DOWN:
|
||||
if self.B2_DOWN:
|
||||
|
||||
self.unhighlight_command()
|
||||
self.unhighlight_command()
|
||||
|
||||
if self.B3_DOWN :
|
||||
self.dothis = self.cancel
|
||||
if self.B3_DOWN :
|
||||
self.dothis = self.cancel
|
||||
|
||||
else:
|
||||
#copy TOS to the mouse (instead of system selection.)
|
||||
self.dothis = self.copyto #middle-left-interclick
|
||||
else:
|
||||
#copy TOS to the mouse (instead of system selection.)
|
||||
self.dothis = self.copyto #middle-left-interclick
|
||||
|
||||
elif self.B3_DOWN :
|
||||
self.unhighlight_command()
|
||||
self.dothis = self.opendoc #right-left-interclick
|
||||
elif self.B3_DOWN :
|
||||
self.unhighlight_command()
|
||||
self.dothis = self.opendoc #right-left-interclick
|
||||
|
||||
else:
|
||||
##button 1 down, set insertion and begin selection.
|
||||
##Actually, do nothing. Tk Text widget defaults take care of it.
|
||||
self.dothis = nothing
|
||||
return
|
||||
else:
|
||||
##button 1 down, set insertion and begin selection.
|
||||
##Actually, do nothing. Tk Text widget defaults take care of it.
|
||||
self.dothis = nothing
|
||||
return
|
||||
|
||||
#Prevent further event handling by returning "break".
|
||||
return "break"
|
||||
#Prevent further event handling by returning "break".
|
||||
return "break"
|
||||
|
||||
def B2d(self, event):
|
||||
'''button two pressed'''
|
||||
self.B2_DOWN = 1
|
||||
def B2d(self, event):
|
||||
'''button two pressed'''
|
||||
self.B2_DOWN = 1
|
||||
|
||||
if self.B1_DOWN :
|
||||
if self.B1_DOWN :
|
||||
|
||||
if self.B3_DOWN :
|
||||
self.dothis = self.cancel
|
||||
if self.B3_DOWN :
|
||||
self.dothis = self.cancel
|
||||
|
||||
else:
|
||||
#left-middle-interclick - copy selection to stack
|
||||
self.dothis = self.copy_selection_to_stack
|
||||
else:
|
||||
#left-middle-interclick - copy selection to stack
|
||||
self.dothis = self.copy_selection_to_stack
|
||||
|
||||
elif self.B3_DOWN :
|
||||
self.unhighlight_command()
|
||||
self.dothis = self.lookup #right-middle-interclick - lookup
|
||||
elif self.B3_DOWN :
|
||||
self.unhighlight_command()
|
||||
self.dothis = self.lookup #right-middle-interclick - lookup
|
||||
|
||||
else:
|
||||
#middle-click - paste X selection to mouse pointer
|
||||
self.set_insertion_point(event)
|
||||
self.dothis = self.paste_X_selection_to_mouse_pointer
|
||||
return
|
||||
else:
|
||||
#middle-click - paste X selection to mouse pointer
|
||||
self.set_insertion_point(event)
|
||||
self.dothis = self.paste_X_selection_to_mouse_pointer
|
||||
return
|
||||
|
||||
return "break"
|
||||
return "break"
|
||||
|
||||
def B3d(self, event):
|
||||
'''button three pressed'''
|
||||
self.B3_DOWN = 1
|
||||
def B3d(self, event):
|
||||
'''button three pressed'''
|
||||
self.B3_DOWN = 1
|
||||
|
||||
if self.B1_DOWN :
|
||||
if self.B1_DOWN :
|
||||
|
||||
if self.B2_DOWN :
|
||||
self.dothis = self.cancel
|
||||
if self.B2_DOWN :
|
||||
self.dothis = self.cancel
|
||||
|
||||
else:
|
||||
#left-right-interclick - run selection
|
||||
self.dothis = self.run_selection
|
||||
else:
|
||||
#left-right-interclick - run selection
|
||||
self.dothis = self.run_selection
|
||||
|
||||
elif self.B2_DOWN :
|
||||
#middle-right-interclick - Pop/Cut from TOS to insertion cursor
|
||||
self.unhighlight_command()
|
||||
self.dothis = self.pastecut
|
||||
elif self.B2_DOWN :
|
||||
#middle-right-interclick - Pop/Cut from TOS to insertion cursor
|
||||
self.unhighlight_command()
|
||||
self.dothis = self.pastecut
|
||||
|
||||
else:
|
||||
#right-click
|
||||
self.CommandFirstDown(event)
|
||||
else:
|
||||
#right-click
|
||||
self.CommandFirstDown(event)
|
||||
|
||||
return "break"
|
||||
return "break"
|
||||
|
||||
def B1m(self, event):
|
||||
'''button one moved'''
|
||||
if self.B2_DOWN or self.B3_DOWN:
|
||||
return "break"
|
||||
def B1m(self, event):
|
||||
'''button one moved'''
|
||||
if self.B2_DOWN or self.B3_DOWN:
|
||||
return "break"
|
||||
|
||||
def B2m(self, event):
|
||||
'''button two moved'''
|
||||
if self.dothis == self.paste_X_selection_to_mouse_pointer and \
|
||||
not (self.B1_DOWN or self.B3_DOWN):
|
||||
def B2m(self, event):
|
||||
'''button two moved'''
|
||||
if self.dothis == self.paste_X_selection_to_mouse_pointer and \
|
||||
not (self.B1_DOWN or self.B3_DOWN):
|
||||
|
||||
self.beenMovingB2 = True
|
||||
return
|
||||
self.beenMovingB2 = True
|
||||
return
|
||||
|
||||
return "break"
|
||||
return "break"
|
||||
|
||||
def B3m(self, event):
|
||||
'''button three moved'''
|
||||
if self.dothis == self.do_command and \
|
||||
not (self.B1_DOWN or self.B2_DOWN):
|
||||
def B3m(self, event):
|
||||
'''button three moved'''
|
||||
if self.dothis == self.do_command and \
|
||||
not (self.B1_DOWN or self.B2_DOWN):
|
||||
|
||||
self.update_command_word(event)
|
||||
self.update_command_word(event)
|
||||
|
||||
return "break"
|
||||
return "break"
|
||||
|
||||
def scan_command(self, event):
|
||||
self.update_command_word(event)
|
||||
def scan_command(self, event):
|
||||
self.update_command_word(event)
|
||||
|
||||
def B1r(self, event):
|
||||
'''button one released'''
|
||||
self.B1_DOWN = False
|
||||
def B1r(self, event):
|
||||
'''button one released'''
|
||||
self.B1_DOWN = False
|
||||
|
||||
if not (self.B2_DOWN or self.B3_DOWN):
|
||||
self.dothis(event)
|
||||
if not (self.B2_DOWN or self.B3_DOWN):
|
||||
self.dothis(event)
|
||||
|
||||
return "break"
|
||||
return "break"
|
||||
|
||||
def B2r(self, event):
|
||||
'''button two released'''
|
||||
self.B2_DOWN = False
|
||||
def B2r(self, event):
|
||||
'''button two released'''
|
||||
self.B2_DOWN = False
|
||||
|
||||
if not (self.B1_DOWN or self.B3_DOWN or self.beenMovingB2):
|
||||
self.dothis(event)
|
||||
if not (self.B1_DOWN or self.B3_DOWN or self.beenMovingB2):
|
||||
self.dothis(event)
|
||||
|
||||
self.beenMovingB2 = False
|
||||
self.beenMovingB2 = False
|
||||
|
||||
return "break"
|
||||
return "break"
|
||||
|
||||
def B3r(self, event):
|
||||
'''button three released'''
|
||||
self.B3_DOWN = False
|
||||
def B3r(self, event):
|
||||
'''button three released'''
|
||||
self.B3_DOWN = False
|
||||
|
||||
if not (self.B1_DOWN or self.B2_DOWN) :
|
||||
self.dothis(event)
|
||||
if not (self.B1_DOWN or self.B2_DOWN) :
|
||||
self.dothis(event)
|
||||
|
||||
return "break"
|
||||
return "break"
|
||||
|
||||
def InsertFirstDown(self, event):
|
||||
self.focus()
|
||||
self.dothis = nothing
|
||||
self.set_insertion_point(event)
|
||||
def InsertFirstDown(self, event):
|
||||
self.focus()
|
||||
self.dothis = nothing
|
||||
self.set_insertion_point(event)
|
||||
|
||||
def CommandFirstDown(self, event):
|
||||
self.dothis = self.do_command
|
||||
self.update_command_word(event)
|
||||
def CommandFirstDown(self, event):
|
||||
self.dothis = self.do_command
|
||||
self.update_command_word(event)
|
||||
|
||||
+335
-335
@@ -25,12 +25,12 @@ A Graphical User Interface for a dialect of Joy in Python.
|
||||
|
||||
The GUI
|
||||
|
||||
History
|
||||
Structure
|
||||
Commands
|
||||
Mouse Chords
|
||||
Keyboard
|
||||
Output from Joy
|
||||
History
|
||||
Structure
|
||||
Commands
|
||||
Mouse Chords
|
||||
Keyboard
|
||||
Output from Joy
|
||||
|
||||
|
||||
'''
|
||||
@@ -40,11 +40,11 @@ standard_library.install_aliases()
|
||||
from builtins import str, map, object
|
||||
from past.builtins import basestring
|
||||
try:
|
||||
import tkinter as tk
|
||||
from tkinter.font import families, Font
|
||||
import tkinter as tk
|
||||
from tkinter.font import families, Font
|
||||
except ImportError:
|
||||
import Tkinter as tk
|
||||
from tkFont import families, Font
|
||||
import Tkinter as tk
|
||||
from tkFont import families, Font
|
||||
|
||||
from re import compile as regular_expression
|
||||
from traceback import format_exc
|
||||
@@ -58,17 +58,17 @@ from .world import World
|
||||
|
||||
|
||||
def make_gui(dictionary):
|
||||
t = TextViewerWidget(World(dictionary=dictionary))
|
||||
t['font'] = get_font()
|
||||
t._root().title('Joy')
|
||||
t.pack(expand=True, fill=tk.BOTH)
|
||||
return t
|
||||
t = TextViewerWidget(World(dictionary=dictionary))
|
||||
t['font'] = get_font()
|
||||
t._root().title('Joy')
|
||||
t.pack(expand=True, fill=tk.BOTH)
|
||||
return t
|
||||
|
||||
|
||||
def get_font(family='EB Garamond', size=14):
|
||||
if family not in families():
|
||||
family = 'Times'
|
||||
return Font(family=family, size=size)
|
||||
if family not in families():
|
||||
family = 'Times'
|
||||
return Font(family=family, size=size)
|
||||
|
||||
|
||||
#: Define mapping between Tkinter events and functions or methods. The
|
||||
@@ -77,85 +77,85 @@ def get_font(family='EB Garamond', size=14):
|
||||
#: must return the actual callable to which to bind the event sequence.
|
||||
TEXT_BINDINGS = {
|
||||
|
||||
#I want to ensure that these keyboard shortcuts work.
|
||||
'<Control-Return>': lambda tv: tv._control_enter,
|
||||
'<Control-v>': lambda tv: tv._paste,
|
||||
'<Control-V>': lambda tv: tv._paste,
|
||||
'<F3>': lambda tv: tv.copy_selection_to_stack,
|
||||
'<F4>': lambda tv: tv.copyto,
|
||||
'<Shift-F3>': lambda tv: tv.cut,
|
||||
'<Shift-F4>': lambda tv: tv.pastecut,
|
||||
'<Shift-Insert>': lambda tv: tv._paste,
|
||||
}
|
||||
#I want to ensure that these keyboard shortcuts work.
|
||||
'<Control-Return>': lambda tv: tv._control_enter,
|
||||
'<Control-v>': lambda tv: tv._paste,
|
||||
'<Control-V>': lambda tv: tv._paste,
|
||||
'<F3>': lambda tv: tv.copy_selection_to_stack,
|
||||
'<F4>': lambda tv: tv.copyto,
|
||||
'<Shift-F3>': lambda tv: tv.cut,
|
||||
'<Shift-F4>': lambda tv: tv.pastecut,
|
||||
'<Shift-Insert>': lambda tv: tv._paste,
|
||||
}
|
||||
|
||||
|
||||
class SavingMixin(object):
|
||||
|
||||
def __init__(self, saver=None, filename=None, save_delay=2000):
|
||||
self.saver = self._saver if saver is None else saver
|
||||
self.filename = filename
|
||||
self._save_delay = save_delay
|
||||
self.tk.call(self._w, 'edit', 'modified', 0)
|
||||
self.bind('<<Modified>>', self._beenModified)
|
||||
self._resetting_modified_flag = False
|
||||
self._save = None
|
||||
def __init__(self, saver=None, filename=None, save_delay=2000):
|
||||
self.saver = self._saver if saver is None else saver
|
||||
self.filename = filename
|
||||
self._save_delay = save_delay
|
||||
self.tk.call(self._w, 'edit', 'modified', 0)
|
||||
self.bind('<<Modified>>', self._beenModified)
|
||||
self._resetting_modified_flag = False
|
||||
self._save = None
|
||||
|
||||
def save(self):
|
||||
'''
|
||||
Call _saveFunc() after a certain amount of idle time.
|
||||
def save(self):
|
||||
'''
|
||||
Call _saveFunc() after a certain amount of idle time.
|
||||
|
||||
Called by _beenModified().
|
||||
'''
|
||||
self._cancelSave()
|
||||
if self.saver:
|
||||
self._saveAfter(self._save_delay)
|
||||
Called by _beenModified().
|
||||
'''
|
||||
self._cancelSave()
|
||||
if self.saver:
|
||||
self._saveAfter(self._save_delay)
|
||||
|
||||
def _saveAfter(self, delay):
|
||||
'''
|
||||
Trigger a cancel-able call to _saveFunc() after delay milliseconds.
|
||||
'''
|
||||
self._save = self.after(delay, self._saveFunc)
|
||||
def _saveAfter(self, delay):
|
||||
'''
|
||||
Trigger a cancel-able call to _saveFunc() after delay milliseconds.
|
||||
'''
|
||||
self._save = self.after(delay, self._saveFunc)
|
||||
|
||||
def _saveFunc(self):
|
||||
self._save = None
|
||||
self.saver(self._get_contents())
|
||||
def _saveFunc(self):
|
||||
self._save = None
|
||||
self.saver(self._get_contents())
|
||||
|
||||
def _saver(self, text):
|
||||
if not self.filename:
|
||||
return
|
||||
with open(self.filename, 'wb') as f:
|
||||
os.chmod(self.filename, 0o600)
|
||||
f.write(text.encode('UTF_8'))
|
||||
f.flush()
|
||||
os.fsync(f.fileno())
|
||||
if hasattr(self, 'repo'):
|
||||
self.repo.stage([self.repo_relative_filename])
|
||||
self.world.save()
|
||||
def _saver(self, text):
|
||||
if not self.filename:
|
||||
return
|
||||
with open(self.filename, 'wb') as f:
|
||||
os.chmod(self.filename, 0o600)
|
||||
f.write(text.encode('UTF_8'))
|
||||
f.flush()
|
||||
os.fsync(f.fileno())
|
||||
if hasattr(self, 'repo'):
|
||||
self.repo.stage([self.repo_relative_filename])
|
||||
self.world.save()
|
||||
|
||||
def _cancelSave(self):
|
||||
if self._save is not None:
|
||||
self.after_cancel(self._save)
|
||||
self._save = None
|
||||
def _cancelSave(self):
|
||||
if self._save is not None:
|
||||
self.after_cancel(self._save)
|
||||
self._save = None
|
||||
|
||||
def _get_contents(self):
|
||||
self['state'] = 'disabled'
|
||||
try:
|
||||
return self.get('0.0', 'end')[:-1]
|
||||
finally:
|
||||
self['state'] = 'normal'
|
||||
def _get_contents(self):
|
||||
self['state'] = 'disabled'
|
||||
try:
|
||||
return self.get('0.0', 'end')[:-1]
|
||||
finally:
|
||||
self['state'] = 'normal'
|
||||
|
||||
def _beenModified(self, event):
|
||||
if self._resetting_modified_flag:
|
||||
return
|
||||
self._clearModifiedFlag()
|
||||
self.save()
|
||||
def _beenModified(self, event):
|
||||
if self._resetting_modified_flag:
|
||||
return
|
||||
self._clearModifiedFlag()
|
||||
self.save()
|
||||
|
||||
def _clearModifiedFlag(self):
|
||||
self._resetting_modified_flag = True
|
||||
try:
|
||||
self.tk.call(self._w, 'edit', 'modified', 0)
|
||||
finally:
|
||||
self._resetting_modified_flag = False
|
||||
def _clearModifiedFlag(self):
|
||||
self._resetting_modified_flag = True
|
||||
try:
|
||||
self.tk.call(self._w, 'edit', 'modified', 0)
|
||||
finally:
|
||||
self._resetting_modified_flag = False
|
||||
|
||||
## tags = self._saveTags()
|
||||
## chunks = self.DUMP()
|
||||
@@ -163,309 +163,309 @@ class SavingMixin(object):
|
||||
|
||||
|
||||
class TextViewerWidget(tk.Text, MouseBindingsMixin, SavingMixin):
|
||||
"""
|
||||
This class is a Tkinter Text with special mousebindings to make
|
||||
it act as a Xerblin Text Viewer.
|
||||
"""
|
||||
"""
|
||||
This class is a Tkinter Text with special mousebindings to make
|
||||
it act as a Xerblin Text Viewer.
|
||||
"""
|
||||
|
||||
#This is a regular expression for finding commands in the text.
|
||||
command_re = regular_expression(r'[-a-zA-Z0-9_\\~/.:!@#$%&*?=+<>]+')
|
||||
#This is a regular expression for finding commands in the text.
|
||||
command_re = regular_expression(r'[-a-zA-Z0-9_\\~/.:!@#$%&*?=+<>]+')
|
||||
|
||||
#These are the config tags for command text when it's highlighted.
|
||||
command_tags = dict(
|
||||
#underline = 1,
|
||||
#bgstipple = "gray50",
|
||||
borderwidth = 2,
|
||||
relief=tk.RIDGE,
|
||||
foreground = "green"
|
||||
)
|
||||
#These are the config tags for command text when it's highlighted.
|
||||
command_tags = dict(
|
||||
#underline = 1,
|
||||
#bgstipple = "gray50",
|
||||
borderwidth = 2,
|
||||
relief=tk.RIDGE,
|
||||
foreground = "green"
|
||||
)
|
||||
|
||||
def __init__(self, world, master=None, **kw):
|
||||
def __init__(self, world, master=None, **kw):
|
||||
|
||||
self.world = world
|
||||
if self.world.text_widget is None:
|
||||
self.world.text_widget = self
|
||||
self.world = world
|
||||
if self.world.text_widget is None:
|
||||
self.world.text_widget = self
|
||||
|
||||
#Turn on undo, but don't override a passed-in setting.
|
||||
kw.setdefault('undo', True)
|
||||
#Turn on undo, but don't override a passed-in setting.
|
||||
kw.setdefault('undo', True)
|
||||
|
||||
# kw.setdefault('bg', 'white')
|
||||
kw.setdefault('wrap', 'word')
|
||||
kw.setdefault('font', 'arial 12')
|
||||
kw.setdefault('wrap', 'word')
|
||||
kw.setdefault('font', 'arial 12')
|
||||
|
||||
text_bindings = kw.pop('text_bindings', TEXT_BINDINGS)
|
||||
text_bindings = kw.pop('text_bindings', TEXT_BINDINGS)
|
||||
|
||||
#Create ourselves as a Tkinter Text
|
||||
tk.Text.__init__(self, master, **kw)
|
||||
#Create ourselves as a Tkinter Text
|
||||
tk.Text.__init__(self, master, **kw)
|
||||
|
||||
#Initialize our mouse mixin.
|
||||
MouseBindingsMixin.__init__(self)
|
||||
#Initialize our mouse mixin.
|
||||
MouseBindingsMixin.__init__(self)
|
||||
|
||||
#Initialize our saver mixin.
|
||||
SavingMixin.__init__(self)
|
||||
#Initialize our saver mixin.
|
||||
SavingMixin.__init__(self)
|
||||
|
||||
#Add tag config for command highlighting.
|
||||
self.tag_config('command', **self.command_tags)
|
||||
self.tag_config('bzzt', foreground = "orange")
|
||||
self.tag_config('huh', foreground = "grey")
|
||||
self.tag_config('number', foreground = "blue")
|
||||
#Add tag config for command highlighting.
|
||||
self.tag_config('command', **self.command_tags)
|
||||
self.tag_config('bzzt', foreground = "orange")
|
||||
self.tag_config('huh', foreground = "grey")
|
||||
self.tag_config('number', foreground = "blue")
|
||||
|
||||
#Create us a command instance variable
|
||||
self.command = ''
|
||||
#Create us a command instance variable
|
||||
self.command = ''
|
||||
|
||||
#Activate event bindings. Modify text_bindings in your config
|
||||
#file to affect the key bindings and whatnot here.
|
||||
for event_sequence, callback_finder in text_bindings.items():
|
||||
callback = callback_finder(self)
|
||||
self.bind(event_sequence, callback)
|
||||
#Activate event bindings. Modify text_bindings in your config
|
||||
#file to affect the key bindings and whatnot here.
|
||||
for event_sequence, callback_finder in text_bindings.items():
|
||||
callback = callback_finder(self)
|
||||
self.bind(event_sequence, callback)
|
||||
|
||||
## T.protocol("WM_DELETE_WINDOW", self.on_close)
|
||||
|
||||
def find_command_in_line(self, line, index):
|
||||
'''
|
||||
Return the command at index in line and its begin and end indices.
|
||||
find_command_in_line(line, index) => command, begin, end
|
||||
'''
|
||||
for match in self.command_re.finditer(line):
|
||||
b, e = match.span()
|
||||
if b <= index <= e:
|
||||
return match.group(), b, e
|
||||
def find_command_in_line(self, line, index):
|
||||
'''
|
||||
Return the command at index in line and its begin and end indices.
|
||||
find_command_in_line(line, index) => command, begin, end
|
||||
'''
|
||||
for match in self.command_re.finditer(line):
|
||||
b, e = match.span()
|
||||
if b <= index <= e:
|
||||
return match.group(), b, e
|
||||
|
||||
def paste_X_selection_to_mouse_pointer(self, event):
|
||||
'''Paste the X selection to the mouse pointer.'''
|
||||
try:
|
||||
text = self.selection_get()
|
||||
except tk.TclError:
|
||||
return 'break'
|
||||
self.insert_it(text)
|
||||
def paste_X_selection_to_mouse_pointer(self, event):
|
||||
'''Paste the X selection to the mouse pointer.'''
|
||||
try:
|
||||
text = self.selection_get()
|
||||
except tk.TclError:
|
||||
return 'break'
|
||||
self.insert_it(text)
|
||||
|
||||
def update_command_word(self, event):
|
||||
'''Highlight the command under the mouse.'''
|
||||
self.unhighlight_command()
|
||||
self.command = ''
|
||||
index = '@%d,%d' % (event.x, event.y)
|
||||
linestart = self.index(index + 'linestart')
|
||||
lineend = self.index(index + 'lineend')
|
||||
line = self.get(linestart, lineend)
|
||||
row, offset = self._get_index(index)
|
||||
def update_command_word(self, event):
|
||||
'''Highlight the command under the mouse.'''
|
||||
self.unhighlight_command()
|
||||
self.command = ''
|
||||
index = '@%d,%d' % (event.x, event.y)
|
||||
linestart = self.index(index + 'linestart')
|
||||
lineend = self.index(index + 'lineend')
|
||||
line = self.get(linestart, lineend)
|
||||
row, offset = self._get_index(index)
|
||||
|
||||
if offset >= len(line) or line[offset].isspace():
|
||||
# The mouse is off the end of the line or on a space so there's no
|
||||
# command, we're done.
|
||||
return
|
||||
if offset >= len(line) or line[offset].isspace():
|
||||
# The mouse is off the end of the line or on a space so there's no
|
||||
# command, we're done.
|
||||
return
|
||||
|
||||
cmd = self.find_command_in_line(line, offset)
|
||||
if cmd is None:
|
||||
return
|
||||
cmd = self.find_command_in_line(line, offset)
|
||||
if cmd is None:
|
||||
return
|
||||
|
||||
cmd, b, e = cmd
|
||||
if is_numerical(cmd):
|
||||
extra_tags = 'number',
|
||||
elif self.world.has(cmd):
|
||||
check = self.world.check(cmd)
|
||||
if check: extra_tags = ()
|
||||
elif check is None: extra_tags = 'huh',
|
||||
else: extra_tags = 'bzzt',
|
||||
else:
|
||||
return
|
||||
self.command = cmd
|
||||
self.highlight_command(
|
||||
'%d.%d' % (row, b),
|
||||
'%d.%d' % (row, e),
|
||||
*extra_tags)
|
||||
cmd, b, e = cmd
|
||||
if is_numerical(cmd):
|
||||
extra_tags = 'number',
|
||||
elif self.world.has(cmd):
|
||||
check = self.world.check(cmd)
|
||||
if check: extra_tags = ()
|
||||
elif check is None: extra_tags = 'huh',
|
||||
else: extra_tags = 'bzzt',
|
||||
else:
|
||||
return
|
||||
self.command = cmd
|
||||
self.highlight_command(
|
||||
'%d.%d' % (row, b),
|
||||
'%d.%d' % (row, e),
|
||||
*extra_tags)
|
||||
|
||||
def highlight_command(self, from_, to, *extra_tags):
|
||||
'''Apply command style from from_ to to.'''
|
||||
cmdstart = self.index(from_)
|
||||
cmdend = self.index(to)
|
||||
self.tag_add('command', cmdstart, cmdend)
|
||||
for tag in extra_tags:
|
||||
self.tag_add(tag, cmdstart, cmdend)
|
||||
def highlight_command(self, from_, to, *extra_tags):
|
||||
'''Apply command style from from_ to to.'''
|
||||
cmdstart = self.index(from_)
|
||||
cmdend = self.index(to)
|
||||
self.tag_add('command', cmdstart, cmdend)
|
||||
for tag in extra_tags:
|
||||
self.tag_add(tag, cmdstart, cmdend)
|
||||
|
||||
def do_command(self, event):
|
||||
'''Do the currently highlighted command.'''
|
||||
self.unhighlight_command()
|
||||
if self.command:
|
||||
self.run_command(self.command)
|
||||
def do_command(self, event):
|
||||
'''Do the currently highlighted command.'''
|
||||
self.unhighlight_command()
|
||||
if self.command:
|
||||
self.run_command(self.command)
|
||||
|
||||
def _control_enter(self, event):
|
||||
select_indices = self.tag_ranges(tk.SEL)
|
||||
if select_indices:
|
||||
command = self.get(select_indices[0], select_indices[1])
|
||||
else:
|
||||
linestart = self.index(tk.INSERT + ' linestart')
|
||||
lineend = self.index(tk.INSERT + ' lineend')
|
||||
command = self.get(linestart, lineend)
|
||||
if command and not command.isspace():
|
||||
self.run_command(command)
|
||||
return 'break'
|
||||
def _control_enter(self, event):
|
||||
select_indices = self.tag_ranges(tk.SEL)
|
||||
if select_indices:
|
||||
command = self.get(select_indices[0], select_indices[1])
|
||||
else:
|
||||
linestart = self.index(tk.INSERT + ' linestart')
|
||||
lineend = self.index(tk.INSERT + ' lineend')
|
||||
command = self.get(linestart, lineend)
|
||||
if command and not command.isspace():
|
||||
self.run_command(command)
|
||||
return 'break'
|
||||
|
||||
def run_command(self, command):
|
||||
'''Given a string run it on the stack, report errors.'''
|
||||
try:
|
||||
self.world.interpret(command)
|
||||
except SystemExit:
|
||||
raise
|
||||
except:
|
||||
self.popupTB(format_exc().rstrip())
|
||||
def run_command(self, command):
|
||||
'''Given a string run it on the stack, report errors.'''
|
||||
try:
|
||||
self.world.interpret(command)
|
||||
except SystemExit:
|
||||
raise
|
||||
except:
|
||||
self.popupTB(format_exc().rstrip())
|
||||
|
||||
def unhighlight_command(self):
|
||||
'''Remove any command highlighting.'''
|
||||
self.tag_remove('number', 1.0, tk.END)
|
||||
self.tag_remove('huh', 1.0, tk.END)
|
||||
self.tag_remove('bzzt', 1.0, tk.END)
|
||||
self.tag_remove('command', 1.0, tk.END)
|
||||
def unhighlight_command(self):
|
||||
'''Remove any command highlighting.'''
|
||||
self.tag_remove('number', 1.0, tk.END)
|
||||
self.tag_remove('huh', 1.0, tk.END)
|
||||
self.tag_remove('bzzt', 1.0, tk.END)
|
||||
self.tag_remove('command', 1.0, tk.END)
|
||||
|
||||
def set_insertion_point(self, event):
|
||||
'''Set the insertion cursor to the current mouse location.'''
|
||||
self.focus()
|
||||
self.mark_set(tk.INSERT, '@%d,%d' % (event.x, event.y))
|
||||
def set_insertion_point(self, event):
|
||||
'''Set the insertion cursor to the current mouse location.'''
|
||||
self.focus()
|
||||
self.mark_set(tk.INSERT, '@%d,%d' % (event.x, event.y))
|
||||
|
||||
def copy_selection_to_stack(self, event):
|
||||
'''Copy selection to stack.'''
|
||||
select_indices = self.tag_ranges(tk.SEL)
|
||||
if select_indices:
|
||||
s = self.get(select_indices[0], select_indices[1])
|
||||
self.world.push(s)
|
||||
def copy_selection_to_stack(self, event):
|
||||
'''Copy selection to stack.'''
|
||||
select_indices = self.tag_ranges(tk.SEL)
|
||||
if select_indices:
|
||||
s = self.get(select_indices[0], select_indices[1])
|
||||
self.world.push(s)
|
||||
|
||||
def cut(self, event):
|
||||
'''Cut selection to stack.'''
|
||||
self.copy_selection_to_stack(event)
|
||||
# Let the pre-existing machinery take care of cutting the selection.
|
||||
self.event_generate("<<Cut>>")
|
||||
def cut(self, event):
|
||||
'''Cut selection to stack.'''
|
||||
self.copy_selection_to_stack(event)
|
||||
# Let the pre-existing machinery take care of cutting the selection.
|
||||
self.event_generate("<<Cut>>")
|
||||
|
||||
def copyto(self, event):
|
||||
'''Actually "paste" from TOS'''
|
||||
s = self.world.peek()
|
||||
if s is not None:
|
||||
self.insert_it(s)
|
||||
def copyto(self, event):
|
||||
'''Actually "paste" from TOS'''
|
||||
s = self.world.peek()
|
||||
if s is not None:
|
||||
self.insert_it(s)
|
||||
|
||||
def insert_it(self, s):
|
||||
if not isinstance(s, basestring):
|
||||
s = stack_to_string(s)
|
||||
def insert_it(self, s):
|
||||
if not isinstance(s, basestring):
|
||||
s = stack_to_string(s)
|
||||
|
||||
# When pasting from the mouse we have to remove the current selection
|
||||
# to prevent destroying it by the paste operation.
|
||||
select_indices = self.tag_ranges(tk.SEL)
|
||||
if select_indices:
|
||||
# Set two marks to remember the selection.
|
||||
self.mark_set('_sel_start', select_indices[0])
|
||||
self.mark_set('_sel_end', select_indices[1])
|
||||
self.tag_remove(tk.SEL, 1.0, tk.END)
|
||||
# When pasting from the mouse we have to remove the current selection
|
||||
# to prevent destroying it by the paste operation.
|
||||
select_indices = self.tag_ranges(tk.SEL)
|
||||
if select_indices:
|
||||
# Set two marks to remember the selection.
|
||||
self.mark_set('_sel_start', select_indices[0])
|
||||
self.mark_set('_sel_end', select_indices[1])
|
||||
self.tag_remove(tk.SEL, 1.0, tk.END)
|
||||
|
||||
self.insert(tk.INSERT, s)
|
||||
self.insert(tk.INSERT, s)
|
||||
|
||||
if select_indices:
|
||||
self.tag_add(tk.SEL, '_sel_start', '_sel_end')
|
||||
self.mark_unset('_sel_start')
|
||||
self.mark_unset('_sel_end')
|
||||
if select_indices:
|
||||
self.tag_add(tk.SEL, '_sel_start', '_sel_end')
|
||||
self.mark_unset('_sel_start')
|
||||
self.mark_unset('_sel_end')
|
||||
|
||||
def run_selection(self, event):
|
||||
'''Run the current selection if any on the stack.'''
|
||||
select_indices = self.tag_ranges(tk.SEL)
|
||||
if select_indices:
|
||||
selection = self.get(select_indices[0], select_indices[1])
|
||||
self.tag_remove(tk.SEL, 1.0, tk.END)
|
||||
self.run_command(selection)
|
||||
def run_selection(self, event):
|
||||
'''Run the current selection if any on the stack.'''
|
||||
select_indices = self.tag_ranges(tk.SEL)
|
||||
if select_indices:
|
||||
selection = self.get(select_indices[0], select_indices[1])
|
||||
self.tag_remove(tk.SEL, 1.0, tk.END)
|
||||
self.run_command(selection)
|
||||
|
||||
def pastecut(self, event):
|
||||
'''Cut the TOS item to the mouse.'''
|
||||
self.copyto(event)
|
||||
self.world.pop()
|
||||
def pastecut(self, event):
|
||||
'''Cut the TOS item to the mouse.'''
|
||||
self.copyto(event)
|
||||
self.world.pop()
|
||||
|
||||
def opendoc(self, event):
|
||||
'''OpenDoc the current command.'''
|
||||
if self.command:
|
||||
self.world.do_opendoc(self.command)
|
||||
def opendoc(self, event):
|
||||
'''OpenDoc the current command.'''
|
||||
if self.command:
|
||||
self.world.do_opendoc(self.command)
|
||||
|
||||
def lookup(self, event):
|
||||
'''Look up the current command.'''
|
||||
if self.command:
|
||||
self.world.do_lookup(self.command)
|
||||
def lookup(self, event):
|
||||
'''Look up the current command.'''
|
||||
if self.command:
|
||||
self.world.do_lookup(self.command)
|
||||
|
||||
def cancel(self, event):
|
||||
'''Cancel whatever we're doing.'''
|
||||
self.leave(None)
|
||||
self.tag_remove(tk.SEL, 1.0, tk.END)
|
||||
self._sel_anchor = '0.0'
|
||||
self.mark_unset(tk.INSERT)
|
||||
def cancel(self, event):
|
||||
'''Cancel whatever we're doing.'''
|
||||
self.leave(None)
|
||||
self.tag_remove(tk.SEL, 1.0, tk.END)
|
||||
self._sel_anchor = '0.0'
|
||||
self.mark_unset(tk.INSERT)
|
||||
|
||||
def leave(self, event):
|
||||
'''Called when mouse leaves the Text window.'''
|
||||
self.unhighlight_command()
|
||||
self.command = ''
|
||||
def leave(self, event):
|
||||
'''Called when mouse leaves the Text window.'''
|
||||
self.unhighlight_command()
|
||||
self.command = ''
|
||||
|
||||
def _get_index(self, index):
|
||||
'''Get the index in (int, int) form of index.'''
|
||||
return tuple(map(int, self.index(index).split('.')))
|
||||
def _get_index(self, index):
|
||||
'''Get the index in (int, int) form of index.'''
|
||||
return tuple(map(int, self.index(index).split('.')))
|
||||
|
||||
def _paste(self, event):
|
||||
'''Paste the system selection to the current selection, replacing it.'''
|
||||
def _paste(self, event):
|
||||
'''Paste the system selection to the current selection, replacing it.'''
|
||||
|
||||
# If we're "key" pasting, we have to move the insertion point
|
||||
# to the selection so the pasted text gets inserted at the
|
||||
# location of the deleted selection.
|
||||
# If we're "key" pasting, we have to move the insertion point
|
||||
# to the selection so the pasted text gets inserted at the
|
||||
# location of the deleted selection.
|
||||
|
||||
select_indices = self.tag_ranges(tk.SEL)
|
||||
if select_indices:
|
||||
# Mark the location of the current insertion cursor
|
||||
self.mark_set('tmark', tk.INSERT)
|
||||
# Put the insertion cursor at the selection
|
||||
self.mark_set(tk.INSERT, select_indices[1])
|
||||
select_indices = self.tag_ranges(tk.SEL)
|
||||
if select_indices:
|
||||
# Mark the location of the current insertion cursor
|
||||
self.mark_set('tmark', tk.INSERT)
|
||||
# Put the insertion cursor at the selection
|
||||
self.mark_set(tk.INSERT, select_indices[1])
|
||||
|
||||
# Paste to the current selection, or if none, to the insertion cursor.
|
||||
self.event_generate("<<Paste>>")
|
||||
# Paste to the current selection, or if none, to the insertion cursor.
|
||||
self.event_generate("<<Paste>>")
|
||||
|
||||
# If we mess with the insertion cursor above, fix it now.
|
||||
if select_indices:
|
||||
# Put the insertion cursor back where it was.
|
||||
self.mark_set(tk.INSERT, 'tmark')
|
||||
# And get rid of our unneeded mark.
|
||||
self.mark_unset('tmark')
|
||||
# If we mess with the insertion cursor above, fix it now.
|
||||
if select_indices:
|
||||
# Put the insertion cursor back where it was.
|
||||
self.mark_set(tk.INSERT, 'tmark')
|
||||
# And get rid of our unneeded mark.
|
||||
self.mark_unset('tmark')
|
||||
|
||||
return 'break'
|
||||
return 'break'
|
||||
|
||||
def init(self, title, filename, repo_relative_filename, repo, font):
|
||||
self.winfo_toplevel().title(title)
|
||||
if os.path.exists(filename):
|
||||
with open(filename) as f:
|
||||
data = f.read()
|
||||
self.insert(tk.END, data)
|
||||
# Prevent this from triggering a git commit.
|
||||
self.update()
|
||||
self._cancelSave()
|
||||
self.pack(expand=True, fill=tk.BOTH)
|
||||
self.filename = filename
|
||||
self.repo_relative_filename = repo_relative_filename
|
||||
self.repo = repo
|
||||
self['font'] = font # See below.
|
||||
def init(self, title, filename, repo_relative_filename, repo, font):
|
||||
self.winfo_toplevel().title(title)
|
||||
if os.path.exists(filename):
|
||||
with open(filename) as f:
|
||||
data = f.read()
|
||||
self.insert(tk.END, data)
|
||||
# Prevent this from triggering a git commit.
|
||||
self.update()
|
||||
self._cancelSave()
|
||||
self.pack(expand=True, fill=tk.BOTH)
|
||||
self.filename = filename
|
||||
self.repo_relative_filename = repo_relative_filename
|
||||
self.repo = repo
|
||||
self['font'] = font # See below.
|
||||
|
||||
def reset(self):
|
||||
if os.path.exists(self.filename):
|
||||
with open(self.filename) as f:
|
||||
data = f.read()
|
||||
if data:
|
||||
self.delete('0.0', tk.END)
|
||||
self.insert(tk.END, data)
|
||||
def reset(self):
|
||||
if os.path.exists(self.filename):
|
||||
with open(self.filename) as f:
|
||||
data = f.read()
|
||||
if data:
|
||||
self.delete('0.0', tk.END)
|
||||
self.insert(tk.END, data)
|
||||
|
||||
def popupTB(self, tb):
|
||||
top = tk.Toplevel()
|
||||
T = TextViewerWidget(
|
||||
self.world,
|
||||
top,
|
||||
width=max(len(s) for s in tb.splitlines()) + 3,
|
||||
)
|
||||
def popupTB(self, tb):
|
||||
top = tk.Toplevel()
|
||||
T = TextViewerWidget(
|
||||
self.world,
|
||||
top,
|
||||
width=max(len(s) for s in tb.splitlines()) + 3,
|
||||
)
|
||||
|
||||
T['background'] = 'darkgrey'
|
||||
T['foreground'] = 'darkblue'
|
||||
T.tag_config('err', foreground='yellow')
|
||||
T['background'] = 'darkgrey'
|
||||
T['foreground'] = 'darkblue'
|
||||
T.tag_config('err', foreground='yellow')
|
||||
|
||||
T.insert(tk.END, tb)
|
||||
last_line = str(int(T.index(tk.END).split('.')[0]) - 1) + '.0'
|
||||
T.tag_add('err', last_line, tk.END)
|
||||
T['state'] = tk.DISABLED
|
||||
T.insert(tk.END, tb)
|
||||
last_line = str(int(T.index(tk.END).split('.')[0]) - 1) + '.0'
|
||||
T.tag_add('err', last_line, tk.END)
|
||||
T['state'] = tk.DISABLED
|
||||
|
||||
top.title(T.get(last_line, tk.END).strip())
|
||||
top.title(T.get(last_line, tk.END).strip())
|
||||
|
||||
T.pack(expand=1, fill=tk.BOTH)
|
||||
T.see(tk.END)
|
||||
T.pack(expand=1, fill=tk.BOTH)
|
||||
T.see(tk.END)
|
||||
|
||||
+55
-55
@@ -13,85 +13,85 @@ DEFAULT_JOY_HOME = expanduser(join('~', '.joypy'))
|
||||
|
||||
|
||||
def is_numerical(s):
|
||||
try:
|
||||
float(s)
|
||||
except ValueError:
|
||||
return False
|
||||
return True
|
||||
try:
|
||||
float(s)
|
||||
except ValueError:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def home_dir(path):
|
||||
'''Return the absolute path of an existing directory.'''
|
||||
'''Return the absolute path of an existing directory.'''
|
||||
|
||||
fullpath = expanduser(path) if path.startswith('~') else abspath(path)
|
||||
fullpath = expanduser(path) if path.startswith('~') else abspath(path)
|
||||
|
||||
if not exists(fullpath):
|
||||
if path == DEFAULT_JOY_HOME:
|
||||
print('Creating JOY_HOME', repr(fullpath))
|
||||
mkdir(fullpath, 0o700)
|
||||
else:
|
||||
print(repr(fullpath), "doesn't exist.", file=sys.stderr)
|
||||
raise ValueError(path)
|
||||
if not exists(fullpath):
|
||||
if path == DEFAULT_JOY_HOME:
|
||||
print('Creating JOY_HOME', repr(fullpath))
|
||||
mkdir(fullpath, 0o700)
|
||||
else:
|
||||
print(repr(fullpath), "doesn't exist.", file=sys.stderr)
|
||||
raise ValueError(path)
|
||||
|
||||
return fullpath
|
||||
return fullpath
|
||||
|
||||
|
||||
def init_home(fullpath):
|
||||
'''
|
||||
Open or create the Repo.
|
||||
If there are contents in the dir but it's not a git repo, quit.
|
||||
'''
|
||||
try:
|
||||
repo = Repo(fullpath)
|
||||
except NotGitRepository:
|
||||
print(repr(fullpath), "no repository", file=sys.stderr)
|
||||
'''
|
||||
Open or create the Repo.
|
||||
If there are contents in the dir but it's not a git repo, quit.
|
||||
'''
|
||||
try:
|
||||
repo = Repo(fullpath)
|
||||
except NotGitRepository:
|
||||
print(repr(fullpath), "no repository", file=sys.stderr)
|
||||
|
||||
if listdir(fullpath):
|
||||
print(repr(fullpath), "has contents\nQUIT.", file=sys.stderr)
|
||||
sys.exit(2)
|
||||
if listdir(fullpath):
|
||||
print(repr(fullpath), "has contents\nQUIT.", file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
print('Initializing repository in', fullpath)
|
||||
repo = init_repo(fullpath)
|
||||
print('Initializing repository in', fullpath)
|
||||
repo = init_repo(fullpath)
|
||||
|
||||
print('Using repository in', fullpath)
|
||||
return repo
|
||||
print('Using repository in', fullpath)
|
||||
return repo
|
||||
|
||||
|
||||
def init_repo(repo_dir):
|
||||
'''
|
||||
Create a repo, load the initial content, and make the first commit.
|
||||
Return the Repo object.
|
||||
'''
|
||||
repo = Repo.init(repo_dir)
|
||||
import joy.gui.init_joy_home
|
||||
joy.gui.init_joy_home.initialize(repo_dir)
|
||||
repo.stage([fn for fn in listdir(repo_dir) if isfile(join(repo_dir, fn))])
|
||||
repo.do_commit('Initial commit.', committer=COMMITTER)
|
||||
return repo
|
||||
'''
|
||||
Create a repo, load the initial content, and make the first commit.
|
||||
Return the Repo object.
|
||||
'''
|
||||
repo = Repo.init(repo_dir)
|
||||
import joy.gui.init_joy_home
|
||||
joy.gui.init_joy_home.initialize(repo_dir)
|
||||
repo.stage([fn for fn in listdir(repo_dir) if isfile(join(repo_dir, fn))])
|
||||
repo.do_commit('Initial commit.', committer=COMMITTER)
|
||||
return repo
|
||||
|
||||
|
||||
argparser = argparse.ArgumentParser(
|
||||
description='Experimental Brutalist UI for Joy.',
|
||||
)
|
||||
description='Experimental Brutalist UI for Joy.',
|
||||
)
|
||||
|
||||
|
||||
argparser.add_argument(
|
||||
'-j', '--joy-home',
|
||||
help='Use a directory other than %s as JOY_HOME' % DEFAULT_JOY_HOME,
|
||||
default=DEFAULT_JOY_HOME,
|
||||
dest='joy_home',
|
||||
type=home_dir,
|
||||
)
|
||||
'-j', '--joy-home',
|
||||
help='Use a directory other than %s as JOY_HOME' % DEFAULT_JOY_HOME,
|
||||
default=DEFAULT_JOY_HOME,
|
||||
dest='joy_home',
|
||||
type=home_dir,
|
||||
)
|
||||
|
||||
|
||||
class FileFaker(object):
|
||||
|
||||
def __init__(self, T):
|
||||
self.T = T
|
||||
def __init__(self, T):
|
||||
self.T = T
|
||||
|
||||
def write(self, text):
|
||||
self.T.insert('end', text)
|
||||
self.T.see('end')
|
||||
def write(self, text):
|
||||
self.T.insert('end', text)
|
||||
self.T.see('end')
|
||||
|
||||
def flush(self):
|
||||
pass
|
||||
def flush(self):
|
||||
pass
|
||||
|
||||
+97
-97
@@ -35,118 +35,118 @@ from .utils import is_numerical
|
||||
|
||||
class World(object):
|
||||
|
||||
def __init__(self, stack=(), dictionary=None, text_widget=None):
|
||||
self.stack = stack
|
||||
self.dictionary = dictionary or {}
|
||||
self.text_widget = text_widget
|
||||
self.check_cache = {}
|
||||
def __init__(self, stack=(), dictionary=None, text_widget=None):
|
||||
self.stack = stack
|
||||
self.dictionary = dictionary or {}
|
||||
self.text_widget = text_widget
|
||||
self.check_cache = {}
|
||||
|
||||
def check(self, name):
|
||||
try:
|
||||
res = self.check_cache[name]
|
||||
except KeyError:
|
||||
res = self.check_cache[name] = type_check(name, self.stack)
|
||||
return res
|
||||
def check(self, name):
|
||||
try:
|
||||
res = self.check_cache[name]
|
||||
except KeyError:
|
||||
res = self.check_cache[name] = type_check(name, self.stack)
|
||||
return res
|
||||
|
||||
def do_lookup(self, name):
|
||||
if name in self.dictionary:
|
||||
self.stack = (Symbol(name), ()), self.stack
|
||||
self.print_stack()
|
||||
self.check_cache.clear()
|
||||
else:
|
||||
assert is_numerical(name)
|
||||
self.interpret(name)
|
||||
def do_lookup(self, name):
|
||||
if name in self.dictionary:
|
||||
self.stack = (Symbol(name), ()), self.stack
|
||||
self.print_stack()
|
||||
self.check_cache.clear()
|
||||
else:
|
||||
assert is_numerical(name)
|
||||
self.interpret(name)
|
||||
|
||||
def do_opendoc(self, name):
|
||||
if is_numerical(name):
|
||||
print('The number', name)
|
||||
else:
|
||||
try:
|
||||
word = self.dictionary[name]
|
||||
except KeyError:
|
||||
print(repr(name), '???')
|
||||
else:
|
||||
print(getdoc(word))
|
||||
self.print_stack()
|
||||
def do_opendoc(self, name):
|
||||
if is_numerical(name):
|
||||
print('The number', name)
|
||||
else:
|
||||
try:
|
||||
word = self.dictionary[name]
|
||||
except KeyError:
|
||||
print(repr(name), '???')
|
||||
else:
|
||||
print(getdoc(word))
|
||||
self.print_stack()
|
||||
|
||||
def pop(self):
|
||||
if self.stack:
|
||||
self.stack = self.stack[1]
|
||||
self.print_stack()
|
||||
self.check_cache.clear()
|
||||
def pop(self):
|
||||
if self.stack:
|
||||
self.stack = self.stack[1]
|
||||
self.print_stack()
|
||||
self.check_cache.clear()
|
||||
|
||||
def push(self, it):
|
||||
it = it.encode('utf8')
|
||||
self.stack = it, self.stack
|
||||
self.print_stack()
|
||||
self.check_cache.clear()
|
||||
def push(self, it):
|
||||
it = it.encode('utf8')
|
||||
self.stack = it, self.stack
|
||||
self.print_stack()
|
||||
self.check_cache.clear()
|
||||
|
||||
def peek(self):
|
||||
if self.stack:
|
||||
return self.stack[0]
|
||||
def peek(self):
|
||||
if self.stack:
|
||||
return self.stack[0]
|
||||
|
||||
def interpret(self, command):
|
||||
if self.has(command) and self.check(command) == False: # not in {True, None}:
|
||||
return
|
||||
old_stack = self.stack
|
||||
try:
|
||||
self.stack, _, self.dictionary = run(
|
||||
command,
|
||||
self.stack,
|
||||
self.dictionary,
|
||||
)
|
||||
finally:
|
||||
self.print_stack()
|
||||
if old_stack != self.stack:
|
||||
self.check_cache.clear()
|
||||
def interpret(self, command):
|
||||
if self.has(command) and self.check(command) == False: # not in {True, None}:
|
||||
return
|
||||
old_stack = self.stack
|
||||
try:
|
||||
self.stack, _, self.dictionary = run(
|
||||
command,
|
||||
self.stack,
|
||||
self.dictionary,
|
||||
)
|
||||
finally:
|
||||
self.print_stack()
|
||||
if old_stack != self.stack:
|
||||
self.check_cache.clear()
|
||||
|
||||
def has(self, name):
|
||||
return name in self.dictionary
|
||||
def has(self, name):
|
||||
return name in self.dictionary
|
||||
|
||||
def save(self):
|
||||
pass
|
||||
def save(self):
|
||||
pass
|
||||
|
||||
def print_stack(self):
|
||||
stack_out_index = self.text_widget.search('<' 'STACK', 1.0)
|
||||
if stack_out_index:
|
||||
self.text_widget.see(stack_out_index)
|
||||
s = stack_to_string(self.stack) + '\n'
|
||||
self.text_widget.insert(stack_out_index, s)
|
||||
def print_stack(self):
|
||||
stack_out_index = self.text_widget.search('<' 'STACK', 1.0)
|
||||
if stack_out_index:
|
||||
self.text_widget.see(stack_out_index)
|
||||
s = stack_to_string(self.stack) + '\n'
|
||||
self.text_widget.insert(stack_out_index, s)
|
||||
|
||||
|
||||
class StackDisplayWorld(World):
|
||||
|
||||
def __init__(self, repo, filename, rel_filename, dictionary=None, text_widget=None):
|
||||
self.filename = filename
|
||||
stack = self.load_stack() or ()
|
||||
World.__init__(self, stack, dictionary, text_widget)
|
||||
self.repo = repo
|
||||
self.relative_STACK_FN = rel_filename
|
||||
def __init__(self, repo, filename, rel_filename, dictionary=None, text_widget=None):
|
||||
self.filename = filename
|
||||
stack = self.load_stack() or ()
|
||||
World.__init__(self, stack, dictionary, text_widget)
|
||||
self.repo = repo
|
||||
self.relative_STACK_FN = rel_filename
|
||||
|
||||
def interpret(self, command):
|
||||
command = command.strip()
|
||||
if self.has(command) and self.check(command) == False: # not in {True, None}:
|
||||
return
|
||||
print('\njoy?', command)
|
||||
super(StackDisplayWorld, self).interpret(command)
|
||||
def interpret(self, command):
|
||||
command = command.strip()
|
||||
if self.has(command) and self.check(command) == False: # not in {True, None}:
|
||||
return
|
||||
print('\njoy?', command)
|
||||
super(StackDisplayWorld, self).interpret(command)
|
||||
|
||||
def print_stack(self):
|
||||
print('\n%s <-' % stack_to_string(self.stack))
|
||||
def print_stack(self):
|
||||
print('\n%s <-' % stack_to_string(self.stack))
|
||||
|
||||
def save(self):
|
||||
with open(self.filename, 'wb') as f:
|
||||
os.chmod(self.filename, 0o600)
|
||||
pickle.dump(self.stack, f, protocol=2)
|
||||
f.flush()
|
||||
os.fsync(f.fileno())
|
||||
self.repo.stage([self.relative_STACK_FN])
|
||||
commit_id = self.repo.do_commit(
|
||||
b'auto-save',
|
||||
committer=b'thun-auto-save <[email protected]>',
|
||||
)
|
||||
_log.info('commit %s', commit_id)
|
||||
def save(self):
|
||||
with open(self.filename, 'wb') as f:
|
||||
os.chmod(self.filename, 0o600)
|
||||
pickle.dump(self.stack, f, protocol=2)
|
||||
f.flush()
|
||||
os.fsync(f.fileno())
|
||||
self.repo.stage([self.relative_STACK_FN])
|
||||
commit_id = self.repo.do_commit(
|
||||
b'auto-save',
|
||||
committer=b'thun-auto-save <[email protected]>',
|
||||
)
|
||||
_log.info('commit %s', commit_id)
|
||||
|
||||
def load_stack(self):
|
||||
if os.path.exists(self.filename):
|
||||
with open(self.filename, 'rb') as f:
|
||||
return pickle.load(f)
|
||||
def load_stack(self):
|
||||
if os.path.exists(self.filename):
|
||||
with open(self.filename, 'rb') as f:
|
||||
return pickle.load(f)
|
||||
|
||||
Reference in New Issue
Block a user