Merge branch 'history' into 'master'
History Fixes #8 See merge request !1
This commit is contained in:
commit
2dafa40734
81
console.py
Normal file
81
console.py
Normal file
@ -0,0 +1,81 @@
|
||||
import atexit
|
||||
import code
|
||||
import os
|
||||
import readline
|
||||
import shlex
|
||||
|
||||
from commands import registered_cmds
|
||||
import example_cmd
|
||||
|
||||
DEFAULT_HISTORY_FILE = "~/.psh_history"
|
||||
|
||||
|
||||
def parse_cmd(potential_cmd):
|
||||
"""Evaluates a potential command. If it exists in the list of
|
||||
registered commands, we return a string that would call the
|
||||
constructor for that command. If it does not exist, we wrap the
|
||||
name of the command with the RawCommand class.
|
||||
|
||||
:return: A string that when evaluated by Python's `eval` feature
|
||||
would build an object of the correct type
|
||||
"""
|
||||
args = potential_cmd.strip().split(' ')
|
||||
cmd_name = args[0]
|
||||
if args:
|
||||
args = args[1:]
|
||||
if cmd_name not in registered_cmds:
|
||||
return "RawCommand({})".format(shlex.split(potential_cmd))
|
||||
else:
|
||||
return "{0}({1})".format(cmd_name,str(args))
|
||||
|
||||
|
||||
def parse_cmds(raw_input_line):
|
||||
"""Parses command objects out of a single | separated string"""
|
||||
potential_cmds = raw_input_line.split('|')
|
||||
cmds = [parse_cmd(cmd) for cmd in potential_cmds]
|
||||
return cmds
|
||||
|
||||
|
||||
class HistoryConsole(code.InteractiveConsole):
|
||||
"""Stolen from https://docs.python.org/2/library/readline.html
|
||||
|
||||
Modified for the purposes of this project to handle special
|
||||
bash-like parsing"""
|
||||
|
||||
def __init__(self, locals=None, filename="<console>",
|
||||
histfile=os.path.expanduser(DEFAULT_HISTORY_FILE)):
|
||||
code.InteractiveConsole.__init__(self, locals, filename)
|
||||
self.init_history(histfile)
|
||||
|
||||
def init_history(self, histfile):
|
||||
readline.parse_and_bind("tab: complete")
|
||||
if hasattr(readline, "read_history_file"):
|
||||
try:
|
||||
readline.read_history_file(histfile)
|
||||
except IOError:
|
||||
pass
|
||||
atexit.register(self.save_history, histfile)
|
||||
|
||||
def raw_input(self, prompt=""):
|
||||
"""Gets a single line of input for the REPL, and returns some valid
|
||||
Python for the rest of the REPL to evaluate. It's the "R" in REPL.
|
||||
If the line begins with ">", we just strip it and evaluate as valid
|
||||
Python."""
|
||||
raw_input_line = input(prompt)
|
||||
if raw_input_line == "":
|
||||
return raw_input_line
|
||||
if raw_input_line[0] == '>':
|
||||
return raw_input_line[1:]
|
||||
else:
|
||||
cmds = parse_cmds(raw_input_line)
|
||||
cmds.append("Printer()")
|
||||
mangled_input = cmds[0]
|
||||
for cmd in cmds[1:]:
|
||||
mangled_input += ".chain(" + cmd + ")"
|
||||
mangled_input += ".call()"
|
||||
print("[DEBUG]: evaluating Python: ", mangled_input)
|
||||
return mangled_input
|
||||
|
||||
|
||||
def save_history(self, histfile):
|
||||
readline.write_history_file(histfile)
|
59
main.py
59
main.py
@ -1,11 +1,8 @@
|
||||
from commands import registered_cmds
|
||||
from raw_commands import RawCommand
|
||||
from formatters import Printer
|
||||
from example_cmd import example_cmd, echo
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import shlex
|
||||
|
||||
from formatters import *
|
||||
from raw_commands import RawCommand
|
||||
|
||||
# Load all of the commands in the path into the global namespace as raw
|
||||
# commands.
|
||||
@ -17,54 +14,10 @@ for path in os.environ['PATH'].split(':'):
|
||||
globals()[binary] = RawCommand(binary)
|
||||
|
||||
|
||||
def parse_cmd(potential_cmd):
|
||||
"""Evaluates a potential command. If it exists in the list of
|
||||
registered commands, we return a string that would call the
|
||||
constructor for that command. If it does not exist, we wrap the
|
||||
name of the command with the RawCommand class.
|
||||
|
||||
:return: A string that when evaluated by Python's `eval` feature
|
||||
would build an object of the correct type
|
||||
"""
|
||||
args = potential_cmd.strip().split(' ')
|
||||
cmd_name = args[0]
|
||||
if args:
|
||||
args = args[1:]
|
||||
if cmd_name not in registered_cmds:
|
||||
return "RawCommand({})".format(shlex.split(potential_cmd))
|
||||
else:
|
||||
return "{0}({1})".format(cmd_name,str(args))
|
||||
|
||||
|
||||
def parse_cmds(raw_input_line):
|
||||
"""Parses command objects out of a single | separated string"""
|
||||
potential_cmds = raw_input_line.split('|')
|
||||
cmds = [parse_cmd(cmd) for cmd in potential_cmds]
|
||||
return cmds
|
||||
|
||||
|
||||
def handle_input(prompt=""):
|
||||
"""Gets a single line of input for the REPL, and returns some valid
|
||||
Python for the rest of the REPL to evaluate. It's the "R" in REPL.
|
||||
If the line begins with ">", we just strip it and evaluate as valid
|
||||
Python."""
|
||||
raw_input_line = input(prompt)
|
||||
if raw_input_line[0] == '>':
|
||||
return raw_input_line[1:]
|
||||
else:
|
||||
cmds = parse_cmds(raw_input_line)
|
||||
cmds.append("Printer()")
|
||||
mangled_input = cmds[0]
|
||||
for cmd in cmds[1:]:
|
||||
mangled_input += ".chain(" + cmd + ")"
|
||||
mangled_input += ".call()"
|
||||
print("[DEBUG]: evaluating Python: ", mangled_input)
|
||||
return mangled_input
|
||||
|
||||
|
||||
def main():
|
||||
import code
|
||||
code.interact("Augmented Unix Userland", handle_input, globals())
|
||||
from console import HistoryConsole
|
||||
console = HistoryConsole(globals())
|
||||
console.interact("Augmented Unix Userland")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
21
tree.py
Normal file
21
tree.py
Normal file
@ -0,0 +1,21 @@
|
||||
class TreeNode(object):
|
||||
"""A tree node holds some data and has iterable children."""
|
||||
|
||||
def __init__(self, data):
|
||||
"""Initializes a data. The data can be any type, but it usually
|
||||
is an ordered dictionary."""
|
||||
self.parent = None
|
||||
self.data = data
|
||||
self.children = []
|
||||
|
||||
def add_child(self, child):
|
||||
"""Adds a child to the node."""
|
||||
child.parent = self
|
||||
self.children.apppend(child)
|
||||
|
||||
def children(self):
|
||||
"""Returns an iterable generator for all the children nodes."""
|
||||
def children_generator():
|
||||
for child in self.children:
|
||||
yield child
|
||||
return children_generator()
|
Reference in New Issue
Block a user