fman's new file system API

After months of hard work, fman's file system API is finally available. It lets you add support for non-standard file systems such as Dropbox, SFTP, ... by means of plugins. This really sets fman apart from other file managers, where you are dependent on the respective vendor to offer new integrations.

A huge boon of the API is how little code it requires. fman's own implementation for handling local files is only 181 lines long. Basic SFTP support can be added in 75 lines. The new ProcessFS plugin is a file system for managing the programs currently running on your computer. It's a mere 84 lines of code.

Here's an example of a very simple custom file system:

from fman.fs import FileSystem

class Example(FileSystem):

	scheme = 'example://'

	def iterdir(self, path):
		return ['File.txt', 'Image.jpg']

When you create a plugin with these contents and navigate to example://, you get:

Note how the two "files" from the code snippet are shown. Of course, the files don't actually exist. But fman doesn't care: It simply displays what the code tells it to.

To make the example more interesting, let us introduce a directory structure:

class Example(FileSystem):

	scheme = 'example://'

	def iterdir(self, path):
		if path == '':
			return ['Directory', 'File.txt', 'Image.jpg']
		elif path == 'Directory':
			return ['File in directory.txt']

	def is_dir(self, path):
		return path == 'Directory'

When you reload your plugin with the built-in Reload plugins command, you then get the following:

We now have a directory that is also displayed as such. What's even better, you can open it to see:

Note how the location has changed to example://Directory and the file inside the directory is displayed.

So what happened behind the scenes? When you open a URL example://Directory, fman sees that it should be handled by the example:// file system. That's why we have scheme = 'example:// in the code above.

Next, fman calls our implementation of iterdir(path). The path it passes is everything after the example:// prefix; So 'Directory' in the example. Looking at the code, we see that it returns ['File in directory.txt'] in this case.

Finally, fman invokes is_dir(path) for each file in the directory. In the example, fman passes path = 'Directory/File in directory.txt'. Because this is not equal to 'Directory', our code returns False, and so fman treats it as a file and not a folder.

This completes the simple example. File systems can obviously do much more: You can for instance tell fman how your file system implements the Copy and Move commands. For more information, please refer to the API documentation. If you have any questions, get in touch! I would love to help you get started.

You currently need a separate command to navigate to example://. This will do:

from fman import DirectoryPaneCommand

class OpenExample(DirectoryPaneCommand):
	def __call__(self):
		self.pane.set_path('example://')

Copy this code into your plugin, then use the Command Palette to run Reload plugins and then Open example.

Michael started fman in 2016, convinced that we deserve a better file manager. fman's launch in 2017 was a huge success. But despite full-time work, it only makes $500 per month. The goal is to fix this.