def addline(env, args, kwargs): """[LINE,...] {file:filename}@Adds all LINEs to file filename. Note that newlines must be included.""" try: _file = kwargs["file"] if _file[0] not in ["/", "~"]: _file = os.path.join(env.directory, _file) for line in args: open(kwargs["file"], "a").write(line + "\n") return except KeyError: raise ErgonomicaError( "[ergo: ArgumentError]: No file set for addline.")
def rm(env, args, kwargs): """[FILE,...]@Remove FILEs (works for directories as well).""" for x in args: path = os.path.expanduser(x) if os.path.exists(path): if os.path.isdir(path): shutil.rmtree(path) else: os.remove(path) else: raise ErgonomicaError("[ergo: NoSuchFileOrDirectoryError]: '%s'." % (path))
def mkdir(env, args, kwargs): """[DIR,...]@Make DIRs.""" for directory in args: try: os.mkdir(os.path.expanduser(directory)) except OSError: if errno.EEXIST: if kwargs.get("overwrite") == 'true': shutil.rmtree(os.path.expanduser(directory)) os.mkdir(os.path.expanduser(directory)) else: raise ErgonomicaError( '[ergo: DirectoryExist]') # TODO issue #42
def cow(env, args, kwargs): """STRING@Make a cow say STRING.""" if len(args) == 1: string = args[0] s = " " + "_" * (len(string) + 2) + "\n" s += "< %s >\n" % string s += " " + "-" * (len(string) + 2) s += """ \\ ^__^ \\ (oo)\\_______ (__)\\ )\\/\\ ||----w | || ||""" return s else: raise ErgonomicaError( "[ergo: Wrong number of arguments for 'cow' command.")
def get_code_blocks(string): lines = string.split("\n") blocks = [] for line in lines: if line == "": pass elif line[0] != " ": blocks.append(line) else: if (not line.startswith(" ")) and (line.startswith(" ")): raise ErgonomicaError( "[ergo: SyntaxError]: Incorrect indentation on line '%s'." % line) else: blocks[-1] += "\n" + line[3:] return blocks
def cd(env, args, kwargs): """[DIR]@Changes to directory DIR. If none specified, changes to ~.""" try: if args == []: os.chdir(os.path.expanduser("~")) elif args[0][0] in ["~", "/"]: os.chdir(os.path.expanduser(args[0])) else: os.chdir(os.path.join(env.directory, args[0])) env.directory = os.getcwd() except OSError: _, error, _ = sys.exc_info() raise ErgonomicaError( "[ergo: NoSuchDirectoryError] No such directory '%s'. Perhaps it's a file?" % (re.findall(r"'(.*?)'", str(error))[0]))
def main(argc): """rm: Remove files and directories. Usage: rm FILE """ _file = argc.args['FILE'] if _file[0] == "/": path = _file elif _file[0] == "~": path = os.path.expanduser(_file) else: path = os.path.join(argc.env.directory, _file) if os.path.exists(path): if os.path.isdir(path): shutil.rmtree(path) else: os.remove(path) else: raise ErgonomicaError("[ergo: NoSuchFileOrDirectoryError]: '%s'." % (path))
def find(env, args, kwargs): """[DIR] {name:PATTERN}@Finds a file with name matching PATTERN. If no DIR specified, chooses current directory.""" try: pattern = kwargs["name"] except KeyError: pattern = "*" try: path = args[0] except IndexError: path = env.directory if not os.path.isdir(path): raise ErgonomicaError("[ergo: NoSuchDirectoryError]: No such directory '%s'." % (path)) result = [] for root, dirs, files in os.walk(path): for dir in dirs: if fnmatch.fnmatch(os.path.join(root, dir), pattern): result.append(os.path.join(root, dir)) for name in files: if fnmatch.fnmatch(name, pattern): result.append(os.path.join(root, name)) return [env.theme["files"] + x for x in list(set(result))]
def size(env, args, kwargs): """[FILE,...] {unit:UNIT}@Prints the size of each file. If unit specified, displays size in that unit (B, kB, MB,...).""" out = [] size_factor = 1 if "unit" in kwargs: unit = kwargs["unit"] if unit in SHORT_SIZES: size_factor = SHORT_SIZES.index(unit) elif unit in SIZES: size_factor = SIZES.index(unit) elif unit in NAME_SIZES: size_factor = NAME_SIZES.index(unit) for item in args: try: path = os.path.expanduser(item) if not os.path.exists(path): raise OSError size = file_or_dir_size(path) out.append(item + ": " + str(size / 1024 ** size_factor) + " " + SIZES[size_factor]) except OSError: raise ErgonomicaError("[ergo: NoSuchFileError]: No such file '%s'." % (item)) return out
def ergo_help(env, args, kwargs): """[COMMAND,...]@Display all ergonomica commands. If COMMANDs specified, returns the docstrings and arguments for them.""" out = "" if args == []: return globalization_query("help_welcome_message", env.LANG) for arg in args: if arg == "syntax": out += """In Ergonomica, commands are of the form command arg1 arg2,... {kwarg1:val1,kwarg2:val2,...} For example, finding all files in the root directory that match the regular expression 'e.*o': find / {name:e.*o} Note that you can call a command by the first three letters of its name. For example, instead of edit important_code.py you can type edi important_code.py If a command is not defined in Ergonomica, ergonomica will fallback to BASH (but with Ergonomica syntax). Arguments are the same. If a flag requires a value (like -f file), there will be a kwarg with that flag that takes that value. If it does not require a value, simply supply 't' or 'true' for the value. For example, the command git commit --interactive -m "Making the world a better place" The Ergonomica equivalent for this command would be git commit {-interactive:t,m:"Making the world a better place"} or git commit {-interactive:true,m:"Making the world a better place"} To "pipe" in Ergonomica, one uses the '->' symbol. Commands may be put together as a chain command1 -> command2 -> command3 The last command in the chain will have its output printed. Each command outputs "args", and certain operators (defined later) allow for piping of kwargs. To make a command accept the arguments from the last command, one uses --arg as one of the arguments. For example, to list all files and remove them, one would run ls -> rm --arg (analagous to) rm file1.txt file2.mp3,... To accept kwargs, one uses --kw. To process pipes of arguments, there are "operators", denoted by parenthases, e.g., (filter) x.endswith(".py") The available operators are: (map) python_expression: applies a python expression to each argument. For example, ls -> (map) x + ' is on my computer.' # adds ' is on my computer' to each directory listing (filter) python_expression: returns all arguments such that python_expression is true. For example, ifconfig -> (match) .*broadcast.* # shows lines that contain "broadcast" in ifconfig (ip address on wifi cards) (match) regular_expression: returns all arguments that match regexp regular_expression. For example, ls -> (match) .*\.py # display all .py files (reverse): reverses all arguments (splice): splice arguments from last and current pipes. For example, echo a b -> echo c d -> (splice) # returns a c b d (split): splits all arguments by spaces and flattens list echo "hello world" -> (splice) # returns hello world (kw): sets each first argument to the value of the second in kwargs. For example, echo a 2 b 3 -> (kw) -> set --kw # sets a to 2 and b to 3\n\n""" elif arg == "commands": pruned_verbs = {} for item in env.verbs: if item not in pruned_verbs: pruned_verbs[item] = env.verbs[item] for item in pruned_verbs: docstring = env.verbs[item].__doc__.split("@") out += "%-36s | %29s\n" % (item + " " + docstring[0], docstring[1]) elif arg in env.verbs: docstring = env.verbs[arg].__doc__.split("@") out += "%-26s | %29s\n" % (arg + " " + docstring[0], docstring[1]) else: print("arg is", arg) raise ErgonomicaError( "[ergo: HelpError]: No such help directive '%s'." % (arg)) return out + "\nVisit https://github.com/ergonomica/ergonomica/wiki for more documentation."
def run_operator(block, pipe): operator = get_operator(block) # (map) -- map an operator to a list of operands if operator == "map": try: func = eval("lambda x: " + block.replace("(map)", "")) except Exception as error: raise ErgonomicaError( "[ergo: OperatorError]: Error in parsing command for operator 'map'." + str(error)) try: out = list(pool.map(func, pipe.getstack_args(-1))) except TypeError: if pipe.getstack_args(-1) is None: raise ErgonomicaError( "[ergo: OperatorError]: Error in parsing command for operator 'map'." ) except Exception as error: raise ErgonomicaError("[ergo: OperatorError]: " + (str(error))) #raise error return out #return pipe.args[-1] # (filter) -- return all arguments that match the specified function elif operator == "filter": try: func = eval("lambda x: " + block.replace("(filter)", "")) except SyntaxError: raise ErgonomicaError( "[ergo: OperatorError]: SyntaxError in operator 'filter'.") pipe.lastlast_args = pipe.getstack_args(-1) try: out = pool_filter(func, pipe.getstack_args(-1)) except TypeError as error: if pipe.getstack_args(-1) is None: raise ErgonomicaError( "[ergo: OperatorError]: No arguments provided to operator 'filter'." ) raise error return out # (match) -- return all arguments that match the specified regexp elif operator == "match": exp = block.replace("(match)", "").strip() pool_filter(lambda x: re.findall(exp, x.strip()), pipe.getstack_args(-1)) # (reverse) -- reverse the order of all arguments elif operator == "reverse": return pipe.getstack_args(-1)[::-1] # (splice) -- splice the last and 2nd last argument lists together elif operator == "splice": return list( filter( None, sum( izip_longest(pipe.getstack_args(-2), pipe.getstack_args(-1)), ()))) # (split) -- split input strings by spaces elif operator == "split": return [ item for sublist in [x.split() for x in pipe.getstack_args(-1)] for item in sublist ] # (kw) -- map the last and 2nd last argument lists into a dictionary elif operator == "kw": pipe.setstack_kwargs({ pipe.getstack_args(-1)[i]: pipe.getstack_args(-1)[i + 1] for i in range(len(pipe.getstack_args(-1)) - 1) }) return pipe.getstack_kwargs(-1) else: return False