import color, mode, tab import context from lex import Grammar, PatternRule, RegionRule, PatternMatchRule from mode.python import StringGrammar2 from mode.c import CTabber2 from parse import Any, And, Or, Optional, Name, Match, Matchs class CommentGrammar(Grammar): rules = [ PatternMatchRule(r'x', r'(@[a-z]+)( +)([^ ]+)', r'javadoc', r'spaces', r'javaname'), PatternRule(r"javadoc", r"@[a-z]+"), PatternRule(r"data", r"(?:[^@*]|\*(?!/))+"), ] class JavaGrammar(Grammar): rules = [ PatternRule(r"spaces", r" +"), PatternRule(r'import', r'(?<=import ) *[a-zA-Z0-9_.*]+'), PatternRule(r'package', r'(?<=package ) *[a-zA-Z0-9_.*]+'), RegionRule(r'java_comment', '/\*', CommentGrammar, '\*/'), PatternRule(r'java_comment', r'//.*$'), PatternRule(r'keyword', r"(?:abstract|assert|boolean|break|byte|case|catch|char|class|continue|default|double|do|else|extends|finally|final|float|for|if|implements|import|instanceof|interface|int|long|native|new|package|private|protected|public|return|short|static|switch|super|synchronized|threadsafe|throws|throw|transient|try|void|while)(?![a-zA-Z_])"), PatternRule(r'java_label', r'[a-zA-Z_][a-zA-Z0-9_]*(?=:)'), PatternRule(r'java_builtin', r"(?:null|true|false|this)"), PatternRule(r'identifier', r"[a-zA-Z_][a-zA-Z0-9_]*"), PatternRule(r"unop", r"\+=|-=|\*=|/=|//=|%=|&=\|\^=|>>=|<<=|\*\*="), PatternRule(r'binop', r"\+|<>|<<|<=|<|-|>>|>=|>|\*\*|&|\*|\||/|\^|==|//|~|!=|%"), PatternRule(r"delimiter", r"->|\.|\(|\)|\[|\]|{|}|@|,|:|`|;|=|\?"), PatternRule(r"java_integer", r"(?:0(?![x0-9])|[1-9][0-9]*|0[0-7]+|0[xX][0-9a-fA-F]+)[lL]?"), PatternRule(r"java_float", r"[0-9]+\.[0-9]*|\.[0-9]+|(?:[0-9]|[0-9]+\.[0-9]*|\.[0-9]+)[eE][\+-]?[0-9]+"), RegionRule(r'string', '"', StringGrammar2, '"'), PatternRule(r'java_char', r"'.'|'\\.'|'\\[0-7]{3}'"), PatternRule(r"eol", r"\n$"), ] CLASS_MATCH = And(Optional(Name('spaces')), Matchs('keyword', ('public', 'protected', 'private')), Name('spaces'), Match('keyword', 'class'), Name('spaces'), Name('identifier')) CLASS_OFFSET = 1 METHOD_MATCH = And(Optional(Name('spaces')), Matchs('keyword', ('public', 'protected', 'private')), Name('spaces'), Optional(And(Match('keyword', 'static'), Name('spaces'))), Any(), Name('spaces'), Name('identifier'), Optional(Name('spaces')), Match('delimiter', '(')) METHOD_OFFSET = 2 class JavaTabber2(tab.StackTabber2): open_tokens = {'delimiter': {'{': '}', '(': ')', '[': ']'}} close_tokens = {'delimiter': {'}': '{', ')': '(', ']': '['}} control_tokens = {'keyword': {'if': 1, 'else': 1, 'while': 1, 'do': 1, 'for': 1}} end_at_eof = False end_at_tokens = {'delimiter': {';': 1}} nocontinue_tokens = {'delimiter': {';': 1}, 'java_comment.start': 1, 'java_comment.data': 1, 'java_comment.end': 1} start_free_tokens = {'string.start': 'string.end'} end_free_tokens = {'string.end': 'string.start'} def is_base(self, y): return y == 0 def _is_indent(self, t): return t.name == 'spaces' def _is_ignored(self, t): return t.fqname() in ('spaces', 'eol', 'comment', 'comment.start', 'comment.data', 'comment.null', 'comment.end') class JavaContext(context.Context): class_match = CLASS_MATCH class_offset = CLASS_OFFSET method_match = METHOD_MATCH method_offset = METHOD_OFFSET def _regen_stack(self, y): if y > 0 and self.namelines[y - 1][1]: return list(self.namelines[y - 1][1]) else: return [] def _build_name_map(self, y1, y2, last, curr, stack): highlights = self.mode.window.get_highlighter() i = y1 while i < y2: if not stack: curr = None tokens = highlights.tokens[i] result = self.class_match.match(tokens) if result: curr = tokens[result[0] - self.class_offset].string result = self.method_match.match(tokens) if result: curr = tokens[result[0] - self.method_offset].string if curr is not None: self.names.setdefault(curr, i) for t in tokens: if t.match('delimiter', '{'): stack.append(curr) elif t.match('delimiter', '}'): if stack: stack.pop(-1) if stack: curr = stack[-1] else: curr = None if curr: self.namelines[i] = (curr, tuple(stack)) i += 1 class Java(mode.Fundamental): name = 'Java' extensions = ['.java'] tabbercls = JavaTabber2 grammar = JavaGrammar commentc = '//' opentokens = ('delimiter',) opentags = {'(': ')', '[': ']', '{': '}'} closetokens = ('delimiter',) closetags = {')': '(', ']': '[', '}': '{'} colors = { 'java_comment.start': ('red', 'default', 'bold'), 'java_comment.end': ('red', 'default', 'bold'), 'java_comment.javadoc': ('magenta', 'default', 'bold'), 'java_comment.javaname': ('yellow', 'default', 'bold'), 'java_comment.data': ('red', 'default', 'bold'), 'java_comment.null': ('red', 'default', 'bold'), 'import': ('blue', 'default', 'bold'), 'java_label': ('magenta', 'default', 'bold'), 'java_builtin': ('magenta', 'default', 'bold'), 'java_char': ('green', 'default', 'bold'), 'java_integer': ('green', 'default', 'bold'), 'java_float': ('green', 'default', 'bold'), } format = "%(flag)s %(bname)-18s (%(mname)s) %(indent)s %(cursor)s/%(mark)s %(perc)s [%(func)s]" def get_status_names(self): names = mode.Fundamental.get_status_names(self) c = self.window.logical_cursor() names['func'] = self.get_line_function(c.y) return names 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.context = JavaContext(self) def get_functions(self): return self.context.get_names() def get_function_names(self): return self.context.get_name_list() def get_line_function(self, y): return self.context.get_line_name(y) install = Java.install