Sublime Forum

[SOLVED] Time stamp html files (only) on save

#1

I want to update a time stamp string in ,html files on save. The following command updates the time stamp strang, but I do not see how to automate this to work on save, but only for .html files. Thanks for any help.

`import sublime, sublime_plugin, datetime

class TimeStampOnSaveCommand(sublime_plugin.TextCommand):
def run(self, edit):
content = self.view.find("", 0, sublime.LITERAL)
if content.empty(): return # no time stamp requested

	content = self.view.line(content) # get whole line
	timestamp = "Updated %s" % (datetime.datetime.now().strftime("%A, %B %d, %Y %I:%M:%S %p").lstrip("0").replace(" 0", " "))
	self.view.replace(edit, content, "<!-- TSBegin --> " + timestamp  + " <!-- TSEnd -->")

`

0 Likes

#2

I managed to get things working, as follows.

# *******************************************************************
import sublime, sublime_plugin, datetime 

class TimeStampOnSaveCommand(sublime_plugin.TextCommand):
	def run(self, edit):
		# .html files only
		if (self.view.file_name().endswith('.html') == False): return

		# Get time stamp line, if any
		content = self.view.find("", 0, sublime.LITERAL)
		if content.empty(): return # no time stamp requested

		content = self.view.line(content) # get whole line
		timestamp = "Updated %s" % (datetime.datetime.now().strftime("%A, %B %d, %Y %I:%M:%S %p").lstrip("0").replace(" 0", " "))
		self.view.replace(edit, content, " " + timestamp  + " ")

class TimeStampOnSaveListener(sublime_plugin.EventListener):
	def on_pre_save(self, edit): 
		sublime.active_window().run_command('time_stamp_on_save')
0 Likes

#3

You want to use an event listener for that and trigger on the pre-save event. Here’s a simple example:

import sublime, sublime_plugin, os.path

class TimeStamper(sublime_plugin.EventListener):
    # Invoked before a view is saved
    def on_pre_save(self,view):
        # Leave if syntax is not HTML-ish
        if "HTML" not in view.settings ().get ("syntax"):
            return

        # Run the command; or, inline it here
        view.run_command ("time_stamp_on_save")

This takes the tack of checking the syntax set for the file to see if it’s something HTML-like; that way it will trigger on the first save if you happen to have already set the syntax.

It invokes the command you already mentioned above on the view being saved, but you could also inline that particular command if you wanted to. For example, if you only wanted to invoke this on save and never via a key combination, it doesn’t necessarily need to be defined as a command.

1 Like

#4

This is very helpful. Also, I wasn’t aware of using view.settings() to determine the file type. Thanks very much.

0 Likes

#5

I am trying to inline the command, but when I edit and save the following, the console gives the error

TypeError: on_pre_save() missing 1 required positional argument: 'edit'

What am I doing wrong?

import sublime, sublime_plugin, datetime 

# Adice: https://forum.sublimetext.com/t/restrict-command-to-file-type-html-on-save/21572
class htmlTimeStampOnSaveListener(sublime_plugin.EventListener):
    # Invoked before a view is saved
	def on_pre_save(self,view):  
		# Leave if syntax is not HTML-ish
		if "HTML" not in view.settings().get("syntax"):
			return

		# Get time stamp line; leave if none
		content = self.view.find("<!-- TSBegin -->", 0, sublime.LITERAL)
		if content.empty():
			return

		content = self.view.line(content) # get whole line
		timestamp = "Updated %s" % (datetime.datetime.now().strftime("%A, %B %d, %Y %I:%M:%S %p").lstrip("0").replace(" 0", " "))
		self.view.replace(edit, content, "<!-- TSBegin --> " + timestamp  + " <!-- TSEnd -->")
0 Likes

#6

Ahh yeah, sorry, I totally gave you some bum info there. Sorry about that. :frowning: You actually have to do it the way that you were doing it originally. My bad.

The gist of this is that in order to invoke the view.replace() method you need an instance of an edit object, but there isn’t one defined anywhere in the code you posted (the offending line is self.view.replace (edit, content, ...)) and so it’s getting mad.

An edit object is something that is used to group buffer modifications that happen as a part of a command together so that they can be undone by the undo command. Unfortunately, you can’t create edit objects yourself, you can only use the ones that you’re given by Sublime.

Sublime passes them to the run method of a TextCommand as seen in your original code, but not to an event handler. The only way to get an edit object is to work this like you were originally and have the event handler invoke the command on the view. The internals of view.run_command take care of getting the edit object for you.

Again, apologies for leading you down the wrong path, there.

0 Likes

#7

Got it, and no problem. Thanks for helping me along the learning curve.

Here is the current version, renamed html_time_stamp_on_save to make clear it only works with html files.

import sublime, sublime_plugin, datetime 

# ctrl-`: Test with view.run_command('html_time_stamp_on_save')
# Advice: https://forum.sublimetext.com/t/restrict-command-to-file-type-html-on-save/21572
class htmlTimeStampOnSaveCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        # Time stamp line formatted for .html files only
        if (self.view.file_name().endswith('.html') == False): return

        # Get time stamp line; leave if none
        content = self.view.find("<!-- TSBegin -->", 0, sublime.LITERAL)
        if content.empty(): return

        # Update time stamp line
        content = self.view.line(content) # get whole line
        timestamp = "Updated %s" % (datetime.datetime.now().strftime("%A, %B %d, %Y %I:%M:%S %p").lstrip("0").replace(" 0", " "))
        self.view.replace(edit, content, "<!-- TSBegin --> " + timestamp  + " <!-- TSEnd -->")

class TimeStampOnSaveListener(sublime_plugin.EventListener):
    def on_pre_save(self, edit): 
        sublime.active_window().run_command('html_time_stamp_on_save')

0 Likes