Sublime Forum

Load_settings(base_name) and save_settings(base_name) only searching the User package

#1

In the quest to build my first package (called ck2IDE) I created a ck2IDE.sublime-settings. First I placed it into Packages/ck2IDE/settings, and in a test command used load_settings(ck2IDE.sublime-settings) - but nothing was loaded. Then I used the function to set a setting field and then used save_settings(ck2IDE.sublime-settings) - and it saved to /Pachakges/User/ck2IDE.sublime-settings.

I repeated the operation moving ck2IDE.sublime-settings from /Packages/ck2IDE/settings to /Packages/ck2IDE, and got the same result.

Does this mean that saving/loading settings is hardcoded to only work with the User package? Is that intended or a bug?

1 Like

How to load a custom package setting respecting the Sublime Text settings hierarchy?
#2

Can you provide a small sample of code thatā€™s not working?

When you say sublime.load_settings('ck2IDE.sublime-settings') it should find all files by that name in all paths inside all packages (except that User is special, see below), then combine them together in the order that they were found and load the result.

Packages are found in load order, which is always Default first, User last and everything else in lexical order (plus shipped packages load before user installed packages).

The User package is an exception to the rule in that sublime-settings files that it contains are only found and loaded if theyā€™re in the root of the package. Thatā€™s because when you say sublime.save_settings('ckIDE.sublime-settings') the result is always to save the file at the root of the User package.

The overall idea is that since settings files combine together and User is always last, anything that plugin code does to load settings should come from everywhere, while all saved settings are user specific overrides and should go into the User package. In that package only files in the root of the package are considered presumably to enforce that there can only ever be one file with that name in the package.

1 Like

#3

Oh, so save_settings will save them to the user packageā€¦ interesting, Iā€™ll keep that in mind. I was hoping to use custom setting files to persist custom data in the package itself, but looks like Iā€™ll need to do it with normal python scripting devices then.

As for the loading issue, This is the quick dirty command Iā€™m using to test:

from sublime import *
from sublime_plugin import *

class a_test(TextCommand):
	def run(self, edit):
		settings = load_settings('ck2IDE.sublime-settings')
		print(settings.get('game_folder'))
		settings.set('game_folder', 'replaced')
		save_settings('ck2IDE.sublime-settings')

and these are the contents of /Packages/ck2IDE/ck2IDE.sublime-settings:

{
    // dummy for testing
    "game_folder": "test",
}

The first time running the command, ā€œNoneā€ will be printed in the consle; the subsequent times, ā€œreplacedā€ will be printed. Neve once is ā€œtestā€ printed, signaling that the package-specific settings file is never loaded.

1 Like

#4

Default values should be in your file - donā€™t put it in any different file paths ( this is a huge bug ) and the user can use their settings file of the same name in the User\ folder ( again, no sub-folders ) to change the values to what they wantā€¦

Iā€™ve submitted a report to them in order to allow searching, at the very least, User\PackageName\ for the settings file because otherwise the User folder gets so polluted with a ton of files which shouldnā€™t be thereā€¦

Also - you can load settings files from different paths, but if you do, the User file wonā€™t be properly loaded from - OR if you call save settings when it saves to the user file it wonā€™t be properly saved to either ( itā€™ll see it as a blank ) because of the way files loadā€¦

For instance - load settings/file.sublime-settingsā€¦ edit blah to True from None ā€¦ save to settings/file.sublime-settings will result in an EMPTY fileā€¦

Or, if you try to save to file.sublime-settings using the settings/file.sublime-settings object, youā€™ll get a blank file because it loads the file into memory and uses that - but using nested folders you wonā€™t be able to save and other features will not workā€¦

So you canā€™t have any settings files in a nested folder, unfortunately ( it makes the plugin folders look incredibly unprofessional and efficiency in finding files is greatly reduced )ā€¦

EDIT:

When you load settings - ie sublime.load_settings( ā€˜blah.sublime-settingsā€™ ) - it is loaded into memory and monitored for changesā€¦ you donā€™t need to reload it everā€¦ You can keep calling sublime.load_settings( ā€˜blah.sublime-settingsā€™ ) and it will NOT re-read the file because it is managed in memory meaning you can use that line every time to set data, or get data without repercussion ( ie it is micro-cached )ā€¦

If you use blah.sublime-settings as the file-name, then it will look for that file in Packages*, and Packages\User* and a few other placesā€¦

If a User file exists, and key values which are different will take precedence over the default value in the root folder of your packageā€¦

I recommend setting up helper functions in case the filename ever changes.

1 Like

#5

THanks for the answer. I already knew that once loaded, settings are kept in memory. In any case, looking at how things stand right now, I think Iā€™m better off, for the purpose I wanted my custom settings (just persisting data across runs of Sublime and across all windows), that itā€™s better for me to store the data at the plugin leve and persist it to dist with some custom script.

1 Like

#6

Hmm, I canā€™t replicate this behaviour; I copied your example plugin and settings to the following directory structure in Packages:

tmartin:dart:/tmp/bob/sublime_text_3_3143/Data/Packages> tree ck2IDE/
ck2IDE/
|-- ck2IDE.sublime-settings
`-- command.py

I get results like the following:

Package Control: No updated packages
reloading plugin ck2IDE.command
>>> view.run_command("a_test")
test
reloading settings Packages/User/ck2IDE.sublime-settings
>>> view.run_command("a_test")
replaced
reloading settings Packages/User/ck2IDE.sublime-settings

This is a bone stock sandboxed version of Sublime 3143. If I copy that package folder over to a fresh sandboxed copy of build 3156, I get the same result:

Package Control: No updated packages
>>> view.run_command("a_test")
test
reloading settings Packages/User/ck2IDE.sublime-settings
>>> view.run_command("a_test")
replaced
reloading settings Packages/User/ck2IDE.sublime-settings

Do you see it saying itā€™s reloading the settings every time you run the command? If you put the package in place while Sublime isnā€™t running and then start it, does it work then?

Just as a note on this, it sounds like you want to save some persistent data into your Package folder and not the User folder or something along those lines.If thatā€™s the case, keep in mind that if your package is installed as a sublime-package file, there will be no package folder for you to store data into unless you mark your package as one that needs to be installed unpacked.

If youā€™re working on it for your own use that probably doesnā€™t matter, but if you want to distribute to a wider audience (e.g. through Package Control) thatā€™s less desirable because it means users canā€™t make tweaks to your package without them being clobbered away on updates.

in such a case, unless you have other reasons that require your package to be unpacked, it may be better to store your data in the Cache folder (sublime.cache_path()) instead.

1 Like

#7

There are a lot of bugs when it comes to the Sublime Text settings system. Iā€™ll be making my own to solve some of themā€¦ There isnā€™t true inheritance which is annoying for someone trying to edit one key of a table instead of replace the entire thing.

Also, when a plugin is installed, it seems as though the settings file wonā€™t properly load until Sublime Text restarts - this may be how Iā€™m using the code, but I only grab the data for it after the Plugin is initialized and that should only happen when fully installed and then loadedā€¦ the keys will show up as None until the restart even if you change them.

I have experimented with settings files in different directors - and Sublime doesnā€™t support it by defaultā€¦ It exists the main settings files to be in your package folder, and then all of the User edited variants to be in the User/ folder without being in the package directory which I believe to be a fault of Sublime Text as that folder will get crowded and if the settings file isnā€™t named in such a way to properly identify the plugin it is associated with then that can lead to other issuesā€¦

This is why I wanted to keep the User plugin file in my package folder and the defaults I wanted organized in a settings/ folder in my installed package folder.

It is possible if I recall correctly that you can read the data, but the user canā€™t edit - or youā€™d have to load 2 separate files - 1 default and 1 userā€¦ and do the inheritance manually.

There were a lot of problems involved with trying to load a settings file from a different folder than authorizedā€¦ It was such a big issue, I opened an issue report to see if they could alter the behavior of where Sublime Text looked for the fileā€¦

There is also another problem, I have 4 or 5 settings files and my code is simple - it tries reading a settings file key from one area, and the default redirects it to the next file in the chain all the way through until trying to read the Sublime Text Syntax settings file then the Sublime Text Default settings fileā€¦ The cost for this operation should be minimal since the data is pre-loadedā€¦ Doing something like this is O( 1 ), technically, and the actual cost should be negligible but with Sublime Text, accessing the keys is actually very expensiveā€¦ Another reason I want to make my own system.

I still need to open an issue report because of how expensive it is to get the data from multiple objectsā€¦ It was such a big problem, I had to code different getters for each settings file and hard-code to use the right file in certain areas of my pluginā€¦ It shouldnā€™t be as expensive as it is - it should be a negligible cost, barely noticeable when doing thousands of requests, but it can cost seconds of time for a small amount of requestsā€¦ I still need to figure out if it is because of the User file, or whatā€¦

This is what I am doing:

return self.GetRunTimeSetting( _key, self.GetDefinitionsSetting( _key, self.GetSyntaxSetting( 'acms_' + _key, self.GetMapSetting( _key, self.GetPluginSetting( _key, self.GetPanelSetting( _key, _default ) ) ) ) ) )

which, basically each one has this set now:

	def GetSettingsObject( self, _name = '' ):								return sublime.load_settings( _name )


	## Plugin RunTime Settings
	__settings_file_runtime__												= 'ACMS_RunTime.sublime-settings'
	def GetRunTimeSettingsFileName( self ):									return self.__settings_file_runtime__
	def GetRunTimeSettingsObject( self ):									return self.GetSettingsObject( self.GetRunTimeSettingsFileName( ) )
	def SaveRunTimeSettings( self ):										return self.SaveSettings( self.GetRunTimeSettingsFileName( ) )
	def HasRunTimeSetting( self, _key ):									return self.GetRunTimeSettingsObject( ).has( _key )
	def GetRunTimeSetting( self, _key, _default = None ):					return self.GetRunTimeSettingsObject( ).get( _key, _default )
	def SetRunTimeSetting( self, _key, _value = None ):						return self.GetRunTimeSettingsObject( ).set( _key, _value )

with the first one being the base of allā€¦ and routing through that setup shouldnā€™t add much to a negligible costā€¦

0 Likes