DEV Community

nurgasemetey
nurgasemetey

Posted on

How I wrote Ulauncher extension for most used timedate macros

Why?

I wrote a lot. And in my writings I use timestamps, dates, times, time-ranges.

I use following datetime formats

  • 2020-11-01
  • 15-18
  • 14:58

For them I used custom bash scripts which were copying to clipboard the date formats I wanted. These scripts were manually added to Linux's custom shortcuts.

Example of bash script:

#!/bin/sh
alias setclip='xclip -selection c'
alias getclip='xclip -selection clipboard -o'
printf $(date +"%Y-%m-%d") | setclip
Enter fullscreen mode Exit fullscreen mode

Initially, I was really happy but after some time number of custom scripts increased. I had difficulties with remembering them.

chelsea

How?

I stumbled to Ulauncher and it is downed on me that I could create extension for these timedate scripts.

For people who don't know, Ulauncher is application launcher to which many developers write many extensions.

Some examples:

  • emoji extension
  • process murderer
  • google translate
  • spotify player

Here is the tutorial link for extension development.

About my extension

Ulauncher requires that extension must have manifest.json file to operate.

Example of manifest.json

{
  "required_api_version": "^2.0.0",
  "name": "Timestamp macros",
  "description": "Copy to clipboard the most used timedate formats",
  "developer_name": "Nurgazy Nazhimidinov",
  "icon": "images/icon.png",
  "options": {
    "query_debounce": 0.05
  },
  "preferences": [
    {
      "id": "time_kw",
      "type": "keyword",
      "name": "Timemacros",
      "default_value": "tm"
    }
  ]
}

Enter fullscreen mode Exit fullscreen mode

It says that if you write keyword Timemacros, extension will be on launcher(WARNING not clicked).

chelsea


if you write Timemacros and click

or

write tm and SPACE, then KeywordQueryEventListener(EventListener) will invoked.

Here is the code:

class DemoExtension(Extension):

    def __init__(self):
        super(DemoExtension, self).__init__()
        self.subscribe(KeywordQueryEvent, KeywordQueryEventListener())

class KeywordQueryEventListener(EventListener):

    def on_event(self, event, extension):
        items = []
        logger.info('preferences %s' % json.dumps(extension.preferences))
        logger.info(event.get_keyword()) # gives the keyword 'tm'
        items.append(ExtensionResultItem(icon='images/icon.png',
                                         name='YYYY-MM-DD',
                                         description='{0:%Y-%m-%d}'.format(datetime.datetime.now()),
                                         on_enter=CopyToClipboardAction('{0:%Y-%m-%d}'.format(datetime.datetime.now()))))

        items.append(ExtensionResultItem(icon='images/icon.png',
                                         name='HH:mm',
                                         description='{0:%H:%M}'.format(datetime.datetime.now()),
                                         on_enter=CopyToClipboardAction(
                                             '{0:%H:%M}'.format(datetime.datetime.now()))))

        items.append(ExtensionResultItem(icon='images/icon.png',
                                         name='YYYY-MM-DD HH:mm',
                                         description='{0:%Y-%m-%d %H:%M}'.format(datetime.datetime.now()),
                                         on_enter=CopyToClipboardAction(
                                             '{0:%Y-%m-%d %H:%M}'.format(datetime.datetime.now()))))

        return RenderResultListAction(items)


if __name__ == '__main__':
    DemoExtension().run()

Enter fullscreen mode Exit fullscreen mode

As you can see KeywordQueryEventListener(EventListener) and on_event is run and RenderResultListAction(items) is returned and presented to user.

Our items would be

  • YYYY-MM-DD
  • HH:mm
  • YYYY-MM-DD HH:mm

Here is the screenshot of items:

chelsea

Code for item:

items.append(ExtensionResultItem(icon='images/icon.png',
                                         name='YYYY-MM-DD',
                                         description='{0:%Y-%m-%d}'.format(datetime.datetime.now()),
                                         on_enter=CopyToClipboardAction('{0:%Y-%m-%d}'.format(datetime.datetime.now()))))

Enter fullscreen mode Exit fullscreen mode

Explanation for ExtensionResultItem:

name - title shown to user, look at screenshot above

description - subtext which is also shown to user, look at screenshot above

on_enter - most important part, says what to do if user clicks on this items. In my case, it is CopyToClipboardAction action which copies data to clipboard.

Summary

At the end, I developed extension with enabled me to discard my custom bash scripts and forget about keyboard shortcuts for them.

Source code on Github

Deprecated bash scripts 😄

chelsea

From personal blog: https://www.nurgasemetey.com/2020/extension-ulauncher/

Top comments (0)