forked from optilude/SublimeTextMisc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
highlight.py
98 lines (77 loc) · 3.19 KB
/
highlight.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import sublime, sublime_plugin
key = "HighlightCurrentWord"
class HighlightCurrentWord(sublime_plugin.EventListener):
def __init__(self):
self.previousRegion = sublime.Region(0, 0)
sublime.set_timeout(self.on_timer, 50)
def on_timer(self):
sublime.set_timeout(self.on_timer, 50)
window = sublime.active_window()
if window is not None:
self.doSearch(window.active_view(), False)
def doSearch(self, view, force=True):
if view == None:
return
selections = view.sel()
if len(selections) == 0:
view.erase_regions(key)
return
visibleRegion = view.visible_region()
if force or (self.previousRegion != visibleRegion):
self.previousRegion = visibleRegion
view.erase_regions(key)
else:
return
# The default separator does not include whitespace, so I add that here no matter what
separatorString = view.settings().get('word_separators') + u" \n\r"
themeSelector = view.settings().get('highlight_word_theme_selector', 'comment')
currentRegion = view.word(selections[0])
currentWord = view.substr(currentRegion).strip(separatorString) # remove leading/trailing separator characters just in case
#print u"|%s|" % currentWord
if(len(currentWord) == 0):
view.erase_regions(key)
return
searchStart = self.previousRegion.a - len(currentWord)
searchEnd = self.previousRegion.b + len(currentWord)
# Reduce m*n search to just n by mapping each word separator character into a dictionary
separators = {}
for c in separatorString:
separators[c] = True
# ignore the selection if it spans multiple words
for c in currentWord:
if c in separators:
return
# If we are multi-selecting and all the words are the same, then we should still highlight
if len(selections) > 1:
for region in selections:
word = view.substr(region).strip(separatorString)
if word != currentWord:
return
validRegions = []
while True:
foundRegion = view.find(currentWord, searchStart, sublime.LITERAL)
if foundRegion == None:
break
# regions can have reversed start/ends so normalize them
start = min(foundRegion.a, foundRegion.b)
end = max(foundRegion.a, foundRegion.b)
searchStart = end
if foundRegion.empty() or foundRegion.intersects(currentRegion):
continue
# check if the character before and after the region is a separator character
# if it is not, then the region is part of a larger word and shouldn't match
# this can't be done in a regex because we would be unable to use the word_separators setting string
leadingCharacter = view.substr(sublime.Region(start-1, start))
followingCharacter = view.substr(sublime.Region(end, end+1))
if start == 0 or leadingCharacter in separators:
if end == view.size()-1 or followingCharacter in separators:
validRegions.append(foundRegion)
if searchStart > searchEnd:
break
view.add_regions(key, validRegions, themeSelector)
def on_selection_modified(self, view):
self.doSearch(view)
def on_close(self, view):
self.doSearch(view)
def on_activated(self, view):
self.doSearch(view)