Home | History | Annotate | Download | only in idlelib
      1 from Tkinter import *
      2 
      3 from idlelib import SearchEngine
      4 from idlelib.SearchDialogBase import SearchDialogBase
      5 import re
      6 
      7 
      8 def replace(text):
      9     root = text._root()
     10     engine = SearchEngine.get(root)
     11     if not hasattr(engine, "_replacedialog"):
     12         engine._replacedialog = ReplaceDialog(root, engine)
     13     dialog = engine._replacedialog
     14     dialog.open(text)
     15 
     16 
     17 class ReplaceDialog(SearchDialogBase):
     18 
     19     title = "Replace Dialog"
     20     icon = "Replace"
     21 
     22     def __init__(self, root, engine):
     23         SearchDialogBase.__init__(self, root, engine)
     24         self.replvar = StringVar(root)
     25 
     26     def open(self, text):
     27         SearchDialogBase.open(self, text)
     28         try:
     29             first = text.index("sel.first")
     30         except TclError:
     31             first = None
     32         try:
     33             last = text.index("sel.last")
     34         except TclError:
     35             last = None
     36         first = first or text.index("insert")
     37         last = last or first
     38         self.show_hit(first, last)
     39         self.ok = 1
     40 
     41     def create_entries(self):
     42         SearchDialogBase.create_entries(self)
     43         self.replent = self.make_entry("Replace with:", self.replvar)
     44 
     45     def create_command_buttons(self):
     46         SearchDialogBase.create_command_buttons(self)
     47         self.make_button("Find", self.find_it)
     48         self.make_button("Replace", self.replace_it)
     49         self.make_button("Replace+Find", self.default_command, 1)
     50         self.make_button("Replace All", self.replace_all)
     51 
     52     def find_it(self, event=None):
     53         self.do_find(0)
     54 
     55     def replace_it(self, event=None):
     56         if self.do_find(self.ok):
     57             self.do_replace()
     58 
     59     def default_command(self, event=None):
     60         if self.do_find(self.ok):
     61             if self.do_replace():   # Only find next match if replace succeeded.
     62                                     # A bad re can cause a it to fail.
     63                 self.do_find(0)
     64 
     65     def _replace_expand(self, m, repl):
     66         """ Helper function for expanding a regular expression
     67             in the replace field, if needed. """
     68         if self.engine.isre():
     69             try:
     70                 new = m.expand(repl)
     71             except re.error:
     72                 self.engine.report_error(repl, 'Invalid Replace Expression')
     73                 new = None
     74         else:
     75             new = repl
     76         return new
     77 
     78     def replace_all(self, event=None):
     79         prog = self.engine.getprog()
     80         if not prog:
     81             return
     82         repl = self.replvar.get()
     83         text = self.text
     84         res = self.engine.search_text(text, prog)
     85         if not res:
     86             text.bell()
     87             return
     88         text.tag_remove("sel", "1.0", "end")
     89         text.tag_remove("hit", "1.0", "end")
     90         line = res[0]
     91         col = res[1].start()
     92         if self.engine.iswrap():
     93             line = 1
     94             col = 0
     95         ok = 1
     96         first = last = None
     97         # XXX ought to replace circular instead of top-to-bottom when wrapping
     98         text.undo_block_start()
     99         while 1:
    100             res = self.engine.search_forward(text, prog, line, col, 0, ok)
    101             if not res:
    102                 break
    103             line, m = res
    104             chars = text.get("%d.0" % line, "%d.0" % (line+1))
    105             orig = m.group()
    106             new = self._replace_expand(m, repl)
    107             if new is None:
    108                 break
    109             i, j = m.span()
    110             first = "%d.%d" % (line, i)
    111             last = "%d.%d" % (line, j)
    112             if new == orig:
    113                 text.mark_set("insert", last)
    114             else:
    115                 text.mark_set("insert", first)
    116                 if first != last:
    117                     text.delete(first, last)
    118                 if new:
    119                     text.insert(first, new)
    120             col = i + len(new)
    121             ok = 0
    122         text.undo_block_stop()
    123         if first and last:
    124             self.show_hit(first, last)
    125         self.close()
    126 
    127     def do_find(self, ok=0):
    128         if not self.engine.getprog():
    129             return False
    130         text = self.text
    131         res = self.engine.search_text(text, None, ok)
    132         if not res:
    133             text.bell()
    134             return False
    135         line, m = res
    136         i, j = m.span()
    137         first = "%d.%d" % (line, i)
    138         last = "%d.%d" % (line, j)
    139         self.show_hit(first, last)
    140         self.ok = 1
    141         return True
    142 
    143     def do_replace(self):
    144         prog = self.engine.getprog()
    145         if not prog:
    146             return False
    147         text = self.text
    148         try:
    149             first = pos = text.index("sel.first")
    150             last = text.index("sel.last")
    151         except TclError:
    152             pos = None
    153         if not pos:
    154             first = last = pos = text.index("insert")
    155         line, col = SearchEngine.get_line_col(pos)
    156         chars = text.get("%d.0" % line, "%d.0" % (line+1))
    157         m = prog.match(chars, col)
    158         if not prog:
    159             return False
    160         new = self._replace_expand(m, self.replvar.get())
    161         if new is None:
    162             return False
    163         text.mark_set("insert", first)
    164         text.undo_block_start()
    165         if m.group():
    166             text.delete(first, last)
    167         if new:
    168             text.insert(first, new)
    169         text.undo_block_stop()
    170         self.show_hit(first, text.index("insert"))
    171         self.ok = 0
    172         return True
    173 
    174     def show_hit(self, first, last):
    175         text = self.text
    176         text.mark_set("insert", first)
    177         text.tag_remove("sel", "1.0", "end")
    178         text.tag_add("sel", first, last)
    179         text.tag_remove("hit", "1.0", "end")
    180         if first == last:
    181             text.tag_add("hit", first)
    182         else:
    183             text.tag_add("hit", first, last)
    184         text.see("insert")
    185         text.update_idletasks()
    186 
    187     def close(self, event=None):
    188         SearchDialogBase.close(self, event)
    189         self.text.tag_remove("hit", "1.0", "end")
    190