;;; org-clock-waybar.el --- Summary ;; Copyright (C) 2021 Gergely Polonkai ;; Author: Gergely Polonkai ;; Keywords: org, clocking, waybar ;; Version: 1.0 ;; Package-Requires: ((emacs "26.1")) ;; URL: https://gitea.polonkai.eu/gergely/org-clock-waybar ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;;; Commentary: ;; Export the currently clocked-in task in JSON format that Waybar can process ;; ;; To use it, customize the `org-clock-waybar-filename' variable (defaults to ;; $XDG_CONFIG_HOME/waybar-current-task.json) and add the following snippet to ;; your Waybar config: ;; ;; "custom/org": { ;; "format": " {}", ;; "return-type": "json", ;; "restart-interval": 5, ;; "exec": "cat /home/yourusername/.cache/waybar-current-task.json" ;; } ;;; Code: (require 'xdg nil t) (require 'json) (require 'org-clock) (defgroup org-clock-waybar nil "Send current clocked task to a JSON file for Waybar visualization" :group 'emacs) (defcustom org-clock-waybar-filename (if (fboundp 'xdg-cache-home) (expand-file-name "waybar-current-task.json" (xdg-cache-home)) (expand-file-name "~/.cache/waybar-current-task.json")) "Name of the file to save task data to." :type 'string :group 'org-clock-waybar) (defcustom org-clock-waybar-not-clocked-in-text "Not clocked in" "Text to display when not clocked in on any task." :type 'string :group 'org-clock-waybar) (defconst org-clock-waybar-filename-coding-system (if (coding-system-p 'utf-8-emacs) 'utf-8-emacs 'emacs-mule) "Coding system of the file `org-clock-waybar-filename'.") (defsubst org-clock-waybar--get-task-title () "Get the title of TASK." (when (org-clocking-p) (substring-no-properties org-clock-current-task))) (defsubst org-clock-waybar--get-task-category () "Get the category of TASK." (when (org-clocking-p) (get-text-property 0 'org-category org-clock-current-task))) (defun org-clock-waybar--get-tooltip () "The default tooltip to send to waybar." (when (org-clocking-p) (let ((clocked-time (org-clock-get-clocked-time))) (format "%s: %s (%s)" (org-clock-waybar--get-task-category) (org-clock-waybar--get-task-title) (org-duration-from-minutes clocked-time))))) (defun org-clock-waybar--get-tags () "Get the tags of the currently clocked-in task." (when (org-clocking-p) (or (org-with-point-at org-clock-marker (org-get-tags)) "") )) (defun org-clock-waybar--get-clocked-task-json () "Get the currently clocked-in task’s data as a stringified JSON object. The output is in JSON format constructed in a way so Waybar can process it. If there is no clocked in task, alt becomes empty and text will be set to the value of `org-clock-waybar-not-clocked-in-text'." (let* ((category (org-clock-waybar--get-task-category)) (title (org-clock-waybar--get-task-title)) (tooltip (org-clock-waybar--get-tooltip)) (output (json-new-object))) (setq output (json-add-to-object output "text" (or title org-clock-waybar-not-clocked-in-text))) (setq output (json-add-to-object output "alt" (or category ""))) (setq output (json-add-to-object output "tooltip" (or tooltip ""))) (setq output (json-add-to-object output "class" (or (org-clock-waybar--get-tags) ""))) (setq output (json-add-to-object output "percentage" "")) (json-encode output))) (defun org-clock-waybar-save-task () "Save the current clocked in task to `org-clock-waybar-filename'." (with-temp-buffer (erase-buffer) (set-buffer-file-coding-system org-clock-waybar-filename-coding-system) (insert (org-clock-waybar--get-clocked-task-json)) (write-file org-clock-waybar-filename))) (defun org-clock-waybar-ouptut-task () "Output the current task in JSON format Waybar can understand. This function is ought to be used via Emacsclient: emacsclient --eval '(org-clock-waybar-output-task)'" (let* ((output (org-clock-waybar--get-clocked-task-json)) (start 0) (end (length output))) (set-text-properties start end nil output) output)) (defun org-clock-waybar-setup () "Setup org-clock-waybar. It adds `org-clock-waybar-save-task' to both `org-clock-in-hook' and `org-clock-out-hook'." (add-hook 'org-clock-cancel-hook #'org-clock-waybar-save-task) (add-hook 'org-clock-in-hook #'org-clock-waybar-save-task) (add-hook 'org-clock-out-hook #'org-clock-waybar-save-task) (add-hook 'kill-emacs-hook #'org-clock-waybar-save-task)) (provide 'org-clock-waybar) ;;; org-clock-waybar.el ends here