pmacs3/mode/javascript.py

143 lines
5.7 KiB
Python

import os.path
import time
import tab
from mode import Fundamental
from method.shell import Interact
from lex import Grammar, PatternRule, RegionRule, PatternMatchRule
from point import Point
class StringGrammar1(Grammar):
rules = [
PatternRule('octal', r'\\[0-7]{3}'),
PatternRule('hex', r'\\x[0-9a-fA-F]{2}'),
PatternRule('escaped', r'\\.'),
PatternRule('data', r'[^\\\']+'),
]
class StringGrammar2(Grammar):
rules = [
PatternRule('octal', r'\\[0-7]{3}'),
PatternRule('hex', r'\\x[0-9a-fA-F]{2}'),
PatternRule('escaped', r'\\.'),
PatternRule('data', r'[^\\\"]+'),
]
class RegexGrammar(Grammar):
rules = [
PatternRule('octal', r'\\[0-7]{3}'),
PatternRule('hex', r'\\x[0-9a-fA-F]{2}'),
PatternRule('escaped', r'\\.'),
PatternRule('data', r'[^/\\]+'),
]
chr1 = '[a-zA-Z_]'
chr2 = '[a-zA-Z_0-9]'
word = chr1 + chr2 + '*'
class JavascriptGrammar(Grammar):
rules = [
PatternRule('comment', '//.*$'),
RegionRule('comment', r'/\*', Grammar, '\*/'),
RegionRule('comment', r'<!--', Grammar, '-->'),
PatternRule('continuation', r'\\(?= *$)'),
PatternMatchRule('x', '(function)( +)(' + word + ')',
'js.reserved', 'spaces', 'js.function'),
PatternMatchRule('x', '(class|new)( +)(' + word + ')',
'js.reserved', 'spaces', 'js.class'),
PatternRule('js.reserved', '(?:abstract|as|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|function|get|goto|if|import|implements|include|instanceof|interface|in|is|namespace|native|new|null|package|private|protected|public|return|set|super|switch|synchronized|this|throws|throw|transient|true|try|typeof|use|var|void|volatile|while|with)(?!' + chr2 + ')'),
PatternRule('js.identifier', word),
PatternRule('js.integer', "(?:0|[1-9][0-9]*|0[0-7]+|0[xX][0-9a-fA-F]+)[lL]?"),
PatternRule('js.float', r"[0-9]+\.[0-9]*|\.[0-9]+|(?:[0-9]|[0-9]+\.[0-9]*|\.[0-9]+)[eE][\+-]?[0-9]+"),
PatternRule('eol', r'\n'),
PatternRule('spaces', ' +'),
PatternRule('delimiter', r'%=|&&=|&=|\(|\)|\*=|\+=|,|-=|\.{3}|\.|/=(?= |$)|::|:|;|<<=|>>=|>>>=|\?|\[|\]|^=|^^=|\{|\}|\|=|\|\|='),
# fucking javascript!
# their lexer grammar requires one-token look-behind in order to know
# whether a "/" starts a literal regex, or is part of a mathematical
# expression/assignment.
RegionRule('js.regex', r"(?<=[\(=:,]) */", RegexGrammar, "/[a-z]*"),
PatternRule('js.operator', r'!==|!=|!|%|&&|&|\*|\+\+|\+|--|-|/|<<=|<<|<=|<|===|==|=|>>>=|>>>|>>=|>>|>=|>|\\|\|\|'),
RegionRule('string', "'", StringGrammar1, "'"),
RegionRule('string', '"', StringGrammar2, '"'),
]
class JavascriptTabber2(tab.StackTabber2):
open_tokens = {'delimiter': {'{': '}', '(': ')', '[': ']'}}
close_tokens = {'delimiter': {'}': '{', ')': '(', ']': '['}}
control_tokens = {'js.keyword': {'if': 1, 'else': 1, 'while': 1,
'do': 1, 'for': 1}}
end_at_eof = False
end_at_tokens = {'delimiter': {';': 1}}
nocontinue_tokens = {'delimiter': {';': 1, ',': 1},
'comment': 1,
'comment.start': 1,
'comment.data': 1,
'comment.end': 1}
start_free_tokens = {'string.start': 'string.end'}
end_free_tokens = {'string.end': 'string.start'}
def is_base(self, y):
if y == 0: return True
highlighter = self.mode.window.buffer.highlights[self.mode.name]
if not highlighter.tokens[y]: return False
t = highlighter.tokens[y][0]
return t.name == 'js.reserved' and t.string == 'function'
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 RhinoStart(Interact):
args = []
reuse = True
def _execute(self, w, **vargs):
cmd = w.application.config.get('rhino.cmd', 'rhino')
Interact._execute(self, w, bname='*Rhino*', cmd=cmd)
class RhinoLoadFile(RhinoStart):
args = []
reuse = True
def _execute(self, w, **vargs):
RhinoStart._execute(self, w, **vargs)
b = w.application.get_buffer_by_name('*Rhino*')
path = os.path.realpath(w.buffer.path)
time.sleep(0.5)
b.pipe_write('load("env.js");\n')
time.sleep(0.5)
b.pipe_write('load("%s");\n' % path)
class Javascript(Fundamental):
name = 'Javascript'
extensions = ['.js']
grammar = JavascriptGrammar
tabbercls = JavascriptTabber2
commentc = '//'
opentokens = ('delimiter',)
opentags = {'(': ')', '[': ']', '{': '}'}
closetokens = ('delimiter',)
closetags = {')': '(', ']': '[', '}': '{'}
colors = {
'js.function': ('blue', 'default', 'bold'),
'js.class': ('magenta', 'default', 'bold'),
'js.reserved': ('cyan', 'default', 'bold'),
'js.regex.start': ('cyan', 'default', 'bold'),
'js.regex.data': ('cyan', 'default', 'bold'),
'js.regex.null': ('cyan', 'default', 'bold'),
'js.regex.octal': ('magenta', 'default', 'bold'),
'js.regex.escaped': ('magenta', 'default', 'bold'),
'js.regex.end': ('cyan', 'default', 'bold'),
}
config = {'rhino.cmd': 'rhino'}
actions = [RhinoStart, RhinoLoadFile]
_bindings = {
'close-paren': (')',),
'close-brace': ('}',),
'close-bracket': (']',),
}
install = Javascript.install