Checkout the [https://plover.readthedocs.io/en/latest/plugin_dev.html Plugin Development Guide], which is the updated version of the information below. You might also find the [https://plover.readthedocs.io/en/latest/api_reference.html API reference] to be useful.
''See also: [[Plugin Development]]''
{{Out of date-section|2024-04-28T12:42:49.972649}}
== How Plugins Work ==
Plugins are generally implemented as separate Python packages that are installed into the Python environment that Plover uses. In order to support this, Plover's code uses a dynamic plugin discovery system via [https://setuptools.readthedocs.io/en/latest/setuptools.html#dynamic-discovery-of-services-and-plugins setuptools's entry_points configuration] to allow other packages to define themselves as certain types of plugins for Plover. After collecting the registry of plugins in the active Python environment on initialization, Plover has hooks in its code to call into each of the different types in the registry at various parts of its life cycle.
Much of Plover's built-in functionary is actually implemented via this plugin architecture in the main repository. For example, .json and .rtf dictionary support is from dictionary plugins, keyboard, Gemini PR, TX Bolt, and more input methods are all machine plugins, the English stenography layout is a system plugin, the entire UI itself is a GUI plugin, and much more.
== Types of Plugins (For Developers) ==
The following is each type of plugin available to develop in the packaged version of Plover and their relevant technical information.
Some examples are given for each type of plugin, but also check out the setup files in the [https://github.com/openstenoproject/plover main Plover repository] to find a bunch of plugins built into the release.
'''TODO: Document the base engine's hooks, or at least point to the code for them, for extension and GUI plugins'''
=== plover.command ===
Command plugins are used for executing arbitrary logic in response to a stroke. The logic can interact with the stenography engine itself but can also do completely separate tasks. It is not recommended to use command plugins to manipulate the stenography translation process as other plugin types are generally more suited for that.
The string argument is optional, and if not provided by the stroke definition after a <code>:</code> will always be sent as <code><nowiki>''</nowiki></code>.
Dictionary format:
{
"S-": "{PLOVER:EXAMPLE_COMMAND:argument}",
"T-": "{PLOVER:EXAMPLE_COMMAND}"
}
=== plover.dictionary ===
Dictionary plugins are used to support other types of dictionary formats other than Plover's default JSON format. They can range from other text formats to completely code-driven dictionaries.
from plover.steno_dictionary import StenoDictionary
class ExampleDictionary(StenoDictionary):
# The basics are that _load is called during initialization to pull your dictionary
# file format into memory and _save is called after an edit for you to implement
# saving to your dictionary file format. If you are not relying on the typical way
# StenoDictionary stores entries in memory as part of your _load implementation,
# such as what plover_python_dictionary does, you may need to re-implement more parts
# of the base class like get, while making sure LONGEST_KEY and similar essential state
# is set appropriately and maintained. See the base class for details on what is available.
def _load(self, filename: str) -> None:
# If you are not maintaining your own state format, self.update is usually
# called here to add strokes / definitions to the dictionary state.
pass
def _save(self, filename: str) -> None:
pass
Note that setting <code>readonly</code> to <code>True</code> on your dictionary class will make it so the user is not able to modify a dictionary of that type in the UI.
=== plover.extension ===
Extension plugins are used to execute arbitrary code. They are started when Plover starts and can be enabled or disabled in the ''Plugins'' section of the configuration dialog. They are ideal for background processes that should run concurrently to the main stenography engine but can be used to perform one-time actions as well.
And if you're using Qt Designer to create your UI, you can use the helpers provided by <code>plover_build_utils.setup</code> to automate the generation of Python code from your UI definitions; in <code>setup.py</code>:
from setuptools import setup
from plover_build_utils.setup import BuildPy, BuildUi
Note: this will also hook into the <code>build_py</code> command so other relevant setup commands (<code>build</code>, <code>install</code>, <code>develop</code>, ...) will automatically generate the UI files.
Additionally, you'll want to make sure the correct file are included/excluded; in <code>MANIFEST.in</code>:
# Exclude generated UI files.
exclude plover_example_tool/*_rc.py
exclude plover_example_tool/*_ui.py
# Ensure base UI files are included.
include plover_example_tool/*.ui
recursive-include plover_example_tool/resources *
Check the [https://packaging.python.org/guides/using-manifest-in/ relevant section of the Python Packaging User Guide] for more information on using <code>MANIFEST.in</code>.
<code>plover_example_tool/main.py</code>:
from plover.gui_qt.tool import Tool
from plover.engine import StenoEngine
<nowiki>#</nowiki> You will also want to import / inherit from the Python class generated by your .ui
<nowiki>#</nowiki> file if you are using Qt Designer.
class Main(Tool):
<nowiki> </nowiki> # This is what the tool will show up as in the UI
<nowiki> </nowiki> TITLE = 'Example Tool'
<nowiki> </nowiki> # This is the Qt path to your icon in your resource files to use
<nowiki> </nowiki> ICON = <nowiki>''</nowiki>
<nowiki> </nowiki> # This is an identifier for your tool, just make it unique
# Value format: [0]: default value, [1]: conversion function to convert your value into a single usable value.
# The opions can be configured through the UI if a dedicated `machine_option` plugin is available, of by
# manually editing the relevant section in `plover.cfg`.
return {
'option 1': ('default for option 1', str),
'option 2': ('default for option 2', str),
}
...
There are 4 methods that can be called to inform Plover about the machine status: <code>_stopped</code>, <code>_initializing</code>, <code>_ready</code>, <code>_error</code>.
The <code>_notify</code> method should be called whenever a stroke is received. It takes a set of key names in the current system (it's possible to convert from machine key names to system key names (actions) with <code>self.keymap.keys_to_actions</code> function) and then tells the steno engine the key input that just occurred.
There are 3 ways to configure the keymap:
* Add an entry for the machine in a system plugin's default bindings definition (<code>KEYMAPS</code> variable).
* The user can manually set the keymap in the ''Plover -> Configure -> Machine'' tab, along with any other additional configuration if a <code>machine_option</code> plugin is available for the machine type
* Define a class variable <code>KEYMAP_MACHINE_TYPE</code>, which means that the default configuration is the same as the default configuration of the specified machine. [https://github.com/openstenoproject/plover/blob/f4e45364fc5f58745c459f878d13ec6442497f46/plover/machine/procat.py#L33 Example]
The example shown uses the <code>ThreadedStenotypeBase</code> class as it is the most common use case, but you can build machine plugins off of the <code>StenotypeBase</code>, <code>SerialStenotypeBase</code>, or other classes depending on your needs.
=== plover.macro ===
Macro plugins are used for defining strokes that add translations to or modify translations in the translator based on existing state. Unlike commands, macro plugins have access to the entire translator object used by the engine to go from strokes to translations and are meant for manipulating the stenography translation process.
'''TODO: Probably improve the description of the use cases here, especially meta vs. macro.'''
The string argument is optional, and if not provided by the stroke definition after a <code>:</code> will always be sent as <code><nowiki>''</nowiki></code>.
Through the use of <code>translator.get_state().translations</code> you can access the previously translated entries. You can undo translations using <code>translator.untranslate_translation(...)</code> and you can apply new translations onto the translator using <code>translator.translate_translation(...)</code>.
Dictionary format:
{
"S-": "=example_macro:argument",
"T-": "=example_macro"
}
=== plover.meta ===
Meta plugins are used for defining strokes that create custom formatting actions that get added to the translator. Unlike commands, meta plugins have access to the previously translated text via the formatter that maps translations to actions so they can be used for manipulating the stenography translation process.
'''TODO: Probably improve the description of the use cases here, especially meta vs. macro.'''
The string argument is optional, and if not provided by the stroke definition after a <code>:</code> will always be sent as <code><nowiki>''</nowiki></code>.
You will want to use either <code>context.new_action()</code> or <code>context.copy_last_action()</code> as the basis for your output value. See the source code for the various properties around an action that can be set or modified. To access the previously translated text, you can call <code>context.last_*</code> methods.
Dictionary format:
{
"S-": "{:example_meta:argument}",
"T-": "{:example_meta}"
}
=== plover.system ===
System plugins are used to define stenography key layouts. If you want to modify steno order, add new keys, remove keys, rename keys, change how orthography rules work, and more then you can define a new system to do so. Once installed, users can change their system in the Plover -> Configure -> System menu.
The following would be for a new system called "Example System".
setup.cfg:
...
[options]
include_package_data = True
...
[options.entry_points]
plover.system =
Example System = plover_example_system.system
...
MANIFEST.in:
include plover_example_system/dictionaries/*
Without the MANIFEST file and <code>include_package_data</code> in your setup files, your dictionaries may not be properly copied into your build when you go to distribute the plugin.
plover_example_system/system.py:
...
<nowiki>#</nowiki> The keys in your system, defined in steno order
Note that there are a lot of possible fields in a system plugin. You must set them all to something but you don't necessarily have to set them to something meaningful, as shown above, so they can be pretty straightforward.
Since it is a Python file rather than purely declarative you can run code for logic as needed but Plover will try to directly access all of these fields which does not leave much room for that. However, it does mean that if for example you wanted to make a slight modification on the standard English system to add a key, you could import it and set your system's fields to its fields as desired with changes to KEYS only; or, you could make a base system class that you import and expand with slightly different values in the various fields for multiple system plugins like Michela does for Italian.
== Development Workflow ==
=== Starting Development ===
'''TODO: Create a suite of [https://help.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-template-repository template repos] that can be cloned by people to start their own to make this section really simple. Also point to https://github.com/openstenoproject/plover<nowiki/>'s README about setting up a dev environment first (and maybe update that to encourage the use of venv instead of system-wide setup)'''
<nowiki>**</nowiki>TODO Flesh out the issues that arose on [https://discord.com/channels/136953735426473984/144999734254370816/712446672944234507 Discord]. The big takeaway was that if running from source, you will need the plugin manager installed via <code>pip install -r requirements_plugins.txt</code>
=== Testing ===
While developing your plugin you will need to test the functionality works as expected and the way you can test it depends on how you are running Plover. For any methods discussed, you will at minimum need to restart Plover after you make any code changes to your plugin for them to take effect.
If you are running a packaged version of Plover like what is installed from the Windows installer or the AppImage, you can run the following command on the Plover executable file to install a plugin into Plover's Python environment:
On Windows you will need to use <code>plover_console.exe</code> instead of <code>plover.exe</code>. Note that what is exposed through that interface is essentially the <code>pip</code> command, so the <code>-e</code> in the example is the "editable" flag for <code>pip</code> which lets you just restart Plover to see your changes rather than having to reinstall the plugin each time. That means you also have the freedom to install plugins from local file paths, from git, etc. as you would install any Python package with <code>pip</code>.
If you are running Plover from source instead, Plover will be using whatever Python environment you execute Plover from. You can still use the above command if plover is in the PATH of the environment you're running from and you've already installed the [https://github.com/benoit-pierre/plover_plugins_manager plugin manager] into your environment, otherwise you would just use <code>pip</code> commands like normal to install your plugin into the Python environment you're using:
pip install -e /path/to/plugin/directory
=== Publishing ===
Once you've finished testing your plugin works as expected, you're ready to publish it to be installed by other users that are not developers. This is done by uploading your package to [https://pypi.org/ PyPI, the Python Package Index] with some guidelines around it.
Those guidelines up front:
* Your plugin's name as defined in your setup files should start with <code>plover-</code> to avoid clashing with general Python package namespaces
* Your plugin's setup files must define one of its keywords to be <code>plover_plugin</code> as this is how the plugin manager finds it on PyPI
* Your plugin's setup files must define a long_description. The plugin manager can display plain text, .rst, or .md files specified here.
* Your plugin should only use features that the distributed version of Plover supports in order to prevent errors for end users; that version can be verified by looking at Plover's setup files
The first thing you need to do to actually publish is make an account on PyPI which should be relatively straightforward.
There are a myriad of ways to actually build and publish a package but the easiest and most recommended way to publish to PyPI is by running [https://twine.readthedocs.io/en/latest/ twine] in your plugin directory like so:
python setup.py sdist bdist_wheel
twine upload dist/*
See its documentation for more information on how to install it and set it up. You don't need to publish to Test PyPI as it suggests unless you want to as part of your workflow. One thing to note about twine is it will automatically convert your <code>plover_x_name</code> snake case name for your plugin into a <code>plover-x-name</code> hyphenated name for the package it uploads.
If you make updates to your plugin and need to publish that, just make sure to bump the version in your setup files and otherwise the steps are exactly the same.
=== Adding the package to the Plover plugins registry ===
Because PyPI's XMLRPC search endpoint is disabled, starting from version 0.5.16, the [https://github.com/benoit-pierre/plover_plugins_manager/ Plugins manager for Plover] fetches the list of Plover plugins from a [https://github.com/openstenoproject/plover_plugins_registry GitHub repository]. You should contact the maintainer to have your plugin added to the list.
[[Category:Plover]]
[[Category:Plover]]
Revision as of 15:39, 12 May 2025
Plugins can be made for Plover to extend its functionality in various ways, from the tools available in the GUI to the types of dictionaries supported. They are available starting from Plover version 4.0.
How to Install Plugins
Via the built-in Plugins Manager (recommended)
Open the main window of Plover.
You can also right click on the Plover icon.
Go to Tools → Plugins Manager.
Browse the available plugins and select the one you want to install.
Select Install/Update to install the plugin.
Press Yes to the security warning.
Once the plugin has finished installing, close the progress window.
If you do not see the plugins manager, follow the instructions here to bring it back.
Manually Installing Plugins
Some plugins are not yet in the registry and do in the show up in the plugins manager list. It is still possible to manually install plugins. Ensure you are running Plover 4.x – version 3 and below do not include plugin support.
Open a command line (Command Prompt app on Windows, Terminal on Linux and macOS).
Type git and press enter.
You should see something the following output:
If the above command does not work, first verify you've installed git. If you are still running into an error when trying to run git, you may have to restart or manually add git to your path (particularly if you are on Windows).
Install the plugin
Installing the plugin requires accessing the Plover executable as outlined in the invoke Plover from the Command Line page. For each command listed below, replace plugin-name with an applicable string:
For plugins on PyPI, this is the name of the package (e.g., plover-touchscreen-stenotype).
For other plugins, this is the URL from the previous step, prefixed with git+ (e.g., git+https://github.com/greenwyrt/plover2CAT).
Linux
Open a terminal in the same folder as the Plover AppImage and run the following command:
Note that depending on the version of Plover you are using, the first part of the command may be different. Instead of typing the whole filename out, you can type ./plover and then press Tab to autocomplete the rest.
TODO: Information on how to install the plugins manager for non-developers, screenshots, point developers towards the development workflow section which has other options.
Spectra Lexer This is like the lookup or suggestions window, but with a lot of extra features such as explanations for why a word is briefed that way and diagrams. There is also a web version and a bot in the discord server, though these only use the default Plover dictionaries and not any additional user dictionaries you may have.
Plover-clippy or Plover-clippy-2 Logs suggestions that are more efficient than what you used to type to a file in your plover configuration directory. Useful for finding new briefs, especially for phrases. By default the output of Plover-clippy-2 is written into clippy_2.org in your config folder, which you can open from Plover's menu item "Open config folder". Open the clippy file in a text editor and review it from time to time to see what you could type more efficiently.
Plover Word Tray Automatically looks up efficient outlines for words that start with the current input, much like autocomplete suggestions. It's similar to the lookup window and suggestions window in one. In addition, if you are stuck on a word, you can start fingerspelling it or sound out the first syllable and it'll try to guess what you're trying to spell.
Dictionary Plugins
Dictionary plugins add support for other dictionary formats besides Plover’s native JSON format.
There is no setup required for these plugins beyond installation and restarting Plover.
Machine Plugins
Machine plugins add support for new input protocols, such as the serial input from various professional stenography machines or even MIDI keyboards.
These plugins add new entries in the Machine dropdown menu in Plover's configuration.
System Plugins
System plugins defines new key layouts and theories. This lets Plover support stenographic layouts other than the standard American Stenotype system, such as Michela (plover-michela) or Korean CAS (plover-korean).
To use a system plugin, configure it under the System tab of Plover's configuration.
Command Plugins
Commands plugins allow Plover to run arbitrary commands in response to a stroke. The logic can interact with the stenography engine itself but can also do completely separate tasks.
See the plugin's own documentation for setup details.
Macro and Meta Plugins
Macro and meta plugins add or modify translations in the translator, typically for transforming previously entered text. Macros have access to the entire translation and can perform transformations on the raw stroke input, whereas metas only have access to the translated output.
To use macro and meta plugins, see the plugin's own documentation for setting up entries.
GUI Plugins
GUI plugins add user-facing tools, like the built-in Suggestions and Lookup tools. GUI plugins are automatically loaded at startup, and can be accessed by clicking on its icon on the toolbar or in the Tools dropdown menu.
There is no setup required for these plugins beyond installation and restarting Plover.
Extension Plugins
Extension plugins can be used to execute arbitrary code.
To use an extension plugin, it must be enabled in the Plugins tab of Plover's configuration.