| 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 import shell
|
| 21 | from display import ui
|
| 22 |
|
| 23 |
|
| 24 | class Bind(vm._Builtin):
|
| 25 | """For :, true, false."""
|
| 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 | 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: ui.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
|