Galaxie Shell 0.2.6 documentation


Navigation:   | Index   | Search   | Top   | Up   |
Table of Content: |

© Copyright 2020-2024, Galaxie Shell Team.

Top » Module code » glxshell.lib.cmd

Source code for glxshell.lib.cmd

from glxshell.lib.columnize import columnize
import sys  # MiroPython doesn't yet have a string module
from glxshell.lib.argparse import ArgumentParser
from glxshell.lib.argparse import WrapperCmdLineArgParser
from glxshell.lib.path import expanduser, exists
import os
try:
    import subprocess
except ImportError:
    subprocess = None
#
# A generic class to build line-oriented command interpreters.
#
# Interpreters constructed with this class obey the following conventions:
#
# 1. End of file on input is processed as the command 'EOF'.
# 2. A command is parsed out of each line by collecting the prefix composed
#    of characters in the identchars member.
# 3. A command `foo' is dispatched to a method 'do_foo()'; the do_ method
#    is passed a single argument consisting of the remainder of the line.
# 4. Typing an empty line repeats the last command.  (Actually, it calls the
#    method `emptyline', which may be overridden in a subclass.)
# 5. There is a predefined `help' method.  Given an argument `topic', it
#    calls the command `help_topic'.  With no arguments, it lists all topics
#    with defined help_ functions, broken into up to three topics; documented
#    commands, miscellaneous help topics, and undocumented commands.
# 6. The command '?' is a synonym for `help'.  The command '!' is a synonym
#    for `shell', if a do_shell method exists.
# 7. If completion is enabled, completing commands will be done automatically,
#    and completing of commands args is done by calling complete_foo() with
#    arguments text, line, begidx, endidx.  text is string we are matching
#    against, all returned matches must begin with it.  line is the current
#    input line (lstripped), begidx and endidx are the beginning and end
#    indexes of the text being matched, which could be used to provide
#    different completion depending upon which position the argument is in.
#
# The `default' method may be overridden to intercept commands for which there
# is no do_ method.
#
# The `completedefault' method may be overridden to intercept completions for
# commands that have no complete_ method.
#
# The data member `self.ruler' sets the character used to draw separator lines
# in the help messages.  If empty, no ruler line is drawn.  It defaults to "=".
#
# If the value of `self.intro' is nonempty when the cmdloop method is called,
# it is printed out on interpreter startup.  This value may be overridden
# via an optional argument to the cmdloop() method.
#
# The data members `self.doc_header', `self.misc_header', and
# `self.undoc_header' set the headers used for the help function's
# listings of documented functions, miscellaneous topics, and undocumented
# functions respectively.
#
# ----------------------------------------------------------------------------
# This is a copy of python's Cmd, but leaves out features that aren't relevant
# or can't currently be implemented for MicroPython.
#
# One of the notable deviations is that since MicroPython strips doc strings,
# this means that that help by doc string feature doesn't work.
#
# completions have also been stripped out.


# import string, sys


parser_man = ArgumentParser(
    prog="man", description="The man utility shall write information about each of the name operands.", add_help=True
)
parser_man.add_argument(
    "name",
    nargs="?",
    help="A keyword or the name of a standard utility.",
)

PROMPT = "(Cmd) "
# IDENTCHARS = string.ascii_letters + string.digits + '_'
IDENTCHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"


[docs] class Cmd: """ A simple framework for writing line-oriented command interpreters. These are often useful for test harnesses, administrative tools, and prototypes that will later be wrapped in a more sophisticated interface. A Cmd instance or subclass instance is a line-oriented interpreter framework. There is no good reason to instantiate Cmd itself; rather, it's useful as a superclass of an interpreter class you define yourself in order to inherit Cmd's methods and encapsulate action methods. """ prompt = PROMPT identchars = IDENTCHARS ruler = "=" lastcmd = "" intro = None doc_leader = "" doc_header = "Documented commands (type man <topic>):" misc_header = "Miscellaneous help topics:" undoc_header = "Undocumented commands:" nohelp = "No manual entry for %s" use_rawinput = 1 def __init__(self, completekey='tab'): """ Instantiate a line-oriented interpreter framework. """ self.cmdqueue = [] self.completekey = completekey self.completion_matches = [] self.exit_code = 0 self.rc_file = ".glxshrc" self.logout_file = ".glxsh_logout" self.history_path = expanduser("~/.glxsh_history") self.history_length = 100
[docs] def cmdloop(self, intro=None): """ Repeatedly issue a prompt, accept input, parse an initial prefix off the received input, and dispatch to action methods, passing them the remainder of the line as argument. """ self.preloop() if self.use_rawinput and self.completekey: try: import readline self.old_completer = readline.get_completer() readline.set_completer(self.complete) readline.parse_and_bind(self.completekey + ": complete") # do not use - as delimiter self.old_delims = readline.get_completer_delims() readline.set_completer_delims(self.old_delims.replace("-", "")) readline.parse_and_bind("set colored-completion-prefix off") readline.parse_and_bind("set show-all-if-unmodified on") readline.parse_and_bind("set horizontal-scroll-mode on") if not exists(self.history_path): open(self.history_path, 'a+').close() readline.read_history_file(self.history_path) readline.set_history_length(self.history_length) except ImportError: pass try: if intro is not None: self.intro = intro if self.intro: sys.stdout.write(str(self.intro) + "\n") stop = None while not stop: if self.cmdqueue: line = self.cmdqueue.pop(0) else: if self.use_rawinput: try: sys.stdout.write(self.prompt) sys.stdout.flush() line = input() except EOFError: line = "EOF" except KeyboardInterrupt: sys.stdout.write("^C") sys.stdout.flush() line = "" else: try: sys.stdout.write(self.prompt) sys.stdout.flush() line = sys.stdin.readline() if not len(line): line = "EOF" else: line = line.rstrip("\r\n") except KeyboardInterrupt: sys.stdout.write("^C") sys.stdout.flush() line = "" line = self.precmd(line) stop = self.onecmd(line) stop = self.postcmd(stop, line) self.postloop() finally: if self.use_rawinput and self.completekey: try: import readline readline.set_completer(self.old_completer) readline.set_completer_delims(self.old_delims) readline.write_history_file(self.history_path) except ImportError: pass return self.exit_code
[docs] def precmd(self, line): """ Hook method executed just before the command line is interpreted, but after the input prompt is generated and issued. """ return line
[docs] def postcmd(self, stop, line): """ Hook method executed just after a command dispatch is finished. """ return stop
[docs] def preloop(self): """ Hook method executed once when the cmdloop() method is called. """ pass
[docs] def postloop(self): """ Hook method executed once when the cmdloop() method is about to return. """ pass
[docs] def parseline(self, line): """ Parse the line into a command name and a string containing the arguments. Returns a tuple containing (command, args, line). 'command' and 'args' may be None if the line couldn't be parsed. """ line = line.strip() if not line: return None, None, line elif line[0] == "?": line = "man " + line[1:] elif line[0] == "!": if hasattr(self, "do_shell"): line = "shell " + line[1:] else: return None, None, line i, n = 0, len(line) while i < n and line[i] in self.identchars: i = i + 1 cmd, arg = line[:i], line[i:].strip() return cmd, arg, line
[docs] def onecmd(self, line): """ Interpret the argument as though it had been typed in response to the prompt. This may be overridden, but should not normally need to be; see the precmd() and postcmd() methods for useful execution hooks. The return value is a flag indicating whether interpretation of commands by the interpreter should stop. """ cmd, arg, line = self.parseline(line) if not line: return self.emptyline() if cmd is None: return self.default(line) self.lastcmd = line if line == "EOF": self.lastcmd = "" if cmd == "": return self.default(line) else: try: func = getattr(self, "do_" + cmd) except AttributeError: return self.default(line) return func(arg)
[docs] def onecmdhooks(self, line): self.onecmd(line) return self.exit_code
[docs] def emptyline(self): """ Called when an empty line is entered in response to the prompt. If this method is not overridden, it repeats the last nonempty command entered. """ if self.lastcmd: return self.onecmd(self.lastcmd)
[docs] def default(self, line): """ Called on an input line when the command prefix is not recognized. If this method is not overridden, it prints an error message and returns. """ sys.stdout.write("*** Unknown syntax: %s\n" % line)
[docs] def default_completer(self, *ignored): """ Method called to complete an input line when no command-specific complete_*() method is available. By default, it returns an empty list. """ return []
[docs] def completenames(self, text, *ignored): return ["%s " % a[3:] for a in self.get_names() if a.startswith("do_%s" % text)]
[docs] def complete(self, text, state): """ Return the next possible completion for 'text'. If a command has not been entered, then complete against command list. Otherwise try to call complete_<command> to get list of completions. """ if state == 0: import readline original_line = readline.get_line_buffer() line = original_line.lstrip() stripped = len(original_line) - len(line) start_index = readline.get_begidx() - stripped end_index = readline.get_endidx() - stripped if start_index > 0: cmd, args, foo = self.parseline(line) if cmd == "": complete_function = self.default_completer else: try: complete_function = getattr(self, "complete_" + cmd) except AttributeError: complete_function = self.default_completer else: complete_function = self.completenames self.completion_matches = complete_function(text, line, start_index, end_index) try: return self.completion_matches[state] except IndexError: return None
[docs] def get_names(self): # This method used to pull in base class attributes # at a time dir() didn't do it yet. return dir(self.__class__)
[docs] def complete_man(self, *args): commands = set([a[3:] for a in self.get_names() if a.startswith("do_" + args[0])]) topics = set(a[5:] for a in self.get_names() if a.startswith("help_" + args[0])) return list(commands | topics)
[docs] @staticmethod def help_man(): parser_man.print_help()
@WrapperCmdLineArgParser(parser_man) def do_man(self, arg, parsed): """ List available commands with "help" or detailed help with "help cmd". """ if parsed.help: self.help_man() return 0 if arg: # XXX check arg syntax try: func = getattr(self, "help_" + arg) except AttributeError: sys.stdout.write("%s\n" % str(self.nohelp % (arg,))) return 1 return func() else: names = self.get_names() cmds_doc = [] cmds_undoc = [] help = {} for name in names: if name[:5] == "help_": help[name[5:]] = 1 names.sort() # There can be duplicates if routines overridden prevname = "" for name in names: if name[:3] == "do_": if name == prevname: continue prevname = name cmd = name[3:] if cmd in help: cmds_doc.append(cmd) del help[cmd] else: cmds_undoc.append(cmd) sys.stdout.write("%s\n" % self.doc_leader) self.print_topics(self.doc_header, cmds_doc, 15, 80) self.print_topics(self.misc_header, list(help.keys()), 15, 80) if cmds_undoc != ['EOF']: self.print_topics(self.undoc_header, cmds_undoc, 15, 80) return 0
[docs] def print_topics(self, header, cmds, cmdlen, maxcol): if cmds: sys.stdout.write("%s\n" % header) if self.ruler: sys.stdout.write("%s\n" % str(self.ruler * len(header))) columnize(cmds, maxcol - 1) sys.stdout.write("\n")

Top » Module code » glxshell.lib.cmd

© Copyright 2020-2024, Galaxie Shell Team.
This page is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License (CC BY-NC-SA 4.0).
Examples, recipes, and other code in the documentation are additionally licensed under the Zero Clause BSD License.
See History and License for more information.

Last updated on None.
Created using Sphinx 8.0.2.