emacs-orgmode
[Top][All Lists]
Advanced

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

[O] Progress of org-find-timestamps


From: Marc-Oliver Ihm
Subject: [O] Progress of org-find-timestamps
Date: Sun, 14 Aug 2011 17:00:49 +0200
User-agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0) Gecko/20110624 Thunderbird/5.0

Am 28.07.2011 09:54, schrieb Bastien:
> Hi Marc-Oliver,
> 
> Marc-Oliver Ihm<address@hidden>  writes:
> 
>> Thanx for testing again !
> 
> You're welcome.
> 
>> I will try to figure out, how to patch `org-sparse-tree'.
> 
> Thanks -- let us know how it goes, and take the time to grasp
> Org's internals...
> 
>> And I will add active timestamps. Which was a think, that I have
>> thought of before, but postponed until someone would suggest/request
>> this feature :-)
> 
> Yep.  It will make your `org-find-timestamps' function quite useful.
> Please be aware that I will spend some time and trying to create a cache
> for timestamps (see recent discussions about calfw), and that such a
> cache could help a lot in making your solution easier to implement.
> 
> Best,
> 



Hello Bastien,


Just to keep you and the newsgroup updated :-)

Down below you will find the current version of org-find-timestamps.

It is, as you did suggest, now capable of finding active timestamps as well as 
inactive ones.
However, studying the code of org-sparse-tree, I realized, that it would be 
beneficial, to be able to
find CLOSED, SCHEDULED and DEADLINE timestamps as well. Therefore I have 
started to implement these features as well.
Moreover I would like to make available some of the functionality of 
org-find-timestamps within org-sparse-tree.

As soon as I am done with this, I will post a patch to org.el.


with kind regards, Marc-Oliver Ihm


P.s.: I realized the the features of org-sparse-tree and org-find-timestamps 
overlap to a considerable degree, 
although the do not share any code. This is probably a sign, that both 
functions should be reworked to use some 
common helper functions. This might be a secound step, once org-find-timestamps 
has found its way into the code ...



(defun org-find-timestamps (&optional first-date last-date buffer-name which 
collect-method sort)
  "Find inactive timestamps within a date-range and maybe sort them.

This function can help to bring the notes, that you take within
org-mode, into a chronological order, even if they are scattered
among many different nodes. The result is somewhat like a diary,
listing your notes for each successive day. Please be aware
however: This intended usage requires, that you routinely
insert inactive timestamps into the notes that you write.

org-find-timstamps works by creating a regular expression to
match a given range of dates, doing a search for it and
displaying the results either as a sparse tree or with the help
of occur. The original buffer is not modified.

Argument FIRST-DATE and LAST-DATE (yyyy-mm-dd) define the range
of timestamps to search for. 

BUFFER-NAME specifies the name of the buffer to search. If nil, use 
current buffer.

WHICH (`active', `inactive' or `both'), tells which timestamps to use.

COLLECT-METHOD can be one of `org-occur', `occur' and
`multi-occur', thus telling: Which buffers to search (current or
all org-mode buffers) and how to present matches.

Results will be sorted according to SORT (either the symbol `y'
or `n'); this is only possible, if results are presented with
`occur' or `multi-occur'.

All Arguments can be `nil' (or ommitted), in which case their values are
queried interactively.

"
  (interactive)
  
  (let ((occur-buffer-name "*Occur*")
        (occur-header-regex "^[0-9]+ match\\(es\\)?") ;; regexp to match for 
header-lines in *Occur* buffer
        description
        swap-dates
        (days 0) 
        date-regex
        buff
        org-buffers
        )
    (if buffer-name (switch-to-buffer buffer-name))
    (save-window-excursion
      ;; ask for type of timestamp to search, if not supplied as an argument
      (cond ((null which)
             (setq which (intern-soft (car (split-string (org-icompleting-read 
"Please choose, which type of timestamp  to search: " '("active" "inactive" 
"both") nil t nil nil "inactive"))))))
            ((not (member which '(active inactive both)))
             (error "Argument `WHICH' can not be `%s'" which)))
      ;; ask for date-range, if not supplied as argument
      (or last-date (setq last-date (org-read-date nil nil nil "End date (or 
start): " nil nil)))
      (or first-date (setq first-date (org-read-date nil nil nil "Start date 
(or end): " nil nil)))
      ;; swap dates, if required
      (when (string< last-date first-date)
        (setq swap-dates last-date)
        (setq last-date first-date)
        (setq first-date swap-dates))
      ;; readable description of what we searched for
      (setq description (format "%s timestamps from %s to %s in %s, %s" 
                                (if (eq which 'both) "active and inactive" 
(symbol-name which))
                                first-date last-date
                                (if (eq collect-method 'multi-occur) "all 
org-buffers" (concat "buffer " (buffer-name)))
                                (if (and (eq sort 'yes) (not (eq collect-method 
'org-occur))) "sorted" "not sorted")))
      ;; temporary buffer for date-manipulations
      (with-temp-buffer
        ;; construct list of dates in working buffer, loop as long we did not 
reach end-date
        (while (not (looking-at-p last-date))
          (goto-char (point-max))
          ;; Type of timstamp (inactive) might be wrong, will be corrected below
          (insert "[")
          ;; Day of week (Mo) might be wrong, will be corrected below
          (insert first-date " Mo]\n") 
          (forward-line -1)
          ;; advance number of days and correct day of week
          (org-timestamp-change days 'day) 
          (setq days (1+ days))
          (when (eq which 'both)
            ;; double last timestamp
            (let (start content)
              (move-to-column 0)
              (setq start (point))
              (forward-line)
              (setq content (delete-and-extract-region start (point)))
              (insert content)
              (insert content)
              (forward-line -1)
              )
            )
          (unless (eq which 'inactive)
            ;; inserted inactive timestamp above, now we correct this
            (org-toggle-timestamp-type)
            )
          (move-to-column 1)
          )
        (goto-char (point-max))
        ;; transform constructed list of dates into a single, optimized regex
        (setq date-regex (regexp-opt (split-string (buffer-string) "\n" t)))
        )
      )
    ;; If no argument supplied, ask user, which buffers to search and how to 
present results 
    (or collect-method (setq collect-method (intern (car (split-string 
(org-icompleting-read "Please choose, which buffers to search and how to 
present the matches: " '("occur -- this buffer, list" "multi-occur -- all 
org-buffers, list" "org-occur -- this-buffer, sparse tree") nil t nil nil 
"occur -- this buffer, list"))))))

    ;; Perform the actual search
    (save-window-excursion
      (cond ((eq collect-method 'occur)
             (occur date-regex)
             )
            ((eq collect-method 'org-occur)
             (if (string= major-mode "org-mode")
                 (org-occur date-regex)
               (error "Buffer not in org-mode"))
             )
            ((eq collect-method 'multi-occur)
             ;; construct list of all org-buffers
             (dolist (buff (buffer-list))
               (set-buffer buff)
               (if (string= major-mode "org-mode")
                   (setq org-buffers (cons buff org-buffers))))
             (multi-occur org-buffers date-regex))
            (t (error (format "Argument `COLLECT-METHOD' can not be `%s'" 
collect-method)))
            )
      )
    ;; Postprocessing: Optionally sort buffer with results
    ;; org-occur operates on the current buffer, so we cannot modify its 
results afterwards
    (if (eq collect-method 'org-occur)
        (message (concat "Sparse tree with " description))
      ;; switch to occur-buffer and modify it
      (if (not (get-buffer occur-buffer-name))
          (message (concat "Did not find any matches for " description))
        (let ((original-inhibit-read-only inhibit-read-only))
          (unwind-protect 
              (progn
                ;; next line might be risky, so we unwind-protect it
                (setq inhibit-read-only t)
                (set-buffer occur-buffer-name)
                (goto-char (point-min))
                ;; beautify the occur-buffer by replacing the potentially long 
original regexp
                (while (search-forward (concat " for \"" date-regex "\"") nil t)
                  (replace-match "" nil t))
                (goto-char (point-min))
                ;; Sort results by matching date ?
                (when (cond ((eq sort 'yes) t)
                            ((eq sort 'no) nil)
                            ((null sort) (y-or-n-p "Sort results by date ? "))
                            (t (error "Argument `SORT' can not be `%s'" sort)))
                  (when (eq collect-method 'multi-occur)
                    ;; bring all header lines ('xx matches for ..') to top of 
buffer, all lines with matches to bottom
                    (sort-subr t
                               'forward-line
                               'end-of-line
                               ;; search-key for this sort only differentiates 
between header-lines and matche-lines
                               (lambda () (if (looking-at-p occur-header-regex) 
2 1))
                               nil)
                    )
                  ;; goto first line of matches
                  (goto-char (point-max))
                  (search-backward-regexp occur-header-regex)
                  (forward-line)
                  ;; sort all matches according to date, that matched the regex
                  (sort-subr t
                             'forward-line
                             'end-of-line
                             ;; search-key for this sort is date
                             (lambda () (search-forward-regexp date-regex) 
(substring (match-string 0) 1 -1))
                             nil 
                             'string<)
                  ;; pretend, that we did not modify the occur-buffer
                  )
                (insert (format "Searched for %s.\n" description))
                (goto-char (point-min))
                (set-buffer-modified-p nil)
                )
            (setq inhibit-read-only original-inhibit-read-only)
            )
          )
        ;; show result
        (switch-to-buffer occur-buffer-name)
        )
      )
    )
  )





reply via email to

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