pmacs3/mode/java.py

179 lines
7.4 KiB
Python

import mode, tab
import context
from lex import Grammar, PatternRule, RegionRule, PatternMatchRule
from mode.python import StringGrammar2
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"(?:[^@*]|\*(?!/))+"),
]
chr1 = '[a-zA-Z_]'
chr2 = '[a-zA-Z0-9_]'
word1 = chr1 + chr2 + '*'
word2 = '(?:' + word1 + r'\.' + ')*' + word1
class JavaGrammar(Grammar):
rules = [
PatternRule(r"spaces", r" +"),
PatternMatchRule('x', r'(import)( +)(' + word2 + '(?:\.\*)?)', 'keyword', 'spaces', 'import'),
PatternMatchRule('x', r'(package)( +)(' + word2 + ')', 'keyword', 'spaces', 'package'),
PatternMatchRule('x', r'(class)( +)(' + word1 + ')', 'keyword', 'spaces', 'java_class'),
PatternMatchRule('x', '(new)( +)(' + word2 + ')', 'keyword', 'spaces', 'java_class'),
RegionRule(r'java_comment', '/\*', CommentGrammar, '\*/'),
PatternRule(r'comment', r'//.*$'),
PatternRule(r'keyword', r"(?:abstract|assert|break|case|catch|class|continue|default|do|else|extends|finally|final|for|if|implements|import|instanceof|interface|native|new|package|private|protected|public|return|static|switch|super|synchronized|threadsafe|throws|throw|transient|try|while)(?![a-zA-Z_])"),
PatternRule(r'java_label', r'[a-zA-Z_][a-zA-Z0-9_]*(?=:)'),
PatternMatchRule('x', '(' + word2 + ')((?:\[\])?)( +)(' + word1 + ')( *)(\()',
'java_type', 'delimiter', 'spaces', 'java_function', 'spaces', 'delimiter'),
PatternMatchRule('x', '(' + word2 + ')((?:\[\])?)( +)(' + word1 + ')(?! *\()',
'java_type', 'delimiter', 'spaces', 'identifier'),
PatternRule(r'java_builtin', r"(?:null|true|false|this)"),
PatternRule(r'identifier', word1),
PatternRule(r"operator", r"\+=|-=|\*=|/=|//=|%=|&=\|\^=|>>=|<<=|\*\*="),
PatternRule(r'operator', r"\+|<>|<<|<=|<|-|>>|>=|>|\*\*|&|\*|\||/|\^|==|//|~|!=|%"),
PatternRule(r"delimiter", r"->|\.|\(|\)|\[|\]|{|}|@|,|:|`|;|=|\?"),
PatternRule(r"integer", r"(?:0(?![x0-9])|[1-9][0-9]*|0[0-7]+|0[xX][0-9a-fA-F]+)[lL]?"),
PatternRule(r"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('java_class'))
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('java_function'),
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_class': ('green', 'default', 'bold'),
'java_label': ('magenta', 'default', 'bold'),
'java_builtin': ('magenta', 'default', 'bold'),
'java_char': ('green', 'default', 'bold'),
'java_function': ('blue', 'default', 'bold'),
'java_type': ('magenta', 'default', 'bold'),
}
_bindings = {
'close-paren': (')',),
'close-brace': ('}',),
'close-bracket': (']',),
}
format = "%(flag)s %(bname)-18s (%(mname)s) %(indent)s %(cursor)s/%(mark)s %(perc)s [%(func)s]"
def __init__(self, w):
mode.Fundamental.__init__(self, w)
self.context = JavaContext(self)
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 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