1ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotimport string
2ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotimport re
3ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
4ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot###$ event <<expand-word>>
5ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot###$ win <Alt-slash>
6ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot###$ unix <Alt-slash>
7ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
8ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotclass AutoExpand:
9ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
10ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    menudefs = [
11ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        ('edit', [
12ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            ('E_xpand Word', '<<expand-word>>'),
13ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot         ]),
14ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    ]
15ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
16ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    wordchars = string.ascii_letters + string.digits + "_"
17ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
18ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def __init__(self, editwin):
19ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.text = editwin.text
20ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.state = None
21ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
22ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def expand_word_event(self, event):
23ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        curinsert = self.text.index("insert")
24ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        curline = self.text.get("insert linestart", "insert lineend")
25ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if not self.state:
26ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            words = self.getwords()
27ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            index = 0
28ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        else:
29ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            words, index, insert, line = self.state
30ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if insert != curinsert or line != curline:
31ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                words = self.getwords()
32ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                index = 0
33ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if not words:
34ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.text.bell()
35ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            return "break"
36ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        word = self.getprevword()
37ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.text.delete("insert - %d chars" % len(word), "insert")
38ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        newword = words[index]
39ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        index = (index + 1) % len(words)
40ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if index == 0:
41ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.text.bell()            # Warn we cycled around
42ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.text.insert("insert", newword)
43ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        curinsert = self.text.index("insert")
44ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        curline = self.text.get("insert linestart", "insert lineend")
45ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.state = words, index, curinsert, curline
46ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        return "break"
47ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
48ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def getwords(self):
49ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        word = self.getprevword()
50ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if not word:
51ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            return []
52ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        before = self.text.get("1.0", "insert wordstart")
53ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        wbefore = re.findall(r"\b" + word + r"\w+\b", before)
54ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        del before
55ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        after = self.text.get("insert wordend", "end")
56ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        wafter = re.findall(r"\b" + word + r"\w+\b", after)
57ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        del after
58ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if not wbefore and not wafter:
59ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            return []
60ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        words = []
61ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        dict = {}
62ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # search backwards through words before
63ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        wbefore.reverse()
64ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        for w in wbefore:
65ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if dict.get(w):
66ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                continue
67ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            words.append(w)
68ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            dict[w] = w
69ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # search onwards through words after
70ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        for w in wafter:
71ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if dict.get(w):
72ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                continue
73ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            words.append(w)
74ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            dict[w] = w
75ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        words.append(word)
76ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        return words
77ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
78ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def getprevword(self):
79ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        line = self.text.get("insert linestart", "insert")
80ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        i = len(line)
81ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        while i > 0 and line[i-1] in self.wordchars:
82ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            i = i-1
83ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        return line[i:]
84