home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / lib / gedit-2 / plugins / snippets / Snippet.py < prev    next >
Encoding:
Python Source  |  2006-08-27  |  10.0 KB  |  361 lines

  1. #    Gedit snippets plugin
  2. #    Copyright (C) 2005-2006  Jesse van den Kieboom <jesse@icecrew.nl>
  3. #
  4. #    This program is free software; you can redistribute it and/or modify
  5. #    it under the terms of the GNU General Public License as published by
  6. #    the Free Software Foundation; either version 2 of the License, or
  7. #    (at your option) any later version.
  8. #
  9. #    This program is distributed in the hope that it will be useful,
  10. #    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. #    GNU General Public License for more details.
  13. #
  14. #    You should have received a copy of the GNU General Public License
  15. #    along with this program; if not, write to the Free Software
  16. #    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17.  
  18. from SnippetPlaceholders import *
  19. import os
  20. from functions import *
  21.  
  22. class EvalUtilities:
  23.     def __init__(self, view=None):
  24.         self.view = view
  25.         self.namespace = {}
  26.         self.init_namespace()
  27.     
  28.     def init_namespace(self):
  29.         self.namespace['__builtins__'] = __builtins__
  30.         self.namespace['align'] = self.util_align
  31.  
  32.     def real_len(self, s, tablen = 0):
  33.         if tablen == 0:
  34.             tablen = self.view.get_tabs_width()
  35.         
  36.         return len(s.expandtabs(tablen))
  37.  
  38.     def util_align(self, items):
  39.         maxlen = []
  40.         tablen = self.view.get_tabs_width()
  41.         
  42.         for row in range(0, len(items)):
  43.             for col in range(0, len(items[row]) - 1):
  44.                 if row == 0:
  45.                     maxlen.append(0)
  46.                 
  47.                 items[row][col] += "\t"
  48.                 rl = self.real_len(items[row][col], tablen)
  49.                 
  50.                 if (rl > maxlen[col]):
  51.                     maxlen[col] = rl
  52.  
  53.         result = ''
  54.         
  55.         for row in range(0, len(items)):
  56.             for col in range(0, len(items[row]) - 1):
  57.                 item = items[row][col]
  58.                 
  59.                 result += item + ("\t" * ((maxlen[col] - \
  60.                         self.real_len(item, tablen)) / tablen))
  61.             
  62.             result += items[row][len(items[row]) - 1]
  63.             
  64.             if row != len(items) - 1:
  65.                 result += "\n"
  66.         
  67.         return result
  68.  
  69. class Snippet:
  70.     def __init__(self, data):
  71.         self.data = data
  72.     
  73.     def __getitem__(self, prop):
  74.         return self.data[prop]
  75.     
  76.     def __setitem__(self, prop, value):
  77.         self.data[prop] = value
  78.     
  79.     def accelerator_display(self):
  80.         accel = self['accelerator']
  81.  
  82.         if accel:
  83.             keyval, mod = gtk.accelerator_parse(accel)
  84.             accel = gtk.accelerator_get_label(keyval, mod)
  85.         
  86.         return accel or ''
  87.  
  88.     def display(self):
  89.         nm = markup_escape(self['description'])
  90.         
  91.         tag = self['tag']
  92.         accel = self.accelerator_display()
  93.         detail = []
  94.         
  95.         if tag and tag != '':
  96.             detail.append(tag)
  97.             
  98.         if accel and accel != '':
  99.             detail.append(accel)
  100.         
  101.         if not detail:
  102.             return nm
  103.         else:
  104.             return nm + ' (<b>' + markup_escape(str.join(', ', detail)) + \
  105.                     '</b>)'
  106.  
  107.     def add_placeholder(self, placeholders, placeholder):
  108.         if placeholders.has_key(placeholder.tabstop):
  109.             if placeholder.tabstop == -1:
  110.                 placeholders[-1].append(placeholder)
  111.             else:
  112.                 # This would be an error, really....
  113.                 None
  114.         elif placeholder.tabstop == -1:
  115.             placeholders[-1] = [placeholder]
  116.         else:
  117.             placeholders[placeholder.tabstop] = placeholder
  118.     
  119.     def updateLastInsert(self, view, index, lastInsert, text, mark, indent):
  120.         if index - lastInsert > 0:
  121.             buf = view.get_buffer()
  122.             piter = buf.get_iter_at_mark(mark)
  123.             
  124.             lines = re.sub('\\\\(.)', '\\1', text[lastInsert:index]).split('\n')
  125.             
  126.             if len(lines) == 1:
  127.                 buf.insert(piter, spaces_instead_of_tabs(view, lines[0]))
  128.             else:
  129.                 text = lines[0] + '\n'
  130.             
  131.                 for i in range(1, len(lines)):
  132.                     text += indent + spaces_instead_of_tabs(view, lines[i]) + '\n'
  133.  
  134.                 buf.insert(piter, text[:-1])
  135.  
  136.             lastInsert = index
  137.             
  138.         return lastInsert
  139.     
  140.     def substitute_environment(self, text, index, m):
  141.         # make sure indentation is preserved
  142.         
  143.         if m.group(1) in os.environ:
  144.             linestart = text.rfind('\n', 0, index)
  145.             indentend = linestart + 1
  146.             
  147.             while text[indentend].isspace() and not text[indentend] == '\n' \
  148.                     and not text[indentend] == '\r':
  149.                 indentend += 1
  150.  
  151.             indent = text[linestart + 1:indentend]
  152.             lines = os.environ[m.group(1)].split('\n')
  153.             insert = unicode.join('\n' + unicode(indent), lines)
  154.             text = text[:index] + insert + text[index + \
  155.                     len(m.group(0)):]
  156.             
  157.             return (text, index + len(insert))
  158.         else:
  159.             return (text, index + len(m.group(0)))
  160.         
  161.     def parse_variables(self, text, index):
  162.         # Environmental variable substitution
  163.         s = text[index:]
  164.         match = re.match('\\$([A-Z_]+)', s) or re.match('\\${([A-Z_]+)}', s)
  165.                 
  166.         if match:
  167.             text, index = self.substitute_environment(text, index, match)
  168.         
  169.         return text, index, match
  170.  
  171.     def parse_placeholder(self, s):
  172.         result = re.match('\\${([0-9]+)(:((\\\\:|\\\\}|[^:])+?))?}', s) or \
  173.                 re.match('\\$([0-9]+)', s)
  174.         
  175.         return result and (result, SnippetPlaceholder)
  176.     
  177.     def parse_shell(self, s):
  178.         result = re.match('`(([0-9]+):)?((\\\\`|[^`])+?)`', s) or \
  179.                 re.match('\\$\\((([0-9]+):)?((\\\\\\)|[^`])+?)\\)', s)
  180.         
  181.         return result and (result, SnippetPlaceholderShell)
  182.     
  183.     def parse_eval(self, s):
  184.         result = re.match('\\$<(([0-9, ]+):)?((\\\\>|[^>])+?)>', s)
  185.         
  186.         return result and (result, SnippetPlaceholderEval)
  187.  
  188.     def parse_text(self, view, marks):
  189.         placeholders = {}
  190.         lastInsert = 0
  191.         index = 0
  192.         text = self['text']
  193.         buf = view.get_buffer()
  194.  
  195.         indent = compute_indentation(view, \
  196.                 view.get_buffer().get_iter_at_mark(marks[1]))
  197.  
  198.         utils = EvalUtilities(view)
  199.  
  200.         while index < len(text):
  201.             c = text[index]
  202.             match = None
  203.             s = text[index:]    
  204.                     
  205.             if c == '\\':
  206.                 # Skip escapements
  207.                 index += 1
  208.             elif c == '`':
  209.                 match = self.parse_shell(s)
  210.             elif c == '$':
  211.                 text, index, handled = self.parse_variables(text, index)
  212.                 
  213.                 if handled:
  214.                     continue
  215.  
  216.                 match = self.parse_placeholder(s) or \
  217.                         self.parse_shell(s) or \
  218.                         self.parse_eval(s)
  219.  
  220.             if match:
  221.                 if index != lastInsert or index == 0:
  222.                     self.updateLastInsert(view, index, lastInsert, \
  223.                             text, marks[1], indent)
  224.                     begin = buf.get_iter_at_mark(marks[1])
  225.  
  226.                     if match[1] == SnippetPlaceholderEval:
  227.                         refs = (match[0].group(2) and \
  228.                                 match[0].group(2).split(','))
  229.                         placeholder = SnippetPlaceholderEval(view, \
  230.                                 refs, begin, match[0].group(3), \
  231.                                 utils.namespace)
  232.                     elif match[1] == SnippetPlaceholderShell:
  233.                         tabstop = (match[0].group(2) and \
  234.                                 int(match[0].group(2))) or -1
  235.                         placeholder = SnippetPlaceholderShell(view, \
  236.                                 tabstop, begin, match[0].group(3))                        
  237.                     else:
  238.                         tabstop = int(match[0].group(1))
  239.                         default = match[0].lastindex >= 2 and \
  240.                                 re.sub('\\\\(.)', '\\1', match[0].group(3))
  241.                         
  242.                         if tabstop == 0:
  243.                             # End placeholder
  244.                             placeholder = SnippetPlaceholderEnd(view, begin,
  245.                                     default)
  246.                         elif placeholders.has_key(tabstop):
  247.                             # Mirror placeholder
  248.                             placeholder = SnippetPlaceholderMirror(view, \
  249.                                     tabstop, begin)
  250.                         else:
  251.                             # Default placeholder
  252.                             placeholder = SnippetPlaceholder(view, tabstop, \
  253.                                     default, begin)
  254.                         
  255.                     
  256.                     self.add_placeholder(placeholders, placeholder)
  257.                     index += len(match[0].group(0)) - 1
  258.                     lastInsert = index + 1
  259.                     
  260.             index += 1
  261.         
  262.         lastInsert = self.updateLastInsert(view, index, lastInsert, text, \
  263.                 marks[1], indent)
  264.  
  265.         # Create end placeholder if there isn't one yet
  266.         if not placeholders.has_key(0):
  267.             placeholders[0] = SnippetPlaceholderEnd(view, \
  268.                     buf.get_iter_at_mark(marks[1]), None)
  269.  
  270.         # Make sure run_last is ran for all placeholders and remove any
  271.         # non `ok` placeholders
  272.         for tabstop in placeholders.copy():
  273.             if tabstop == -1: # anonymous
  274.                 ph = list(placeholders[-1])
  275.             else:
  276.                 ph = [placeholders[tabstop]]
  277.             
  278.             for placeholder in ph:
  279.                 placeholder.run_last(placeholders)
  280.                 
  281.                 if not placeholder.ok:
  282.                     if placeholder.default:
  283.                         buf.delete(placeholder.begin_iter(), \
  284.                                 placeholder.end_iter())
  285.                     
  286.                     placeholder.remove()
  287.  
  288.                     if placeholder.tabstop == -1:
  289.                         del placeholders[-1][placeholders[-1].index(\
  290.                                 placeholder)]
  291.                     else:
  292.                         del placeholders[placeholder.tabstop]
  293.         
  294.         # Remove all the Expand placeholders which have a tabstop because
  295.         # they can be used to mirror, but they shouldn't be real tabstops
  296.         # This is problably a bit of a dirty hack :)
  297.         if not placeholders.has_key(-1):
  298.             placeholders[-1] = []
  299.  
  300.         for tabstop in placeholders.copy():
  301.             if tabstop != -1:
  302.                 if isinstance(placeholders[tabstop], SnippetPlaceholderExpand):
  303.                     placeholders[-1].append(placeholders[tabstop])
  304.                     del placeholders[tabstop]
  305.         
  306.         return placeholders
  307.     
  308.     def insert_into(self, plugin_data):
  309.         buf = plugin_data.view.get_buffer()
  310.         insert = buf.get_iter_at_mark(buf.get_insert())
  311.         lastIndex = 0
  312.         
  313.         # Find closest mark at current insertion, so that we may insert
  314.         # our marks in the correct order
  315.         (current, next) = plugin_data.next_placeholder()
  316.         
  317.         if current:
  318.             # Insert AFTER current
  319.             lastIndex = plugin_data.placeholders.index(current) + 1
  320.         elif next:
  321.             # Insert BEFORE next
  322.             lastIndex = plugin_data.placeholders.index(next)
  323.         else:
  324.             # Insert at first position
  325.             lastIndex = 0
  326.         
  327.         # lastIndex now contains the position of the last mark
  328.         # Create snippet bounding marks
  329.         marks = (buf.create_mark(None, insert, True), \
  330.                 buf.create_mark(None, insert, False), \
  331.                 buf.create_mark(None, insert, False))
  332.         
  333.         # Now parse the contents of this snippet, create SnippetPlaceholders
  334.         # and insert the placholder marks in the marks array of plugin_data
  335.         placeholders = self.parse_text(plugin_data.view, marks)
  336.         
  337.         # So now all of the snippet is in the buffer, we have all our 
  338.         # placeholders right here, what's next, put all marks in the 
  339.         # plugin_data.marks
  340.         k = placeholders.keys()
  341.         k.sort(reverse=True)
  342.         
  343.         plugin_data.placeholders.insert(lastIndex, placeholders[0])
  344.         lastIter = placeholders[0].end_iter()
  345.         
  346.         for tabstop in k:
  347.             if tabstop != -1 and tabstop != 0:
  348.                 placeholder = placeholders[tabstop]
  349.                 endIter = placeholder.end_iter()
  350.                 
  351.                 if lastIter.compare(endIter) < 0:
  352.                     lastIter = endIter
  353.                 
  354.                 # Inserting placeholder
  355.                 plugin_data.placeholders.insert(lastIndex, placeholder)
  356.         
  357.         # Move end mark to last placeholder
  358.         buf.move_mark(marks[1], lastIter)
  359.         
  360.         return (marks[0], marks[1], marks[2], placeholders)
  361.