2 # -*- coding: utf-8 -*-
4 Joypy - Copyright © 2018 Simon Forman
6 'This program comes with ABSOLUTELY NO WARRANTY; for details right-click "warranty".'
7 ' This is free software, and you are welcome to redistribute it under certain conditions;'
8 ' right-click "sharing" for details.'
9 ' Right-click on these commands to see docs on UI commands: key_bindings mouse_bindings')
10 import os, pickle, sys
11 from textwrap import dedent
13 from joy.gui.textwidget import TextViewerWidget, tk, get_font, TEXT_BINDINGS
14 from joy.gui.utils import init_home, FileFaker
15 from joy.gui.world import StackDisplayWorld
16 from joy.library import initialize
17 from joy.utils.stack import stack_to_string
20 tb = TEXT_BINDINGS.copy()
22 '<F3>': lambda tv: tv.copy_selection_to_stack,
23 '<F4>': lambda tv: tv.cut,
24 # '<F-->': lambda tv: tv.pastecut,
25 # '<F6>': lambda tv: tv.copyto,
27 defaults = dict(text_bindings=tb, width=80, height=25)
34 '<Shift-F5>': 'roll<',
35 '<Shift-F6>': 'roll>',
40 '<Shift-F3>': 'parse',
43 '<F1>': 'reset_log show_log',
44 '<Escape>': 'clear reset_log show_log',
45 '<Control-Delete>': 'pop',
46 '<Control-Shift-Delete>': 'popd',
50 def repo_relative_path(path):
51 return os.path.relpath(
53 os.path.commonprefix((repo.controldir(), path))
57 def key_bindings(*args):
59 Ctrl-Enter - Run the selection as Joy code.
61 F1 - Reset and show (if hidden) the log.
62 Esc - Like F1 but also clears the stack.
64 F12 - print a list of all command words, or right-click "words".
69 def mouse_bindings(*args):
71 Mouse button chords (to cancel a chord, click the third mouse button.)
73 Left - Point, sweep selection
74 Left-Middle - Copy the selection, place text on stack
75 Left-Right - Run the selection as Joy code
77 Middle - Paste selection (bypass stack); click and drag to scroll.
78 Middle-Left - Paste from top of stack, preserve
79 Middle-Right - Paste from top of stack, pop
81 Right - Execute command word under mouse cursor
82 Right-Left - Print docs of command word under mouse cursor
83 Right-Middle - Lookup word (kinda useless now)
89 log.delete('0.0', tk.END)
95 log_window.wm_deiconify()
100 def grand_reset(s, e, d):
101 stack = world.load_stack() or ()
107 JOY_HOME, repo = init_home()
108 STACK_FN = os.path.join(JOY_HOME, 'stack.pickle')
109 REL_STACK_FN = repo_relative_path(STACK_FN)
110 JOY_FN = os.path.join(JOY_HOME, 'scratch.txt')
111 LOG_FN = os.path.join(JOY_HOME, 'log.txt')
120 D[func.__name__] = func
121 world = StackDisplayWorld(repo, STACK_FN, REL_STACK_FN, dictionary=D)
122 t = TextViewerWidget(world, **defaults)
123 log_window = tk.Toplevel()
124 log_window.protocol("WM_DELETE_WINDOW", log_window.withdraw)
125 log = TextViewerWidget(world, log_window, **defaults)
126 FONT = get_font('Iosevka', size=14) # Requires Tk root already set up.
127 log.init('Log', LOG_FN, repo_relative_path(LOG_FN), repo, FONT)
128 t.init('Joy - ' + JOY_HOME, JOY_FN, repo_relative_path(JOY_FN), repo, FONT)
129 for event, command in GLOBAL_COMMANDS.items():
130 t.bind_all(event, lambda _, _command=command: world.interpret(_command))
134 sys.stdout, old_stdout = FileFaker(log), sys.stdout
138 sys.stdout = old_stdout
142 if __name__ == '__main__':