2014-06-04 21:54:43 -03:00
|
|
|
'''Complete the current word before the cursor with words in the editor.
|
|
|
|
|
|
|
|
Each menu selection or shortcut key selection replaces the word with a
|
|
|
|
different word with the same prefix. The search for matches begins
|
|
|
|
before the target and moves toward the top of the editor. It then starts
|
|
|
|
after the cursor and moves down. It then returns to the original word and
|
|
|
|
the cycle starts again.
|
|
|
|
|
|
|
|
Changing the current text line or leaving the cursor in a different
|
|
|
|
place before requesting the next selection causes AutoExpand to reset
|
|
|
|
its state.
|
|
|
|
|
|
|
|
This is an extension file and there is only one instance of AutoExpand.
|
|
|
|
'''
|
2000-08-14 22:13:23 -03:00
|
|
|
import re
|
2016-08-31 01:50:55 -03:00
|
|
|
import string
|
2000-08-14 22:13:23 -03:00
|
|
|
|
|
|
|
###$ event <<expand-word>>
|
|
|
|
###$ win <Alt-slash>
|
|
|
|
###$ unix <Alt-slash>
|
|
|
|
|
|
|
|
class AutoExpand:
|
|
|
|
|
|
|
|
menudefs = [
|
|
|
|
('edit', [
|
2003-01-03 21:43:53 -04:00
|
|
|
('E_xpand Word', '<<expand-word>>'),
|
2000-08-14 22:13:23 -03:00
|
|
|
]),
|
|
|
|
]
|
|
|
|
|
2002-09-15 17:50:02 -03:00
|
|
|
wordchars = string.ascii_letters + string.digits + "_"
|
2000-08-14 22:13:23 -03:00
|
|
|
|
|
|
|
def __init__(self, editwin):
|
|
|
|
self.text = editwin.text
|
2016-08-11 00:44:54 -03:00
|
|
|
self.bell = self.text.bell
|
2000-08-14 22:13:23 -03:00
|
|
|
self.state = None
|
|
|
|
|
|
|
|
def expand_word_event(self, event):
|
2014-06-04 21:54:43 -03:00
|
|
|
"Replace the current word with the next expansion."
|
2000-08-14 22:13:23 -03:00
|
|
|
curinsert = self.text.index("insert")
|
|
|
|
curline = self.text.get("insert linestart", "insert lineend")
|
|
|
|
if not self.state:
|
|
|
|
words = self.getwords()
|
|
|
|
index = 0
|
|
|
|
else:
|
|
|
|
words, index, insert, line = self.state
|
|
|
|
if insert != curinsert or line != curline:
|
|
|
|
words = self.getwords()
|
|
|
|
index = 0
|
|
|
|
if not words:
|
2016-08-11 00:44:54 -03:00
|
|
|
self.bell()
|
2000-08-14 22:13:23 -03:00
|
|
|
return "break"
|
|
|
|
word = self.getprevword()
|
|
|
|
self.text.delete("insert - %d chars" % len(word), "insert")
|
|
|
|
newword = words[index]
|
|
|
|
index = (index + 1) % len(words)
|
|
|
|
if index == 0:
|
2016-08-11 00:44:54 -03:00
|
|
|
self.bell() # Warn we cycled around
|
2000-08-14 22:13:23 -03:00
|
|
|
self.text.insert("insert", newword)
|
|
|
|
curinsert = self.text.index("insert")
|
|
|
|
curline = self.text.get("insert linestart", "insert lineend")
|
|
|
|
self.state = words, index, curinsert, curline
|
|
|
|
return "break"
|
|
|
|
|
|
|
|
def getwords(self):
|
2014-06-04 21:54:43 -03:00
|
|
|
"Return a list of words that match the prefix before the cursor."
|
2000-08-14 22:13:23 -03:00
|
|
|
word = self.getprevword()
|
|
|
|
if not word:
|
|
|
|
return []
|
|
|
|
before = self.text.get("1.0", "insert wordstart")
|
|
|
|
wbefore = re.findall(r"\b" + word + r"\w+\b", before)
|
|
|
|
del before
|
|
|
|
after = self.text.get("insert wordend", "end")
|
|
|
|
wafter = re.findall(r"\b" + word + r"\w+\b", after)
|
|
|
|
del after
|
|
|
|
if not wbefore and not wafter:
|
|
|
|
return []
|
|
|
|
words = []
|
|
|
|
dict = {}
|
|
|
|
# search backwards through words before
|
|
|
|
wbefore.reverse()
|
|
|
|
for w in wbefore:
|
|
|
|
if dict.get(w):
|
|
|
|
continue
|
|
|
|
words.append(w)
|
|
|
|
dict[w] = w
|
|
|
|
# search onwards through words after
|
|
|
|
for w in wafter:
|
|
|
|
if dict.get(w):
|
|
|
|
continue
|
|
|
|
words.append(w)
|
|
|
|
dict[w] = w
|
|
|
|
words.append(word)
|
|
|
|
return words
|
|
|
|
|
|
|
|
def getprevword(self):
|
2014-06-04 21:54:43 -03:00
|
|
|
"Return the word prefix before the cursor."
|
2000-08-14 22:13:23 -03:00
|
|
|
line = self.text.get("insert linestart", "insert")
|
|
|
|
i = len(line)
|
|
|
|
while i > 0 and line[i-1] in self.wordchars:
|
|
|
|
i = i-1
|
|
|
|
return line[i:]
|
2014-06-04 21:54:43 -03:00
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
import unittest
|
|
|
|
unittest.main('idlelib.idle_test.test_autoexpand', verbosity=2)
|