OILS / frontend / py_readline.py View on Github | oils.pub

178 lines, 87 significant
1"""
2py_readline.py: GNU readline wrapper that's also implemented in C++
3"""
4
5try:
6 import line_input
7except ImportError:
8 # Note: build/ovm-compile.sh doesn't build pyext/line_input.c unless shell
9 # var $HAVE_READLINE is set
10 # On the other hand, cpp/frontend_pyreadline.cc uses -D HAVE_READLINE, a
11 # C++ preprocessor var
12 line_input = None
13
14from typing import Optional, Callable, Tuple, TYPE_CHECKING
15if TYPE_CHECKING:
16 from core.completion import ReadlineCallback
17 from core.comp_ui import _IDisplay
18
19
20class Readline(object):
21 """
22 A thin wrapper around GNU readline to make it usable from C++.
23 Try to avoid adding any logic here.
24 """
25
26 def __init__(self):
27 # type: () -> None
28 assert line_input is not None
29
30 def prompt_input(self, prompt):
31 # type: (str) -> str
32 """
33 Print prompt, read line, and return it with trailing newline. Or raise
34 EOFError.
35 """
36 # Add trailing newline to make GNU readline conform to Python's
37 # f.readline() interface
38 return raw_input(prompt) + '\n'
39
40 def parse_and_bind(self, s):
41 # type: (str) -> None
42 line_input.parse_and_bind(s)
43
44 def read_init_file(self, s):
45 # type: (str) -> None
46 line_input.read_init_file(s)
47
48 def add_history(self, line):
49 # type: (str) -> None
50 line_input.add_history(line)
51
52 def read_history_file(self, path=None):
53 # type: (Optional[str]) -> None
54 line_input.read_history_file(path)
55
56 def write_history_file(self, path=None):
57 # type: (Optional[str]) -> None
58 line_input.write_history_file(path)
59
60 def set_completer(self, completer=None):
61 # type: (Optional[ReadlineCallback]) -> None
62 line_input.set_completer(completer)
63
64 def set_completer_delims(self, delims):
65 # type: (str) -> None
66 line_input.set_completer_delims(delims)
67
68 def set_completion_display_matches_hook(self, display=None):
69 # type: (Optional[_IDisplay]) -> None
70 hook = None
71 if display is not None:
72 hook = lambda *args: display.PrintCandidates(*args)
73
74 line_input.set_completion_display_matches_hook(hook)
75
76 def get_line_buffer(self):
77 # type: () -> str
78 return line_input.get_line_buffer()
79
80 def get_begidx(self):
81 # type: () -> int
82 return line_input.get_begidx()
83
84 def get_endidx(self):
85 # type: () -> int
86 return line_input.get_endidx()
87
88 def clear_history(self):
89 # type: () -> None
90 line_input.clear_history()
91
92 def get_history_item(self, pos):
93 # type: (int) -> str
94 return line_input.get_history_item(pos)
95
96 def remove_history_item(self, pos):
97 # type: (int) -> None
98 line_input.remove_history_item(pos)
99
100 def get_current_history_length(self):
101 # type: () -> int
102 return line_input.get_current_history_length()
103
104 def resize_terminal(self):
105 # type: () -> None
106 line_input.resize_terminal()
107
108 def list_funmap_names(self):
109 # type: () -> None
110 line_input.list_funmap_names()
111
112 def function_dumper(self, print_readably):
113 # type: (bool) -> None
114 line_input.function_dumper(print_readably)
115
116 def macro_dumper(self, print_readably):
117 # type: (bool) -> None
118 line_input.macro_dumper(print_readably)
119
120 def variable_dumper(self, print_readably):
121 # type: (bool) -> None
122 line_input.variable_dumper(print_readably)
123
124 def query_bindings(self, fn_name):
125 # type: (str) -> None
126 line_input.query_bindings(fn_name)
127
128 def unbind_rl_function(self, fn_name):
129 # type: (str) -> None
130 line_input.unbind_rl_function(fn_name)
131
132 def use_temp_keymap(self, fn_name):
133 # type: (str) -> None
134 line_input.use_temp_keymap(fn_name)
135
136 def restore_orig_keymap(self):
137 # type: () -> None
138 line_input.restore_orig_keymap()
139
140 def print_shell_cmd_map(self):
141 # type: () -> None
142 line_input.print_shell_cmd_map()
143
144 def unbind_keyseq(self, keyseq):
145 # type: (str) -> None
146 line_input.unbind_keyseq(keyseq)
147
148 def bind_shell_command(self, keyseq, cmd):
149 # type: (str, str) -> None
150 line_input.bind_shell_command(keyseq, cmd)
151
152 def set_bind_shell_command_hook(self, hook):
153 # type: (Callable[[str, str, int], Tuple[int, str, int]]) -> None
154 assert hook is not None
155
156 line_input.set_bind_shell_command_hook(hook)
157
158
159def MaybeGetReadline():
160 # type: () -> Optional[Readline]
161 """Returns a readline "module" if we were built with readline support."""
162 if line_input is not None:
163 return Readline()
164
165 return None
166
167
168if __name__ == '__main__':
169 import sys
170 readline = MaybeGetReadline()
171 try:
172 prompt_str = sys.argv[1]
173 except IndexError:
174 prompt_str = '! '
175
176 while True:
177 x = readline.prompt_input(prompt_str)
178 print(x)