;;; org-clock-waybar --- 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) (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 (expand-file-name "waybar-current-task.json" (xdg-cache-home)) "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 (task) "Get the title of TASK." (when task (substring-no-properties task))) (defsubst org-clock-waybar--get-task-category (task) "Get the category of TASK." (when task (get-text-property 0 'org-category task))) (defun org-clock-waybar--get-tooltip () "The default tooltip to send to waybar." (when org-clock-current-task (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-clocked-task-json (&optional clocking-out) "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'. If CLOCKING-OUT is non-nil, `org-clock-current-task' will be treated as if it were nil; this is required because `org-clock-out' calls the hook functions before setting `org-clock-current-task' to nil." (let* ((task (if clocking-out nil org-clock-current-task)) (category (org-clock-waybar--get-task-title task)) (title (org-clock-waybar--get-task-category task)) (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" "")) (setq output (json-add-to-object output "percentage" "")) (json-encode output))) (defun org-clock-waybar-save-task (&optional clocking-out) "Save the current clocked in task to `org-clock-waybar-filename'. If CLOCKING-OUT is non-nil, treat the current task as if it were nil." (with-temp-buffer (erase-buffer) (set-buffer-file-coding-system org-clock-waybar-filename-coding-system) (insert (org-clock-waybar--get-clocked-task-json clocking-out)) (write-file org-clock-waybar-filename))) (defun org-clock-waybar-clear-task () "Clear the current task from `org-clock-waybar-filename'." (org-clock-waybar-save-task t)) (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)'" (org-clock-waybar--get-clocked-task-json)) (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-in-hook #'org-clock-waybar-save-task) (add-hook 'org-clock-out-hook #'org-clock-waybar-task) (add-hook 'kill-emacs-hook #'org-clock-waybar-clear-task)) (provide 'org-clock-waybar) ;;; org-clock-waybar.el ends here