Sublime Forum

Highlight Current Word

#1

This is a plugin that highlights all occurrences of the current word in the current view. The current word is defined as the string of characters that contains the cursor position and starts and ends with a character from the word_separators setting. The plugin also delays the search by 0.5 seconds, so on large documents it will not do the search on every keypress, which really makes it feel much more responsive. There is a highlight_word_theme_selector setting which defaults to comment. This allows you to customize the color of the highlighted words independently of other theme settings. (I used this because I wanted the highlighted words to be similar to search results, but just a little darker, so the theme selector helps).

This is my first plugin, I found the basic idea from a similar current word plugin but added a few features.

I had a few questions too though if anyone has ideas:

  1. It looks like there is no way to stop a timeout or tell it to repeat. I worked around this, but it might be a nice thing to have?
  2. Are there any threading issues that need to be taken care of in the timeouts? I haven’t done this, but what I would like to do is to store a reference to a view object in an event handler, and then access it later in the timeout. Is that possible?
  3. I tried to setup my theme to highlight the current word with a green background. For whatever reason, when I set the background key in the theme for that selector to green, it did nothing. When I set the foreground selector to green, it made the background green and the text of the word pink. I would really like the text to be white for some more contrast, can that be done? How? Is there a reason the foreground setting is used for the background?

Here is the code: github.com/ajpalkovic/SublimePl … ghlight.py

0 Likes

TagMatcher and WordHighlight
#2

Hey man, glad to see you here too :mrgreen:
Here is what i’m using right now: Highlight Current Word plugin with ST2
I didn’t saw any performance issues on medium files (~500kb).

0 Likes

#3

Heh, nice to see you too. I figured it was time to switch, I start working on a linux box in 1 week and e still sucks on linux.

O yea, that’s the one I tried at first. It wasn’t too bad, but I could see the cpu usage going up which I didn’t really like. I hate any lag at all in my editor. Also, it uses regular expressions, I think \b, to detect word boundaries, which I didn’t like because I couldn’t customize it. The settings file has a word_separators setting built in, so I opted to use that. That was something that always bugged me about how I implemented it in e. Also, that one styled them as comments, which in my theme made it really hard to see.

0 Likes

#4

I like your idea of using timer and RE and will probably incorporate it in my own plugin.

Another way to implement the RE searching is:

separatorString = view.settings().get('word_separators') separatorString = re.escape(separatorString) ... foundRegions = view.find_all(r'(^|%s\s])%s(%s\s]|$)'%(separatorString, currentWord, separatorString)) ...

The results could include the separator before and after, so you have to strip them.
Not sure it’s better than your solution.

0 Likes

#5

Interesting. I didn’t go that route because of speed. I had considered something similar, but I didn’t know exactly how the regex search was implemented. In particular, for each character of the document, it might have had to compare it to each of separator characters, so it becomes an m*n problem, but with a dictionary it guarantees nearly constant lookup, so it’s just n. I’ll benchmark it just for fun anyway, in theory the regex should be slower, but idk if it actually is.

0 Likes

#6

With regards to #2, there aren’t any threading with callbacks run from set_timeout: they’re all run on the main thread. FWIW, set_timeout is the only threadsafe function to call in the API, calling other functions in a thread other than the main one will throw an exception.

Currently, the background color is extracted from the theme, and the foreground color is automatically generated to be a contrasting one. I’ll make a change in in the next build so that if the theme explicitly provides both a foreground and background color for the given scope, then they’ll be used as is.

0 Likes

#7

It’s very curious, on a 2.5 mb file, the regex took about 1.5 seconds to do 5 passes, but the non-regex option took about .17 seconds for most words, but on a word like NULL that occurs multiple times it took up to a full second to do 5 passes.

You have no clue how awesome it is to have the developer actually respond to a forum post. (I’m from e :smile:) Thanks for adding that functionality though.

0 Likes

#8

Thanks for doing the benchmark.
Even if it’s expected, it’s useful to know that RE is way slower than a straight text search.

Since the text search find every occurrence of NULL and filter them after, I first thought that your test file have a lot of word composed with NULL, but except nullity and nullify I didn’t see any others.
How many occurrence of NULL in your test file ?

0 Likes

#9

Well, it was a sql file, so NULL occurred a few thousand times in it. The regex doesn’t have to do any extra processing on each match, so its performance is fairly consistent regardless of the number of matches, but find_all has to check the character before and after, so when it matches a ton of things it slows down. Neverthless, I am going to rewrite it to be fast and instant soon. :smile:

0 Likes

#10

I just posted a rewrite of this to the gist.

Basically, instead of using a delay, I do something far smarter. It is silly to do a search for the current word on the entire document every time as you are only looking at the visible region. So now I contain the search to just be in the visible region of the view. As you scroll and modify the document the search is done instantly. Since it is only working on the visible screen it is quite fast (< .2 seconds for 1000 searches on my machine), but the downside is that the matches aren’t visible in the minimap.

Also, if you multiselect the same word, it will still highlight that word in the file. Before it would highlight nothing on multiselect.

0 Likes

#11

This is really nice. Thanks.

Just a small issue: The highlighted words start flickering while scrolling and sometimes turn gray while they are still in the viewport.

0 Likes

#12

Hmm, I haven’t seen any flickering or color changing going on. I just pushed a couple of changes to the gist that might help.

The problem is there is no on_scroll event, so I just had a small timer that periodically checked if the viewport had changes dimensions. That works, but that would be my guess why the flickering is there. If you still have it, maybe try setting the interval to 10, instead of 50, restart sublime and see if that fixes it.

0 Likes

#13

The flickering itself is not so much a problem. But after scrolling, the highlighted words look sometimes different, depending on which flickering state i stop scrolling. As if their selector changes. Here are screenshots with the Monokai Theme and “searchHighlight” as the selector:

themeSelector = view.settings().get(‘highlight_word_theme_selector’, ‘searchHighlight’)

Before scrolling:

After scrolling:

0 Likes

#14

Ok, “searchHighlight” doesn’t exist… The example works anyway :smile:

0 Likes

#15

Heh, it actually might be because you have two versions of the plugin running :smile:
I haven’t figured out a good solution for this yet, it appears that sometimes when I make changes to a plugin the old events / timers aren’t always killed properly. In this case, you actually might have two versions of the plugins that are firing the same events but with a different default, so it’s a race condition to see which one gets displayed. I might have messed up in coding it, but for now, I’d say just restart sublime once you have finished your changes to the plugin. You can add highlight_word_theme_selector to your settings file, that way you do not need to modify the plugin to change the color. (This is also why I never saw the flickering because I set this, which overrode the default). Then you can drop something like this into your theme file:

            <dict>
                <key>name</key>
                <string>Current Word</string>
                <key>scope</key>
                <string>currentword</string>
                <key>settings</key>
                <dict>
                    <key>foreground</key>
                    <string>#F8F8F8</string>
                    <key>background</key>
                    <string>#117004</string>
                </dict>
            </dict>
0 Likes

#16

Ah, ok. Adding highlight_word_theme_selector to the settings did the trick. I already defined a key in my theme – and did some testing with various other keys. That has to be the reason for the issue. Thanks a lot!

0 Likes

#17

If it were any other editor it might be silly, but the minimap means that you can see selections beyond your current frame. You have to have a really bright selection colour to pick them out in the minimap, though (which I do).

0 Likes

#18

Yea, I thought about that too. I could hardly see the highlights though so I didn’t really find it that useful. You can always do a find all if you truly want to see all of them. Also, since it’s in a gist right now, you can grab an old version too if you need to.

0 Likes

#19

Can the highlighted words keep on highlighting until I make another selection on other words?
just like the search function, it will highlight the searched term persistently.

0 Likes

#20

Hi,

Just a question on this: In the current file, it says:

# The search is performed half a second after the most recent event in order to prevent the search hapenning on every keypress.
# Each of the event handlers simply marks the time of the most recent event and a timer periodically executes doSearch

However, if I’m reading the code right, this isn’t the case: it’s doing the search every half second and every time the selection is changed, since:

def on_selection_modified(self, view):
    self.doSearch(view)

Isn’t that a bit resource intensive?

Martin

0 Likes