How to write a Kupfer plug-in
Kupfer is quite useful without extra plug-ins. However, when a service you use is not provided, it becomes quite hard (or impossible) to work with it without a plug-in. To write a plug-in for Kupfer does not need to be difficult as there is a lot of functionality provided for first time plug-in writers.
What to add
There are three types of classes that you can add to Kupfer: Sources, Actions, and Leafs. You extend the functionality of Kupfer by adding one or more classes of these types.
A Source is a collection of items. Examples are "Firefox Bookmarks", "Directories", "Files", "Windows", "Albums", or "Songs". The items inside a Source are called Leafs.
A Leaf is an item in Kupfer. You can search or create a Leaf by typing some text. Examples are text, URL, host, file, directory, or a music album. After you select a Leaf, you can search for an Action.
Some actions are Leafs. These are called RunnableLeafs. A RunnableLeaf is something that doesn't need a Leaf subject. An example of this is "Restart".
An Action is a type that processes the Leaf. Examples are "Open File", "Go to URL", "Delete File", and "Open".
When you create a plug-in you create one or more of these types. You don't need all three. It's possible (and expected) to reuse the Source, Leaf, and Action types. You can add a Source that adds items of type UrlLeaf. An example is a bookmark source.
You can add an Action that works with existing Leafs. An example of a core action that does this is the AppendTo action, that appends text to a file.
Kupfer contains a few default action utilities. Examples are show_url or launch_commandline. In your plug-in, you format the url and call utils.show_url(url) to automatically open a URL in a browser.
When your plugin uses settings, it's possible to add a few lines to the plugin to get input fields on the plugin configuration. This configuration is automatically loaded when the plugin is activated. You don't need to provide this yourself.
Where to start
User-defined plugins can be added to ~/.local/share/Kupfer/plugins/. When you quit and restart Kupfer, Plugins are reloaded. You need to enable the plugin in the plugin settings.
A good way to start with a plugin is to add a layer around a website. Some websites have a way to pre-fill a form with values. Fastmail has the compose URL `https://www.fastmail.com/mail/compose` which takes the query parameters `to`, `subject`, and `body`. When you add these parameters to the URL the form will be pre-filled with this information.
We could write a plugin like this. You create an action that opens this URL with the contacts that you found. Kupfer already has a ContactLeaf with an email address. There is an example of an Action in `clawsmail.py` that gathers contacts. In the case of Fastmail, you can call `utils.show_url` with the right url to open the window where you can finish the email.
Another way is to add a layer around a command-line program. An example is the command `brotab`, which allows us to activate or close tabs. The source would call `brotab list` and provide the tabs as Leafs. Two actions that we would add or Activate and Close Tab, which would call `brotab activate <tab_id>` and `brotab close <tab_id>`.
The third way to start is by calling into a library. It is useful to use a library because Kupfer itself doesn't need that much code. An example could be a Pinboard plugin. There is a library for Pinboard that can return the bookmarks. The plugin would add a Source for these bookmarks and return UrlLeafs. The user can use URLs with the actions that are available in Kupfer by default.
Writing a plugin for Kupfer does not have to be hard. There are examples already for different types of functionality. You can use websites, command-line tools, and libraries to make information available or perform an action. You can place the plugin in a specific directory in your home folder to make it available in Kupfer. You can add settings with a few lines of code.
Why you should use multiple calendars
In most calendar applications, it's possible to create multiple calendars. Perhaps you only use the default calendar and would like to know why it would be useful to have multiple calendars. In this article, I will give my take on why you should use more than one calendar.
Types of calendars
I have a calendar for when the garbage container should put on the side of the street. The dates are available in advance for the year. I add these dates to a specific calendar for these events.
Another calendar I have is a calendar called Environment. This calendar contains events that I need to know about, but don't have to act on directly.
Show or hide the calendar
When you have a calendar for a specific type of event, it's easier to show or hide the calendar. The garbage calendar events don't have much influence on me planning my day. So it's useful that I can hide this calendar. If my default calendar also contains these events, it would be impossible to hide them.
Default settings for notifications
The garbage calendar has specific default settings for notifications. The evening before the collection at 8 pm, I get notified that I need to take the garbage out.
The other example is for events where you don't want notifications. The Environment calendar should not notify me. The default setting makes it easier to create events.
Default settings for free and busy
When you create a new calendar, determine if you need the events on the calendar to be free or busy. When you have an Environment calendar, you should put the events to free by default. But perhaps the calendar from an event scheduling app should be set to busy.
Default settings for public and private
When you have a calendar with public events and sometimes want to keep some events private, you could create a second calendar for events that are private by default. These events can show up as busy moments in your schedule but would not be visible to other people.
Sharing with other people
When you invite people to events, you share it with them. When you want to share more events, you can also share the whole calendar. It may be useful in a long-lived group, and you have repeating events and don't need to know who will attend.
An example of this is when you are part of a team. We have multiple events in a week that we have on the calendar. Without the shared calendar, someone would need to invite you to these events. A better way is to create a calendar and add the team events to that calendar. Every team member can take a look at the events and know exactly when to be there.
Sharing with apps
The problem with apps is that you do not always know what kinds of events these apps create on your calendar. Because of that, it can be better to create a new calendar and let the app create events in that calendar. Examples of apps that update your calendar are Todoist and RescueTime.
For importing many events
To create many events, you can create a recurring event. Recurring events can't help you when these events don't repeat. When you want to number the meetings or have different titles, you also won't be able to do it.
A solution would be to create a file and import it. However, when we import a file, this can give the wrong result. With the import, we add many events to the calendar at once. When these events are not right, it can be almost impossible to remove those events from the calendar in most calendar apps. The problem becomes worse when we mixed events with your other events.
To solve this, you first create a new calendar and then import these events to that calendar. When the result is different from what you expect, you can remove the whole calendar and try again.
With multiple calendars, you have more control over your events. You can set the default settings and share, import and remove these calendars more easily. Multiple calendars are a great to use for increasing your productivity.
Use of space in a Bullet Journal
The Bullet Journal method tells us how to add notes to our notebooks without having to plan. Notebooks are linear. If we plan our spreads, we never know if we leave enough room for things to come. The Bullet Journal Method is a method where we don't have to plan.
We add new notes on the next empty spread. The structure of the notebook grows with the use and removes the need for planning the content in advance. Each type of collection adds a constant number of pages.
We place the Monthly Log in the next open spread. The Monthly Log only takes two pages. The following pages are still empty and ready to be used. Only in front of the Monthly Log is there a possibility of a partial space. But this should be no more that one or two pages.
The Daily Log uses as much space as is needed. It grows linearly to use as much space as we need until the next collection. We can split a Daily Log at any time. We continue with the Daily Log after the collection.
The Future log uses constant space. We can reserve as many pages as needed and think about how long we will use a notebook. We add pages in spreads of 6 months. So depending on the speed with which we fill a notebook, we can add 6, 12, or 18 months and use 1, 2, or 3 spreads.
In a Bullet Journal, we can have many pages between multiple parts of a collection. There are two ways in which we can connect these parts: the Index and threading.
The Index contains all the collections that we created. Each collection has a list of page numbers where we can find it. We can add collections in two ways: the first way is to collect all page numbers for a collection on the same line. When we have a new spread, we add the page numbers following the entry with the same name.
The second way is to write every collection on a new line with the page number after it. When you add a new spread for the same collection, you add its name and page number at the end of the Index.
With threading, you connect all the spreads of the same collection. We thread the last page of the current collection to the next page of the next collection.
The Bullet Journal method removes the need to plan pages in advance, because of how we add pages and how we can find what we want.
It does improve the scriptability of Ek. I can now follow feeds while creating the channel like this:
ek follow `ek channels Blogs` https://example.com/blog/
The channels call will return the uid of the created channel or the uid of the existing channels when it already exists.