emacs-orgmode
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Elisp function to get the upcoming event with the closest scheduled


From: Rodrigo Morales
Subject: Re: Elisp function to get the upcoming event with the closest scheduled date
Date: Wed, 3 Jan 2024 00:29:49 -0500

Rodrigo Morales <me@rodrigomorales.site> writes:

I managed to show the entry with the nearest upcoming scheduled date in
the tab bar with the following utilities (see code block below). Here's
an screenshot:
https://upload.wikimedia.org/wikipedia/commons/f/f3/Show_information_of_Org_Agenda_in_tab-bar.png

Here are some notes of the code:

+ The function my/org-agenda-nearest-upcoming-scheduled-search performs
  linear search through all headings in all files listed in
  org-agenda-files in order to search the entry with the nearest
  upcoming scheduled date.
+ The variable my/org-agenda-nearest-upcoming-scheduled stores the
  information of the event.
+ I added my/org-agenda-nearest-upcoming-scheduled-display to
  tab-bar-format in order to display the information that I requested.

Because my/org-agenda-nearest-upcoming-scheduled-search uses linear
search it is a rather expensive operation if there are many entries to
look up. I haven't decided yet when this functino should be called so
that it is called the fewer amount of times and it actually shows th
entry with the nearest upcoming scheduled date. It is necessary that it
is called in the proper times so that the
my/org-agenda-nearest-upcoming-scheduled is updated accordingly when
setting the scheduled date for new entries.

#+BEGIN_SRC elisp
(defvar my/org-agenda-nearest-upcoming-scheduled nil
  "Store entry with the nearest upcoming scheduled date.

The value should store a CONS CELL whose CAR is the title of the
entry and the CDR is the date of the entry.")

(defun my/org-agenda-nearest-upcoming-scheduled-search ()
  "Set the value for variable that store the entry with the nearest upcoming 
scheduled date."
  (let (nearest-entry
        ;; Store the scheduled date in seconds of the current entry.
        entry-scheduled
        (current-time (float-time)))
    ;; Iterate through all files in `org-agenda-files'
    (dolist (file org-agenda-files)
      (with-current-buffer (find-file-noselect file)
        ;; Iterate through all headings
        (org-map-entries
         (lambda ()
           (when (and
                  ;; Check the current entry has SCHEDULED
                  (setq entry-scheduled (org-entry-get nil "SCHEDULED"))
                  ;; If the currenty entry has SCHEDULED, we proceed
                  ;; to convert it to seconds using org-2ft. We cannot
                  ;; write org-entry-get and org-2ft in the same
                  ;; expression because it is possible that
                  ;; org-entry-get returns nil and org-2ft returns 0
                  ;; when nil is passed, so we won't be checking that
                  ;; the entry has SCHEDULED.
                  (setq entry-scheduled (org-2ft entry-scheduled))
                  ;; Check time of the entry is greater than the current time
                  (> entry-scheduled current-time))
             ;; If there's no nearest entry yet, then store the
             ;; current entry as the nearest entry.
             ;;
             ;; We use an if conditional because for plist-put to
             ;; work, it is needed that the property list is not nil.
             (if (null nearest-entry)
                 (setq nearest-entry
                       `(:item ,(org-entry-get nil "ITEM")
                         :scheduled ,entry-scheduled
                         :scheduled-string ,(org-entry-get nil "SCHEDULED")
                         :marker ,(point-marker)))
               ;; If a nearest entry has been found previously,
               ;; compare their scheduled time.
               (when (> (plist-get nearest-entry :scheduled) entry-scheduled)
                 (plist-put nearest-entry :item (org-entry-get nil "ITEM"))
                 (plist-put nearest-entry :scheduled entry-scheduled)
                 (plist-put nearest-entry :scheduled-string (org-entry-get nil 
"SCHEDULED"))
                 (plist-put nearest-entry :marker (point-marker)))))))))
    (setq my/org-agenda-nearest-upcoming-scheduled nearest-entry)
    (unless nearest-entry
      (error "No event with scheduled date than the current date was found."))))

(defun my/org-agenda-nearest-upcoming-scheduled-display ()
  (if my/org-agenda-nearest-upcoming-scheduled
      (progn
        ;; If the previously found entry has an scheduled date that has
        ;; already passed, let's search for a new upcoming scheduled.
        (when (<
               (plist-get my/org-agenda-nearest-upcoming-scheduled :scheduled)
               (float-time))
          (my/org-agenda-nearest-upcoming-scheduled-search))
        (let* ((time-difference
                (truncate
                 (-
                  (plist-get my/org-agenda-nearest-upcoming-scheduled 
:scheduled)
                  (float-time))))
               (days (/ time-difference 86400))
               (hours (/ (% time-difference 86400) 3600))
               (minutes (/ (% time-difference 3600) 60)))
          ;; TODO: The following is a list of menu items. I still
          ;; don't know the meaning of the first item in the menu item
          ;; definition, so I've written foo.
          `((foo
             menu-item
             ,(propertize
               (concat
                (plist-get my/org-agenda-nearest-upcoming-scheduled :item)
                " | "
                (string-join
                 (delq
                  nil
                  (funcall
                   'append
                   (unless (eq days 0) (list (number-to-string days) "days"))
                   (unless (eq hours 0) (list (number-to-string hours) "hours"))
                   (unless (eq minutes 0) (list (number-to-string minutes) 
"minutes"))))
                 " "))
               'face
               `(:background ,(face-attribute 'default :background)
                 :foreground ,(face-attribute 'default :foreground)
                 :box (:line-width (1 . 1)
                       :color ,(face-attribute 'default :foreground))))
             my/org-agenda-nearest-upcoming-scheduled-jump
             :help (plist-get my/org-agenda-nearest-upcoming-scheduled 
:scheduled-string)))))
    `((foo
       menu-item
       ,(propertize
         "No entry found"
         'face
         `(:background ,(face-attribute 'default :background)
           :foreground ,(face-attribute 'default :foreground)
           :box (:line-width (1 . 1)
                 :color ,(face-attribute 'default :foreground))))
       ignore
       :help "No entry with the nearest upcoming scheduled date found."))))

(defun my/org-agenda-nearest-upcoming-scheduled-jump ()
  (interactive)
  (with-current-buffer (switch-to-buffer
                        (marker-buffer
                         (plist-get my/org-agenda-nearest-upcoming-scheduled 
:marker)))
    (goto-char (plist-get my/org-agenda-nearest-upcoming-scheduled :marker))))
#+END_SRC




reply via email to

[Prev in Thread] Current Thread [Next in Thread]