From 619e5bdcae1fe63d777de249570adee07f162a24 Mon Sep 17 00:00:00 2001 From: Daniel Borchmann Date: Sun, 26 Jan 2020 20:42:08 +0100 Subject: [PATCH] No longer store timeline of current buffer in separate variable This does not play nicely with undo, because undo won't track changes to local variables. Thus, if we every want to have a working undo in timeline buffers, the timeline needs to be saved as something textual. Luckily, we already store each entry of the timeline as a text property in the timeline table, and from now on we will extract the timeline from there whenever we need it. Undo is still not working fully yet, there are some oddities that need to be addressed first. --- site-lisp/timeline-tools.el | 108 ++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 48 deletions(-) diff --git a/site-lisp/timeline-tools.el b/site-lisp/timeline-tools.el index 9239e50..77da068 100644 --- a/site-lisp/timeline-tools.el +++ b/site-lisp/timeline-tools.el @@ -91,9 +91,6 @@ end date of the timeline." (defvar timeline-tools--current-files nil "Files from which the current timeline has been extracted.") -(defvar timeline-tools--current-timeline nil - "Currently displayed timeline in abstract form.") - (defvar timeline-tools-mode-map (let ((map (make-sparse-keymap))) (define-key map [remap self-insert-command] 'undefined) @@ -434,10 +431,10 @@ interactively, START and END are queried with `org-read-date’." (setq-local timeline-tools--current-time-start (org-time-string-to-seconds tstart)) (setq-local timeline-tools--current-time-end (org-time-string-to-seconds tend)) (setq-local timeline-tools--current-files files) - (setq-local timeline-tools--current-timeline nil) (setq-local timeline-tools-time-format timeline-tools-time-format) (setq-local timeline-tools-headline-time-format timeline-tools-headline-time-format) (hl-line-mode) + (buffer-enable-undo) (timeline-tools-redraw-timeline 'force)) (pop-to-buffer target-buffer) t)) @@ -466,45 +463,64 @@ current values of the relevant buffer local variables." (interactive) (if (not (eq major-mode 'timeline-tools-mode)) (user-error "Not in Timeline buffer") - (when force - (setq-local timeline-tools--current-timeline - (timeline-tools-transform-timeline - (timeline-tools-timeline - timeline-tools--current-time-start - timeline-tools--current-time-end - timeline-tools--current-files)))) - (erase-buffer) - (insert (format "* Timeline from [%s] to [%s]\n\n" - (format-time-string timeline-tools-headline-time-format - timeline-tools--current-time-start) - (format-time-string timeline-tools-headline-time-format - timeline-tools--current-time-end))) - (insert "|--|\n") - (insert "| Category | Start | End | Duration | Task |\n") - (let ((last-category nil) - (current-category nil)) - (dolist (line timeline-tools--current-timeline) - (setq current-category (funcall timeline-tools-category-function - line - timeline-tools--current-time-start - timeline-tools--current-time-end)) - (when (not (equal last-category current-category)) - (insert "|--|\n") - (setq last-category current-category)) - (insert - (propertize (format "| %s | %s | %s | %s min | %s | \n" - current-category - (timeline-tools-format-entry-time line 'start) - (timeline-tools-format-entry-time line 'end) - (timeline-tools-entry-duration line) - (timeline-tools-entry-headline line)) - 'marker (timeline-tools-entry-marker line) - 'entry line)))) - (insert "|--|\n") - (org-table-align) - (goto-char (point-min)) - (timeline-tools-next-line) - (buffer-enable-undo))) + (let ((timeline (if force + (timeline-tools-transform-timeline + (timeline-tools-timeline + timeline-tools--current-time-start + timeline-tools--current-time-end + timeline-tools--current-files)) + (timeline-tools--get-timeline-from-buffer)))) + (erase-buffer) + (insert (format "* Timeline from [%s] to [%s]\n\n" + (format-time-string timeline-tools-headline-time-format + timeline-tools--current-time-start) + (format-time-string timeline-tools-headline-time-format + timeline-tools--current-time-end))) + (insert "|--|\n") + (insert "| Category | Start | End | Duration | Task |\n") + (let ((last-category nil) + (current-category nil)) + (dolist (line timeline) + (setq current-category (funcall timeline-tools-category-function + line + timeline-tools--current-time-start + timeline-tools--current-time-end)) + (when (not (equal last-category current-category)) + (insert "|--|\n") + (setq last-category current-category)) + (insert + (propertize (format "| %s | %s | %s | %s min | %s | \n" + current-category + (timeline-tools-format-entry-time line 'start) + (timeline-tools-format-entry-time line 'end) + (timeline-tools-entry-duration line) + (timeline-tools-entry-headline line)) + 'marker (timeline-tools-entry-marker line) + 'entry line)))) + (insert "|--|\n") + (org-table-align) + (goto-char (point-min)) + (timeline-tools-next-line)))) + +(defun timeline-tools--get-timeline-from-buffer () + "Extract current timeline from buffer and return it. +This function expects the individual lines of a timeline to be +text properties under the keyword `entry' in the current buffer, +as it is done by `timeline-tools-redraw-timeline'." + (if (not (eq major-mode 'timeline-tools-mode)) + (user-error "Not in Timeline buffer") + (let (timeline) + (save-mark-and-excursion + (goto-char (point-min)) + (while (zerop (forward-line)) + ;; scan line for a text property named `entry' + (while (and (not (eolp)) + (not (get-text-property (point) 'entry))) + (forward-char)) + ;; if not at the end, we have found something … add it + (unless (eolp) + (push (get-text-property (point) 'entry) timeline))) + (nreverse timeline))))) (defun timeline-tools-reparse-timeline () "Parse timeline from files again and redraw current display. @@ -564,11 +580,7 @@ Updates category properties before constructing the new timeline." (let ((entry (get-text-property (point) 'entry))) (unless entry (user-error "Not on valid row in timeline")) - (unless (< 1 (length timeline-tools--current-timeline)) - (user-error "Cannot delete last line")) - (setq-local timeline-tools--current-timeline - (timeline-tools-transform-timeline - (delq entry timeline-tools--current-timeline))))) + (kill-line))) ;; the call to `erase-buffer’ in `timeline-tools-redraw-timeline’ somehow ;; makes `save-mark-and-excursion’ meaningless; thus we save the number of the ;; current line by ourselves