home *** CD-ROM | disk | FTP | other *** search
/ Freelog 125 / Freelog_MarsAvril2015_No125.iso / Bureautique / OpenOffice / Apache_OpenOffice_4.1.1_Win_x86_install_fr.exe / openoffice1.cab / ParenMatch.py < prev    next >
Text File  |  2014-07-29  |  7KB  |  173 lines

  1. """ParenMatch -- An IDLE extension for parenthesis matching.
  2.  
  3. When you hit a right paren, the cursor should move briefly to the left
  4. paren.  Paren here is used generically; the matching applies to
  5. parentheses, square brackets, and curly braces.
  6. """
  7.  
  8. from idlelib.HyperParser import HyperParser
  9. from idlelib.configHandler import idleConf
  10.  
  11. _openers = {')':'(',']':'[','}':'{'}
  12. CHECK_DELAY = 100 # miliseconds
  13.  
  14. class ParenMatch:
  15.     """Highlight matching parentheses
  16.  
  17.     There are three supported style of paren matching, based loosely
  18.     on the Emacs options.  The style is select based on the
  19.     HILITE_STYLE attribute; it can be changed used the set_style
  20.     method.
  21.  
  22.     The supported styles are:
  23.  
  24.     default -- When a right paren is typed, highlight the matching
  25.         left paren for 1/2 sec.
  26.  
  27.     expression -- When a right paren is typed, highlight the entire
  28.         expression from the left paren to the right paren.
  29.  
  30.     TODO:
  31.         - extend IDLE with configuration dialog to change options
  32.         - implement rest of Emacs highlight styles (see below)
  33.         - print mismatch warning in IDLE status window
  34.  
  35.     Note: In Emacs, there are several styles of highlight where the
  36.     matching paren is highlighted whenever the cursor is immediately
  37.     to the right of a right paren.  I don't know how to do that in Tk,
  38.     so I haven't bothered.
  39.     """
  40.     menudefs = [
  41.         ('edit', [
  42.             ("Show surrounding parens", "<<flash-paren>>"),
  43.         ])
  44.     ]
  45.     STYLE = idleConf.GetOption('extensions','ParenMatch','style',
  46.             default='expression')
  47.     FLASH_DELAY = idleConf.GetOption('extensions','ParenMatch','flash-delay',
  48.             type='int',default=500)
  49.     HILITE_CONFIG = idleConf.GetHighlight(idleConf.CurrentTheme(),'hilite')
  50.     BELL = idleConf.GetOption('extensions','ParenMatch','bell',
  51.             type='bool',default=1)
  52.  
  53.     RESTORE_VIRTUAL_EVENT_NAME = "<<parenmatch-check-restore>>"
  54.     # We want the restore event be called before the usual return and
  55.     # backspace events.
  56.     RESTORE_SEQUENCES = ("<KeyPress>", "<ButtonPress>",
  57.                          "<Key-Return>", "<Key-BackSpace>")
  58.  
  59.     def __init__(self, editwin):
  60.         self.editwin = editwin
  61.         self.text = editwin.text
  62.         # Bind the check-restore event to the function restore_event,
  63.         # so that we can then use activate_restore (which calls event_add)
  64.         # and deactivate_restore (which calls event_delete).
  65.         editwin.text.bind(self.RESTORE_VIRTUAL_EVENT_NAME,
  66.                           self.restore_event)
  67.         self.counter = 0
  68.         self.is_restore_active = 0
  69.         self.set_style(self.STYLE)
  70.  
  71.     def activate_restore(self):
  72.         if not self.is_restore_active:
  73.             for seq in self.RESTORE_SEQUENCES:
  74.                 self.text.event_add(self.RESTORE_VIRTUAL_EVENT_NAME, seq)
  75.             self.is_restore_active = True
  76.  
  77.     def deactivate_restore(self):
  78.         if self.is_restore_active:
  79.             for seq in self.RESTORE_SEQUENCES:
  80.                 self.text.event_delete(self.RESTORE_VIRTUAL_EVENT_NAME, seq)
  81.             self.is_restore_active = False
  82.  
  83.     def set_style(self, style):
  84.         self.STYLE = style
  85.         if style == "default":
  86.             self.create_tag = self.create_tag_default
  87.             self.set_timeout = self.set_timeout_last
  88.         elif style == "expression":
  89.             self.create_tag = self.create_tag_expression
  90.             self.set_timeout = self.set_timeout_none
  91.  
  92.     def flash_paren_event(self, event):
  93.         indices = HyperParser(self.editwin, "insert").get_surrounding_brackets()
  94.         if indices is None:
  95.             self.warn_mismatched()
  96.             return
  97.         self.activate_restore()
  98.         self.create_tag(indices)
  99.         self.set_timeout_last()
  100.  
  101.     def paren_closed_event(self, event):
  102.         # If it was a shortcut and not really a closing paren, quit.
  103.         closer = self.text.get("insert-1c")
  104.         if closer not in _openers:
  105.             return
  106.         hp = HyperParser(self.editwin, "insert-1c")
  107.         if not hp.is_in_code():
  108.             return
  109.         indices = hp.get_surrounding_brackets(_openers[closer], True)
  110.         if indices is None:
  111.             self.warn_mismatched()
  112.             return
  113.         self.activate_restore()
  114.         self.create_tag(indices)
  115.         self.set_timeout()
  116.  
  117.     def restore_event(self, event=None):
  118.         self.text.tag_delete("paren")
  119.         self.deactivate_restore()
  120.         self.counter += 1   # disable the last timer, if there is one.
  121.  
  122.     def handle_restore_timer(self, timer_count):
  123.         if timer_count == self.counter:
  124.             self.restore_event()
  125.  
  126.     def warn_mismatched(self):
  127.         if self.BELL:
  128.             self.text.bell()
  129.  
  130.     # any one of the create_tag_XXX methods can be used depending on
  131.     # the style
  132.  
  133.     def create_tag_default(self, indices):
  134.         """Highlight the single paren that matches"""
  135.         self.text.tag_add("paren", indices[0])
  136.         self.text.tag_config("paren", self.HILITE_CONFIG)
  137.  
  138.     def create_tag_expression(self, indices):
  139.         """Highlight the entire expression"""
  140.         if self.text.get(indices[1]) in (')', ']', '}'):
  141.             rightindex = indices[1]+"+1c"
  142.         else:
  143.             rightindex = indices[1]
  144.         self.text.tag_add("paren", indices[0], rightindex)
  145.         self.text.tag_config("paren", self.HILITE_CONFIG)
  146.  
  147.     # any one of the set_timeout_XXX methods can be used depending on
  148.     # the style
  149.  
  150.     def set_timeout_none(self):
  151.         """Highlight will remain until user input turns it off
  152.         or the insert has moved"""
  153.         # After CHECK_DELAY, call a function which disables the "paren" tag
  154.         # if the event is for the most recent timer and the insert has changed,
  155.         # or schedules another call for itself.
  156.         self.counter += 1
  157.         def callme(callme, self=self, c=self.counter,
  158.                    index=self.text.index("insert")):
  159.             if index != self.text.index("insert"):
  160.                 self.handle_restore_timer(c)
  161.             else:
  162.                 self.editwin.text_frame.after(CHECK_DELAY, callme, callme)
  163.         self.editwin.text_frame.after(CHECK_DELAY, callme, callme)
  164.  
  165.     def set_timeout_last(self):
  166.         """The last highlight created will be removed after .5 sec"""
  167.         # associate a counter with an event; only disable the "paren"
  168.         # tag if the event is for the most recent timer.
  169.         self.counter += 1
  170.         self.editwin.text_frame.after(self.FLASH_DELAY,
  171.                                       lambda self=self, c=self.counter: \
  172.                                       self.handle_restore_timer(c))
  173.