Sublime Forum

How to wait until view is loaded. Event handler?

#1

Hi all,

I’m a 53 year old newbie - waited as long as I could to post here, but I’m stumped.

I am writing a simple plugin to handle wiki-like link references in Markdown so that I can cross reference between headers in my work notes. I have three different styles per Markdown convention:

[header] - header within the same file
Some text - header within the same file with alternate link name
Some text header within some other file (type 3 below)

First two work fine - I take the header text “slugify” per method provided in Markdown packages, find the matched location and center the view on the header. The last one works fine if the file is already in a view - view switches to the other file, then centers on the header.

The problem I have is if the other file is not already open: it looks like the search for headers is executing before the file is loaded, so no headers are found.

It looks to me like I need to use the on_load event listener to wait until the file is fully loaded into the view before searching for headers, but I can’t figure out how this is done.

Here is the relevant portion of my code:

		# Form path to file and open if type 3
		if lType == 3:
			path = text[int(lPath)+1:int(rPath)]
			activeView = self.view.window().open_file(path)
			activeView.window().focus_view(activeView)
		else:
			activeView = self.view.window().active_view()
		print(activeView.file_name())
		print(activeView.is_loading()) #Always returns TRUE if file wasn't already in a view
		
		## Need to wait under new file is loaded, something
		## to do with EventListener.on_load()?

		# find all the headers, slugify, and stop on a match
		locations = activeView.find_all('^\#]+')
		while len(locations):
			location = locations.pop(0)
			slug = slugify(activeView.substr(activeView.line(location.end())),'-')
			print(slug)
			if slug == link:
				print('match!')
				activeView.show_at_center(location)
				break

Any help would be appreciated.

  • Kurt
0 Likes

#2

Hi,
the following is not tested, only quick and dirty :wink:
To make your plugin safe, it would be usefull to insert a timer in the while-loop to avoid a endless-loop if loading fails.

[code]class YourPluginCommand(sublime_plugin.TextCommand):
has_load = False
file2load = None
def run(self, edit):
# your code here
# set the path of the file you want to load
self.file2load = “File_Path”
# the EventListener sets “has_load” if ready, wait until this happens
while not self.has_load:
pass
# reset “has_load” and “file2load”
self.has_load = False
self.file2load = None
# here follows your other code

class EventListener(sublime_plugin.EventListener):
# Called when a file is finished loading.
def on_load(self, view):
# checks if an file is to load from your plugin
if not YourPluginCommand.file2load:
return
# is this the file you wait to load?
if view.file_name() == YourPluginCommand.file2load:
YourPluginCommand.has_load = True[/code]

0 Likes

#3

i think it would be better to pass a callback to it, like having a global callback table

[code]callbacks_on_load = {}

class YourPluginCommand(sublime_plugin.TextCommand):
def run(self, edit):
global callbacks_on_load
bar = 42
callbacks_on_load"File_Path"] = lambda: self.foo(bar)

def foo(self,bar):
    # here follows your other code
    pass

class EventListener(sublime_plugin.EventListener):
# Called when a file is finished loading.
def on_load(self, view):
global callbacks_on_load
if view.file_name() in callbacks_on_load:
callbacks_on_loadview.file_name()
del callbacks_on_load[view.file_name()]
[/code]

0 Likes

#4

Thanks so much for both answers. I’ll definitely look at the callback. In the mean-time, here’s what I came up with…

The “set_location” method takes the opened view and the link text, finds the corresponding header and centers the
view on it. If I have a type 3 link (defined above) and the file isn’t already open in a view, then I let the on_load_async
(file opening is an asynchronous operation) event call the set_location method.

class OpenLinkUnderCursorCommand(sublime_plugin.TextCommand):
	link = str('')
	def run(self, edit):
		sel = self.view.sel()[0]
		text = self.view.substr(self.view.line(sel))
		position = self.view.rowcol(sel.begin())[1] # position of the cursor on the line

		# Determine the type
		lType = link_type(text,position)

		# Determine the path ends (type 3) and link ends (all types)
		index = set_point(lType,text,position)

		# Form slugified link
		self.link = slugify(text(index[2]+1):index[3]],'-')

		if lType == 3:
			# If already open, change view to it then set location
			# Otherwise open the file, and let event listener set location
			pathName = text(index[0]+1):index[1]]
			isView = self.view.window().find_open_file(pathName)
			if isView:
				self.view.window().focus_view(isView)
				activeView = self.view.window().active_view()
				set_location(activeView,self.link)
			else:
				OpenLinkUnderCursorCommand.link = self.link
				self.view.window().open_file(pathName)
		else:
			# type 1 or 2
			activeView = self.view.window().active_view()
			set_location(activeView,self.link)

class EventListener(sublime_plugin.EventListener):
	def on_load_async(self,view):
		set_location(view,OpenLinkUnderCursorCommand.link)

Thanks again for the help - definitely learned a lot!

  • Kurt
1 Like