1 | #!/usr/bin/env python2
|
2 | """
|
3 | builtin_lib.py - Builtins that are bindings to libraries, e.g. 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.ui import ErrorFormatter
|
21 | from core import shell
|
22 |
|
23 |
|
24 | class Bind(vm._Builtin):
|
25 | """For :, true, false."""
|
26 |
|
27 | def __init__(self, readline, errfmt):
|
28 | # type: (Optional[Readline], ErrorFormatter) -> None
|
29 | self.readline = readline
|
30 | self.errfmt = errfmt
|
31 |
|
32 | def Run(self, cmd_val):
|
33 | # type: (cmd_value.Argv) -> int
|
34 | self.errfmt.Print_("warning: bind isn't implemented",
|
35 | blame_loc=cmd_val.arg_locs[0])
|
36 | return 1
|
37 |
|
38 |
|
39 | class History(vm._Builtin):
|
40 | """Show interactive command history."""
|
41 |
|
42 | def __init__(
|
43 | self,
|
44 | readline, # type: Optional[Readline]
|
45 | sh_files, # type: shell.ShellFiles
|
46 | errfmt, # type: ErrorFormatter
|
47 | f, # type: mylib.Writer
|
48 | ):
|
49 | # type: (...) -> None
|
50 | self.readline = readline
|
51 | self.sh_files = sh_files
|
52 | self.errfmt = errfmt
|
53 | self.f = f # this hook is for unit testing only
|
54 |
|
55 | def Run(self, cmd_val):
|
56 | # type: (cmd_value.Argv) -> int
|
57 | # NOTE: This builtin doesn't do anything in non-interactive mode in bash?
|
58 | # It silently exits zero.
|
59 | # zsh -c 'history' produces an error.
|
60 | readline = self.readline
|
61 | if not readline:
|
62 | e_usage("is disabled because Oil wasn't compiled with 'readline'",
|
63 | loc.Missing)
|
64 |
|
65 | attrs, arg_r = flag_util.ParseCmdVal('history', cmd_val)
|
66 | arg = arg_types.history(attrs.attrs)
|
67 |
|
68 | # Clear all history
|
69 | if arg.c:
|
70 | readline.clear_history()
|
71 | return 0
|
72 |
|
73 | if arg.a:
|
74 | hist_file = self.sh_files.HistoryFile()
|
75 | if hist_file is None:
|
76 | return 1
|
77 |
|
78 | try:
|
79 | readline.write_history_file(hist_file)
|
80 | except (IOError, OSError) as e:
|
81 | self.errfmt.Print_(
|
82 | 'Error writing HISTFILE %r: %s' %
|
83 | (hist_file, pyutil.strerror(e)), loc.Missing)
|
84 | return 1
|
85 |
|
86 | return 0
|
87 |
|
88 | if arg.r:
|
89 | hist_file = self.sh_files.HistoryFile()
|
90 | if hist_file is None:
|
91 | return 1
|
92 |
|
93 | try:
|
94 | readline.read_history_file(hist_file)
|
95 | except (IOError, OSError) as e:
|
96 | self.errfmt.Print_(
|
97 | 'Error reading HISTFILE %r: %s' %
|
98 | (hist_file, pyutil.strerror(e)), loc.Missing)
|
99 | return 1
|
100 |
|
101 | return 0
|
102 |
|
103 | # Delete history entry by id number
|
104 | arg_d = mops.BigTruncate(arg.d)
|
105 | if arg_d >= 0:
|
106 | cmd_index = arg_d - 1
|
107 |
|
108 | try:
|
109 | readline.remove_history_item(cmd_index)
|
110 | except ValueError:
|
111 | e_usage("couldn't find item %d" % arg_d, loc.Missing)
|
112 |
|
113 | return 0
|
114 |
|
115 | # Returns 0 items in non-interactive mode?
|
116 | num_items = readline.get_current_history_length()
|
117 | #log('len = %d', num_items)
|
118 |
|
119 | num_arg, num_arg_loc = arg_r.Peek2()
|
120 |
|
121 | if num_arg is None:
|
122 | start_index = 1
|
123 | else:
|
124 | try:
|
125 | num_to_show = int(num_arg)
|
126 | except ValueError:
|
127 | e_usage('got invalid argument %r' % num_arg, num_arg_loc)
|
128 | start_index = max(1, num_items + 1 - num_to_show)
|
129 |
|
130 | arg_r.Next()
|
131 | if not arg_r.AtEnd():
|
132 | e_usage('got too many arguments', loc.Missing)
|
133 |
|
134 | # TODO:
|
135 | # - Exclude lines that don't parse from the history! bash and zsh don't do
|
136 | # that.
|
137 | # - Consolidate multiline commands.
|
138 |
|
139 | for i in xrange(start_index, num_items + 1): # 1-based index
|
140 | item = readline.get_history_item(i)
|
141 | self.f.write('%5d %s\n' % (i, item))
|
142 | return 0
|