jpayne@68
|
1 '''Complete the current word before the cursor with words in the editor.
|
jpayne@68
|
2
|
jpayne@68
|
3 Each menu selection or shortcut key selection replaces the word with a
|
jpayne@68
|
4 different word with the same prefix. The search for matches begins
|
jpayne@68
|
5 before the target and moves toward the top of the editor. It then starts
|
jpayne@68
|
6 after the cursor and moves down. It then returns to the original word and
|
jpayne@68
|
7 the cycle starts again.
|
jpayne@68
|
8
|
jpayne@68
|
9 Changing the current text line or leaving the cursor in a different
|
jpayne@68
|
10 place before requesting the next selection causes AutoExpand to reset
|
jpayne@68
|
11 its state.
|
jpayne@68
|
12
|
jpayne@68
|
13 There is only one instance of Autoexpand.
|
jpayne@68
|
14 '''
|
jpayne@68
|
15 import re
|
jpayne@68
|
16 import string
|
jpayne@68
|
17
|
jpayne@68
|
18
|
jpayne@68
|
19 class AutoExpand:
|
jpayne@68
|
20 wordchars = string.ascii_letters + string.digits + "_"
|
jpayne@68
|
21
|
jpayne@68
|
22 def __init__(self, editwin):
|
jpayne@68
|
23 self.text = editwin.text
|
jpayne@68
|
24 self.bell = self.text.bell
|
jpayne@68
|
25 self.state = None
|
jpayne@68
|
26
|
jpayne@68
|
27 def expand_word_event(self, event):
|
jpayne@68
|
28 "Replace the current word with the next expansion."
|
jpayne@68
|
29 curinsert = self.text.index("insert")
|
jpayne@68
|
30 curline = self.text.get("insert linestart", "insert lineend")
|
jpayne@68
|
31 if not self.state:
|
jpayne@68
|
32 words = self.getwords()
|
jpayne@68
|
33 index = 0
|
jpayne@68
|
34 else:
|
jpayne@68
|
35 words, index, insert, line = self.state
|
jpayne@68
|
36 if insert != curinsert or line != curline:
|
jpayne@68
|
37 words = self.getwords()
|
jpayne@68
|
38 index = 0
|
jpayne@68
|
39 if not words:
|
jpayne@68
|
40 self.bell()
|
jpayne@68
|
41 return "break"
|
jpayne@68
|
42 word = self.getprevword()
|
jpayne@68
|
43 self.text.delete("insert - %d chars" % len(word), "insert")
|
jpayne@68
|
44 newword = words[index]
|
jpayne@68
|
45 index = (index + 1) % len(words)
|
jpayne@68
|
46 if index == 0:
|
jpayne@68
|
47 self.bell() # Warn we cycled around
|
jpayne@68
|
48 self.text.insert("insert", newword)
|
jpayne@68
|
49 curinsert = self.text.index("insert")
|
jpayne@68
|
50 curline = self.text.get("insert linestart", "insert lineend")
|
jpayne@68
|
51 self.state = words, index, curinsert, curline
|
jpayne@68
|
52 return "break"
|
jpayne@68
|
53
|
jpayne@68
|
54 def getwords(self):
|
jpayne@68
|
55 "Return a list of words that match the prefix before the cursor."
|
jpayne@68
|
56 word = self.getprevword()
|
jpayne@68
|
57 if not word:
|
jpayne@68
|
58 return []
|
jpayne@68
|
59 before = self.text.get("1.0", "insert wordstart")
|
jpayne@68
|
60 wbefore = re.findall(r"\b" + word + r"\w+\b", before)
|
jpayne@68
|
61 del before
|
jpayne@68
|
62 after = self.text.get("insert wordend", "end")
|
jpayne@68
|
63 wafter = re.findall(r"\b" + word + r"\w+\b", after)
|
jpayne@68
|
64 del after
|
jpayne@68
|
65 if not wbefore and not wafter:
|
jpayne@68
|
66 return []
|
jpayne@68
|
67 words = []
|
jpayne@68
|
68 dict = {}
|
jpayne@68
|
69 # search backwards through words before
|
jpayne@68
|
70 wbefore.reverse()
|
jpayne@68
|
71 for w in wbefore:
|
jpayne@68
|
72 if dict.get(w):
|
jpayne@68
|
73 continue
|
jpayne@68
|
74 words.append(w)
|
jpayne@68
|
75 dict[w] = w
|
jpayne@68
|
76 # search onwards through words after
|
jpayne@68
|
77 for w in wafter:
|
jpayne@68
|
78 if dict.get(w):
|
jpayne@68
|
79 continue
|
jpayne@68
|
80 words.append(w)
|
jpayne@68
|
81 dict[w] = w
|
jpayne@68
|
82 words.append(word)
|
jpayne@68
|
83 return words
|
jpayne@68
|
84
|
jpayne@68
|
85 def getprevword(self):
|
jpayne@68
|
86 "Return the word prefix before the cursor."
|
jpayne@68
|
87 line = self.text.get("insert linestart", "insert")
|
jpayne@68
|
88 i = len(line)
|
jpayne@68
|
89 while i > 0 and line[i-1] in self.wordchars:
|
jpayne@68
|
90 i = i-1
|
jpayne@68
|
91 return line[i:]
|
jpayne@68
|
92
|
jpayne@68
|
93
|
jpayne@68
|
94 if __name__ == '__main__':
|
jpayne@68
|
95 from unittest import main
|
jpayne@68
|
96 main('idlelib.idle_test.test_autoexpand', verbosity=2)
|