Skip to content

Development

It's easy to write your own plugin by making a python package and then indicating it's name as the plugin name.

Contributing guidelines

Writing plugins

Plugins can be loaded with full python module path, eg: "mymodule.pyprlandplugin", the loaded module must provide an Extension class.

Check the interface.py file to know the base methods, also have a look at the example below.

To get more details when an error is occurring, use pypr --debug <log file path>, it will also display the log in the console.

NOTE

To quickly get started, you can directly edit the experimental built-in plugin. In order to distribute it, make your own Python package or trigger a pull request. If you prefer to make a separate package, check the examples's package

The Extension interface provides a couple of built-in attributes:

  • config : object exposing the plugin section in pyprland.toml
  • notify ,notify_error, notify_info : access to Hyprland's notification system
  • hyprctl, hyprctl_json : invoke Hyprland's IPC system

IMPORTANT

Contact me to get your extension listed on the home page

TIP

You can set a plugins_paths=["/custom/path/example"] in the hyprland section of the configuration to add extra paths (eg: during development).

NOTE

If your extension is at the root of the plugin (this is not recommended, preferable add a name space, as in johns_pyprland.super_feature, rather than super_feature) you can still import it using the external: prefix when you refer to it in the plugins list.

API Documentation

Run tox run -e doc then visit http://localhost:8080

The most important to know are:

  • hyprctl_json to get a response from an IPC query
  • hyprctl to trigger general IPC commands
  • on_reload to be implemented, called when the config is (re)loaded
  • run_<command_name> to implement a command
  • event_<event_name> called when the given event is emitted by Hyprland

All those methods are async

On top of that:

  • the first line of a run_* command's docstring will be used by the help command
  • self.config in your Extension contains the entry corresponding to your plugin name in the TOML file
  • state from ..common module contains ready to use information
  • there is a MenuMixin in ..adapters.menus to make menu-based plugins easy

Workflow

Just ^C when you make a change and repeat:

sh
pypr exit ; pypr --debug /tmp/output.log

Creating a plugin

python
from .interface import Plugin


class Extension(Plugin):
    " My plugin "

    async def init(self):
        await self.notify("My plugin loaded")

Adding a command

Just add a method called run_<name of your command> to your Extension class, eg with "togglezoom" command:

python
    zoomed = False

    async def run_togglezoom(self, args):
        """ this doc string will show in `help` to document `togglezoom`
        But this line will not show in the CLI help
        """
      if self.zoomed:
        await self.hyprctl('misc:cursor_zoom_factor 1', 'keyword')
      else:
        await self.hyprctl('misc:cursor_zoom_factor 2', 'keyword')
      self.zoomed = not self.zoomed

Reacting to an event

Similar as a command, implement some async def event_<the event you are interested in> method.

Code safety

Pypr ensures only one run_ or event_ handler runs at a time, allowing the plugins code to stay simple and avoid the need for concurrency handling. However, each plugin can run its handlers in parallel.

Reusable code

py
from ..common import state, CastBoolMixin
  • state provides a couple of handy variables so you don't have to fetch them, allow optimizing the most common operations
  • Mixins are providing common code, for instance the CastBoolMixin provides the cast_bool method to your Extension.

If you want to use menus, then the MenuMixin will provide:

  • menu to show a menu
  • ensure_menu_configured to call before you require a menu in your plugin

Example

You'll find a basic external plugin in the examples folder.

It provides one command: pypr dummy.

Read the plugin code

It's a simple python package. To install it for development without a need to re-install it for testing, you can use pip install -e . in this folder. It's ready to be published using poetry publish, don't forget to update the details in the pyproject.toml file.

Usage

Ensure you added pypr_examples.focus_counter to your plugins list:

toml
[pyprland]
plugins = [
  "pypr_examples.focus_counter"
]

Optionally you can customize one color:

toml
["pypr_examples.focus_counter"]
color = "FFFF00"