def _AddCliTreeKeywordsAndBuiltins(root): """Adds keywords and builtins to the CLI tree root.""" # Add the exit builtin to the CLI tree. node = cli_tree.Node( command='exit', description='Exit the interactive shell.', positionals=[ { 'default': '0', 'description': 'The exit status.', 'name': 'status', 'nargs': '?', 'required': False, 'value': 'STATUS', }, ], ) node[parser.LOOKUP_IS_GROUP] = False root[parser.LOOKUP_COMMANDS]['exit'] = node # Add special shell keywords that may be followed by commands. for name in [ '!', '{', 'do', 'elif', 'else', 'if', 'then', 'time', 'until', 'while' ]: node = cli_tree.Node(name) node[parser.LOOKUP_IS_GROUP] = False node[parser.LOOKUP_IS_SPECIAL] = True root[parser.LOOKUP_COMMANDS][name] = node # Add misc shell keywords. for name in ['break', 'case', 'continue', 'done', 'esac', 'fi']: node = cli_tree.Node(name) node[parser.LOOKUP_IS_GROUP] = False root[parser.LOOKUP_COMMANDS][name] = node
def LoadAll(directory=None, ignore_out_of_date=False, root=None, warn_on_exceptions=True): """Loads all CLI trees in directory and adds them to tree. Args: directory: The config directory containing the CLI tree modules. ignore_out_of_date: Ignore out of date trees instead of regenerating. root: dict, The CLI root to update. A new root is created if None. warn_on_exceptions: Warn on exceptions instead of raising if True. Raises: CliTreeVersionError: loaded tree version mismatch ImportModuleError: import errors Returns: The CLI tree. """ # Create the root node if needed. if root is None: root = cli_tree.Node(description='The CLI tree root.') # Load the default CLI if available. if cli_tree.DEFAULT_CLI_NAME not in root[cli_tree.LOOKUP_COMMANDS]: try: root[cli_tree.LOOKUP_COMMANDS][cli_tree.DEFAULT_CLI_NAME] = ( cli_tree.Load()) except cli_tree.CliTreeLoadError: pass # Load extra CLIs by searching directories in order. .json files are treated # as CLI modules/data, where the file base name is the name of the CLI root # command. directories = _GetDirectories( directory=directory, warn_on_exceptions=warn_on_exceptions) loaded = {cli_tree.DEFAULT_CLI_NAME, '__init__'} # Already loaded this above. for directory in directories: if not directory or not os.path.exists(directory): continue for (dirpath, _, filenames) in os.walk(six.text_type(directory)): for filename in sorted(filenames): # For stability across runs. command, extension = os.path.splitext(filename) if extension != '.json': continue if command in loaded: # Already loaded. Earlier directory hits take precedence. continue loaded.add(command) if command == cli_tree.DEFAULT_CLI_NAME: tree = cli_tree.Load(os.path.join(dirpath, filename)) else: tree = LoadOrGenerate(command, directories=[dirpath], ignore_out_of_date=ignore_out_of_date, warn_on_exceptions=warn_on_exceptions) if tree: root[cli_tree.LOOKUP_COMMANDS][command] = tree # Don't search subdirectories. break return root
def __init__(self, cosh=None, args=None, config=None): self.args = args self.coshell = cosh self.config = config self.key_bindings = bindings.KeyBindings( edit_mode=self.coshell.edit_mode == 'emacs') # Load the default CLI trees. On startup we ignore out of date trees. The # alternative is to regenerate them before the first prompt. This could be # a noticeable delay for users that accrue a lot of trees. Although ignored # at startup, the regen will happen on demand as the individual commands # are typed. self.root = generate_cli_trees.LoadAll(ignore_out_of_date=True, warn_on_exceptions=True) # Add the exit command completer node to the CLI tree. self.root[parser.LOOKUP_COMMANDS]['exit'] = cli_tree.Node( command='exit', description='Exit the interactive shell.', positionals=[ { 'default': '0', 'description': 'The exit status.', 'name': 'status', 'nargs': '?', 'required': False, 'value': 'STATUS', }, ], ) # Create the parser and completer. interactive_parser = parser.Parser(self.root, context=config.context, hidden=config.hidden) interactive_completer = completer.InteractiveCliCompleter( interactive_parser=interactive_parser, args=args, cosh=self.coshell, hidden=config.hidden, manpage_generator=config.manpage_generator) # Make sure that complete_while_typing is disabled when # enable_history_search is enabled. (First convert to SimpleFilter, to # avoid doing bitwise operations on bool objects.) complete_while_typing = shortcuts.to_simple_filter(True) enable_history_search = shortcuts.to_simple_filter(False) complete_while_typing &= ~enable_history_search history_file = os.path.join(core_config.Paths().global_config_dir, 'shell_history') multiline = shortcuts.to_simple_filter(False) # Create the default buffer. self.default_buffer = pt_buffer.Buffer( enable_history_search=enable_history_search, complete_while_typing=complete_while_typing, is_multiline=multiline, history=pt_history.FileHistory(history_file), validator=None, completer=interactive_completer, auto_suggest=(auto_suggest.AutoSuggestFromHistory() if config.suggest else None), accept_action=pt_buffer.AcceptAction.RETURN_DOCUMENT, ) # Create the CLI. self.cli = CLI( config=config, cosh=cosh, root=self.root, interactive_parser=interactive_parser, application=self._CreatePromptApplication(config=config, multiline=multiline), eventloop=shortcuts.create_eventloop(), output=shortcuts.create_output(), ) self.key_bindings.Initialize(self.cli)
def __init__(self, cli=None, cosh=None, args=None, config=None): self.args = args self.coshell = cosh self.config = config self.key_bindings = bindings.KeyBindings( edit_mode=self.coshell.edit_mode == 'emacs') # Load the default CLI trees. self.root = cli_tree.LoadAll(cli=cli) # Add the exit command completer node to the CLI tree. self.root[parser.LOOKUP_COMMANDS]['exit'] = cli_tree.Node( command='exit', description='Exit the interactive shell.', positionals=[ { 'default': '0', 'description': 'The exit status.', 'name': 'status', 'nargs': '?', 'required': False, 'value': 'STATUS', }, ], ) # Create the parser and completer. shell_parser = parser.Parser( self.root, context=config.context, hidden=config.hidden) shell_completer = completer.ShellCliCompleter(shell_parser=shell_parser, args=args, cosh=self.coshell, hidden=config.hidden) # Make sure that complete_while_typing is disabled when # enable_history_search is enabled. (First convert to SimpleFilter, to # avoid doing bitwise operations on bool objects.) complete_while_typing = shortcuts.to_simple_filter(True) enable_history_search = shortcuts.to_simple_filter(False) complete_while_typing &= ~enable_history_search history_file = os.path.join(core_config.Paths().global_config_dir, 'shell_history') multiline = shortcuts.to_simple_filter(False) # Create the default buffer. self.default_buffer = pt_buffer.Buffer( enable_history_search=enable_history_search, complete_while_typing=complete_while_typing, is_multiline=multiline, history=pt_history.FileHistory(history_file), validator=None, completer=shell_completer, auto_suggest=(auto_suggest.AutoSuggestFromHistory() if config.suggest else None), accept_action=pt_buffer.AcceptAction.RETURN_DOCUMENT, ) # Create the CLI. self.cli = CLI( config=config, cosh=cosh, root=self.root, shell_parser=shell_parser, application=self._CreatePromptApplication(config=config, multiline=multiline), eventloop=shortcuts.create_eventloop(), output=shortcuts.create_output(), ) self.key_bindings.Initialize(self.cli)