diff --git a/application.py b/application.py index d6e06a3..d8cc844 100755 --- a/application.py +++ b/application.py @@ -134,7 +134,7 @@ class Application(object): 'latex', 'insertmini', 'conf', 'haskell', 'erlang', 'iperl', 'iperlmini', 'ipython', 'ipythonmini', 'awk', 'bds', #XYZ - 'shell', 'shellmini', 'fstab' + 'shell', 'shellmini', 'fstab', 'yacc', ) for name in names: exec("import mode.%s; mode.%s.install(self)" % (name, name)) diff --git a/code_examples/ld_map_parser.y b/code_examples/ld_map_parser.y new file mode 100644 index 0000000..3cd6d4f --- /dev/null +++ b/code_examples/ld_map_parser.y @@ -0,0 +1,127 @@ +%{ +#include +#include +#include +#include + + + extern char* yytext; + + /*extern char * yylval;*/ + /* + Parser for linker map files. + */ + + void print_node(xmlNodePtr node) { + xmlDocPtr doc = NULL; + doc = xmlNewDoc("1.0"); + xmlDocSetRootElement(doc, node); + xmlSaveFile("ldmap.out.xml", doc); + } + +%} + +%union { + char* strn; + xmlNodePtr node; +}; + +%token SYMBOL LPAREN RPAREN HEX; +%token OBJ_FILE ARCH_FILE DYN_FILE; +%token HEADER ARCH_HEADER + +%type thingie file objfile archfile dynfile sym hexval head + +%type arch_section arch_list arch_entry + + +%% + +thingie: thingie file { printf("File: %s\n", $2); $$ = $2;} + | thingie sym { printf("Sym: %s\n", $2); $$ = $2;} + | thingie hexval { printf("Hex: %s\n", $2); $$ = $2;} + | thingie head { printf("Header: %s\n", $2); $$ = $2;} + | thingie arch_section { printf("Arch section:\n"); print_node($2); $$ = ""} + | thingie '(' { $$= "";} + | thingie ')' { $$= "";} + | thingie '*' { $$ = ""; } + | thingie ',' { $$ = ""; } + | thingie '=' { $$ = ""; } + | thingie '+' { $$ = ""; } + | thingie '&' { $$ = ""; } + | thingie '!' { $$ = ""; } + | thingie '?' { $$ = ""; } + | thingie ':' { $$ = ""; } + | { $$ = "end" } + ; + + + arch_section: ARCH_HEADER arch_list + { + $$ = xmlNewNode(NULL, "arch-section"); + xmlAddChild($$, $2); + } + +arch_list: +arch_list arch_entry arch_entry '(' sym ')' +{ + xmlNodePtr tmp; + tmp = xmlNewNode(NULL, "added"); + + /*$$ = $6; xmlAddChild($6, $1); */ + xmlAddChild(tmp, $2); + xmlAddChild(tmp, $3); + xmlNewProp(tmp, "symbol", $5); + xmlAddChild($1, tmp); + $$ = $1; +} + +| arch_list arch_entry file '(' sym ')' +{ + xmlNodePtr tmp; + tmp = xmlNewNode(NULL, "added"); + xmlAddChild(tmp, $2); + xmlNewChild(tmp, NULL, "file", $3); + xmlNewProp(tmp, "symbol", $5); + xmlAddChild($1, tmp); + $$ = $1; +} + +| {$$ = xmlNewNode(NULL, "arch-list")} + +arch_entry: archfile '(' file ')' +{ + $$= xmlNewNode(NULL, "archive"); + xmlNodeAddContent($$, $1); + xmlNewProp($$, "member", $3); +} + +file: objfile { $$ = $1; } + | archfile { $$ = $1; } + | dynfile { $$ = $1; }; + +dynfile: DYN_FILE { $$ = strdup(yytext); }; + +objfile: OBJ_FILE { $$ = strdup(yytext); }; + +archfile: ARCH_FILE { $$ = strdup(yytext); }; + +sym: SYMBOL { $$ = strdup(yytext); }; + +hexval: HEX { $$ = strdup(yytext); }; + +head: HEADER { $$ = strdup(yytext); }; + + +%% + +main() { + /* do {*/ + yyparse(); + /* } while (!feof(yyin) );*/ +} + +yyerror( char * s) { + + fprintf(stderr, "yyerror is: %s ; %s\n", s, yytext); +} diff --git a/mode/brm.py b/mode/brm.py new file mode 100644 index 0000000..ae9f645 --- /dev/null +++ b/mode/brm.py @@ -0,0 +1,156 @@ +import re, sets, string + +import color, method, minibuffer, mode, searchutil +from point import Point + +subgroup_re = re.compile(r'((?:\\\\)*)\\(0|[1-9][0-9]*)') + +class ReplaceOne(method.Method): + def execute(self, w, **vargs): + m = w.buffer.method + _replace(m) + _find_next(m, False) + _finish(m, w) + +class ReplaceDone(method.Method): + def execute(self, w, **vargs): + m = w.buffer.method + _replace(m) + _end(w) + w.set_error("Replace done") + +class SkipReplace(method.Method): + def execute(self, w, **vargs): + m = w.buffer.method + _find_next(m, True) + _finish(m, w) + +class ReplaceAll(method.Method): + def execute(self, w, **vargs): + m = w.buffer.method + while m.p1 is not None: + _replace(m) + _find_next(m, False) + _end(w) + w.set_error("Replace ended") + +class BrmCancel(method.Method): + def execute(self, w, **vargs): + _end(w) + w.set_error("BRM cancelled") + +def _find_next(m, move=False): + s = m.before + w = m.old_window + c = w.logical_cursor() + try: + if m.is_literal: + r = re.compile(searchutil.escape_literal(s)) + else: + r = re.compile(s) + except: + (m.p1, m.p2) = (None, None) + return False + + if move: + newc = searchutil.find_next(r, w, False, start=c.add(1, 0)) + else: + newc = searchutil.find_next(r, w, False, start=c.add(0, 0)) + + if newc: + (m.p1, m.p2, m.match) = newc + return True + else: + (m.p1, m.p2, m.match) = (None, None, None) + return False + +def _get_before(m): + if m.match is None: + return m.before + else: + return m.match.group(0) + +def _get_after(m): + if m.after is None: + return None + elif m.match is None: + return m.after + + def _repl(match): + (pre, num) = (match.group(1), int(match.group(2))) + if num == 0 or m.match.lastindex and num <= m.match.lastindex: + return pre + m.match.group(num) + else: + return match.group(0) + + return subgroup_re.sub(_repl, m.after) + +def _set_prompt(m): + w = m.old_window + if m.p1 is None: + #w.application.mini_prompt = '%r was not found' % m.before + w.application.mini_prompt = '[%r] %r was not found' % (m.p1, m.before) + return + (x, y) = m.p1.xy() + count = 0 + while y < len(w.buffer.lines): + count += w.buffer.lines[y][x:].count(m.before) + y += 1 + x = 0 + + after = _get_after(m) + before = _get_before(m) + + if count > 1: + p = 'Replace %r with %r [ynadq] (%d occurances)?' % (before, after, count) + elif count == 1: + p = 'Replace %r with %r [ynadq] (1 occurance)?' % (before, after) + elif count == 0: + p = 'Replace %r with %r [ynadq] (0 occurances)?' % (before, after) + #raise Exception("this can't happen") + else: + raise Exception("this REALLY can't happen") + w.application.mini_prompt = p + +def _replace(m): + m.old_window.buffer.delete(m.p1, m.p2) + if m.after: + after = _get_after(m) + m.old_window.buffer.insert_string(m.p1, after) + +def _finish(m, w): + if m.p1 is None: + _end(w) + w.set_error("Replace ended") + else: + _set_prompt(m) + +def _end(w): + w.application.close_mini_buffer() + w.application.clear_highlighted_ranges('search') + w.buffer.method.old_cursor = None + w.buffer.method.old_window = None + assert not w.application.mini_active + +class Brm(mode.Fundamental): + modename = 'Bicycle-Repairman' + actions = [ReplaceAll, ReplaceDone, ReplaceOne, SkipReplace, BrmCancel] + def __init__(self, w): + mode.Fundamental.__init__(self, w) + + self.actions = {} + self.bindings = {} + #self.add_bindings('replace-all', ('a', '!',)) + #self.add_bindings('replace-done', ('d',)) + #self.add_bindings('replace-one', ('y', 'SPACE',)) + #self.add_bindings('skip-replace', ('n', 'DELETE',)) + self.add_bindings('brm-cancel', ('q', 'RETURN', 'C-]', 'C-n', 'C-p', 'C-a', 'C-e', 'C-f', 'C-b', 'C-g')) + + m = w.buffer.method + found = _find_next(m, False) + if not found: + w.set_error('%r was not found' % m.before) + raise minibuffer.MiniBufferError + _set_prompt(m) + +install = Brm.install diff --git a/mode/c.py b/mode/c.py index 657db33..e36b592 100644 --- a/mode/c.py +++ b/mode/c.py @@ -63,7 +63,8 @@ class CGrammar(Grammar): PatternRule(r'char', r"'.'|'\\.'|'\\[0-7]{3}'"), PatternGroupRule(r'includegrp', r'macro.start', r'# *include', r'spaces', - r' +', r'header', r'< *[-A-Za-z/0-9_.]+ *>|" *[-A-Za-z/0-9_.]+ *"'), + r' +', r'header', r'< *[-A-Za-z/0-9_.]+ *>|" *[-A-Za-z/0-9_.]+ *"', + 'macro.end', r'\n$'), PatternRule(r'identifier', r"[a-zA-Z_][a-zA-Z0-9_]*"), diff --git a/mode/python.py b/mode/python.py index 5cb0544..5a4fcc6 100644 --- a/mode/python.py +++ b/mode/python.py @@ -1,8 +1,14 @@ import commands, os.path, sets, string, sys, traceback -import color, completer, context, default, mode, method, regex, tab +import color, completer, context, default, mode, method, regex, tab, method.introspect from point import Point from lex import Grammar, PatternRule, RegionRule, OverridePatternRule +try: + import bike + has_bike = True +except ImportError: + has_bike = False + class StringGrammar1(Grammar): rules = [ PatternRule(r'octal', r'\\[0-7]{3}'), @@ -365,6 +371,33 @@ class PythonListNames(method.Method): output = '\n'.join(sorted(names)) + "\n" w.application.data_buffer("*Python-List-Names*", output, switch_to=True) +class PythonBrmFindReferences(method.Method): + def _execute(self, w, **vargs): + if w.mode.brm is None: + w.set_error('bicycle repairman not installed') + return + path = w.buffer.path + cursor = w.logical_cursor() + y, x = cursor.yx() + refs = w.mode.brm.findReferencesByCoordinates(path, y, x) + lines = [] + n = 0 + for r in refs: + f, n, c = r.filename, r.lineno, r.confidence + s = '%s:%d: %3d%% confidence' % (f, n, c) + lines.append(s) + n += 1 + if n == 0: + w.set_error('no references found') + return + + data = '\n'.join(lines) + w.application.data_buffer("*References*", data, switch_to=True) + if n == 1: + w.set_error('1 reference found') + else: + w.set_error('%d references found' % n) + class PythonNameCompleter(completer.Completer): def _get_dict(self, w): return w.buffer.method.old_window.mode.context.get_names() @@ -502,7 +535,7 @@ class Python(mode.Fundamental): } actions = [PythonInitNames, PythonListNames, PythonGotoName, PythonGotoFunction, PythonGotoClass, PythonCheckSyntax, - PythonDictCleanup, PythonSemanticComplete, + PythonDictCleanup, PythonSemanticComplete, PythonBrmFindReferences, PythonInsertTripleSquotes, PythonInsertTripleDquotes] completers = { "pythonname": PythonNameCompleter(None), @@ -533,4 +566,10 @@ class Python(mode.Fundamental): self.add_bindings('python-semantic-complete', ('C-c TAB',)) self.context = PythonContext(self) + # bicycle repairman! + if has_bike: + self.brm = bike.init() + else: + self.brm = None + install = Python.install diff --git a/mode/yacc.py b/mode/yacc.py new file mode 100644 index 0000000..701ac86 --- /dev/null +++ b/mode/yacc.py @@ -0,0 +1,51 @@ +import color, mode, tab +from lex import Grammar, PatternRule, RegionRule +from mode.c import C, CGrammar, CTabber2 + +_rules = list(CGrammar.rules) +_rules.insert(0, PatternRule(r"yacc_directive", r"^%[a-zA-Z_]+")) +_rules.insert(1, PatternRule(r"yacc_section", r"%%")) +_rules.insert(2, PatternRule(r"yacc_delimiter", r"%{|%}")) +_rules.insert(3, PatternRule(r"yacc_production", r"^[a-z_]+:")) +_rules.insert(4, PatternRule(r"yacc_var", r"\$[0-9\$]")) +_rules.insert(5, PatternRule(r"yacc_empty", r"^ +\n$")) + +class TrueDict(dict): + def __contains__(self, k): return True + def __getitem__(self, k): return True + def __setitem__(self, k): pass + def __delitem__(self, k): raise Exception, 'not possible' + def __len__(self): return 1 + def __repr__(self): return '' + def get(self, k): return True + +class YaccGrammar(CGrammar): + rules = _rules + +class YaccTabber(CTabber2): + open_tokens = {'delimiter': {'{': '}', '(': ')', '[': ']'}, + 'yacc_delimiter': {'%{': '%}'}} + close_tokens = {'delimiter': {'}': '{', ')': '(', ']': '['}, + 'yacc_delimiter': {'%}': '%{'}} + control_tokens = {'yacc_production': TrueDict()} + scope_tokens = {} + end_at_eof = False + end_at_tokens = {'yacc_empty': TrueDict()} + nocontinue_tokens = {} + start_free_tokens = {'string.start': 'string.end'} + end_free_tokens = {'string.end': 'string.start'} + +class Yacc(mode.Fundamental): + modename = 'yacc' + extensions = ['.y'] + grammar = YaccGrammar + tabbercls = YaccTabber + colors = { + 'yacc_directive': ('yellow', 'default', 'bold'), + 'yacc_section': ('yellow', 'default', 'bold'), + 'yacc_delimiter': ('yellow', 'default', 'bold'), + 'yacc_production': ('yellow', 'default', 'bold'), + 'yacc_var': ('yellow', 'default', 'bold'), + } + +install = Yacc.install diff --git a/tab.py b/tab.py index d8a8403..4c3a833 100644 --- a/tab.py +++ b/tab.py @@ -296,7 +296,7 @@ class StackTabber2(Tabber): def _match(self, *names): return self.stack and self.stack[-1].name in names def _nomatch(self, *names): - return self.stack and self.stack[-1].name not in names + return not self.stack or self.stack[-1].name not in names def _pop(self, *names): if self._match(*names): self.stack.pop() @@ -408,6 +408,10 @@ class StackTabber2(Tabber): self._pop('macro') return + #d = self.end_at_tokens.get(name, {}) + #if d: + # raise Exception, (name, s, d, d.get(s), d[s]) + # remove implicit continuation if self.end_at_eof and i + start == end: self._pop_while('continue', 'control')