/usr/share/emacs/site-lisp/planner-el/planner-id.el is in planner-el 3.42-5.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 | ;;; planner-id.el --- planner.el extension for global task IDs
;; Copyright (C) 2003, 2004, 2005, 2008 Free Software Foundation, Inc.
;; Author: Sacha Chua <sacha@free.net.ph>
;; URL: http://www.wjsullivan.net/PlannerMode.html
;; This file is part of Planner. It is not part of GNU Emacs.
;; Planner is free software; you can redistribute it and/or modify it
;; under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; Planner is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with Planner; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;;
;; After loading planner.el, place planner-id.el in your load path
;; and add this to your .emacs
;;
;; (require 'planner-id)
;;
;; This module modifies the behavior of planner.el, adding global task
;; IDs so that tasks can be edited and updated.
;;
;; To automatically update linked tasks whenever you save a planner
;; file, set planner-id-update-automatically to a non-nil value. This
;; does not update completed or cancelled tasks. See documentation for
;; planner-id-update-tasks-on-page to find out how to force updates.
;;
;; Planner IDs are of the form {{Identifier:Number}}
;;
;; Alternatives: If you don't mind using a function to change your
;; task descriptions, you may find M-x planner-edit-task-description
;; easier to use. Other changes (A/B/C, status) can be applied with
;; M-x planner-update-task after you edit the buffer.
;;; Contributors:
;; Oliver Krause <oik@gmx.net>: Main idea, testing.
;; Jim Ottaway provided a fix for interaction of task IDs with
;; multiple links, as well as a regexp bug.
;; Yann Hodique helped port this to Muse.
(require 'planner)
;;; Code:
(defgroup planner-id nil
"Planner ID options."
:prefix "planner-id-"
:group 'planner)
(defcustom planner-id-add-task-id-flag t
"Non-nil means add task IDs to newly-created tasks."
:type 'boolean
:group 'planner-id)
(defcustom planner-id-tracking-file "~/.planner-id"
"File that stores an alist with the current planner ids."
:type 'file
:group 'planner-id)
(defcustom planner-id-update-automatically t
"Non-nil means update linked files automatically when file is saved."
:type 'boolean
:group 'planner-id)
(defface planner-id-face
'((((class color) (background light))
(:foreground "lightgray"))
(t (:foreground "darkgray")))
"Face for planner ID links."
:group 'planner-id)
(defvar planner-id-values nil
"Alist with (key nextvalue) pairs.")
(defvar planner-id-regexp "{{\\([^:\n]+\\):\\([0-9]+\\)}}"
"Regexp matching planner IDs.")
(defun planner-id-get-id-from-string (string &optional key)
"Return the planner ID in STRING as (identifier number).
If KEY is specified, match against that."
(when (string-match
(concat "{{\\("
(or key "[^:\n]+")
"\\):\\([0-9]+\\)}}") string)
(cons (planner-match-string-no-properties 1 string)
(planner-match-string-no-properties 2 string))))
(defun planner-id-get-current-id ()
"Return the planner ID on the current line as (identifier number)."
(planner-id-get-id-from-string
(buffer-substring (planner-line-beginning-position)
(planner-line-end-position))))
(defun planner-id-format-as-string (id)
"Return the planner ID as a string of the form {{identifier:number}}."
(concat "{{" (car id) ":" (cdr id) "}}"))
;;;###autoload
(defun planner-id-find-task (task-info &optional point)
"Find task described by TASK-INFO. If POINT is non-nil, start from there.
If task is found, move point to line beginning and return non-nil.
If task is not found, leave point at POINT or the start of the buffer
and return nil."
(goto-char (or point (point-min)))
(let ((task-id
(cond
;; Task ID
((listp task-info)
(planner-id-get-id-from-string
(planner-task-description task-info)))
;; Just the ID
((numberp task-info)
(cons "Tasks" (number-to-string task-info)))
;; ID as string
((stringp task-info) (cons "Tasks" task-info))))
(found nil))
(when (re-search-forward
(concat planner-task-regexp ".*"
(regexp-quote
(if task-id
(planner-id-format-as-string task-id)
(planner-task-description task-info))))
nil t)
(goto-char (planner-line-beginning-position)))))
;;; Redeclaration
;;;###autoload
(defun planner-id-jump-to-linked-task (&optional info)
"Display the linked task page.
If INFO is specified, follow that task instead."
(interactive)
(let* ((task-info (or info (planner-current-task-info)))
(link (and task-info (planner-task-link task-info))))
(when (planner-local-page-p link)
(planner-find-file link)
(widen)
(planner-id-find-task task-info))))
(defun planner-id-save ()
"Save `planner-id-values' in `planner-id-tracking-file'."
(with-temp-file planner-id-tracking-file
(print planner-id-values (current-buffer))))
(defun planner-id-make-global-id (identifier)
"Return a globally unique ID as (IDENTIFIER number)."
(planner-id-load)
(let ((result
(cons
identifier
(number-to-string
(let ((elem (assoc identifier planner-id-values)))
(if elem
(setcdr elem (1+ (cdr elem)))
(add-to-list 'planner-id-values (cons identifier 0))
0))))))
(planner-id-save)
result))
(defun planner-id-load ()
"Read the data from `planner-id-tracking-file'."
(setq planner-id-values nil)
(with-temp-buffer
(condition-case nil
(progn
(insert-file-contents-literally planner-id-tracking-file)
(goto-char (point-min))
(setq planner-id-values (read (current-buffer))))
(error
(message "Could not read planner-id-values from %s. Setting it to nil."
planner-id-tracking-file)))))
;;;###autoload
(defun planner-id-add-task-id-maybe ()
"Add task ID if `planner-id-add-task-id-flag' is non-nil."
(when planner-id-add-task-id-flag
(planner-id-add-task-id)))
(defun planner-id-add-task-id ()
"Add a task ID for the current task if it does not have one yet.
Update the linked task page, if any."
(interactive)
(save-window-excursion
(save-excursion
(let* ((task-info (planner-current-task-info)))
(unless (or (not task-info) (planner-id-get-current-id))
(planner-edit-task-description
(concat (planner-task-description task-info) " "
(planner-id-format-as-string
(planner-id-make-global-id "Tasks")))))))))
(defun planner-id-update-tasks-on-page (&optional force)
"Update all tasks on this page.
Completed or cancelled tasks are not updated. This can be added
to `write-file-functions' (CVS Emacs) or `write-file-hooks'.
If FORCE is non-nil, completed and cancelled tasks are also updated."
(interactive (list current-prefix-arg))
;; Prevent planner-id updates from cascading
(let ((planner-id-update-automatically nil))
(with-planner-update-setup
(goto-char (point-min))
(while (re-search-forward
(concat
(if force
planner-task-regexp
planner-live-task-regexp)
".*?{{Tasks:[0-9]+}}")
nil t)
(planner-update-task)
;; Force the next line to be considered even if
;; planner-multi-update-task kicked in.
(forward-line 1))))
nil)
(defun planner-id-remove-tasks-on-page ()
"Remove the task IDs from all tasks on this page.
This function does _not_ update tasks on linked pages."
(save-excursion
(goto-char (point-min))
(while (re-search-forward
(concat planner-task-regexp
"\\(.*?\\)\\(\\s-+{{Tasks:[0-9]+}}\\)") nil t)
(replace-match "" t t nil 1))))
(defun planner-id-add-task-id-to-all ()
"Add a task ID for all the tasks on the page.
Update the linked page, if any."
(interactive)
(save-excursion
(goto-char (point-min))
(while (re-search-forward planner-task-regexp nil t)
(planner-id-add-task-id))
(font-lock-fontify-buffer)))
(defun planner-id-at-point (&optional pos)
"Return non-nil if a URL or Wiki link name is at POS."
(if (or (null pos)
(and (char-after pos)
(not (eq (char-syntax (char-after pos)) ? ))))
(let ((case-fold-search nil)
(here (or pos (point))))
(save-excursion
(goto-char here)
(skip-chars-backward " \t\n")
(or (looking-at "{{Tasks:[^}\n]+}}")
(and (search-backward "{{" (planner-line-beginning-position) t)
(looking-at "{{Tasks:[^}\n]+}}"))
(<= here (match-end 0)))))))
(eval-and-compile
(require 'compile)
(unless (boundp 'grep-command)
;; Emacs 21 CVS
(require 'grep)))
(defun planner-id-search-id (id)
"Search for all occurrences of ID."
(interactive "MID: ")
(grep (concat (or grep-command "grep") " "
(shell-quote-argument id) " "
(shell-quote-argument
(expand-file-name (planner-directory))) "/*")))
(defun planner-id-follow-id-at-point ()
"Display a list of all pages containing the ID at point."
(interactive current-prefix-arg)
(if (planner-id-at-point)
(planner-id-search-id (match-string 0))
(error "There is no valid link at point")))
;; Very ugly compatibility hack.
(defmacro planner-follow-event (event)
(if (featurep 'xemacs)
`(progn
(set-buffer (window-buffer (event-window event)))
(and (event-point event) (goto-char (event-point event))))
`(progn
(set-buffer (window-buffer (posn-window (event-start event))))
(goto-char (posn-point (event-start event))))))
(defun planner-id-follow-id-at-mouse (event)
"Display a list of all pages containing the ID at mouse.
EVENT is the mouse event."
(interactive "eN")
(save-excursion
(planner-follow-event event))
(when (planner-id-at-point)
(planner-id-search-id (match-string 0))))
;; (defvar planner-id-keymap
;; (let ((map (make-sparse-keymap)))
;; (define-key map [return] 'planner-id-follow-id-at-point)
;; (define-key map [(control ?m)] 'planner-id-follow-id-at-point)
;; (define-key map [(shift return)] 'planner-id-follow-id-at-point)
;; (if (featurep 'xemacs)
;; (progn
;; (define-key map [(button2)] 'planner-id-follow-id-at-mouse)
;; (define-key map [(shift button2)] 'planner-id-follow-id-at-mouse))
;; (define-key map [(mouse-2)] 'planner-id-follow-id-at-mouse)
;; (define-key map [(shift mouse-2)] 'planner-id-follow-id-at-mouse))
;; (unless (eq emacs-major-version 21)
;; (set-keymap-parent map planner-mode-map))
;; map)
;; "Local keymap used by planner when on an ID.")
;;;###autoload
(defun planner-id-markup (beg end &optional verbose)
"Highlight IDs as unobtrusive, clickable text from BEG to END.
VERBOSE is ignored."
(goto-char beg)
(while (re-search-forward "{{[^}\n]+}}" end t)
(planner-highlight-region
(match-beginning 0)
(match-end 0)
'planner-id 60
(list
'face 'planner-id-face
'intangible nil
;;'keymap planner-id-keymap
))))
;;;###autoload
(defun planner-id-update-tasks-maybe ()
"Update tasks depending on the value of `planner-id-update-automatically'."
(when planner-id-update-automatically
(planner-id-update-tasks-on-page)))
;;;###autoload
(defun planner-id-setup ()
"Hook into `planner-mode'."
(add-hook 'muse-colors-buffer-hook
'planner-id-markup t t)
(add-hook
(if (and (boundp 'write-file-functions)
(not (featurep 'xemacs)))
'write-file-functions
'write-file-hooks)
'planner-id-update-tasks-maybe nil t))
(add-hook 'planner-mode-hook 'planner-id-setup)
(add-hook 'planner-create-task-hook 'planner-id-add-task-id-maybe)
(setq planner-jump-to-linked-task-function 'planner-id-jump-to-linked-task)
(setq planner-find-task-function 'planner-id-find-task)
(eval-after-load "planner-publish"
'(add-to-list 'planner-publish-markup-regexps
'(1270 planner-id-regexp 0 "")))
(provide 'planner-id)
;;; planner-id.el ends here
|