# -*- coding: utf-8 -*- # Nemubot is a modulable IRC bot, built around XML configuration files. # Copyright (C) 2012 Mercier Pierre-Olivier # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import imp import os import readline import shlex import sys import traceback from . import builtins class Prompt: def __init__(self): self.selectedServer = None self.HOOKS_CAPS = dict() self.HOOKS_LIST = dict() def add_cap_hook(self, name, call, data=None): self.HOOKS_CAPS[name] = (lambda d, t, c, p: call(d, t, c, p), data) def add_list_hook(self, name, call): self.HOOKS_LIST[name] = call def lex_cmd(self, line): """Return an array of tokens Argument: line -- the line to lex """ try: cmds = shlex.split(line) except: exc_type, exc_value, _ = sys.exc_info() sys.stderr.write(traceback.format_exception_only(exc_type, exc_value)[0]) return bgn = 0 # Separate commands (command separator: ;) for i in range(0, len(cmds)): if cmds[i][-1] == ';': if i != bgn: yield cmds[bgn:i] bgn = i + 1 # Return rest of the command (that not end with a ;) if bgn != len(cmds): yield cmds[bgn:] def exec_cmd(self, toks, context): """Execute the command Arguments: toks -- lexed tokens to executes context -- current bot context """ if toks[0] in builtins.CAPS: return builtins.CAPS[toks[0]](toks, context, self) elif toks[0] in self.HOOKS_CAPS: f, d = self.HOOKS_CAPS[toks[0]] return f(d, toks, context, self) else: print("Unknown command: `%s'" % toks[0]) return "" def getPS1(self): """Get the PS1 associated to the selected server""" if self.selectedServer is None: return "nemubot" else: return self.selectedServer.id def run(self, context): """Launch the prompt Argument: context -- current bot context """ ret = "" while ret != "quit" and ret != "reset" and ret != "refresh": try: line = input("\033[0;33m%s§\033[0m " % self.getPS1()) cmds = self.lex_cmd(line.strip()) for toks in cmds: try: ret = self.exec_cmd(toks, context) except: exc_type, exc_value, exc_traceback = sys.exc_info() traceback.print_exception(exc_type, exc_value, exc_traceback) except KeyboardInterrupt: print("") except EOFError: ret = "quit" print("quit") return ret != "quit" def hotswap(bak): p = Prompt() p.HOOKS_CAPS = bak.HOOKS_CAPS p.HOOKS_LIST = bak.HOOKS_LIST return p def reload(): import prompt.builtins imp.reload(prompt.builtins)