Sublime Forum

TagMatcher and WordHighlight

#1

There are two very useful features that are missing.

[size=150]Highlighting Matching Tags:[/size]

Although Sublime Text 2 does match tags, but it only shows a little dotted underline; which is not very visual. To fix this, there is this TagMatcher plugin which is unfortunately very slow; especially when you’re editing large files. Notepad++ has implemented this feature and it works like a charm there. It never causes any glitches, even in gigantic files.

[size=150]Highlighting matching words on select:[/size]

This can be very useful when you want to quickly find where else in your code, you have used a word (a variable name for example). There is a plugin called “WordHighlight” which has the same issue as the TagMatcher plugin. It’s slow and causes crashes and errors when working with rather large files. This feature is also properly implemented in notepad++, without any glitches.

So I would like to ask a native implementation of these two very useful features.

0 Likes

#2

You can try BracketHighlighter which fixes a number of issues that SublimeBracket and SublimeTagmatcher had and adds features. Large file issues is what caused me to create it.

I don’t have an alternative suggestion for WordHighlight though. I do think WordHighlight could be implemented to be kinder in really large files. It seems to search the entire file on every selection change. Search the entire file can bog things down.

0 Likes

#3

Just tired your plugin. It has a long delay which is very annoying. And I know this delay is probably there to prevent the issues that those other plugins have. But like I said, notepad++ implements the same functionality, without any delay, and it works like a charm even in gigantic files.

0 Likes

#4

I believe the lastest version of wordhighlight will not highlight if the file size is over a certain size. Additionally, there is now a menu item to quickly enable and disable it. There is still some work to be done to fix the large file issue.

0 Likes

#5

I used to use Notepad++ on Windows as well, so I am well aware of what you are talking about. Keep in mind, the plugin is not native code, so there is some overhead in with the scripting.

You are correct, the delay is to prevent the issues that other plugins have. I wouldn’t say it is a long delay, but it does feel that way at first because you are used to instantaneous highlighting. But I will be honest when I say this; how often to you need instantaneous highlighting. Matching brackets isn’t usually something I need to aware of 100% of the time right that instance. It is a nice guide that is there when you need it.

You can adjust the delay and such to your liking in the settings file, or not use the plugin at all if you do in fact find it too annoying. I honestly think if you used it a while, the delay would be insignificant, but everyone is different, but at least you know it is an option.

0 Likes

#6

So can we please get a native implementation of TagMatcher? :cry:

0 Likes

#7

This is a much faster word highlight plugin. It only scans the current visible text, rather than the entire document which makes it a hell of a lot faster.

0 Likes

#8

[quote=“ajpalkovic”]This is a much faster word highlight plugin. It only scans the current visible text, rather than the entire document which makes it a hell of a lot faster.
https://forum.sublimetext.com/t/highlight-current-word/1798/1[/quote]

Got around to trying your version of word highlight. Very nice approach; I will be keeping this around.

I made a couple of changes to suite my tastes: only highlight word when the whole word is selected, and tweaked the highlight style, but I am very pleased with this version. You should take the time to package this up and put it on Package Control. A lot people use WordHighlight, but it has its issues, so I imagine a lot of people would use your version as well.

Thanks.

0 Likes

#9

facelessuser: its funny to read from you that “wordhighlight” has issues because sometimes shows the “slow plugin” message for taking tiny “ms”, when in your plugin (BracketHighlighter) you hacked the “sublime timer” to hide the “slow plugin” error for your plugin. Regards, :laughing:

0 Likes

#10

@facelessuser

let it go :smile:

0 Likes

#11

[quote=“castles_made_of_sand”]@facelessuser

let it go :smile:[/quote]

:smile:

0 Likes

#12

I decided to go ahead and post my mod of ajpalkovic’s plugin here (didn’t want to fork his entire personal plugin folder).

Additions

  • Currently, the plugin highlights the words if your cursor is inside, so I added a setting which also requires you to select the whole word before it begins highlighting. This is False by default.

  • Added a setting to use outline highlighting instead of solid highlighting to mimic WordHighlight’s style. Default is False.

It does seem you have to restart ST2 when you change the highlight style. I think it is because of how the plugin runs.

Bugs

  • There was one insignificant bug that would spew some errors in the console when a file was first loaded because the “word_separators” settings was not yet available, so I just provided a default value for this case so not to spew errors on this.

[code]import sublime
import sublime_plugin

KEY = “HighlightCurrentWord”
STYLE = “solid”
SCOPE = ‘comment’

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

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()
    view = window.active_view() if window != None else None
    self.doSearch(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"") + u" \n\r\t"
    themeSelector = view.settings().get('highlight_word_theme_selector', SCOPE)

    currentRegion = view.word(selections[0])

    # See if a word is selected or if you are just in a word
    if view.settings().get('highlight_word_require_word_select', False) and currentRegion.size() != selections[0].size():
        view.erase_regions(KEY)
        return

    # remove leading/trailing separator characters just in case
    currentWord = view.substr(currentRegion).strip(separatorString)

    #print u"|%s|" % currentWord
    if len(currentWord) == 0:
        view.erase_regions(KEY)
        return

    size = view.size() - 1
    searchStart = max(0, self.previousRegion.a - len(currentWord))
    searchEnd = min(size, 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 = max(0, min(foundRegion.a, foundRegion.b))
        end = min(size, max(foundRegion.a, foundRegion.b))
        if searchStart == end:
            searchStart += 1
            continue
        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
        if start == 0 or view.substr(sublime.Region(start - 1, start)) in separators:
            if end == size or view.substr(sublime.Region(end, end + 1)) in separators:
                validRegions.append(foundRegion)

        if searchStart > searchEnd:
            break

    # Pick highlight style "outline" or the default "solid"
    style = sublime.DRAW_OUTLINED if view.settings().get('highlight_word_outline_style', False) == True else 0

    view.add_regions(
      KEY,
      validRegions,
      themeSelector,
      "",
      style
    )

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

[/code]

**Edit: ** I have recently removed the “on_activated” and “on_close” events I don’t think they are really needed.

0 Likes

#13

Yah, sublime doesn’t properly unload timers when a plugin is reloaded. I’ve posted about it before, but I think the bug reports just tend to get lost in the chaos of the forums. You can repro it by creating an ‘internal’ (not just a single timeout) that just prints hi every seond, then save the plugin five times.

0 Likes