Sublime Forum

API: How to tell whether a View object represents an "unusual" view?

#1

By “unusual” view, I mean stuff like the “Find Results” panel, i.e. views which are not the code editor in the main part of the Sublime window.

1 Like

Determining what kind of widget a view represents
#2

You can determine what some views are for using some tests, but I don’t think there is a generic way to know with 100% certainty for all possible views; can you elaborate on why you’re trying to distinguish them?

For example, the input widgets in the quick panel, command palette, console etc have a setting of is_widget that’s applied to them to distinguish them from other views.

The window.panels() method returns the names of all of the listed panels in that window, and window.find_output_panel() will return the view associated with a panel by name. Thus you can use view.id() on a view and compare it to the id of one of those views to see if it appears to be a panel or not.

Note however that it’s possible for a plugin to create a panel that’s unlisted (that is, not displayed in the panel switcher menu), in which case you would be unable to distinguish it from a regular view in the general case.

2 Likes

#3

The “Find Results” view is an ordinary view. There are a couple of ways to check whether a view is a Find Results view:

view.name() == 'Find Results'
view.settings().get('syntax') == 'Packages/Default/Find Results.hidden-tmLanguage'

Of course, there’s nothing stopping you or anyone else from creating a view with that name and syntax.

You can usually tell whether a view is a panel thus:

view.settings().get('is_widget')

However, this setting could be modified by anyone on any view. You can find out if a view is a listed panel as follows:

any(view == window.find_output_panel(panel[7:]) for panel in window.panels())

But unlisted panels do not show up here.

2 Likes

#4

Thank you both for the detailed info.

The reason it came up was because with this package, I noticed that if one of those so-called modelines appeared in Find Results, the plugin could kick in and change the syntax highlighting used in that panel. And it doesn’t make sense for the entire Find Results to be presented with, for example, Bash syntax highlighting.

So I put in some print debugging and noticed that the plugin was also being activated in all kinds of “unusual” views in addition to the Find Results panel.

1 Like

#5

Ahh, yeah I can see how that might be annoying. That’s an example of something that takes a little bit more work to detect and is not entirely foolproof.

For example since this is a find results, it could see if the view is a panel. However it’s possible for find results to show up in a buffer, so that doesn’t help. It could also check for a view with a specific name, but if someone happened to create a package that used ripgrep to search, it might use a different view name and have the same problem.

At some level there is either a trade off where something like this happens or the package is made more configurable; for example to block it from doing anything when the syntax is something specific, or having the ability to turn off the on_activated event listener and just have it fire on_load.

In this case the regular expression that the package is using isn’t anchored at the start of a line; if it was, then the hits in the search wouldn’t trigger because they all start with line numbers (unless your filename is named the same as a mode line, in which case you may have other issues :wink: ).

I don’t know enough about how emacs works to know if that is a helpful or breaking change, though. Also it would not help in the hypothetical situation I outlined above, if some other package generates text in a way that the regex would still match.

2 Likes

#6

I think this is what frou was looking for:

view == view.window().active_sheet().view()
1 Like

#7

Good idea. How about this tweak?

# Test whether `view` is a "normal" view:
any(sheet.view() == view for sheet in view.window().sheets())

Though, as @OdatNurd mentioned previously, this is not bulletproof for the Find Results in particular, because there is the toggle button allowing it to appear either as a Panel or a Buffer (View).

0 Likes

#8

If the Find Results are in the main view of a sheet/tab (instead of a panel), is that still a case that you would consider “unusual” for your purposes? Because I was thinking you meant any time that the view is the main view for a sheet/tab (of any kind), it would qualify as not-unusual, and anything else is unusual. At least that’s what I was looking for, for what I was doing. And that was the result I got with my solution. Or maybe we mean the same thing, and I’m not seeing what you’re seeing? (If so, how do you get to the scenario you’re talking about.)

If you did want to treat things like the Find Results (as a main view) as unusual, what about adding a check for view.is_scratch() too? That flag’s probably pretty common for “unusual main” views.

view == view.window().active_sheet().view() and not view.is_scratch()
0 Likes

#9

BTW, I think my active_sheet() step can be skipped. This seems to be equivalent:

view == view.window().active_view()

or

view == view.window().active_view() and not view.is_scratch()
0 Likes

#10

What I ended up with for my purposes (the Emacs-esque feature mentioned earlier) was checking the settings argument in the class-method ViewEventListener.is_applicable for "is_widget" and subsequently, if needed, early-returning from the event-handling instance-methods like ViewEventListener.on_load when not view.file_name() or view.is_scratch()

Find Results being a View rather than a Panel was just a hypothetical - I personally never have it set to do that.

0 Likes

#11

I see. Too bad is_applicable only lets you check settings.

Out of curiosity, would you want your plugin to work if it didn’t have a backing file yet? Like for a new file.

0 Likes

#12

@epost

Saving being a lightweight “checkpoint” for automated things to happen is kinda nice. (Even more so for linting, where continuous analysis can cause more distraction than its worth)

0 Likes

#13

Note that any method involving .active_*(), e.g. .active_view(), will not work for view objects that are not the active view, for obvious reason. An example would be a command being executed on a view that is not currently active (through the API).

0 Likes

#14

Thanks. If I’m getting the gist of what you mean, I think that’s actually the desired effect for what I was trying to do (sorry, I’m sort of hijacking this thread – frou’s is slightly different). I have certain commands I don’t want accidentally run on views other than the “active” view. (I didn’t realize before that “active” was the proper term.)

0 Likes

#15

(2020 update) There’s a forthcoming API that’s relevant to this.

0 Likes