Skip to content

Commit d85018c

Browse files
authored
Add interrupt handler (#102)
Add an interrupt handler and SIGUSR1 handler. (On MS Windows, SIGURS1 doesn't exist) This includes interrupt completion for prompt_toolkit and GNU Readline. Also, the `Abort[]` response: $Aborted, is now showing.
1 parent 13c84f8 commit d85018c

File tree

7 files changed

+389
-61
lines changed

7 files changed

+389
-61
lines changed

mathicsscript/__main__.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,12 @@
2424
from pygments import highlight
2525

2626
from mathicsscript.asymptote import asymptote_version
27+
from mathicsscript.interrupt import setup_signal_handler
2728
from mathicsscript.settings import definitions
2829
from mathicsscript.termshell import ShellEscapeException, mma_lexer
2930
from mathicsscript.termshell_gnu import TerminalShellGNUReadline
30-
from mathicsscript.termshell_prompt import (
31-
TerminalShellCommon,
32-
TerminalShellPromptToolKit,
33-
)
31+
from mathicsscript.termshell import TerminalShellCommon
32+
from mathicsscript.termshell_prompt import TerminalShellPromptToolKit
3433
from mathicsscript.version import __version__
3534

3635
try:
@@ -123,7 +122,7 @@ def load_settings(shell):
123122
continue
124123
evaluation.evaluate(query)
125124
except KeyboardInterrupt:
126-
print("\nKeyboardInterrupt")
125+
shell.errmsg("\nKeyboardInterrupt")
127126
return True
128127

129128

@@ -145,16 +144,17 @@ def interactive_eval_loop(
145144
shell: TerminalShellCommon,
146145
unicode,
147146
prompt,
148-
matplotlib: bool,
149-
asymptote: bool,
150147
strict_wl_output: bool,
151148
):
149+
setup_signal_handler()
150+
152151
def identity(x: Any) -> Any:
153152
return x
154153

155154
def fmt_fun(query: Any) -> Any:
156155
return highlight(str(query), mma_lexer, shell.terminal_formatter)
157156

157+
shell.fmt_fn = fmt_fun
158158
while True:
159159
try:
160160
if have_readline and shell.using_readline:
@@ -173,6 +173,11 @@ def fmt_fun(query: Any) -> Any:
173173
fmt = fmt_fun
174174

175175
evaluation = Evaluation(shell.definitions, output=TerminalOutput(shell))
176+
177+
# Store shell into the evaluation so that an interrupt handler
178+
# has access to this
179+
evaluation.shell = shell
180+
176181
query, source_code = evaluation.parse_feeder_returning_code(shell)
177182
if mathics_core.PRE_EVALUATION_HOOK is not None:
178183
mathics_core.PRE_EVALUATION_HOOK(query, evaluation)
@@ -214,7 +219,7 @@ def fmt_fun(query: Any) -> Any:
214219
try:
215220
print(open(source_code[2:], "r").read())
216221
except Exception:
217-
print(str(sys.exc_info()[1]))
222+
shell.errmsg(str(sys.exc_info()[1]))
218223
else:
219224
subprocess.run(source_code[1:], shell=True)
220225

@@ -224,13 +229,13 @@ def fmt_fun(query: Any) -> Any:
224229
# shell.definitions.increment_line(1)
225230

226231
except KeyboardInterrupt:
227-
print("\nKeyboardInterrupt")
232+
shell.errmsg("\nKeyboardInterrupt")
228233
except EOFError:
229234
if prompt:
230-
print("\n\nGoodbye!\n")
235+
shell.errmsg("\n\nGoodbye!\n")
231236
break
232237
except SystemExit:
233-
print("\n\nGoodbye!\n")
238+
shell.errmsg("\n\nGoodbye!\n")
234239
# raise to pass the error code on, e.g. Quit[1]
235240
raise
236241
finally:
@@ -526,9 +531,7 @@ def main(
526531
)
527532

528533
definitions.set_line_no(0)
529-
interactive_eval_loop(
530-
shell, charset, prompt, asymptote, matplotlib, strict_wl_output
531-
)
534+
interactive_eval_loop(shell, charset, prompt, strict_wl_output)
532535
return exit_rc
533536

534537

mathicsscript/completion.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@
2323
from mathics.core.symbols import strip_context
2424
from mathics_scanner import named_characters
2525
from mathics_pygments.lexer import Regex
26-
from prompt_toolkit.completion import CompleteEvent, Completion, WordCompleter
26+
from prompt_toolkit.completion import (
27+
CompleteEvent,
28+
Completer,
29+
Completion,
30+
WordCompleter,
31+
)
2732
from prompt_toolkit.document import Document
2833

2934
SYMBOLS = rf"[`]?({Regex.IDENTIFIER}|{Regex.NAMED_CHARACTER})(`({Regex.IDENTIFIER}|{Regex.NAMED_CHARACTER}))+[`]?"
@@ -54,6 +59,28 @@ def get_datadir():
5459
return osp.realpath(datadir)
5560

5661

62+
class InterruptCompleter(Completer):
63+
"""
64+
Completer for the simple command set: 'continue', 'abort', 'exit', 'show'.
65+
"""
66+
67+
COMMANDS = [
68+
"abort",
69+
"continue",
70+
"exit",
71+
"inspect",
72+
"show",
73+
]
74+
75+
def get_completions(
76+
self, document: Document, complete_event
77+
) -> Iterable[Completion]:
78+
word = document.get_word_before_cursor()
79+
for cmd in self.COMMANDS:
80+
if cmd.startswith(word):
81+
yield Completion(cmd, -len(word))
82+
83+
5784
class MathicsCompleter(WordCompleter):
5885
def __init__(self, definitions):
5986
self.definitions = definitions

mathicsscript/format.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from mathics.core.atoms import String
1212
from mathics.core.symbols import Symbol
1313
from mathics.core.systemsymbols import (
14+
SymbolAborted,
1415
SymbolExport,
1516
SymbolExportString,
1617
SymbolFullForm,
@@ -21,6 +22,7 @@
2122
SymbolOutputForm,
2223
SymbolPlot,
2324
SymbolStandardForm,
25+
SymbolStringForm,
2426
SymbolTeXForm,
2527
)
2628
from mathics.session import get_settings_value
@@ -61,7 +63,7 @@
6163

6264
def format_output(obj, expr, format=None):
6365
"""
64-
Handle unformatted output using the *specific* capabilities of mathics-django.
66+
Handle unformatted output using the *specific* capabilities of mathicsscript
6567
6668
evaluation.py format_output() from which this was derived is similar but
6769
it can't make use of a front-ends specific capabilities.
@@ -161,7 +163,15 @@ def eval_boxes(result, fn: Callable, obj, **options):
161163
write_asy_and_view(asy_str)
162164
return expr_type
163165

166+
if expr is SymbolAborted:
167+
obj.out = ["$Aborted"]
168+
obj.last_eval = SymbolAborted
169+
return "$Aborted"
164170
if format == "text":
171+
if expr_head is SymbolStringForm:
172+
return expr.elements[0].value
173+
elif isinstance(expr, String):
174+
return expr.value
165175
result = expr.format(obj, SymbolOutputForm)
166176
elif format == "xml":
167177
result = Expression(SymbolStandardForm, expr).format(obj, SymbolMathMLForm)

0 commit comments

Comments
 (0)