1 | #!/usr/bin/env python2
|
2 | """
|
3 | readline_osh.py - Builtins that are dependent on GNU readline.
|
4 | """
|
5 | from __future__ import print_function
|
6 |
|
7 | from _devbuild.gen import arg_types
|
8 | from _devbuild.gen.syntax_asdl import loc
|
9 | from core.error import e_usage
|
10 | from core import pyutil
|
11 | from core import vm
|
12 | from frontend import flag_util
|
13 | from mycpp import mops
|
14 | from mycpp import mylib
|
15 |
|
16 | from typing import Optional, TYPE_CHECKING
|
17 | if TYPE_CHECKING:
|
18 | from _devbuild.gen.runtime_asdl import cmd_value
|
19 | from frontend.py_readline import Readline
|
20 | from core import shell
|
21 | from display import ui
|
22 |
|
23 |
|
24 | class Bind(vm._Builtin):
|
25 | """Interactive interface to readline bindings"""
|
26 |
|
27 | def __init__(self, readline, errfmt):
|
28 | # type: (Optional[Readline], ui.ErrorFormatter) -> None
|
29 | self.readline = readline
|
30 | self.errfmt = errfmt
|
31 |
|
32 | def Run(self, cmd_val):
|
33 | # type: (cmd_value.Argv) -> int
|
34 | readline = self.readline
|
35 | if not readline:
|
36 | e_usage("is disabled because Oil wasn't compiled with 'readline'",
|
37 | loc.Missing)
|
38 |
|
39 | attrs, arg_r = flag_util.ParseCmdVal('bind', cmd_val)
|
40 |
|
41 | print(attrs)
|
42 | print(attrs.attrs)
|
43 | print(arg_r)
|
44 |
|
45 | arg = arg_types.bind(attrs.attrs)
|
46 | print(arg)
|
47 |
|
48 | if arg.m:
|
49 | print("Using keymap: " + arg.m)
|
50 |
|
51 | if arg.l:
|
52 | readline.list_funmap_names()
|
53 |
|
54 | if arg.p:
|
55 | readline.function_dumper(True)
|
56 |
|
57 | if arg.P:
|
58 | readline.function_dumper(False)
|
59 |
|
60 | if arg.s:
|
61 | readline.macro_dumper(True)
|
62 |
|
63 | if arg.S:
|
64 | readline.macro_dumper(False)
|
65 |
|
66 | if arg.v:
|
67 | readline.variable_dumper(True)
|
68 |
|
69 | if arg.V:
|
70 | readline.variable_dumper(False)
|
71 |
|
72 | self.errfmt.Print_("warning: bind isn't implemented",
|
73 | blame_loc=cmd_val.arg_locs[0])
|
74 | return 1
|
75 |
|
76 |
|
77 | class History(vm._Builtin):
|
78 | """Show interactive command history."""
|
79 |
|
80 | def __init__(
|
81 | self,
|
82 | readline, # type: Optional[Readline]
|
83 | sh_files, # type: shell.ShellFiles
|
84 | errfmt, # type: ui.ErrorFormatter
|
85 | f, # type: mylib.Writer
|
86 | ):
|
87 | # type: (...) -> None
|
88 | self.readline = readline
|
89 | self.sh_files = sh_files
|
90 | self.errfmt = errfmt
|
91 | self.f = f # this hook is for unit testing only
|
92 |
|
93 | def Run(self, cmd_val):
|
94 | # type: (cmd_value.Argv) -> int
|
95 | # NOTE: This builtin doesn't do anything in non-interactive mode in bash?
|
96 | # It silently exits zero.
|
97 | # zsh -c 'history' produces an error.
|
98 | readline = self.readline
|
99 | if not readline:
|
100 | e_usage("is disabled because Oils wasn't compiled with 'readline'",
|
101 | loc.Missing)
|
102 |
|
103 | attrs, arg_r = flag_util.ParseCmdVal('history', cmd_val)
|
104 | arg = arg_types.history(attrs.attrs)
|
105 |
|
106 | # Clear all history
|
107 | if arg.c:
|
108 | readline.clear_history()
|
109 | return 0
|
110 |
|
111 | if arg.a:
|
112 | hist_file = self.sh_files.HistoryFile()
|
113 | if hist_file is None:
|
114 | return 1
|
115 |
|
116 | try:
|
117 | readline.write_history_file(hist_file)
|
118 | except (IOError, OSError) as e:
|
119 | self.errfmt.Print_(
|
120 | 'Error writing HISTFILE %r: %s' %
|
121 | (hist_file, pyutil.strerror(e)), loc.Missing)
|
122 | return 1
|
123 |
|
124 | return 0
|
125 |
|
126 | if arg.r:
|
127 | hist_file = self.sh_files.HistoryFile()
|
128 | if hist_file is None:
|
129 | return 1
|
130 |
|
131 | try:
|
132 | readline.read_history_file(hist_file)
|
133 | except (IOError, OSError) as e:
|
134 | self.errfmt.Print_(
|
135 | 'Error reading HISTFILE %r: %s' %
|
136 | (hist_file, pyutil.strerror(e)), loc.Missing)
|
137 | return 1
|
138 |
|
139 | return 0
|
140 |
|
141 | # Delete history entry by id number
|
142 | arg_d = mops.BigTruncate(arg.d)
|
143 | if arg_d >= 0:
|
144 | cmd_index = arg_d - 1
|
145 |
|
146 | try:
|
147 | readline.remove_history_item(cmd_index)
|
148 | except ValueError:
|
149 | e_usage("couldn't find item %d" % arg_d, loc.Missing)
|
150 |
|
151 | return 0
|
152 |
|
153 | # Returns 0 items in non-interactive mode?
|
154 | num_items = readline.get_current_history_length()
|
155 | #log('len = %d', num_items)
|
156 |
|
157 | num_arg, num_arg_loc = arg_r.Peek2()
|
158 |
|
159 | if num_arg is None:
|
160 | start_index = 1
|
161 | else:
|
162 | try:
|
163 | num_to_show = int(num_arg)
|
164 | except ValueError:
|
165 | e_usage('got invalid argument %r' % num_arg, num_arg_loc)
|
166 | start_index = max(1, num_items + 1 - num_to_show)
|
167 |
|
168 | arg_r.Next()
|
169 | if not arg_r.AtEnd():
|
170 | e_usage('got too many arguments', loc.Missing)
|
171 |
|
172 | # TODO:
|
173 | # - Exclude lines that don't parse from the history! bash and zsh don't do
|
174 | # that.
|
175 | # - Consolidate multiline commands.
|
176 |
|
177 | for i in xrange(start_index, num_items + 1): # 1-based index
|
178 | item = readline.get_history_item(i)
|
179 | self.f.write('%5d %s\n' % (i, item))
|
180 | return 0
|