Sublime Forum

on_activated on startup

#1

I have an EventListener plugin who’s on_activated method isn’t getting called on startup in ST3. Is this as designed in ST3? If so, what’s the recommended way of getting a plugin to do something on startup?

I have the following, which feels a bit dirty and causes a visual hiccup between the time of Sublime starting and the timeout firing:

[code]def plugin_loaded():
sublime.set_timeout(force_active)

def force_active():
view_id = sublime_api.window_active_view(sublime_api.active_window())
sublime_plugin.on_activated(view_id)
[/code]

0 Likes

#2

…and actually, I ran into a different but related issue - there’s a different plugin I’m using that seems to be crashing over what appears to be a race condition between its EventListener.on_activated and its plugin_loaded function. Its on_activated is making the assumption that plugin_loaded is always run beforehand, but that doesn’t seem to be the case (restarting ST3 multiple times in a row shows it sometimes is and sometimes isn’t).

0 Likes

#3

on_activated isn’t called during startup. I’ll make a change for the next build so a call is synthesised, which makes more sense.

In general, I believe on_activated cannot be called before plugin_loaded, unless another plugin is changing focus in its plugin_loaded call, which would cause on_activated to be called before the next plugin receives its plugin_loaded call.

0 Likes

#4

Great, thanks!

0 Likes

#5

I would expect the plugin_loaded function is always run before any other plugin implementations (commands, events). It may even happen that events depend on the plugin_loaded function to have run before (e.g. if it imports modules or defines globals).

So, maybe it would be possible keep track on all the event-firing calls within plugin_loaded and fire them after all plugins finished loading? I can imagine that being complicated, though.

0 Likes

#6

There is no neat solution unfortunately. If events were queued up, then that would break other contracts. For example, on_modified is currently always called before run_command returns, and queueing up the event would break this.

The reality is that Sublime Text relies on plugins being good citizens in any case (e.g., not doing blocking io in the main thread, not doing a lot of computation in the main thread), and not doing things like changing input focus in response to plugin_loaded in part of that: I can’t imagine how that would ever be a good user experience, for example.

I’m not quite sure why jburnett would have been seeing on_activated getting called before plugin_loaded sometimes, while a plugin switching input focus in response to plugin_loaded() would cause this, I’d be surprised if such a plugin even exists at this point in time.

0 Likes

#7

A bit more detail (one was a red herring):

One plugin (my own hacky thing) was doing an open() in plugin_loaded. This apparently causes a change to sys.modules (at least it does on Windows), which led to the crash in 3010 (and fixed in 3011 - again, thanks!).

The red herring was that another (public) plugin after that was crashing in its on_activated because its on_loaded never got the chance to run (because of the crash above). I’m still not sure why it sometimes happened and sometimes didn’t. Is plugin load order somewhat guaranteed to be in some kind of order?

In any case, I’ll chalk to latter bit to it being late :smile:

0 Likes

#8

There seems to be a bit more happening out of order… I’m seeing things like on_selection_modified happening before on_activated. Here’s a boiled down example:

[code]import sublime_plugin

class TestListener(sublime_plugin.EventListener):
def on_activated(self, view):
print(‘test.on_activated’)

def on_selection_modified(self, view):
    print('test.on_selection_modified')

def on_selection_modified_async(self, view):
    print('test.on_selection_modified_async')

[/code]

Dump that into a test py file, make sure remember_open_files is enabled so you get a buffer opened by default, and restart ST3 (3012 here). After restart, immediately click in the open view, and then open the console. You’ll see that on_selection_* was called before on_activated.

…is this as designed now?

0 Likes

#9

One more (again, this is different from ST2, but not sure if this is as designed now)… When on_activated is called after open a file, the passed in view does not yet exist in the any of the views you get from the global sublime.windows().

import sublime import sublime_plugin class TestListener(sublime_plugin.EventListener): def on_activated(self, view): this_view_id = view.id() all_view_ids = set([view.id() for window in sublime.windows() for view in window.views()]) print('view exists:', this_view_id in all_view_ids, this_view_id, all_view_ids)

In ST2, the above will print “view exists: True” when you open a new file. ST3 will print twice, the first is False, the second True.

0 Likes

#10

I am running build 3103 and I noticed that when launching ST3, the plugin’s EventListener on_activated is called for the active view, but on_activated_async doesn’t - is this as designed?

2 Likes

#11

I guess one way to workaround it for now, is to have an on_activated listener that will use sublime.set_timeout_async to execute the desired code.

0 Likes

#12

Yeah, thats what I did in the end - it just seemed weird.

0 Likes

#13

this would be a really easy fix @jps and @wbond to integrate the workaround I suggested directly - lines 106 and 107 in sublime_plugin.py are:

if "on_activated" in dir(obj):
    on_activated_targets.append(obj)

and line 131 does the calling.

1 Like