|
9 | 9 | from typing import Any |
10 | 10 |
|
11 | 11 | import click |
| 12 | +import mathics.core as mathics_core |
12 | 13 | from mathics import license_string, settings, version_info |
13 | 14 | from mathics.core.attributes import attribute_string_to_number |
14 | 15 | from mathics.core.definitions import autoload_files |
15 | 16 | from mathics.core.evaluation import Evaluation, Output |
16 | 17 | from mathics.core.expression import from_python |
17 | 18 | from mathics.core.parser import MathicsFileLineFeeder |
18 | 19 | from mathics.core.symbols import Symbol, SymbolFalse, SymbolTrue |
| 20 | +from mathics.core.systemsymbols import SymbolTeXForm |
19 | 21 | from mathics_scanner import replace_wl_with_plain_text |
20 | 22 | from pygments import highlight |
21 | 23 |
|
22 | 24 | from mathicsscript.asymptote import asymptote_version |
23 | 25 | from mathicsscript.settings import definitions |
24 | 26 | from mathicsscript.termshell import ShellEscapeException, mma_lexer |
25 | 27 | from mathicsscript.termshell_gnu import TerminalShellGNUReadline |
26 | | -from mathicsscript.termshell_prompt import TerminalShellPromptToolKit |
| 28 | +from mathicsscript.termshell_prompt import ( |
| 29 | + TerminalShellCommon, |
| 30 | + TerminalShellPromptToolKit, |
| 31 | +) |
27 | 32 | from mathicsscript.version import __version__ |
28 | 33 |
|
29 | 34 | try: |
|
47 | 52 | **version_info |
48 | 53 | ) |
49 | 54 |
|
50 | | - |
51 | 55 | if "cython" in version_info: |
52 | 56 | version_string += f"cython {version_info['cython']}, " |
53 | 57 |
|
@@ -135,6 +139,100 @@ def out(self, out): |
135 | 139 | return self.shell.out_callback(out) |
136 | 140 |
|
137 | 141 |
|
| 142 | +def interactive_eval_loop( |
| 143 | + shell: TerminalShellCommon, unicode, prompt, strict_wl_output: bool |
| 144 | +): |
| 145 | + def identity(x: Any) -> Any: |
| 146 | + return x |
| 147 | + |
| 148 | + def fmt_fun(query: Any) -> Any: |
| 149 | + return highlight(str(query), mma_lexer, shell.terminal_formatter) |
| 150 | + |
| 151 | + while True: |
| 152 | + try: |
| 153 | + if have_readline and shell.using_readline: |
| 154 | + import readline as GNU_readline |
| 155 | + |
| 156 | + last_pos = GNU_readline.get_current_history_length() |
| 157 | + |
| 158 | + full_form = definitions.get_ownvalue( |
| 159 | + "Settings`$ShowFullFormInput" |
| 160 | + ).replace.to_python() |
| 161 | + style = definitions.get_ownvalue("Settings`$PygmentsStyle") |
| 162 | + fmt = identity |
| 163 | + if style: |
| 164 | + style = style.replace.get_string_value() |
| 165 | + if shell.terminal_formatter: |
| 166 | + fmt = fmt_fun |
| 167 | + |
| 168 | + evaluation = Evaluation(shell.definitions, output=TerminalOutput(shell)) |
| 169 | + query, source_code = evaluation.parse_feeder_returning_code(shell) |
| 170 | + if mathics_core.PRE_EVALUATION_HOOK is not None: |
| 171 | + mathics_core.PRE_EVALUATION_HOOK(query, evaluation) |
| 172 | + |
| 173 | + if ( |
| 174 | + have_readline |
| 175 | + and shell.using_readline |
| 176 | + and hasattr(GNU_readline, "remove_history_item") |
| 177 | + ): |
| 178 | + current_pos = GNU_readline.get_current_history_length() |
| 179 | + for pos in range(last_pos, current_pos - 1): |
| 180 | + GNU_readline.remove_history_item(pos) |
| 181 | + wl_input = source_code.rstrip() |
| 182 | + if unicode: |
| 183 | + wl_input = replace_wl_with_plain_text(wl_input) |
| 184 | + GNU_readline.add_history(wl_input) |
| 185 | + |
| 186 | + if query is None: |
| 187 | + continue |
| 188 | + |
| 189 | + if hasattr(query, "head") and query.head == SymbolTeXForm: |
| 190 | + output_style = "//TeXForm" |
| 191 | + else: |
| 192 | + output_style = "" |
| 193 | + |
| 194 | + if full_form: |
| 195 | + print(fmt(query)) |
| 196 | + result = evaluation.evaluate( |
| 197 | + query, timeout=settings.TIMEOUT, format="unformatted" |
| 198 | + ) |
| 199 | + if result is not None: |
| 200 | + shell.print_result( |
| 201 | + result, prompt, output_style, strict_wl_output=strict_wl_output |
| 202 | + ) |
| 203 | + |
| 204 | + except ShellEscapeException as e: |
| 205 | + source_code = e.line |
| 206 | + if len(source_code) and source_code[1] == "!": |
| 207 | + try: |
| 208 | + print(open(source_code[2:], "r").read()) |
| 209 | + except Exception: |
| 210 | + print(str(sys.exc_info()[1])) |
| 211 | + else: |
| 212 | + subprocess.run(source_code[1:], shell=True) |
| 213 | + |
| 214 | + # Should we test exit code for adding to history? |
| 215 | + GNU_readline.add_history(source_code.rstrip()) |
| 216 | + # FIXME add this... when in Mathics core updated |
| 217 | + # shell.definitions.increment_line(1) |
| 218 | + |
| 219 | + except (KeyboardInterrupt): |
| 220 | + print("\nKeyboardInterrupt") |
| 221 | + except EOFError: |
| 222 | + if prompt: |
| 223 | + print("\n\nGoodbye!\n") |
| 224 | + break |
| 225 | + except SystemExit: |
| 226 | + print("\n\nGoodbye!\n") |
| 227 | + # raise to pass the error code on, e.g. Quit[1] |
| 228 | + raise |
| 229 | + finally: |
| 230 | + # Reset the input line that would be shown in a parse error. |
| 231 | + # This is not to be confused with the number of complete |
| 232 | + # inputs that have been seen, i.e. In[] |
| 233 | + shell.reset_lineno() |
| 234 | + |
| 235 | + |
138 | 236 | @click.command() |
139 | 237 | @click.version_option(version=__version__) |
140 | 238 | @click.option( |
@@ -184,6 +282,11 @@ def out(self, out): |
184 | 282 | show_default=True, |
185 | 283 | help="Accept Unicode operators in input and show unicode in output.", |
186 | 284 | ) |
| 285 | +@click.option( |
| 286 | + "--post-mortem/--no-unicode", |
| 287 | + show_default=True, |
| 288 | + help="go to post-mortem debug on a terminating system exception (needs trepan3k)", |
| 289 | +) |
187 | 290 | @click.option( |
188 | 291 | "--prompt/--no-prompt", |
189 | 292 | default=True, |
@@ -242,6 +345,7 @@ def main( |
242 | 345 | readline, |
243 | 346 | completion, |
244 | 347 | unicode, |
| 348 | + post_mortem, |
245 | 349 | prompt, |
246 | 350 | pyextensions, |
247 | 351 | execute, |
@@ -275,6 +379,17 @@ def main( |
275 | 379 | "Settings`$PygmentsShowTokens", from_python(True if pygments_tokens else False) |
276 | 380 | ) |
277 | 381 |
|
| 382 | + if post_mortem: |
| 383 | + try: |
| 384 | + from trepan.post_mortem import post_mortem_excepthook |
| 385 | + except ImportError: |
| 386 | + print( |
| 387 | + "trepan3k is needed for post-mortem debugging --post-mortem option ignored." |
| 388 | + ) |
| 389 | + print("And you may want also trepan3k-mathics3-plugin as well.") |
| 390 | + else: |
| 391 | + sys.excepthook = post_mortem_excepthook |
| 392 | + |
278 | 393 | readline = "none" if (execute or file and not persist) else readline.lower() |
279 | 394 | if readline == "prompt": |
280 | 395 | shell = TerminalShellPromptToolKit( |
@@ -373,96 +488,9 @@ def main( |
373 | 488 | definitions.set_attribute( |
374 | 489 | "Settings`MathicsScriptVersion", attribute_string_to_number["System`Locked"] |
375 | 490 | ) |
376 | | - TeXForm = Symbol("System`TeXForm") |
377 | | - |
378 | | - def identity(x: Any) -> Any: |
379 | | - return x |
380 | | - |
381 | | - def fmt_fun(query: Any) -> Any: |
382 | | - return highlight(str(query), mma_lexer, shell.terminal_formatter) |
383 | 491 |
|
384 | 492 | definitions.set_line_no(0) |
385 | | - while True: |
386 | | - try: |
387 | | - if have_readline and shell.using_readline: |
388 | | - import readline as GNU_readline |
389 | | - |
390 | | - last_pos = GNU_readline.get_current_history_length() |
391 | | - |
392 | | - full_form = definitions.get_ownvalue( |
393 | | - "Settings`$ShowFullFormInput" |
394 | | - ).replace.to_python() |
395 | | - style = definitions.get_ownvalue("Settings`$PygmentsStyle") |
396 | | - fmt = identity |
397 | | - if style: |
398 | | - style = style.replace.get_string_value() |
399 | | - if shell.terminal_formatter: |
400 | | - fmt = fmt_fun |
401 | | - |
402 | | - evaluation = Evaluation(shell.definitions, output=TerminalOutput(shell)) |
403 | | - query, source_code = evaluation.parse_feeder_returning_code(shell) |
404 | | - |
405 | | - if ( |
406 | | - have_readline |
407 | | - and shell.using_readline |
408 | | - and hasattr(GNU_readline, "remove_history_item") |
409 | | - ): |
410 | | - current_pos = GNU_readline.get_current_history_length() |
411 | | - for pos in range(last_pos, current_pos - 1): |
412 | | - GNU_readline.remove_history_item(pos) |
413 | | - wl_input = source_code.rstrip() |
414 | | - if unicode: |
415 | | - wl_input = replace_wl_with_plain_text(wl_input) |
416 | | - GNU_readline.add_history(wl_input) |
417 | | - |
418 | | - if query is None: |
419 | | - continue |
420 | | - |
421 | | - if hasattr(query, "head") and query.head == TeXForm: |
422 | | - output_style = "//TeXForm" |
423 | | - else: |
424 | | - output_style = "" |
425 | | - |
426 | | - if full_form: |
427 | | - print(fmt(query)) |
428 | | - result = evaluation.evaluate( |
429 | | - query, timeout=settings.TIMEOUT, format="unformatted" |
430 | | - ) |
431 | | - if result is not None: |
432 | | - shell.print_result( |
433 | | - result, prompt, output_style, strict_wl_output=strict_wl_output |
434 | | - ) |
435 | | - |
436 | | - except ShellEscapeException as e: |
437 | | - source_code = e.line |
438 | | - if len(source_code) and source_code[1] == "!": |
439 | | - try: |
440 | | - print(open(source_code[2:], "r").read()) |
441 | | - except Exception: |
442 | | - print(str(sys.exc_info()[1])) |
443 | | - else: |
444 | | - subprocess.run(source_code[1:], shell=True) |
445 | | - |
446 | | - # Should we test exit code for adding to history? |
447 | | - GNU_readline.add_history(source_code.rstrip()) |
448 | | - # FIXME add this... when in Mathics core updated |
449 | | - # shell.definitions.increment_line(1) |
450 | | - |
451 | | - except (KeyboardInterrupt): |
452 | | - print("\nKeyboardInterrupt") |
453 | | - except EOFError: |
454 | | - if prompt: |
455 | | - print("\n\nGoodbye!\n") |
456 | | - break |
457 | | - except SystemExit: |
458 | | - print("\n\nGoodbye!\n") |
459 | | - # raise to pass the error code on, e.g. Quit[1] |
460 | | - raise |
461 | | - finally: |
462 | | - # Reset the input line that would be shown in a parse error. |
463 | | - # This is not to be confused with the number of complete |
464 | | - # inputs that have been seen, i.e. In[] |
465 | | - shell.reset_lineno() |
| 493 | + interactive_eval_loop(shell, unicode, prompt, strict_wl_output) |
466 | 494 | return exit_rc |
467 | 495 |
|
468 | 496 |
|
|
0 commit comments