Sublime Forum

Best way to deal with highlighting multi-line function definitions

#9

view.extract_tokens_with_scopes is probably more useful

4 Likes

#10

Looks like something awesome is missing in the official doc :smile:

1 Like

#11

That does make sense, thanks! It would seem reasonably efficient. And I’m going to do it the other way around: search for uncategorised blocks (of which there should be none), then go backwards scope by scope until a non-comment, not-just-source scope is found; if the scope found is a function declaration, add a comment ;{ to the end of the line, so the syntax-highlighter (which I am writing myself) will recognise it as a function definition; if the scope found is something else, continue to the next uncategorised block.

I think I should probably only run this on load or save, because it may use too much processing power if it is e.g. run on each character typed.

By the way, how did you make those underlines? They look very nice. Are you using syntax highlighting / colour scheme, or is it something from a plug-in? I have so far failed to make underlines in a colour scheme. I don’t think I could do it in a plug-in either, but I don’t remember exactly.

0 Likes

#12

That is a very interesting, undocumented function! So what view.extract_tokens_with_scopes does is take a region and return all scopes found inside it as an array of regions. In locating the function line belonging to an uncategorised block, I’m not entirely sure whether this would be preferable to just using .extract_scope (or am I mistaken?); but it will certainly prove useful in many other cases where I want my plug-in to parse scopes! I already have a use case in mind, cool.

0 Likes

#13

This will make you disappointed :slight_smile:
It’s made by a handy screenshot tool. https://www.snipaste.com
Strongly recommended if you are using Windows.

0 Likes

#14

This is one of the reasons to use the add_regions() API endpoint on a view. For example, try selecting some text in a file and then entering this in the Sublime console:

view.add_regions("test", view.sel(), "region.redish", flags=sublime.DRAW_SOLID_UNDERLINE | sublime.DRAW_NO_FILL | sublime.DRAW_NO_OUTLINE)
0 Likes

Markup text ranges for warnings/hints?
#15

Excellent. Is it possible to add tooltips to the regions so if you hover your mouse over them you get some information? I think I may have seen this by adding symbols in the gutter also but I can’t remember where.

0 Likes

#16

The EventListener.on_hover() event triggers when the user hovers the mouse; one of the arguments it gets tells you where the hover is happening.

So you could have an event listener for that and check if hover_zone == sublime.HOVER_TEXT, and if so check the regions you’ve saved to see if the point falls within one of them or not. From that you could use view.show_popup() to generate a tooltip.

0 Likes

#17

I think I get it. That means I need to keep a persistent list of warnings also so I can reference them later.

Just looking at this now I’m not seeing how view.add_regions is going to work because I don’t have a reference to the correct view for the given file. For example if you’re parsing errors from a compiler you get paths/names with corresponding line numbers but how do you translate that file name to a view object I can call add_regions on? Is that even possible?

0 Likes

#18

If the file is open, window.find_open_file() will return the view object that’s associated with the file with that name; alternatively you could also iterate over all of the views in a window and check their file_name() property to see if it matches, but find_open_file() is likely faster because it’s in the core. Presumably it would also take care of things like case sensitivity checks on platforms that support that sort of thing (though I don’t know if that’s actually the case or not).

For a case like this you can only apply regions to files that are open, so you can do it right at the time you capture the messages but you also need to do something like an on_load() event listener to detect when new files are opening so you can check and see if they need any regions.

The exec command does it that way; every time a file opens it executes the exec command with an argument that tells it to update annotations. The magic of file_regex in a build makes Sublime try to open files when you double click on them, which integrates nicely.

0 Likes

#19

Thanks, I got it now.

One last thing is that I can’t figure out how to map get a region for the line/column. add_regions wants a Selection object right? Here’s what I’m trying to do with no luck.

    line_num = 10
	pt = a_view.text_point(line_num, 0)
	sel = sublime.Selection(0)
	sel.add(sublime.Region(pt))
	a_view.add_regions("warning", sel, "region.redish", flags=sublime.DRAW_SOLID_UNDERLINE | sublime.DRAW_NO_FILL | sublime.DRAW_NO_OUTLINE)
0 Likes

#20

view.add_regions() wants a list of region objects. The Selection class represents selections that way, which is why it’s a handy test to do that in the console.

In order to do what you want here you need to pass it something like [sublime.Region(0, 10), sublime.Region(20, 25)] or such; a list of manually constructed regions.

Note however that something like sublime.Region(10) will give you a region that starts and end at character position 10 only; so in that case the region won’t display because it’s empty, and you’d also have to hover the mouse at exactly that point later as well.

You can use view.text_point() to convert a row and column (both 0 based) to a point for use in the region constructor. On the flip side you can use view.rowcol() to convert a point into a (row, col) tuple if you need to go in the other direction. Lastly, view.line() will return back a region that spans the line that the position that you give it is in.

So taken all together, you could wrap the whole of line 10 with something like this:

line_pos = view.text_point(10 - 1, 0)
line_region = view.line(line_pos)
view.add_regions('warning', [line_region], "region.redish", flags=sublime.DRAW_SOLID_UNDERLINE | sublime.DRAW_NO_FILL | sublime.DRAW_NO_OUTLINE)

Note also that the hover event will give you a single point that says where the cursor is; if you use view.get_regions() you will get a list of all of the regions with the key you provide, and it’s always sorted from the top of the file down. You can use the region.contains() method to easily determine which region contains the point (if any) and then use that index to determine what the hover text should be.

0 Likes

#21

Thanks I think I got it now. You’ve been really helpful as always.

0 Likes

#22

Hah! Thanks for the link

0 Likes

#23

Ah, thanks, that works! So it is not possible to add an underline using a colour scheme?

0 Likes

#24

By the way, do you know Sublime Linter? It will automatically mark errors and warnings, you’d only need to write a simple plug-in to have it get the errors and warnings from your compiler or other external linter. It also has pop-ups.

0 Likes

#25

That is correct; currently the only font effects that can be applied via the color scheme are bold and italic, although it has been mentioned that the next series of builds is going to include a glow effect as well.

0 Likes

#26

Getting back to this today and found another issue. Currently I need to keep track of the warnings by line number so I can reference them for on_hover events. This is fine of course unless the document changes lines and then things get out of sync.

Is there a way to assign arbitrary data to the regions so I could reference the region by some unique ID? If ST gave each region a unique ID that was returned from add_regions that would be good also but I don’t see that’s the case.

0 Likes

#27

Thanks for the tip. I never heard of it before but maybe I should go that route.

0 Likes

#28

Technically, I referred to it in the original thread that linked to this one as something that does the thing you’re trying to do here. :wink:

0 Likes