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