Viewing file: Snippet.py (9.98 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
# Gedit snippets plugin # Copyright (C) 2005-2006 Jesse van den Kieboom <jesse@icecrew.nl> # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
from SnippetPlaceholders import * import os from functions import *
class EvalUtilities: def __init__(self, view=None): self.view = view self.namespace = {} self.init_namespace() def init_namespace(self): self.namespace['__builtins__'] = __builtins__ self.namespace['align'] = self.util_align
def real_len(self, s, tablen = 0): if tablen == 0: tablen = self.view.get_tabs_width() return len(s.expandtabs(tablen))
def util_align(self, items): maxlen = [] tablen = self.view.get_tabs_width() for row in range(0, len(items)): for col in range(0, len(items[row]) - 1): if row == 0: maxlen.append(0) items[row][col] += "\t" rl = self.real_len(items[row][col], tablen) if (rl > maxlen[col]): maxlen[col] = rl
result = '' for row in range(0, len(items)): for col in range(0, len(items[row]) - 1): item = items[row][col] result += item + ("\t" * ((maxlen[col] - \ self.real_len(item, tablen)) / tablen)) result += items[row][len(items[row]) - 1] if row != len(items) - 1: result += "\n" return result
class Snippet: def __init__(self, data): self.data = data def __getitem__(self, prop): return self.data[prop] def __setitem__(self, prop, value): self.data[prop] = value def accelerator_display(self): accel = self['accelerator']
if accel: keyval, mod = gtk.accelerator_parse(accel) accel = gtk.accelerator_get_label(keyval, mod) return accel or ''
def display(self): nm = markup_escape(self['description']) tag = self['tag'] accel = self.accelerator_display() detail = [] if tag and tag != '': detail.append(tag) if accel and accel != '': detail.append(accel) if not detail: return nm else: return nm + ' (<b>' + markup_escape(str.join(', ', detail)) + \ '</b>)'
def add_placeholder(self, placeholders, placeholder): if placeholders.has_key(placeholder.tabstop): if placeholder.tabstop == -1: placeholders[-1].append(placeholder) else: # This would be an error, really.... None elif placeholder.tabstop == -1: placeholders[-1] = [placeholder] else: placeholders[placeholder.tabstop] = placeholder def updateLastInsert(self, view, index, lastInsert, text, mark, indent): if index - lastInsert > 0: buf = view.get_buffer() piter = buf.get_iter_at_mark(mark) lines = re.sub('\\\\(.)', '\\1', text[lastInsert:index]).split('\n') if len(lines) == 1: buf.insert(piter, spaces_instead_of_tabs(view, lines[0])) else: text = lines[0] + '\n' for i in range(1, len(lines)): text += indent + spaces_instead_of_tabs(view, lines[i]) + '\n'
buf.insert(piter, text[:-1])
lastInsert = index return lastInsert def substitute_environment(self, text, index, m): # make sure indentation is preserved if m.group(1) in os.environ: linestart = text.rfind('\n', 0, index) indentend = linestart + 1 while text[indentend].isspace() and not text[indentend] == '\n' \ and not text[indentend] == '\r': indentend += 1
indent = text[linestart + 1:indentend] lines = os.environ[m.group(1)].split('\n') insert = unicode.join('\n' + unicode(indent), lines) text = text[:index] + insert + text[index + \ len(m.group(0)):] return (text, index + len(insert)) else: return (text, index + len(m.group(0))) def parse_variables(self, text, index): # Environmental variable substitution s = text[index:] match = re.match('\\$([A-Z_]+)', s) or re.match('\\${([A-Z_]+)}', s) if match: text, index = self.substitute_environment(text, index, match) return text, index, match
def parse_placeholder(self, s): result = re.match('\\${([0-9]+)(:((\\\\:|\\\\}|[^:])+?))?}', s) or \ re.match('\\$([0-9]+)', s) return result and (result, SnippetPlaceholder) def parse_shell(self, s): result = re.match('`(([0-9]+):)?((\\\\`|[^`])+?)`', s) or \ re.match('\\$\\((([0-9]+):)?((\\\\\\)|[^`])+?)\\)', s) return result and (result, SnippetPlaceholderShell) def parse_eval(self, s): result = re.match('\\$<(([0-9, ]+):)?((\\\\>|[^>])+?)>', s) return result and (result, SnippetPlaceholderEval)
def parse_text(self, view, marks): placeholders = {} lastInsert = 0 index = 0 text = self['text'] buf = view.get_buffer()
indent = compute_indentation(view, \ view.get_buffer().get_iter_at_mark(marks[1]))
utils = EvalUtilities(view)
while index < len(text): c = text[index] match = None s = text[index:] if c == '\\': # Skip escapements index += 1 elif c == '`': match = self.parse_shell(s) elif c == '$': text, index, handled = self.parse_variables(text, index) if handled: continue
match = self.parse_placeholder(s) or \ self.parse_shell(s) or \ self.parse_eval(s)
if match: if index != lastInsert or index == 0: self.updateLastInsert(view, index, lastInsert, \ text, marks[1], indent) begin = buf.get_iter_at_mark(marks[1])
if match[1] == SnippetPlaceholderEval: refs = (match[0].group(2) and \ match[0].group(2).split(',')) placeholder = SnippetPlaceholderEval(view, \ refs, begin, match[0].group(3), \ utils.namespace) elif match[1] == SnippetPlaceholderShell: tabstop = (match[0].group(2) and \ int(match[0].group(2))) or -1 placeholder = SnippetPlaceholderShell(view, \ tabstop, begin, match[0].group(3)) else: tabstop = int(match[0].group(1)) default = match[0].lastindex >= 2 and \ re.sub('\\\\(.)', '\\1', match[0].group(3)) if tabstop == 0: # End placeholder placeholder = SnippetPlaceholderEnd(view, begin, default) elif placeholders.has_key(tabstop): # Mirror placeholder placeholder = SnippetPlaceholderMirror(view, \ tabstop, begin) else: # Default placeholder placeholder = SnippetPlaceholder(view, tabstop, \ default, begin) self.add_placeholder(placeholders, placeholder) index += len(match[0].group(0)) - 1 lastInsert = index + 1 index += 1 lastInsert = self.updateLastInsert(view, index, lastInsert, text, \ marks[1], indent)
# Create end placeholder if there isn't one yet if not placeholders.has_key(0): placeholders[0] = SnippetPlaceholderEnd(view, \ buf.get_iter_at_mark(marks[1]), None)
# Make sure run_last is ran for all placeholders and remove any # non `ok` placeholders for tabstop in placeholders.copy(): if tabstop == -1: # anonymous ph = list(placeholders[-1]) else: ph = [placeholders[tabstop]] for placeholder in ph: placeholder.run_last(placeholders) if not placeholder.ok: if placeholder.default: buf.delete(placeholder.begin_iter(), \ placeholder.end_iter()) placeholder.remove()
if placeholder.tabstop == -1: del placeholders[-1][placeholders[-1].index(\ placeholder)] else: del placeholders[placeholder.tabstop] # Remove all the Expand placeholders which have a tabstop because # they can be used to mirror, but they shouldn't be real tabstops # This is problably a bit of a dirty hack :) if not placeholders.has_key(-1): placeholders[-1] = []
for tabstop in placeholders.copy(): if tabstop != -1: if isinstance(placeholders[tabstop], SnippetPlaceholderExpand): placeholders[-1].append(placeholders[tabstop]) del placeholders[tabstop] return placeholders def insert_into(self, plugin_data): buf = plugin_data.view.get_buffer() insert = buf.get_iter_at_mark(buf.get_insert()) lastIndex = 0 # Find closest mark at current insertion, so that we may insert # our marks in the correct order (current, next) = plugin_data.next_placeholder() if current: # Insert AFTER current lastIndex = plugin_data.placeholders.index(current) + 1 elif next: # Insert BEFORE next lastIndex = plugin_data.placeholders.index(next) else: # Insert at first position lastIndex = 0 # lastIndex now contains the position of the last mark # Create snippet bounding marks marks = (buf.create_mark(None, insert, True), \ buf.create_mark(None, insert, False), \ buf.create_mark(None, insert, False)) # Now parse the contents of this snippet, create SnippetPlaceholders # and insert the placholder marks in the marks array of plugin_data placeholders = self.parse_text(plugin_data.view, marks) # So now all of the snippet is in the buffer, we have all our # placeholders right here, what's next, put all marks in the # plugin_data.marks k = placeholders.keys() k.sort(reverse=True) plugin_data.placeholders.insert(lastIndex, placeholders[0]) lastIter = placeholders[0].end_iter() for tabstop in k: if tabstop != -1 and tabstop != 0: placeholder = placeholders[tabstop] endIter = placeholder.end_iter() if lastIter.compare(endIter) < 0: lastIter = endIter # Inserting placeholder plugin_data.placeholders.insert(lastIndex, placeholder) # Move end mark to last placeholder buf.move_mark(marks[1], lastIter) return (marks[0], marks[1], marks[2], placeholders)
|