Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extended terminal handling #2

Merged
merged 2 commits into from
Oct 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
include README.rst
include NEWS.rst
include ChangeLog
include COPYING
include Makefile
include mathicsscript/inputrc
recursive-include mathicsscript *.py
recursive-exclude __pycache__
1 change: 1 addition & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Features
* GNU Readline terminal interaction. This includes
- saving command history between sessions.
- variable completion
- limited ESC keyboard input; for example *esc* ``p`` *esc* is π
* Syntax highlighting using `pygments`.
* Automatic detection of light or dark terminal background color.

Expand Down
137 changes: 137 additions & 0 deletions mathicsscript/inputrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# GNU Readline input translations

# Lowercase TeX Greek symbols
"\e\\alpha\e": "α"
"\e\\beta\e": "β"
"\e\\gamma\e": "γ"
"\e\\delta\e": "δ"
"\e\\epsilon\e": "ε"
"\e\\zeta\e": "ζ"
"\e\\eta\e": "η"
"\e\\theta\e": "θ"
"\e\\iota\e": "ι"
"\e\\kappa\e": "κ"
"\e\\lambda\e": "λ"
"\e\\mu\e": "μ"
"\e\\nu\e": "ν"
"\e\\xi\e": "ξ"
"\e\\omicron\e": "ο"
"\e\\pi\e": "π"
"\e\\rho\e": "ρ"
"\e\\varsigma\e": "ς"
"\e\\sigma\e": "σ"
"\e\\tau\e": "τ"
"\e\\upsilon\e": "υ"
"\e\\phi\e": "φ"
"\e\\chi\e": "χ"
"\e\\psi\e": "ψ"
"\e\\omega\e": "ω"

# Lowercase named characters
"\ea\e": "α"
"\eb\e": "β"
"\eg\e": "γ"
"\ed\e": "δ"
"\ee\e": "ε"
"\ez\e": "ζ"
"\ee\e": "η"
"\et\e": "θ"
"\ei\e": "ι"
"\ek\e": "κ"
"\el\e": "λ"
"\em\e": "μ"
"\en\e": "ν"
"\ex\e": "ξ"
"\eo\e": "ω"
"\ep\e": "π"
"\er\e": "ρ"
"\ev\e": "ς"
"\es\e": "σ"
"\et\e": "τ"
"\eu\e": "υ"
# "\e\\phi\e": "φ" # ?
# "\e\\chi\e": "χ" # ?
# "\e\\psi\e": "ψ" # ?

# Uppercase TeX Greek symbols
"\e\\Gamma\e": "Γ"
"\e\\Delta\e": "Δ"
"\e\\Theta\e": "Θ"
"\e\\Lambda\e": "Λ"
"\e\\Xi\e": "Ξ"
"\e\\Pi\e": "Π"
"\e\\Sigma\e": "Σ"
"\e\\Upsilon\e": "Υ"
"\e\\Phi\e": "Φ"
"\e\\Psi\e": "Ψ"
"\e\\Omega\e": "Ω"

# Things we have Unicode symbols for
"\einf\e": "∞"
"\edeg\e": "°"
"\e&&\e": "∧"

# Things we have don't have Unicode symbols in terminal.
# So we use the Mathics name

"\e->\e": "\\[Rule]"
"\e|\e": "\\[VerticalSeparator]"
"\el\e": "\\[LeftBracketingBar]"
"\er\e": "\\[RightBracketingBar]"
"\edd\e": "\\[DifferentialD]"
"\eee\e": "\\[ExponentialE]"
"\eii\e": "\\[ImaginaryI]"
"\ejj\e": "\\[ImaginaryJ]"
"\esca\e": "\\[ScriptA]"
"\escb\e": "\\[ScriptB]"
"\escc\e": "\\[ScriptC]"
"\escd\e": "\\[ScriptD]"
"\esce\e": "\\[ScriptE]"
"\escf\e": "\\[ScriptF]"
"\escg\e": "\\[ScriptG]"
"\esch\e": "\\[ScriptH]"
"\esci\e": "\\[ScriptI]"
"\escj\e": "\\[ScriptJ]"
"\esck\e": "\\[ScriptK]"
"\escl\e": "\\[ScriptL]"
"\escm\e": "\\[ScriptM]"
"\escn\e": "\\[ScriptN]"
"\esco\e": "\\[ScriptO]"
"\escp\e": "\\[ScriptP]"
"\escq\e": "\\[ScriptQ]"
"\escr\e": "\\[ScriptR]"
"\escs\e": "\\[ScriptS]"
"\esct\e": "\\[ScriptT]"
"\escu\e": "\\[ScriptU]"
"\escv\e": "\\[ScriptV]"
"\escw\e": "\\[ScriptW]"
"\escx\e": "\\[ScriptX]"
"\escy\e": "\\[ScriptY]
"\escz\e": "\\[ScriptZ]
"\escA\e": "\\[ScriptCapitalA]"
"\escB\e": "\\[ScriptCapitalB]"
"\escC\e": "\\[ScriptCapitalC]"
"\escD\e": "\\[ScriptCapitalD]"
"\escE\e": "\\[ScriptCapitalE]"
"\escF\e": "\\[ScriptCapitalF]"
"\escG\e": "\\[ScriptCapitalG]"
"\escH\e": "\\[ScriptCapitalH]"
"\escI\e": "\\[ScriptCapitalI]"
"\escJ\e": "\\[ScriptCapitalJ]"
"\escK\e": "\\[ScriptCapitalK]"
"\escL\e": "\\[ScriptCapitalL]"
"\escM\e": "\\[ScriptCapitalM]"
"\escN\e": "\\[ScriptCapitalN]"
"\escO\e": "\\[ScriptCapitalO]"
"\escP\e": "\\[ScriptCapitalP]"
"\escQ\e": "\\[ScriptCapitalQ]"
"\escR\e": "\\[ScriptCapitalR]"
"\escS\e": "\\[ScriptCapitalS]"
"\escT\e": "\\[ScriptCapitalT]"
"\escU\e": "\\[ScriptCapitalU]"
"\escV\e": "\\[ScriptCapitalV]"
"\escW\e": "\\[ScriptCapitalW]"
"\escX\e": "\\[ScriptCapitalX]"
"\esCy\e": "\\[ScripCapitaltY]
"\esCz\e": "\\[ScripCapitaltZ]
tab: complete
35 changes: 30 additions & 5 deletions mathicsscript/termshell.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
import os
import os.path as osp
import locale
import pathlib
import sys
import re

from mathics.core.expression import strip_context
from mathics.core.characters import named_characters

from pygments import highlight
from pygments.lexers import MathematicaLexer
Expand Down Expand Up @@ -43,11 +44,12 @@

from readline import (
read_history_file,
read_init_file,
set_completer,
set_completer_delims,
set_history_length,
write_history_file,
parse_and_bind,
# parse_and_bind,
)

try:
Expand Down Expand Up @@ -82,12 +84,21 @@ def __init__(
lambda text, state: self.complete_symbol_name(text, state)
)

self.named_character_names = set(named_characters.keys())


# Make _ a delimiter, but not $ or `
# set_completer_delims(
# " \t\n_~!@#%^&*()-=+[{]}\\|;:'\",<>/?"
# )
set_completer_delims(
" \t\n_~!@#%^&*()-=+[{]}\\|;:'\",<>/?"
" \t\n_~!@#%^&*()-=+{]}|;:'\",<>/?"
)

parse_and_bind("tab: complete")
inputrc = pathlib.Path(__file__).parent.absolute() / "inputrc"
read_init_file(inputrc)
# parse_and_bind('"\ep\e": "\u03C0"')
# parse_and_bind("tab: complete")
self.completion_candidates = []

# History
Expand Down Expand Up @@ -161,7 +172,7 @@ def to_output(self, text):
return newline.join(text.splitlines())

def out_callback(self, out):
print(self.to_output(str(out)))
print(self.to_output(str(out)))\

def read_line(self, prompt):
if self.using_readline:
Expand All @@ -187,12 +198,26 @@ def rl_read_line(self, prompt):

def complete_symbol_name(self, text, state):
try:
match = re.match(r"^.*\\\[([A-Z][a-z]*)$", text)
if match:
return self._complete_named_characters(match.group(1), state)
return self._complete_symbol_name(text, state)
except Exception:
# any exception thrown inside the completer gets silently
# thrown away otherwise
print("Unhandled error in readline completion")

def _complete_named_characters(self, prefix, state):
"""prefix is the text after \[. Return a list of named character names.
"""
if state == 0:
self.completion_candidates = ["\\[" + name + "]" for name in self.named_character_names if name.startswith(prefix)]
try:
return self.completion_candidates[state]
except IndexError:
return None


def _complete_symbol_name(self, text, state):
# The readline module calls this function repeatedly,
# increasing 'state' each time and expecting one string to be
Expand Down