emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* Elisp function to get the upcoming event with the closest scheduled date
@ 2023-12-31 17:30 Rodrigo Morales
  2024-01-03  5:29 ` Rodrigo Morales
  0 siblings, 1 reply; 2+ messages in thread
From: Rodrigo Morales @ 2023-12-31 17:30 UTC (permalink / raw)
  To: emacs-orgmode

I just learned that it is possible to add functions to tab-bar-format,
which is the variable that controls the information that is shown in the
tab-bar.

I want to write a function that gets the upcoming event with the closest
scheduled date so that it is shown in the tab-bar. I want to know if
someone has written a function that accomplishes the described
behavior. If not, does anyone have some tips for writing such function?


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: Elisp function to get the upcoming event with the closest scheduled date
  2023-12-31 17:30 Elisp function to get the upcoming event with the closest scheduled date Rodrigo Morales
@ 2024-01-03  5:29 ` Rodrigo Morales
  0 siblings, 0 replies; 2+ messages in thread
From: Rodrigo Morales @ 2024-01-03  5:29 UTC (permalink / raw)
  To: emacs-orgmode

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



^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2024-01-03  5:30 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-12-31 17:30 Elisp function to get the upcoming event with the closest scheduled date Rodrigo Morales
2024-01-03  5:29 ` Rodrigo Morales

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).