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