org-faq.org: Mention Bernt's doc as the origine of Victor's solution.
[worg.git] / code / elisp / org-reftable.el
1 ;;; org-reftable.el --- Ordered lookup table for reference numbers\r
2 \r
3 ;; Copyright (C) 2011,2012 Free Software Foundation, Inc.\r
4 \r
5 ;; Author: Marc-Oliver Ihm <org-reftable@ferntreffer.de>\r
6 ;; Keywords: hypermedia, matching\r
7 ;; Requires: org\r
8 ;; Download: http://orgmode.org/worg/code/elisp/org-reftable.el\r
9 ;; Version: 2.0.0\r
10 \r
11 ;;; License:\r
12 \r
13 ;; This program is free software; you can redistribute it and/or modify\r
14 ;; it under the terms of the GNU General Public License as published by\r
15 ;; the Free Software Foundation; either version 3, or (at your option)\r
16 ;; any later version.\r
17 ;;\r
18 ;; This program is distributed in the hope that it will be useful,\r
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of\r
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
21 ;; GNU General Public License for more details.\r
22 ;;\r
23 ;; You should have received a copy of the GNU General Public License\r
24 ;; along with GNU Emacs; see the file COPYING.  If not, write to the\r
25 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,\r
26 ;; Boston, MA 02110-1301, USA.\r
27 \r
28 ;;; Commentary:\r
29 \r
30 ;; Purpose:\r
31 ;;\r
32 ;;  Create, search and look up numbers from a dedicated reference table.\r
33 ;;  These numbers (e.g. "R237" or "-455-") may be used to refer to:\r
34 ;;\r
35 ;;   - Nodes in Org-mode (insert them into the heading)\r
36 ;;\r
37 ;;   - Things outside of org (e.g. mailfolders, directories, reports or\r
38 ;;     pieces of paper)\r
39 ;;\r
40 ;;  The table is kept sorted for most frequently or most recently used\r
41 ;;  reference numbers. Additionally, lines can be selected by keywords, so\r
42 ;;  that specific references can be found very easily. Earlier versions of \r
43 ;;  this extension had been named org-refer-by-number.el.\r
44 ;;\r
45 ;;\r
46 ;; Setup:\r
47 ;;\r
48 ;;  - Add these lines to your .emacs:\r
49 ;;\r
50 ;;    (require 'org-reftable)\r
51 ;;    ;; Later you should probably change this id, as will be explained below\r
52 ;;    (setq org-reftable-id "00e26bef-1929-4110-b8b4-7eb9c9ab1fd4")\r
53 ;;    ;; Optionally assign a key; pick your own favorite\r
54 ;;    (global-set-key (kbd "C-+") 'org-reftable)\r
55 ;;\r
56 ;;  - Just invoke `org-reftable', which will explain how to complete your\r
57 ;;    setup by creating the necessary reference table.\r
58 ;;\r
59 ;;\r
60 ;; Further reading:\r
61 ;;\r
62 ;;  - For the necessary setup read the documentation of `org-reftable-id'\r
63 ;;    (which is, what `org-reftable' shows, as long as your setup is still\r
64 ;;    incomplete).\r
65 ;;\r
66 ;;  - For regular usage, see the function `org-reftable'.\r
67 ;;\r
68 \r
69 ;;; Change Log:\r
70 \r
71 ;;   [2012-12-07 Fr] Version 2.0.0:\r
72 ;;    - renamed the package from \"org-refer-by-number\" to \"org-reftable\"\r
73 ;;    - The format of the reference table has changed ! You need to bring\r
74 ;;      your existing table into the new format by hand (which however is\r
75 ;;      easy and explained below)\r
76 ;;    - Reference table can be sorted after usage count or date of last access\r
77 ;;    - Ask user explicitly, which command to invoke\r
78 \r
79 ;;   [2012-09-22 Sa] Version 1.5.0:\r
80 ;;    - New command "sort" to sort a buffer or region by reference number\r
81 ;;    - New commands "highlight" and "unhighlight" to mark references\r
82 \r
83 ;;   [2012-07-13 Fr] Version 1.4.0:\r
84 ;;    - New command "head" to find a headline with a reference number\r
85 \r
86 ;;   [2012-04-28 Sa] Version 1.3.0:\r
87 ;;    - New commands occur and multi-occur\r
88 ;;    - All commands can now be invoked explicitly\r
89 ;;    - New documentation\r
90 ;;    - Many bugfixes\r
91 \r
92 ;;   [2011-12-10 Sa] Version 1.2.0:\r
93 ;;    - Fixed a bug, which lead to a loss of newly created reference numbers\r
94 ;;    - Introduced single and double prefix arguments\r
95 ;;    - Started this Change Log\r
96 \r
97 ;;; Code:\r
98 \r
99 (require 'org-table)\r
100 (require 'cl)\r
101 \r
102 (defvar org-reftable-preferred-command nil\r
103   "Preferred command when choosing")\r
104 \r
105 (defvar org-reftable-commands '(occur head new enter leave goto help reorder sort update highlight unhighlight)\r
106   "List of commands known to org-reftable:\r
107  \r
108 \r
109   occur: If you supply a keyword (text): Apply emacs standard\r
110     occur operation on the table of references; ask for a\r
111     string (keyword) to select lines. Occur will only show you\r
112     references which contain the given keyword, so you can easily\r
113     find the right one\r
114 \r
115    If you supply a reference (number): Apply emacs standard\r
116    multi-occur operation all org-mode buffers to search for a\r
117    specific reference\r
118 \r
119   head: Scan all headings until the first one with the given\r
120     reference number is found\r
121 \r
122   new: Create a new reference. Copy any previously selected text\r
123 \r
124   leave: Leave the table of references. If the last command has\r
125     been \"new\", the new reference is copied and ready to yank\r
126 \r
127   enter: Just enter the node with the table of references\r
128 \r
129   goto: Search for a specific references within the table of\r
130     references\r
131 \r
132   help: Show this list of commands\r
133 \r
134   all: Show all commands including the less frequently used ones\r
135     given below.\r
136 \r
137   reorder: Temporarily reorder the table of references, e.g. by\r
138     cound or last access\r
139 \r
140   sort: Sort a set of lines (either the active region or the\r
141     whole buffer) by the references found within each line\r
142 \r
143   update: For the given reference update the line in the\r
144     reference table\r
145 \r
146   highlight: Highlight references in region or buffer\r
147 \r
148   unhighlight: Remove highlights\r
149 \r
150 \r
151 When prompting for a command, org-reftable puts the most likely\r
152 chosen one (e.g. \"occur\" or \"new\") at the front of the list,\r
153 so that you may just type RET. If this command needs additional\r
154 input (like e.g. \"occur\" does, which needs a string to search\r
155 for), you may supply this input right away, although you are\r
156 still beeing prompted for the command (in that case your input\r
157 will not match any of the given choices).\r
158 \r
159 ")\r
160 \r
161 (defvar org-reftable-commands-some '(occur head new leave enter goto all help)\r
162   "Subset of org-reftable-commands shown initially" )\r
163 \r
164 (defvar org-reftable-id nil \r
165   "Id of the Org-mode node, which contains the reference table.\r
166 \r
167 Read below, on how to set up things. See the documentation of\r
168 `org-reftable' for normal usage after setup.\r
169 \r
170 Setup requires two steps:\r
171 \r
172  - Adjust your .emacs initialization file\r
173 \r
174  - Create a suitable org-mode node\r
175 \r
176 \r
177 Here are the lines, you should add to your .emacs:\r
178 \r
179   (require 'org-reftable)\r
180   ;; Later you should probably change this id, as will be explained below\r
181   (setq org-reftable-id \"00e26bef-1929-4110-b8b4-7eb9c9ab1fd4\")\r
182   ;; Optionally assign a key; pick your own favorite\r
183   (global-set-key (kbd \"C-+\") 'org-reftable)\r
184 \r
185 Do not forget to restart emacs to make these lines effective.\r
186 \r
187 The id given above is an example, yours can be different.\r
188 \r
189 \r
190 As a second step you need to create the org-mode node, where your\r
191 reference numbers will be stored. It may look like this:\r
192 \r
193 \r
194   * org-reftable\r
195     :PROPERTIES:\r
196     :ID:       00e26bef-1929-4110-b8b4-7eb9c9ab1fd4\r
197     :END:\r
198 \r
199 \r
200     |     | comment            |         |         |               |\r
201     | ref | ;c                 | count;s | created | last-accessed |\r
202     |-----+--------------------+---------+---------+---------------|\r
203     | R1  | My first reference |         |         |               |\r
204 \r
205 \r
206 \r
207 You may just want to copy this node into one of your org-files.\r
208 Many things however can or should be adjusted:\r
209 \r
210  - The node needs not be a top level node.\r
211 \r
212  - Its name is completely at you choice. The node is found\r
213    through its ID.\r
214 \r
215  - There are two lines of headings above the first hline. The\r
216    first one is ignored by org-reftable, and you can use them to\r
217    give meaningful names to columns; the second line however\r
218    contains configuration information for org-reftable; please\r
219    read further below for its format.\r
220 \r
221  - The sequence of columns does not matter. You may reorder them\r
222     any way you like; e.g. make the comment-column the last\r
223     columns within the table.\r
224 \r
225  - You can add further columns or even remove the\r
226    \"Comment\"-column. The columns \"ref\" and \"created\"\r
227    however are required. Columns \"cound\" and \"last-accessed\"\r
228    are optional, but highly suggested anyway.\r
229 \r
230  - Your references need not start at \"R1\"; However, having an\r
231    initial row is required (it servers a template for subsequent\r
232    references).\r
233 \r
234  - Your reference need not have the form \"R1\"; you may just as\r
235    well choose any text, that contains a single number,\r
236    e.g. \"reference-{1}\" or \"#1\" or \"++1++\" or \"-1-\". The\r
237    function `org-reftable' will inspect your first reference and\r
238    create all subsequent references in the same way.\r
239     \r
240  - You may want to change the ID-Property of the node above and\r
241    create a new one, which is unique (and not just a copy of\r
242    mine). You need to change it in the lines copied to your .emacs\r
243    too. However, this is not strictly required to make things\r
244    work, so you may do this later, after trying out this package.\r
245 \r
246 \r
247 Optionally you may tweak the second header line to adjust\r
248 `org-reftable' a bit. In the ecample above it looks like this:\r
249 \r
250 \r
251     | ref | ;c                 | count;s | created | last-accessed |\r
252     |-----+--------------------+---------+---------+---------------|\r
253 \r
254 The different fields have different meanings:\r
255 \r
256  - ref : this denotes the column which contains you references\r
257 \r
258  - ;c : the flag \"c\" (\"c\" for \"copy\") denotes this column\r
259    as the one beeing copied on command \"leave\". In the example above,\r
260    it is the comment-column.\r
261 \r
262  - count;s : this is the column which counts last access, whence\r
263    \"count\"; the flag \"s\" stands for \"sort\", so this is the\r
264    column after which the table is sorted. You may also sort\r
265    after columns \"ref\" or \"last-accessed\".\r
266 \r
267  - created : date when this reference was created.\r
268 \r
269  - last-accessed : date and time, when this reference was last accessed.\r
270 \r
271 \r
272 After this two-step setup process you may invoke `org-reftable'\r
273 to create a new reference number; read there for instructions on\r
274 normal usage.\r
275 \r
276 If you have an existing reference table from a version of\r
277 org-reftable before 2.0 (in fact earlier versions were rather\r
278 named org-refer-by-number), you need to add a second headline\r
279 like this, just about the hline to reflect the usage of columns\r
280 in earlier versions:\r
281 \r
282   | ref | created |\r
283 \r
284 This will mark the first column as the actual references and the\r
285 second column as the date of creation. However, to take advantage\r
286 of the new features you should also add two other columns \"count;s\" \r
287 (marked as the sort-column) and \"last-accessed\".\r
288 \r
289 ")\r
290 \r
291 (defvar org-reftable-windowconfig-before nil \r
292   "Saved window-configuration for `org-reftable'.\r
293 This variable is only used internally.")\r
294 \r
295 (defvar org-reftable-marker-outside-before nil \r
296   "Saved position in reftable-buffer bit outside of reftable (if at all).\r
297 This variable is only used internally.")\r
298 \r
299 (defvar org-reftable-last-action nil \r
300   "Last action performed by `org-reftable'.\r
301 This variable is only used internally.")\r
302 \r
303 (defvar org-reftable-occur-buffer nil\r
304   "Buffer (if any) with result from occur or multi-occur.\r
305 This variable is only used internally.")\r
306 \r
307 (defvar org-reftable-ref-regex nil\r
308   "Regular expression to search for\r
309 This variable is only used internally.")\r
310 \r
311 \r
312 \r
313 (defun org-reftable  (&optional what search) \r
314   "Create, search and look up numbers from a dedicated reference table.\r
315 These numbers (e.g. \"R237\" or \"-455-\") may be used to refer to:\r
316 \r
317  - Nodes in Org-mode (insert them into the heading)\r
318 \r
319  - Things outside of org (e.g. mailfolders, directories, reports or\r
320    pieces of paper)\r
321 \r
322 The table is kept sorted for most frequently or most recently used\r
323 reference numbers. Additionally, lines can be selected by keywords, so\r
324 that specific references can be found easily.\r
325 \r
326 \r
327 Read below for a detailed description of this function. See the\r
328 documentation of `org-reftable-id' for the necessary\r
329 setup.\r
330 \r
331 \r
332 The function `org-reftable' operates on a dedicated table (called\r
333 the reference table) within a special Org-mode node. The node has\r
334 to be created as part of your initial setup. Each line of the\r
335 reference table contains:\r
336 \r
337  - A reference \r
338 \r
339  - Its respective creation date\r
340 \r
341  - A number; counting, how often each reference has been\r
342    used. This number is updated automatically and the table can\r
343    be sorted according to it, so that most frequently used\r
344    references appear at the top of the table and can be spotted\r
345    easily.\r
346 \r
347  - Date and time of last access. This column can alternatively be\r
348    used to sort the table.\r
349 \r
350 The reference table is found through the id of the containing\r
351 node; this id must be stored within `org-reftable-id' (see there\r
352 for details).\r
353 \r
354 \r
355 The function `org-reftable' is the only interactive function of\r
356 this package and its sole entry point; it offers several commands\r
357 to create, find and look up these reference numbers. All of them\r
358 are described in the docstring of `org-reftable-commands' (see\r
359 there for details).\r
360 \r
361 \r
362 Finally, org-reftable can also be invoked from elisp; the two\r
363 optional arguments to be accepted are:\r
364 \r
365   search : string to search for\r
366     what : symbol of the command to invoke\r
367 \r
368 An example would be:\r
369 \r
370  (org-reftable \"237\" 'head)   ;; find heading with ref 237\r
371 \r
372 "\r
373 \r
374   (interactive "P")\r
375 \r
376   (let (within-node        ; True, if we are within node with reference table\r
377         result-is-visible  ; True, if node or occur is visible in any window\r
378         ref-node-buffer-and-point  ; cons with buffer and point of reference node\r
379         below-cursor       ; word below cursor\r
380         active-region      ; active region (if any)\r
381         guarded-search     ; with guard against additional digits\r
382         commands           ; currently active set of selectable commands\r
383         what-adjusted      ; True, if we had to adjust what\r
384         what-input         ; Input on what question (need not necessary be "what")\r
385         reorder-once       ; Column to use for single time sorting\r
386         parts              ; Parts of a typical reference number (which\r
387                            ; need not be a plain number); these are:\r
388         head               ; Any header before number (e.g. "R")\r
389         maxref             ; Maximum number from reference table (e.g. "153")\r
390         tail               ; Tail after number (e.g. "}" or "")\r
391         ref-regex          ; Regular expression to match a reference\r
392         numcols            ; Number of columns in reference table\r
393         columns            ; Associate column names with numbers\r
394         kill-new-text      ; Text that will be appended to kill ring\r
395         message-text       ; Text that will be issued as an explanation,\r
396                            ; what we have done\r
397         )\r
398 \r
399     ;;\r
400     ;; Examine current buffer and location, before turning to reference table\r
401     ;;\r
402 \r
403     ;; Get the content of the active region or the word under cursor\r
404     (if (and transient-mark-mode\r
405              mark-active)\r
406         (setq active-region (buffer-substring (region-beginning) (region-end))))\r
407     (setq below-cursor (thing-at-point 'symbol))\r
408 \r
409 \r
410     ;; Find out, if we are within reference table or not\r
411     (setq within-node (string= (org-id-get) org-reftable-id))\r
412 \r
413     ;; Find out, if point in any window is within node with reference table\r
414     (mapc (lambda (x) (with-current-buffer (window-buffer x)\r
415                         (when (or \r
416                                (string= (org-id-get) org-reftable-id)\r
417                                (eq (window-buffer x) \r
418                                    org-reftable-occur-buffer))\r
419                           (setq result-is-visible t))))\r
420           (window-list))\r
421         \r
422 \r
423 \r
424     ;;\r
425     ;; Get decoration of references and highest number from reference table\r
426     ;;\r
427 \r
428     ;; Find node\r
429     (setq ref-node-buffer-and-point (org-reftable-id-find))\r
430     (unless ref-node-buffer-and-point\r
431       (org-reftable-report-setup-error \r
432        (format "Cannot find node with id \"%s\"" org-reftable-id)))\r
433 \r
434     ;; Get configuration of reftable\r
435     (with-current-buffer (car ref-node-buffer-and-point)\r
436       (unless (string= (org-id-get) org-reftable-id)\r
437         ;; Get marker for point within reftable-buffer, but only if outside\r
438         ;; of reftable (if point is within reftable, we will try to stay at\r
439         ;; the same ref)\r
440         (setq org-reftable-marker-outside-before (point-marker))\r
441         (goto-char (cdr ref-node-buffer-and-point)))\r
442 \r
443       ;; parse table\r
444       (setq parts (org-reftable-parse-and-adjust-table reorder-once)))\r
445     \r
446     ;; Give names to parts of configuration\r
447     (setq head (nth 0 parts))\r
448     (setq maxref (nth 1 parts))\r
449     (setq tail (nth 2 parts))\r
450     (setq numcols (nth 3 parts))\r
451     (setq columns (nth 4 parts))\r
452     (setq ref-regex (nth 5 parts))\r
453     \r
454     ;;\r
455     ;; Find out, what we are supposed to do\r
456     ;;\r
457 \r
458     (if (equal what '(4)) (setq what 'leave))\r
459 \r
460     ;; Set preferred action, that will be the default choice\r
461     (setq org-reftable-preferred-command\r
462           (if within-node\r
463               (if (eq org-reftable-last-action 'new)\r
464                   'leave\r
465                 'occur)\r
466           (if active-region\r
467               'new\r
468            (if (and below-cursor (string-match ref-regex below-cursor))\r
469             'occur\r
470             nil))))\r
471     \r
472     ;; Ask user\r
473     (unless what\r
474       (setq commands (copy-list org-reftable-commands-some))\r
475       (while (progn\r
476                (setq what-input\r
477                      (org-icompleting-read \r
478                       "Please choose: " \r
479                       (mapcar 'symbol-name \r
480                               ;; Construct unique list of commands with\r
481                               ;; preferred one at front\r
482                               (delq nil (delete-dups \r
483                                          (append \r
484                                           (list org-reftable-preferred-command)\r
485                                           commands))))\r
486                       nil nil))\r
487                (setq what (intern what-input))\r
488                \r
489                ;; user is not required to input one of the commands; if\r
490                ;; not, take the first one and use the original input for\r
491                ;; next question\r
492                (if (memq what commands)\r
493                    ;; input matched one element of list, dont need original\r
494                    ;; input any more\r
495                    (setq what-input nil)\r
496                  ;; what-input will be used for next question, use first\r
497                  ;; command for what\r
498                  (setq what (or org-reftable-preferred-command\r
499                                 (first commands)))\r
500                  ;; remove any trailing dot, that user might have added to\r
501                  ;; disambiguate his input\r
502                  (if (equal (substring what-input -1) ".")\r
503                      ;; but do this only, if dot was really necessary to\r
504                      ;; disambiguate\r
505                      (let ((shortened-what-input (substring what-input 0 -1)))\r
506                        (unless (test-completion shortened-what-input \r
507                                             (mapcar 'symbol-name \r
508                                                     org-reftable-commands))\r
509                            (setq what-input shortened-what-input)))))\r
510                      \r
511 \r
512                ;; ask for reorder in loop, because we have to ask for\r
513                ;; what right again\r
514                (if (eq what 'reorder)\r
515                    (setq reorder-once\r
516                          (intern\r
517                           (org-icompleting-read \r
518                            "Please choose column to reorder reftable once: " \r
519                            (mapcar 'symbol-name '(ref count last-accessed))\r
520                            nil t))))\r
521                \r
522                ;; offer extended selection of commands, if asked for\r
523                (if (eq what 'all)\r
524                    (setq commands (copy-list org-reftable-commands)))\r
525 \r
526                ;; maybe ask initial question again\r
527                (memq what '(reorder all)))))\r
528 \r
529 \r
530     ;;\r
531     ;; Get search, if required\r
532     ;;\r
533 \r
534     ;; These actions need a search string:\r
535     (when (memq what '(goto occur head update))\r
536 \r
537       ;; Maybe we've got a search string from the arguments\r
538       (unless search\r
539         (let (search-from-table\r
540               search-from-cursor)\r
541           \r
542           ;; Search string can come from several sources:\r
543           ;; From ref column of table\r
544           (when within-node\r
545             (save-excursion (setq search-from-table (org-table-get-field (cdr (assoc 'ref columns)))))\r
546             (if (string= search-from-table "") (setq search-from-table nil)))      \r
547           ;; From string below cursor\r
548           (when (and (not within-node)\r
549                      below-cursor\r
550                      (string-match (concat "\\(" ref-regex "\\)") \r
551                                    below-cursor))\r
552             (setq search-from-cursor (match-string 1 below-cursor)))\r
553           \r
554           ;; Depending on requested action, get search from one of the sources above\r
555           (cond ((eq what 'goto)\r
556                  (setq search (or what-input search-from-cursor)))\r
557                 ((memq what '(head occur))\r
558                  (setq search (or what-input search-from-table search-from-cursor))))))\r
559 \r
560 \r
561       ;; If we still do not have a search string, ask user explicitly\r
562       (unless search\r
563         \r
564         (if what-input \r
565             (setq search what-input)\r
566           (setq search (read-from-minibuffer\r
567                         (cond ((memq what '(goto occur head))\r
568                                "Text or reference number to search for: ")\r
569                               ((eq what 'update)\r
570                                "Reference number to update: ")))))\r
571 \r
572         (if (string-match "^\\s *[0-9]*\\s *$" search)\r
573             (unless (string= search "")\r
574               (setq search (format "%s%s%s" head (org-trim search) tail)))))\r
575       \r
576       ;; Clean up search string\r
577       (if (string= search "") (setq search nil))\r
578       (if search (setq search (org-trim search)))\r
579 \r
580       (setq guarded-search \r
581             (concat (regexp-quote search)\r
582                     ;; if there is no tail in reference number, we\r
583                     ;; have to guard agains trailing digits\r
584                     (if (string= tail "") "\\($\\|[^0-9]\\)" "")))\r
585 \r
586 \r
587       ;;\r
588       ;; Do some sanity checking before really starting\r
589       ;;\r
590 \r
591       ;; Correct requested action, if nothing to search\r
592       (when (and (not search)\r
593                  (memq what '(search occur head)))\r
594         (setq what 'enter)\r
595         (setq what-adjusted t))\r
596 \r
597       ;; Check for invalid combinations of arguments; try to be helpful\r
598       (if (string-match ref-regex search)\r
599           (progn\r
600             ;; Count searches and update last access date\r
601             (if search (org-reftable-update-reference-line search columns))\r
602             (if (eq what 'occur) (setq what 'multi-occur)))\r
603         (when (memq what '(goto head))\r
604             (error "Can do '%s' only for a number (not '%s'), try 'occur' to search for text" what search))))\r
605 \r
606     \r
607     ;;\r
608     ;; Prepare\r
609     ;;\r
610 \r
611     ;; Move into table, if outside\r
612     (when (memq what '(enter new goto occur multi-occur))\r
613       ;; Save current window configuration\r
614       (when (or (not result-is-visible)\r
615                 (not org-reftable-windowconfig-before))\r
616         (setq org-reftable-windowconfig-before (current-window-configuration)))\r
617 \r
618       ;; Switch to reference table\r
619       (org-pop-to-buffer-same-window (car ref-node-buffer-and-point))\r
620       (goto-char (cdr ref-node-buffer-and-point))\r
621       (show-subtree)\r
622       (org-show-context))\r
623 \r
624 \r
625     ;;\r
626     ;; Actually do, what is requested\r
627     ;;\r
628 \r
629     (cond\r
630 \r
631 \r
632      ((eq what 'help)\r
633       \r
634       (let ((help-what\r
635              ;; which sort of help ?\r
636              (intern\r
637               (concat \r
638                "help-"\r
639                (org-icompleting-read \r
640                 "Help on: "\r
641                 (mapcar 'symbol-name '(commands usage setup)) \r
642                 nil t)))))\r
643 \r
644         ;; help is taken from docstring of functions or variables\r
645         (cond ((eq help-what 'help-commands)\r
646                (org-reftable-show-help 'org-reftable-commands))\r
647               ((eq help-what 'help-usage)\r
648                (org-reftable-show-help 'org-reftable))\r
649               ((eq help-what 'help-setup)\r
650                (org-reftable-show-help 'org-reftable-id)))))\r
651 \r
652 \r
653      ((eq what 'multi-occur) \r
654       \r
655       ;; Conveniently position cursor on number to search for\r
656       (org-reftable-goto-top)\r
657       (let (found (initial (point)))\r
658         (while (and (not found)\r
659                     (forward-line)\r
660                     (org-at-table-p))\r
661           (save-excursion \r
662             (setq found (string= search \r
663                                  (org-trim (org-table-get-field (cdr (assoc 'ref columns))))))))\r
664         (if found \r
665             (org-table-goto-column (cdr (assoc 'ref columns)))\r
666           (goto-char initial)))\r
667 \r
668       ;; Construct list of all org-buffers\r
669       (let (buff org-buffers)\r
670         (dolist (buff (buffer-list))\r
671           (set-buffer buff)\r
672           (if (string= major-mode "org-mode")\r
673               (setq org-buffers (cons buff org-buffers))))\r
674 \r
675         ;; Do multi-occur\r
676         (multi-occur org-buffers guarded-search)\r
677         (if (get-buffer "*Occur*")\r
678             (progn \r
679               (setq message-text (format "multi-occur for '%s'" search))\r
680               (setq org-reftable-occur-buffer (get-buffer "*Occur*"))\r
681               (other-window 1)\r
682               (toggle-truncate-lines 1))\r
683           (setq message-text (format "Did not find '%s'" search)))))\r
684 \r
685 \r
686      ((eq what 'head)\r
687 \r
688       (message (format "Scanning headlines for '%s' ..." search))\r
689       (let (buffer point)\r
690         (if (catch 'found\r
691               (progn\r
692                 ;; loop over all headlines, stop on first match\r
693                 (org-map-entries \r
694                  (lambda () \r
695                    (when (looking-at (concat ".*\\b" guarded-search))\r
696                      (setq buffer (current-buffer))\r
697                      (setq point (point))\r
698                      (throw 'found t)))          \r
699                  nil 'agenda)\r
700                 nil))\r
701             (progn\r
702               (setq message-text (format "Found '%s'" search))\r
703               (org-pop-to-buffer-same-window buffer)\r
704               (goto-char point)\r
705               (org-reveal))\r
706           (setq message-text (format "Did not find '%s'" search)))))\r
707 \r
708 \r
709      ((eq what 'leave)\r
710 \r
711       (when result-is-visible\r
712 \r
713         ;; If we are within the occur-buffer, switch over to get current line\r
714         (if (and (string= (buffer-name) "*Occur*")\r
715                  (eq org-reftable-last-action 'occur))\r
716             (occur-mode-goto-occurrence))\r
717 \r
718         (let (copy-column)              \r
719           ;; Try to copy requested column\r
720           (setq copy-column (cdr (assoc \r
721                                   (if (eq org-reftable-last-action 'new)\r
722                                       'goto\r
723                                     'copy)\r
724                                   columns)))\r
725             \r
726           ;; Add to kill ring\r
727           (if (memq org-reftable-last-action '(new enter goto occur))\r
728               (setq kill-new-text \r
729                     (org-trim (org-table-get-field copy-column))))))\r
730 \r
731       ;; Restore position within buffer with reference table\r
732       (with-current-buffer (car ref-node-buffer-and-point)\r
733         (when org-reftable-marker-outside-before\r
734           (goto-char (marker-position org-reftable-marker-outside-before))\r
735           (move-marker org-reftable-marker-outside-before nil)))\r
736 \r
737       ;; Restore windowconfig\r
738       (if org-reftable-windowconfig-before \r
739           (progn  \r
740             ;; Restore initial window configuration\r
741             (set-window-configuration org-reftable-windowconfig-before)\r
742             (setq org-reftable-windowconfig-before nil)\r
743             ;; Goto initial position\r
744             (recenter)\r
745             (setq message-text "Back"))\r
746         ;; We did not have a window-configuration to restore, so we cannot\r
747         ;; pretend we have returned back\r
748         (setq message-text "Cannot leave; nowhere to go to")\r
749         (setq kill-new-text nil)))\r
750 \r
751 \r
752      ((eq what 'goto)\r
753 \r
754       ;; Go downward in table to requested reference\r
755       (let (found (initial (point)))\r
756         (org-reftable-goto-top)\r
757         (while (and (not found)\r
758                     (forward-line)\r
759                     (org-at-table-p))\r
760           (save-excursion \r
761             (setq found \r
762                   (string= search \r
763                            (org-trim (org-table-get-field (cdr (assoc 'ref columns))))))))\r
764         (if found\r
765             (progn\r
766               (setq message-text (format "Found '%s'" search))\r
767               (org-table-goto-column (cdr (assoc 'ref columns)))\r
768               (if (looking-back " ") (backward-char)))\r
769           (setq message-text (format "Did not find '%s'" search))\r
770           (goto-char initial)\r
771           (forward-line)\r
772           (setq what 'missed))))\r
773 \r
774 \r
775      ((eq what 'occur)\r
776 \r
777       ;; search for string: occur\r
778       (save-restriction\r
779         (org-narrow-to-subtree)\r
780         (occur search)\r
781         (widen)\r
782         (if (get-buffer "*Occur*")\r
783             (with-current-buffer "*Occur*"\r
784 \r
785               ;; install helpful keyboard-shortcuts within occur-buffer\r
786               (let ((keymap (make-sparse-keymap)))\r
787                 (set-keymap-parent keymap occur-mode-map)\r
788 \r
789                 (define-key keymap (kbd "RET") \r
790                   (lambda () (interactive) \r
791                     (org-reftable-occur-helper 'head)))\r
792 \r
793                 (define-key keymap (kbd "<C-return>") \r
794                   (lambda () (interactive) \r
795                     (org-reftable-occur-helper 'multi-occur)))\r
796 \r
797                 (use-local-map keymap))\r
798               (setq org-reftable-ref-regex ref-regex)\r
799 \r
800               ;; insert some help text\r
801               (other-window 1)\r
802               (toggle-truncate-lines 1)\r
803               (let ((inhibit-read-only t)) \r
804                 (insert (substitute-command-keys \r
805                          "Type RET to find heading, C-RET for multi-occur, \\[next-error-follow-minor-mode] for follow-mode.\n\n")))\r
806               (forward-line 1)\r
807               (setq message-text\r
808                     (format  "Occur for '%s'" search)))\r
809           (setq message-text\r
810                 (format "Did not find any matches for '%s'" search)))))\r
811 \r
812 \r
813      ((eq what 'new)\r
814 \r
815       ;; add a new row\r
816       (org-reftable-goto-top)\r
817       (let ((new (format "%s%d%s" head (1+ maxref) tail)))\r
818 \r
819         (org-table-insert-row)\r
820 \r
821         ;; fill special columns with standard values\r
822         (org-table-goto-column (cdr (assoc 'ref columns)))\r
823         (insert new)\r
824         (org-table-goto-column (cdr (assoc 'created columns)))\r
825         (org-insert-time-stamp nil nil t)\r
826 \r
827         ;; goto first nonempty field\r
828         (catch 'empty\r
829           (dotimes (col numcols)\r
830             (org-table-goto-column (+ col 1))\r
831             (if (string= (org-trim (org-table-get-field)) "")\r
832                 (throw 'empty t)))\r
833           ;; none found, goto first\r
834           (org-table-goto-column 1))\r
835 \r
836         (org-table-align)\r
837         (if active-region (setq kill-new-text active-region))\r
838         (setq message-text (format "Adding a new row '%s'" new))))\r
839 \r
840 \r
841      ((eq what 'enter)\r
842 \r
843       ;; simply go into table\r
844       (org-reftable-goto-top)\r
845       (show-subtree)\r
846       (recenter)\r
847       (if what-adjusted\r
848           (setq message-text "Nothing to search for; at reference table")\r
849         (setq message-text "At reference table")))\r
850 \r
851 \r
852      ((eq what 'sort)\r
853 \r
854       ;; sort lines according to contained reference\r
855       (let (begin end where)\r
856         (catch 'aborted\r
857           ;; either active region or whole buffer\r
858           (if (and transient-mark-mode\r
859                    mark-active)\r
860               ;; sort only region\r
861               (progn\r
862                 (setq begin (region-beginning))\r
863                 (setq end (region-end))\r
864                 (setq where "region"))\r
865             ;; sort whole buffer\r
866             (setq begin (point-min))\r
867             (setq end (point-max))\r
868             (setq where "whole buffer")\r
869             ;; make sure\r
870             (unless (y-or-n-p "Sort whole buffer ")\r
871               (setq message-text "Sort aborted")\r
872               (throw 'aborted nil)))\r
873           \r
874           (save-excursion\r
875             (save-restriction\r
876               (goto-char (point-min))\r
877               (narrow-to-region begin end)\r
878               (sort-subr nil 'forward-line 'end-of-line \r
879                          (lambda ()\r
880                            (if (looking-at (concat "^.*\\b" ref-regex "\\b"))\r
881                                (string-to-number (match-string 1))\r
882                              0))))\r
883             (highlight-regexp ref-regex)\r
884             (setq message-text (format "Sorted %s from character %d to %d, %d lines" \r
885                                        where begin end\r
886                                        (count-lines begin end)))))))\r
887     \r
888 \r
889      ((eq what 'update)\r
890 \r
891       ;; simply update line in reftable\r
892       (save-excursion\r
893         (beginning-of-line)\r
894         (if (org-reftable-update-reference-line search columns)\r
895             (setq message-text (format "Updated reference '%s'" search))\r
896           (setq message-text (format "Did not find reference '%s'" search)))))\r
897 \r
898 \r
899      ((memq what '(highlight unhighlight))\r
900 \r
901       (let ((where "buffer"))\r
902         (save-excursion\r
903           (save-restriction\r
904             (when (and transient-mark-mode\r
905                        mark-active)\r
906               (narrow-to-region (region-beginning) (region-end))\r
907               (setq where "region"))\r
908 \r
909             (if (eq what 'highlight)\r
910                 (progn\r
911                   (highlight-regexp ref-regex)\r
912                   (setq message-text (format "Highlighted references in %s" where)))\r
913               (unhighlight-regexp ref-regex)\r
914               (setq message-text (format "Removed highlights for references in %s" where)))))))\r
915 \r
916 \r
917      (t (error "This is a bug: Unmatched condition '%s'" what)))\r
918 \r
919 \r
920     ;; remember what we have done for next time\r
921     (setq org-reftable-last-action what)\r
922     \r
923     ;; tell, what we have done and what can be yanked\r
924     (if kill-new-text (setq kill-new-text \r
925                             (substring-no-properties kill-new-text)))\r
926     (if (string= kill-new-text "") (setq kill-new-text nil))\r
927     (let ((m (concat \r
928               message-text\r
929               (if (and message-text kill-new-text) \r
930                   " and r" \r
931                 (if kill-new-text "R" ""))\r
932               (if kill-new-text (format "eady to yank '%s'" kill-new-text) ""))))\r
933       (unless (string= m "") (message m)))\r
934     (if kill-new-text (kill-new kill-new-text))))\r
935 \r
936 \r
937 \r
938 (defun org-reftable-parse-and-adjust-table (&optional sort-column)\r
939   "Trim reference table, only used internally"\r
940 \r
941   (let ((maxref 0)\r
942         top\r
943         bottom\r
944         field\r
945         parts\r
946         numcols\r
947         columns\r
948         head\r
949         tail\r
950         ref-regex\r
951         initial-ref\r
952         initial-point)\r
953 \r
954     (setq initial-point (point))\r
955     (org-reftable-goto-top)\r
956     (setq top (point))\r
957     \r
958     (goto-char top)\r
959     \r
960     ;; count columns\r
961     (org-table-goto-column 100)\r
962     (setq numcols (- (org-table-current-column) 1))\r
963     (org-table-goto-column 1)\r
964     \r
965     ;; get contents of columns\r
966     (forward-line -2)\r
967     (unless (org-at-table-p)\r
968       (org-reftable-report-setup-error \r
969        "Reference table starts with a hline" t))\r
970     \r
971     (setq columns (org-reftable-parse-headings numcols))\r
972     \r
973     ;; Go beyond end of table\r
974     (while (org-at-table-p) (forward-line 1))\r
975     \r
976     ;; Kill all empty rows at bottom\r
977     (while (progn\r
978              (forward-line -1)\r
979              (org-table-goto-column 1)\r
980              (string= "" (org-trim (org-table-get-field (cdr (assoc 'ref columns))))))\r
981       (org-table-kill-row))\r
982     (forward-line)\r
983     (setq bottom (point))\r
984     (forward-line -1)\r
985     \r
986     ;; Retrieve any decorations around the number within ref-field of\r
987     ;; the first row\r
988     (goto-char top)\r
989     (setq field (org-trim (org-table-get-field  (cdr (assoc 'ref columns)))))\r
990     (or (numberp (string-match "^\\([^0-9]*\\)\\([0-9]+\\)\\([^0-9]*\\)$" field))\r
991         (org-reftable-report-setup-error \r
992          (format "reference column in first line of reference table '%s' does not contain a number" field) t))\r
993     \r
994     ;; These are the decorations used within the first row of the\r
995     ;; reference table\r
996     (setq head (match-string 1 field))\r
997     (setq tail (match-string 3 field))\r
998     (setq ref-regex (concat (regexp-quote head)\r
999                             "\\([0-9]+\\)" \r
1000                             (regexp-quote tail)))\r
1001 \r
1002     ;; Save initial ref\r
1003     (save-excursion\r
1004       (let (field)\r
1005         (goto-char initial-point)\r
1006         (setq field (org-table-get-field (cdr (assoc 'ref columns))))\r
1007         (if (string-match ref-regex field)\r
1008             (setq initial-ref (concat head (match-string 1 field) tail)))))\r
1009 \r
1010     ;; Go through table to find maximum number\r
1011     (let ((ref 0)\r
1012           field)\r
1013       (while (org-at-table-p) \r
1014         (setq field (org-trim (org-table-get-field (cdr (assoc 'ref columns)))))\r
1015         (if (string-match ref-regex field)\r
1016             (setq ref (string-to-number (match-string 1 field)))\r
1017           \r
1018           (unless (string= "" field)\r
1019             (org-reftable-report-setup-error \r
1020              (format "Reference field in line of reference table '%s' does not contain a number" field) t)))\r
1021         (if (> ref maxref) (setq maxref ref))\r
1022         (forward-line 1)))\r
1023     \r
1024     (setq parts (list head maxref tail numcols columns ref-regex))\r
1025     \r
1026     ;; sort table after sort-column\r
1027     (unless sort-column (setq sort-column (cdr (assoc 'sort columns))))\r
1028     (goto-char top)\r
1029     (forward-line 0)\r
1030     (save-restriction\r
1031       (narrow-to-region (point) bottom)\r
1032       (sort-subr t\r
1033                  'forward-line \r
1034                  'end-of-line \r
1035                  (lambda ()\r
1036                    (let (ref\r
1037                          (ref-field (org-table-get-field \r
1038                                      (cdr (assoc 'ref columns)))))\r
1039                      (string-match ref-regex ref-field)\r
1040                      ;; get reference with leading zeroes, so it can be\r
1041                      ;; sorted as text\r
1042                      (setq ref (format \r
1043                                 "%06d" \r
1044                                 (string-to-number \r
1045                                  (match-string 1 ref-field))))\r
1046                      \r
1047                      ;; Construct different sort-keys according to\r
1048                      ;; requested sort column; append ref as a secondary\r
1049                      ;; sort key\r
1050 \r
1051                      ;; \r
1052                      (cond ((eq sort-column 'count)\r
1053                             (concat (format \r
1054                                      "%08d" \r
1055                                      (string-to-number \r
1056                                       (org-table-get-field \r
1057                                        (cdr (assoc 'count columns))))) \r
1058                                     " " ref))\r
1059                            \r
1060                            ((eq sort-column 'last-accessed)\r
1061                             (concat (org-table-get-field \r
1062                                      (cdr (assoc 'last-accessed columns))) \r
1063                                     " " ref))\r
1064                            \r
1065                            ((eq sort-column 'ref)\r
1066                             ref)\r
1067                            \r
1068                            (t \r
1069                             (error "Bug !")))))\r
1070                  nil\r
1071                  'string<)\r
1072       )\r
1073 \r
1074     ;; align table\r
1075     (org-table-align)\r
1076     \r
1077     ;; go back to top of table\r
1078     (goto-char top)\r
1079 \r
1080     ;; Goto back to initial ref, because reformatting of table above might\r
1081     ;; have moved point\r
1082     (when initial-ref\r
1083       (while (and (org-at-table-p)\r
1084                   (not (string= initial-ref (org-trim (org-table-get-field (cdr (assoc 'ref columns)))))))\r
1085         (forward-line))\r
1086       ;; did not find ref, go back to top\r
1087       (if (not (org-at-table-p)) (goto-char top)))\r
1088 \r
1089     parts))\r
1090 \r
1091 \r
1092 \r
1093 (defun org-reftable-goto-top ()\r
1094   "Goto topmost reference line in reftable"\r
1095 \r
1096   ;; go to heading of node\r
1097   (while (not (org-at-heading-p)) (forward-line -1))\r
1098   (forward-line 1)\r
1099   ;; go to table within node, but make sure we do not get into another node\r
1100   (while (and (not (org-at-heading-p))\r
1101               (not (org-at-table-p))\r
1102               (not (eq (point) (point-max)))) \r
1103     (forward-line 1))\r
1104      \r
1105   ;; check, if there really is a table\r
1106   (unless (org-at-table-p)\r
1107     (org-reftable-report-setup-error \r
1108      "Cannot find reference table within reference node" t))\r
1109 \r
1110   ;; go to first hline\r
1111   (while (and (not (org-at-table-hline-p))\r
1112               (org-at-table-p))\r
1113     (forward-line 1))\r
1114      \r
1115   ;; and check\r
1116   (unless (org-at-table-hline-p)\r
1117     (org-reftable-report-setup-error \r
1118      "Cannot find hline within reference table" t))      \r
1119 \r
1120   (forward-line 1)\r
1121   (org-table-goto-column 1))\r
1122 \r
1123 \r
1124 \r
1125 (defun org-reftable-id-find ()\r
1126   "Find org-reftable-id"\r
1127   (let ((marker (org-id-find org-reftable-id 'marker))\r
1128         marker-and-buffer)\r
1129 \r
1130     (if marker \r
1131         (progn \r
1132           (setq marker-and-buffer (cons (marker-buffer marker) (marker-position marker)))\r
1133           (move-marker marker nil)\r
1134           marker-and-buffer)\r
1135       nil)))\r
1136 \r
1137 \r
1138 \r
1139 (defun org-reftable-parse-headings (numcols)\r
1140   "Parse headings to find special columns"\r
1141 \r
1142   (let (columns)\r
1143 \r
1144     ;; Associate names of special columns with column-numbers\r
1145     (setq columns (copy-tree '((ref . 0) (created . 0) (last-accessed . 0) \r
1146                                (count . 0) (sort . nil) (copy . nil))))\r
1147 \r
1148     ;; For each column\r
1149     (dotimes (col numcols)\r
1150       (let* (field-flags ;; raw heading, consisting of file name and maybe\r
1151                          ;; flags (seperated by ";")\r
1152              field       ;; field name only\r
1153              field-symbol ;; and as a symbol\r
1154              flags       ;; flags from field-flags\r
1155              found)\r
1156 \r
1157         ;; parse field-flags into field and flags\r
1158         (setq field-flags (org-trim (org-table-get-field (+ col 1))))\r
1159         (if (string-match "^\\([^;]*\\);\\([a-z]+\\)$" field-flags)\r
1160             (progn \r
1161               (setq field (downcase (or (match-string 1 field-flags) "")))\r
1162               ;; get flags as list of characters\r
1163               (setq flags (mapcar 'string-to-char \r
1164                                   (split-string \r
1165                                    (downcase (match-string 2 field-flags)) \r
1166                                    "" t))))\r
1167           ;; no flags\r
1168           (setq field field-flags))\r
1169 \r
1170         (unless (string= field "") (setq field-symbol (intern (downcase field))))\r
1171 \r
1172         ;; Check, that no flags appear twice\r
1173         (mapc (lambda (x)\r
1174                 (when (memq (car x) flags)\r
1175                   (if (cdr (assoc (cdr x) columns))\r
1176                       (org-reftable-report-setup-error \r
1177                        (format "More than one heading is marked with flag '%c'" (car x)) t))))\r
1178               '((?s . sort)\r
1179                 (?c . copy)))\r
1180         \r
1181         ;; Process flags\r
1182         (if (memq ?s flags)\r
1183             (setcdr (assoc 'sort columns) field-symbol))\r
1184         (if (memq ?c flags)\r
1185             (setcdr (assoc 'copy columns) (+ col 1)))\r
1186         \r
1187         ;; Store columns in alist\r
1188         (setq found (assoc field-symbol columns))\r
1189         (when found\r
1190           (if (> (cdr found) 0) \r
1191               (org-reftable-report-setup-error \r
1192                (format "'%s' appears two times as column heading" (downcase field)) t))\r
1193           (setcdr found (+ col 1)))))\r
1194 \r
1195     ;; check if all necessary informations have been specified\r
1196     (unless (> (cdr (assoc 'ref columns)) 0)\r
1197       (org-reftable-report-setup-error \r
1198        "column 'ref' has not been set" t))\r
1199 \r
1200     ;; use ref as a default sort-column\r
1201     (unless (cdr (assoc 'sort columns))\r
1202       (setcdr (assoc 'sort columns) 'ref))\r
1203     columns))\r
1204 \r
1205 \r
1206 \r
1207 (defun org-reftable-report-setup-error (text &optional switch-to-node)\r
1208   "Report error, which might be related with incomplete setup; offer help"\r
1209 \r
1210   (when switch-to-node \r
1211     (org-id-goto org-reftable-id)\r
1212     (delete-other-windows))\r
1213   \r
1214   (when (y-or-n-p (concat\r
1215                    text \r
1216                    ";\n"\r
1217                    "the correct setup is explained in the documentation of 'org-reftable-id'.\n" \r
1218                    "Do you want to read it ? "))\r
1219     (org-reftable-show-help 'org-reftable-id))\r
1220 \r
1221   (error "")\r
1222   (setq org-reftable-windowconfig-before nil)\r
1223   (move-marker org-reftable-marker-outside-before nil)\r
1224   (setq org-reftable-last-action 'leave))\r
1225 \r
1226 \r
1227 \r
1228 (defun org-reftable-show-help (function-or-variable)\r
1229   "Show help on command or function and trim help buffer displayed"\r
1230 \r
1231   (let ((isfun (functionp function-or-variable)))\r
1232     ;; bring up help-buffer for function or variable\r
1233     (if isfun\r
1234         (describe-function function-or-variable)\r
1235       (describe-variable function-or-variable))\r
1236 \r
1237     \r
1238     ;; clean up help-buffer\r
1239     (pop-to-buffer "*Help*")\r
1240     (let ((inhibit-read-only t)) \r
1241       (goto-char (point-min))\r
1242       (while (progn\r
1243                (kill-line 1)\r
1244                (not (looking-at \r
1245                      (if isfun\r
1246                          "(" \r
1247                        "Documentation:")))))\r
1248       (kill-line (if isfun 2 1))\r
1249       (goto-char (point-max))\r
1250       (kill-line -2)\r
1251       (goto-char (point-min)))))\r
1252                  \r
1253 \r
1254 \r
1255 (defun org-reftable-update-reference-line (reference columns)\r
1256   "Update access count and time of reference number"\r
1257 \r
1258   (let ((initial (point))\r
1259         found\r
1260         (ref-node-buffer-and-point (org-reftable-id-find)))\r
1261     (with-current-buffer (car ref-node-buffer-and-point)\r
1262       (goto-char (cdr ref-node-buffer-and-point))\r
1263       (org-reftable-goto-top)\r
1264       (while (and (org-at-table-p)\r
1265                   (if (string= reference (org-trim (org-table-get-field (cdr (assoc 'ref columns)))))\r
1266                       (progn (org-table-get-field (cdr (assoc 'count columns))\r
1267                                                   (number-to-string \r
1268                                                    (+ 1 (string-to-number \r
1269                                                          (org-table-get-field (cdr (assoc 'count columns)))))))\r
1270                              (org-table-goto-column (cdr (assoc 'last-accessed columns)))\r
1271                              (org-table-blank-field)\r
1272                              (org-insert-time-stamp nil t t)\r
1273                              (org-table-align)\r
1274                              (setq found t)\r
1275                              nil)\r
1276                     t))\r
1277         (forward-line))\r
1278       (goto-char initial))\r
1279     found))\r
1280 \r
1281 \r
1282 \r
1283 (defun org-reftable-occur-helper (action)\r
1284   "Internal helper function for occur in org-reftable"\r
1285   (save-excursion\r
1286     (beginning-of-line)\r
1287     (if (looking-at (concat ".*\\b\\(" org-reftable-ref-regex "\\)\\b"))\r
1288         (org-reftable action (match-string 1)))))\r
1289 \r
1290 \r
1291 (provide 'org-reftable)\r
1292 \r
1293 ;; Local Variables:\r
1294 ;; fill-column: 75\r
1295 ;; comment-column: 50\r
1296 ;; End:\r
1297 \r
1298 ;;; org-reftable.el ends here\r
1299 \r