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

165 lines, 82 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, TYPE_CHECKING
15if TYPE_CHECKING:
16 from core.completion import ReadlineCallback
17 from core.comp_ui import _IDisplay
18
19
20class Readline(object):
21 """A thin wrapper around GNU readline to make it usable from C++."""
22
23 def __init__(self):
24 # type: () -> None
25 assert line_input is not None
26
27 def prompt_input(self, prompt):
28 # type: (str) -> str
29 """
30 Print prompt, read line, and return it with trailing newline. Or raise
31 EOFError.
32 """
33 # Add trailing newline to make GNU readline conform to Python's
34 # f.readline() interface
35 return raw_input(prompt) + '\n'
36
37 def parse_and_bind(self, s):
38 # type: (str) -> None
39 line_input.parse_and_bind(s)
40
41 def read_init_file(self, s):
42 # type: (str) -> None
43 line_input.read_init_file(s)
44
45 def add_history(self, line):
46 # type: (str) -> None
47 line_input.add_history(line)
48
49 def read_history_file(self, path=None):
50 # type: (Optional[str]) -> None
51 line_input.read_history_file(path)
52
53 def write_history_file(self, path=None):
54 # type: (Optional[str]) -> None
55 line_input.write_history_file(path)
56
57 def set_completer(self, completer=None):
58 # type: (Optional[ReadlineCallback]) -> None
59 line_input.set_completer(completer)
60
61 def set_completer_delims(self, delims):
62 # type: (str) -> None
63 line_input.set_completer_delims(delims)
64
65 def set_completion_display_matches_hook(self, display=None):
66 # type: (Optional[_IDisplay]) -> None
67 hook = None
68 if display is not None:
69 hook = lambda *args: display.PrintCandidates(*args)
70
71 line_input.set_completion_display_matches_hook(hook)
72
73 def get_line_buffer(self):
74 # type: () -> str
75 return line_input.get_line_buffer()
76
77 def get_begidx(self):
78 # type: () -> int
79 return line_input.get_begidx()
80
81 def get_endidx(self):
82 # type: () -> int
83 return line_input.get_endidx()
84
85 def clear_history(self):
86 # type: () -> None
87 line_input.clear_history()
88
89 def get_history_item(self, pos):
90 # type: (int) -> str
91 return line_input.get_history_item(pos)
92
93 def remove_history_item(self, pos):
94 # type: (int) -> None
95 line_input.remove_history_item(pos)
96
97 def get_current_history_length(self):
98 # type: () -> int
99 return line_input.get_current_history_length()
100
101 def resize_terminal(self):
102 # type: () -> None
103 line_input.resize_terminal()
104
105 def list_funmap_names(self):
106 # type: () -> None
107 line_input.list_funmap_names()
108
109 def function_dumper(self, print_readably):
110 # type: (bool) -> None
111 line_input.function_dumper(print_readably)
112
113 def macro_dumper(self, print_readably):
114 # type: (bool) -> None
115 line_input.macro_dumper(print_readably)
116
117 def variable_dumper(self, print_readably):
118 # type: (bool) -> None
119 line_input.variable_dumper(print_readably)
120
121 def query_bindings(self, fn_name):
122 # type: (str) -> None
123 line_input.query_bindings(fn_name)
124
125 def unbind_rl_function(self, fn_name):
126 # type: (str) -> None
127 line_input.unbind_rl_function(fn_name)
128
129 def use_temp_keymap(self, fn_name):
130 # type: (str) -> None
131 line_input.use_temp_keymap(fn_name)
132
133 def restore_orig_keymap(self):
134 # type: () -> None
135 line_input.restore_orig_keymap()
136
137 def print_shell_cmd_map(self):
138 # type: () -> None
139 line_input.print_shell_cmd_map()
140
141 def unbind_keyseq(self, keyseq):
142 # type: (str) -> None
143 line_input.unbind_keyseq(keyseq)
144
145
146def MaybeGetReadline():
147 # type: () -> Optional[Readline]
148 """Returns a readline "module" if we were built with readline support."""
149 if line_input is not None:
150 return Readline()
151
152 return None
153
154
155if __name__ == '__main__':
156 import sys
157 readline = MaybeGetReadline()
158 try:
159 prompt_str = sys.argv[1]
160 except IndexError:
161 prompt_str = '! '
162
163 while True:
164 x = readline.prompt_input(prompt_str)
165 print(x)