import sublime_plugin
class Test(sublime_plugin.EventListener):
def on_pre_save(self, view):
view.set_syntax_file("Packages/Python/Python.tmLanguage")
Here is simple example. Logically (from my point of view), it should change syntax before saving, and so, the file should be saved as <filename>.py
.
But actually, the syntax will be changed after the save operation. So, if I originally worked with js
file, it will be saved as js
, not py
.
I'm wondering why on_pre_save
works so strange, or, in other words, is there any difference between on_pre_save
and on_post_save
. Also, and that's my practical interest, how I can perform some arbitrary(1) action right before saving?
(1) I've specifically use the word "arbitrary", because I don't mean only syntax changes. It may be something different. For example, change the font from Consolas to Times New Roman.
The on_pre_save
event happens just before a file buffer is written to disk, and allows you to take any action that you might want to take before the file on disk changes, for example making some change to the content of the buffer (e.g. "reformat on save").
The on_post_save
event happens just after the file buffer has been written to disk, allowing you to take any action you might want to take after a save operation, for example examining the contents of the buffer once it's "final" (e.g. "lint on save", which if done through an external tool requires the changes to be on disk and not just in memory).
In either case the file name of the file has already been selected by the user at the time the event happens. For a new file, that means that on_pre_save
doesn't happen until after they've selected the name and location of the file. For an existing file, save
just resaves with the same filename.
To answer your question, you can do most any "arbitrary" thing you want in the on_pre_save
to have it happen prior to when a save happens. It's also possible to change the filename in that situation if you really want to.
Note however that changing the filename out from under the user without asking them first is decidedly bad UX. Additionally, if you change the filename to a file that already exists from within on_pre_save
sublime will blindly overwrite the file with no warnings, which is also Bad Mojo.
For something that's going to alter the name and location of the file on disk, the more appropriate way to go is have a command the user has to explicitly invoke to make that happen so that they're fully aware of what's going on.
As requested in a comment and for completeness, here's an example that does what you wanted your example code above to do.
The important thing to note here is that you have to be extremely careful about the situation that you trigger this event in. As written above, your plugin would make it impossible to ever save any kind of file ever due to it swapping over to a python file instead.
In this example it's constrained to only take effect on a text file, turning it into a python file. Note however that if there was a python file with that name already in that location, it would overwrite it without warning you that it's about to happen.
Be extremely wary with this code; it's quite easy to accidentally stop yourself from being able to save files with the correct name, which could for example stop you from being able to use Sublime to fix the code, amongst other nasty issues.
import sublime_plugin
import os
class TestListener(sublime_plugin.EventListener):
def on_pre_save(self, view):
# This part is extremely important because as mentioned above it's
# entirely disconcerting for your save operation to gank your
# filename and make it suddenly be something else without any
# warning. If you're not careful you might destroy your ability to
# use sublime to fix your plugin, for example.
if not view.file_name().endswith(".txt"):
print("Doing nothing for: ", view.file_name())
return
# HUGE WARNING: This CAN and WILL willfully clobber over any file
# that already happens to exist without any warning to you
# whatsoever, and is most decidedly a Bad Idea(tm)
python_name = os.path.splitext(view.file_name())[0] + ".py"
view.retarget(python_name)