From mboxrd@z Thu Jan 1 00:00:00 1970 From: Marc-Oliver Ihm Subject: Progress of org-find-timestamps Date: Sun, 14 Aug 2011 17:00:49 +0200 Message-ID: <4E47E321.7040505@online.de> References: <4E22A556.3010202@online.de> <4E29C4BA.5090906@online.de> <87sjpts1cm.fsf@gnu.org> <4E2F12C3.6040502@online.de> <87oc0e6d5n.fsf@altern.org> Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-15 Content-Transfer-Encoding: 7bit Return-path: Received: from eggs.gnu.org ([140.186.70.92]:34746) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QscBY-0002xb-18 for emacs-orgmode@gnu.org; Sun, 14 Aug 2011 11:01:09 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QscBW-0008Ay-Fc for emacs-orgmode@gnu.org; Sun, 14 Aug 2011 11:01:08 -0400 Received: from lo.gmane.org ([80.91.229.12]:39512) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QscBW-0008Aq-21 for emacs-orgmode@gnu.org; Sun, 14 Aug 2011 11:01:06 -0400 Received: from list by lo.gmane.org with local (Exim 4.69) (envelope-from ) id 1QscBU-0000JU-Me for emacs-orgmode@gnu.org; Sun, 14 Aug 2011 17:01:04 +0200 Received: from p54a8860b.dip0.t-ipconnect.de ([84.168.134.11]) by main.gmane.org with esmtp (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Sun, 14 Aug 2011 17:01:04 +0200 Received: from marc-oliver.ihm by p54a8860b.dip0.t-ipconnect.de with local (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Sun, 14 Aug 2011 17:01:04 +0200 In-Reply-To: <87oc0e6d5n.fsf@altern.org> List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org Sender: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org To: emacs-orgmode@gnu.org Cc: Marc-Oliver Ihm Am 28.07.2011 09:54, schrieb Bastien: > Hi Marc-Oliver, > > Marc-Oliver Ihm 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) ) ) ) )