diff --git a/IDEAS b/IDEAS index dbf3905..4063af2 100644 --- a/IDEAS +++ b/IDEAS @@ -1,3 +1,15 @@ +2009/03/27: + +1. Create a Method attribute meaning should-appear-in-help-buffers. Use this to +hide actions that only make sense when the mini-buffer is open, as well as weird +actions like "text-insert-space" + +2. Create a way to figure out what actions are legal in the various mini-buffer +modes (search, replace, whatever). + +3. Maybe write a per-mode "how to use this mode" document that can be accessed +in a uniform way. This way, various non-discoverable features can be documented. + 2009/02/15: Remove $MODE.lib in favor of $MODE.libs[] diff --git a/method/__init__.py b/method/__init__.py index bfbdf0d..67d050b 100644 --- a/method/__init__.py +++ b/method/__init__.py @@ -341,6 +341,7 @@ class UppercaseWord(Method): w.insert_string(p1, word.upper()) class MetaX(Method): + '''Call pmacs functions by name (with or without arguments)''' args = [arg('method', dt="method", p="M-x ", h='Method to execute')] name_re = re.compile(r'[a-z0-9_-]+') @@ -572,6 +573,7 @@ class UncommentRegion(Method): # wrapping/justifying/etc class WrapLine(Method): + '''Wrap a line of text based on a predefined margin''' limit = 80 space_re = re.compile(' +') def _token_len(self, tokens): @@ -636,6 +638,7 @@ class WrapLine(Method): w.goto(Point(x, y)) class WrapParagraph(Method): + '''Wrap contiguous lines of text based on a predefined margin''' limit = 80 valid_re = re.compile('^( *)([^ ].*)$') empty_re = regex.whitespace @@ -854,31 +857,40 @@ class IndentBlock(Method): w.buffer.delete(Point(0, p1.y), Point(0, p2.y)) w.buffer.insert_string(Point(0, p1.y), '\n'.join(lines) + '\n') -class FileDiff(Method): +class Diff(Method): '''diff the buffer's contents with the given file''' - args = [arg("path", t=type(""), p="Filename: ", dt='path', - h="path to diff against current buffer's contents")] + args = [arg("path1", t=type(""), p="Filename: ", dt='path', h="left path to diff"), + arg("path2", t=type(""), p="Filename: ", dt='path', h="right path to diff")] + def _get_cmd(self, w, **vargs): + return ("/usr/bin/diff", '-u', vargs['path1'], vargs['path2']) + def _pipe_write(self, pipe, w, **vargs): + pass def _execute(self, w, **vargs): - cmd = ("/usr/bin/diff", '-u', '-', vargs['path']) + cmd = self._get_cmd(w, **vargs) pipe = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE) - pid = pipe.pid - - indata = w.buffer.make_string() - pipe.stdin.write(indata) - pipe.stdin.close() - + self._pipe_write(pipe, w, **vargs) outdata = pipe.stdout.read() errdata = pipe.stderr.read() - status = pipe.wait() >> 8 - + status = pipe.wait() if status == 0: - w.set_error("No difference found") + w.set_error("No difference found" + str(status)) elif status == 1: w.application.data_buffer("*Diff*", outdata, switch_to=True, modename='diff') w.set_error("Differences were found") else: w.application.data_buffer("*Diff*", errdata, switch_to=True) - w.set_error("There was an error: %d exited with status %s" % (pid, status)) + w.set_error("There was an error: %d exited with status %s" % (pipe.pid, status)) + +class FileDiff(Diff): + '''diff the buffer's contents with the given file''' + args = [arg("path", t=type(""), p="Filename: ", dt='path', + h="path to diff against current buffer's contents")] + def _get_cmd(self, w, **vargs): + return ("/usr/bin/diff", '-u', '-', vargs['path']) + def _pipe_write(self, pipe, w, **vargs): + indata = w.buffer.make_string() + pipe.stdin.write(indata) + pipe.stdin.close() class SetMode(Method): '''Set the mode of the current buffer''' @@ -915,8 +927,9 @@ class UnsplitWindow(Method): w.application.single_slot() w.set_error('Window has been unsplit back to one window!') -class CloseTag(Method): - mytag = ')' +class CloseParen(Method): + '''Insert ), matching if applicable''' + mytag = ')' def _execute(self, w, **vargs): # first, de-reference some variables and actually do the insertion # NOTE: we derence the cursor *before* inserting the character, so it is @@ -968,13 +981,10 @@ class CloseTag(Method): y -= 1 i = len(tokens[y]) - 1 -class CloseParen(CloseTag): - '''Insert ), matching if applicable''' - mytag = ')' -class CloseBrace(CloseTag): +class CloseBrace(CloseParen): '''Insert }, matching if applicable''' mytag = '}' -class CloseBracket(CloseTag): +class CloseBracket(CloseParen): '''Insert ], matching if applicable''' mytag = ']' @@ -982,8 +992,7 @@ class RegisterSave(Method): '''Save the top item of the kill stack into the named register''' MAX_TXT = 30 MAX_REG = 18 - args = [arg('name', dt="register", p="Register name: ", - h="Name of the register to use")] + args = [arg('name', dt="register", p="Register name: ", h="Register name to use")] def _pre_execute(self, w, **vargs): if not w.has_kill(): raise MethodError("No text on the kill stack") @@ -998,11 +1007,10 @@ class RegisterSave(Method): w.set_error('Saved %r into register %r' % (text, name)) class RegisterRestore(Method): - '''Push the value saved in the named register onto the kill stack''' + '''Push the value of the named register onto the kill stack''' MAX_TXT = 30 MAX_REG = 18 - args = [arg('name', dt="register", p="Register name: ", - h="Name of the register to use")] + args = [arg('name', dt="register", p="Register name: ", h="Register name to use")] def _execute(self, w, **vargs): name = vargs['name'] if name not in w.application.registers: @@ -1018,8 +1026,8 @@ class RegisterRestore(Method): 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')] + '''View the value of a particular config variables''' + args = [arg('name', dt='config', p="Config variable: ", h='Config variable name')] def _execute(self, w, **vargs): name = vargs['name'] if name in w.application.config: @@ -1029,6 +1037,7 @@ class GetConfigVariable(Method): w.set_error("param %r is not set" % (name,)) class ViewConfigVariables(Method): + '''View the value of all config variables''' def _execute(self, w, **vargs): lines = ["APPLICATION CONFIGURATION VARIABLES\n"] for name in w.application.config: @@ -1037,10 +1046,9 @@ class ViewConfigVariables(Method): 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')] + '''Set a particular config variable to a value''' + args = [arg('name', dt='config', p="Variable name: ", h='Config variable name'), + arg('value', t=type(''), p="Variable value: ", h='Config variable value')] def _execute(self, w, **vargs): name = vargs['name'] found = name in w.application.config @@ -1055,6 +1063,7 @@ class SetConfigVariable(Method): w.set_error("previously unset param %r set to %r" % (name, value)) class ToggleHeader(Method): + '''Toggle the visibility of the buffer header''' def _execute(self, w, **vargs): if w.mode.showing_header(): w.mode.disable_header() @@ -1063,7 +1072,9 @@ class ToggleHeader(Method): w.mode.enable_header() w.set_error('Header visible') +# TODO: rename to left-margin class ToggleLineNumbers(Method): + '''Toggle the visibility of the left margin''' def _execute(self, w, **vargs): if w.mode.showing_line_numbers(): w.mode.disable_line_numbers() @@ -1073,12 +1084,14 @@ class ToggleLineNumbers(Method): w.set_error('Line numbers visible') class SetTabWidth(Method): + '''Set the tab-width for the current buffer''' args = [arg('width', t=type(0), p="Tab Width: ", h='New tab width for buffer')] def _execute(self, w, **vargs): w.mode.tabwidth = vargs['width'] w.set_error('Tab width set to %d' % w.mode.tabwidth) class SetModeTabWidth(Method): + '''Set the default tab-width for the current mode''' args = [arg('mode', dt='mode', p="Mode: ", h=''), arg('width', t=type(0), p="Default Tab Width: ", h='New default tab width for mode')] def _execute(self, w, **vargs): diff --git a/mode/awk.py b/mode/awk.py index a70de33..5188b29 100644 --- a/mode/awk.py +++ b/mode/awk.py @@ -66,6 +66,7 @@ class AwkTabber(StackTabber2): return t.name in ('spaces', 'eol', 'comment') class AwkFilterFile(Exec): + '''Filter a file through the current buffer's AWK program''' show_success = True args = [arg('path', dt="path", p="Filter File: ", dv=default.path_dirname, ld=True, h="file to open")] def _execute(self, w, **vargs): @@ -87,6 +88,7 @@ class AwkFilterFile(Exec): w.set_error("awk exited with status %d" % status) class AwkFilterBuffer(Pipe): + '''Filter a buffer through the current buffer's AWK program''' args = [arg('name', dt="buffer", p="Filter Buffer: ", h="name of the buffer to switch to")] def _execute(self, w, **vargs): if not hasattr(w.buffer, 'path'): @@ -111,6 +113,7 @@ class AwkFilterBuffer(Pipe): w.set_error("awk exited with status %d" % status) class AwkFilterInput(Method): + '''Filter input through the current buffer's AWK program''' args = [arg('input', p="Data To Filter: ", h="data to filter")] def _execute(self, w, **vargs): if not hasattr(w.buffer, 'path'): diff --git a/mode/replace.py b/mode/replace.py index e9bd1fc..3b5e830 100644 --- a/mode/replace.py +++ b/mode/replace.py @@ -6,6 +6,7 @@ from point import Point subgroup_re = re.compile(r'((?:\\\\)*)\\(0|[1-9][0-9]*)') class ReplaceOne(method.Method): + 'In a replace command, replace the next occurance' def execute(self, w, **vargs): m = w.buffer.method _replace(m) @@ -13,6 +14,7 @@ class ReplaceOne(method.Method): _finish(m, w) class ReplaceDone(method.Method): + 'In a replace command, replace the next occurance and exit' def execute(self, w, **vargs): m = w.buffer.method _replace(m) @@ -20,12 +22,14 @@ class ReplaceDone(method.Method): w.set_error("Replace done") class SkipReplace(method.Method): + 'In a replace command, skip the next occurance' def execute(self, w, **vargs): m = w.buffer.method _find_next(m, True) _finish(m, w) class ReplaceAll(method.Method): + 'In a replace command, replace all remaining occurances' def execute(self, w, **vargs): m = w.buffer.method while m.p1 is not None: @@ -35,6 +39,7 @@ class ReplaceAll(method.Method): w.set_error("Replace ended") class CancelReplace(method.Method): + 'Cancel a currently running replace command' def execute(self, w, **vargs): _end(w) w.set_error("Replace cancelled") diff --git a/mode/search.py b/mode/search.py index 8437b68..e9227c7 100644 --- a/mode/search.py +++ b/mode/search.py @@ -20,6 +20,7 @@ def _make_regex(w, s): raise searchutil.IllegalPatternError("failed to compile: %r" % s) class SearchNext(method.Method): + 'In a search command, move to the next occurance' def execute(self, w, **vargs): w.buffer.method.direction = 'next' s = w.buffer.make_string() @@ -34,6 +35,7 @@ class SearchNext(method.Method): action.execute(w) class SearchPrevious(method.Method): + 'In a search command, move to the previous occurance' def execute(self, w, **vargs): w.buffer.method.direction = 'previous' if not w.buffer.make_string(): @@ -48,6 +50,7 @@ class SearchPrevious(method.Method): w.application.clear_highlighted_ranges('search') class EndSearch(method.Method): + 'End the current search command, leaving the cursor in place' def execute(self, w, **vargs): old_w = w.buffer.method.old_window old_c = w.buffer.method.old_cursor @@ -56,6 +59,7 @@ class EndSearch(method.Method): w.set_error("Mark set to search start") class CancelSearch(method.Method): + 'End the current search command, restoring the cursor to the search start' def execute(self, w, **vargs): w.buffer.method.old_window.goto(w.buffer.method.old_cursor) _end(w)