Plugins are the primary way to extend XYZCommander functionality. In fact even base functionality is implemented mainly via plugins.
Plugins are being held in one of the following directories:
In these directories namespace subdirectories are created (see below for more details).
Plugin entry-point is a main.py file inside plugin directory. This file should contain class named XYZPlugin sublclassed from libxyz.core.plugins.BasePlugin class.
XYZPlugin class should define following mandatory attributes:
Also some optional attributes can be defined:
Namespaces are used to hierarchically organize exported methods and to prevent method-names collisions.
Typical plugin namespace path is:
:<namespace>:<plugin-name>
Here <namespace> is one of the available namespaces:
- sys - Virtual system plugins
- core - Core plugins
- ui - User-interface related
- vfs - Virtual file-system related
- fsrules - FSRules extensions
- misc - Other miscellaneous
All plugin management is performed using PluginManger instance, accessible as pm attribute of libxyz.core.XYZData object named xyz.
PluginManger supports following methods:
In all cases <plugin> is a plugin namespace path.
Once loaded plugin is stored in cache, so subsequent calls will simply return it from cache. If reloading needed reload method is used.
Only enabled plugins can be loaded and used. List of enabled plugins must be defined in Configuration files. Plugins are usually loaded by first request.
After plugin gets loaded for first time following actions take place:
Plugin can export methods and data.
Plugin exports its public methods via ‘public’ dictionary of BasePlugin class. Access to public methods can be performed as:
- plugin.public["method"]()
- plugin.method()
Second variant is simpler, cleaner and therefore preferable.
Plugin exports its public data via ‘public_data’ dictionary of BasePlugin class. Access to public data can be performed as:
- plugin.public_data["obj"]
- plugin["obj"]
So, in general, access to public methods is performed as attribute access: plugin.method(), and access to public data is performed as dict-item access: plugin["data_obj"].
Following is an example of typical plugin usage in python code (other cases will be described later):
# Load plugin
hello = self.xyz.pm.load(":misc:hello")
# Call public method say_hello() directly
hello.say_hello()
# Access public data `some_object`
print hello["some_object"]
# Or load only the method itself using from_load
say_hello = self.xyz.pm.from_load(":misc:hello", "say_hello")
# And then call
say_hello()
# Load only the data object itself using from_load_data
some_object = self.xyz.pm.from_load_data(":misc:hello", "some_object")
Also see the Configuration files for how to bind plugin methods to keyboard shortcuts.
Plugins configuration is performed using plugin_conf() function.
plugin_conf() is just a shorthand for let(plugin, opts, sect=”plugins”), so both methods can be used.
For example, if we’d have following block in plugins config:
plugin_conf(":misc:hello", {
"show_version": true
})
Plugin :misc:hello can access show_version variable as:
show_version = self.conf[u"show_version"]
or:
show_version = xyz.conf[u"plugins"][u":misc:hello"][u"show_version"]
TODO