diff --git a/IDEAS b/IDEAS index cfac716..f14fdbc 100644 --- a/IDEAS +++ b/IDEAS @@ -22,10 +22,6 @@ buffer, rather than storing all this junk piecemeal. 2007/07/19: -Convert all classes to subclass object. - -2007/07/19: - The minibuffer should be able to expand to become multi-line if the prompt/input string becomes too long. @@ -34,6 +30,8 @@ prompt/input string becomes too long. It would be nice to be able to toggle various lexing rules on/off, so that for instance text mode could make spell checking optional, or optionally highlight URLs/emails/etc. +AMENDED (2008/03/20): in the case of spell-checking and other non-standard +rules, we can do this with state variables in the mode. 2007/07/15: diff --git a/application.py b/application.py index 09e332a..15e955e 100755 --- a/application.py +++ b/application.py @@ -41,6 +41,7 @@ class Application(object): # initialize some basic stuff # each highlighted_range contains three things: (window, start_p, end_p) + self.config = {} self.highlighted_ranges = [] self.mini_active = False self.mini_buffer = None @@ -184,6 +185,7 @@ class Application(object): method.DATATYPES['buffer'] = completer.BufferCompleter(self) method.DATATYPES['command'] = completer.CommandCompleter() method.DATATYPES['shell'] = completer.ShellCompleter() + method.DATATYPES['config'] = completer.ConfigCompleter() method.DATATYPES['method'] = completer.MethodCompleter() method.DATATYPES['register'] = completer.RegisterCompleter() method.DATATYPES['mode'] = completer.ModeCompleter() diff --git a/completer.py b/completer.py index 1a8d682..7b109ba 100644 --- a/completer.py +++ b/completer.py @@ -94,6 +94,10 @@ class MethodCompleter(Completer): def get_candidates(self, s, w=None): return [n for n in w.application.methods if n.startswith(s)] +class ConfigCompleter(Completer): + def get_candidates(self, s, w=None): + return [n for n in w.application.config if n.startswith(s)] + class RegisterCompleter(Completer): def get_candidates(self, s, w=None): return [n for n in w.application.registers if n.startswith(s)] diff --git a/method/__init__.py b/method/__init__.py index 3f92cbd..337b08c 100644 --- a/method/__init__.py +++ b/method/__init__.py @@ -7,6 +7,7 @@ from point import Point DATATYPES = { "path": None, "buffer": None, + "config": None, "method": None, "register": None, "command": None, @@ -909,3 +910,36 @@ class RegisterRestore(Method): if len(name) > self.MAX_REG: name = name[0:self.MAX_REG] + '...' w.set_error('Restored %r from register %r' % (text, name)) + +class GetConfigVariable(Method): + args = [arg('name', dt='config', p="Variable name: ", + h='Name of the configuration parameter')] + def _execute(self, w, **vargs): + name = vargs['name'] + if name in w.application.config: + value = w.application.config[name] + w.set_error("param %s set to %r" % (name, value)) + else: + w.set_error("param %s is not set" % (name,)) + +class ViewConfigVariables(Method): + def _execute(self, w, **vargs): + lines = ["APPLICATION CONFIGURATION VARIABLES\n"] + for name in w.application.config: + lines.append(" %-20s %r\n" % (name, w.application.config[name])) + data = ''.join(lines) + w.application.data_buffer('*Config*', data, switch_to=True) + +class SetConfigVariable(Method): + args = [arg('name', dt='config', p="Variable name: ", + h='Name of the configuration parameter'), + arg('value', t=type(''), p="Variable value: ", + h='Configuration parameter value to use')] + def _execute(self, w, **vargs): + name, value = vargs['name'], vargs['value'] + found = name in w.application.config + w.application.config[name] = value + if found: + w.set_error("param %s set to %r" % (name, value)) + else: + w.set_error("previously unset param %s set to %r" % (name, value)) diff --git a/method/shell.py b/method/shell.py index cb332d0..1d508e5 100644 --- a/method/shell.py +++ b/method/shell.py @@ -8,20 +8,38 @@ from method import DATATYPES, Method, Argument class Exec(Method): '''Execute a command in a shell and put the output in a new buffer''' + show_success = True args = [Argument('cmd', prompt="Exec: ", datatype='shell')] - def _doit(self, w, path, cmd): + def _doit(self, w, path, cmd, cmdname=None, bufname=None): if path: try: cmd = cmd % {'path': path} except: pass - (status, output) = commands.getstatusoutput(cmd) - self._display(w, output, status, cmd) - def _display(self, w, data, status, cmd): - bufname = '*%s*' % self.name.title() - w.application.data_buffer(bufname, data, switch_to=True) - w.set_error("Shell exited with %d" % status) + if bufname is None: + bufname = '*%s*' % self.name.title() + if cmdname is None: + cmdname = cmd.split(None, 1)[0] + p = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT) + output = p.stdout.read() + result = p.wait() + status = os.WEXITSTATUS(result) + + if not os.WIFEXITED(result): + err = True + errmsg = "%s: killed by signal %r" % (cmdname, os.WTERMSIG(result)) + elif status != 0: + err = True + errmsg = "%s: failed with status %r" % (cmdname, status) + else: + err = False + errmsg = "%s: ok" % (cmdname,) + + if output: + switch_to = err or self.show_success + w.application.data_buffer(bufname, output, switch_to=switch_to) + w.set_error(errmsg) def _execute(self, w, **vargs): if w.buffer.btype == 'dir': diff --git a/mode/__init__.py b/mode/__init__.py index 870ea79..b6a3989 100644 --- a/mode/__init__.py +++ b/mode/__init__.py @@ -74,18 +74,19 @@ class Handler(object): class Fundamental(Handler): '''This is the default mode''' - modename = "Fundamental" - paths = [] - basenames = [] - extensions = [] - detection = [] - savetabs = False - tabwidth = 4 - tabbercls = None - grammar = None - lexer = None - tabber = None - colors = {} + modename = "Fundamental" + paths = [] + basenames = [] + extensions = [] + detection = [] + savetabs = False + tabwidth = 4 + tabbercls = None + grammar = None + lexer = None + tabber = None + colors = {} + config = {} def install(cls, app): app.setmode(cls.modename.lower(), cls, paths=cls.paths, @@ -97,6 +98,8 @@ class Fundamental(Handler): raise Exception, s else: app.token_colors[key] = val + for (key, val) in cls.config.iteritems(): + app.config[key] = val install = classmethod(install) def __init__(self, w): diff --git a/mode/c.py b/mode/c.py index cf7bcde..0dbe5a9 100644 --- a/mode/c.py +++ b/mode/c.py @@ -1,6 +1,6 @@ import os, re from subprocess import Popen, PIPE, STDOUT -import color, default, method, mode, tab +import color, default, method, method.shell, mode, tab from lex import Grammar, PatternRule, RegionRule, OverridePatternRule from mode.python import StringGrammar @@ -208,42 +208,32 @@ class C(mode.Fundamental): 'structname': ('yellow', 'default'), 'enumname': ('yellow', 'default'), } + config = { + 'c.syntaxcmd': "gcc -x c -fsyntax-only %(path)s", + 'c.makecmd': "make", + } def __init__(self, w): mode.Fundamental.__init__(self, w) self.add_bindings('close-paren', (')',)) self.add_bindings('close-brace', ('}',)) self.add_bindings('close-bracket', (']',)) + self.add_action_and_bindings(CCheckSyntax(), ('C-c s',)) self.add_action_and_bindings(CMake(), ('C-c C-c',)) - self.add_action_and_bindings(CSetMake(), ('C-c M-m',)) - self.makecmd = "make" -class CSetMake(method.Method): - '''Set the path(s) to find perl modules''' - args = [method.Argument("cmd", type=type(""), prompt="Make Cmd: ", - default=default.build_constant("make"))] +class CCheckSyntax(method.shell.Exec): + '''Build this C program (using the mode's make cmd)''' + show_success = False + args = [] def _execute(self, w, **vargs): - w.mode.makecmd = vargs['cmd'] - -class CMake(method.Method): - '''Check the syntax of the current python file''' + self._doit(w, w.buffer.path, w.application.config['c.syntaxcmd'], + cmdname='c-check-syntax') + +class CMake(method.shell.Exec): + '''Build this C program (using the mode's make cmd)''' + show_success = False + args = [] def _execute(self, w, **vargs): - p = Popen(w.mode.makecmd, stdout=PIPE) - output = p.stdout.read() - - result = p.wait() - status = os.WEXITSTATUS(result) - - if not os.WIFEXITED(result): - err = True - errmsg = "make: killed by signal %r" % os.WTERMSIG(result) - elif status != 0: - err = True - errmsg = "make: failed with status %r" % status - else: - err = False - errmsg = "make: OK (output in *CMake*)" - - w.application.data_buffer("*CMake*", output, switch_to=err) - w.set_error(errmsg) + self._doit(w, w.buffer.path, w.application.config['c.makecmd'], + cmdname='c-make') install = C.install