Note: I am going to do a few minor tweaks - but I may leave it as is for this post…
Since I don’t like hard-coding values which may not make sense ( the -3 does for .py since it’s for python files to be reloaded ) I will add a var designating which extension it is to track so either .py is entered, or just py and I’ll then change the value as -1 shift is common and easier to identify than -3… but, I may leave it too… since the 0-5 for User. exists and I’m not sure if I see much of a point of adding it - different languages wouldn’t be using different folder names ( or? )… we’ll see…
Hopefully this helps someone though.
New
##
## Main Plugin Auto-Refresh System - Josh 'Acecool' Moser
##
##
## Imports
##
import sublime_plugin
##
## This Event Listener is specifically to enable auto-refreshing of plugin core files when they're edited... It is purposefully kept separate so others can learn from it / use as a drop-in module for thier own plugins...
##
class AcecoolCodeMappingSystemDynamicPluginReloaderEventListener( sublime_plugin.EventListener ):
##
## Important Data...
##
## The package name used for reloading files listed below...
PackageName = 'AcecoolCodeMappingSystem'
##
## When a package Python file has been saved, we auto-refresh only that particular file... - Note: If you update this function you will need to save twice - the first time uses the current method in memory for output, and the second time shows you what the function has become...
##
def on_post_save_async( self, _view ):
## Grab the file-name of the file which was saved
_file = _view.file_name( )
## Grab the extension of the saved file - note this doesn't work on files with more than 1 extension or decimal - as per Python file-naming / import conventions, do not add decimals to the file-name. Only use 1 extension such as file.ext - anything else will not be importable using the import call, you'll need to manually execute the code behind the import call which is messy and can lead to issues if you're unfamiliar with the system and it can lead to other problems..
_ext = _file.split( '.' )[ - 1 ] == 'py'
## Determine the index of the package name, if it exists..
_index = _file.find( self.PackageName )
## If we've saved a python file inside of our Package, then we assemble the include...
if ( _ext and _index > 0 ):
## Note: Either of the following _plugin assignments will work, simply uncomment one and comment the other - the comment details exactly what happens with each example...
## For simplicty convert all folders to decimals...
_file = _file.replace( '\\', '.' )
## This method takes Path\To\||PackageName\InternalFolders\FileName||[[.py]] - [[...]] being subtracted from the return using -3, ||...|| being what's captured starting with _index + len( ... ) through -3... - After we capture what's needed ignoring the rest, we replace backslashes with decimals.
_plugin = _file[ _index : - 3 ]
## This method takes: Path\To\PackageName||\Internal\Folders\FileName||[[.py]] - we leave the left \\ ( by not adding + 1 to _index + _len ) to convert it to a decimal so we don't need to manually add it... [[...]] being subtracted from the return using -3, ||...|| being what's captured starting with _index + len( ... ) through -3...
## _plugin = self.PackageName + _file[ _index + len( self.PackageName ) : -3 ]
## User Folder Clause - If User is found in the file-name, and the index is LESS than the name of the package-name, then we are in Packages\User\ACMS\ so we need to account for that...
_plugin_user = _file[ _index - 5 : - 3 ]
if ( _plugin_user.startswith( 'User.' ) ):
_plugin = 'User.' + _plugin
## Print it out to make sure it works..
print( '>> Dynamic Package File Reloader > On Save Event Triggered for Package File: "' + _file + '" - Which converts to Import Plugin: "' + _plugin + '"' )
## Reload our Package File...
sublime_plugin.reload_plugin( _plugin )
Here’s a new version - I added support for User. folders - since I am using _file with the replaced chars for more than 1 area I now set a designated reference for it, then I simply check to see if -5 chars starts with User. and if so I add User. to the main plugin path…
And if it wasn’t clear, it works for unlimited nested paths which is nice… since my addon will use Py files in the User folder, this was something I needed
Old
Solution:
The dynamic version is what I use because I like having nested folders, etc… and because the logic is less expensive compared to the non-dynamic variant, and it requires less user interaction to set up… Simply drop it in and done…
Notes: The class name can be set to what-ever you want as far as I know, and the PackageName needs to be set to the folder-name the system will ‘subscribe’ to to look for changes / saved files within that package name within \Sublime Text 3\Packages<PackageName>\* — The package must be extracted ( I know that when a package is updated the change is automatically loaded into memory so this shouldn’t be necessary for packaged addons, but when you’re developing an addon, it is much easier to deal with loose files and this is what it is for )…
##
## Main Plugin Auto-Refresh System - Dynamic Variant - Josh 'Acecool' Moser
##
##
## Imports
##
import sublime_plugin
##
## This Event Listener is specifically to enable auto-refreshing of plugin core files when they're edited... It is purposefully kept separate so others can learn from it / use as a drop-in module for thier own plugins...
## Note: The class name can be anything you want as far as I know...
##
class AcecoolCodeMappingSystemDynamicPluginReloaderEventListener( sublime_plugin.EventListener ):
##
## Important Data...
##
## The package name used for reloading files listed below...
## Note: This needs to be set to the folder-name this auto-refresh system will subscribe to for change-detection and auto-reloading of files within...
PackageName = 'AcecoolCodeMappingSystem'
##
## When a package Python file has been saved, we auto-refresh only that particular file... - Note: If you update this function you will need to save twice - the first time uses the current method in memory for output, and the second time shows you what the function has become...
##
def on_post_save_async( self, _view ):
## Grab the file-name of the file which was saved
_file = _view.file_name( )
## Grab the extension of the saved file - note this doesn't work on files with more than 1 extension or decimal - as per Python file-naming / import conventions, do not add decimals to the file-name. Only use 1 extension such as file.ext - anything else will not be importable using the import call, you'll need to manually execute the code behind the import call which is messy and can lead to issues if you're unfamiliar with the system and it can lead to other problems..
_ext = _file.split( '.' )[ - 1 ] == 'py'
## Determine the index of the package name, if it exists..
_index = _file.find( self.PackageName )
## If we've saved a python file inside of our Package, then we assemble the include...
if ( _ext and _index > 0 ):
## Note: Either of the following _plugin assignments will work, simply uncomment one and comment the other - the comment details exactly what happens with each example...
## This method takes Path\To\||PackageName\InternalFolders\FileName||[[.py]] - [[...]] being subtracted from the return using -3, ||...|| being what's captured starting with _index + len( ... ) through -3... - After we capture what's needed ignoring the rest, we replace backslashes with decimals.
_plugin = _file[ _index : - 3 ].replace( '\\', '.' )
## This method takes: Path\To\PackageName||\Internal\Folders\FileName||[[.py]] - we leave the left \\ ( by not adding + 1 to _index + _len ) to convert it to a decimal so we don't need to manually add it... [[...]] being subtracted from the return using -3, ||...|| being what's captured starting with _index + len( ... ) through -3...
## _plugin = self.PackageName + _file[ _index + len( self.PackageName ) : -3 ].replace( '\\', '.' )
## Print it out to make sure it works..
print( '>> Dynamic Package File Reloader > On Save Event Triggered for Package File: "' + _file + '" - Which converts to Import Plugin: "' + _plugin + '"' )
## Reload our Package File...
sublime_plugin.reload_plugin( _plugin )
Hopefully this helps the next person who needs something to auto-refresh…
Original Post below:
I’m working on the edit_settings_plus command and I’ve run into a new problem…
When I save the file which contains it - the print statements in run doesn’t change when I execute the command…
I’ve tried calling sublime_plugin.reload_plugin( ‘Acecool_CMS.Acecool_CMS’ ) for Acecool_CMS/Acecool_CMS.py and while it may say reloading plugin in console - the print statements and logic only updates when I restart sublime text…
I used to have this issue on imported files but sublime_plugin.reload_plugin solves that… But why isn’t it working for an Application Command?
I can’t seem to find anything related ( sublime-syntax files update for me just fine, sublime-menu files update flawlessly too on save, etc… ) also the other logic in the file updates and I can print outside of the class edit_settings_plus and it’ll update - just not the actual command…
If it was a matter of updating the class - I’d think overwriting it would work but it doesn’t…
Any suggestions would be welcome!
So far I’ve got a lot of functionality added - the base_file, user_file, default can be text or List with basic entries all lined up - file_list can be a List with Dict entries containing base_file, user_file, default and some are optional… I still need to process a few things before it’s done but having to relaunch every edit would make something that wouldn’t take long and exponentially increase the time it takes…