Plugin Architecture

On the previous page, we defined a new command in a Python (.py) file:

from fman import DirectoryPaneCommand, show_alert

class SayHi(DirectoryPaneCommand):
	def __call__(self):
		show_alert('Hello World!')

A DirectoryPaneCommand is an action that can be performed in the context of a directory pane:

We also bound our command to a keyboard shortcut:

[
	{ "keys": ["F3"], "command": "say_hi" }
]

Note how the command was called SayHi in the Python file, but is referred to in the settings file as say_hi. When fman encounters a command called ThisIsAnExample in a Python file, it registers it as this_is_an_example.

Directory structure

The directory structure of our simple plugin looked as follows:

  • Hello World/
  • hello_world/
    • __init__.py
  • Key Bindings.json

hello_world/ is a Python package, that is, a directory containing a file called __init__.py and possibly other .py files. All your Python sources must lie inside such a package. The package name (in this case hello_world) must be unique to avoid name clashes with other plugins.

Plugin order

fman loads plugins in the following order:

  1. Shipped Plugins. These plugins are included in fman's installation directory. Currently, Core is the only such plugin.
  2. Third-party Plugins. These lie in the Plugins/Third-party/ subdirectory of your data directory. Plugins installed with fman's built-in commands get placed here.
  3. User Plugins. Plugins you develop yourself should be placed in the Plugins/User/ folder of the data directory. A special case is the Settings plugin, described below.
  4. The Settings Plugin. This is a normal User plugin except for the special property that it is the last plugin that is loaded. Because of this, it can overwrite the settings of all other plugins. You use it to configure fman; For instance when defining your own keyboard shortcuts.

Each plugin overwrites or extends the settings of any previously loaded plugins. For example, the Core plugin contains the settings file Key Bindings.json. On the previous page, we created a file with the same name in our Hello World plugin. Our file thus extended the existing keyboard shortcuts by a new one.

Whether a settings file extends or overwrites existing values depends on its contents. Key Bindings.json for example is a list, which you can see from the fact that it starts and ends with square brackets:

[
	...
]

When a plugin A defines a list in a settings file with the same name as a previously loaded plugin B, then A's values are prepended to B's.

The other interesting case are dictionaries, which start end end with curly braces. For example, the Core plugin uses the file Core Settings.json to remember the text editor you chose the first time you pressed F4:

{
	"editor": {
		"args": [
			"/usr/bin/open", "-a",
			"/Applications/Sublime Text.app", "{file}"
		]
	}
}

Dictionaries like this overwrite the values of previously loaded plugins.