pmacs3/mode/awk.py

167 lines
6.9 KiB
Python

import os.path
from subprocess import Popen, PIPE, STDOUT
from mode import Fundamental
import default
from lex import Grammar, PatternRule, RegionRule, PatternMatchRule
from mode.python import StringGrammar2
from tab import StackTabber2
from method import Method, Argument, arg
from method.shell import Exec, Pipe
chr1 = '[a-zA-Z_]'
chr2 = '[a-zA-Z0-9_]'
word = chr1 + chr2 + '*'
class RegexGrammar(Grammar):
rules = [
PatternRule(r'escaped', r'\\.'),
PatternRule(r'data', r'[^\\/]+'),
]
class AwkGrammar(Grammar):
rules = [
PatternRule(r'comment', r'#.*\n$'),
PatternRule(r'spaces', r' +'),
RegionRule(r'awk_regex', r'/(?! )', RegexGrammar, r'/'),
PatternMatchRule('x', r'(function)( +)(' + word + ')',
'keyword', 'spaces', r'function'),
PatternRule(r'awk_global', r'(?:TEXTDOMAIN|SUBSEP|RLENGTH|RSTART|RT|RS|PROCINFO|ORS|OFS|OFMT|NR|NF|LINT|IGNORECASE|FS|FNR|FILENAME|FIELDWIDTHS|ERRNO|ENVIRON|CONVFMT|BINMODE|ARGV|ARGIND|ARGC)(?!' + chr2 + ')'),
PatternRule(r'delimiter', r'(?:[\{\}()\[\]?:;,]|=(?!=)|\+=|-=|\*=|/=|\%=|\^=)'),
PatternRule(r'keyword', r'(?:BEGIN|END|function|if|else|while|do|for|break|continue|delete|exit)(?!' + chr2 + ')'),
PatternRule(r'builtin', r'(?:return|close|getline|nextfile|next|printf|print|system|fflush|atan2|cos|exp|int|log|rand|sin|sqrt|srand|asorti|asort|gensub|gsub|index|length|match|split|sprintf|strtonum|substr|sub|tolower|toupper|mktime|strftime|systime|and|compl|lshift|or|xor|rshift|bindtextdomain|dcgettext|dcngettext|extension)(?!' + chr2 + ')'),
PatternRule(r'awk_field', r'\$\d*'),
PatternRule(r'number', r'-?0x[0-9A-Fa-f]+'),
PatternRule(r'number', r'-?0[0-7]*'),
PatternRule(r'number', r'-?[0-9]+\.?[0-9]*'),
PatternRule(r'number', r'-?\.[0-9]+'),
PatternRule(r'operator', r'!(?![=~])|--|\+\+'),
PatternRule(r'operator', r'(?:&&|\|\||<=|>=|!=|!~|==|\^|%|[-~/+*<>])'),
RegionRule(r'string', r'"', StringGrammar2, r'"'),
PatternRule(r'awk_function', word + '(?=\()'),
PatternRule(r'awk_identifier', word),
PatternRule(r'continuation', r'\\\n$'),
PatternRule(r'eol', r'\n'),
]
class AwkTabber(StackTabber2):
open_tokens = {'delimiter': {'{': '}', '(': ')', '[': ']'}}
close_tokens = {'delimiter': {'}': '{', ')': '(', ']': '['}}
control_tokens = {
'keyword': {'if': 1, 'else': 1, 'while': 1, 'do': 1, 'for': 1},
}
end_at_eof = True
end_at_tokens = {}
def _is_base(self, y):
if y == 0: return True
t = self._get_tokens(y)[0]
if t.fqname() == 'awk_regex.start': return True
if t.name in ('awk_field', 'awk_global'): return True
if t.name == 'keyword' and t.string in ('BEGIN', 'END'): return True
return False
def _is_indent(self, t): return t.name == 'spaces'
def _is_ignored(self, t): 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):
if not hasattr(w.buffer, 'path'):
w.set_error("Buffer %r has no program" % w.buffer.name())
return
elif w.buffer.changed():
w.set_error("Buffer %r is not saved" % w.buffer.name())
return
elif not os.path.exists(vargs['path']):
w.set_error("File %r not found" % vargs['path'])
return
cmd = 'awk -f %r %r' % (w.buffer.path, vargs['path'])
pipe = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT)
outdata = pipe.stdout.read()
status = pipe.wait() >> 8
w.application.data_buffer('*Awk-Output*', outdata, switch_to=True)
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'):
w.set_error("Buffer %r has no program" % w.buffer.name())
return
elif w.buffer.changed():
w.set_error("Buffer %r is not saved" % w.buffer.name())
return
elif not w.application.has_buffer_name(vargs['name']):
w.set_error("Buffer %r not found" % vargs['name'])
return
b = w.application.bufferlist.get_buffer_by_name(vargs['name'])
opts = w.application.config['awk.cmd-opts']
cmd = 'awk %s -f %r' % (opts, w.buffer.path)
pipe = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
pipe.stdin.write(b.make_string())
pipe.stdin.close()
output = pipe.stdout.read()
status = pipe.wait() >> 8
w.application.data_buffer('*Awk-Output*', output, switch_to=True)
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'):
w.set_error("Buffer %r has no program" % w.buffer.name())
return
elif w.buffer.changed():
w.set_error("Buffer %r is not saved" % w.buffer.name())
return
opts = w.application.config['awk.cmd-opts']
cmd = 'awk %s -f %r' % (opts, w.buffer.path)
pipe = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
pipe.stdin.write(vargs['input'])
pipe.stdin.close()
output = pipe.stdout.read()
status = pipe.wait() >> 8
w.application.data_buffer('*Awk-Output*', output, switch_to=True)
w.set_error("awk exited with status %d" % status)
class Awk(Fundamental):
name = 'awk'
tabbercls = AwkTabber
extensions = ['.awk']
grammar = AwkGrammar
opentokens = ('delimiter',)
opentags = {'(': ')', '[': ']', '{': '}'}
closetokens = ('delimiter',)
closetags = {')': '(', ']': '[', '}': '{'}
config = {'awk.cmd-opts': ""}
actions = [AwkFilterFile, AwkFilterBuffer, AwkFilterInput]
colors = {
'awk_global': ('yellow', 'default', 'bold'),
'awk_function': ('magenta', 'default', 'bold'),
'awk_field': ('yellow', 'default', 'bold'),
#'awk_identifier': ('yellow', 'default', 'bold'),
'awk_regex.start': ('cyan', 'default', 'bold'),
'awk_regex.null': ('cyan', 'default', 'bold'),
'awk_regex.data': ('cyan', 'default', 'bold'),
'awk_regex.end': ('cyan', 'default', 'bold'),
}
_bindings = {
'close-paren': (')',),
'close-brace': ('}',),
'close-bracket': (']',),
}
install = Awk.install