diff options
| author | Carsten Dominik | 2008-03-22 05:55:11 +0000 |
|---|---|---|
| committer | Carsten Dominik | 2008-03-22 05:55:11 +0000 |
| commit | 51ec3f09e45ca399c95108b6e486535012640743 (patch) | |
| tree | a192ef9e0eafff03bdc7e331c78d5a3a304422dd /lisp/textmodes | |
| parent | ecf185525e405508d394da3ab9691f0362dc4068 (diff) | |
| download | emacs-51ec3f09e45ca399c95108b6e486535012640743.tar.gz emacs-51ec3f09e45ca399c95108b6e486535012640743.zip | |
Move org files to their own directory
Diffstat (limited to 'lisp/textmodes')
| -rw-r--r-- | lisp/textmodes/org-export-latex.el | 1539 | ||||
| -rw-r--r-- | lisp/textmodes/org-irc.el | 228 | ||||
| -rw-r--r-- | lisp/textmodes/org-mac-message.el | 79 | ||||
| -rw-r--r-- | lisp/textmodes/org-mouse.el | 1110 | ||||
| -rw-r--r-- | lisp/textmodes/org-publish.el | 661 | ||||
| -rw-r--r-- | lisp/textmodes/org.el | 28976 |
6 files changed, 0 insertions, 32593 deletions
diff --git a/lisp/textmodes/org-export-latex.el b/lisp/textmodes/org-export-latex.el deleted file mode 100644 index d8dbeed4f76..00000000000 --- a/lisp/textmodes/org-export-latex.el +++ /dev/null | |||
| @@ -1,1539 +0,0 @@ | |||
| 1 | ;;; org-export-latex.el --- LaTeX exporter for org-mode | ||
| 2 | ;; | ||
| 3 | ;; Copyright (c) 2007, 2008 Free Software Foundation, Inc. | ||
| 4 | ;; | ||
| 5 | ;; Emacs Lisp Archive Entry | ||
| 6 | ;; Filename: org-export-latex.el | ||
| 7 | ;; Version: 5.23 | ||
| 8 | ;; Author: Bastien Guerry <bzg AT altern DOT org> | ||
| 9 | ;; Maintainer: Bastien Guerry <bzg AT altern DOT org> | ||
| 10 | ;; Keywords: org, wp, tex | ||
| 11 | ;; Description: Converts an org-mode buffer into LaTeX | ||
| 12 | ;; URL: http://www.cognition.ens.fr/~guerry/u/org-export-latex.el | ||
| 13 | ;; | ||
| 14 | ;; This file is part of GNU Emacs. | ||
| 15 | ;; | ||
| 16 | ;; GNU Emacs is free software; you can redistribute it and/or modify it | ||
| 17 | ;; under the terms of the GNU General Public License as published by the | ||
| 18 | ;; Free Software Foundation; either version 3, or (at your option) any | ||
| 19 | ;; later version. | ||
| 20 | ;; | ||
| 21 | ;; GNU Emacs is distributed in the hope that it will be useful, but | ||
| 22 | ;; WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 23 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 24 | ;; General Public License for more details. | ||
| 25 | ;; | ||
| 26 | ;; You should have received a copy of the GNU General Public License | ||
| 27 | ;; along with GNU Emacs; see the file COPYING. If not, write to the Free | ||
| 28 | ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | ||
| 29 | ;; MA 02110-1301, USA. | ||
| 30 | ;; | ||
| 31 | ;;; Commentary: | ||
| 32 | ;; | ||
| 33 | ;; This library implements a LaTeX exporter for org-mode. | ||
| 34 | ;; | ||
| 35 | ;; Put this file into your load-path and the following into your ~/.emacs: | ||
| 36 | ;; (require 'org-export-latex) | ||
| 37 | ;; | ||
| 38 | ;; The interactive functions are similar to those of the HTML exporter: | ||
| 39 | ;; | ||
| 40 | ;; M-x `org-export-as-latex' | ||
| 41 | ;; M-x `org-export-as-latex-batch' | ||
| 42 | ;; M-x `org-export-as-latex-to-buffer' | ||
| 43 | ;; M-x `org-export-region-as-latex' | ||
| 44 | ;; M-x `org-replace-region-by-latex' | ||
| 45 | ;; | ||
| 46 | ;;; Code: | ||
| 47 | |||
| 48 | (eval-when-compile | ||
| 49 | (require 'cl)) | ||
| 50 | |||
| 51 | (require 'footnote) | ||
| 52 | (require 'org) | ||
| 53 | |||
| 54 | ;;; Variables: | ||
| 55 | (defvar org-export-latex-class nil) | ||
| 56 | (defvar org-export-latex-header nil) | ||
| 57 | (defvar org-export-latex-append-header nil) | ||
| 58 | (defvar org-export-latex-options-plist nil) | ||
| 59 | (defvar org-export-latex-todo-keywords-1 nil) | ||
| 60 | (defvar org-export-latex-all-targets-re nil) | ||
| 61 | (defvar org-export-latex-add-level 0) | ||
| 62 | (defvar org-export-latex-sectioning "") | ||
| 63 | (defvar org-export-latex-sectioning-depth 0) | ||
| 64 | (defvar org-export-latex-list-beginning-re | ||
| 65 | "^\\([ \t]*\\)\\([-+*]\\|[0-9]+[.)]\\) +?") | ||
| 66 | |||
| 67 | (defvar org-export-latex-special-string-regexps | ||
| 68 | '(org-ts-regexp | ||
| 69 | org-scheduled-string | ||
| 70 | org-deadline-string | ||
| 71 | org-clock-string) | ||
| 72 | "A list of regexps to convert as special keywords.") | ||
| 73 | |||
| 74 | (defvar latexp) ; dynamically scoped from org.el | ||
| 75 | (defvar re-quote) ; dynamically scoped from org.el | ||
| 76 | (defvar commentsp) ; dynamically scoped from org.el | ||
| 77 | |||
| 78 | ;;; User variables: | ||
| 79 | |||
| 80 | (defcustom org-export-latex-default-class "article" | ||
| 81 | "The default LaTeX class." | ||
| 82 | :group 'org-export-latex | ||
| 83 | :type '(string :tag "LaTeX class")) | ||
| 84 | |||
| 85 | (defcustom org-export-latex-classes | ||
| 86 | '(("article" | ||
| 87 | "\\documentclass[11pt,a4paper]{article} | ||
| 88 | \\usepackage[utf8]{inputenc} | ||
| 89 | \\usepackage[T1]{fontenc} | ||
| 90 | \\usepackage{hyperref}" | ||
| 91 | ("\\section{%s}" . "\\section*{%s}") | ||
| 92 | ("\\subsection{%s}" . "\\subsection*{%s}") | ||
| 93 | ("\\subsubsection{%s}" . "\\subsubsection*{%s}") | ||
| 94 | ("\\paragraph{%s}" . "\\paragraph*{%s}") | ||
| 95 | ("\\subparagraph{%s}" . "\\subparagraph*{%s}")) | ||
| 96 | ("report" | ||
| 97 | "\\documentclass[11pt,a4paper]{report} | ||
| 98 | \\usepackage[utf8]{inputenc} | ||
| 99 | \\usepackage[T1]{fontenc} | ||
| 100 | \\usepackage{hyperref}" | ||
| 101 | ("\\part{%s}" . "\\part*{%s}") | ||
| 102 | ("\\chapter{%s}" . "\\chapter*{%s}") | ||
| 103 | ("\\section{%s}" . "\\section*{%s}") | ||
| 104 | ("\\subsection{%s}" . "\\subsection*{%s}") | ||
| 105 | ("\\subsubsection{%s}" . "\\subsubsection*{%s}")) | ||
| 106 | ("book" | ||
| 107 | "\\documentclass[11pt,a4paper]{book} | ||
| 108 | \\usepackage[utf8]{inputenc} | ||
| 109 | \\usepackage[T1]{fontenc} | ||
| 110 | \\usepackage{hyperref}" | ||
| 111 | ("\\part{%s}" . "\\part*{%s}") | ||
| 112 | ("\\chapter{%s}" . "\\chapter*{%s}") | ||
| 113 | ("\\section{%s}" . "\\section*{%s}") | ||
| 114 | ("\\subsection{%s}" . "\\subsection*{%s}") | ||
| 115 | ("\\subsubsection{%s}" . "\\subsubsection*{%s}"))) | ||
| 116 | "Alist of LaTeX classes and associated header and structure. | ||
| 117 | If #+LaTeX_CLASS is set in the buffer, use its value and the | ||
| 118 | associated information. Here is the structure of each cell: | ||
| 119 | |||
| 120 | \(class-name | ||
| 121 | header-string | ||
| 122 | (unnumbered-section numbered-section\) | ||
| 123 | ...\) | ||
| 124 | |||
| 125 | A %s formatter is mandatory in each section string and will be | ||
| 126 | replaced by the title of the section." | ||
| 127 | :group 'org-export-latex | ||
| 128 | :type '(repeat | ||
| 129 | (list (string :tag "LaTeX class") | ||
| 130 | (string :tag "LaTeX header") | ||
| 131 | (cons :tag "Level 1" | ||
| 132 | (string :tag "Numbered") | ||
| 133 | (string :tag "Unnumbered")) | ||
| 134 | (cons :tag "Level 2" | ||
| 135 | (string :tag "Numbered") | ||
| 136 | (string :tag "Unnumbered")) | ||
| 137 | (cons :tag "Level 3" | ||
| 138 | (string :tag "Numbered") | ||
| 139 | (string :tag "Unnumbered")) | ||
| 140 | (cons :tag "Level 4" | ||
| 141 | (string :tag "Numbered") | ||
| 142 | (string :tag "Unnumbered")) | ||
| 143 | (cons :tag "Level 5" | ||
| 144 | (string :tag "Numbered") | ||
| 145 | (string :tag "Unnumbered"))))) | ||
| 146 | |||
| 147 | (defcustom org-export-latex-emphasis-alist | ||
| 148 | '(("*" "\\textbf{%s}" nil) | ||
| 149 | ("/" "\\emph{%s}" nil) | ||
| 150 | ("_" "\\underline{%s}" nil) | ||
| 151 | ("+" "\\texttt{%s}" nil) | ||
| 152 | ("=" "\\texttt{%s}" nil) | ||
| 153 | ("~" "\\texttt{%s}" t)) | ||
| 154 | "Alist of LaTeX expressions to convert emphasis fontifiers. | ||
| 155 | Each element of the list is a list of three elements. | ||
| 156 | The first element is the character used as a marker for fontification. | ||
| 157 | The second element is a formatting string to wrap fontified text with. | ||
| 158 | The third element decides whether to protect converted text from other | ||
| 159 | conversions." | ||
| 160 | :group 'org-export-latex | ||
| 161 | :type 'alist) | ||
| 162 | |||
| 163 | (defcustom org-export-latex-title-command "\\maketitle" | ||
| 164 | "The command used to insert the title just after \\begin{document}. | ||
| 165 | If this string contains the formatting specification \"%s\" then | ||
| 166 | it will be used as a formatting string, passing the title as an | ||
| 167 | argument." | ||
| 168 | :group 'org-export-latex | ||
| 169 | :type 'string) | ||
| 170 | |||
| 171 | (defcustom org-export-latex-date-format | ||
| 172 | "%d %B %Y" | ||
| 173 | "Format string for \\date{...}." | ||
| 174 | :group 'org-export-latex | ||
| 175 | :type 'string) | ||
| 176 | |||
| 177 | (defcustom org-export-latex-tables-verbatim nil | ||
| 178 | "When non-nil, export tables as verbatim." | ||
| 179 | :group 'org-export-latex | ||
| 180 | :type 'boolean) | ||
| 181 | |||
| 182 | (defcustom org-export-latex-tables-column-borders nil | ||
| 183 | "When non-nil, group of columns are surrounded with borders, | ||
| 184 | XSeven if these borders are the outside borders of the table." | ||
| 185 | :group 'org-export-latex | ||
| 186 | :type 'boolean) | ||
| 187 | |||
| 188 | (defcustom org-export-latex-packages-alist nil | ||
| 189 | "Alist of packages to be inserted in the header. | ||
| 190 | Each cell is of the forma \( \"option\" . \"package\" \)." | ||
| 191 | :group 'org-export-latex | ||
| 192 | :type 'alist) | ||
| 193 | |||
| 194 | (defcustom org-export-latex-low-levels 'description | ||
| 195 | "How to convert sections below the current level of sectioning, | ||
| 196 | as specified by `org-export-headline-levels' or the value of \"H:\" | ||
| 197 | in Org's #+OPTION line. | ||
| 198 | |||
| 199 | This can be either nil (skip the sections), 'description (convert | ||
| 200 | the sections as descriptive lists) or a string to be used instead | ||
| 201 | of \\section{%s}. In this latter case, the %s stands here for the | ||
| 202 | inserted headline and is mandatory." | ||
| 203 | :group 'org-export-latex | ||
| 204 | :type '(choice (const :tag "Ignore" nil) | ||
| 205 | (symbol :tag "Convert as descriptive list" description) | ||
| 206 | (string :tag "Use a section string" :value "\\subparagraph{%s}"))) | ||
| 207 | |||
| 208 | (defcustom org-export-latex-remove-from-headlines | ||
| 209 | '(:todo t :priority t :tags t) | ||
| 210 | "A plist of keywords to remove from headlines. | ||
| 211 | Non-nil means remove this keyword type from the headline. | ||
| 212 | |||
| 213 | Don't remove the keys, just change their values." | ||
| 214 | :type 'plist | ||
| 215 | :group 'org-export-latex) | ||
| 216 | |||
| 217 | (defcustom org-export-latex-image-default-option "width=10em" | ||
| 218 | "Default option for images." | ||
| 219 | :group 'org-export-latex | ||
| 220 | :type 'string) | ||
| 221 | |||
| 222 | (defcustom org-export-latex-coding-system nil | ||
| 223 | "Coding system for the exported LaTex file." | ||
| 224 | :group 'org-export-latex | ||
| 225 | :type 'coding-system) | ||
| 226 | |||
| 227 | (defcustom org-list-radio-list-templates | ||
| 228 | '((latex-mode "% BEGIN RECEIVE ORGLST %n | ||
| 229 | % END RECEIVE ORGLST %n | ||
| 230 | \\begin{comment} | ||
| 231 | #+ORGLST: SEND %n org-list-to-latex | ||
| 232 | | | | | ||
| 233 | \\end{comment}\n") | ||
| 234 | (texinfo-mode "@c BEGIN RECEIVE ORGLST %n | ||
| 235 | @c END RECEIVE ORGLST %n | ||
| 236 | @ignore | ||
| 237 | #+ORGLST: SEND %n org-list-to-texinfo | ||
| 238 | | | | | ||
| 239 | @end ignore\n") | ||
| 240 | (html-mode "<!-- BEGIN RECEIVE ORGLST %n --> | ||
| 241 | <!-- END RECEIVE ORGLST %n --> | ||
| 242 | <!-- | ||
| 243 | #+ORGLST: SEND %n org-list-to-html | ||
| 244 | | | | | ||
| 245 | -->\n")) | ||
| 246 | "Templates for radio lists in different major modes. | ||
| 247 | All occurrences of %n in a template will be replaced with the name of the | ||
| 248 | list, obtained by prompting the user." | ||
| 249 | :group 'org-plain-lists | ||
| 250 | :type '(repeat | ||
| 251 | (list (symbol :tag "Major mode") | ||
| 252 | (string :tag "Format")))) | ||
| 253 | |||
| 254 | ;;; Autoload functions: | ||
| 255 | |||
| 256 | ;;;###autoload | ||
| 257 | (defun org-export-as-latex-batch () | ||
| 258 | "Call `org-export-as-latex', may be used in batch processing as | ||
| 259 | emacs --batch | ||
| 260 | --load=$HOME/lib/emacs/org.el | ||
| 261 | --eval \"(setq org-export-headline-levels 2)\" | ||
| 262 | --visit=MyFile --funcall org-export-as-latex-batch" | ||
| 263 | (org-export-as-latex org-export-headline-levels 'hidden)) | ||
| 264 | |||
| 265 | ;;;###autoload | ||
| 266 | (defun org-export-as-latex-to-buffer (arg) | ||
| 267 | "Call `org-exort-as-latex` with output to a temporary buffer. | ||
| 268 | No file is created. The prefix ARG is passed through to `org-export-as-latex'." | ||
| 269 | (interactive "P") | ||
| 270 | (org-export-as-latex arg nil nil "*Org LaTeX Export*") | ||
| 271 | (switch-to-buffer-other-window "*Org LaTeX Export*")) | ||
| 272 | |||
| 273 | ;;;###autoload | ||
| 274 | (defun org-replace-region-by-latex (beg end) | ||
| 275 | "Replace the region from BEG to END with its LaTeX export. | ||
| 276 | It assumes the region has `org-mode' syntax, and then convert it to | ||
| 277 | LaTeX. This can be used in any buffer. For example, you could | ||
| 278 | write an itemized list in `org-mode' syntax in an LaTeX buffer and | ||
| 279 | then use this command to convert it." | ||
| 280 | (interactive "r") | ||
| 281 | (let (reg latex buf) | ||
| 282 | (save-window-excursion | ||
| 283 | (if (org-mode-p) | ||
| 284 | (setq latex (org-export-region-as-latex | ||
| 285 | beg end t 'string)) | ||
| 286 | (setq reg (buffer-substring beg end) | ||
| 287 | buf (get-buffer-create "*Org tmp*")) | ||
| 288 | (save-excursion | ||
| 289 | (set-buffer buf) | ||
| 290 | (erase-buffer) | ||
| 291 | (insert reg) | ||
| 292 | (org-mode) | ||
| 293 | (setq latex (org-export-region-as-latex | ||
| 294 | (point-min) (point-max) t 'string))) | ||
| 295 | (kill-buffer buf))) | ||
| 296 | (delete-region beg end) | ||
| 297 | (insert latex))) | ||
| 298 | |||
| 299 | ;;;###autoload | ||
| 300 | (defun org-export-region-as-latex (beg end &optional body-only buffer) | ||
| 301 | "Convert region from BEG to END in `org-mode' buffer to LaTeX. | ||
| 302 | If prefix arg BODY-ONLY is set, omit file header, footer, and table of | ||
| 303 | contents, and only produce the region of converted text, useful for | ||
| 304 | cut-and-paste operations. | ||
| 305 | If BUFFER is a buffer or a string, use/create that buffer as a target | ||
| 306 | of the converted LaTeX. If BUFFER is the symbol `string', return the | ||
| 307 | produced LaTeX as a string and leave not buffer behind. For example, | ||
| 308 | a Lisp program could call this function in the following way: | ||
| 309 | |||
| 310 | (setq latex (org-export-region-as-latex beg end t 'string)) | ||
| 311 | |||
| 312 | When called interactively, the output buffer is selected, and shown | ||
| 313 | in a window. A non-interactive call will only retunr the buffer." | ||
| 314 | (interactive "r\nP") | ||
| 315 | (when (interactive-p) | ||
| 316 | (setq buffer "*Org LaTeX Export*")) | ||
| 317 | (let ((transient-mark-mode t) (zmacs-regions t) | ||
| 318 | rtn) | ||
| 319 | (goto-char end) | ||
| 320 | (set-mark (point)) ;; to activate the region | ||
| 321 | (goto-char beg) | ||
| 322 | (setq rtn (org-export-as-latex | ||
| 323 | nil nil nil | ||
| 324 | buffer body-only)) | ||
| 325 | (if (fboundp 'deactivate-mark) (deactivate-mark)) | ||
| 326 | (if (and (interactive-p) (bufferp rtn)) | ||
| 327 | (switch-to-buffer-other-window rtn) | ||
| 328 | rtn))) | ||
| 329 | |||
| 330 | ;;;###autoload | ||
| 331 | (defun org-export-as-latex (arg &optional hidden ext-plist | ||
| 332 | to-buffer body-only pub-dir) | ||
| 333 | "Export current buffer to a LaTeX file. | ||
| 334 | If there is an active region, export only the region. The prefix | ||
| 335 | ARG specifies how many levels of the outline should become | ||
| 336 | headlines. The default is 3. Lower levels will be exported | ||
| 337 | depending on `org-export-latex-low-levels'. The default is to | ||
| 338 | convert them as description lists. When HIDDEN is non-nil, don't | ||
| 339 | display the LaTeX buffer. EXT-PLIST is a property list with | ||
| 340 | external parameters overriding org-mode's default settings, but | ||
| 341 | still inferior to file-local settings. When TO-BUFFER is | ||
| 342 | non-nil, create a buffer with that name and export to that | ||
| 343 | buffer. If TO-BUFFER is the symbol `string', don't leave any | ||
| 344 | buffer behind but just return the resulting LaTeX as a string. | ||
| 345 | When BODY-ONLY is set, don't produce the file header and footer, | ||
| 346 | simply return the content of \begin{document}...\end{document}, | ||
| 347 | without even the \begin{document} and \end{document} commands. | ||
| 348 | when PUB-DIR is set, use this as the publishing directory." | ||
| 349 | (interactive "P") | ||
| 350 | ;; Make sure we have a file name when we need it. | ||
| 351 | (when (and (not (or to-buffer body-only)) | ||
| 352 | (not buffer-file-name)) | ||
| 353 | (if (buffer-base-buffer) | ||
| 354 | (org-set-local 'buffer-file-name | ||
| 355 | (with-current-buffer (buffer-base-buffer) | ||
| 356 | buffer-file-name)) | ||
| 357 | (error "Need a file name to be able to export"))) | ||
| 358 | |||
| 359 | (message "Exporting to LaTeX...") | ||
| 360 | (org-update-radio-target-regexp) | ||
| 361 | (org-export-latex-set-initial-vars ext-plist arg) | ||
| 362 | (let* ((wcf (current-window-configuration)) | ||
| 363 | (opt-plist org-export-latex-options-plist) | ||
| 364 | (region-p (org-region-active-p)) | ||
| 365 | (subtree-p | ||
| 366 | (when region-p | ||
| 367 | (save-excursion | ||
| 368 | (goto-char (region-beginning)) | ||
| 369 | (and (org-at-heading-p) | ||
| 370 | (>= (org-end-of-subtree t t) (region-end)))))) | ||
| 371 | (title (or (and subtree-p (org-export-get-title-from-subtree)) | ||
| 372 | (plist-get opt-plist :title) | ||
| 373 | (and (not | ||
| 374 | (plist-get opt-plist :skip-before-1st-heading)) | ||
| 375 | (org-export-grab-title-from-buffer)) | ||
| 376 | (file-name-sans-extension | ||
| 377 | (file-name-nondirectory buffer-file-name)))) | ||
| 378 | (filename (concat (file-name-as-directory | ||
| 379 | (or pub-dir | ||
| 380 | (org-export-directory :LaTeX ext-plist))) | ||
| 381 | (file-name-sans-extension | ||
| 382 | (file-name-nondirectory ;sans-extension | ||
| 383 | buffer-file-name)) ".tex")) | ||
| 384 | (filename (if (equal (file-truename filename) | ||
| 385 | (file-truename buffer-file-name)) | ||
| 386 | (concat filename ".tex") | ||
| 387 | filename)) | ||
| 388 | (buffer (if to-buffer | ||
| 389 | (cond | ||
| 390 | ((eq to-buffer 'string) (get-buffer-create | ||
| 391 | "*Org LaTeX Export*")) | ||
| 392 | (t (get-buffer-create to-buffer))) | ||
| 393 | (find-file-noselect filename))) | ||
| 394 | (odd org-odd-levels-only) | ||
| 395 | (header (org-export-latex-make-header title opt-plist)) | ||
| 396 | (skip (cond (subtree-p nil) | ||
| 397 | (region-p t) | ||
| 398 | ;; never skip first lines when exporting a subtree | ||
| 399 | (t (plist-get opt-plist :skip-before-1st-heading)))) | ||
| 400 | (text (plist-get opt-plist :text)) | ||
| 401 | (first-lines (if skip "" (org-export-latex-first-lines))) | ||
| 402 | (coding-system (and (boundp 'buffer-file-coding-system) | ||
| 403 | buffer-file-coding-system)) | ||
| 404 | (coding-system-for-write (or org-export-latex-coding-system | ||
| 405 | coding-system)) | ||
| 406 | (save-buffer-coding-system (or org-export-latex-coding-system | ||
| 407 | coding-system)) | ||
| 408 | (region (buffer-substring | ||
| 409 | (if region-p (region-beginning) (point-min)) | ||
| 410 | (if region-p (region-end) (point-max)))) | ||
| 411 | (string-for-export | ||
| 412 | (org-cleaned-string-for-export | ||
| 413 | region :emph-multiline t | ||
| 414 | :for-LaTeX t | ||
| 415 | :comments nil | ||
| 416 | :add-text (if (eq to-buffer 'string) nil text) | ||
| 417 | :skip-before-1st-heading skip | ||
| 418 | :LaTeX-fragments nil))) | ||
| 419 | |||
| 420 | (set-buffer buffer) | ||
| 421 | (erase-buffer) | ||
| 422 | |||
| 423 | (and (fboundp 'set-buffer-file-coding-system) | ||
| 424 | (set-buffer-file-coding-system coding-system-for-write)) | ||
| 425 | |||
| 426 | ;; insert the header and initial document commands | ||
| 427 | (unless (or (eq to-buffer 'string) body-only) | ||
| 428 | (insert header)) | ||
| 429 | |||
| 430 | ;; insert text found in #+TEXT | ||
| 431 | (when (and text (not (eq to-buffer 'string))) | ||
| 432 | (insert (org-export-latex-content | ||
| 433 | text '(lists tables fixed-width keywords)) | ||
| 434 | "\n\n")) | ||
| 435 | |||
| 436 | ;; insert lines before the first headline | ||
| 437 | (unless (or skip (eq to-buffer 'string)) | ||
| 438 | (insert first-lines)) | ||
| 439 | |||
| 440 | ;; handle the case where the region does not begin with a section | ||
| 441 | (when region-p | ||
| 442 | (insert (with-temp-buffer | ||
| 443 | (insert string-for-export) | ||
| 444 | (org-export-latex-first-lines)))) | ||
| 445 | |||
| 446 | ;; export the content of headlines | ||
| 447 | (org-export-latex-global | ||
| 448 | (with-temp-buffer | ||
| 449 | (insert string-for-export) | ||
| 450 | (goto-char (point-min)) | ||
| 451 | (when (re-search-forward "^\\(\\*+\\) " nil t) | ||
| 452 | (let* ((asters (length (match-string 1))) | ||
| 453 | (level (if odd (- asters 2) (- asters 1)))) | ||
| 454 | (setq org-export-latex-add-level | ||
| 455 | (if odd (1- (/ (1+ asters) 2)) (1- asters))) | ||
| 456 | (org-export-latex-parse-global level odd))))) | ||
| 457 | |||
| 458 | ;; finalization | ||
| 459 | (unless body-only (insert "\n\\end{document}")) | ||
| 460 | (or to-buffer (save-buffer)) | ||
| 461 | (goto-char (point-min)) | ||
| 462 | (message "Exporting to LaTeX...done") | ||
| 463 | (prog1 | ||
| 464 | (if (eq to-buffer 'string) | ||
| 465 | (prog1 (buffer-substring (point-min) (point-max)) | ||
| 466 | (kill-buffer (current-buffer))) | ||
| 467 | (current-buffer)) | ||
| 468 | (set-window-configuration wcf)))) | ||
| 469 | |||
| 470 | ;;; Parsing functions: | ||
| 471 | |||
| 472 | (defun org-export-latex-parse-global (level odd) | ||
| 473 | "Parse the current buffer recursively, starting at LEVEL. | ||
| 474 | If ODD is non-nil, assume the buffer only contains odd sections. | ||
| 475 | Return a list reflecting the document structure." | ||
| 476 | (save-excursion | ||
| 477 | (goto-char (point-min)) | ||
| 478 | (let* ((cnt 0) output | ||
| 479 | (depth org-export-latex-sectioning-depth)) | ||
| 480 | (while (re-search-forward | ||
| 481 | (concat "^\\(\\(?:\\*\\)\\{" | ||
| 482 | (number-to-string (+ (if odd 2 1) level)) | ||
| 483 | "\\}\\) \\(.*\\)$") | ||
| 484 | ;; make sure that there is no upper heading | ||
| 485 | (when (> level 0) | ||
| 486 | (save-excursion | ||
| 487 | (save-match-data | ||
| 488 | (re-search-forward | ||
| 489 | (concat "^\\(\\(?:\\*\\)\\{" | ||
| 490 | (number-to-string level) | ||
| 491 | "\\}\\) \\(.*\\)$") nil t)))) t) | ||
| 492 | (setq cnt (1+ cnt)) | ||
| 493 | (let* ((pos (match-beginning 0)) | ||
| 494 | (heading (match-string 2)) | ||
| 495 | (nlevel (if odd (/ (+ 3 level) 2) (1+ level)))) | ||
| 496 | (save-excursion | ||
| 497 | (narrow-to-region | ||
| 498 | (point) | ||
| 499 | (save-match-data | ||
| 500 | (if (re-search-forward | ||
| 501 | (concat "^\\(\\(?:\\*\\)\\{" | ||
| 502 | (number-to-string (+ (if odd 2 1) level)) | ||
| 503 | "\\}\\) \\(.*\\)$") nil t) | ||
| 504 | (match-beginning 0) | ||
| 505 | (point-max)))) | ||
| 506 | (goto-char (point-min)) | ||
| 507 | (setq output | ||
| 508 | (append output | ||
| 509 | (list | ||
| 510 | (list | ||
| 511 | `(pos . ,pos) | ||
| 512 | `(level . ,nlevel) | ||
| 513 | `(occur . ,cnt) | ||
| 514 | `(heading . ,heading) | ||
| 515 | `(content . ,(org-export-latex-parse-content)) | ||
| 516 | `(subcontent . ,(org-export-latex-parse-subcontent | ||
| 517 | level odd))))))) | ||
| 518 | (widen))) | ||
| 519 | (list output)))) | ||
| 520 | |||
| 521 | (defun org-export-latex-parse-content () | ||
| 522 | "Extract the content of a section." | ||
| 523 | (let ((beg (point)) | ||
| 524 | (end (if (re-search-forward "^\\(\\*\\)+ .*$" nil t) | ||
| 525 | (progn (beginning-of-line) (point)) | ||
| 526 | (point-max)))) | ||
| 527 | (buffer-substring beg end))) | ||
| 528 | |||
| 529 | (defun org-export-latex-parse-subcontent (level odd) | ||
| 530 | "Extract the subcontent of a section at LEVEL. | ||
| 531 | If ODD Is non-nil, assume subcontent only contains odd sections." | ||
| 532 | (if (not (re-search-forward | ||
| 533 | (concat "^\\(\\(?:\\*\\)\\{" | ||
| 534 | (number-to-string (+ (if odd 4 2) level)) | ||
| 535 | "\\}\\) \\(.*\\)$") | ||
| 536 | nil t)) | ||
| 537 | nil ; subcontent is nil | ||
| 538 | (org-export-latex-parse-global (+ (if odd 2 1) level) odd))) | ||
| 539 | |||
| 540 | ;;; Rendering functions: | ||
| 541 | (defun org-export-latex-global (content) | ||
| 542 | "Export CONTENT to LaTeX. | ||
| 543 | CONTENT is an element of the list produced by | ||
| 544 | `org-export-latex-parse-global'." | ||
| 545 | (if (eq (car content) 'subcontent) | ||
| 546 | (mapc 'org-export-latex-sub (cdr content)) | ||
| 547 | (org-export-latex-sub (car content)))) | ||
| 548 | |||
| 549 | (defun org-export-latex-sub (subcontent) | ||
| 550 | "Export the list SUBCONTENT to LaTeX. | ||
| 551 | SUBCONTENT is an alist containing information about the headline | ||
| 552 | and its content." | ||
| 553 | (let ((num (plist-get org-export-latex-options-plist :section-numbers))) | ||
| 554 | (mapc (lambda(x) (org-export-latex-subcontent x num)) subcontent))) | ||
| 555 | |||
| 556 | (defun org-export-latex-subcontent (subcontent num) | ||
| 557 | "Export each cell of SUBCONTENT to LaTeX." | ||
| 558 | (let ((heading (org-export-latex-fontify-headline | ||
| 559 | (cdr (assoc 'heading subcontent)))) | ||
| 560 | (level (- (cdr (assoc 'level subcontent)) | ||
| 561 | org-export-latex-add-level)) | ||
| 562 | (occur (number-to-string (cdr (assoc 'occur subcontent)))) | ||
| 563 | (content (cdr (assoc 'content subcontent))) | ||
| 564 | (subcontent (cadr (assoc 'subcontent subcontent)))) | ||
| 565 | (cond | ||
| 566 | ;; Normal conversion | ||
| 567 | ((<= level org-export-latex-sectioning-depth) | ||
| 568 | (let ((sec (nth (1- level) org-export-latex-sectioning))) | ||
| 569 | (insert (format (if num (car sec) (cdr sec)) heading) "\n")) | ||
| 570 | (insert (org-export-latex-content content)) | ||
| 571 | (cond ((stringp subcontent) (insert subcontent)) | ||
| 572 | ((listp subcontent) (org-export-latex-sub subcontent)))) | ||
| 573 | ;; At a level under the hl option: we can drop this subsection | ||
| 574 | ((> level org-export-latex-sectioning-depth) | ||
| 575 | (cond ((eq org-export-latex-low-levels 'description) | ||
| 576 | (insert (format "\\begin{description}\n\n\\item[%s]\n\n" heading)) | ||
| 577 | (insert (org-export-latex-content content)) | ||
| 578 | (cond ((stringp subcontent) (insert subcontent)) | ||
| 579 | ((listp subcontent) (org-export-latex-sub subcontent))) | ||
| 580 | (insert "\\end{description}\n")) | ||
| 581 | ((stringp org-export-latex-low-levels) | ||
| 582 | (insert (format org-export-latex-low-levels heading) "\n") | ||
| 583 | (insert (org-export-latex-content content)) | ||
| 584 | (cond ((stringp subcontent) (insert subcontent)) | ||
| 585 | ((listp subcontent) (org-export-latex-sub subcontent))))))))) | ||
| 586 | |||
| 587 | ;;; Exporting internals: | ||
| 588 | (defun org-export-latex-set-initial-vars (ext-plist level) | ||
| 589 | "Store org local variables required for LaTeX export. | ||
| 590 | EXT-PLIST is an optional additional plist. | ||
| 591 | LEVEL indicates the default depth for export." | ||
| 592 | (setq org-export-latex-todo-keywords-1 org-todo-keywords-1 | ||
| 593 | org-export-latex-all-targets-re | ||
| 594 | (org-make-target-link-regexp (org-all-targets)) | ||
| 595 | org-export-latex-options-plist | ||
| 596 | (org-combine-plists (org-default-export-plist) ext-plist | ||
| 597 | (org-infile-export-plist)) | ||
| 598 | org-export-latex-class | ||
| 599 | (save-excursion | ||
| 600 | (goto-char (point-min)) | ||
| 601 | (if (and (re-search-forward "^#\\+LaTeX_CLASS:[ \t]*\\([a-zA-Z]+\\)" nil t) | ||
| 602 | (assoc (match-string 1) org-export-latex-classes)) | ||
| 603 | (match-string 1) | ||
| 604 | org-export-latex-default-class)) | ||
| 605 | org-export-latex-header | ||
| 606 | (cadr (assoc org-export-latex-class org-export-latex-classes)) | ||
| 607 | org-export-latex-sectioning | ||
| 608 | (cddr (assoc org-export-latex-class org-export-latex-classes)) | ||
| 609 | org-export-latex-sectioning-depth | ||
| 610 | (or level | ||
| 611 | (let ((hl-levels | ||
| 612 | (plist-get org-export-latex-options-plist :headline-levels)) | ||
| 613 | (sec-depth (length org-export-latex-sectioning))) | ||
| 614 | (if (> hl-levels sec-depth) sec-depth hl-levels))))) | ||
| 615 | |||
| 616 | (defun org-export-latex-make-header (title opt-plist) | ||
| 617 | "Make the LaTeX header and return it as a string. | ||
| 618 | TITLE is the current title from the buffer or region. | ||
| 619 | OPT-PLIST is the options plist for current buffer." | ||
| 620 | (let ((toc (plist-get opt-plist :table-of-contents)) | ||
| 621 | (author (plist-get opt-plist :author))) | ||
| 622 | (concat | ||
| 623 | (if (plist-get opt-plist :time-stamp-file) | ||
| 624 | (format-time-string "% Created %Y-%m-%d %a %H:%M\n")) | ||
| 625 | ;; insert LaTeX custom header | ||
| 626 | org-export-latex-header | ||
| 627 | "\n" | ||
| 628 | ;; insert information on LaTeX packages | ||
| 629 | (when org-export-latex-packages-alist | ||
| 630 | (mapconcat (lambda(p) | ||
| 631 | (if (equal "" (car p)) | ||
| 632 | (format "\\usepackage{%s}" (cadr p)) | ||
| 633 | (format "\\usepackage[%s]{%s}" | ||
| 634 | (car p) (cadr p)))) | ||
| 635 | org-export-latex-packages-alist "\n")) | ||
| 636 | ;; insert additional commands in the header | ||
| 637 | org-export-latex-append-header | ||
| 638 | ;; insert the title | ||
| 639 | (format | ||
| 640 | "\n\n\\title{%s}\n" | ||
| 641 | ;; convert the title | ||
| 642 | (org-export-latex-content | ||
| 643 | title '(lists tables fixed-width keywords))) | ||
| 644 | ;; insert author info | ||
| 645 | (if (plist-get opt-plist :author-info) | ||
| 646 | (format "\\author{%s}\n" | ||
| 647 | (or author user-full-name)) | ||
| 648 | (format "%%\\author{%s}\n" | ||
| 649 | (or author user-full-name))) | ||
| 650 | ;; insert the date | ||
| 651 | (format "\\date{%s}\n" | ||
| 652 | (format-time-string | ||
| 653 | (or (plist-get opt-plist :date) | ||
| 654 | org-export-latex-date-format))) | ||
| 655 | ;; beginning of the document | ||
| 656 | "\n\\begin{document}\n\n" | ||
| 657 | ;; insert the title command | ||
| 658 | (if (string-match "%s" org-export-latex-title-command) | ||
| 659 | (format org-export-latex-title-command title) | ||
| 660 | org-export-latex-title-command) | ||
| 661 | "\n\n" | ||
| 662 | ;; table of contents | ||
| 663 | (when (and org-export-with-toc | ||
| 664 | (plist-get opt-plist :section-numbers)) | ||
| 665 | (cond ((numberp toc) | ||
| 666 | (format "\\setcounter{tocdepth}{%s}\n\\tableofcontents\n\n" | ||
| 667 | (min toc (plist-get opt-plist :headline-levels)))) | ||
| 668 | (toc (format "\\setcounter{tocdepth}{%s}\n\\tableofcontents\n\n" | ||
| 669 | (plist-get opt-plist :headline-levels)))))))) | ||
| 670 | |||
| 671 | (defun org-export-latex-first-lines (&optional comments) | ||
| 672 | "Export the first lines before first headline. | ||
| 673 | COMMENTS is either nil to replace them with the empty string or a | ||
| 674 | formatting string like %%%%s if we want to comment them out." | ||
| 675 | (save-excursion | ||
| 676 | (goto-char (point-min)) | ||
| 677 | (if (org-at-heading-p) (beginning-of-line 2)) | ||
| 678 | (let* ((pt (point)) | ||
| 679 | (end (if (and (re-search-forward "^\\* " nil t) | ||
| 680 | (not (eq pt (match-beginning 0)))) | ||
| 681 | (goto-char (match-beginning 0)) | ||
| 682 | (goto-char (point-max))))) | ||
| 683 | (org-export-latex-content | ||
| 684 | (org-cleaned-string-for-export | ||
| 685 | (buffer-substring (point-min) end) | ||
| 686 | :for-LaTeX t | ||
| 687 | :emph-multiline t | ||
| 688 | :add-text nil | ||
| 689 | :comments nil | ||
| 690 | :skip-before-1st-heading nil | ||
| 691 | :LaTeX-fragments nil))))) | ||
| 692 | |||
| 693 | (defun org-export-latex-content (content &optional exclude-list) | ||
| 694 | "Convert CONTENT string to LaTeX. | ||
| 695 | Don't perform conversions that are in EXCLUDE-LIST. Recognized | ||
| 696 | conversion types are: quotation-marks, emphasis, sub-superscript, | ||
| 697 | links, keywords, lists, tables, fixed-width" | ||
| 698 | (with-temp-buffer | ||
| 699 | (insert content) | ||
| 700 | (unless (memq 'quotation-marks exclude-list) | ||
| 701 | (org-export-latex-quotation-marks)) | ||
| 702 | (unless (memq 'emphasis exclude-list) | ||
| 703 | (when (plist-get org-export-latex-options-plist :emphasize) | ||
| 704 | (org-export-latex-fontify))) | ||
| 705 | (unless (memq 'sub-superscript exclude-list) | ||
| 706 | (org-export-latex-special-chars | ||
| 707 | (plist-get org-export-latex-options-plist :sub-superscript))) | ||
| 708 | (unless (memq 'links exclude-list) | ||
| 709 | (org-export-latex-links)) | ||
| 710 | (unless (memq 'keywords exclude-list) | ||
| 711 | (org-export-latex-keywords | ||
| 712 | (plist-get org-export-latex-options-plist :timestamps))) | ||
| 713 | (unless (memq 'lists exclude-list) | ||
| 714 | (org-export-latex-lists)) | ||
| 715 | (unless (memq 'tables exclude-list) | ||
| 716 | (org-export-latex-tables | ||
| 717 | (plist-get org-export-latex-options-plist :tables))) | ||
| 718 | (unless (memq 'fixed-width exclude-list) | ||
| 719 | (org-export-latex-fixed-width | ||
| 720 | (plist-get org-export-latex-options-plist :fixed-width))) | ||
| 721 | ;; return string | ||
| 722 | (buffer-substring (point-min) (point-max)))) | ||
| 723 | |||
| 724 | (defun org-export-latex-protect-string (s) | ||
| 725 | "Prevent further conversion for string S by adding the | ||
| 726 | org-protect property." | ||
| 727 | (add-text-properties 0 (length s) '(org-protected t) s) s) | ||
| 728 | |||
| 729 | (defun org-export-latex-protect-char-in-string (char-list string) | ||
| 730 | "Add org-protected text-property to char from CHAR-LIST in STRING." | ||
| 731 | (with-temp-buffer | ||
| 732 | (save-match-data | ||
| 733 | (insert string) | ||
| 734 | (goto-char (point-min)) | ||
| 735 | (while (re-search-forward (regexp-opt char-list) nil t) | ||
| 736 | (add-text-properties (match-beginning 0) | ||
| 737 | (match-end 0) '(org-protected t))) | ||
| 738 | (buffer-string)))) | ||
| 739 | |||
| 740 | (defun org-export-latex-keywords-maybe (remove-list) | ||
| 741 | "Maybe remove keywords depending on rules in REMOVE-LIST." | ||
| 742 | (goto-char (point-min)) | ||
| 743 | (let ((re-todo (mapconcat 'identity org-export-latex-todo-keywords-1 "\\|")) | ||
| 744 | (case-fold-search nil)) | ||
| 745 | ;; convert TODO keywords | ||
| 746 | (when (re-search-forward (concat "^\\(" re-todo "\\)") nil t) | ||
| 747 | (if (plist-get remove-list :todo) | ||
| 748 | (replace-match "") | ||
| 749 | (replace-match (format "\\texttt{%s}" (match-string 1)) t t))) | ||
| 750 | ;; convert priority string | ||
| 751 | (when (re-search-forward "\\[\\\\#.\\]" nil t) | ||
| 752 | (if (plist-get remove-list :priority) | ||
| 753 | (replace-match "") | ||
| 754 | (replace-match (format "\\texttt{%s}" (match-string 0)) t t))) | ||
| 755 | ;; convert tags | ||
| 756 | (when (re-search-forward "\\(:[a-zA-Z0-9]+\\)+:" nil t) | ||
| 757 | (if (or (not org-export-with-tags) | ||
| 758 | (plist-get remove-list :tags)) | ||
| 759 | (replace-match "") | ||
| 760 | (replace-match (format "\\texttt{%s}" (match-string 0)) t t))))) | ||
| 761 | |||
| 762 | (defun org-export-latex-fontify-headline (string) | ||
| 763 | "Fontify special words in string." | ||
| 764 | (with-temp-buffer | ||
| 765 | ;; FIXME: org-inside-LaTeX-fragment-p doesn't work when the $...$ is at | ||
| 766 | ;; the beginning of the buffer - inserting "\n" is safe here though. | ||
| 767 | (insert "\n" string) | ||
| 768 | (goto-char (point-min)) | ||
| 769 | (when (plist-get org-export-latex-options-plist :emphasize) | ||
| 770 | (org-export-latex-fontify)) | ||
| 771 | (org-export-latex-special-chars | ||
| 772 | (plist-get org-export-latex-options-plist :sub-superscript)) | ||
| 773 | (org-export-latex-keywords-maybe | ||
| 774 | org-export-latex-remove-from-headlines) | ||
| 775 | (org-export-latex-links) | ||
| 776 | (org-trim (buffer-substring-no-properties (point-min) (point-max))))) | ||
| 777 | |||
| 778 | (defun org-export-latex-quotation-marks () | ||
| 779 | "Export question marks depending on language conventions." | ||
| 780 | (let* ((lang (plist-get org-export-latex-options-plist :language)) | ||
| 781 | (quote-rpl (if (equal lang "fr") | ||
| 782 | '(("\\(\\s-\\)\"" "«~") | ||
| 783 | ("\\(\\S-\\)\"" "~»") | ||
| 784 | ("\\(\\s-\\)'" "`")) | ||
| 785 | '(("\\(\\s-\\)\"" "``") | ||
| 786 | ("\\(\\S-\\)\"" "''") | ||
| 787 | ("\\(\\s-\\)'" "`"))))) | ||
| 788 | (mapc (lambda(l) (goto-char (point-min)) | ||
| 789 | (while (re-search-forward (car l) nil t) | ||
| 790 | (let ((rpl (concat (match-string 1) (cadr l)))) | ||
| 791 | (org-export-latex-protect-string rpl) | ||
| 792 | (org-if-unprotected | ||
| 793 | (replace-match rpl t t))))) quote-rpl))) | ||
| 794 | |||
| 795 | (defun org-export-latex-special-chars (sub-superscript) | ||
| 796 | "Export special characters to LaTeX. | ||
| 797 | If SUB-SUPERSCRIPT is non-nil, convert \\ and ^. | ||
| 798 | See the `org-export-latex.el' code for a complete conversion table." | ||
| 799 | (goto-char (point-min)) | ||
| 800 | (mapc (lambda(c) | ||
| 801 | (goto-char (point-min)) | ||
| 802 | (while (re-search-forward c nil t) | ||
| 803 | ;; Put the point where to check for org-protected | ||
| 804 | (unless (or (get-text-property (match-beginning 2) 'org-protected) | ||
| 805 | (org-at-table-p)) | ||
| 806 | (cond ((member (match-string 2) '("\\$" "$")) | ||
| 807 | (if (equal (match-string 2) "\\$") | ||
| 808 | (replace-match (concat (match-string 1) "$" | ||
| 809 | (match-string 3)) t t) | ||
| 810 | (replace-match (concat (match-string 1) "\\$" | ||
| 811 | (match-string 3)) t t))) | ||
| 812 | ((member (match-string 2) '("&" "%" "#")) | ||
| 813 | (if (equal (match-string 1) "\\") | ||
| 814 | (replace-match (match-string 2) t t) | ||
| 815 | (replace-match (concat (match-string 1) "\\" | ||
| 816 | (match-string 2)) t t))) | ||
| 817 | ((equal (match-string 2) "...") | ||
| 818 | (replace-match | ||
| 819 | (concat (match-string 1) | ||
| 820 | (org-export-latex-protect-string "\\ldots{}")) t t)) | ||
| 821 | ((equal (match-string 2) "~") | ||
| 822 | (cond ((equal (match-string 1) "\\") nil) | ||
| 823 | ((eq 'org-link (get-text-property 0 'face (match-string 2))) | ||
| 824 | (replace-match (concat (match-string 1) "\\~") t t)) | ||
| 825 | (t (replace-match | ||
| 826 | (org-export-latex-protect-string | ||
| 827 | (concat (match-string 1) "\\~{}")) t t)))) | ||
| 828 | ((member (match-string 2) '("{" "}")) | ||
| 829 | (unless (save-match-data (org-inside-LaTeX-fragment-p)) | ||
| 830 | (if (equal (match-string 1) "\\") | ||
| 831 | (replace-match (match-string 2) t t) | ||
| 832 | (replace-match (concat (match-string 1) "\\" | ||
| 833 | (match-string 2)) t t))))) | ||
| 834 | (unless (save-match-data (org-inside-LaTeX-fragment-p)) | ||
| 835 | (cond ((equal (match-string 2) "\\") | ||
| 836 | (replace-match (or (save-match-data | ||
| 837 | (org-export-latex-treat-backslash-char | ||
| 838 | (match-string 1) | ||
| 839 | (match-string 3))) "") t t)) | ||
| 840 | ((member (match-string 2) '("_" "^")) | ||
| 841 | (replace-match (or (save-match-data | ||
| 842 | (org-export-latex-treat-sub-super-char | ||
| 843 | sub-superscript | ||
| 844 | (match-string 1) | ||
| 845 | (match-string 2) | ||
| 846 | (match-string 3))) "") t t))))))) | ||
| 847 | '("^\\([^\n$]*?\\|^\\)\\(\\\\?\\$\\)\\([^\n$]*\\)$" | ||
| 848 | "\\([a-za-z0-9]+\\|[ \t\n]\\|\\b\\|\\\\\\)\\(_\\|\\^\\)\\([a-za-z0-9]+\\|[ \t\n]\\|[:punct:]\\|{[a-za-z0-9]+}\\|([a-za-z0-9]+)\\)" | ||
| 849 | "\\(.\\|^\\)\\(\\\\\\)\\([ \t\n]\\|[a-zA-Z&#%{}\"]+\\)" | ||
| 850 | "\\(.\\|^\\)\\(&\\)" | ||
| 851 | "\\(.\\|^\\)\\(#\\)" | ||
| 852 | "\\(.\\|^\\)\\(%\\)" | ||
| 853 | "\\(.\\|^\\)\\({\\)" | ||
| 854 | "\\(.\\|^\\)\\(}\\)" | ||
| 855 | "\\(.\\|^\\)\\(~\\)" | ||
| 856 | "\\(.\\|^\\)\\(\\.\\.\\.\\)" | ||
| 857 | ;; (?\< . "\\textless{}") | ||
| 858 | ;; (?\> . "\\textgreater{}") | ||
| 859 | ))) | ||
| 860 | |||
| 861 | (defun org-export-latex-treat-sub-super-char | ||
| 862 | (subsup string-before char string-after) | ||
| 863 | "Convert the \"_\" and \"^\" characters to LaTeX. | ||
| 864 | SUBSUP corresponds to the ^: option in the #+OPTIONS line. | ||
| 865 | Convert CHAR depending on STRING-BEFORE and STRING-AFTER." | ||
| 866 | (cond ((equal string-before "\\") | ||
| 867 | (concat string-before char string-after)) | ||
| 868 | ;; this is part of a math formula | ||
| 869 | ((and (string-match "\\S-+" string-before) | ||
| 870 | (string-match "\\S-+" string-after)) | ||
| 871 | (cond ((eq 'org-link (get-text-property 0 'face char)) | ||
| 872 | (concat string-before "\\" char string-after)) | ||
| 873 | ((save-match-data (org-inside-LaTeX-fragment-p)) | ||
| 874 | (if subsup | ||
| 875 | (cond ((eq 1 (length string-after)) | ||
| 876 | (concat string-before char string-after)) | ||
| 877 | ((string-match "[({]?\\([^)}]+\\)[)}]?" string-after) | ||
| 878 | (format "%s%s{%s}" string-before char | ||
| 879 | (match-string 1 string-after)))))) | ||
| 880 | ((and subsup | ||
| 881 | (> (length string-after) 1) | ||
| 882 | (string-match "[({]?\\([^)}]+\\)[)}]?" string-after)) | ||
| 883 | (format "$%s%s{%s}$" string-before char | ||
| 884 | (match-string 1 string-after))) | ||
| 885 | (subsup (concat "$" string-before char string-after "$")) | ||
| 886 | (t (org-export-latex-protect-string | ||
| 887 | (concat string-before "\\" char "{}" string-after))))) | ||
| 888 | (t (org-export-latex-protect-string | ||
| 889 | (concat string-before "\\" char "{}" string-after))))) | ||
| 890 | |||
| 891 | (defun org-export-latex-treat-backslash-char (string-before string-after) | ||
| 892 | "Convert the \"$\" special character to LaTeX. | ||
| 893 | The conversion is made depending of STRING-BEFORE and STRING-AFTER." | ||
| 894 | (cond ((member (list string-after) org-html-entities) | ||
| 895 | ;; backslash is part of a special entity (like "\alpha") | ||
| 896 | (concat string-before "$\\" | ||
| 897 | (or (cdar (member (list string-after) org-html-entities)) | ||
| 898 | string-after) "$")) | ||
| 899 | ((and (not (string-match "^[ \n\t]" string-after)) | ||
| 900 | (not (string-match "[ \t]\\'\\|^" string-before))) | ||
| 901 | ;; backslash is inside a word | ||
| 902 | (org-export-latex-protect-string | ||
| 903 | (concat string-before "\\textbackslash{}" string-after))) | ||
| 904 | ((not (or (equal string-after "") | ||
| 905 | (string-match "^[ \t\n]" string-after))) | ||
| 906 | ;; backslash might escape a character (like \#) or a user TeX | ||
| 907 | ;; macro (like \setcounter) | ||
| 908 | (org-export-latex-protect-string | ||
| 909 | (concat string-before "\\" string-after))) | ||
| 910 | ((and (string-match "^[ \t\n]" string-after) | ||
| 911 | (string-match "[ \t\n]\\'" string-before)) | ||
| 912 | ;; backslash is alone, convert it to $\backslash$ | ||
| 913 | (org-export-latex-protect-string | ||
| 914 | (concat string-before "\\textbackslash{}" string-after))) | ||
| 915 | (t (org-export-latex-protect-string | ||
| 916 | (concat string-before "\\textbackslash{}" string-after))))) | ||
| 917 | |||
| 918 | (defun org-export-latex-keywords (timestamps) | ||
| 919 | "Convert special keywords to LaTeX. | ||
| 920 | Regexps are those from `org-export-latex-special-string-regexps'." | ||
| 921 | (let ((rg org-export-latex-special-string-regexps) r) | ||
| 922 | (while (setq r (pop rg)) | ||
| 923 | (goto-char (point-min)) | ||
| 924 | (while (re-search-forward (eval r) nil t) | ||
| 925 | (if (not timestamps) | ||
| 926 | (replace-match (format "\\\\texttt{%s}" (match-string 0)) t) | ||
| 927 | (replace-match "")))))) | ||
| 928 | |||
| 929 | (defun org-export-latex-fixed-width (opt) | ||
| 930 | "When OPT is non-nil convert fixed-width sections to LaTeX." | ||
| 931 | (goto-char (point-min)) | ||
| 932 | (while (re-search-forward "^[ \t]*:" nil t) | ||
| 933 | (if opt | ||
| 934 | (progn (goto-char (match-beginning 0)) | ||
| 935 | (insert "\\begin{verbatim}\n") | ||
| 936 | (while (looking-at "^\\([ \t]*\\):\\(.*\\)$") | ||
| 937 | (replace-match (concat (match-string 1) | ||
| 938 | (match-string 2)) t t) | ||
| 939 | (forward-line)) | ||
| 940 | (insert "\\end{verbatim}\n\n")) | ||
| 941 | (progn (goto-char (match-beginning 0)) | ||
| 942 | (while (looking-at "^\\([ \t]*\\):\\(.*\\)$") | ||
| 943 | (replace-match (concat "%" (match-string 1) | ||
| 944 | (match-string 2)) t t) | ||
| 945 | (forward-line)))))) | ||
| 946 | |||
| 947 | (defun org-export-latex-tables (insert) | ||
| 948 | "Convert tables to LaTeX and INSERT it." | ||
| 949 | (goto-char (point-min)) | ||
| 950 | (while (re-search-forward "^\\([ \t]*\\)|" nil t) | ||
| 951 | ;; FIXME really need to save-excursion? | ||
| 952 | (save-excursion (org-table-align)) | ||
| 953 | (let* ((beg (org-table-begin)) | ||
| 954 | (end (org-table-end)) | ||
| 955 | (raw-table (buffer-substring-no-properties beg end)) | ||
| 956 | fnum fields line lines olines gr colgropen line-fmt align) | ||
| 957 | (if org-export-latex-tables-verbatim | ||
| 958 | (let* ((tbl (concat "\\begin{verbatim}\n" raw-table | ||
| 959 | "\\end{verbatim}\n"))) | ||
| 960 | (apply 'delete-region (list beg end)) | ||
| 961 | (insert tbl)) | ||
| 962 | (progn | ||
| 963 | (setq lines (split-string raw-table "\n" t)) | ||
| 964 | (apply 'delete-region (list beg end)) | ||
| 965 | (when org-export-table-remove-special-lines | ||
| 966 | (setq lines (org-table-clean-before-export lines))) | ||
| 967 | ;; make a formatting string to reflect aligment | ||
| 968 | (setq olines lines) | ||
| 969 | (while (and (not line-fmt) (setq line (pop olines))) | ||
| 970 | (unless (string-match "^[ \t]*|-" line) | ||
| 971 | (setq fields (org-split-string line "[ \t]*|[ \t]*")) | ||
| 972 | (setq fnum (make-vector (length fields) 0)) | ||
| 973 | (setq line-fmt | ||
| 974 | (mapconcat | ||
| 975 | (lambda (x) | ||
| 976 | (setq gr (pop org-table-colgroup-info)) | ||
| 977 | (format "%s%%s%s" | ||
| 978 | (cond ((eq gr ':start) | ||
| 979 | (prog1 (if colgropen "|" "") | ||
| 980 | (setq colgropen t))) | ||
| 981 | ((eq gr ':startend) | ||
| 982 | (prog1 (if colgropen "|" "|") | ||
| 983 | (setq colgropen nil))) | ||
| 984 | (t "")) | ||
| 985 | (if (memq gr '(:end :startend)) | ||
| 986 | (progn (setq colgropen nil) "|") | ||
| 987 | ""))) | ||
| 988 | fnum "")))) | ||
| 989 | ;; fix double || in line-fmt | ||
| 990 | (setq line-fmt (replace-regexp-in-string "||" "|" line-fmt)) | ||
| 991 | ;; maybe remove the first and last "|" | ||
| 992 | (when (and (not org-export-latex-tables-column-borders) | ||
| 993 | (string-match "^\\(|\\)?\\(.+\\)|$" line-fmt)) | ||
| 994 | (setq line-fmt (match-string 2 line-fmt))) | ||
| 995 | ;; format alignment | ||
| 996 | (setq align (apply 'format | ||
| 997 | (cons line-fmt | ||
| 998 | (mapcar (lambda (x) (if x "r" "l")) | ||
| 999 | org-table-last-alignment)))) | ||
| 1000 | ;; prepare the table to send to orgtbl-to-latex | ||
| 1001 | (setq lines | ||
| 1002 | (mapcar | ||
| 1003 | (lambda(elem) | ||
| 1004 | (or (and (string-match "[ \t]*|-+" elem) 'hline) | ||
| 1005 | (split-string (org-trim elem) "|" t))) | ||
| 1006 | lines)) | ||
| 1007 | (when insert | ||
| 1008 | (insert (orgtbl-to-latex | ||
| 1009 | lines `(:tstart ,(concat "\\begin{tabular}{" align "}"))) | ||
| 1010 | "\n\n"))))))) | ||
| 1011 | |||
| 1012 | (defun org-export-latex-fontify () | ||
| 1013 | "Convert fontification to LaTeX." | ||
| 1014 | (goto-char (point-min)) | ||
| 1015 | (while (re-search-forward org-emph-re nil t) | ||
| 1016 | ;; The match goes one char after the *string* | ||
| 1017 | (let ((emph (assoc (match-string 3) | ||
| 1018 | org-export-latex-emphasis-alist)) | ||
| 1019 | rpl) | ||
| 1020 | (unless (get-text-property (1- (point)) 'org-protected) | ||
| 1021 | (setq rpl (concat (match-string 1) | ||
| 1022 | (format (org-export-latex-protect-char-in-string | ||
| 1023 | '("\\" "{" "}") (cadr emph)) | ||
| 1024 | (match-string 4)) | ||
| 1025 | (match-string 5))) | ||
| 1026 | (if (caddr emph) | ||
| 1027 | (setq rpl (org-export-latex-protect-string rpl))) | ||
| 1028 | (replace-match rpl t t))) | ||
| 1029 | (backward-char))) | ||
| 1030 | |||
| 1031 | (defun org-export-latex-links () | ||
| 1032 | ;; Make sure to use the LaTeX hyperref and graphicx package | ||
| 1033 | ;; or send some warnings. | ||
| 1034 | "Convert links to LaTeX." | ||
| 1035 | (goto-char (point-min)) | ||
| 1036 | (while (re-search-forward org-bracket-link-analytic-regexp nil t) | ||
| 1037 | (org-if-unprotected | ||
| 1038 | (goto-char (match-beginning 0)) | ||
| 1039 | (let* ((re-radio org-export-latex-all-targets-re) | ||
| 1040 | (remove (list (match-beginning 0) (match-end 0))) | ||
| 1041 | (type (match-string 2)) | ||
| 1042 | (raw-path (match-string 3)) | ||
| 1043 | (full-raw-path (concat (match-string 1) raw-path)) | ||
| 1044 | (desc (match-string 5)) | ||
| 1045 | imgp radiop | ||
| 1046 | ;; define the path of the link | ||
| 1047 | (path (cond | ||
| 1048 | ((member type '("http" "https" "ftp")) | ||
| 1049 | (concat type ":" raw-path)) | ||
| 1050 | ((and re-radio (string-match re-radio raw-path)) | ||
| 1051 | (setq radiop t)) | ||
| 1052 | ((equal type "mailto") | ||
| 1053 | (concat type ":" raw-path)) | ||
| 1054 | ((equal type "file") | ||
| 1055 | (if (and (or (org-file-image-p (expand-file-name raw-path)) | ||
| 1056 | (string-match "\\.eps$" raw-path)) | ||
| 1057 | (equal desc full-raw-path)) | ||
| 1058 | (setq imgp t) | ||
| 1059 | (progn (when (string-match "\\(.+\\)::.+" raw-path) | ||
| 1060 | (setq raw-path (match-string 1 raw-path))) | ||
| 1061 | (if (file-exists-p raw-path) | ||
| 1062 | (concat type "://" (expand-file-name raw-path)) | ||
| 1063 | (concat type "://" (org-export-directory | ||
| 1064 | :LaTeX org-export-latex-options-plist) | ||
| 1065 | raw-path)))))))) | ||
| 1066 | ;; process with link inserting | ||
| 1067 | (apply 'delete-region remove) | ||
| 1068 | (cond ((and imgp (plist-get org-export-latex-options-plist :inline-images)) | ||
| 1069 | (insert (format "\\includegraphics[%s]{%s}" | ||
| 1070 | ;; image option should be set be a comment line | ||
| 1071 | org-export-latex-image-default-option | ||
| 1072 | (expand-file-name raw-path)))) | ||
| 1073 | (radiop (insert (format "\\hyperref[%s]{%s}" raw-path desc))) | ||
| 1074 | (path (insert (format "\\href{%s}{%s}" path desc))) | ||
| 1075 | (t (insert "\\texttt{" desc "}"))))))) | ||
| 1076 | |||
| 1077 | (defvar org-latex-entities) ; defined below | ||
| 1078 | |||
| 1079 | (defun org-export-latex-cleaned-string () | ||
| 1080 | "Clean stuff in the LaTeX export." | ||
| 1081 | |||
| 1082 | ;; Preserve line breaks | ||
| 1083 | (goto-char (point-min)) | ||
| 1084 | (while (re-search-forward "\\\\\\\\" nil t) | ||
| 1085 | (add-text-properties (match-beginning 0) (match-end 0) | ||
| 1086 | '(org-protected t))) | ||
| 1087 | |||
| 1088 | ;; Convert LaTeX to \LaTeX{} | ||
| 1089 | (goto-char (point-min)) | ||
| 1090 | (let ((case-fold-search nil) rpl) | ||
| 1091 | (while (re-search-forward "\\([^+_]\\)LaTeX" nil t) | ||
| 1092 | (replace-match (org-export-latex-protect-string | ||
| 1093 | (concat (match-string 1) "\\LaTeX{}")) t t))) | ||
| 1094 | |||
| 1095 | ;; Convert horizontal rules | ||
| 1096 | (goto-char (point-min)) | ||
| 1097 | (while (re-search-forward "^----+.$" nil t) | ||
| 1098 | (replace-match (org-export-latex-protect-string "\\hrule") t t)) | ||
| 1099 | |||
| 1100 | ;; Protect LaTeX commands like \commad[...]{...} or \command{...} | ||
| 1101 | (goto-char (point-min)) | ||
| 1102 | (while (re-search-forward "\\\\[a-zA-Z]+\\(?:\\[.*\\]\\)?{.*}" nil t) | ||
| 1103 | (add-text-properties (match-beginning 0) (match-end 0) | ||
| 1104 | '(org-protected t))) | ||
| 1105 | |||
| 1106 | ;; Protect LaTeX entities | ||
| 1107 | (goto-char (point-min)) | ||
| 1108 | (while (re-search-forward (regexp-opt org-latex-entities) nil t) | ||
| 1109 | (add-text-properties (match-beginning 0) (match-end 0) | ||
| 1110 | '(org-protected t))) | ||
| 1111 | |||
| 1112 | ;; Replace radio links | ||
| 1113 | (goto-char (point-min)) | ||
| 1114 | (while (re-search-forward | ||
| 1115 | (concat "<<<?" org-export-latex-all-targets-re | ||
| 1116 | ">>>?\\((INVISIBLE)\\)?") nil t) | ||
| 1117 | (replace-match | ||
| 1118 | (org-export-latex-protect-string | ||
| 1119 | (format "\\label{%s}%s"(match-string 1) | ||
| 1120 | (if (match-string 2) "" (match-string 1)))) t t)) | ||
| 1121 | |||
| 1122 | ;; Delete @<...> constructs | ||
| 1123 | ;; Thanks to Daniel Clemente for this regexp | ||
| 1124 | (goto-char (point-min)) | ||
| 1125 | (while (re-search-forward "@<\\(?:[^\"\n]\\|\".*\"\\)*?>" nil t) | ||
| 1126 | (replace-match "")) | ||
| 1127 | |||
| 1128 | ;; When converting to LaTeX, replace footnotes | ||
| 1129 | ;; FIXME: don't protect footnotes from conversion | ||
| 1130 | (when (plist-get org-export-latex-options-plist :footnotes) | ||
| 1131 | (goto-char (point-min)) | ||
| 1132 | (while (re-search-forward "\\[[0-9]+\\]" nil t) | ||
| 1133 | (when (save-match-data | ||
| 1134 | (save-excursion (beginning-of-line) | ||
| 1135 | (looking-at "[^:|#]"))) | ||
| 1136 | (let ((foot-beg (match-beginning 0)) | ||
| 1137 | (foot-end (match-end 0)) | ||
| 1138 | (foot-prefix (match-string 0)) | ||
| 1139 | footnote footnote-rpl) | ||
| 1140 | (save-excursion | ||
| 1141 | (when (search-forward foot-prefix nil t) | ||
| 1142 | (replace-match "") | ||
| 1143 | (let ((end (save-excursion | ||
| 1144 | (if (re-search-forward "^$\\|^#.*$\\|\\[[0-9]+\\]" nil t) | ||
| 1145 | (match-beginning 0) (point-max))))) | ||
| 1146 | (setq footnote (concat (org-trim (buffer-substring (point) end)) | ||
| 1147 | " ")) ; prevent last } being part of a link | ||
| 1148 | (delete-region (point) end)) | ||
| 1149 | (goto-char foot-beg) | ||
| 1150 | (delete-region foot-beg foot-end) | ||
| 1151 | (unless (null footnote) | ||
| 1152 | (setq footnote-rpl (format "\\footnote{%s}" footnote)) | ||
| 1153 | (add-text-properties 0 10 '(org-protected t) footnote-rpl) | ||
| 1154 | (add-text-properties (1- (length footnote-rpl)) | ||
| 1155 | (length footnote-rpl) | ||
| 1156 | '(org-protected t) footnote-rpl) | ||
| 1157 | (insert footnote-rpl))))))) | ||
| 1158 | |||
| 1159 | ;; Replace footnote section tag for LaTeX | ||
| 1160 | (goto-char (point-min)) | ||
| 1161 | (while (re-search-forward | ||
| 1162 | (concat "^" footnote-section-tag-regexp) nil t) | ||
| 1163 | (replace-match "")))) | ||
| 1164 | |||
| 1165 | ;;; List handling: | ||
| 1166 | |||
| 1167 | (defun org-export-latex-lists () | ||
| 1168 | "Replace plain text lists in current buffer into LaTeX lists." | ||
| 1169 | "Convert lists to LaTeX." | ||
| 1170 | (goto-char (point-min)) | ||
| 1171 | (while (re-search-forward org-export-latex-list-beginning-re nil t) | ||
| 1172 | (beginning-of-line) | ||
| 1173 | (insert (org-list-to-latex (org-list-parse-list t)) "\n"))) | ||
| 1174 | |||
| 1175 | (defun org-list-parse-list (&optional delete) | ||
| 1176 | "Parse the list at point. | ||
| 1177 | Return a list containing first level items as strings and | ||
| 1178 | sublevels as a list of strings." | ||
| 1179 | (let ((start (org-list-item-begin)) | ||
| 1180 | (end (org-list-end)) | ||
| 1181 | output itemsep) | ||
| 1182 | (while (re-search-forward org-export-latex-list-beginning-re end t) | ||
| 1183 | (setq itemsep (if (save-match-data | ||
| 1184 | (string-match "^[0-9]" (match-string 2))) | ||
| 1185 | "[0-9]+\\(?:\\.\\|)\\)" "[-+]")) | ||
| 1186 | (let* ((indent1 (match-string 1)) | ||
| 1187 | (nextitem (save-excursion | ||
| 1188 | (save-match-data | ||
| 1189 | (or (and (re-search-forward | ||
| 1190 | (concat "^" indent1 itemsep " *?") end t) | ||
| 1191 | (match-beginning 0)) end)))) | ||
| 1192 | (item (buffer-substring | ||
| 1193 | (point) | ||
| 1194 | (or (and (re-search-forward | ||
| 1195 | org-export-latex-list-beginning-re end t) | ||
| 1196 | (goto-char (match-beginning 0))) | ||
| 1197 | (goto-char end)))) | ||
| 1198 | (nextindent (match-string 1)) | ||
| 1199 | (item (org-trim item)) | ||
| 1200 | (item (if (string-match "^\\[.+\\]" item) | ||
| 1201 | (replace-match "\\\\texttt{\\&}" | ||
| 1202 | t nil item) item))) | ||
| 1203 | (push item output) | ||
| 1204 | (when (> (length nextindent) | ||
| 1205 | (length indent1)) | ||
| 1206 | (narrow-to-region (point) nextitem) | ||
| 1207 | (push (org-list-parse-list) output) | ||
| 1208 | (widen)))) | ||
| 1209 | (when delete (delete-region start end)) | ||
| 1210 | (setq output (nreverse output)) | ||
| 1211 | (push (if (string-match "^\\[0" itemsep) | ||
| 1212 | 'ordered 'unordered) output))) | ||
| 1213 | |||
| 1214 | (defun org-list-item-begin () | ||
| 1215 | "Find the beginning of the list item and return its position." | ||
| 1216 | (save-excursion | ||
| 1217 | (if (not (or (looking-at org-export-latex-list-beginning-re) | ||
| 1218 | (re-search-backward | ||
| 1219 | org-export-latex-list-beginning-re nil t))) | ||
| 1220 | (progn (goto-char (point-min)) (point)) | ||
| 1221 | (match-beginning 0)))) | ||
| 1222 | |||
| 1223 | (defun org-list-end () | ||
| 1224 | "Find the end of the list and return its position." | ||
| 1225 | (save-excursion | ||
| 1226 | (catch 'exit | ||
| 1227 | (while (or (looking-at org-export-latex-list-beginning-re) | ||
| 1228 | (looking-at "^[ \t]+\\|^$")) | ||
| 1229 | (if (eq (point) (point-max)) | ||
| 1230 | (throw 'exit (point-max))) | ||
| 1231 | (forward-line 1))) (point))) | ||
| 1232 | |||
| 1233 | (defun org-list-insert-radio-list () | ||
| 1234 | "Insert a radio list template appropriate for this major mode." | ||
| 1235 | (interactive) | ||
| 1236 | (let* ((e (assq major-mode org-list-radio-list-templates)) | ||
| 1237 | (txt (nth 1 e)) | ||
| 1238 | name pos) | ||
| 1239 | (unless e (error "No radio list setup defined for %s" major-mode)) | ||
| 1240 | (setq name (read-string "List name: ")) | ||
| 1241 | (while (string-match "%n" txt) | ||
| 1242 | (setq txt (replace-match name t t txt))) | ||
| 1243 | (or (bolp) (insert "\n")) | ||
| 1244 | (setq pos (point)) | ||
| 1245 | (insert txt) | ||
| 1246 | (goto-char pos))) | ||
| 1247 | |||
| 1248 | (defun org-list-send-list (&optional maybe) | ||
| 1249 | "Send a tranformed version of this list to the receiver position. | ||
| 1250 | With argument MAYBE, fail quietly if no transformation is defined for | ||
| 1251 | this list." | ||
| 1252 | (interactive) | ||
| 1253 | (catch 'exit | ||
| 1254 | (unless (org-at-item-p) (error "Not at a list")) | ||
| 1255 | (save-excursion | ||
| 1256 | (goto-char (org-list-item-begin)) | ||
| 1257 | (beginning-of-line 0) | ||
| 1258 | (unless (looking-at "#\\+ORGLST: *SEND +\\([a-zA-Z0-9_]+\\) +\\([^ \t\r\n]+\\)\\( +.*\\)?") | ||
| 1259 | (if maybe | ||
| 1260 | (throw 'exit nil) | ||
| 1261 | (error "Don't know how to transform this list")))) | ||
| 1262 | (let* ((name (match-string 1)) | ||
| 1263 | beg | ||
| 1264 | (transform (intern (match-string 2))) | ||
| 1265 | (txt (buffer-substring-no-properties | ||
| 1266 | (org-list-item-begin) | ||
| 1267 | (org-list-end))) | ||
| 1268 | (list (org-list-parse-list))) | ||
| 1269 | (unless (fboundp transform) | ||
| 1270 | (error "No such transformation function %s" transform)) | ||
| 1271 | (setq txt (funcall transform list)) | ||
| 1272 | ;; Find the insertion place | ||
| 1273 | (save-excursion | ||
| 1274 | (goto-char (point-min)) | ||
| 1275 | (unless (re-search-forward | ||
| 1276 | (concat "BEGIN RECEIVE ORGLST +" name "\\([ \t]\\|$\\)") nil t) | ||
| 1277 | (error "Don't know where to insert translated list")) | ||
| 1278 | (goto-char (match-beginning 0)) | ||
| 1279 | (beginning-of-line 2) | ||
| 1280 | (setq beg (point)) | ||
| 1281 | (unless (re-search-forward (concat "END RECEIVE ORGLST +" name) nil t) | ||
| 1282 | (error "Cannot find end of insertion region")) | ||
| 1283 | (beginning-of-line 1) | ||
| 1284 | (delete-region beg (point)) | ||
| 1285 | (goto-char beg) | ||
| 1286 | (insert txt "\n")) | ||
| 1287 | (message "List converted and installed at receiver location")))) | ||
| 1288 | |||
| 1289 | (defun org-list-to-generic (list params) | ||
| 1290 | "Convert a LIST parsed through `org-list-parse-list' to other formats. | ||
| 1291 | |||
| 1292 | Valid parameters are | ||
| 1293 | |||
| 1294 | :ustart String to start an unordered list | ||
| 1295 | :uend String to end an unordered list | ||
| 1296 | |||
| 1297 | :ostart String to start an ordered list | ||
| 1298 | :oend String to end an ordered list | ||
| 1299 | |||
| 1300 | :splice When set to t, return only list body lines, don't wrap | ||
| 1301 | them into :[u/o]start and :[u/o]end. Default is nil. | ||
| 1302 | |||
| 1303 | :istart String to start a list item | ||
| 1304 | :iend String to end a list item | ||
| 1305 | :isep String to separate items | ||
| 1306 | :lsep String to separate sublists" | ||
| 1307 | (interactive) | ||
| 1308 | (let* ((p params) sublist | ||
| 1309 | (splicep (plist-get p :splice)) | ||
| 1310 | (ostart (plist-get p :ostart)) | ||
| 1311 | (oend (plist-get p :oend)) | ||
| 1312 | (ustart (plist-get p :ustart)) | ||
| 1313 | (uend (plist-get p :uend)) | ||
| 1314 | (istart (plist-get p :istart)) | ||
| 1315 | (iend (plist-get p :iend)) | ||
| 1316 | (isep (plist-get p :isep)) | ||
| 1317 | (lsep (plist-get p :lsep))) | ||
| 1318 | (let ((wrapper | ||
| 1319 | (cond ((eq (car list) 'ordered) | ||
| 1320 | (concat ostart "\n%s" oend "\n")) | ||
| 1321 | ((eq (car list) 'unordered) | ||
| 1322 | (concat ustart "\n%s" uend "\n")))) | ||
| 1323 | rtn) | ||
| 1324 | (while (setq sublist (pop list)) | ||
| 1325 | (cond ((symbolp sublist) nil) | ||
| 1326 | ((stringp sublist) | ||
| 1327 | (setq rtn (concat rtn istart sublist iend isep))) | ||
| 1328 | (t | ||
| 1329 | (setq rtn (concat rtn ;; previous list | ||
| 1330 | lsep ;; list separator | ||
| 1331 | (org-list-to-generic sublist p) | ||
| 1332 | lsep ;; list separator | ||
| 1333 | ))))) | ||
| 1334 | (format wrapper rtn)))) | ||
| 1335 | |||
| 1336 | (defun org-list-to-latex (list) | ||
| 1337 | "Convert LIST into a LaTeX list." | ||
| 1338 | (org-list-to-generic | ||
| 1339 | list '(:splicep nil :ostart "\\begin{enumerate}" :oend "\\end{enumerate}" | ||
| 1340 | :ustart "\\begin{itemize}" :uend "\\end{itemize}" | ||
| 1341 | :istart "\\item " :iend "" | ||
| 1342 | :isep "\n" :lsep "\n"))) | ||
| 1343 | |||
| 1344 | (defun org-list-to-html (list) | ||
| 1345 | "Convert LIST into a HTML list." | ||
| 1346 | (org-list-to-generic | ||
| 1347 | list '(:splicep nil :ostart "<ol>" :oend "</ol>" | ||
| 1348 | :ustart "<ul>" :uend "</ul>" | ||
| 1349 | :istart "<li>" :iend "</li>" | ||
| 1350 | :isep "\n" :lsep "\n"))) | ||
| 1351 | |||
| 1352 | (defun org-list-to-texinfo (list) | ||
| 1353 | "Convert LIST into a Texinfo list." | ||
| 1354 | (org-list-to-generic | ||
| 1355 | list '(:splicep nil :ostart "@itemize @minus" :oend "@end itemize" | ||
| 1356 | :ustart "@enumerate" :uend "@end enumerate" | ||
| 1357 | :istart "@item\n" :iend "" | ||
| 1358 | :isep "\n" :lsep "\n"))) | ||
| 1359 | |||
| 1360 | (defconst org-latex-entities | ||
| 1361 | '("\\!" | ||
| 1362 | "\\'" | ||
| 1363 | "\\+" | ||
| 1364 | "\\," | ||
| 1365 | "\\-" | ||
| 1366 | "\\:" | ||
| 1367 | "\\;" | ||
| 1368 | "\\<" | ||
| 1369 | "\\=" | ||
| 1370 | "\\>" | ||
| 1371 | "\\Huge" | ||
| 1372 | "\\LARGE" | ||
| 1373 | "\\Large" | ||
| 1374 | "\\Styles" | ||
| 1375 | "\\\\" | ||
| 1376 | "\\`" | ||
| 1377 | "\\addcontentsline" | ||
| 1378 | "\\address" | ||
| 1379 | "\\addtocontents" | ||
| 1380 | "\\addtocounter" | ||
| 1381 | "\\addtolength" | ||
| 1382 | "\\addvspace" | ||
| 1383 | "\\alph" | ||
| 1384 | "\\appendix" | ||
| 1385 | "\\arabic" | ||
| 1386 | "\\author" | ||
| 1387 | "\\begin{array}" | ||
| 1388 | "\\begin{center}" | ||
| 1389 | "\\begin{description}" | ||
| 1390 | "\\begin{enumerate}" | ||
| 1391 | "\\begin{eqnarray}" | ||
| 1392 | "\\begin{equation}" | ||
| 1393 | "\\begin{figure}" | ||
| 1394 | "\\begin{flushleft}" | ||
| 1395 | "\\begin{flushright}" | ||
| 1396 | "\\begin{itemize}" | ||
| 1397 | "\\begin{list}" | ||
| 1398 | "\\begin{minipage}" | ||
| 1399 | "\\begin{picture}" | ||
| 1400 | "\\begin{quotation}" | ||
| 1401 | "\\begin{quote}" | ||
| 1402 | "\\begin{tabbing}" | ||
| 1403 | "\\begin{table}" | ||
| 1404 | "\\begin{tabular}" | ||
| 1405 | "\\begin{thebibliography}" | ||
| 1406 | "\\begin{theorem}" | ||
| 1407 | "\\begin{titlepage}" | ||
| 1408 | "\\begin{verbatim}" | ||
| 1409 | "\\begin{verse}" | ||
| 1410 | "\\bf" | ||
| 1411 | "\\bf" | ||
| 1412 | "\\bibitem" | ||
| 1413 | "\\bigskip" | ||
| 1414 | "\\cdots" | ||
| 1415 | "\\centering" | ||
| 1416 | "\\circle" | ||
| 1417 | "\\cite" | ||
| 1418 | "\\cleardoublepage" | ||
| 1419 | "\\clearpage" | ||
| 1420 | "\\cline" | ||
| 1421 | "\\closing" | ||
| 1422 | "\\dashbox" | ||
| 1423 | "\\date" | ||
| 1424 | "\\ddots" | ||
| 1425 | "\\dotfill" | ||
| 1426 | "\\em" | ||
| 1427 | "\\fbox" | ||
| 1428 | "\\flushbottom" | ||
| 1429 | "\\fnsymbol" | ||
| 1430 | "\\footnote" | ||
| 1431 | "\\footnotemark" | ||
| 1432 | "\\footnotesize" | ||
| 1433 | "\\footnotetext" | ||
| 1434 | "\\frac" | ||
| 1435 | "\\frame" | ||
| 1436 | "\\framebox" | ||
| 1437 | "\\hfill" | ||
| 1438 | "\\hline" | ||
| 1439 | "\\hrulespace" | ||
| 1440 | "\\hspace" | ||
| 1441 | "\\huge" | ||
| 1442 | "\\hyphenation" | ||
| 1443 | "\\include" | ||
| 1444 | "\\includeonly" | ||
| 1445 | "\\indent" | ||
| 1446 | "\\input" | ||
| 1447 | "\\it" | ||
| 1448 | "\\kill" | ||
| 1449 | "\\label" | ||
| 1450 | "\\large" | ||
| 1451 | "\\ldots" | ||
| 1452 | "\\line" | ||
| 1453 | "\\linebreak" | ||
| 1454 | "\\linethickness" | ||
| 1455 | "\\listoffigures" | ||
| 1456 | "\\listoftables" | ||
| 1457 | "\\location" | ||
| 1458 | "\\makebox" | ||
| 1459 | "\\maketitle" | ||
| 1460 | "\\mark" | ||
| 1461 | "\\mbox" | ||
| 1462 | "\\medskip" | ||
| 1463 | "\\multicolumn" | ||
| 1464 | "\\multiput" | ||
| 1465 | "\\newcommand" | ||
| 1466 | "\\newcounter" | ||
| 1467 | "\\newenvironment" | ||
| 1468 | "\\newfont" | ||
| 1469 | "\\newlength" | ||
| 1470 | "\\newline" | ||
| 1471 | "\\newpage" | ||
| 1472 | "\\newsavebox" | ||
| 1473 | "\\newtheorem" | ||
| 1474 | "\\nocite" | ||
| 1475 | "\\nofiles" | ||
| 1476 | "\\noindent" | ||
| 1477 | "\\nolinebreak" | ||
| 1478 | "\\nopagebreak" | ||
| 1479 | "\\normalsize" | ||
| 1480 | "\\onecolumn" | ||
| 1481 | "\\opening" | ||
| 1482 | "\\oval" | ||
| 1483 | "\\overbrace" | ||
| 1484 | "\\overline" | ||
| 1485 | "\\pagebreak" | ||
| 1486 | "\\pagenumbering" | ||
| 1487 | "\\pageref" | ||
| 1488 | "\\pagestyle" | ||
| 1489 | "\\par" | ||
| 1490 | "\\parbox" | ||
| 1491 | "\\put" | ||
| 1492 | "\\raggedbottom" | ||
| 1493 | "\\raggedleft" | ||
| 1494 | "\\raggedright" | ||
| 1495 | "\\raisebox" | ||
| 1496 | "\\ref" | ||
| 1497 | "\\rm" | ||
| 1498 | "\\roman" | ||
| 1499 | "\\rule" | ||
| 1500 | "\\savebox" | ||
| 1501 | "\\sc" | ||
| 1502 | "\\scriptsize" | ||
| 1503 | "\\setcounter" | ||
| 1504 | "\\setlength" | ||
| 1505 | "\\settowidth" | ||
| 1506 | "\\sf" | ||
| 1507 | "\\shortstack" | ||
| 1508 | "\\signature" | ||
| 1509 | "\\sl" | ||
| 1510 | "\\small" | ||
| 1511 | "\\smallskip" | ||
| 1512 | "\\sqrt" | ||
| 1513 | "\\tableofcontents" | ||
| 1514 | "\\telephone" | ||
| 1515 | "\\thanks" | ||
| 1516 | "\\thispagestyle" | ||
| 1517 | "\\tiny" | ||
| 1518 | "\\title" | ||
| 1519 | "\\tt" | ||
| 1520 | "\\twocolumn" | ||
| 1521 | "\\typein" | ||
| 1522 | "\\typeout" | ||
| 1523 | "\\underbrace" | ||
| 1524 | "\\underline" | ||
| 1525 | "\\usebox" | ||
| 1526 | "\\usecounter" | ||
| 1527 | "\\value" | ||
| 1528 | "\\vdots" | ||
| 1529 | "\\vector" | ||
| 1530 | "\\verb" | ||
| 1531 | "\\vfill" | ||
| 1532 | "\\vline" | ||
| 1533 | "\\vspace") | ||
| 1534 | "A list of LaTeX commands to be protected when performing conversion.") | ||
| 1535 | |||
| 1536 | (provide 'org-export-latex) | ||
| 1537 | |||
| 1538 | ;; arch-tag: 23c2b87d-da04-4c2d-ad2d-1eb6487bc3ad | ||
| 1539 | ;;; org-export-latex.el ends here | ||
diff --git a/lisp/textmodes/org-irc.el b/lisp/textmodes/org-irc.el deleted file mode 100644 index d880eda9b4d..00000000000 --- a/lisp/textmodes/org-irc.el +++ /dev/null | |||
| @@ -1,228 +0,0 @@ | |||
| 1 | ;;; org-irc.el --- Store links to IRC sessions | ||
| 2 | |||
| 3 | ;; Copyright (C) 2008 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: Philip Jackson <emacs@shellarchive.co.uk> | ||
| 6 | ;; Keywords: erc, irc, link, org | ||
| 7 | ;; Version: 1.3 | ||
| 8 | |||
| 9 | ;; This file is part of GNU Emacs. | ||
| 10 | |||
| 11 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 12 | ;; it under the terms of the GNU General Public License as published by | ||
| 13 | ;; the Free Software Foundation; either version 3, or (at your option) | ||
| 14 | ;; any later version. | ||
| 15 | |||
| 16 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 19 | ;; GNU General Public License for more details. | ||
| 20 | |||
| 21 | ;; You should have received a copy of the GNU General Public License | ||
| 22 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | ||
| 23 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 24 | ;; Boston, MA 02110-1301, USA. | ||
| 25 | |||
| 26 | ;;; Commentary: | ||
| 27 | |||
| 28 | ;; Link to an IRC session. Only ERC has been implemented at the | ||
| 29 | ;; moment. | ||
| 30 | ;; | ||
| 31 | ;; This file is loaded by default whenever org.el is loaded. Please | ||
| 32 | ;; customize the variable `org-default-extensions' to select extensions | ||
| 33 | ;; you would like to use, and to deselect those which you don't want. | ||
| 34 | ;; | ||
| 35 | ;; Please note that at the moment only ERC is supported. Other clients | ||
| 36 | ;; shouldn't be diffficult to add though. | ||
| 37 | ;; | ||
| 38 | ;; Then set `org-irc-link-to-logs' to non-nil if you would like a | ||
| 39 | ;; file:/ type link to be created to the current line in the logs or | ||
| 40 | ;; to t if you would like to create an irc:/ style link. | ||
| 41 | ;; | ||
| 42 | ;; Links within an org buffer might look like this: | ||
| 43 | ;; | ||
| 44 | ;; [[irc:/irc.freenode.net/#emacs/bob][chat with bob in #emacs on freenode]] | ||
| 45 | ;; [[irc:/irc.freenode.net/#emacs][#emacs on freenode]] | ||
| 46 | ;; [[irc:/irc.freenode.net/]] | ||
| 47 | ;; | ||
| 48 | ;; If, when the resulting link is visited, there is no connection to a | ||
| 49 | ;; requested server then one will be created. | ||
| 50 | |||
| 51 | ;;; Code: | ||
| 52 | |||
| 53 | (require 'org) | ||
| 54 | (require 'erc) | ||
| 55 | (require 'erc-log) | ||
| 56 | |||
| 57 | (defvar org-irc-client 'erc | ||
| 58 | "The IRC client to act on") | ||
| 59 | (defvar org-irc-link-to-logs nil | ||
| 60 | "non-nil will store a link to the logs, nil will store an irc: style link") | ||
| 61 | |||
| 62 | (defvar erc-default-port) ; dynamically scoped from erc.el | ||
| 63 | (defvar erc-session-port) ; dynamically scoped form erc-backend.el | ||
| 64 | (defvar erc-server-announced-name) ; dynamically scoped form erc-backend.el | ||
| 65 | |||
| 66 | ;; Generic functions/config (extend these for other clients) | ||
| 67 | |||
| 68 | (add-to-list 'org-store-link-functions | ||
| 69 | 'org-irc-store-link) | ||
| 70 | |||
| 71 | (org-add-link-type "irc" 'org-irc-visit nil) | ||
| 72 | |||
| 73 | (defun org-irc-visit (link) | ||
| 74 | "Dispatch to the correct visit function based on the client" | ||
| 75 | (let ((link (org-irc-parse-link link))) | ||
| 76 | (cond | ||
| 77 | ((eq org-irc-client 'erc) | ||
| 78 | (org-irc-visit-erc link)) | ||
| 79 | (t | ||
| 80 | (error "erc only known client"))))) | ||
| 81 | |||
| 82 | (defun org-irc-parse-link (link) | ||
| 83 | "Get a of irc link attributes where `link' looks like | ||
| 84 | server:port/chan/user (port, chan and user being optional)." | ||
| 85 | (let* ((parts (split-string link "/" t)) | ||
| 86 | (len (length parts))) | ||
| 87 | (when (or (< len 1) (> len 3)) | ||
| 88 | (error "Failed to parse link needed 1-3 parts, got %d." len)) | ||
| 89 | (setcar parts (split-string (car parts) ":" t)) | ||
| 90 | parts)) | ||
| 91 | |||
| 92 | ;;;###autoload | ||
| 93 | (defun org-irc-store-link () | ||
| 94 | "Dispatch to the appropreate function to store a link to | ||
| 95 | something IRC related" | ||
| 96 | (cond | ||
| 97 | ((eq major-mode 'erc-mode) | ||
| 98 | (org-irc-erc-store-link)))) | ||
| 99 | |||
| 100 | (defun org-irc-elipsify-description (string &optional after) | ||
| 101 | "Strip starting and ending whitespace and replace any chars | ||
| 102 | that appear after the value in `after' with '...'" | ||
| 103 | (let* ((after (number-to-string (or after 30))) | ||
| 104 | (replace-map (list (cons "^[ \t]*" "") | ||
| 105 | (cons "[ \t]*$" "") | ||
| 106 | (cons (concat "^\\(.\\{" after | ||
| 107 | "\\}\\).*") "\\1...")))) | ||
| 108 | (mapc (lambda (x) | ||
| 109 | (when (string-match (car x) string) | ||
| 110 | (setq string (replace-match (cdr x) nil nil string)))) | ||
| 111 | replace-map) | ||
| 112 | string)) | ||
| 113 | |||
| 114 | ;; ERC specific functions | ||
| 115 | |||
| 116 | (defun org-irc-erc-get-line-from-log (erc-line) | ||
| 117 | "Find the most suitable line to link to from the erc logs. If | ||
| 118 | the user is on the erc-prompt then search backward for the first | ||
| 119 | non-blank line, otherwise return the current line. The result is | ||
| 120 | a cons of the filename and search string." | ||
| 121 | (erc-save-buffer-in-logs) | ||
| 122 | (with-current-buffer (find-file-noselect (erc-current-logfile)) | ||
| 123 | (goto-char (point-max)) | ||
| 124 | (list | ||
| 125 | (abbreviate-file-name buffer-file-name) | ||
| 126 | ;; can we get a '::' part? | ||
| 127 | (if (string= erc-line (erc-prompt)) | ||
| 128 | (progn | ||
| 129 | (goto-char (point-at-bol)) | ||
| 130 | (when (search-backward-regexp "^[^ ]" nil t) | ||
| 131 | (buffer-substring-no-properties (point-at-bol) | ||
| 132 | (point-at-eol)))) | ||
| 133 | (when (search-backward erc-line nil t) | ||
| 134 | (buffer-substring-no-properties (point-at-bol) | ||
| 135 | (point-at-eol))))))) | ||
| 136 | |||
| 137 | (defun org-irc-erc-store-link () | ||
| 138 | "Depending on the variable `org-irc-link-to-logs' store either | ||
| 139 | a link to the log file for the current session or an irc: link to | ||
| 140 | the session itself." | ||
| 141 | (if org-irc-link-to-logs | ||
| 142 | (let* ((erc-line (buffer-substring-no-properties | ||
| 143 | (point-at-bol) (point-at-eol))) | ||
| 144 | (parsed-line (org-irc-erc-get-line-from-log erc-line))) | ||
| 145 | (if (erc-logging-enabled nil) | ||
| 146 | (progn | ||
| 147 | (org-store-link-props | ||
| 148 | :type "file" | ||
| 149 | :description (concat "'" (org-irc-elipsify-description | ||
| 150 | (cadr parsed-line) 20) | ||
| 151 | "' from an IRC conversation") | ||
| 152 | :link (concat "file:" (car parsed-line) "::" | ||
| 153 | (cadr parsed-line))) | ||
| 154 | t) | ||
| 155 | (error "This ERC session is not being logged"))) | ||
| 156 | (let* ((link-text (org-irc-get-erc-link)) | ||
| 157 | (link (org-irc-parse-link link-text))) | ||
| 158 | (if link-text | ||
| 159 | (progn | ||
| 160 | (org-store-link-props | ||
| 161 | :type "irc" | ||
| 162 | :link (org-make-link "irc:/" link-text) | ||
| 163 | :description (concat "irc session '" link-text "'") | ||
| 164 | :server (car (car link)) | ||
| 165 | :port (or (cadr (pop link)) erc-default-port) | ||
| 166 | :nick (pop link)) | ||
| 167 | t) | ||
| 168 | (error "Failed to create ('irc:/' style) ERC link"))))) | ||
| 169 | |||
| 170 | (defun org-irc-get-erc-link () | ||
| 171 | "Return an org compatible irc:/ link from an ERC buffer" | ||
| 172 | (let ((link (concat erc-server-announced-name ":" | ||
| 173 | (number-to-string erc-session-port)))) | ||
| 174 | (concat link "/" | ||
| 175 | (if (and (erc-default-target) | ||
| 176 | (erc-channel-p (erc-default-target)) | ||
| 177 | (car (get-text-property (point) 'erc-data))) | ||
| 178 | ;; we can get a nick | ||
| 179 | (let ((nick (car (get-text-property (point) 'erc-data)))) | ||
| 180 | (concat (erc-default-target) "/" nick)) | ||
| 181 | (erc-default-target))))) | ||
| 182 | |||
| 183 | (defun org-irc-visit-erc (link) | ||
| 184 | "Visit an ERC buffer based on criteria from the followed link" | ||
| 185 | (let* ((server (car (car link))) | ||
| 186 | (port (or (cadr (pop link)) erc-default-port)) | ||
| 187 | (server-buffer) | ||
| 188 | (buffer-list | ||
| 189 | (erc-buffer-filter | ||
| 190 | (lambda nil | ||
| 191 | (let ((tmp-server-buf (erc-server-buffer))) | ||
| 192 | (and tmp-server-buf | ||
| 193 | (with-current-buffer tmp-server-buf | ||
| 194 | (and | ||
| 195 | (string= erc-session-port port) | ||
| 196 | (string= erc-server-announced-name server) | ||
| 197 | (setq server-buffer tmp-server-buf))))))))) | ||
| 198 | (if buffer-list | ||
| 199 | (let ((chan-name (pop link))) | ||
| 200 | ;; if we got a channel name then switch to it or join it | ||
| 201 | (if chan-name | ||
| 202 | (let ((chan-buf (catch 'found | ||
| 203 | (dolist (x buffer-list) | ||
| 204 | (if (string= (buffer-name x) chan-name) | ||
| 205 | (throw 'found x)))))) | ||
| 206 | (if chan-buf | ||
| 207 | (progn | ||
| 208 | (switch-to-buffer chan-buf) | ||
| 209 | ;; if we got a nick, and they're in the chan, | ||
| 210 | ;; then start a chat with them | ||
| 211 | (let ((nick (pop link))) | ||
| 212 | (when nick | ||
| 213 | (if (member nick (erc-get-server-nickname-list)) | ||
| 214 | (progn | ||
| 215 | (goto-char (point-max)) | ||
| 216 | (insert (concat nick ": "))) | ||
| 217 | (error "%s not found in %s" nick chan-name))))) | ||
| 218 | (progn | ||
| 219 | (switch-to-buffer server-buffer) | ||
| 220 | (erc-cmd-JOIN chan-name)))) | ||
| 221 | (switch-to-buffer server-buffer))) | ||
| 222 | ;; no server match, make new connection | ||
| 223 | (erc-select :server server :port port)))) | ||
| 224 | |||
| 225 | (provide 'org-irc) | ||
| 226 | |||
| 227 | ;; arch-tag: 018d7dda-53b8-4a35-ba92-6670939e525a | ||
| 228 | ;;; org-irc.el ends here | ||
diff --git a/lisp/textmodes/org-mac-message.el b/lisp/textmodes/org-mac-message.el deleted file mode 100644 index 7e2688510c3..00000000000 --- a/lisp/textmodes/org-mac-message.el +++ /dev/null | |||
| @@ -1,79 +0,0 @@ | |||
| 1 | ;;; org-mac-message.el --- Support for links to Apple Mail messages by Message-ID | ||
| 2 | |||
| 3 | ;; Copyright (C) 2008 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: John Wiegley <johnw@gnu.org> | ||
| 6 | ;; Version: 1.2 | ||
| 7 | ;; Keywords: outlines, hypermedia, calendar, wp | ||
| 8 | |||
| 9 | ;; This file is part of GNU Emacs. | ||
| 10 | |||
| 11 | ;; Emacs is free software; you can redistribute it and/or modify | ||
| 12 | ;; it under the terms of the GNU General Public License as published by | ||
| 13 | ;; the Free Software Foundation; either version 3, or (at your option) | ||
| 14 | ;; any later version. | ||
| 15 | |||
| 16 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 19 | ;; GNU General Public License for more details. | ||
| 20 | |||
| 21 | ;; You should have received a copy of the GNU General Public License | ||
| 22 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | ||
| 23 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 24 | ;; Boston, MA 02110-1301, USA. | ||
| 25 | |||
| 26 | ;;; Code: | ||
| 27 | |||
| 28 | (require 'org) | ||
| 29 | |||
| 30 | (org-add-link-type "message" 'org-mac-message-open) | ||
| 31 | |||
| 32 | (declare-function do-applescript "mac.c" (string)) | ||
| 33 | (unless (fboundp 'do-applescript) | ||
| 34 | ;; Need to fake this using shell-command-to-string | ||
| 35 | (defun do-applescript (script) | ||
| 36 | (let (start cmd return) | ||
| 37 | (while (string-match "\n" script) | ||
| 38 | (setq script (replace-match "\r" t t script))) | ||
| 39 | (while (string-match "'" script start) | ||
| 40 | (setq start (+ 2 (match-beginning 0)) | ||
| 41 | script (replace-match "\\'" t t script))) | ||
| 42 | (setq cmd (concat "osascript -e '" script "'")) | ||
| 43 | (setq return (shell-command-to-string cmd)) | ||
| 44 | (concat "\"" (org-trim return) "\"")))) | ||
| 45 | |||
| 46 | (defun org-mac-message-open (message-id) | ||
| 47 | "Visit the message with the given Message-ID. | ||
| 48 | This will use the command `open' with the message url." | ||
| 49 | (start-process (concat "open message:" message-id) nil | ||
| 50 | "open" (concat "message://<" (substring message-id 2) ">"))) | ||
| 51 | |||
| 52 | (defun org-mac-message-insert-link () | ||
| 53 | "Insert a link to the messages currently selected in Apple Mail. | ||
| 54 | This will use applescript to get the message-id and the subject of the | ||
| 55 | active mail in AppleMail and make a link out of it." | ||
| 56 | (interactive) | ||
| 57 | (insert (org-mac-message-get-link))) | ||
| 58 | |||
| 59 | (defun org-mac-message-get-link () | ||
| 60 | "Insert a link to the messages currently selected in Apple Mail. | ||
| 61 | This will use applescript to get the message-id and the subject of the | ||
| 62 | active mail in AppleMail and make a link out of it." | ||
| 63 | (let ((subject (do-applescript "tell application \"Mail\" | ||
| 64 | set theMessages to selection | ||
| 65 | subject of beginning of theMessages | ||
| 66 | end tell")) | ||
| 67 | (message-id (do-applescript "tell application \"Mail\" | ||
| 68 | set theMessages to selection | ||
| 69 | message id of beginning of theMessages | ||
| 70 | end tell"))) | ||
| 71 | (org-make-link-string | ||
| 72 | (concat "message://" | ||
| 73 | (substring message-id 1 (1- (length message-id)))) | ||
| 74 | (substring subject 1 (1- (length subject)))))) | ||
| 75 | |||
| 76 | (provide 'org-mac-message) | ||
| 77 | |||
| 78 | ;; arch-tag: 3806d0c1-abe1-4db6-9c31-f3ed7d4a9b32 | ||
| 79 | ;;; org-mac-message.el ends here | ||
diff --git a/lisp/textmodes/org-mouse.el b/lisp/textmodes/org-mouse.el deleted file mode 100644 index 52770899f70..00000000000 --- a/lisp/textmodes/org-mouse.el +++ /dev/null | |||
| @@ -1,1110 +0,0 @@ | |||
| 1 | ;;; org-mouse.el --- Better mouse support for org-mode | ||
| 2 | |||
| 3 | ;; Copyright (C) 2006, 2007, 2008 Free Software Foundation | ||
| 4 | ;; | ||
| 5 | ;; Author: Piotr Zielinski <piotr dot zielinski at gmail dot com> | ||
| 6 | ;; Maintainer: Carsten Dominik <carsten at orgmode dot org> | ||
| 7 | ;; Version: 5.23 | ||
| 8 | ;; | ||
| 9 | ;; This file is part of GNU Emacs. | ||
| 10 | ;; | ||
| 11 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 12 | ;; it under the terms of the GNU General Public License as published by | ||
| 13 | ;; the Free Software Foundation; either version 3, or (at your option) | ||
| 14 | ;; any later version. | ||
| 15 | |||
| 16 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 19 | ;; GNU General Public License for more details. | ||
| 20 | |||
| 21 | ;; You should have received a copy of the GNU General Public License | ||
| 22 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | ||
| 23 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 24 | ;; Boston, MA 02110-1301, USA. | ||
| 25 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 26 | ;; | ||
| 27 | ;;; Commentary: | ||
| 28 | ;; | ||
| 29 | ;; Org-mouse provides mouse support for org-mode. | ||
| 30 | ;; | ||
| 31 | ;; http://orgmode.org | ||
| 32 | ;; | ||
| 33 | ;; Org-mouse implements the following features: | ||
| 34 | ;; * following links with the left mouse button (in Emacs 22) | ||
| 35 | ;; * subtree expansion/collapse (org-cycle) with the left mouse button | ||
| 36 | ;; * several context menus on the right mouse button: | ||
| 37 | ;; + general text | ||
| 38 | ;; + headlines | ||
| 39 | ;; + timestamps | ||
| 40 | ;; + priorities | ||
| 41 | ;; + links | ||
| 42 | ;; + tags | ||
| 43 | ;; * promoting/demoting/moving subtrees with mouse-3 | ||
| 44 | ;; + if the drag starts and ends in the same line then promote/demote | ||
| 45 | ;; + otherwise move the subtree | ||
| 46 | ;; | ||
| 47 | ;; Use | ||
| 48 | ;; --- | ||
| 49 | ;; | ||
| 50 | ;; To use this package, put the following line in your .emacs: | ||
| 51 | ;; | ||
| 52 | ;; (require 'org-mouse) | ||
| 53 | ;; | ||
| 54 | |||
| 55 | ;; Fixme: | ||
| 56 | ;; + deal with folding / unfolding issues | ||
| 57 | |||
| 58 | ;; TODO (This list is only theoretical, if you'd like to have some | ||
| 59 | ;; feature implemented or a bug fix please send me an email, even if | ||
| 60 | ;; something similar appears in the list below. This will help me get | ||
| 61 | ;; the priorities right.): | ||
| 62 | ;; | ||
| 63 | ;; + org-store-link, insert link | ||
| 64 | ;; + org tables | ||
| 65 | ;; + occur with the current word/tag (same menu item) | ||
| 66 | ;; + ctrl-c ctrl-c, for example, renumber the current list | ||
| 67 | ;; + internal links | ||
| 68 | |||
| 69 | ;; Please email the maintainer with new feature suggestions / bugs | ||
| 70 | |||
| 71 | ;; History: | ||
| 72 | ;; | ||
| 73 | ;; SInce version 5.10: Changes are listed in the general org-mode docs. | ||
| 74 | ;; | ||
| 75 | ;; Version 5.09 | ||
| 76 | ;; + Version number synchronization with Org-mode. | ||
| 77 | ;; | ||
| 78 | ;; Version 0.25 | ||
| 79 | ;; + made compatible with org-mode 4.70 (thanks to Carsten for the patch) | ||
| 80 | ;; | ||
| 81 | ;; Version 0.24 | ||
| 82 | ;; + minor changes to the table menu | ||
| 83 | ;; | ||
| 84 | ;; Version 0.23 | ||
| 85 | ;; + preliminary support for tables and calculation marks | ||
| 86 | ;; + context menu support for org-agenda-undo & org-sort-entries | ||
| 87 | ;; | ||
| 88 | ;; Version 0.22 | ||
| 89 | ;; + handles undo support for the agenda buffer (requires org-mode >=4.58) | ||
| 90 | ;; | ||
| 91 | ;; Version 0.21 | ||
| 92 | ;; + selected text activates its context menu | ||
| 93 | ;; + shift-middleclick or right-drag inserts the text from the clipboard in the form of a link | ||
| 94 | ;; | ||
| 95 | ;; Version 0.20 | ||
| 96 | ;; + the new "TODO Status" submenu replaces the "Cycle TODO" menu item | ||
| 97 | ;; + the TODO menu can now list occurrences of a specific TODO keyword | ||
| 98 | ;; + #+STARTUP line is now recognized | ||
| 99 | ;; | ||
| 100 | ;; Version 0.19 | ||
| 101 | ;; + added support for dragging URLs to the org-buffer | ||
| 102 | ;; | ||
| 103 | ;; Version 0.18 | ||
| 104 | ;; + added support for agenda blocks | ||
| 105 | ;; | ||
| 106 | ;; Version 0.17 | ||
| 107 | ;; + toggle checkboxes with a single click | ||
| 108 | ;; | ||
| 109 | ;; Version 0.16 | ||
| 110 | ;; + added support for checkboxes | ||
| 111 | ;; | ||
| 112 | ;; Version 0.15 | ||
| 113 | ;; + org-mode now works with the Agenda buffer as well | ||
| 114 | ;; | ||
| 115 | ;; Version 0.14 | ||
| 116 | ;; + added a menu option that converts plain list items to outline items | ||
| 117 | ;; | ||
| 118 | ;; Version 0.13 | ||
| 119 | ;; + "Insert Heading" now inserts a sibling heading if the point is | ||
| 120 | ;; on "***" and a child heading otherwise | ||
| 121 | ;; | ||
| 122 | ;; Version 0.12 | ||
| 123 | ;; + compatible with Emacs 21 | ||
| 124 | ;; + custom agenda commands added to the main menu | ||
| 125 | ;; + moving trees should now work between windows in the same frame | ||
| 126 | ;; | ||
| 127 | ;; Version 0.11 | ||
| 128 | ;; + fixed org-mouse-at-link (thanks to Carsten) | ||
| 129 | ;; + removed [follow-link] bindings | ||
| 130 | ;; | ||
| 131 | ;; Version 0.10 | ||
| 132 | ;; + added a menu option to remove highlights | ||
| 133 | ;; + compatible with org-mode 4.21 now | ||
| 134 | ;; | ||
| 135 | ;; Version 0.08: | ||
| 136 | ;; + trees can be moved/promoted/demoted by dragging with the right | ||
| 137 | ;; mouse button (mouse-3) | ||
| 138 | ;; + small changes in the above function | ||
| 139 | ;; | ||
| 140 | ;; Versions 0.01 -- 0.07: (I don't remember) | ||
| 141 | |||
| 142 | (eval-when-compile (require 'cl)) | ||
| 143 | (require 'org) | ||
| 144 | |||
| 145 | (defvar org-mouse-plain-list-regexp "\\([ \t]*\\)\\([-+*]\\|[0-9]+[.)]\\) " | ||
| 146 | "Regular expression that matches a plain list.") | ||
| 147 | (defvar org-mouse-direct t | ||
| 148 | "Internal variable indicating whether the current action is direct. | ||
| 149 | |||
| 150 | If t, then the current action has been invoked directly through the buffer | ||
| 151 | it is intended to operate on. If nil, then the action has been invoked | ||
| 152 | indirectly, for example, through the agenda buffer.") | ||
| 153 | |||
| 154 | (defgroup org-mouse nil | ||
| 155 | "Mouse support for org-mode." | ||
| 156 | :tag "Org Mouse" | ||
| 157 | :group 'org) | ||
| 158 | |||
| 159 | (defcustom org-mouse-punctuation ":" | ||
| 160 | "Punctuation used when inserting text by drag and drop." | ||
| 161 | :group 'org-mouse | ||
| 162 | :type 'string) | ||
| 163 | |||
| 164 | |||
| 165 | (defun org-mouse-re-search-line (regexp) | ||
| 166 | "Search the current line for a given regular expression." | ||
| 167 | (beginning-of-line) | ||
| 168 | (re-search-forward regexp (point-at-eol) t)) | ||
| 169 | |||
| 170 | (defun org-mouse-end-headline () | ||
| 171 | "Go to the end of current headline (ignoring tags)." | ||
| 172 | (interactive) | ||
| 173 | (end-of-line) | ||
| 174 | (skip-chars-backward "\t ") | ||
| 175 | (when (looking-back ":[A-Za-z]+:") | ||
| 176 | (skip-chars-backward ":A-Za-z") | ||
| 177 | (skip-chars-backward "\t "))) | ||
| 178 | |||
| 179 | (defvar org-mouse-context-menu-function nil | ||
| 180 | "Function to create the context menu. | ||
| 181 | The value of this variable is the function invoked by | ||
| 182 | `org-mouse-context-menu' as the context menu.") | ||
| 183 | (make-variable-buffer-local 'org-mouse-context-menu-function) | ||
| 184 | |||
| 185 | (defun org-mouse-show-context-menu (event prefix) | ||
| 186 | "Invoke the context menu. | ||
| 187 | |||
| 188 | If the value of `org-mouse-context-menu-function' is a function, then | ||
| 189 | this function is called. Otherwise, the current major mode menu is used." | ||
| 190 | (interactive "@e \nP") | ||
| 191 | (if (and (= (event-click-count event) 1) | ||
| 192 | (or (not mark-active) | ||
| 193 | (sit-for (/ double-click-time 1000.0)))) | ||
| 194 | (progn | ||
| 195 | (select-window (posn-window (event-start event))) | ||
| 196 | (when (not (org-mouse-mark-active)) | ||
| 197 | (goto-char (posn-point (event-start event))) | ||
| 198 | (when (not (eolp)) (save-excursion (run-hooks 'post-command-hook))) | ||
| 199 | (let ((redisplay-dont-pause t)) | ||
| 200 | (sit-for 0))) | ||
| 201 | (if (functionp org-mouse-context-menu-function) | ||
| 202 | (funcall org-mouse-context-menu-function event) | ||
| 203 | (mouse-major-mode-menu event prefix))) | ||
| 204 | (setq this-command 'mouse-save-then-kill) | ||
| 205 | (mouse-save-then-kill event))) | ||
| 206 | |||
| 207 | |||
| 208 | (defun org-mouse-line-position () | ||
| 209 | "Returns `:beginning' or `:middle' or `:end', depending on the point position. | ||
| 210 | |||
| 211 | If the point is at the end of the line, return `:end'. | ||
| 212 | If the point is separated from the beginning of the line only by white | ||
| 213 | space and *'s (`org-mouse-bolp'), return `:beginning'. Otherwise, | ||
| 214 | return `:middle'." | ||
| 215 | (cond | ||
| 216 | ((eolp) :end) | ||
| 217 | ((org-mouse-bolp) :beginning) | ||
| 218 | (t :middle))) | ||
| 219 | |||
| 220 | (defun org-mouse-empty-line () | ||
| 221 | "Return non-nil iff the line contains only white space." | ||
| 222 | (save-excursion (beginning-of-line) (looking-at "[ \t]*$"))) | ||
| 223 | |||
| 224 | (defun org-mouse-next-heading () | ||
| 225 | "Go to the next heading. | ||
| 226 | If there is none, ensure that the point is at the beginning of an empty line." | ||
| 227 | (unless (outline-next-heading) | ||
| 228 | (beginning-of-line) | ||
| 229 | (unless (org-mouse-empty-line) | ||
| 230 | (end-of-line) | ||
| 231 | (newline)))) | ||
| 232 | |||
| 233 | (defun org-mouse-insert-heading () | ||
| 234 | "Insert a new heading, as `org-insert-heading'. | ||
| 235 | |||
| 236 | If the point is at the :beginning (`org-mouse-line-position') of the line, | ||
| 237 | insert the new heading before the current line. Otherwise, insert it | ||
| 238 | after the current heading." | ||
| 239 | (interactive) | ||
| 240 | (case (org-mouse-line-position) | ||
| 241 | (:beginning (beginning-of-line) | ||
| 242 | (org-insert-heading)) | ||
| 243 | (t (org-mouse-next-heading) | ||
| 244 | (org-insert-heading)))) | ||
| 245 | |||
| 246 | (defun org-mouse-timestamp-today (&optional shift units) | ||
| 247 | "Change the timestamp into SHIFT UNITS in the future. | ||
| 248 | |||
| 249 | For the acceptable UNITS, see `org-timestamp-change'." | ||
| 250 | (interactive) | ||
| 251 | (flet ((org-read-date (&rest rest) (current-time))) | ||
| 252 | (org-time-stamp nil)) | ||
| 253 | (when shift | ||
| 254 | (org-timestamp-change shift units))) | ||
| 255 | |||
| 256 | (defun org-mouse-keyword-menu (keywords function &optional selected itemformat) | ||
| 257 | "A helper function. | ||
| 258 | |||
| 259 | Returns a menu fragment consisting of KEYWORDS. When a keyword | ||
| 260 | is selected by the user, FUNCTION is called with the selected | ||
| 261 | keyword as the only argument. | ||
| 262 | |||
| 263 | If SELECTED is nil, then all items are normal menu items. If | ||
| 264 | SELECTED is a function, then each item is a checkbox, which is | ||
| 265 | enabled for a given keyword iff (funcall SELECTED keyword) return | ||
| 266 | non-nil. If SELECTED is neither nil nor a function, then the | ||
| 267 | items are radio buttons. A radio button is enabled for the | ||
| 268 | keyword `equal' to SELECTED. | ||
| 269 | |||
| 270 | ITEMFORMAT governs formatting of the elements of KEYWORDS. If it | ||
| 271 | is a function, it is invoked with the keyword as the only | ||
| 272 | argument. If it is a string, it is interpreted as the format | ||
| 273 | string to (format ITEMFORMAT keyword). If it is neither a string | ||
| 274 | nor a function, elements of KEYWORDS are used directly. " | ||
| 275 | (mapcar | ||
| 276 | `(lambda (keyword) | ||
| 277 | (vector (cond | ||
| 278 | ((functionp ,itemformat) (funcall ,itemformat keyword)) | ||
| 279 | ((stringp ,itemformat) (format ,itemformat keyword)) | ||
| 280 | (t keyword)) | ||
| 281 | (list 'funcall ,function keyword) | ||
| 282 | :style (cond | ||
| 283 | ((null ,selected) t) | ||
| 284 | ((functionp ,selected) 'toggle) | ||
| 285 | (t 'radio)) | ||
| 286 | :selected (if (functionp ,selected) | ||
| 287 | (and (funcall ,selected keyword) t) | ||
| 288 | (equal ,selected keyword)))) | ||
| 289 | keywords)) | ||
| 290 | |||
| 291 | (defun org-mouse-remove-match-and-spaces () | ||
| 292 | "Remove the match, make just one space around the point." | ||
| 293 | (interactive) | ||
| 294 | (replace-match "") | ||
| 295 | (just-one-space)) | ||
| 296 | |||
| 297 | (defvar rest) | ||
| 298 | (defun org-mouse-replace-match-and-surround (newtext &optional fixedcase | ||
| 299 | literal string subexp) | ||
| 300 | "The same as `replace-match', but surrounds the replacement with spaces." | ||
| 301 | (apply 'replace-match rest) | ||
| 302 | (save-excursion | ||
| 303 | (goto-char (match-beginning (or subexp 0))) | ||
| 304 | (just-one-space) | ||
| 305 | (goto-char (match-end (or subexp 0))) | ||
| 306 | (just-one-space))) | ||
| 307 | |||
| 308 | |||
| 309 | (defun org-mouse-keyword-replace-menu (keywords &optional group itemformat | ||
| 310 | nosurround) | ||
| 311 | "A helper function. | ||
| 312 | |||
| 313 | Returns a menu fragment consisting of KEYWORDS. When a keyword | ||
| 314 | is selected, group GROUP of the current match is replaced by the | ||
| 315 | keyword. The method ensures that both ends of the replacement | ||
| 316 | are separated from the rest of the text in the buffer by | ||
| 317 | individual spaces (unless NOSURROND is non-nil). | ||
| 318 | |||
| 319 | The final entry of the menu is always \"None\", which removes the | ||
| 320 | match. | ||
| 321 | |||
| 322 | ITEMFORMAT governs formatting of the elements of KEYWORDS. If it | ||
| 323 | is a function, it is invoked with the keyword as the only | ||
| 324 | argument. If it is a string, it is interpreted as the format | ||
| 325 | string to (format ITEMFORMAT keyword). If it is neither a string | ||
| 326 | nor a function, elements of KEYWORDS are used directly. | ||
| 327 | " | ||
| 328 | (setq group (or group 0)) | ||
| 329 | (let ((replace (org-mouse-match-closure | ||
| 330 | (if nosurround 'replace-match | ||
| 331 | 'org-mouse-replace-match-and-surround)))) | ||
| 332 | (append | ||
| 333 | (org-mouse-keyword-menu | ||
| 334 | keywords | ||
| 335 | `(lambda (keyword) (funcall ,replace keyword t t nil ,group)) | ||
| 336 | (match-string group) | ||
| 337 | itemformat) | ||
| 338 | `(["None" org-mouse-remove-match-and-spaces | ||
| 339 | :style radio | ||
| 340 | :selected ,(not (member (match-string group) keywords))])))) | ||
| 341 | |||
| 342 | (defun org-mouse-show-headlines () | ||
| 343 | "Change the visibility of the current org buffer to only show headlines." | ||
| 344 | (interactive) | ||
| 345 | (let ((this-command 'org-cycle) | ||
| 346 | (last-command 'org-cycle) | ||
| 347 | (org-cycle-global-status nil)) | ||
| 348 | (org-cycle '(4)) | ||
| 349 | (org-cycle '(4)))) | ||
| 350 | |||
| 351 | (defun org-mouse-show-overview () | ||
| 352 | "Change visibility of current org buffer to first-level headlines only." | ||
| 353 | (interactive) | ||
| 354 | (let ((org-cycle-global-status nil)) | ||
| 355 | (org-cycle '(4)))) | ||
| 356 | |||
| 357 | (defun org-mouse-set-priority (priority) | ||
| 358 | "Set the priority of the current headline to PRIORITY." | ||
| 359 | (flet ((read-char-exclusive () priority)) | ||
| 360 | (org-priority))) | ||
| 361 | |||
| 362 | (defvar org-mouse-priority-regexp "\\[#\\([A-Z]\\)\\]" | ||
| 363 | "Regular expression matching the priority indicator. | ||
| 364 | Differs from `org-priority-regexp' in that it doesn't contain the | ||
| 365 | leading '.*?'.") | ||
| 366 | |||
| 367 | (defun org-mouse-get-priority (&optional default) | ||
| 368 | "Return the priority of the current headline. | ||
| 369 | DEFAULT is returned if no priority is given in the headline." | ||
| 370 | (save-excursion | ||
| 371 | (if (org-mouse-re-search-line org-mouse-priority-regexp) | ||
| 372 | (match-string 1) | ||
| 373 | (when default (char-to-string org-default-priority))))) | ||
| 374 | |||
| 375 | ;; (defun org-mouse-at-link () | ||
| 376 | ;; (and (eq (get-text-property (point) 'face) 'org-link) | ||
| 377 | ;; (save-excursion | ||
| 378 | ;; (goto-char (previous-single-property-change (point) 'face)) | ||
| 379 | ;; (or (looking-at org-bracket-link-regexp) | ||
| 380 | ;; (looking-at org-angle-link-re) | ||
| 381 | ;; (looking-at org-plain-link-re))))) | ||
| 382 | |||
| 383 | |||
| 384 | (defun org-mouse-delete-timestamp () | ||
| 385 | "Deletes the current timestamp as well as the preceding keyword. | ||
| 386 | SCHEDULED: or DEADLINE: or ANYTHINGLIKETHIS:" | ||
| 387 | (when (or (org-at-date-range-p) (org-at-timestamp-p)) | ||
| 388 | (replace-match "") ; delete the timestamp | ||
| 389 | (skip-chars-backward " :A-Z") | ||
| 390 | (when (looking-at " *[A-Z][A-Z]+:") | ||
| 391 | (replace-match "")))) | ||
| 392 | |||
| 393 | (defun org-mouse-looking-at (regexp skipchars &optional movechars) | ||
| 394 | (save-excursion | ||
| 395 | (let ((point (point))) | ||
| 396 | (if (looking-at regexp) t | ||
| 397 | (skip-chars-backward skipchars) | ||
| 398 | (forward-char (or movechars 0)) | ||
| 399 | (when (looking-at regexp) | ||
| 400 | (> (match-end 0) point)))))) | ||
| 401 | |||
| 402 | (defun org-mouse-priority-list () | ||
| 403 | (loop for priority from ?A to org-lowest-priority | ||
| 404 | collect (char-to-string priority))) | ||
| 405 | |||
| 406 | (defun org-mouse-tag-menu () ;todo | ||
| 407 | (append | ||
| 408 | (let ((tags (org-split-string (org-get-tags) ":"))) | ||
| 409 | (org-mouse-keyword-menu | ||
| 410 | (sort (mapcar 'car (org-get-buffer-tags)) 'string-lessp) | ||
| 411 | `(lambda (tag) | ||
| 412 | (org-mouse-set-tags | ||
| 413 | (sort (if (member tag (quote ,tags)) | ||
| 414 | (delete tag (quote ,tags)) | ||
| 415 | (cons tag (quote ,tags))) | ||
| 416 | 'string-lessp))) | ||
| 417 | `(lambda (tag) (member tag (quote ,tags))) | ||
| 418 | )) | ||
| 419 | '("--" | ||
| 420 | ["Align Tags Here" (org-set-tags nil t) t] | ||
| 421 | ["Align Tags in Buffer" (org-set-tags t t) t] | ||
| 422 | ["Set Tags ..." (org-set-tags) t]))) | ||
| 423 | |||
| 424 | |||
| 425 | |||
| 426 | (defun org-mouse-set-tags (tags) | ||
| 427 | (save-excursion | ||
| 428 | ;; remove existing tags first | ||
| 429 | (beginning-of-line) | ||
| 430 | (when (org-mouse-re-search-line ":\\(\\([A-Za-z_]+:\\)+\\)") | ||
| 431 | (replace-match "")) | ||
| 432 | |||
| 433 | ;; set new tags if any | ||
| 434 | (when tags | ||
| 435 | (end-of-line) | ||
| 436 | (insert " :" (mapconcat 'identity tags ":") ":") | ||
| 437 | (org-set-tags nil t)))) | ||
| 438 | |||
| 439 | (defun org-mouse-insert-checkbox () | ||
| 440 | (interactive) | ||
| 441 | (and (org-at-item-p) | ||
| 442 | (goto-char (match-end 0)) | ||
| 443 | (unless (org-at-item-checkbox-p) | ||
| 444 | (delete-horizontal-space) | ||
| 445 | (insert " [ ] ")))) | ||
| 446 | |||
| 447 | (defun org-mouse-agenda-type (type) | ||
| 448 | (case type | ||
| 449 | ('tags "Tags: ") | ||
| 450 | ('todo "TODO: ") | ||
| 451 | ('tags-tree "Tags tree: ") | ||
| 452 | ('todo-tree "TODO tree: ") | ||
| 453 | ('occur-tree "Occur tree: ") | ||
| 454 | (t "Agenda command ???"))) | ||
| 455 | |||
| 456 | |||
| 457 | (defun org-mouse-list-options-menu (alloptions &optional function) | ||
| 458 | (let ((options (save-match-data | ||
| 459 | (split-string (match-string-no-properties 1))))) | ||
| 460 | (print options) | ||
| 461 | (loop for name in alloptions | ||
| 462 | collect | ||
| 463 | (vector name | ||
| 464 | `(progn | ||
| 465 | (replace-match | ||
| 466 | (mapconcat 'identity | ||
| 467 | (sort (if (member ',name ',options) | ||
| 468 | (delete ',name ',options) | ||
| 469 | (cons ',name ',options)) | ||
| 470 | 'string-lessp) | ||
| 471 | " ") | ||
| 472 | nil nil nil 1) | ||
| 473 | (when (functionp ',function) (funcall ',function))) | ||
| 474 | :style 'toggle | ||
| 475 | :selected (and (member name options) t))))) | ||
| 476 | |||
| 477 | (defun org-mouse-clip-text (text maxlength) | ||
| 478 | (if (> (length text) maxlength) | ||
| 479 | (concat (substring text 0 (- maxlength 3)) "...") | ||
| 480 | text)) | ||
| 481 | |||
| 482 | (defun org-mouse-popup-global-menu () | ||
| 483 | (popup-menu | ||
| 484 | `("Main Menu" | ||
| 485 | ["Show Overview" org-mouse-show-overview t] | ||
| 486 | ["Show Headlines" org-mouse-show-headlines t] | ||
| 487 | ["Show All" show-all t] | ||
| 488 | ["Remove Highlights" org-remove-occur-highlights | ||
| 489 | :visible org-occur-highlights] | ||
| 490 | "--" | ||
| 491 | ["Check Deadlines" | ||
| 492 | (if (functionp 'org-check-deadlines-and-todos) | ||
| 493 | (org-check-deadlines-and-todos org-deadline-warning-days) | ||
| 494 | (org-check-deadlines org-deadline-warning-days)) t] | ||
| 495 | ["Check TODOs" org-show-todo-tree t] | ||
| 496 | ("Check Tags" | ||
| 497 | ,@(org-mouse-keyword-menu | ||
| 498 | (sort (mapcar 'car (org-get-buffer-tags)) 'string-lessp) | ||
| 499 | '(lambda (tag) (org-tags-sparse-tree nil tag))) | ||
| 500 | "--" | ||
| 501 | ["Custom Tag ..." org-tags-sparse-tree t]) | ||
| 502 | ["Check Phrase ..." org-occur] | ||
| 503 | "--" | ||
| 504 | ["Display Agenda" org-agenda-list t] | ||
| 505 | ["Display Timeline" org-timeline t] | ||
| 506 | ["Display TODO List" org-todo-list t] | ||
| 507 | ("Display Tags" | ||
| 508 | ,@(org-mouse-keyword-menu | ||
| 509 | (sort (mapcar 'car (org-get-buffer-tags)) 'string-lessp) | ||
| 510 | '(lambda (tag) (org-tags-view nil tag))) | ||
| 511 | "--" | ||
| 512 | ["Custom Tag ..." org-tags-view t]) | ||
| 513 | ["Display Calendar" org-goto-calendar t] | ||
| 514 | "--" | ||
| 515 | ,@(org-mouse-keyword-menu | ||
| 516 | (mapcar 'car org-agenda-custom-commands) | ||
| 517 | '(lambda (key) | ||
| 518 | (eval `(flet ((read-char-exclusive () (string-to-char ,key))) | ||
| 519 | (org-agenda nil)))) | ||
| 520 | nil | ||
| 521 | '(lambda (key) | ||
| 522 | (let ((entry (assoc key org-agenda-custom-commands))) | ||
| 523 | (org-mouse-clip-text | ||
| 524 | (cond | ||
| 525 | ((stringp (nth 1 entry)) (nth 1 entry)) | ||
| 526 | ((stringp (nth 2 entry)) | ||
| 527 | (concat (org-mouse-agenda-type (nth 1 entry)) | ||
| 528 | (nth 2 entry))) | ||
| 529 | (t "Agenda Command '%s'")) | ||
| 530 | 30)))) | ||
| 531 | "--" | ||
| 532 | ["Delete Blank Lines" delete-blank-lines | ||
| 533 | :visible (org-mouse-empty-line)] | ||
| 534 | ["Insert Checkbox" org-mouse-insert-checkbox | ||
| 535 | :visible (and (org-at-item-p) (not (org-at-item-checkbox-p)))] | ||
| 536 | ["Insert Checkboxes" | ||
| 537 | (org-mouse-for-each-item 'org-mouse-insert-checkbox) | ||
| 538 | :visible (and (org-at-item-p) (not (org-at-item-checkbox-p)))] | ||
| 539 | ["Plain List to Outline" org-mouse-transform-to-outline | ||
| 540 | :visible (org-at-item-p)]))) | ||
| 541 | |||
| 542 | |||
| 543 | (defun org-mouse-get-context (contextlist context) | ||
| 544 | (let ((contextdata (assq context contextlist))) | ||
| 545 | (when contextdata | ||
| 546 | (save-excursion | ||
| 547 | (goto-char (second contextdata)) | ||
| 548 | (re-search-forward ".*" (third contextdata)))))) | ||
| 549 | |||
| 550 | (defun org-mouse-for-each-item (function) | ||
| 551 | (save-excursion | ||
| 552 | (ignore-errors | ||
| 553 | (while t (org-previous-item))) | ||
| 554 | (ignore-errors | ||
| 555 | (while t | ||
| 556 | (funcall function) | ||
| 557 | (org-next-item))))) | ||
| 558 | |||
| 559 | (defun org-mouse-bolp () | ||
| 560 | "Returns true if there only spaces, tabs, and '*', between the beginning of line and the point" | ||
| 561 | (save-excursion | ||
| 562 | (skip-chars-backward " \t*") (bolp))) | ||
| 563 | |||
| 564 | (defun org-mouse-insert-item (text) | ||
| 565 | (case (org-mouse-line-position) | ||
| 566 | (:beginning ; insert before | ||
| 567 | (beginning-of-line) | ||
| 568 | (looking-at "[ \t]*") | ||
| 569 | (open-line 1) | ||
| 570 | (indent-to (- (match-end 0) (match-beginning 0))) | ||
| 571 | (insert "+ ")) | ||
| 572 | |||
| 573 | (:middle ; insert after | ||
| 574 | (end-of-line) | ||
| 575 | (newline t) | ||
| 576 | (indent-relative) | ||
| 577 | (insert "+ ")) | ||
| 578 | |||
| 579 | (:end ; insert text here | ||
| 580 | (skip-chars-backward " \t") | ||
| 581 | (kill-region (point) (point-at-eol)) | ||
| 582 | (unless (looking-back org-mouse-punctuation) | ||
| 583 | (insert (concat org-mouse-punctuation " "))))) | ||
| 584 | |||
| 585 | (insert text) | ||
| 586 | (beginning-of-line)) | ||
| 587 | |||
| 588 | (defadvice dnd-insert-text (around org-mouse-dnd-insert-text activate) | ||
| 589 | (if (eq major-mode 'org-mode) | ||
| 590 | (org-mouse-insert-item text) | ||
| 591 | ad-do-it)) | ||
| 592 | |||
| 593 | (defadvice dnd-open-file (around org-mouse-dnd-open-file activate) | ||
| 594 | (if (eq major-mode 'org-mode) | ||
| 595 | (org-mouse-insert-item uri) | ||
| 596 | ad-do-it)) | ||
| 597 | |||
| 598 | (defun org-mouse-match-closure (function) | ||
| 599 | (let ((match (match-data t))) | ||
| 600 | `(lambda (&rest rest) | ||
| 601 | (save-match-data | ||
| 602 | (set-match-data ',match) | ||
| 603 | (apply ',function rest))))) | ||
| 604 | |||
| 605 | (defun org-mouse-todo-keywords () | ||
| 606 | (if (boundp 'org-todo-keywords-1) org-todo-keywords-1 org-todo-keywords)) | ||
| 607 | |||
| 608 | (defun org-mouse-match-todo-keyword () | ||
| 609 | (save-excursion | ||
| 610 | (org-back-to-heading) | ||
| 611 | (if (looking-at outline-regexp) (goto-char (match-end 0))) | ||
| 612 | (or (looking-at (concat " +" org-todo-regexp " *")) | ||
| 613 | (looking-at " \\( *\\)")))) | ||
| 614 | |||
| 615 | (defun org-mouse-yank-link (click) | ||
| 616 | (interactive "e") | ||
| 617 | ;; Give temporary modes such as isearch a chance to turn off. | ||
| 618 | (run-hooks 'mouse-leave-buffer-hook) | ||
| 619 | (mouse-set-point click) | ||
| 620 | (setq mouse-selection-click-count 0) | ||
| 621 | (delete-horizontal-space) | ||
| 622 | (insert-for-yank (concat " [[" (current-kill 0) "]] "))) | ||
| 623 | |||
| 624 | (defun org-mouse-context-menu (&optional event) | ||
| 625 | (let ((stamp-prefixes (list org-deadline-string org-scheduled-string)) | ||
| 626 | (contextlist (org-context))) | ||
| 627 | (flet ((get-context (context) (org-mouse-get-context contextlist context))) | ||
| 628 | (cond | ||
| 629 | ((org-mouse-mark-active) | ||
| 630 | (let ((region-string (buffer-substring (region-beginning) (region-end)))) | ||
| 631 | (popup-menu | ||
| 632 | `(nil | ||
| 633 | ["Sparse Tree" (org-occur ',region-string)] | ||
| 634 | ["Find in Buffer" (occur ',region-string)] | ||
| 635 | ["Grep in Current Dir" | ||
| 636 | (grep (format "grep -rnH -e '%s' *" ',region-string))] | ||
| 637 | ["Grep in Parent Dir" | ||
| 638 | (grep (format "grep -rnH -e '%s' ../*" ',region-string))] | ||
| 639 | "--" | ||
| 640 | ["Convert to Link" | ||
| 641 | (progn (save-excursion (goto-char (region-beginning)) (insert "[[")) | ||
| 642 | (save-excursion (goto-char (region-end)) (insert "]]")))] | ||
| 643 | ["Insert Link Here" (org-mouse-yank-link ',event)])))) | ||
| 644 | |||
| 645 | ((save-excursion (beginning-of-line) (looking-at "#\\+STARTUP: \\(.*\\)")) | ||
| 646 | (popup-menu | ||
| 647 | `(nil | ||
| 648 | ,@(org-mouse-list-options-menu (mapcar 'car org-startup-options) | ||
| 649 | 'org-mode-restart)))) | ||
| 650 | ((or (eolp) | ||
| 651 | (and (looking-at "\\( \\|\t\\)\\(+:[0-9a-zA-Z_:]+\\)?\\( \\|\t\\)+$") | ||
| 652 | (looking-back " \\|\t"))) | ||
| 653 | (org-mouse-popup-global-menu)) | ||
| 654 | ((get-context :checkbox) | ||
| 655 | (popup-menu | ||
| 656 | '(nil | ||
| 657 | ["Toggle" org-toggle-checkbox t] | ||
| 658 | ["Remove" org-mouse-remove-match-and-spaces t] | ||
| 659 | "" | ||
| 660 | ["All Clear" (org-mouse-for-each-item | ||
| 661 | (lambda () | ||
| 662 | (when (save-excursion (org-at-item-checkbox-p)) | ||
| 663 | (replace-match "[ ]"))))] | ||
| 664 | ["All Set" (org-mouse-for-each-item | ||
| 665 | (lambda () | ||
| 666 | (when (save-excursion (org-at-item-checkbox-p)) | ||
| 667 | (replace-match "[X]"))))] | ||
| 668 | ["All Toggle" (org-mouse-for-each-item 'org-toggle-checkbox) t] | ||
| 669 | ["All Remove" (org-mouse-for-each-item | ||
| 670 | (lambda () | ||
| 671 | (when (save-excursion (org-at-item-checkbox-p)) | ||
| 672 | (org-mouse-remove-match-and-spaces))))] | ||
| 673 | ))) | ||
| 674 | ((and (org-mouse-looking-at "\\b\\w+" "a-zA-Z0-9_") | ||
| 675 | (member (match-string 0) (org-mouse-todo-keywords))) | ||
| 676 | (popup-menu | ||
| 677 | `(nil | ||
| 678 | ,@(org-mouse-keyword-replace-menu (org-mouse-todo-keywords)) | ||
| 679 | "--" | ||
| 680 | ["Check TODOs" org-show-todo-tree t] | ||
| 681 | ["List all TODO keywords" org-todo-list t] | ||
| 682 | [,(format "List only %s" (match-string 0)) | ||
| 683 | (org-todo-list (match-string 0)) t] | ||
| 684 | ))) | ||
| 685 | ((and (org-mouse-looking-at "\\b[A-Z]+:" "A-Z") | ||
| 686 | (member (match-string 0) stamp-prefixes)) | ||
| 687 | (popup-menu | ||
| 688 | `(nil | ||
| 689 | ,@(org-mouse-keyword-replace-menu stamp-prefixes) | ||
| 690 | "--" | ||
| 691 | ["Check Deadlines" org-check-deadlines t] | ||
| 692 | ))) | ||
| 693 | ((org-mouse-looking-at org-mouse-priority-regexp "[]A-Z#") ; priority | ||
| 694 | (popup-menu `(nil ,@(org-mouse-keyword-replace-menu | ||
| 695 | (org-mouse-priority-list) 1 "Priority %s" t)))) | ||
| 696 | ((get-context :link) | ||
| 697 | (popup-menu | ||
| 698 | '(nil | ||
| 699 | ["Open" org-open-at-point t] | ||
| 700 | ["Open in Emacs" (org-open-at-point t) t] | ||
| 701 | "--" | ||
| 702 | ["Copy link" (kill-new (match-string 0))] | ||
| 703 | ["Cut link" | ||
| 704 | (progn | ||
| 705 | (kill-region (match-beginning 0) (match-end 0)) | ||
| 706 | (just-one-space))] | ||
| 707 | "--" | ||
| 708 | ["Grep for TODOs" | ||
| 709 | (grep (format "grep -nH -i 'todo\\|fixme' %s*" (match-string 2)))] | ||
| 710 | ; ["Paste file link" ((insert "file:") (yank))] | ||
| 711 | ))) | ||
| 712 | ((org-mouse-looking-at ":\\([A-Za-z0-9_]+\\):" "A-Za-z0-9_" -1) ;tags | ||
| 713 | (popup-menu | ||
| 714 | `(nil | ||
| 715 | [,(format "Display '%s'" (match-string 1)) | ||
| 716 | (org-tags-view nil ,(match-string 1))] | ||
| 717 | [,(format "Sparse Tree '%s'" (match-string 1)) | ||
| 718 | (org-tags-sparse-tree nil ,(match-string 1))] | ||
| 719 | "--" | ||
| 720 | ,@(org-mouse-tag-menu)))) | ||
| 721 | ((org-at-timestamp-p) | ||
| 722 | (popup-menu | ||
| 723 | '(nil | ||
| 724 | ["Show Day" org-open-at-point t] | ||
| 725 | ["Change Timestamp" org-time-stamp t] | ||
| 726 | ["Delete Timestamp" (org-mouse-delete-timestamp) t] | ||
| 727 | ["Compute Time Range" org-evaluate-time-range (org-at-date-range-p)] | ||
| 728 | "--" | ||
| 729 | ["Set for Today" org-mouse-timestamp-today] | ||
| 730 | ["Set for Tomorrow" (org-mouse-timestamp-today 1 'day)] | ||
| 731 | ["Set in 1 Week" (org-mouse-timestamp-today 7 'day)] | ||
| 732 | ["Set in 2 Weeks" (org-mouse-timestamp-today 14 'day)] | ||
| 733 | ["Set in a Month" (org-mouse-timestamp-today 1 'month)] | ||
| 734 | "--" | ||
| 735 | ["+ 1 Day" (org-timestamp-change 1 'day)] | ||
| 736 | ["+ 1 Week" (org-timestamp-change 7 'day)] | ||
| 737 | ["+ 1 Month" (org-timestamp-change 1 'month)] | ||
| 738 | "--" | ||
| 739 | ["- 1 Day" (org-timestamp-change -1 'day)] | ||
| 740 | ["- 1 Week" (org-timestamp-change -7 'day)] | ||
| 741 | ["- 1 Month" (org-timestamp-change -1 'month)]))) | ||
| 742 | ((get-context :table-special) | ||
| 743 | (let ((mdata (match-data))) | ||
| 744 | (incf (car mdata) 2) | ||
| 745 | (store-match-data mdata)) | ||
| 746 | (message "match: %S" (match-string 0)) | ||
| 747 | (popup-menu `(nil ,@(org-mouse-keyword-replace-menu | ||
| 748 | '(" " "!" "^" "_" "$" "#" "*" "'") 0 | ||
| 749 | (lambda (mark) | ||
| 750 | (case (string-to-char mark) | ||
| 751 | (? "( ) Nothing Special") | ||
| 752 | (?! "(!) Column Names") | ||
| 753 | (?^ "(^) Field Names Above") | ||
| 754 | (?_ "(^) Field Names Below") | ||
| 755 | (?$ "($) Formula Parameters") | ||
| 756 | (?# "(#) Recalculation: Auto") | ||
| 757 | (?* "(*) Recalculation: Manual") | ||
| 758 | (?' "(') Recalculation: None"))) t)))) | ||
| 759 | ((assq :table contextlist) | ||
| 760 | (popup-menu | ||
| 761 | '(nil | ||
| 762 | ["Align Table" org-ctrl-c-ctrl-c] | ||
| 763 | ["Blank Field" org-table-blank-field] | ||
| 764 | ["Edit Field" org-table-edit-field] | ||
| 765 | "--" | ||
| 766 | ("Column" | ||
| 767 | ["Move Column Left" org-metaleft] | ||
| 768 | ["Move Column Right" org-metaright] | ||
| 769 | ["Delete Column" org-shiftmetaleft] | ||
| 770 | ["Insert Column" org-shiftmetaright] | ||
| 771 | "--" | ||
| 772 | ["Enable Narrowing" (setq org-table-limit-column-width (not org-table-limit-column-width)) :selected org-table-limit-column-width :style toggle]) | ||
| 773 | ("Row" | ||
| 774 | ["Move Row Up" org-metaup] | ||
| 775 | ["Move Row Down" org-metadown] | ||
| 776 | ["Delete Row" org-shiftmetaup] | ||
| 777 | ["Insert Row" org-shiftmetadown] | ||
| 778 | ["Sort lines in region" org-table-sort-lines (org-at-table-p)] | ||
| 779 | "--" | ||
| 780 | ["Insert Hline" org-table-insert-hline]) | ||
| 781 | ("Rectangle" | ||
| 782 | ["Copy Rectangle" org-copy-special] | ||
| 783 | ["Cut Rectangle" org-cut-special] | ||
| 784 | ["Paste Rectangle" org-paste-special] | ||
| 785 | ["Fill Rectangle" org-table-wrap-region]) | ||
| 786 | "--" | ||
| 787 | ["Set Column Formula" org-table-eval-formula] | ||
| 788 | ["Set Field Formula" (org-table-eval-formula '(4))] | ||
| 789 | ["Edit Formulas" org-table-edit-formulas] | ||
| 790 | "--" | ||
| 791 | ["Recalculate Line" org-table-recalculate] | ||
| 792 | ["Recalculate All" (org-table-recalculate '(4))] | ||
| 793 | ["Iterate All" (org-table-recalculate '(16))] | ||
| 794 | "--" | ||
| 795 | ["Toggle Recalculate Mark" org-table-rotate-recalc-marks] | ||
| 796 | ["Sum Column/Rectangle" org-table-sum | ||
| 797 | :active (or (org-at-table-p) (org-region-active-p))] | ||
| 798 | ["Field Info" org-table-field-info] | ||
| 799 | ["Debug Formulas" | ||
| 800 | (setq org-table-formula-debug (not org-table-formula-debug)) | ||
| 801 | :style toggle :selected org-table-formula-debug] | ||
| 802 | ))) | ||
| 803 | ((and (assq :headline contextlist) (not (eolp))) | ||
| 804 | (let ((priority (org-mouse-get-priority t))) | ||
| 805 | (popup-menu | ||
| 806 | `("Headline Menu" | ||
| 807 | ("Tags and Priorities" | ||
| 808 | ,@(org-mouse-keyword-menu | ||
| 809 | (org-mouse-priority-list) | ||
| 810 | '(lambda (keyword) | ||
| 811 | (org-mouse-set-priority (string-to-char keyword))) | ||
| 812 | priority "Priority %s") | ||
| 813 | "--" | ||
| 814 | ,@(org-mouse-tag-menu)) | ||
| 815 | ("TODO Status" | ||
| 816 | ,@(progn (org-mouse-match-todo-keyword) | ||
| 817 | (org-mouse-keyword-replace-menu (org-mouse-todo-keywords) | ||
| 818 | 1))) | ||
| 819 | ["Show Tags" | ||
| 820 | (with-current-buffer org-mouse-main-buffer (org-agenda-show-tags)) | ||
| 821 | :visible (not org-mouse-direct)] | ||
| 822 | ["Show Priority" | ||
| 823 | (with-current-buffer org-mouse-main-buffer (org-agenda-show-priority)) | ||
| 824 | :visible (not org-mouse-direct)] | ||
| 825 | ,@(if org-mouse-direct '("--") nil) | ||
| 826 | ["New Heading" org-mouse-insert-heading :visible org-mouse-direct] | ||
| 827 | ["Set Deadline" | ||
| 828 | (progn (org-mouse-end-headline) (insert " ") (org-deadline)) | ||
| 829 | :active (not (save-excursion | ||
| 830 | (org-mouse-re-search-line org-deadline-regexp)))] | ||
| 831 | ["Schedule Task" | ||
| 832 | (progn (org-mouse-end-headline) (insert " ") (org-schedule)) | ||
| 833 | :active (not (save-excursion | ||
| 834 | (org-mouse-re-search-line org-scheduled-regexp)))] | ||
| 835 | ["Insert Timestamp" | ||
| 836 | (progn (org-mouse-end-headline) (insert " ") (org-time-stamp nil)) t] | ||
| 837 | ; ["Timestamp (inactive)" org-time-stamp-inactive t] | ||
| 838 | "--" | ||
| 839 | ["Archive Subtree" org-archive-subtree] | ||
| 840 | ["Cut Subtree" org-cut-special] | ||
| 841 | ["Copy Subtree" org-copy-special] | ||
| 842 | ["Paste Subtree" org-paste-special :visible org-mouse-direct] | ||
| 843 | ("Sort Children" | ||
| 844 | ["Alphabetically" (org-sort-entries nil ?a)] | ||
| 845 | ["Numerically" (org-sort-entries nil ?n)] | ||
| 846 | ["By Time/Date" (org-sort-entries nil ?t)] | ||
| 847 | "--" | ||
| 848 | ["Reverse Alphabetically" (org-sort-entries nil ?A)] | ||
| 849 | ["Reverse Numerically" (org-sort-entries nil ?N)] | ||
| 850 | ["Reverse By Time/Date" (org-sort-entries nil ?T)]) | ||
| 851 | "--" | ||
| 852 | ["Move Trees" org-mouse-move-tree :active nil] | ||
| 853 | )))) | ||
| 854 | (t | ||
| 855 | (org-mouse-popup-global-menu)))))) | ||
| 856 | |||
| 857 | ;; (defun org-mouse-at-regexp (regexp) | ||
| 858 | ;; (save-excursion | ||
| 859 | ;; (let ((point (point)) | ||
| 860 | ;; (bol (progn (beginning-of-line) (point))) | ||
| 861 | ;; (eol (progn (end-of-line) (point)))) | ||
| 862 | ;; (goto-char point) | ||
| 863 | ;; (re-search-backward regexp bol 1) | ||
| 864 | ;; (and (not (eolp)) | ||
| 865 | ;; (progn (forward-char) | ||
| 866 | ;; (re-search-forward regexp eol t)) | ||
| 867 | ;; (<= (match-beginning 0) point))))) | ||
| 868 | |||
| 869 | (defun org-mouse-mark-active () | ||
| 870 | (and mark-active transient-mark-mode)) | ||
| 871 | |||
| 872 | (defun org-mouse-in-region-p (pos) | ||
| 873 | (and (org-mouse-mark-active) | ||
| 874 | (>= pos (region-beginning)) | ||
| 875 | (< pos (region-end)))) | ||
| 876 | |||
| 877 | (defun org-mouse-down-mouse (event) | ||
| 878 | (interactive "e") | ||
| 879 | (setq this-command last-command) | ||
| 880 | (unless (and (= 1 (event-click-count event)) | ||
| 881 | (org-mouse-in-region-p (posn-point (event-start event)))) | ||
| 882 | (mouse-drag-region event))) | ||
| 883 | |||
| 884 | (add-hook 'org-mode-hook | ||
| 885 | '(lambda () | ||
| 886 | (setq org-mouse-context-menu-function 'org-mouse-context-menu) | ||
| 887 | |||
| 888 | ; (define-key org-mouse-map [follow-link] 'mouse-face) | ||
| 889 | (define-key org-mouse-map (if (featurep 'xemacs) [button3] [mouse-3]) nil) | ||
| 890 | (define-key org-mode-map [mouse-3] 'org-mouse-show-context-menu) | ||
| 891 | (define-key org-mode-map [down-mouse-1] 'org-mouse-down-mouse) | ||
| 892 | (define-key org-mouse-map [C-drag-mouse-1] 'org-mouse-move-tree) | ||
| 893 | (define-key org-mouse-map [C-down-mouse-1] 'org-mouse-move-tree-start) | ||
| 894 | (define-key org-mode-map [S-mouse-2] 'org-mouse-yank-link) | ||
| 895 | (define-key org-mode-map [drag-mouse-3] 'org-mouse-yank-link) | ||
| 896 | (define-key org-mouse-map [drag-mouse-3] 'org-mouse-move-tree) | ||
| 897 | (define-key org-mouse-map [down-mouse-3] 'org-mouse-move-tree-start) | ||
| 898 | |||
| 899 | (font-lock-add-keywords nil | ||
| 900 | `((,outline-regexp | ||
| 901 | 0 `(face org-link mouse-face highlight keymap ,org-mouse-map) | ||
| 902 | 'prepend) | ||
| 903 | ("^[ \t]*\\([-+*]\\|[0-9]+[.)]\\) +" | ||
| 904 | (1 `(face org-link keymap ,org-mouse-map mouse-face highlight) 'prepend)) | ||
| 905 | ("^[ \t]*\\([-+*]\\|[0-9]+[.)]\\) +\\(\\[[ X]\\]\\)" | ||
| 906 | (2 `(face bold keymap ,org-mouse-map mouse-face highlight) t))) | ||
| 907 | t) | ||
| 908 | |||
| 909 | (defadvice org-open-at-point (around org-mouse-open-at-point activate) | ||
| 910 | (let ((context (org-context))) | ||
| 911 | (cond | ||
| 912 | ((assq :headline-stars context) (org-cycle)) | ||
| 913 | ((assq :checkbox context) (org-toggle-checkbox)) | ||
| 914 | ((assq :item-bullet context) | ||
| 915 | (let ((org-cycle-include-plain-lists t)) (org-cycle))) | ||
| 916 | (t ad-do-it)))))) | ||
| 917 | |||
| 918 | (defun org-mouse-move-tree-start (event) | ||
| 919 | (interactive "e") | ||
| 920 | (message "Same line: promote/demote, (***):move before, (text): make a child")) | ||
| 921 | |||
| 922 | |||
| 923 | (defun org-mouse-make-marker (position) | ||
| 924 | (with-current-buffer (window-buffer (posn-window position)) | ||
| 925 | (copy-marker (posn-point position)))) | ||
| 926 | |||
| 927 | (defun org-mouse-move-tree (event) | ||
| 928 | ;; todo: handle movements between different buffers | ||
| 929 | (interactive "e") | ||
| 930 | (save-excursion | ||
| 931 | (let* ((start (org-mouse-make-marker (event-start event))) | ||
| 932 | (end (org-mouse-make-marker (event-end event))) | ||
| 933 | (sbuf (marker-buffer start)) | ||
| 934 | (ebuf (marker-buffer end))) | ||
| 935 | |||
| 936 | (when (and sbuf ebuf) | ||
| 937 | (set-buffer sbuf) | ||
| 938 | (goto-char start) | ||
| 939 | (org-back-to-heading) | ||
| 940 | (if (and (eq sbuf ebuf) | ||
| 941 | (equal | ||
| 942 | (point) | ||
| 943 | (save-excursion (goto-char end) (org-back-to-heading) (point)))) | ||
| 944 | ;; if the same line then promote/demote | ||
| 945 | (if (>= end start) (org-demote-subtree) (org-promote-subtree)) | ||
| 946 | ;; if different lines then move | ||
| 947 | (org-cut-subtree) | ||
| 948 | |||
| 949 | (set-buffer ebuf) | ||
| 950 | (goto-char end) | ||
| 951 | (org-back-to-heading) | ||
| 952 | (when (and (eq sbuf ebuf) | ||
| 953 | (equal | ||
| 954 | (point) | ||
| 955 | (save-excursion (goto-char start) | ||
| 956 | (org-back-to-heading) (point)))) | ||
| 957 | (outline-end-of-subtree) | ||
| 958 | (end-of-line) | ||
| 959 | (if (eobp) (newline) (forward-char))) | ||
| 960 | |||
| 961 | (when (looking-at outline-regexp) | ||
| 962 | (let ((level (- (match-end 0) (match-beginning 0)))) | ||
| 963 | (when (> end (match-end 0)) | ||
| 964 | (outline-end-of-subtree) | ||
| 965 | (end-of-line) | ||
| 966 | (if (eobp) (newline) (forward-char)) | ||
| 967 | (setq level (1+ level))) | ||
| 968 | (org-paste-subtree level) | ||
| 969 | (save-excursion | ||
| 970 | (outline-end-of-subtree) | ||
| 971 | (when (bolp) (delete-char -1)))))))))) | ||
| 972 | |||
| 973 | |||
| 974 | (defun org-mouse-transform-to-outline () | ||
| 975 | (interactive) | ||
| 976 | (org-back-to-heading) | ||
| 977 | (let ((minlevel 1000) | ||
| 978 | (replace-text (concat (match-string 0) "* "))) | ||
| 979 | (beginning-of-line 2) | ||
| 980 | (save-excursion | ||
| 981 | (while (not (or (eobp) (looking-at outline-regexp))) | ||
| 982 | (when (looking-at org-mouse-plain-list-regexp) | ||
| 983 | (setq minlevel (min minlevel (- (match-end 1) (match-beginning 1))))) | ||
| 984 | (forward-line))) | ||
| 985 | (while (not (or (eobp) (looking-at outline-regexp))) | ||
| 986 | (when (and (looking-at org-mouse-plain-list-regexp) | ||
| 987 | (eq minlevel (- (match-end 1) (match-beginning 1)))) | ||
| 988 | (replace-match replace-text)) | ||
| 989 | (forward-line)))) | ||
| 990 | |||
| 991 | (defvar _cmd) ;dynamically scoped from `org-with-remote-undo'. | ||
| 992 | |||
| 993 | (defun org-mouse-do-remotely (command) | ||
| 994 | ; (org-agenda-check-no-diary) | ||
| 995 | (when (get-text-property (point) 'org-marker) | ||
| 996 | (let* ((anticol (- (point-at-eol) (point))) | ||
| 997 | (marker (get-text-property (point) 'org-marker)) | ||
| 998 | (buffer (marker-buffer marker)) | ||
| 999 | (pos (marker-position marker)) | ||
| 1000 | (hdmarker (get-text-property (point) 'org-hd-marker)) | ||
| 1001 | (buffer-read-only nil) | ||
| 1002 | (newhead "--- removed ---") | ||
| 1003 | (org-mouse-direct nil) | ||
| 1004 | (org-mouse-main-buffer (current-buffer))) | ||
| 1005 | (when (eq (with-current-buffer buffer major-mode) 'org-mode) | ||
| 1006 | (let ((endmarker (save-excursion | ||
| 1007 | (set-buffer buffer) | ||
| 1008 | (outline-end-of-subtree) | ||
| 1009 | (forward-char 1) | ||
| 1010 | (copy-marker (point))))) | ||
| 1011 | (org-with-remote-undo buffer | ||
| 1012 | (with-current-buffer buffer | ||
| 1013 | (widen) | ||
| 1014 | (goto-char pos) | ||
| 1015 | (org-show-hidden-entry) | ||
| 1016 | (save-excursion | ||
| 1017 | (and (outline-next-heading) | ||
| 1018 | (org-flag-heading nil))) ; show the next heading | ||
| 1019 | (org-back-to-heading) | ||
| 1020 | (setq marker (copy-marker (point))) | ||
| 1021 | (goto-char (max (point-at-bol) (- (point-at-eol) anticol))) | ||
| 1022 | (funcall command) | ||
| 1023 | (message "_cmd: %S" _cmd) | ||
| 1024 | (message "this-command: %S" this-command) | ||
| 1025 | (unless (eq (marker-position marker) (marker-position endmarker)) | ||
| 1026 | (setq newhead (org-get-heading)))) | ||
| 1027 | |||
| 1028 | (beginning-of-line 1) | ||
| 1029 | (save-excursion | ||
| 1030 | (org-agenda-change-all-lines newhead hdmarker 'fixface)))) | ||
| 1031 | t)))) | ||
| 1032 | |||
| 1033 | (defun org-mouse-agenda-context-menu (&optional event) | ||
| 1034 | (or (org-mouse-do-remotely 'org-mouse-context-menu) | ||
| 1035 | (popup-menu | ||
| 1036 | '("Agenda" | ||
| 1037 | ("Agenda Files") | ||
| 1038 | "--" | ||
| 1039 | ["Undo" (progn (message "last command: %S" last-command) (setq this-command 'org-agenda-undo) (org-agenda-undo)) | ||
| 1040 | :visible (if (eq last-command 'org-agenda-undo) | ||
| 1041 | org-agenda-pending-undo-list | ||
| 1042 | org-agenda-undo-list)] | ||
| 1043 | ["Rebuild Buffer" org-agenda-redo t] | ||
| 1044 | ["New Diary Entry" | ||
| 1045 | org-agenda-diary-entry (org-agenda-check-type nil 'agenda 'timeline) t] | ||
| 1046 | "--" | ||
| 1047 | ["Goto Today" org-agenda-goto-today | ||
| 1048 | (org-agenda-check-type nil 'agenda 'timeline) t] | ||
| 1049 | ["Display Calendar" org-agenda-goto-calendar | ||
| 1050 | (org-agenda-check-type nil 'agenda 'timeline) t] | ||
| 1051 | ("Calendar Commands" | ||
| 1052 | ["Phases of the Moon" org-agenda-phases-of-moon | ||
| 1053 | (org-agenda-check-type nil 'agenda 'timeline)] | ||
| 1054 | ["Sunrise/Sunset" org-agenda-sunrise-sunset | ||
| 1055 | (org-agenda-check-type nil 'agenda 'timeline)] | ||
| 1056 | ["Holidays" org-agenda-holidays | ||
| 1057 | (org-agenda-check-type nil 'agenda 'timeline)] | ||
| 1058 | ["Convert" org-agenda-convert-date | ||
| 1059 | (org-agenda-check-type nil 'agenda 'timeline)] | ||
| 1060 | "--" | ||
| 1061 | ["Create iCalendar file" org-export-icalendar-combine-agenda-files t]) | ||
| 1062 | "--" | ||
| 1063 | ["Day View" org-agenda-day-view | ||
| 1064 | :active (org-agenda-check-type nil 'agenda) | ||
| 1065 | :style radio :selected (equal org-agenda-ndays 1)] | ||
| 1066 | ["Week View" org-agenda-week-view | ||
| 1067 | :active (org-agenda-check-type nil 'agenda) | ||
| 1068 | :style radio :selected (equal org-agenda-ndays 7)] | ||
| 1069 | "--" | ||
| 1070 | ["Show Logbook entries" org-agenda-log-mode | ||
| 1071 | :style toggle :selected org-agenda-show-log | ||
| 1072 | :active (org-agenda-check-type nil 'agenda 'timeline)] | ||
| 1073 | ["Include Diary" org-agenda-toggle-diary | ||
| 1074 | :style toggle :selected org-agenda-include-diary | ||
| 1075 | :active (org-agenda-check-type nil 'agenda)] | ||
| 1076 | ["Use Time Grid" org-agenda-toggle-time-grid | ||
| 1077 | :style toggle :selected org-agenda-use-time-grid | ||
| 1078 | :active (org-agenda-check-type nil 'agenda)] | ||
| 1079 | ["Follow Mode" org-agenda-follow-mode | ||
| 1080 | :style toggle :selected org-agenda-follow-mode] | ||
| 1081 | "--" | ||
| 1082 | ["Quit" org-agenda-quit t] | ||
| 1083 | ["Exit and Release Buffers" org-agenda-exit t] | ||
| 1084 | )))) | ||
| 1085 | |||
| 1086 | (defun org-mouse-get-gesture (event) | ||
| 1087 | (let ((startxy (posn-x-y (event-start event))) | ||
| 1088 | (endxy (posn-x-y (event-end event)))) | ||
| 1089 | (if (< (car startxy) (car endxy)) :right :left))) | ||
| 1090 | |||
| 1091 | |||
| 1092 | ; (setq org-agenda-mode-hook nil) | ||
| 1093 | (add-hook 'org-agenda-mode-hook | ||
| 1094 | '(lambda () | ||
| 1095 | (setq org-mouse-context-menu-function 'org-mouse-agenda-context-menu) | ||
| 1096 | (define-key org-agenda-keymap | ||
| 1097 | (if (featurep 'xemacs) [button3] [mouse-3]) | ||
| 1098 | 'org-mouse-show-context-menu) | ||
| 1099 | (define-key org-agenda-keymap [down-mouse-3] 'org-mouse-move-tree-start) | ||
| 1100 | (define-key org-agenda-keymap [C-mouse-4] 'org-agenda-earlier) | ||
| 1101 | (define-key org-agenda-keymap [C-mouse-5] 'org-agenda-later) | ||
| 1102 | (define-key org-agenda-keymap [drag-mouse-3] | ||
| 1103 | '(lambda (event) (interactive "e") | ||
| 1104 | (case (org-mouse-get-gesture event) | ||
| 1105 | (:left (org-agenda-earlier 1)) | ||
| 1106 | (:right (org-agenda-later 1))))))) | ||
| 1107 | |||
| 1108 | (provide 'org-mouse) | ||
| 1109 | |||
| 1110 | ;; arch-tag: ff1ae557-3529-41a3-95c6-baaebdcc280f | ||
diff --git a/lisp/textmodes/org-publish.el b/lisp/textmodes/org-publish.el deleted file mode 100644 index d881fd4a062..00000000000 --- a/lisp/textmodes/org-publish.el +++ /dev/null | |||
| @@ -1,661 +0,0 @@ | |||
| 1 | ;;; org-publish.el --- publish related org-mode files as a website | ||
| 2 | |||
| 3 | ;; Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: David O'Toole <dto@gnu.org> | ||
| 6 | ;; Maintainer: Bastien Guerry <bzg AT altern DOT org> | ||
| 7 | ;; Keywords: hypermedia, outlines, wp | ||
| 8 | ;; Version: 5.23a | ||
| 9 | |||
| 10 | ;; This file is part of GNU Emacs. | ||
| 11 | ;; | ||
| 12 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 13 | ;; it under the terms of the GNU General Public License as published by | ||
| 14 | ;; the Free Software Foundation; either version 3, or (at your option) | ||
| 15 | ;; any later version. | ||
| 16 | |||
| 17 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 18 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | ;; GNU General Public License for more details. | ||
| 21 | |||
| 22 | ;; You should have received a copy of the GNU General Public License | ||
| 23 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | ||
| 24 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 25 | ;; Boston, MA 02110-1301, USA. | ||
| 26 | |||
| 27 | ;;; Commentary: | ||
| 28 | |||
| 29 | ;; Requires at least version 4.27 of org.el | ||
| 30 | |||
| 31 | ;; This program allow configurable publishing of related sets of | ||
| 32 | ;; Org-mode files as a complete website. | ||
| 33 | ;; | ||
| 34 | ;; org-publish.el can do the following: | ||
| 35 | ;; | ||
| 36 | ;; + Publish all one's org-files to HTML or LaTeX | ||
| 37 | ;; + Upload HTML, images, attachments and other files to a web server | ||
| 38 | ;; + Exclude selected private pages from publishing | ||
| 39 | ;; + Publish a clickable index of pages | ||
| 40 | ;; + Manage local timestamps for publishing only changed files | ||
| 41 | ;; + Accept plugin functions to extend range of publishable content | ||
| 42 | ;; | ||
| 43 | ;; Special thanks to the org-mode maintainer Carsten Dominik for his | ||
| 44 | ;; ideas, enthusiasm, and cooperation. | ||
| 45 | |||
| 46 | ;;; Installation: | ||
| 47 | |||
| 48 | ;; Put org-publish.el in your load path, byte-compile it, and then add | ||
| 49 | ;; the following lines to your emacs initialization file: | ||
| 50 | |||
| 51 | ;; (autoload 'org-publish "org-publish" nil t) | ||
| 52 | ;; (autoload 'org-publish "org-publish-all" nil t) | ||
| 53 | ;; (autoload 'org-publish "org-publish-current-file" nil t) | ||
| 54 | ;; (autoload 'org-publish "org-publish-current-project" nil t) | ||
| 55 | |||
| 56 | ;; NOTE: When org-publish.el is included with org.el, those forms are | ||
| 57 | ;; already in the file org-install.el, and hence don't need to be put | ||
| 58 | ;; in your emacs initialization file in this case. | ||
| 59 | |||
| 60 | ;;; Usage: | ||
| 61 | ;; | ||
| 62 | ;; The program's main configuration variable is | ||
| 63 | ;; `org-publish-project-alist'. See below for example configurations | ||
| 64 | ;; with commentary. | ||
| 65 | |||
| 66 | ;; The main interactive functions are: | ||
| 67 | ;; | ||
| 68 | ;; M-x org-publish | ||
| 69 | ;; M-x org-publish-all | ||
| 70 | ;; M-x org-publish-current-file | ||
| 71 | ;; M-x org-publish-current-project | ||
| 72 | |||
| 73 | ;;;; Simple example configuration: | ||
| 74 | |||
| 75 | ;; (setq org-publish-project-alist | ||
| 76 | ;; (list | ||
| 77 | ;; '("org" . (:base-directory "~/org/" | ||
| 78 | ;; :base-extension "org" | ||
| 79 | ;; :publishing-directory "~/public_html" | ||
| 80 | ;; :with-section-numbers nil | ||
| 81 | ;; :table-of-contents nil | ||
| 82 | ;; :recursive t | ||
| 83 | ;; :style "<link rel=stylesheet href=\"../other/mystyle.css\" type=\"text/css\">"))) | ||
| 84 | |||
| 85 | ;;;; More complex example configuration: | ||
| 86 | |||
| 87 | ;; Imagine your *.org files are kept in ~/org, your images in | ||
| 88 | ;; ~/images, and stylesheets in ~/other. Now imagine you want to | ||
| 89 | ;; publish the files through an ssh connection to a remote host, via | ||
| 90 | ;; Tramp-mode. To maintain relative links from *.org files to /images | ||
| 91 | ;; and /other, we should replicate the same directory structure in | ||
| 92 | ;; your web server account's designated html root (in this case, | ||
| 93 | ;; assumed to be ~/html) | ||
| 94 | |||
| 95 | ;; Once you've done created the proper directories, you can adapt the | ||
| 96 | ;; following example configuration to your specific paths, run M-x | ||
| 97 | ;; org-publish-all, and it should publish the files to the correct | ||
| 98 | ;; directories on the web server, transforming the *.org files into | ||
| 99 | ;; HTML, and leaving other files alone. | ||
| 100 | |||
| 101 | ;; (setq org-publish-project-alist | ||
| 102 | ;; (list | ||
| 103 | ;; '("orgfiles" :base-directory "~/org/" | ||
| 104 | ;; :base-extension "org" | ||
| 105 | ;; :publishing-directory "/ssh:user@host:~/html/notebook/" | ||
| 106 | ;; :publishing-function org-publish-org-to-html | ||
| 107 | ;; :exclude "PrivatePage.org" ;; regexp | ||
| 108 | ;; :headline-levels 3 | ||
| 109 | ;; :with-section-numbers nil | ||
| 110 | ;; :table-of-contents nil | ||
| 111 | ;; :style "<link rel=stylesheet href=\"../other/mystyle.css\" type=\"text/css\">" | ||
| 112 | ;; :auto-preamble t | ||
| 113 | ;; :auto-postamble nil) | ||
| 114 | ;; ("images" :base-directory "~/images/" | ||
| 115 | ;; :base-extension "jpg\\|gif\\|png" | ||
| 116 | ;; :publishing-directory "/ssh:user@host:~/html/images/" | ||
| 117 | ;; :publishing-function org-publish-attachment) | ||
| 118 | ;; ("other" :base-directory "~/other/" | ||
| 119 | ;; :base-extension "css" | ||
| 120 | ;; :publishing-directory "/ssh:user@host:~/html/other/" | ||
| 121 | ;; :publishing-function org-publish-attachment) | ||
| 122 | ;; ("website" :components ("orgfiles" "images" "other")))) | ||
| 123 | |||
| 124 | ;; For more information, see the documentation for the variable | ||
| 125 | ;; `org-publish-project-alist'. | ||
| 126 | |||
| 127 | ;; Of course, you don't have to publish to remote directories from | ||
| 128 | ;; within emacs. You can always just publish to local folders, and | ||
| 129 | ;; then use the synchronization/upload tool of your choice. | ||
| 130 | |||
| 131 | ;;; List of user-visible changes since version 1.27 | ||
| 132 | |||
| 133 | ;; 1.78: Allow list-valued :publishing-function | ||
| 134 | ;; 1.77: Added :preparation-function, this allows you to use GNU Make etc. | ||
| 135 | ;; 1.65: Remove old "composite projects". They're redundant. | ||
| 136 | ;; 1.64: Allow meta-projects with :components | ||
| 137 | ;; 1.57: Timestamps flag is now called "org-publish-use-timestamps-flag" | ||
| 138 | ;; 1.52: Properly set default for :index-filename | ||
| 139 | ;; 1.48: Composite projects allowed. | ||
| 140 | ;; :include keyword allowed. | ||
| 141 | ;; 1.43: Index no longer includes itself in the index. | ||
| 142 | ;; 1.42: Fix "function definition is void" error | ||
| 143 | ;; when :publishing-function not set in org-publish-current-file. | ||
| 144 | ;; 1.41: Fixed bug where index isn't published on first try. | ||
| 145 | ;; 1.37: Added interactive function "org-publish". Prompts for particular | ||
| 146 | ;; project name to publish. | ||
| 147 | ;; 1.34: Added force-publish option to all interactive functions. | ||
| 148 | ;; 1.32: Fixed "index.org has changed on disk" error during index publishing. | ||
| 149 | ;; 1.30: Fixed startup error caused by (require 'em-unix) | ||
| 150 | |||
| 151 | ;;; Code: | ||
| 152 | |||
| 153 | (eval-when-compile | ||
| 154 | (require 'cl)) | ||
| 155 | |||
| 156 | (eval-and-compile | ||
| 157 | (unless (fboundp 'declare-function) | ||
| 158 | (defmacro declare-function (fn file &optional arglist fileonly)))) | ||
| 159 | |||
| 160 | (require 'dired-aux) | ||
| 161 | |||
| 162 | (defgroup org-publish nil | ||
| 163 | "Options for publishing a set of Org-mode and related files." | ||
| 164 | :tag "Org Publishing" | ||
| 165 | :group 'org) | ||
| 166 | |||
| 167 | (defcustom org-publish-project-alist nil | ||
| 168 | "Association list to control publishing behavior. | ||
| 169 | Each element of the alist is a publishing 'project.' The CAR of | ||
| 170 | each element is a string, uniquely identifying the project. The | ||
| 171 | CDR of each element is in one of the following forms: | ||
| 172 | |||
| 173 | (:property value :property value ... ) | ||
| 174 | |||
| 175 | OR, | ||
| 176 | |||
| 177 | (:components (\"project-1\" \"project-2\" ...)) | ||
| 178 | |||
| 179 | When the CDR of an element of org-publish-project-alist is in | ||
| 180 | this second form, the elements of the list after :components are | ||
| 181 | taken to be components of the project, which group together files | ||
| 182 | requiring different publishing options. When you publish such a | ||
| 183 | project with M-x org-publish, the components all publish. | ||
| 184 | |||
| 185 | When a property is given a value in org-publish-project-alist, its | ||
| 186 | setting overrides the value of the corresponding user variable | ||
| 187 | (if any) during publishing. However, options set within a file | ||
| 188 | override everything. | ||
| 189 | |||
| 190 | Most properties are optional, but some should always be set: | ||
| 191 | |||
| 192 | :base-directory Directory containing publishing source files | ||
| 193 | :base-extension Extension (without the dot!) of source files. | ||
| 194 | This can be a regular expression. | ||
| 195 | :publishing-directory Directory (possibly remote) where output | ||
| 196 | files will be published | ||
| 197 | |||
| 198 | The :exclude property may be used to prevent certain files from | ||
| 199 | being published. Its value may be a string or regexp matching | ||
| 200 | file names you don't want to be published. | ||
| 201 | |||
| 202 | The :include property may be used to include extra files. Its | ||
| 203 | value may be a list of filenames to include. The filenames are | ||
| 204 | considered relative to the publishing directory. | ||
| 205 | |||
| 206 | When both :include and :exclude properties are given values, the | ||
| 207 | exclusion step happens first. | ||
| 208 | |||
| 209 | One special property controls which back-end function to use for | ||
| 210 | publishing files in the project. This can be used to extend the | ||
| 211 | set of file types publishable by org-publish, as well as the set | ||
| 212 | of output formats. | ||
| 213 | |||
| 214 | :publishing-function Function to publish file. The default is | ||
| 215 | org-publish-org-to-html, but other | ||
| 216 | values are possible. May also be a | ||
| 217 | list of functions, in which case | ||
| 218 | each function in the list is invoked | ||
| 219 | in turn. | ||
| 220 | |||
| 221 | Another property allows you to insert code that prepares a | ||
| 222 | project for publishing. For example, you could call GNU Make on a | ||
| 223 | certain makefile, to ensure published files are built up to date. | ||
| 224 | |||
| 225 | :preparation-function Function to be called before publishing | ||
| 226 | this project. | ||
| 227 | |||
| 228 | Some properties control details of the Org publishing process, | ||
| 229 | and are equivalent to the corresponding user variables listed in | ||
| 230 | the right column. See the documentation for those variables to | ||
| 231 | learn more about their use and default values. | ||
| 232 | |||
| 233 | :language org-export-default-language | ||
| 234 | :headline-levels org-export-headline-levels | ||
| 235 | :section-numbers org-export-with-section-numbers | ||
| 236 | :table-of-contents org-export-with-toc | ||
| 237 | :emphasize org-export-with-emphasize | ||
| 238 | :sub-superscript org-export-with-sub-superscripts | ||
| 239 | :TeX-macros org-export-with-TeX-macros | ||
| 240 | :fixed-width org-export-with-fixed-width | ||
| 241 | :tables org-export-with-tables | ||
| 242 | :table-auto-headline org-export-highlight-first-table-line | ||
| 243 | :style org-export-html-style | ||
| 244 | :convert-org-links org-export-html-link-org-files-as-html | ||
| 245 | :inline-images org-export-html-inline-images | ||
| 246 | :expand-quoted-html org-export-html-expand | ||
| 247 | :timestamp org-export-html-with-timestamp | ||
| 248 | :publishing-directory org-export-publishing-directory | ||
| 249 | :preamble org-export-html-preamble | ||
| 250 | :postamble org-export-html-postamble | ||
| 251 | :auto-preamble org-export-html-auto-preamble | ||
| 252 | :auto-postamble org-export-html-auto-postamble | ||
| 253 | :author user-full-name | ||
| 254 | :email user-mail-address | ||
| 255 | |||
| 256 | The following properties may be used to control publishing of an | ||
| 257 | index of files or summary page for a given project. | ||
| 258 | |||
| 259 | :auto-index Whether to publish an index during | ||
| 260 | org-publish-current-project or org-publish-all. | ||
| 261 | :index-filename Filename for output of index. Defaults | ||
| 262 | to 'index.org' (which becomes 'index.html') | ||
| 263 | :index-title Title of index page. Defaults to name of file. | ||
| 264 | :index-function Plugin function to use for generation of index. | ||
| 265 | Defaults to 'org-publish-org-index', which | ||
| 266 | generates a plain list of links to all files | ||
| 267 | in the project." | ||
| 268 | :group 'org-publish | ||
| 269 | :type 'alist) | ||
| 270 | |||
| 271 | (defcustom org-publish-use-timestamps-flag t | ||
| 272 | "When non-nil, use timestamp checking to publish only changed files. | ||
| 273 | When nil, do no timestamp checking and always publish all | ||
| 274 | files." | ||
| 275 | :group 'org-publish | ||
| 276 | :type 'boolean) | ||
| 277 | |||
| 278 | (defcustom org-publish-timestamp-directory "~/.org-timestamps/" | ||
| 279 | "Name of directory in which to store publishing timestamps." | ||
| 280 | :group 'org-publish | ||
| 281 | :type 'directory) | ||
| 282 | |||
| 283 | (defcustom org-publish-before-export-hook nil | ||
| 284 | "Hook run before export on the Org file. | ||
| 285 | If the functions in this hook modify the original Org buffer, the | ||
| 286 | modified buffer will be used for export, but the buffer will be | ||
| 287 | restored and saved back to its initial state after export." | ||
| 288 | :group 'org-publish | ||
| 289 | :type 'hook) | ||
| 290 | |||
| 291 | (defcustom org-publish-after-export-hook nil | ||
| 292 | "Hook run after export on the exported buffer. | ||
| 293 | If functions in this hook modify the buffer, it will be saved." | ||
| 294 | :group 'org-publish | ||
| 295 | :type 'hook) | ||
| 296 | |||
| 297 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 298 | ;;; Timestamp-related functions | ||
| 299 | |||
| 300 | (defun org-publish-timestamp-filename (filename) | ||
| 301 | "Return path to timestamp file for filename FILENAME." | ||
| 302 | (while (string-match | ||
| 303 | (if (eq system-type 'windows-nt) "~\\|/\\|:" "~\\|/") filename) | ||
| 304 | (setq filename (replace-match "_" nil t filename))) | ||
| 305 | (concat org-publish-timestamp-directory filename ".timestamp")) | ||
| 306 | |||
| 307 | (defun org-publish-needed-p (filename) | ||
| 308 | "Return `t' if FILENAME should be published." | ||
| 309 | (if org-publish-use-timestamps-flag | ||
| 310 | (if (file-exists-p org-publish-timestamp-directory) | ||
| 311 | ;; first handle possible wrong timestamp directory | ||
| 312 | (if (not (file-directory-p org-publish-timestamp-directory)) | ||
| 313 | (error "Org publish timestamp: %s is not a directory" | ||
| 314 | org-publish-timestamp-directory) | ||
| 315 | ;; there is a timestamp, check if FILENAME is newer | ||
| 316 | (file-newer-than-file-p | ||
| 317 | filename (org-publish-timestamp-filename filename)))) | ||
| 318 | ;; don't use timestamps, always return t | ||
| 319 | t)) | ||
| 320 | |||
| 321 | (defun org-publish-update-timestamp (filename) | ||
| 322 | "Update publishing timestamp for file FILENAME. | ||
| 323 | If there is no timestamp, create one." | ||
| 324 | (let ((timestamp-file (org-publish-timestamp-filename filename)) | ||
| 325 | newly-created-timestamp) | ||
| 326 | (if (not (file-exists-p timestamp-file)) | ||
| 327 | ;; create timestamp file if needed | ||
| 328 | (with-temp-buffer | ||
| 329 | (make-directory (file-name-directory timestamp-file) t) | ||
| 330 | (write-file timestamp-file) | ||
| 331 | (setq newly-created-timestamp t))) | ||
| 332 | ;; Emacs 21 doesn't have `set-file-times' | ||
| 333 | (if (and (fboundp 'set-file-times) | ||
| 334 | (not newly-created-timestamp)) | ||
| 335 | (set-file-times timestamp-file) | ||
| 336 | (call-process "touch" nil 0 nil timestamp-file)))) | ||
| 337 | |||
| 338 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 339 | ;;; Mapping files to project names | ||
| 340 | |||
| 341 | (defvar org-publish-files-alist nil | ||
| 342 | "Alist of files and their parent project. | ||
| 343 | Each element of this alist is of the form: | ||
| 344 | |||
| 345 | (file-name . project-name)") | ||
| 346 | |||
| 347 | (defun org-publish-initialize-files-alist (&optional refresh) | ||
| 348 | "Set `org-publish-files-alist' if it is not set. | ||
| 349 | Also set it if the optional argument REFRESH is non-nil." | ||
| 350 | (interactive "P") | ||
| 351 | (when (or refresh (not org-publish-files-alist)) | ||
| 352 | (setq org-publish-files-alist | ||
| 353 | (org-publish-get-files org-publish-project-alist)))) | ||
| 354 | |||
| 355 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 356 | ;;; Compatibility aliases | ||
| 357 | |||
| 358 | ;; Delete-dups is not in Emacs <22 | ||
| 359 | (if (fboundp 'delete-dups) | ||
| 360 | (defalias 'org-publish-delete-dups 'delete-dups) | ||
| 361 | (defun org-publish-delete-dups (list) | ||
| 362 | "Destructively remove `equal' duplicates from LIST. | ||
| 363 | Store the result in LIST and return it. LIST must be a proper list. | ||
| 364 | Of several `equal' occurrences of an element in LIST, the first | ||
| 365 | one is kept. | ||
| 366 | |||
| 367 | This is a compatibility function for Emacsen without `delete-dups'." | ||
| 368 | ;; Code from `subr.el' in Emacs 22: | ||
| 369 | (let ((tail list)) | ||
| 370 | (while tail | ||
| 371 | (setcdr tail (delete (car tail) (cdr tail))) | ||
| 372 | (setq tail (cdr tail)))) | ||
| 373 | list)) | ||
| 374 | |||
| 375 | (declare-function org-publish-delete-dups "org-publish" (list)) | ||
| 376 | |||
| 377 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 378 | ;;; Getting project information out of org-publish-project-alist | ||
| 379 | |||
| 380 | (defun org-publish-get-files (projects-alist &optional no-exclusion) | ||
| 381 | "Return the list of all publishable files for PROJECTS-ALIST. | ||
| 382 | If NO-EXCLUSION is non-nil, don't exclude files." | ||
| 383 | (let (all-files) | ||
| 384 | ;; add all projects | ||
| 385 | (mapc | ||
| 386 | (lambda(p) | ||
| 387 | (let* ((exclude (plist-get (cdr p) :exclude)) | ||
| 388 | (files (and p (org-publish-get-base-files p exclude)))) | ||
| 389 | ;; add all files from this project | ||
| 390 | (mapc (lambda(f) | ||
| 391 | (add-to-list 'all-files | ||
| 392 | (cons (expand-file-name f) (car p)))) | ||
| 393 | files))) | ||
| 394 | (org-publish-expand-projects projects-alist)) | ||
| 395 | all-files)) | ||
| 396 | |||
| 397 | (defun org-publish-expand-projects (projects-alist) | ||
| 398 | "Expand projects contained in PROJECTS-ALIST." | ||
| 399 | (let (without-component with-component) | ||
| 400 | (mapc (lambda(p) | ||
| 401 | (add-to-list | ||
| 402 | (if (plist-get (cdr p) :components) | ||
| 403 | 'with-component 'without-component) p)) | ||
| 404 | projects-alist) | ||
| 405 | (org-publish-delete-dups | ||
| 406 | (append without-component | ||
| 407 | (car (mapcar (lambda(p) (org-publish-expand-components p)) | ||
| 408 | with-component)))))) | ||
| 409 | |||
| 410 | (defun org-publish-expand-components (project) | ||
| 411 | "Expand PROJECT into an alist of its components." | ||
| 412 | (let* ((components (plist-get (cdr project) :components))) | ||
| 413 | (org-publish-delete-dups | ||
| 414 | (delq nil (mapcar (lambda(c) (assoc c org-publish-project-alist)) | ||
| 415 | components))))) | ||
| 416 | |||
| 417 | (defun org-publish-get-base-files (project &optional exclude-regexp) | ||
| 418 | "Return a list of all files in PROJECT. | ||
| 419 | If EXCLUDE-REGEXP is set, this will be used to filter out | ||
| 420 | matching filenames." | ||
| 421 | (let* ((project-plist (cdr project)) | ||
| 422 | (base-dir (file-name-as-directory | ||
| 423 | (plist-get project-plist :base-directory))) | ||
| 424 | (include-list (plist-get project-plist :include)) | ||
| 425 | (recursive-p (plist-get project-plist :recursive)) | ||
| 426 | (extension (or (plist-get project-plist :base-extension) "org")) | ||
| 427 | (regexp (concat "^[^\\.].*\\.\\(" extension "\\)$")) | ||
| 428 | alldirs allfiles files dir) | ||
| 429 | ;; Get all files and directories in base-directory | ||
| 430 | (setq files (dired-files-attributes base-dir)) | ||
| 431 | ;; Get all subdirectories if recursive-p | ||
| 432 | (setq alldirs | ||
| 433 | (if recursive-p | ||
| 434 | (delq nil (mapcar (lambda(f) (if (caaddr f) (cadr f))) files)) | ||
| 435 | (list base-dir))) | ||
| 436 | (while (setq dir (pop alldirs)) | ||
| 437 | (setq files (directory-files dir t regexp)) | ||
| 438 | ;; Exclude files | ||
| 439 | (setq files | ||
| 440 | (if (not exclude-regexp) | ||
| 441 | files | ||
| 442 | (delq nil | ||
| 443 | (mapcar (lambda (x) | ||
| 444 | (if (string-match exclude-regexp x) nil x)) | ||
| 445 | files)))) | ||
| 446 | ;; Include extra files | ||
| 447 | (let (inc) | ||
| 448 | (while (setq inc (pop include-list)) | ||
| 449 | (setq files (cons (expand-file-name inc dir) files)))) | ||
| 450 | (setq allfiles (append allfiles files))) | ||
| 451 | allfiles)) | ||
| 452 | |||
| 453 | (defun org-publish-get-project-from-filename (filename) | ||
| 454 | "Return the project FILENAME belongs." | ||
| 455 | (let* ((project-name (cdr (assoc (expand-file-name filename) | ||
| 456 | org-publish-files-alist)))) | ||
| 457 | (assoc project-name org-publish-project-alist))) | ||
| 458 | |||
| 459 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 460 | ;;; Pluggable publishing back-end functions | ||
| 461 | |||
| 462 | (defun org-publish-org-to (format plist filename pub-dir) | ||
| 463 | "Publish an org file to FORMAT. | ||
| 464 | PLIST is the property list for the given project. | ||
| 465 | FILENAME is the filename of the org file to be published. | ||
| 466 | PUB-DIR is the publishing directory." | ||
| 467 | (require 'org) | ||
| 468 | (unless (file-exists-p pub-dir) | ||
| 469 | (make-directory pub-dir t)) | ||
| 470 | (find-file filename) | ||
| 471 | (let ((init-buf (current-buffer)) | ||
| 472 | (init-point (point)) | ||
| 473 | (init-buf-string (buffer-string)) export-buf) | ||
| 474 | ;; run hooks before exporting | ||
| 475 | (run-hooks 'org-publish-before-export-hook) | ||
| 476 | ;; export the possibly modified buffer | ||
| 477 | (setq export-buf | ||
| 478 | (funcall (intern (concat "org-export-as-" format)) | ||
| 479 | (plist-get plist :headline-levels) | ||
| 480 | nil plist nil nil pub-dir)) | ||
| 481 | (set-buffer export-buf) | ||
| 482 | ;; run hooks after export and save export | ||
| 483 | (and (run-hooks 'org-publish-after-export-hook) | ||
| 484 | (if (buffer-modified-p) (save-buffer))) | ||
| 485 | ;; maybe restore buffer's content | ||
| 486 | (set-buffer init-buf) | ||
| 487 | (when (buffer-modified-p init-buf) | ||
| 488 | (erase-buffer) | ||
| 489 | (insert init-buf-string) | ||
| 490 | (save-buffer) | ||
| 491 | (goto-char init-point)))) | ||
| 492 | |||
| 493 | (defun org-publish-org-to-latex (plist filename pub-dir) | ||
| 494 | "Publish an org file to LaTeX. | ||
| 495 | See `org-publish-org-to' to the list of arguments." | ||
| 496 | (org-publish-org-to "latex" plist filename pub-dir)) | ||
| 497 | |||
| 498 | (defun org-publish-org-to-html (plist filename pub-dir) | ||
| 499 | "Publish an org file to HTML. | ||
| 500 | See `org-publish-org-to' to the list of arguments." | ||
| 501 | (org-publish-org-to "html" plist filename pub-dir)) | ||
| 502 | |||
| 503 | (defun org-publish-attachment (plist filename pub-dir) | ||
| 504 | "Publish a file with no transformation of any kind. | ||
| 505 | See `org-publish-org-to' to the list of arguments." | ||
| 506 | ;; make sure eshell/cp code is loaded | ||
| 507 | (eval-and-compile | ||
| 508 | (require 'eshell) | ||
| 509 | (require 'esh-maint) | ||
| 510 | (require 'em-unix)) | ||
| 511 | (eshell/cp filename pub-dir)) | ||
| 512 | |||
| 513 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 514 | ;;; Publishing files, sets of files, and indices | ||
| 515 | |||
| 516 | (defun org-publish-file (filename &optional project) | ||
| 517 | "Publish file FILENAME from PROJECT." | ||
| 518 | (when (org-publish-needed-p filename) | ||
| 519 | (let* ((project | ||
| 520 | (or project | ||
| 521 | (or (org-publish-get-project-from-filename filename) | ||
| 522 | (if (y-or-n-p | ||
| 523 | (format "%s is not in a project. Re-read the list of projects files? " | ||
| 524 | (abbreviate-file-name filename))) | ||
| 525 | ;; If requested, re-initialize the list of projects files | ||
| 526 | (progn (org-publish-initialize-files-alist t) | ||
| 527 | (or (org-publish-get-project-from-filename filename) | ||
| 528 | (error "File %s not part of any known project" | ||
| 529 | (abbreviate-file-name filename)))) | ||
| 530 | (error "Can't publish file outside of a project"))))) | ||
| 531 | (project-plist (cdr project)) | ||
| 532 | (publishing-function | ||
| 533 | (or (plist-get project-plist :publishing-function) | ||
| 534 | 'org-publish-org-to-html)) | ||
| 535 | (base-dir (file-name-as-directory | ||
| 536 | (file-truename (plist-get project-plist :base-directory)))) | ||
| 537 | (pub-dir (file-name-as-directory | ||
| 538 | (file-truename (plist-get project-plist :publishing-directory)))) | ||
| 539 | tmp-pub-dir) | ||
| 540 | (setq tmp-pub-dir | ||
| 541 | (file-name-directory | ||
| 542 | (concat pub-dir | ||
| 543 | (and (string-match (regexp-quote base-dir) filename) | ||
| 544 | (substring filename (match-end 0)))))) | ||
| 545 | (if (listp publishing-function) | ||
| 546 | ;; allow chain of publishing functions | ||
| 547 | (mapc (lambda (f) | ||
| 548 | (funcall f project-plist filename tmp-pub-dir)) | ||
| 549 | publishing-function) | ||
| 550 | (funcall publishing-function project-plist filename tmp-pub-dir))) | ||
| 551 | (org-publish-update-timestamp filename))) | ||
| 552 | |||
| 553 | (defun org-publish-projects (projects) | ||
| 554 | "Publish all files belonging to the PROJECTS alist. | ||
| 555 | If :auto-index is set, publish the index too." | ||
| 556 | (mapc | ||
| 557 | (lambda (project) | ||
| 558 | (let* ((project-plist (cdr project)) | ||
| 559 | (exclude-regexp (plist-get project-plist :exclude)) | ||
| 560 | (index-p (plist-get project-plist :auto-index)) | ||
| 561 | (index-filename (or (plist-get project-plist :index-filename) | ||
| 562 | "index.org")) | ||
| 563 | (index-function (or (plist-get project-plist :index-function) | ||
| 564 | 'org-publish-org-index)) | ||
| 565 | (preparation-function (plist-get project-plist :preparation-function)) | ||
| 566 | (files (org-publish-get-base-files project exclude-regexp)) file) | ||
| 567 | (when preparation-function (funcall preparation-function)) | ||
| 568 | (if index-p (funcall index-function project index-filename)) | ||
| 569 | (while (setq file (pop files)) | ||
| 570 | (org-publish-file file project)))) | ||
| 571 | (org-publish-expand-projects projects))) | ||
| 572 | |||
| 573 | (defun org-publish-org-index (project &optional index-filename) | ||
| 574 | "Create an index of pages in set defined by PROJECT. | ||
| 575 | Optionally set the filename of the index with INDEX-FILENAME. | ||
| 576 | Default for INDEX-FILENAME is 'index.org'." | ||
| 577 | (let* ((project-plist (cdr project)) | ||
| 578 | (dir (file-name-as-directory | ||
| 579 | (plist-get project-plist :base-directory))) | ||
| 580 | (exclude-regexp (plist-get project-plist :exclude)) | ||
| 581 | (files (org-publish-get-base-files project exclude-regexp)) | ||
| 582 | (index-filename (concat dir (or index-filename "index.org"))) | ||
| 583 | (index-buffer (find-buffer-visiting index-filename)) | ||
| 584 | (ifn (file-name-nondirectory index-filename)) | ||
| 585 | file) | ||
| 586 | ;; if buffer is already open, kill it to prevent error message | ||
| 587 | (if index-buffer | ||
| 588 | (kill-buffer index-buffer)) | ||
| 589 | (with-temp-buffer | ||
| 590 | (while (setq file (pop files)) | ||
| 591 | (let ((fn (file-name-nondirectory file))) | ||
| 592 | ;; index shouldn't index itself | ||
| 593 | (unless (string= fn ifn) | ||
| 594 | (insert (concat " + [[file:" fn "][" | ||
| 595 | (file-name-sans-extension fn) | ||
| 596 | "]]\n"))))) | ||
| 597 | (write-file index-filename) | ||
| 598 | (kill-buffer (current-buffer))))) | ||
| 599 | |||
| 600 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 601 | ;;; Interactive publishing functions | ||
| 602 | |||
| 603 | (defalias 'org-publish-project 'org-publish "Publish project.") | ||
| 604 | |||
| 605 | ;;;###autoload | ||
| 606 | (defun org-publish (project &optional force) | ||
| 607 | "Publish PROJECT." | ||
| 608 | (interactive "P") | ||
| 609 | (save-window-excursion | ||
| 610 | (let* ((force current-prefix-arg) | ||
| 611 | (org-publish-use-timestamps-flag | ||
| 612 | (if force nil org-publish-use-timestamps-flag))) | ||
| 613 | (org-publish-projects | ||
| 614 | (list (or project | ||
| 615 | (assoc (completing-read | ||
| 616 | "Publish project: " | ||
| 617 | org-publish-project-alist nil t) | ||
| 618 | org-publish-project-alist))))))) | ||
| 619 | |||
| 620 | ;;;###autoload | ||
| 621 | (defun org-publish-all (&optional force) | ||
| 622 | "Publish all projects. | ||
| 623 | With prefix argument, force publish all files." | ||
| 624 | (interactive "P") | ||
| 625 | (org-publish-initialize-files-alist) | ||
| 626 | (save-window-excursion | ||
| 627 | (let ((org-publish-use-timestamps-flag | ||
| 628 | (if force nil org-publish-use-timestamps-flag))) | ||
| 629 | (org-publish-projects org-publish-project-alist)))) | ||
| 630 | |||
| 631 | ;;;###autoload | ||
| 632 | (defun org-publish-current-file (&optional force) | ||
| 633 | "Publish the current file. | ||
| 634 | With prefix argument, force publish the file." | ||
| 635 | (interactive "P") | ||
| 636 | (org-publish-initialize-files-alist) | ||
| 637 | (save-window-excursion | ||
| 638 | (let ((org-publish-use-timestamps-flag | ||
| 639 | (if force nil org-publish-use-timestamps-flag))) | ||
| 640 | (org-publish-file (buffer-file-name))))) | ||
| 641 | |||
| 642 | ;;;###autoload | ||
| 643 | (defun org-publish-current-project (&optional force) | ||
| 644 | "Publish the project associated with the current file. | ||
| 645 | With a prefix argument, force publishing of all files in | ||
| 646 | the project." | ||
| 647 | (interactive "P") | ||
| 648 | (org-publish-initialize-files-alist) | ||
| 649 | (save-window-excursion | ||
| 650 | (let ((project (org-publish-get-project-from-filename (buffer-file-name))) | ||
| 651 | (org-publish-use-timestamps-flag | ||
| 652 | (if force nil org-publish-use-timestamps-flag))) | ||
| 653 | (if (not project) | ||
| 654 | (error "File %s is not part of any known project" (buffer-file-name))) | ||
| 655 | (org-publish project)))) | ||
| 656 | |||
| 657 | (provide 'org-publish) | ||
| 658 | |||
| 659 | |||
| 660 | ;; arch-tag: 72807f3c-8af0-4a6b-8dca-c3376eb25adb | ||
| 661 | ;;; org-publish.el ends here | ||
diff --git a/lisp/textmodes/org.el b/lisp/textmodes/org.el deleted file mode 100644 index 1da611aa790..00000000000 --- a/lisp/textmodes/org.el +++ /dev/null | |||
| @@ -1,28976 +0,0 @@ | |||
| 1 | ;;; org.el --- Outline-based notes management and organizer | ||
| 2 | ;; Carstens outline-mode for keeping track of everything. | ||
| 3 | ;; Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. | ||
| 4 | ;; | ||
| 5 | ;; Author: Carsten Dominik <carsten at orgmode dot org> | ||
| 6 | ;; Keywords: outlines, hypermedia, calendar, wp | ||
| 7 | ;; Homepage: http://orgmode.org | ||
| 8 | ;; Version: 5.23a | ||
| 9 | ;; | ||
| 10 | ;; This file is part of GNU Emacs. | ||
| 11 | ;; | ||
| 12 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 13 | ;; it under the terms of the GNU General Public License as published by | ||
| 14 | ;; the Free Software Foundation; either version 3, or (at your option) | ||
| 15 | ;; any later version. | ||
| 16 | |||
| 17 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 18 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | ;; GNU General Public License for more details. | ||
| 21 | |||
| 22 | ;; You should have received a copy of the GNU General Public License | ||
| 23 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | ||
| 24 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 25 | ;; Boston, MA 02110-1301, USA. | ||
| 26 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 27 | ;; | ||
| 28 | ;;; Commentary: | ||
| 29 | ;; | ||
| 30 | ;; Org-mode is a mode for keeping notes, maintaining ToDo lists, and doing | ||
| 31 | ;; project planning with a fast and effective plain-text system. | ||
| 32 | ;; | ||
| 33 | ;; Org-mode develops organizational tasks around NOTES files that contain | ||
| 34 | ;; information about projects as plain text. Org-mode is implemented on | ||
| 35 | ;; top of outline-mode, which makes it possible to keep the content of | ||
| 36 | ;; large files well structured. Visibility cycling and structure editing | ||
| 37 | ;; help to work with the tree. Tables are easily created with a built-in | ||
| 38 | ;; table editor. Org-mode supports ToDo items, deadlines, time stamps, | ||
| 39 | ;; and scheduling. It dynamically compiles entries into an agenda that | ||
| 40 | ;; utilizes and smoothly integrates much of the Emacs calendar and diary. | ||
| 41 | ;; Plain text URL-like links connect to websites, emails, Usenet | ||
| 42 | ;; messages, BBDB entries, and any files related to the projects. For | ||
| 43 | ;; printing and sharing of notes, an Org-mode file can be exported as a | ||
| 44 | ;; structured ASCII file, as HTML, or (todo and agenda items only) as an | ||
| 45 | ;; iCalendar file. It can also serve as a publishing tool for a set of | ||
| 46 | ;; linked webpages. | ||
| 47 | ;; | ||
| 48 | ;; Installation and Activation | ||
| 49 | ;; --------------------------- | ||
| 50 | ;; See the corresponding sections in the manual at | ||
| 51 | ;; | ||
| 52 | ;; http://orgmode.org/org.html#Installation | ||
| 53 | ;; | ||
| 54 | ;; Documentation | ||
| 55 | ;; ------------- | ||
| 56 | ;; The documentation of Org-mode can be found in the TeXInfo file. The | ||
| 57 | ;; distribution also contains a PDF version of it. At the homepage of | ||
| 58 | ;; Org-mode, you can read the same text online as HTML. There is also an | ||
| 59 | ;; excellent reference card made by Philip Rooke. This card can be found | ||
| 60 | ;; in the etc/ directory of Emacs 22. | ||
| 61 | ;; | ||
| 62 | ;; A list of recent changes can be found at | ||
| 63 | ;; http://orgmode.org/Changes.html | ||
| 64 | ;; | ||
| 65 | ;;; Code: | ||
| 66 | |||
| 67 | ;;;; Require other packages | ||
| 68 | |||
| 69 | (eval-when-compile | ||
| 70 | (require 'cl) | ||
| 71 | (require 'gnus-sum) | ||
| 72 | (require 'calendar)) | ||
| 73 | ;; For XEmacs, noutline is not yet provided by outline.el, so arrange for | ||
| 74 | ;; the file noutline.el being loaded. | ||
| 75 | (if (featurep 'xemacs) (condition-case nil (require 'noutline))) | ||
| 76 | ;; We require noutline, which might be provided in outline.el | ||
| 77 | (require 'outline) (require 'noutline) | ||
| 78 | ;; Other stuff we need. | ||
| 79 | (require 'time-date) | ||
| 80 | (unless (fboundp 'time-subtract) (defalias 'time-subtract 'subtract-time)) | ||
| 81 | (require 'easymenu) | ||
| 82 | |||
| 83 | ;;;; Customization variables | ||
| 84 | |||
| 85 | ;;; Version | ||
| 86 | |||
| 87 | (defconst org-version "5.23a" | ||
| 88 | "The version number of the file org.el.") | ||
| 89 | |||
| 90 | (defun org-version (&optional here) | ||
| 91 | "Show the org-mode version in the echo area. | ||
| 92 | With prefix arg HERE, insert it at point." | ||
| 93 | (interactive "P") | ||
| 94 | (let ((version (format "Org-mode version %s" org-version))) | ||
| 95 | (message version) | ||
| 96 | (if here | ||
| 97 | (insert version)))) | ||
| 98 | |||
| 99 | ;;; Compatibility constants | ||
| 100 | (defconst org-xemacs-p (featurep 'xemacs)) ; not used by org.el itself | ||
| 101 | (defconst org-format-transports-properties-p | ||
| 102 | (let ((x "a")) | ||
| 103 | (add-text-properties 0 1 '(test t) x) | ||
| 104 | (get-text-property 0 'test (format "%s" x))) | ||
| 105 | "Does format transport text properties?") | ||
| 106 | |||
| 107 | (defmacro org-bound-and-true-p (var) | ||
| 108 | "Return the value of symbol VAR if it is bound, else nil." | ||
| 109 | `(and (boundp (quote ,var)) ,var)) | ||
| 110 | |||
| 111 | (defmacro org-unmodified (&rest body) | ||
| 112 | "Execute body without changing `buffer-modified-p'." | ||
| 113 | `(set-buffer-modified-p | ||
| 114 | (prog1 (buffer-modified-p) ,@body))) | ||
| 115 | |||
| 116 | (defmacro org-re (s) | ||
| 117 | "Replace posix classes in regular expression." | ||
| 118 | (if (featurep 'xemacs) | ||
| 119 | (let ((ss s)) | ||
| 120 | (save-match-data | ||
| 121 | (while (string-match "\\[:alnum:\\]" ss) | ||
| 122 | (setq ss (replace-match "a-zA-Z0-9" t t ss))) | ||
| 123 | (while (string-match "\\[:alpha:\\]" ss) | ||
| 124 | (setq ss (replace-match "a-zA-Z" t t ss))) | ||
| 125 | ss)) | ||
| 126 | s)) | ||
| 127 | |||
| 128 | (defmacro org-preserve-lc (&rest body) | ||
| 129 | `(let ((_line (org-current-line)) | ||
| 130 | (_col (current-column))) | ||
| 131 | (unwind-protect | ||
| 132 | (progn ,@body) | ||
| 133 | (goto-line _line) | ||
| 134 | (move-to-column _col)))) | ||
| 135 | |||
| 136 | (defmacro org-without-partial-completion (&rest body) | ||
| 137 | `(let ((pc-mode (and (boundp 'partial-completion-mode) | ||
| 138 | partial-completion-mode))) | ||
| 139 | (unwind-protect | ||
| 140 | (progn | ||
| 141 | (if pc-mode (partial-completion-mode -1)) | ||
| 142 | ,@body) | ||
| 143 | (if pc-mode (partial-completion-mode 1))))) | ||
| 144 | |||
| 145 | ;;; The custom variables | ||
| 146 | |||
| 147 | (defgroup org nil | ||
| 148 | "Outline-based notes management and organizer." | ||
| 149 | :tag "Org" | ||
| 150 | :group 'outlines | ||
| 151 | :group 'hypermedia | ||
| 152 | :group 'calendar) | ||
| 153 | |||
| 154 | (defcustom org-load-hook nil | ||
| 155 | "Hook that is run after org.el has been loaded." | ||
| 156 | :group 'org | ||
| 157 | :type 'hook) | ||
| 158 | |||
| 159 | ;(defcustom org-default-extensions '(org-irc) | ||
| 160 | ; "Extensions that should always be loaded together with org.el. | ||
| 161 | ;If the description starts with <A>, this means the extension | ||
| 162 | ;will be autoloaded when needed, preloading is not necessary. | ||
| 163 | ;FIXME: this does not ork correctly, ignore it for now." | ||
| 164 | ; :group 'org | ||
| 165 | ; :type | ||
| 166 | ; '(set :greedy t | ||
| 167 | ; (const :tag " Mouse support (org-mouse.el)" org-mouse) | ||
| 168 | ; (const :tag "<A> Publishing (org-publish.el)" org-publish) | ||
| 169 | ; (const :tag "<A> LaTeX export (org-export-latex.el)" org-export-latex) | ||
| 170 | ; (const :tag " IRC/ERC links (org-irc.el)" org-irc) | ||
| 171 | ; (const :tag " Apple Mail message links under OS X (org-mac-message.el)" org-mac-message))) | ||
| 172 | ; | ||
| 173 | ;(defun org-load-default-extensions () | ||
| 174 | ; "Load all extensions listed in `org-default-extensions'." | ||
| 175 | ; (mapc (lambda (ext) | ||
| 176 | ; (condition-case nil (require ext) | ||
| 177 | ; (error (message "Problems while trying to load feature `%s'" ext)))) | ||
| 178 | ; org-default-extensions)) | ||
| 179 | |||
| 180 | ;(eval-after-load "org" '(org-load-default-extensions)) | ||
| 181 | |||
| 182 | ;; FIXME: Needs a separate group... | ||
| 183 | (defcustom org-completion-fallback-command 'hippie-expand | ||
| 184 | "The expansion command called by \\[org-complete] in normal context. | ||
| 185 | Normal means, no org-mode-specific context." | ||
| 186 | :group 'org | ||
| 187 | :type 'function) | ||
| 188 | |||
| 189 | (defgroup org-startup nil | ||
| 190 | "Options concerning startup of Org-mode." | ||
| 191 | :tag "Org Startup" | ||
| 192 | :group 'org) | ||
| 193 | |||
| 194 | (defcustom org-startup-folded t | ||
| 195 | "Non-nil means, entering Org-mode will switch to OVERVIEW. | ||
| 196 | This can also be configured on a per-file basis by adding one of | ||
| 197 | the following lines anywhere in the buffer: | ||
| 198 | |||
| 199 | #+STARTUP: fold | ||
| 200 | #+STARTUP: nofold | ||
| 201 | #+STARTUP: content" | ||
| 202 | :group 'org-startup | ||
| 203 | :type '(choice | ||
| 204 | (const :tag "nofold: show all" nil) | ||
| 205 | (const :tag "fold: overview" t) | ||
| 206 | (const :tag "content: all headlines" content))) | ||
| 207 | |||
| 208 | (defcustom org-startup-truncated t | ||
| 209 | "Non-nil means, entering Org-mode will set `truncate-lines'. | ||
| 210 | This is useful since some lines containing links can be very long and | ||
| 211 | uninteresting. Also tables look terrible when wrapped." | ||
| 212 | :group 'org-startup | ||
| 213 | :type 'boolean) | ||
| 214 | |||
| 215 | (defcustom org-startup-align-all-tables nil | ||
| 216 | "Non-nil means, align all tables when visiting a file. | ||
| 217 | This is useful when the column width in tables is forced with <N> cookies | ||
| 218 | in table fields. Such tables will look correct only after the first re-align. | ||
| 219 | This can also be configured on a per-file basis by adding one of | ||
| 220 | the following lines anywhere in the buffer: | ||
| 221 | #+STARTUP: align | ||
| 222 | #+STARTUP: noalign" | ||
| 223 | :group 'org-startup | ||
| 224 | :type 'boolean) | ||
| 225 | |||
| 226 | (defcustom org-insert-mode-line-in-empty-file nil | ||
| 227 | "Non-nil means insert the first line setting Org-mode in empty files. | ||
| 228 | When the function `org-mode' is called interactively in an empty file, this | ||
| 229 | normally means that the file name does not automatically trigger Org-mode. | ||
| 230 | To ensure that the file will always be in Org-mode in the future, a | ||
| 231 | line enforcing Org-mode will be inserted into the buffer, if this option | ||
| 232 | has been set." | ||
| 233 | :group 'org-startup | ||
| 234 | :type 'boolean) | ||
| 235 | |||
| 236 | (defcustom org-replace-disputed-keys nil | ||
| 237 | "Non-nil means use alternative key bindings for some keys. | ||
| 238 | Org-mode uses S-<cursor> keys for changing timestamps and priorities. | ||
| 239 | These keys are also used by other packages like `CUA-mode' or `windmove.el'. | ||
| 240 | If you want to use Org-mode together with one of these other modes, | ||
| 241 | or more generally if you would like to move some Org-mode commands to | ||
| 242 | other keys, set this variable and configure the keys with the variable | ||
| 243 | `org-disputed-keys'. | ||
| 244 | |||
| 245 | This option is only relevant at load-time of Org-mode, and must be set | ||
| 246 | *before* org.el is loaded. Changing it requires a restart of Emacs to | ||
| 247 | become effective." | ||
| 248 | :group 'org-startup | ||
| 249 | :type 'boolean) | ||
| 250 | |||
| 251 | (if (fboundp 'defvaralias) | ||
| 252 | (defvaralias 'org-CUA-compatible 'org-replace-disputed-keys)) | ||
| 253 | |||
| 254 | (defcustom org-disputed-keys | ||
| 255 | '(([(shift up)] . [(meta p)]) | ||
| 256 | ([(shift down)] . [(meta n)]) | ||
| 257 | ([(shift left)] . [(meta -)]) | ||
| 258 | ([(shift right)] . [(meta +)]) | ||
| 259 | ([(control shift right)] . [(meta shift +)]) | ||
| 260 | ([(control shift left)] . [(meta shift -)])) | ||
| 261 | "Keys for which Org-mode and other modes compete. | ||
| 262 | This is an alist, cars are the default keys, second element specifies | ||
| 263 | the alternative to use when `org-replace-disputed-keys' is t. | ||
| 264 | |||
| 265 | Keys can be specified in any syntax supported by `define-key'. | ||
| 266 | The value of this option takes effect only at Org-mode's startup, | ||
| 267 | therefore you'll have to restart Emacs to apply it after changing." | ||
| 268 | :group 'org-startup | ||
| 269 | :type 'alist) | ||
| 270 | |||
| 271 | (defun org-key (key) | ||
| 272 | "Select key according to `org-replace-disputed-keys' and `org-disputed-keys'. | ||
| 273 | Or return the original if not disputed." | ||
| 274 | (if org-replace-disputed-keys | ||
| 275 | (let* ((nkey (key-description key)) | ||
| 276 | (x (org-find-if (lambda (x) | ||
| 277 | (equal (key-description (car x)) nkey)) | ||
| 278 | org-disputed-keys))) | ||
| 279 | (if x (cdr x) key)) | ||
| 280 | key)) | ||
| 281 | |||
| 282 | (defun org-find-if (predicate seq) | ||
| 283 | (catch 'exit | ||
| 284 | (while seq | ||
| 285 | (if (funcall predicate (car seq)) | ||
| 286 | (throw 'exit (car seq)) | ||
| 287 | (pop seq))))) | ||
| 288 | |||
| 289 | (defun org-defkey (keymap key def) | ||
| 290 | "Define a key, possibly translated, as returned by `org-key'." | ||
| 291 | (define-key keymap (org-key key) def)) | ||
| 292 | |||
| 293 | (defcustom org-ellipsis nil | ||
| 294 | "The ellipsis to use in the Org-mode outline. | ||
| 295 | When nil, just use the standard three dots. When a string, use that instead, | ||
| 296 | When a face, use the standart 3 dots, but with the specified face. | ||
| 297 | The change affects only Org-mode (which will then use its own display table). | ||
| 298 | Changing this requires executing `M-x org-mode' in a buffer to become | ||
| 299 | effective." | ||
| 300 | :group 'org-startup | ||
| 301 | :type '(choice (const :tag "Default" nil) | ||
| 302 | (face :tag "Face" :value org-warning) | ||
| 303 | (string :tag "String" :value "...#"))) | ||
| 304 | |||
| 305 | (defvar org-display-table nil | ||
| 306 | "The display table for org-mode, in case `org-ellipsis' is non-nil.") | ||
| 307 | |||
| 308 | (defgroup org-keywords nil | ||
| 309 | "Keywords in Org-mode." | ||
| 310 | :tag "Org Keywords" | ||
| 311 | :group 'org) | ||
| 312 | |||
| 313 | (defcustom org-deadline-string "DEADLINE:" | ||
| 314 | "String to mark deadline entries. | ||
| 315 | A deadline is this string, followed by a time stamp. Should be a word, | ||
| 316 | terminated by a colon. You can insert a schedule keyword and | ||
| 317 | a timestamp with \\[org-deadline]. | ||
| 318 | Changes become only effective after restarting Emacs." | ||
| 319 | :group 'org-keywords | ||
| 320 | :type 'string) | ||
| 321 | |||
| 322 | (defcustom org-scheduled-string "SCHEDULED:" | ||
| 323 | "String to mark scheduled TODO entries. | ||
| 324 | A schedule is this string, followed by a time stamp. Should be a word, | ||
| 325 | terminated by a colon. You can insert a schedule keyword and | ||
| 326 | a timestamp with \\[org-schedule]. | ||
| 327 | Changes become only effective after restarting Emacs." | ||
| 328 | :group 'org-keywords | ||
| 329 | :type 'string) | ||
| 330 | |||
| 331 | (defcustom org-closed-string "CLOSED:" | ||
| 332 | "String used as the prefix for timestamps logging closing a TODO entry." | ||
| 333 | :group 'org-keywords | ||
| 334 | :type 'string) | ||
| 335 | |||
| 336 | (defcustom org-clock-string "CLOCK:" | ||
| 337 | "String used as prefix for timestamps clocking work hours on an item." | ||
| 338 | :group 'org-keywords | ||
| 339 | :type 'string) | ||
| 340 | |||
| 341 | (defcustom org-comment-string "COMMENT" | ||
| 342 | "Entries starting with this keyword will never be exported. | ||
| 343 | An entry can be toggled between COMMENT and normal with | ||
| 344 | \\[org-toggle-comment]. | ||
| 345 | Changes become only effective after restarting Emacs." | ||
| 346 | :group 'org-keywords | ||
| 347 | :type 'string) | ||
| 348 | |||
| 349 | (defcustom org-quote-string "QUOTE" | ||
| 350 | "Entries starting with this keyword will be exported in fixed-width font. | ||
| 351 | Quoting applies only to the text in the entry following the headline, and does | ||
| 352 | not extend beyond the next headline, even if that is lower level. | ||
| 353 | An entry can be toggled between QUOTE and normal with | ||
| 354 | \\[org-toggle-fixed-width-section]." | ||
| 355 | :group 'org-keywords | ||
| 356 | :type 'string) | ||
| 357 | |||
| 358 | (defconst org-repeat-re | ||
| 359 | "<[0-9]\\{4\\}-[0-9][0-9]-[0-9][0-9] [^>\n]*\\([.+]?\\+[0-9]+[dwmy]\\)" | ||
| 360 | "Regular expression for specifying repeated events. | ||
| 361 | After a match, group 1 contains the repeat expression.") | ||
| 362 | |||
| 363 | (defgroup org-structure nil | ||
| 364 | "Options concerning the general structure of Org-mode files." | ||
| 365 | :tag "Org Structure" | ||
| 366 | :group 'org) | ||
| 367 | |||
| 368 | (defgroup org-reveal-location nil | ||
| 369 | "Options about how to make context of a location visible." | ||
| 370 | :tag "Org Reveal Location" | ||
| 371 | :group 'org-structure) | ||
| 372 | |||
| 373 | (defconst org-context-choice | ||
| 374 | '(choice | ||
| 375 | (const :tag "Always" t) | ||
| 376 | (const :tag "Never" nil) | ||
| 377 | (repeat :greedy t :tag "Individual contexts" | ||
| 378 | (cons | ||
| 379 | (choice :tag "Context" | ||
| 380 | (const agenda) | ||
| 381 | (const org-goto) | ||
| 382 | (const occur-tree) | ||
| 383 | (const tags-tree) | ||
| 384 | (const link-search) | ||
| 385 | (const mark-goto) | ||
| 386 | (const bookmark-jump) | ||
| 387 | (const isearch) | ||
| 388 | (const default)) | ||
| 389 | (boolean)))) | ||
| 390 | "Contexts for the reveal options.") | ||
| 391 | |||
| 392 | (defcustom org-show-hierarchy-above '((default . t)) | ||
| 393 | "Non-nil means, show full hierarchy when revealing a location. | ||
| 394 | Org-mode often shows locations in an org-mode file which might have | ||
| 395 | been invisible before. When this is set, the hierarchy of headings | ||
| 396 | above the exposed location is shown. | ||
| 397 | Turning this off for example for sparse trees makes them very compact. | ||
| 398 | Instead of t, this can also be an alist specifying this option for different | ||
| 399 | contexts. Valid contexts are | ||
| 400 | agenda when exposing an entry from the agenda | ||
| 401 | org-goto when using the command `org-goto' on key C-c C-j | ||
| 402 | occur-tree when using the command `org-occur' on key C-c / | ||
| 403 | tags-tree when constructing a sparse tree based on tags matches | ||
| 404 | link-search when exposing search matches associated with a link | ||
| 405 | mark-goto when exposing the jump goal of a mark | ||
| 406 | bookmark-jump when exposing a bookmark location | ||
| 407 | isearch when exiting from an incremental search | ||
| 408 | default default for all contexts not set explicitly" | ||
| 409 | :group 'org-reveal-location | ||
| 410 | :type org-context-choice) | ||
| 411 | |||
| 412 | (defcustom org-show-following-heading '((default . nil)) | ||
| 413 | "Non-nil means, show following heading when revealing a location. | ||
| 414 | Org-mode often shows locations in an org-mode file which might have | ||
| 415 | been invisible before. When this is set, the heading following the | ||
| 416 | match is shown. | ||
| 417 | Turning this off for example for sparse trees makes them very compact, | ||
| 418 | but makes it harder to edit the location of the match. In such a case, | ||
| 419 | use the command \\[org-reveal] to show more context. | ||
| 420 | Instead of t, this can also be an alist specifying this option for different | ||
| 421 | contexts. See `org-show-hierarchy-above' for valid contexts." | ||
| 422 | :group 'org-reveal-location | ||
| 423 | :type org-context-choice) | ||
| 424 | |||
| 425 | (defcustom org-show-siblings '((default . nil) (isearch t)) | ||
| 426 | "Non-nil means, show all sibling heading when revealing a location. | ||
| 427 | Org-mode often shows locations in an org-mode file which might have | ||
| 428 | been invisible before. When this is set, the sibling of the current entry | ||
| 429 | heading are all made visible. If `org-show-hierarchy-above' is t, | ||
| 430 | the same happens on each level of the hierarchy above the current entry. | ||
| 431 | |||
| 432 | By default this is on for the isearch context, off for all other contexts. | ||
| 433 | Turning this off for example for sparse trees makes them very compact, | ||
| 434 | but makes it harder to edit the location of the match. In such a case, | ||
| 435 | use the command \\[org-reveal] to show more context. | ||
| 436 | Instead of t, this can also be an alist specifying this option for different | ||
| 437 | contexts. See `org-show-hierarchy-above' for valid contexts." | ||
| 438 | :group 'org-reveal-location | ||
| 439 | :type org-context-choice) | ||
| 440 | |||
| 441 | (defcustom org-show-entry-below '((default . nil)) | ||
| 442 | "Non-nil means, show the entry below a headline when revealing a location. | ||
| 443 | Org-mode often shows locations in an org-mode file which might have | ||
| 444 | been invisible before. When this is set, the text below the headline that is | ||
| 445 | exposed is also shown. | ||
| 446 | |||
| 447 | By default this is off for all contexts. | ||
| 448 | Instead of t, this can also be an alist specifying this option for different | ||
| 449 | contexts. See `org-show-hierarchy-above' for valid contexts." | ||
| 450 | :group 'org-reveal-location | ||
| 451 | :type org-context-choice) | ||
| 452 | |||
| 453 | (defgroup org-cycle nil | ||
| 454 | "Options concerning visibility cycling in Org-mode." | ||
| 455 | :tag "Org Cycle" | ||
| 456 | :group 'org-structure) | ||
| 457 | |||
| 458 | (defcustom org-drawers '("PROPERTIES" "CLOCK") | ||
| 459 | "Names of drawers. Drawers are not opened by cycling on the headline above. | ||
| 460 | Drawers only open with a TAB on the drawer line itself. A drawer looks like | ||
| 461 | this: | ||
| 462 | :DRAWERNAME: | ||
| 463 | ..... | ||
| 464 | :END: | ||
| 465 | The drawer \"PROPERTIES\" is special for capturing properties through | ||
| 466 | the property API. | ||
| 467 | |||
| 468 | Drawers can be defined on the per-file basis with a line like: | ||
| 469 | |||
| 470 | #+DRAWERS: HIDDEN STATE PROPERTIES" | ||
| 471 | :group 'org-structure | ||
| 472 | :type '(repeat (string :tag "Drawer Name"))) | ||
| 473 | |||
| 474 | (defcustom org-cycle-global-at-bob nil | ||
| 475 | "Cycle globally if cursor is at beginning of buffer and not at a headline. | ||
| 476 | This makes it possible to do global cycling without having to use S-TAB or | ||
| 477 | C-u TAB. For this special case to work, the first line of the buffer | ||
| 478 | must not be a headline - it may be empty ot some other text. When used in | ||
| 479 | this way, `org-cycle-hook' is disables temporarily, to make sure the | ||
| 480 | cursor stays at the beginning of the buffer. | ||
| 481 | When this option is nil, don't do anything special at the beginning | ||
| 482 | of the buffer." | ||
| 483 | :group 'org-cycle | ||
| 484 | :type 'boolean) | ||
| 485 | |||
| 486 | (defcustom org-cycle-emulate-tab t | ||
| 487 | "Where should `org-cycle' emulate TAB. | ||
| 488 | nil Never | ||
| 489 | white Only in completely white lines | ||
| 490 | whitestart Only at the beginning of lines, before the first non-white char | ||
| 491 | t Everywhere except in headlines | ||
| 492 | exc-hl-bol Everywhere except at the start of a headline | ||
| 493 | If TAB is used in a place where it does not emulate TAB, the current subtree | ||
| 494 | visibility is cycled." | ||
| 495 | :group 'org-cycle | ||
| 496 | :type '(choice (const :tag "Never" nil) | ||
| 497 | (const :tag "Only in completely white lines" white) | ||
| 498 | (const :tag "Before first char in a line" whitestart) | ||
| 499 | (const :tag "Everywhere except in headlines" t) | ||
| 500 | (const :tag "Everywhere except at bol in headlines" exc-hl-bol) | ||
| 501 | )) | ||
| 502 | |||
| 503 | (defcustom org-cycle-separator-lines 2 | ||
| 504 | "Number of empty lines needed to keep an empty line between collapsed trees. | ||
| 505 | If you leave an empty line between the end of a subtree and the following | ||
| 506 | headline, this empty line is hidden when the subtree is folded. | ||
| 507 | Org-mode will leave (exactly) one empty line visible if the number of | ||
| 508 | empty lines is equal or larger to the number given in this variable. | ||
| 509 | So the default 2 means, at least 2 empty lines after the end of a subtree | ||
| 510 | are needed to produce free space between a collapsed subtree and the | ||
| 511 | following headline. | ||
| 512 | |||
| 513 | Special case: when 0, never leave empty lines in collapsed view." | ||
| 514 | :group 'org-cycle | ||
| 515 | :type 'integer) | ||
| 516 | |||
| 517 | (defcustom org-cycle-hook '(org-cycle-hide-archived-subtrees | ||
| 518 | org-cycle-hide-drawers | ||
| 519 | org-cycle-show-empty-lines | ||
| 520 | org-optimize-window-after-visibility-change) | ||
| 521 | "Hook that is run after `org-cycle' has changed the buffer visibility. | ||
| 522 | The function(s) in this hook must accept a single argument which indicates | ||
| 523 | the new state that was set by the most recent `org-cycle' command. The | ||
| 524 | argument is a symbol. After a global state change, it can have the values | ||
| 525 | `overview', `content', or `all'. After a local state change, it can have | ||
| 526 | the values `folded', `children', or `subtree'." | ||
| 527 | :group 'org-cycle | ||
| 528 | :type 'hook) | ||
| 529 | |||
| 530 | (defgroup org-edit-structure nil | ||
| 531 | "Options concerning structure editing in Org-mode." | ||
| 532 | :tag "Org Edit Structure" | ||
| 533 | :group 'org-structure) | ||
| 534 | |||
| 535 | (defcustom org-odd-levels-only nil | ||
| 536 | "Non-nil means, skip even levels and only use odd levels for the outline. | ||
| 537 | This has the effect that two stars are being added/taken away in | ||
| 538 | promotion/demotion commands. It also influences how levels are | ||
| 539 | handled by the exporters. | ||
| 540 | Changing it requires restart of `font-lock-mode' to become effective | ||
| 541 | for fontification also in regions already fontified. | ||
| 542 | You may also set this on a per-file basis by adding one of the following | ||
| 543 | lines to the buffer: | ||
| 544 | |||
| 545 | #+STARTUP: odd | ||
| 546 | #+STARTUP: oddeven" | ||
| 547 | :group 'org-edit-structure | ||
| 548 | :group 'org-font-lock | ||
| 549 | :type 'boolean) | ||
| 550 | |||
| 551 | (defcustom org-adapt-indentation t | ||
| 552 | "Non-nil means, adapt indentation when promoting and demoting. | ||
| 553 | When this is set and the *entire* text in an entry is indented, the | ||
| 554 | indentation is increased by one space in a demotion command, and | ||
| 555 | decreased by one in a promotion command. If any line in the entry | ||
| 556 | body starts at column 0, indentation is not changed at all." | ||
| 557 | :group 'org-edit-structure | ||
| 558 | :type 'boolean) | ||
| 559 | |||
| 560 | (defcustom org-special-ctrl-a/e nil | ||
| 561 | "Non-nil means `C-a' and `C-e' behave specially in headlines and items. | ||
| 562 | When t, `C-a' will bring back the cursor to the beginning of the | ||
| 563 | headline text, i.e. after the stars and after a possible TODO keyword. | ||
| 564 | In an item, this will be the position after the bullet. | ||
| 565 | When the cursor is already at that position, another `C-a' will bring | ||
| 566 | it to the beginning of the line. | ||
| 567 | `C-e' will jump to the end of the headline, ignoring the presence of tags | ||
| 568 | in the headline. A second `C-e' will then jump to the true end of the | ||
| 569 | line, after any tags. | ||
| 570 | When set to the symbol `reversed', the first `C-a' or `C-e' works normally, | ||
| 571 | and only a directly following, identical keypress will bring the cursor | ||
| 572 | to the special positions." | ||
| 573 | :group 'org-edit-structure | ||
| 574 | :type '(choice | ||
| 575 | (const :tag "off" nil) | ||
| 576 | (const :tag "after bullet first" t) | ||
| 577 | (const :tag "border first" reversed))) | ||
| 578 | |||
| 579 | (if (fboundp 'defvaralias) | ||
| 580 | (defvaralias 'org-special-ctrl-a 'org-special-ctrl-a/e)) | ||
| 581 | |||
| 582 | (defcustom org-special-ctrl-k nil | ||
| 583 | "Non-nil means `C-k' will behave specially in headlines. | ||
| 584 | When nil, `C-k' will call the default `kill-line' command. | ||
| 585 | When t, the following will happen while the cursor is in the headline: | ||
| 586 | |||
| 587 | - When the cursor is at the beginning of a headline, kill the entire | ||
| 588 | line and possible the folded subtree below the line. | ||
| 589 | - When in the middle of the headline text, kill the headline up to the tags. | ||
| 590 | - When after the headline text, kill the tags." | ||
| 591 | :group 'org-edit-structure | ||
| 592 | :type 'boolean) | ||
| 593 | |||
| 594 | (defcustom org-M-RET-may-split-line '((default . t)) | ||
| 595 | "Non-nil means, M-RET will split the line at the cursor position. | ||
| 596 | When nil, it will go to the end of the line before making a | ||
| 597 | new line. | ||
| 598 | You may also set this option in a different way for different | ||
| 599 | contexts. Valid contexts are: | ||
| 600 | |||
| 601 | headline when creating a new headline | ||
| 602 | item when creating a new item | ||
| 603 | table in a table field | ||
| 604 | default the value to be used for all contexts not explicitly | ||
| 605 | customized" | ||
| 606 | :group 'org-structure | ||
| 607 | :group 'org-table | ||
| 608 | :type '(choice | ||
| 609 | (const :tag "Always" t) | ||
| 610 | (const :tag "Never" nil) | ||
| 611 | (repeat :greedy t :tag "Individual contexts" | ||
| 612 | (cons | ||
| 613 | (choice :tag "Context" | ||
| 614 | (const headline) | ||
| 615 | (const item) | ||
| 616 | (const table) | ||
| 617 | (const default)) | ||
| 618 | (boolean))))) | ||
| 619 | |||
| 620 | |||
| 621 | (defcustom org-blank-before-new-entry '((heading . nil) | ||
| 622 | (plain-list-item . nil)) | ||
| 623 | "Should `org-insert-heading' leave a blank line before new heading/item? | ||
| 624 | The value is an alist, with `heading' and `plain-list-item' as car, | ||
| 625 | and a boolean flag as cdr." | ||
| 626 | :group 'org-edit-structure | ||
| 627 | :type '(list | ||
| 628 | (cons (const heading) (boolean)) | ||
| 629 | (cons (const plain-list-item) (boolean)))) | ||
| 630 | |||
| 631 | (defcustom org-insert-heading-hook nil | ||
| 632 | "Hook being run after inserting a new heading." | ||
| 633 | :group 'org-edit-structure | ||
| 634 | :type 'hook) | ||
| 635 | |||
| 636 | (defcustom org-enable-fixed-width-editor t | ||
| 637 | "Non-nil means, lines starting with \":\" are treated as fixed-width. | ||
| 638 | This currently only means, they are never auto-wrapped. | ||
| 639 | When nil, such lines will be treated like ordinary lines. | ||
| 640 | See also the QUOTE keyword." | ||
| 641 | :group 'org-edit-structure | ||
| 642 | :type 'boolean) | ||
| 643 | |||
| 644 | (defcustom org-goto-auto-isearch t | ||
| 645 | "Non-nil means, typing characters in org-goto starts incremental search." | ||
| 646 | :group 'org-edit-structure | ||
| 647 | :type 'boolean) | ||
| 648 | |||
| 649 | (defgroup org-sparse-trees nil | ||
| 650 | "Options concerning sparse trees in Org-mode." | ||
| 651 | :tag "Org Sparse Trees" | ||
| 652 | :group 'org-structure) | ||
| 653 | |||
| 654 | (defcustom org-highlight-sparse-tree-matches t | ||
| 655 | "Non-nil means, highlight all matches that define a sparse tree. | ||
| 656 | The highlights will automatically disappear the next time the buffer is | ||
| 657 | changed by an edit command." | ||
| 658 | :group 'org-sparse-trees | ||
| 659 | :type 'boolean) | ||
| 660 | |||
| 661 | (defcustom org-remove-highlights-with-change t | ||
| 662 | "Non-nil means, any change to the buffer will remove temporary highlights. | ||
| 663 | Such highlights are created by `org-occur' and `org-clock-display'. | ||
| 664 | When nil, `C-c C-c needs to be used to get rid of the highlights. | ||
| 665 | The highlights created by `org-preview-latex-fragment' always need | ||
| 666 | `C-c C-c' to be removed." | ||
| 667 | :group 'org-sparse-trees | ||
| 668 | :group 'org-time | ||
| 669 | :type 'boolean) | ||
| 670 | |||
| 671 | |||
| 672 | (defcustom org-occur-hook '(org-first-headline-recenter) | ||
| 673 | "Hook that is run after `org-occur' has constructed a sparse tree. | ||
| 674 | This can be used to recenter the window to show as much of the structure | ||
| 675 | as possible." | ||
| 676 | :group 'org-sparse-trees | ||
| 677 | :type 'hook) | ||
| 678 | |||
| 679 | (defgroup org-plain-lists nil | ||
| 680 | "Options concerning plain lists in Org-mode." | ||
| 681 | :tag "Org Plain lists" | ||
| 682 | :group 'org-structure) | ||
| 683 | |||
| 684 | (defcustom org-cycle-include-plain-lists nil | ||
| 685 | "Non-nil means, include plain lists into visibility cycling. | ||
| 686 | This means that during cycling, plain list items will *temporarily* be | ||
| 687 | interpreted as outline headlines with a level given by 1000+i where i is the | ||
| 688 | indentation of the bullet. In all other operations, plain list items are | ||
| 689 | not seen as headlines. For example, you cannot assign a TODO keyword to | ||
| 690 | such an item." | ||
| 691 | :group 'org-plain-lists | ||
| 692 | :type 'boolean) | ||
| 693 | |||
| 694 | (defcustom org-plain-list-ordered-item-terminator t | ||
| 695 | "The character that makes a line with leading number an ordered list item. | ||
| 696 | Valid values are ?. and ?\). To get both terminators, use t. While | ||
| 697 | ?. may look nicer, it creates the danger that a line with leading | ||
| 698 | number may be incorrectly interpreted as an item. ?\) therefore is | ||
| 699 | the safe choice." | ||
| 700 | :group 'org-plain-lists | ||
| 701 | :type '(choice (const :tag "dot like in \"2.\"" ?.) | ||
| 702 | (const :tag "paren like in \"2)\"" ?\)) | ||
| 703 | (const :tab "both" t))) | ||
| 704 | |||
| 705 | (defcustom org-auto-renumber-ordered-lists t | ||
| 706 | "Non-nil means, automatically renumber ordered plain lists. | ||
| 707 | Renumbering happens when the sequence have been changed with | ||
| 708 | \\[org-shiftmetaup] or \\[org-shiftmetadown]. After other editing commands, | ||
| 709 | use \\[org-ctrl-c-ctrl-c] to trigger renumbering." | ||
| 710 | :group 'org-plain-lists | ||
| 711 | :type 'boolean) | ||
| 712 | |||
| 713 | (defcustom org-provide-checkbox-statistics t | ||
| 714 | "Non-nil means, update checkbox statistics after insert and toggle. | ||
| 715 | When this is set, checkbox statistics is updated each time you either insert | ||
| 716 | a new checkbox with \\[org-insert-todo-heading] or toggle a checkbox | ||
| 717 | with \\[org-ctrl-c-ctrl-c\\]." | ||
| 718 | :group 'org-plain-lists | ||
| 719 | :type 'boolean) | ||
| 720 | |||
| 721 | (defgroup org-archive nil | ||
| 722 | "Options concerning archiving in Org-mode." | ||
| 723 | :tag "Org Archive" | ||
| 724 | :group 'org-structure) | ||
| 725 | |||
| 726 | (defcustom org-archive-tag "ARCHIVE" | ||
| 727 | "The tag that marks a subtree as archived. | ||
| 728 | An archived subtree does not open during visibility cycling, and does | ||
| 729 | not contribute to the agenda listings. | ||
| 730 | After changing this, font-lock must be restarted in the relevant buffers to | ||
| 731 | get the proper fontification." | ||
| 732 | :group 'org-archive | ||
| 733 | :group 'org-keywords | ||
| 734 | :type 'string) | ||
| 735 | |||
| 736 | (defcustom org-agenda-skip-archived-trees t | ||
| 737 | "Non-nil means, the agenda will skip any items located in archived trees. | ||
| 738 | An archived tree is a tree marked with the tag ARCHIVE." | ||
| 739 | :group 'org-archive | ||
| 740 | :group 'org-agenda-skip | ||
| 741 | :type 'boolean) | ||
| 742 | |||
| 743 | (defcustom org-cycle-open-archived-trees nil | ||
| 744 | "Non-nil means, `org-cycle' will open archived trees. | ||
| 745 | An archived tree is a tree marked with the tag ARCHIVE. | ||
| 746 | When nil, archived trees will stay folded. You can still open them with | ||
| 747 | normal outline commands like `show-all', but not with the cycling commands." | ||
| 748 | :group 'org-archive | ||
| 749 | :group 'org-cycle | ||
| 750 | :type 'boolean) | ||
| 751 | |||
| 752 | (defcustom org-sparse-tree-open-archived-trees nil | ||
| 753 | "Non-nil means sparse tree construction shows matches in archived trees. | ||
| 754 | When nil, matches in these trees are highlighted, but the trees are kept in | ||
| 755 | collapsed state." | ||
| 756 | :group 'org-archive | ||
| 757 | :group 'org-sparse-trees | ||
| 758 | :type 'boolean) | ||
| 759 | |||
| 760 | (defcustom org-archive-location "%s_archive::" | ||
| 761 | "The location where subtrees should be archived. | ||
| 762 | This string consists of two parts, separated by a double-colon. | ||
| 763 | |||
| 764 | The first part is a file name - when omitted, archiving happens in the same | ||
| 765 | file. %s will be replaced by the current file name (without directory part). | ||
| 766 | Archiving to a different file is useful to keep archived entries from | ||
| 767 | contributing to the Org-mode Agenda. | ||
| 768 | |||
| 769 | The part after the double colon is a headline. The archived entries will be | ||
| 770 | filed under that headline. When omitted, the subtrees are simply filed away | ||
| 771 | at the end of the file, as top-level entries. | ||
| 772 | |||
| 773 | Here are a few examples: | ||
| 774 | \"%s_archive::\" | ||
| 775 | If the current file is Projects.org, archive in file | ||
| 776 | Projects.org_archive, as top-level trees. This is the default. | ||
| 777 | |||
| 778 | \"::* Archived Tasks\" | ||
| 779 | Archive in the current file, under the top-level headline | ||
| 780 | \"* Archived Tasks\". | ||
| 781 | |||
| 782 | \"~/org/archive.org::\" | ||
| 783 | Archive in file ~/org/archive.org (absolute path), as top-level trees. | ||
| 784 | |||
| 785 | \"basement::** Finished Tasks\" | ||
| 786 | Archive in file ./basement (relative path), as level 3 trees | ||
| 787 | below the level 2 heading \"** Finished Tasks\". | ||
| 788 | |||
| 789 | You may set this option on a per-file basis by adding to the buffer a | ||
| 790 | line like | ||
| 791 | |||
| 792 | #+ARCHIVE: basement::** Finished Tasks" | ||
| 793 | :group 'org-archive | ||
| 794 | :type 'string) | ||
| 795 | |||
| 796 | (defcustom org-archive-mark-done t | ||
| 797 | "Non-nil means, mark entries as DONE when they are moved to the archive file. | ||
| 798 | This can be a string to set the keyword to use. When t, Org-mode will | ||
| 799 | use the first keyword in its list that means done." | ||
| 800 | :group 'org-archive | ||
| 801 | :type '(choice | ||
| 802 | (const :tag "No" nil) | ||
| 803 | (const :tag "Yes" t) | ||
| 804 | (string :tag "Use this keyword"))) | ||
| 805 | |||
| 806 | (defcustom org-archive-stamp-time t | ||
| 807 | "Non-nil means, add a time stamp to entries moved to an archive file. | ||
| 808 | This variable is obsolete and has no effect anymore, instead add ot remove | ||
| 809 | `time' from the variablle `org-archive-save-context-info'." | ||
| 810 | :group 'org-archive | ||
| 811 | :type 'boolean) | ||
| 812 | |||
| 813 | (defcustom org-archive-save-context-info '(time file olpath category todo itags) | ||
| 814 | "Parts of context info that should be stored as properties when archiving. | ||
| 815 | When a subtree is moved to an archive file, it looses information given by | ||
| 816 | context, like inherited tags, the category, and possibly also the TODO | ||
| 817 | state (depending on the variable `org-archive-mark-done'). | ||
| 818 | This variable can be a list of any of the following symbols: | ||
| 819 | |||
| 820 | time The time of archiving. | ||
| 821 | file The file where the entry originates. | ||
| 822 | itags The local tags, in the headline of the subtree. | ||
| 823 | ltags The tags the subtree inherits from further up the hierarchy. | ||
| 824 | todo The pre-archive TODO state. | ||
| 825 | category The category, taken from file name or #+CATEGORY lines. | ||
| 826 | olpath The outline path to the item. These are all headlines above | ||
| 827 | the current item, separated by /, like a file path. | ||
| 828 | |||
| 829 | For each symbol present in the list, a property will be created in | ||
| 830 | the archived entry, with a prefix \"PRE_ARCHIVE_\", to remember this | ||
| 831 | information." | ||
| 832 | :group 'org-archive | ||
| 833 | :type '(set :greedy t | ||
| 834 | (const :tag "Time" time) | ||
| 835 | (const :tag "File" file) | ||
| 836 | (const :tag "Category" category) | ||
| 837 | (const :tag "TODO state" todo) | ||
| 838 | (const :tag "TODO state" priority) | ||
| 839 | (const :tag "Inherited tags" itags) | ||
| 840 | (const :tag "Outline path" olpath) | ||
| 841 | (const :tag "Local tags" ltags))) | ||
| 842 | |||
| 843 | (defgroup org-imenu-and-speedbar nil | ||
| 844 | "Options concerning imenu and speedbar in Org-mode." | ||
| 845 | :tag "Org Imenu and Speedbar" | ||
| 846 | :group 'org-structure) | ||
| 847 | |||
| 848 | (defcustom org-imenu-depth 2 | ||
| 849 | "The maximum level for Imenu access to Org-mode headlines. | ||
| 850 | This also applied for speedbar access." | ||
| 851 | :group 'org-imenu-and-speedbar | ||
| 852 | :type 'number) | ||
| 853 | |||
| 854 | (defgroup org-table nil | ||
| 855 | "Options concerning tables in Org-mode." | ||
| 856 | :tag "Org Table" | ||
| 857 | :group 'org) | ||
| 858 | |||
| 859 | (defcustom org-enable-table-editor 'optimized | ||
| 860 | "Non-nil means, lines starting with \"|\" are handled by the table editor. | ||
| 861 | When nil, such lines will be treated like ordinary lines. | ||
| 862 | |||
| 863 | When equal to the symbol `optimized', the table editor will be optimized to | ||
| 864 | do the following: | ||
| 865 | - Automatic overwrite mode in front of whitespace in table fields. | ||
| 866 | This makes the structure of the table stay in tact as long as the edited | ||
| 867 | field does not exceed the column width. | ||
| 868 | - Minimize the number of realigns. Normally, the table is aligned each time | ||
| 869 | TAB or RET are pressed to move to another field. With optimization this | ||
| 870 | happens only if changes to a field might have changed the column width. | ||
| 871 | Optimization requires replacing the functions `self-insert-command', | ||
| 872 | `delete-char', and `backward-delete-char' in Org-mode buffers, with a | ||
| 873 | slight (in fact: unnoticeable) speed impact for normal typing. Org-mode is | ||
| 874 | very good at guessing when a re-align will be necessary, but you can always | ||
| 875 | force one with \\[org-ctrl-c-ctrl-c]. | ||
| 876 | |||
| 877 | If you would like to use the optimized version in Org-mode, but the | ||
| 878 | un-optimized version in OrgTbl-mode, see the variable `orgtbl-optimized'. | ||
| 879 | |||
| 880 | This variable can be used to turn on and off the table editor during a session, | ||
| 881 | but in order to toggle optimization, a restart is required. | ||
| 882 | |||
| 883 | See also the variable `org-table-auto-blank-field'." | ||
| 884 | :group 'org-table | ||
| 885 | :type '(choice | ||
| 886 | (const :tag "off" nil) | ||
| 887 | (const :tag "on" t) | ||
| 888 | (const :tag "on, optimized" optimized))) | ||
| 889 | |||
| 890 | (defcustom orgtbl-optimized (eq org-enable-table-editor 'optimized) | ||
| 891 | "Non-nil means, use the optimized table editor version for `orgtbl-mode'. | ||
| 892 | In the optimized version, the table editor takes over all simple keys that | ||
| 893 | normally just insert a character. In tables, the characters are inserted | ||
| 894 | in a way to minimize disturbing the table structure (i.e. in overwrite mode | ||
| 895 | for empty fields). Outside tables, the correct binding of the keys is | ||
| 896 | restored. | ||
| 897 | |||
| 898 | The default for this option is t if the optimized version is also used in | ||
| 899 | Org-mode. See the variable `org-enable-table-editor' for details. Changing | ||
| 900 | this variable requires a restart of Emacs to become effective." | ||
| 901 | :group 'org-table | ||
| 902 | :type 'boolean) | ||
| 903 | |||
| 904 | (defcustom orgtbl-radio-table-templates | ||
| 905 | '((latex-mode "% BEGIN RECEIVE ORGTBL %n | ||
| 906 | % END RECEIVE ORGTBL %n | ||
| 907 | \\begin{comment} | ||
| 908 | #+ORGTBL: SEND %n orgtbl-to-latex :splice nil :skip 0 | ||
| 909 | | | | | ||
| 910 | \\end{comment}\n") | ||
| 911 | (texinfo-mode "@c BEGIN RECEIVE ORGTBL %n | ||
| 912 | @c END RECEIVE ORGTBL %n | ||
| 913 | @ignore | ||
| 914 | #+ORGTBL: SEND %n orgtbl-to-html :splice nil :skip 0 | ||
| 915 | | | | | ||
| 916 | @end ignore\n") | ||
| 917 | (html-mode "<!-- BEGIN RECEIVE ORGTBL %n --> | ||
| 918 | <!-- END RECEIVE ORGTBL %n --> | ||
| 919 | <!-- | ||
| 920 | #+ORGTBL: SEND %n orgtbl-to-html :splice nil :skip 0 | ||
| 921 | | | | | ||
| 922 | -->\n")) | ||
| 923 | "Templates for radio tables in different major modes. | ||
| 924 | All occurrences of %n in a template will be replaced with the name of the | ||
| 925 | table, obtained by prompting the user." | ||
| 926 | :group 'org-table | ||
| 927 | :type '(repeat | ||
| 928 | (list (symbol :tag "Major mode") | ||
| 929 | (string :tag "Format")))) | ||
| 930 | |||
| 931 | (defgroup org-table-settings nil | ||
| 932 | "Settings for tables in Org-mode." | ||
| 933 | :tag "Org Table Settings" | ||
| 934 | :group 'org-table) | ||
| 935 | |||
| 936 | (defcustom org-table-default-size "5x2" | ||
| 937 | "The default size for newly created tables, Columns x Rows." | ||
| 938 | :group 'org-table-settings | ||
| 939 | :type 'string) | ||
| 940 | |||
| 941 | (defcustom org-table-number-regexp | ||
| 942 | "^\\([<>]?[-+^.0-9]*[0-9][-+^.0-9eEdDx()%:]*\\|\\(0[xX]\\)[0-9a-fA-F]+\\|nan\\)$" | ||
| 943 | "Regular expression for recognizing numbers in table columns. | ||
| 944 | If a table column contains mostly numbers, it will be aligned to the | ||
| 945 | right. If not, it will be aligned to the left. | ||
| 946 | |||
| 947 | The default value of this option is a regular expression which allows | ||
| 948 | anything which looks remotely like a number as used in scientific | ||
| 949 | context. For example, all of the following will be considered a | ||
| 950 | number: | ||
| 951 | 12 12.2 2.4e-08 2x10^12 4.034+-0.02 2.7(10) >3.5 | ||
| 952 | |||
| 953 | Other options offered by the customize interface are more restrictive." | ||
| 954 | :group 'org-table-settings | ||
| 955 | :type '(choice | ||
| 956 | (const :tag "Positive Integers" | ||
| 957 | "^[0-9]+$") | ||
| 958 | (const :tag "Integers" | ||
| 959 | "^[-+]?[0-9]+$") | ||
| 960 | (const :tag "Floating Point Numbers" | ||
| 961 | "^[-+]?\\([0-9]*\\.[0-9]+\\|[0-9]+\\.[0-9]*\\)$") | ||
| 962 | (const :tag "Floating Point Number or Integer" | ||
| 963 | "^[-+]?\\([0-9]*\\.[0-9]+\\|[0-9]+\\.?[0-9]*\\)$") | ||
| 964 | (const :tag "Exponential, Floating point, Integer" | ||
| 965 | "^[-+]?[0-9.]+\\([eEdD][-+0-9]+\\)?$") | ||
| 966 | (const :tag "Very General Number-Like, including hex" | ||
| 967 | "^\\([<>]?[-+^.0-9]*[0-9][-+^.0-9eEdDx()%]*\\|\\(0[xX]\\)[0-9a-fA-F]+\\|nan\\)$") | ||
| 968 | (string :tag "Regexp:"))) | ||
| 969 | |||
| 970 | (defcustom org-table-number-fraction 0.5 | ||
| 971 | "Fraction of numbers in a column required to make the column align right. | ||
| 972 | In a column all non-white fields are considered. If at least this | ||
| 973 | fraction of fields is matched by `org-table-number-fraction', | ||
| 974 | alignment to the right border applies." | ||
| 975 | :group 'org-table-settings | ||
| 976 | :type 'number) | ||
| 977 | |||
| 978 | (defgroup org-table-editing nil | ||
| 979 | "Behavior of tables during editing in Org-mode." | ||
| 980 | :tag "Org Table Editing" | ||
| 981 | :group 'org-table) | ||
| 982 | |||
| 983 | (defcustom org-table-automatic-realign t | ||
| 984 | "Non-nil means, automatically re-align table when pressing TAB or RETURN. | ||
| 985 | When nil, aligning is only done with \\[org-table-align], or after column | ||
| 986 | removal/insertion." | ||
| 987 | :group 'org-table-editing | ||
| 988 | :type 'boolean) | ||
| 989 | |||
| 990 | (defcustom org-table-auto-blank-field t | ||
| 991 | "Non-nil means, automatically blank table field when starting to type into it. | ||
| 992 | This only happens when typing immediately after a field motion | ||
| 993 | command (TAB, S-TAB or RET). | ||
| 994 | Only relevant when `org-enable-table-editor' is equal to `optimized'." | ||
| 995 | :group 'org-table-editing | ||
| 996 | :type 'boolean) | ||
| 997 | |||
| 998 | (defcustom org-table-tab-jumps-over-hlines t | ||
| 999 | "Non-nil means, tab in the last column of a table with jump over a hline. | ||
| 1000 | If a horizontal separator line is following the current line, | ||
| 1001 | `org-table-next-field' can either create a new row before that line, or jump | ||
| 1002 | over the line. When this option is nil, a new line will be created before | ||
| 1003 | this line." | ||
| 1004 | :group 'org-table-editing | ||
| 1005 | :type 'boolean) | ||
| 1006 | |||
| 1007 | (defcustom org-table-tab-recognizes-table.el t | ||
| 1008 | "Non-nil means, TAB will automatically notice a table.el table. | ||
| 1009 | When it sees such a table, it moves point into it and - if necessary - | ||
| 1010 | calls `table-recognize-table'." | ||
| 1011 | :group 'org-table-editing | ||
| 1012 | :type 'boolean) | ||
| 1013 | |||
| 1014 | (defgroup org-table-calculation nil | ||
| 1015 | "Options concerning tables in Org-mode." | ||
| 1016 | :tag "Org Table Calculation" | ||
| 1017 | :group 'org-table) | ||
| 1018 | |||
| 1019 | (defcustom org-table-use-standard-references t | ||
| 1020 | "Should org-mode work with table refrences like B3 instead of @3$2? | ||
| 1021 | Possible values are: | ||
| 1022 | nil never use them | ||
| 1023 | from accept as input, do not present for editing | ||
| 1024 | t: accept as input and present for editing" | ||
| 1025 | :group 'org-table-calculation | ||
| 1026 | :type '(choice | ||
| 1027 | (const :tag "Never, don't even check unser input for them" nil) | ||
| 1028 | (const :tag "Always, both as user input, and when editing" t) | ||
| 1029 | (const :tag "Convert user input, don't offer during editing" 'from))) | ||
| 1030 | |||
| 1031 | (defcustom org-table-copy-increment t | ||
| 1032 | "Non-nil means, increment when copying current field with \\[org-table-copy-down]." | ||
| 1033 | :group 'org-table-calculation | ||
| 1034 | :type 'boolean) | ||
| 1035 | |||
| 1036 | (defcustom org-calc-default-modes | ||
| 1037 | '(calc-internal-prec 12 | ||
| 1038 | calc-float-format (float 5) | ||
| 1039 | calc-angle-mode deg | ||
| 1040 | calc-prefer-frac nil | ||
| 1041 | calc-symbolic-mode nil | ||
| 1042 | calc-date-format (YYYY "-" MM "-" DD " " Www (" " HH ":" mm)) | ||
| 1043 | calc-display-working-message t | ||
| 1044 | ) | ||
| 1045 | "List with Calc mode settings for use in calc-eval for table formulas. | ||
| 1046 | The list must contain alternating symbols (Calc modes variables and values). | ||
| 1047 | Don't remove any of the default settings, just change the values. Org-mode | ||
| 1048 | relies on the variables to be present in the list." | ||
| 1049 | :group 'org-table-calculation | ||
| 1050 | :type 'plist) | ||
| 1051 | |||
| 1052 | (defcustom org-table-formula-evaluate-inline t | ||
| 1053 | "Non-nil means, TAB and RET evaluate a formula in current table field. | ||
| 1054 | If the current field starts with an equal sign, it is assumed to be a formula | ||
| 1055 | which should be evaluated as described in the manual and in the documentation | ||
| 1056 | string of the command `org-table-eval-formula'. This feature requires the | ||
| 1057 | Emacs calc package. | ||
| 1058 | When this variable is nil, formula calculation is only available through | ||
| 1059 | the command \\[org-table-eval-formula]." | ||
| 1060 | :group 'org-table-calculation | ||
| 1061 | :type 'boolean) | ||
| 1062 | |||
| 1063 | (defcustom org-table-formula-use-constants t | ||
| 1064 | "Non-nil means, interpret constants in formulas in tables. | ||
| 1065 | A constant looks like `$c' or `$Grav' and will be replaced before evaluation | ||
| 1066 | by the value given in `org-table-formula-constants', or by a value obtained | ||
| 1067 | from the `constants.el' package." | ||
| 1068 | :group 'org-table-calculation | ||
| 1069 | :type 'boolean) | ||
| 1070 | |||
| 1071 | (defcustom org-table-formula-constants nil | ||
| 1072 | "Alist with constant names and values, for use in table formulas. | ||
| 1073 | The car of each element is a name of a constant, without the `$' before it. | ||
| 1074 | The cdr is the value as a string. For example, if you'd like to use the | ||
| 1075 | speed of light in a formula, you would configure | ||
| 1076 | |||
| 1077 | (setq org-table-formula-constants '((\"c\" . \"299792458.\"))) | ||
| 1078 | |||
| 1079 | and then use it in an equation like `$1*$c'. | ||
| 1080 | |||
| 1081 | Constants can also be defined on a per-file basis using a line like | ||
| 1082 | |||
| 1083 | #+CONSTANTS: c=299792458. pi=3.14 eps=2.4e-6" | ||
| 1084 | :group 'org-table-calculation | ||
| 1085 | :type '(repeat | ||
| 1086 | (cons (string :tag "name") | ||
| 1087 | (string :tag "value")))) | ||
| 1088 | |||
| 1089 | (defvar org-table-formula-constants-local nil | ||
| 1090 | "Local version of `org-table-formula-constants'.") | ||
| 1091 | (make-variable-buffer-local 'org-table-formula-constants-local) | ||
| 1092 | |||
| 1093 | (defcustom org-table-allow-automatic-line-recalculation t | ||
| 1094 | "Non-nil means, lines marked with |#| or |*| will be recomputed automatically. | ||
| 1095 | Automatically means, when TAB or RET or C-c C-c are pressed in the line." | ||
| 1096 | :group 'org-table-calculation | ||
| 1097 | :type 'boolean) | ||
| 1098 | |||
| 1099 | (defgroup org-link nil | ||
| 1100 | "Options concerning links in Org-mode." | ||
| 1101 | :tag "Org Link" | ||
| 1102 | :group 'org) | ||
| 1103 | |||
| 1104 | (defvar org-link-abbrev-alist-local nil | ||
| 1105 | "Buffer-local version of `org-link-abbrev-alist', which see. | ||
| 1106 | The value of this is taken from the #+LINK lines.") | ||
| 1107 | (make-variable-buffer-local 'org-link-abbrev-alist-local) | ||
| 1108 | |||
| 1109 | (defcustom org-link-abbrev-alist nil | ||
| 1110 | "Alist of link abbreviations. | ||
| 1111 | The car of each element is a string, to be replaced at the start of a link. | ||
| 1112 | The cdrs are replacement values, like (\"linkkey\" . REPLACE). Abbreviated | ||
| 1113 | links in Org-mode buffers can have an optional tag after a double colon, e.g. | ||
| 1114 | |||
| 1115 | [[linkkey:tag][description]] | ||
| 1116 | |||
| 1117 | If REPLACE is a string, the tag will simply be appended to create the link. | ||
| 1118 | If the string contains \"%s\", the tag will be inserted there. | ||
| 1119 | |||
| 1120 | REPLACE may also be a function that will be called with the tag as the | ||
| 1121 | only argument to create the link, which should be returned as a string. | ||
| 1122 | |||
| 1123 | See the manual for examples." | ||
| 1124 | :group 'org-link | ||
| 1125 | :type 'alist) | ||
| 1126 | |||
| 1127 | (defcustom org-descriptive-links t | ||
| 1128 | "Non-nil means, hide link part and only show description of bracket links. | ||
| 1129 | Bracket links are like [[link][descritpion]]. This variable sets the initial | ||
| 1130 | state in new org-mode buffers. The setting can then be toggled on a | ||
| 1131 | per-buffer basis from the Org->Hyperlinks menu." | ||
| 1132 | :group 'org-link | ||
| 1133 | :type 'boolean) | ||
| 1134 | |||
| 1135 | (defcustom org-link-file-path-type 'adaptive | ||
| 1136 | "How the path name in file links should be stored. | ||
| 1137 | Valid values are: | ||
| 1138 | |||
| 1139 | relative Relative to the current directory, i.e. the directory of the file | ||
| 1140 | into which the link is being inserted. | ||
| 1141 | absolute Absolute path, if possible with ~ for home directory. | ||
| 1142 | noabbrev Absolute path, no abbreviation of home directory. | ||
| 1143 | adaptive Use relative path for files in the current directory and sub- | ||
| 1144 | directories of it. For other files, use an absolute path." | ||
| 1145 | :group 'org-link | ||
| 1146 | :type '(choice | ||
| 1147 | (const relative) | ||
| 1148 | (const absolute) | ||
| 1149 | (const noabbrev) | ||
| 1150 | (const adaptive))) | ||
| 1151 | |||
| 1152 | (defcustom org-activate-links '(bracket angle plain radio tag date) | ||
| 1153 | "Types of links that should be activated in Org-mode files. | ||
| 1154 | This is a list of symbols, each leading to the activation of a certain link | ||
| 1155 | type. In principle, it does not hurt to turn on most link types - there may | ||
| 1156 | be a small gain when turning off unused link types. The types are: | ||
| 1157 | |||
| 1158 | bracket The recommended [[link][description]] or [[link]] links with hiding. | ||
| 1159 | angular Links in angular brackes that may contain whitespace like | ||
| 1160 | <bbdb:Carsten Dominik>. | ||
| 1161 | plain Plain links in normal text, no whitespace, like http://google.com. | ||
| 1162 | radio Text that is matched by a radio target, see manual for details. | ||
| 1163 | tag Tag settings in a headline (link to tag search). | ||
| 1164 | date Time stamps (link to calendar). | ||
| 1165 | |||
| 1166 | Changing this variable requires a restart of Emacs to become effective." | ||
| 1167 | :group 'org-link | ||
| 1168 | :type '(set (const :tag "Double bracket links (new style)" bracket) | ||
| 1169 | (const :tag "Angular bracket links (old style)" angular) | ||
| 1170 | (const :tag "Plain text links" plain) | ||
| 1171 | (const :tag "Radio target matches" radio) | ||
| 1172 | (const :tag "Tags" tag) | ||
| 1173 | (const :tag "Timestamps" date))) | ||
| 1174 | |||
| 1175 | (defgroup org-link-store nil | ||
| 1176 | "Options concerning storing links in Org-mode." | ||
| 1177 | :tag "Org Store Link" | ||
| 1178 | :group 'org-link) | ||
| 1179 | |||
| 1180 | (defcustom org-email-link-description-format "Email %c: %.30s" | ||
| 1181 | "Format of the description part of a link to an email or usenet message. | ||
| 1182 | The following %-excapes will be replaced by corresponding information: | ||
| 1183 | |||
| 1184 | %F full \"From\" field | ||
| 1185 | %f name, taken from \"From\" field, address if no name | ||
| 1186 | %T full \"To\" field | ||
| 1187 | %t first name in \"To\" field, address if no name | ||
| 1188 | %c correspondent. Unually \"from NAME\", but if you sent it yourself, it | ||
| 1189 | will be \"to NAME\". See also the variable `org-from-is-user-regexp'. | ||
| 1190 | %s subject | ||
| 1191 | %m message-id. | ||
| 1192 | |||
| 1193 | You may use normal field width specification between the % and the letter. | ||
| 1194 | This is for example useful to limit the length of the subject. | ||
| 1195 | |||
| 1196 | Examples: \"%f on: %.30s\", \"Email from %f\", \"Email %c\"" | ||
| 1197 | :group 'org-link-store | ||
| 1198 | :type 'string) | ||
| 1199 | |||
| 1200 | (defcustom org-from-is-user-regexp | ||
| 1201 | (let (r1 r2) | ||
| 1202 | (when (and user-mail-address (not (string= user-mail-address ""))) | ||
| 1203 | (setq r1 (concat "\\<" (regexp-quote user-mail-address) "\\>"))) | ||
| 1204 | (when (and user-full-name (not (string= user-full-name ""))) | ||
| 1205 | (setq r2 (concat "\\<" (regexp-quote user-full-name) "\\>"))) | ||
| 1206 | (if (and r1 r2) (concat r1 "\\|" r2) (or r1 r2))) | ||
| 1207 | "Regexp mached against the \"From:\" header of an email or usenet message. | ||
| 1208 | It should match if the message is from the user him/herself." | ||
| 1209 | :group 'org-link-store | ||
| 1210 | :type 'regexp) | ||
| 1211 | |||
| 1212 | (defcustom org-context-in-file-links t | ||
| 1213 | "Non-nil means, file links from `org-store-link' contain context. | ||
| 1214 | A search string will be added to the file name with :: as separator and | ||
| 1215 | used to find the context when the link is activated by the command | ||
| 1216 | `org-open-at-point'. | ||
| 1217 | Using a prefix arg to the command \\[org-store-link] (`org-store-link') | ||
| 1218 | negates this setting for the duration of the command." | ||
| 1219 | :group 'org-link-store | ||
| 1220 | :type 'boolean) | ||
| 1221 | |||
| 1222 | (defcustom org-keep-stored-link-after-insertion nil | ||
| 1223 | "Non-nil means, keep link in list for entire session. | ||
| 1224 | |||
| 1225 | The command `org-store-link' adds a link pointing to the current | ||
| 1226 | location to an internal list. These links accumulate during a session. | ||
| 1227 | The command `org-insert-link' can be used to insert links into any | ||
| 1228 | Org-mode file (offering completion for all stored links). When this | ||
| 1229 | option is nil, every link which has been inserted once using \\[org-insert-link] | ||
| 1230 | will be removed from the list, to make completing the unused links | ||
| 1231 | more efficient." | ||
| 1232 | :group 'org-link-store | ||
| 1233 | :type 'boolean) | ||
| 1234 | |||
| 1235 | (defcustom org-usenet-links-prefer-google nil | ||
| 1236 | "Non-nil means, `org-store-link' will create web links to Google groups. | ||
| 1237 | When nil, Gnus will be used for such links. | ||
| 1238 | Using a prefix arg to the command \\[org-store-link] (`org-store-link') | ||
| 1239 | negates this setting for the duration of the command." | ||
| 1240 | :group 'org-link-store | ||
| 1241 | :type 'boolean) | ||
| 1242 | |||
| 1243 | (defgroup org-link-follow nil | ||
| 1244 | "Options concerning following links in Org-mode." | ||
| 1245 | :tag "Org Follow Link" | ||
| 1246 | :group 'org-link) | ||
| 1247 | |||
| 1248 | (defcustom org-follow-link-hook nil | ||
| 1249 | "Hook that is run after a link has been followed." | ||
| 1250 | :group 'org-link-follow | ||
| 1251 | :type 'hook) | ||
| 1252 | |||
| 1253 | (defcustom org-tab-follows-link nil | ||
| 1254 | "Non-nil means, on links TAB will follow the link. | ||
| 1255 | Needs to be set before org.el is loaded." | ||
| 1256 | :group 'org-link-follow | ||
| 1257 | :type 'boolean) | ||
| 1258 | |||
| 1259 | (defcustom org-return-follows-link nil | ||
| 1260 | "Non-nil means, on links RET will follow the link. | ||
| 1261 | Needs to be set before org.el is loaded." | ||
| 1262 | :group 'org-link-follow | ||
| 1263 | :type 'boolean) | ||
| 1264 | |||
| 1265 | (defcustom org-mouse-1-follows-link | ||
| 1266 | (if (boundp 'mouse-1-click-follows-link) mouse-1-click-follows-link t) | ||
| 1267 | "Non-nil means, mouse-1 on a link will follow the link. | ||
| 1268 | A longer mouse click will still set point. Does not work on XEmacs. | ||
| 1269 | Needs to be set before org.el is loaded." | ||
| 1270 | :group 'org-link-follow | ||
| 1271 | :type 'boolean) | ||
| 1272 | |||
| 1273 | (defcustom org-mark-ring-length 4 | ||
| 1274 | "Number of different positions to be recorded in the ring | ||
| 1275 | Changing this requires a restart of Emacs to work correctly." | ||
| 1276 | :group 'org-link-follow | ||
| 1277 | :type 'interger) | ||
| 1278 | |||
| 1279 | (defcustom org-link-frame-setup | ||
| 1280 | '((vm . vm-visit-folder-other-frame) | ||
| 1281 | (gnus . gnus-other-frame) | ||
| 1282 | (file . find-file-other-window)) | ||
| 1283 | "Setup the frame configuration for following links. | ||
| 1284 | When following a link with Emacs, it may often be useful to display | ||
| 1285 | this link in another window or frame. This variable can be used to | ||
| 1286 | set this up for the different types of links. | ||
| 1287 | For VM, use any of | ||
| 1288 | `vm-visit-folder' | ||
| 1289 | `vm-visit-folder-other-frame' | ||
| 1290 | For Gnus, use any of | ||
| 1291 | `gnus' | ||
| 1292 | `gnus-other-frame' | ||
| 1293 | For FILE, use any of | ||
| 1294 | `find-file' | ||
| 1295 | `find-file-other-window' | ||
| 1296 | `find-file-other-frame' | ||
| 1297 | For the calendar, use the variable `calendar-setup'. | ||
| 1298 | For BBDB, it is currently only possible to display the matches in | ||
| 1299 | another window." | ||
| 1300 | :group 'org-link-follow | ||
| 1301 | :type '(list | ||
| 1302 | (cons (const vm) | ||
| 1303 | (choice | ||
| 1304 | (const vm-visit-folder) | ||
| 1305 | (const vm-visit-folder-other-window) | ||
| 1306 | (const vm-visit-folder-other-frame))) | ||
| 1307 | (cons (const gnus) | ||
| 1308 | (choice | ||
| 1309 | (const gnus) | ||
| 1310 | (const gnus-other-frame))) | ||
| 1311 | (cons (const file) | ||
| 1312 | (choice | ||
| 1313 | (const find-file) | ||
| 1314 | (const find-file-other-window) | ||
| 1315 | (const find-file-other-frame))))) | ||
| 1316 | |||
| 1317 | (defcustom org-display-internal-link-with-indirect-buffer nil | ||
| 1318 | "Non-nil means, use indirect buffer to display infile links. | ||
| 1319 | Activating internal links (from one location in a file to another location | ||
| 1320 | in the same file) normally just jumps to the location. When the link is | ||
| 1321 | activated with a C-u prefix (or with mouse-3), the link is displayed in | ||
| 1322 | another window. When this option is set, the other window actually displays | ||
| 1323 | an indirect buffer clone of the current buffer, to avoid any visibility | ||
| 1324 | changes to the current buffer." | ||
| 1325 | :group 'org-link-follow | ||
| 1326 | :type 'boolean) | ||
| 1327 | |||
| 1328 | (defcustom org-open-non-existing-files nil | ||
| 1329 | "Non-nil means, `org-open-file' will open non-existing files. | ||
| 1330 | When nil, an error will be generated." | ||
| 1331 | :group 'org-link-follow | ||
| 1332 | :type 'boolean) | ||
| 1333 | |||
| 1334 | (defcustom org-link-mailto-program '(browse-url "mailto:%a?subject=%s") | ||
| 1335 | "Function and arguments to call for following mailto links. | ||
| 1336 | This is a list with the first element being a lisp function, and the | ||
| 1337 | remaining elements being arguments to the function. In string arguments, | ||
| 1338 | %a will be replaced by the address, and %s will be replaced by the subject | ||
| 1339 | if one was given like in <mailto:arthur@galaxy.org::this subject>." | ||
| 1340 | :group 'org-link-follow | ||
| 1341 | :type '(choice | ||
| 1342 | (const :tag "browse-url" (browse-url-mail "mailto:%a?subject=%s")) | ||
| 1343 | (const :tag "compose-mail" (compose-mail "%a" "%s")) | ||
| 1344 | (const :tag "message-mail" (message-mail "%a" "%s")) | ||
| 1345 | (cons :tag "other" (function) (repeat :tag "argument" sexp)))) | ||
| 1346 | |||
| 1347 | (defcustom org-confirm-shell-link-function 'yes-or-no-p | ||
| 1348 | "Non-nil means, ask for confirmation before executing shell links. | ||
| 1349 | Shell links can be dangerous: just think about a link | ||
| 1350 | |||
| 1351 | [[shell:rm -rf ~/*][Google Search]] | ||
| 1352 | |||
| 1353 | This link would show up in your Org-mode document as \"Google Search\", | ||
| 1354 | but really it would remove your entire home directory. | ||
| 1355 | Therefore we advise against setting this variable to nil. | ||
| 1356 | Just change it to `y-or-n-p' of you want to confirm with a | ||
| 1357 | single keystroke rather than having to type \"yes\"." | ||
| 1358 | :group 'org-link-follow | ||
| 1359 | :type '(choice | ||
| 1360 | (const :tag "with yes-or-no (safer)" yes-or-no-p) | ||
| 1361 | (const :tag "with y-or-n (faster)" y-or-n-p) | ||
| 1362 | (const :tag "no confirmation (dangerous)" nil))) | ||
| 1363 | |||
| 1364 | (defcustom org-confirm-elisp-link-function 'yes-or-no-p | ||
| 1365 | "Non-nil means, ask for confirmation before executing Emacs Lisp links. | ||
| 1366 | Elisp links can be dangerous: just think about a link | ||
| 1367 | |||
| 1368 | [[elisp:(shell-command \"rm -rf ~/*\")][Google Search]] | ||
| 1369 | |||
| 1370 | This link would show up in your Org-mode document as \"Google Search\", | ||
| 1371 | but really it would remove your entire home directory. | ||
| 1372 | Therefore we advise against setting this variable to nil. | ||
| 1373 | Just change it to `y-or-n-p' of you want to confirm with a | ||
| 1374 | single keystroke rather than having to type \"yes\"." | ||
| 1375 | :group 'org-link-follow | ||
| 1376 | :type '(choice | ||
| 1377 | (const :tag "with yes-or-no (safer)" yes-or-no-p) | ||
| 1378 | (const :tag "with y-or-n (faster)" y-or-n-p) | ||
| 1379 | (const :tag "no confirmation (dangerous)" nil))) | ||
| 1380 | |||
| 1381 | (defconst org-file-apps-defaults-gnu | ||
| 1382 | '((remote . emacs) | ||
| 1383 | (t . mailcap)) | ||
| 1384 | "Default file applications on a UNIX or GNU/Linux system. | ||
| 1385 | See `org-file-apps'.") | ||
| 1386 | |||
| 1387 | (defconst org-file-apps-defaults-macosx | ||
| 1388 | '((remote . emacs) | ||
| 1389 | (t . "open %s") | ||
| 1390 | ("ps" . "gv %s") | ||
| 1391 | ("ps.gz" . "gv %s") | ||
| 1392 | ("eps" . "gv %s") | ||
| 1393 | ("eps.gz" . "gv %s") | ||
| 1394 | ("dvi" . "xdvi %s") | ||
| 1395 | ("fig" . "xfig %s")) | ||
| 1396 | "Default file applications on a MacOS X system. | ||
| 1397 | The system \"open\" is known as a default, but we use X11 applications | ||
| 1398 | for some files for which the OS does not have a good default. | ||
| 1399 | See `org-file-apps'.") | ||
| 1400 | |||
| 1401 | (defconst org-file-apps-defaults-windowsnt | ||
| 1402 | (list | ||
| 1403 | '(remote . emacs) | ||
| 1404 | (cons t | ||
| 1405 | (list (if (featurep 'xemacs) | ||
| 1406 | 'mswindows-shell-execute | ||
| 1407 | 'w32-shell-execute) | ||
| 1408 | "open" 'file))) | ||
| 1409 | "Default file applications on a Windows NT system. | ||
| 1410 | The system \"open\" is used for most files. | ||
| 1411 | See `org-file-apps'.") | ||
| 1412 | |||
| 1413 | (defcustom org-file-apps | ||
| 1414 | '( | ||
| 1415 | ("txt" . emacs) | ||
| 1416 | ("tex" . emacs) | ||
| 1417 | ("ltx" . emacs) | ||
| 1418 | ("org" . emacs) | ||
| 1419 | ("el" . emacs) | ||
| 1420 | ("bib" . emacs) | ||
| 1421 | ) | ||
| 1422 | "External applications for opening `file:path' items in a document. | ||
| 1423 | Org-mode uses system defaults for different file types, but | ||
| 1424 | you can use this variable to set the application for a given file | ||
| 1425 | extension. The entries in this list are cons cells where the car identifies | ||
| 1426 | files and the cdr the corresponding command. Possible values for the | ||
| 1427 | file identifier are | ||
| 1428 | \"ext\" A string identifying an extension | ||
| 1429 | `directory' Matches a directory | ||
| 1430 | `remote' Matches a remote file, accessible through tramp or efs. | ||
| 1431 | Remote files most likely should be visited through Emacs | ||
| 1432 | because external applications cannot handle such paths. | ||
| 1433 | t Default for all remaining files | ||
| 1434 | |||
| 1435 | Possible values for the command are: | ||
| 1436 | `emacs' The file will be visited by the current Emacs process. | ||
| 1437 | `default' Use the default application for this file type. | ||
| 1438 | string A command to be executed by a shell; %s will be replaced | ||
| 1439 | by the path to the file. | ||
| 1440 | sexp A Lisp form which will be evaluated. The file path will | ||
| 1441 | be available in the Lisp variable `file'. | ||
| 1442 | For more examples, see the system specific constants | ||
| 1443 | `org-file-apps-defaults-macosx' | ||
| 1444 | `org-file-apps-defaults-windowsnt' | ||
| 1445 | `org-file-apps-defaults-gnu'." | ||
| 1446 | :group 'org-link-follow | ||
| 1447 | :type '(repeat | ||
| 1448 | (cons (choice :value "" | ||
| 1449 | (string :tag "Extension") | ||
| 1450 | (const :tag "Default for unrecognized files" t) | ||
| 1451 | (const :tag "Remote file" remote) | ||
| 1452 | (const :tag "Links to a directory" directory)) | ||
| 1453 | (choice :value "" | ||
| 1454 | (const :tag "Visit with Emacs" emacs) | ||
| 1455 | (const :tag "Use system default" default) | ||
| 1456 | (string :tag "Command") | ||
| 1457 | (sexp :tag "Lisp form"))))) | ||
| 1458 | |||
| 1459 | (defcustom org-mhe-search-all-folders nil | ||
| 1460 | "Non-nil means, that the search for the mh-message will be extended to | ||
| 1461 | all folders if the message cannot be found in the folder given in the link. | ||
| 1462 | Searching all folders is very efficient with one of the search engines | ||
| 1463 | supported by MH-E, but will be slow with pick." | ||
| 1464 | :group 'org-link-follow | ||
| 1465 | :type 'boolean) | ||
| 1466 | |||
| 1467 | (defgroup org-remember nil | ||
| 1468 | "Options concerning interaction with remember.el." | ||
| 1469 | :tag "Org Remember" | ||
| 1470 | :group 'org) | ||
| 1471 | |||
| 1472 | (defcustom org-directory "~/org" | ||
| 1473 | "Directory with org files. | ||
| 1474 | This directory will be used as default to prompt for org files. | ||
| 1475 | Used by the hooks for remember.el." | ||
| 1476 | :group 'org-remember | ||
| 1477 | :type 'directory) | ||
| 1478 | |||
| 1479 | (defcustom org-default-notes-file "~/.notes" | ||
| 1480 | "Default target for storing notes. | ||
| 1481 | Used by the hooks for remember.el. This can be a string, or nil to mean | ||
| 1482 | the value of `remember-data-file'. | ||
| 1483 | You can set this on a per-template basis with the variable | ||
| 1484 | `org-remember-templates'." | ||
| 1485 | :group 'org-remember | ||
| 1486 | :type '(choice | ||
| 1487 | (const :tag "Default from remember-data-file" nil) | ||
| 1488 | file)) | ||
| 1489 | |||
| 1490 | (defcustom org-remember-store-without-prompt t | ||
| 1491 | "Non-nil means, `C-c C-c' stores remember note without further promts. | ||
| 1492 | In this case, you need `C-u C-c C-c' to get the prompts for | ||
| 1493 | note file and headline. | ||
| 1494 | When this variable is nil, `C-c C-c' give you the prompts, and | ||
| 1495 | `C-u C-c C-c' trigger the fasttrack." | ||
| 1496 | :group 'org-remember | ||
| 1497 | :type 'boolean) | ||
| 1498 | |||
| 1499 | (defcustom org-remember-interactive-interface 'refile | ||
| 1500 | "The interface to be used for interactive filing of remember notes. | ||
| 1501 | This is only used when the interactive mode for selecting a filing | ||
| 1502 | location is used (see the variable `org-remember-store-without-prompt'). | ||
| 1503 | Allowed vaues are: | ||
| 1504 | outline The interface shows an outline of the relevant file | ||
| 1505 | and the correct heading is found by moving through | ||
| 1506 | the outline or by searching with incremental search. | ||
| 1507 | outline-path-completion Headlines in the current buffer are offered via | ||
| 1508 | completion. | ||
| 1509 | refile Use the refile interface, and offer headlines, | ||
| 1510 | possibly from different buffers." | ||
| 1511 | :group 'org-remember | ||
| 1512 | :type '(choice | ||
| 1513 | (const :tag "Refile" refile) | ||
| 1514 | (const :tag "Outline" outline) | ||
| 1515 | (const :tag "Outline-path-completion" outline-path-completion))) | ||
| 1516 | |||
| 1517 | (defcustom org-goto-interface 'outline | ||
| 1518 | "The default interface to be used for `org-goto'. | ||
| 1519 | Allowed vaues are: | ||
| 1520 | outline The interface shows an outline of the relevant file | ||
| 1521 | and the correct heading is found by moving through | ||
| 1522 | the outline or by searching with incremental search. | ||
| 1523 | outline-path-completion Headlines in the current buffer are offered via | ||
| 1524 | completion." | ||
| 1525 | :group 'org-remember ; FIXME: different group for org-goto and org-refile | ||
| 1526 | :type '(choice | ||
| 1527 | (const :tag "Outline" outline) | ||
| 1528 | (const :tag "Outline-path-completion" outline-path-completion))) | ||
| 1529 | |||
| 1530 | (defcustom org-remember-default-headline "" | ||
| 1531 | "The headline that should be the default location in the notes file. | ||
| 1532 | When filing remember notes, the cursor will start at that position. | ||
| 1533 | You can set this on a per-template basis with the variable | ||
| 1534 | `org-remember-templates'." | ||
| 1535 | :group 'org-remember | ||
| 1536 | :type 'string) | ||
| 1537 | |||
| 1538 | (defcustom org-remember-templates nil | ||
| 1539 | "Templates for the creation of remember buffers. | ||
| 1540 | When nil, just let remember make the buffer. | ||
| 1541 | When not nil, this is a list of 5-element lists. In each entry, the first | ||
| 1542 | element is the name of the template, which should be a single short word. | ||
| 1543 | The second element is a character, a unique key to select this template. | ||
| 1544 | The third element is the template. The fourth element is optional and can | ||
| 1545 | specify a destination file for remember items created with this template. | ||
| 1546 | The default file is given by `org-default-notes-file'. An optional fifth | ||
| 1547 | element can specify the headline in that file that should be offered | ||
| 1548 | first when the user is asked to file the entry. The default headline is | ||
| 1549 | given in the variable `org-remember-default-headline'. | ||
| 1550 | |||
| 1551 | An optional sixth element specifies the contexts in which the user can | ||
| 1552 | select the template. This element can be either a list of major modes | ||
| 1553 | or a function. `org-remember' will first check whether the function | ||
| 1554 | returns `t' or if we are in any of the listed major modes, and select | ||
| 1555 | the template accordingly. | ||
| 1556 | |||
| 1557 | The template specifies the structure of the remember buffer. It should have | ||
| 1558 | a first line starting with a star, to act as the org-mode headline. | ||
| 1559 | Furthermore, the following %-escapes will be replaced with content: | ||
| 1560 | |||
| 1561 | %^{prompt} Prompt the user for a string and replace this sequence with it. | ||
| 1562 | A default value and a completion table ca be specified like this: | ||
| 1563 | %^{prompt|default|completion2|completion3|...} | ||
| 1564 | %t time stamp, date only | ||
| 1565 | %T time stamp with date and time | ||
| 1566 | %u, %U like the above, but inactive time stamps | ||
| 1567 | %^t like %t, but prompt for date. Similarly %^T, %^u, %^U | ||
| 1568 | You may define a prompt like %^{Please specify birthday}t | ||
| 1569 | %n user name (taken from `user-full-name') | ||
| 1570 | %a annotation, normally the link created with org-store-link | ||
| 1571 | %i initial content, the region active. If %i is indented, | ||
| 1572 | the entire inserted text will be indented as well. | ||
| 1573 | %c content of the clipboard, or current kill ring head | ||
| 1574 | %^g prompt for tags, with completion on tags in target file | ||
| 1575 | %^G prompt for tags, with completion all tags in all agenda files | ||
| 1576 | %:keyword specific information for certain link types, see below | ||
| 1577 | %[pathname] insert the contents of the file given by `pathname' | ||
| 1578 | %(sexp) evaluate elisp `(sexp)' and replace with the result | ||
| 1579 | %! Store this note immediately after filling the template | ||
| 1580 | |||
| 1581 | %? After completing the template, position cursor here. | ||
| 1582 | |||
| 1583 | Apart from these general escapes, you can access information specific to the | ||
| 1584 | link type that is created. For example, calling `remember' in emails or gnus | ||
| 1585 | will record the author and the subject of the message, which you can access | ||
| 1586 | with %:author and %:subject, respectively. Here is a complete list of what | ||
| 1587 | is recorded for each link type. | ||
| 1588 | |||
| 1589 | Link type | Available information | ||
| 1590 | -------------------+------------------------------------------------------ | ||
| 1591 | bbdb | %:type %:name %:company | ||
| 1592 | vm, wl, mh, rmail | %:type %:subject %:message-id | ||
| 1593 | | %:from %:fromname %:fromaddress | ||
| 1594 | | %:to %:toname %:toaddress | ||
| 1595 | | %:fromto (either \"to NAME\" or \"from NAME\") | ||
| 1596 | gnus | %:group, for messages also all email fields | ||
| 1597 | w3, w3m | %:type %:url | ||
| 1598 | info | %:type %:file %:node | ||
| 1599 | calendar | %:type %:date" | ||
| 1600 | :group 'org-remember | ||
| 1601 | :get (lambda (var) ; Make sure all entries have at least 5 elements | ||
| 1602 | (mapcar (lambda (x) | ||
| 1603 | (if (not (stringp (car x))) (setq x (cons "" x))) | ||
| 1604 | (cond ((= (length x) 4) (append x '(""))) | ||
| 1605 | ((= (length x) 3) (append x '("" ""))) | ||
| 1606 | (t x))) | ||
| 1607 | (default-value var))) | ||
| 1608 | :type '(repeat | ||
| 1609 | :tag "enabled" | ||
| 1610 | (list :value ("" ?a "\n" nil nil nil) | ||
| 1611 | (string :tag "Name") | ||
| 1612 | (character :tag "Selection Key") | ||
| 1613 | (string :tag "Template") | ||
| 1614 | (choice | ||
| 1615 | (file :tag "Destination file") | ||
| 1616 | (const :tag "Prompt for file" nil)) | ||
| 1617 | (choice | ||
| 1618 | (string :tag "Destination headline") | ||
| 1619 | (const :tag "Selection interface for heading")) | ||
| 1620 | (choice | ||
| 1621 | (const :tag "Use by default" nil) | ||
| 1622 | (const :tag "Use in all contexts" t) | ||
| 1623 | (repeat :tag "Use only if in major mode" | ||
| 1624 | (symbol :tag "Major mode")) | ||
| 1625 | (function :tag "Perform a check against function"))))) | ||
| 1626 | |||
| 1627 | (defcustom org-reverse-note-order nil | ||
| 1628 | "Non-nil means, store new notes at the beginning of a file or entry. | ||
| 1629 | When nil, new notes will be filed to the end of a file or entry. | ||
| 1630 | This can also be a list with cons cells of regular expressions that | ||
| 1631 | are matched against file names, and values." | ||
| 1632 | :group 'org-remember | ||
| 1633 | :type '(choice | ||
| 1634 | (const :tag "Reverse always" t) | ||
| 1635 | (const :tag "Reverse never" nil) | ||
| 1636 | (repeat :tag "By file name regexp" | ||
| 1637 | (cons regexp boolean)))) | ||
| 1638 | |||
| 1639 | (defcustom org-refile-targets nil | ||
| 1640 | "Targets for refiling entries with \\[org-refile]. | ||
| 1641 | This is list of cons cells. Each cell contains: | ||
| 1642 | - a specification of the files to be considered, either a list of files, | ||
| 1643 | or a symbol whose function or value fields will be used to retrieve | ||
| 1644 | a file name or a list of file names. Nil means, refile to a different | ||
| 1645 | heading in the current buffer. | ||
| 1646 | - A specification of how to find candidate refile targets. This may be | ||
| 1647 | any of | ||
| 1648 | - a cons cell (:tag . \"TAG\") to identify refile targets by a tag. | ||
| 1649 | This tag has to be present in all target headlines, inheritance will | ||
| 1650 | not be considered. | ||
| 1651 | - a cons cell (:todo . \"KEYWORD\") to identify refile targets by | ||
| 1652 | todo keyword. | ||
| 1653 | - a cons cell (:regexp . \"REGEXP\") with a regular expression matching | ||
| 1654 | headlines that are refiling targets. | ||
| 1655 | - a cons cell (:level . N). Any headline of level N is considered a target. | ||
| 1656 | - a cons cell (:maxlevel . N). Any headline with level <= N is a target." | ||
| 1657 | ;; FIXME: what if there are a var and func with same name??? | ||
| 1658 | :group 'org-remember | ||
| 1659 | :type '(repeat | ||
| 1660 | (cons | ||
| 1661 | (choice :value org-agenda-files | ||
| 1662 | (const :tag "All agenda files" org-agenda-files) | ||
| 1663 | (const :tag "Current buffer" nil) | ||
| 1664 | (function) (variable) (file)) | ||
| 1665 | (choice :tag "Identify target headline by" | ||
| 1666 | (cons :tag "Specific tag" (const :tag) (string)) | ||
| 1667 | (cons :tag "TODO keyword" (const :todo) (string)) | ||
| 1668 | (cons :tag "Regular expression" (const :regexp) (regexp)) | ||
| 1669 | (cons :tag "Level number" (const :level) (integer)) | ||
| 1670 | (cons :tag "Max Level number" (const :maxlevel) (integer)))))) | ||
| 1671 | |||
| 1672 | (defcustom org-refile-use-outline-path nil | ||
| 1673 | "Non-nil means, provide refile targets as paths. | ||
| 1674 | So a level 3 headline will be available as level1/level2/level3. | ||
| 1675 | When the value is `file', also include the file name (without directory) | ||
| 1676 | into the path. When `full-file-path', include the full file path." | ||
| 1677 | :group 'org-remember | ||
| 1678 | :type '(choice | ||
| 1679 | (const :tag "Not" nil) | ||
| 1680 | (const :tag "Yes" t) | ||
| 1681 | (const :tag "Start with file name" file) | ||
| 1682 | (const :tag "Start with full file path" full-file-path))) | ||
| 1683 | |||
| 1684 | (defgroup org-todo nil | ||
| 1685 | "Options concerning TODO items in Org-mode." | ||
| 1686 | :tag "Org TODO" | ||
| 1687 | :group 'org) | ||
| 1688 | |||
| 1689 | (defgroup org-progress nil | ||
| 1690 | "Options concerning Progress logging in Org-mode." | ||
| 1691 | :tag "Org Progress" | ||
| 1692 | :group 'org-time) | ||
| 1693 | |||
| 1694 | (defcustom org-todo-keywords '((sequence "TODO" "DONE")) | ||
| 1695 | "List of TODO entry keyword sequences and their interpretation. | ||
| 1696 | \\<org-mode-map>This is a list of sequences. | ||
| 1697 | |||
| 1698 | Each sequence starts with a symbol, either `sequence' or `type', | ||
| 1699 | indicating if the keywords should be interpreted as a sequence of | ||
| 1700 | action steps, or as different types of TODO items. The first | ||
| 1701 | keywords are states requiring action - these states will select a headline | ||
| 1702 | for inclusion into the global TODO list Org-mode produces. If one of | ||
| 1703 | the \"keywords\" is the vertical bat \"|\" the remaining keywords | ||
| 1704 | signify that no further action is necessary. If \"|\" is not found, | ||
| 1705 | the last keyword is treated as the only DONE state of the sequence. | ||
| 1706 | |||
| 1707 | The command \\[org-todo] cycles an entry through these states, and one | ||
| 1708 | additional state where no keyword is present. For details about this | ||
| 1709 | cycling, see the manual. | ||
| 1710 | |||
| 1711 | TODO keywords and interpretation can also be set on a per-file basis with | ||
| 1712 | the special #+SEQ_TODO and #+TYP_TODO lines. | ||
| 1713 | |||
| 1714 | Each keyword can optionally specify a character for fast state selection | ||
| 1715 | \(in combination with the variable `org-use-fast-todo-selection') | ||
| 1716 | and specifiers for state change logging, using the same syntax | ||
| 1717 | that is used in the \"#+TODO:\" lines. For example, \"WAIT(w)\" says | ||
| 1718 | that the WAIT state can be selected with the \"w\" key. \"WAIT(w!)\" | ||
| 1719 | indicates to record a time stamp each time this state is selected. | ||
| 1720 | |||
| 1721 | Each keyword may also specify if a timestamp or a note should be | ||
| 1722 | recorded when entering or leaving the state, by adding additional | ||
| 1723 | characters in the parenthesis after the keyword. This looks like this: | ||
| 1724 | \"WAIT(w@/!)\". \"@\" means to add a note (with time), \"!\" means to | ||
| 1725 | record only the time of the state change. With X and Y being either | ||
| 1726 | \"@\" or \"!\", \"X/Y\" means use X when entering the state, and use | ||
| 1727 | Y when leaving the state if and only if the *target* state does not | ||
| 1728 | define X. You may omit any of the fast-selection key or X or /Y, | ||
| 1729 | so WAIT(w@), WAIT(w/@) and WAIT(@/@) are all valid. | ||
| 1730 | |||
| 1731 | For backward compatibility, this variable may also be just a list | ||
| 1732 | of keywords - in this case the interptetation (sequence or type) will be | ||
| 1733 | taken from the (otherwise obsolete) variable `org-todo-interpretation'." | ||
| 1734 | :group 'org-todo | ||
| 1735 | :group 'org-keywords | ||
| 1736 | :type '(choice | ||
| 1737 | (repeat :tag "Old syntax, just keywords" | ||
| 1738 | (string :tag "Keyword")) | ||
| 1739 | (repeat :tag "New syntax" | ||
| 1740 | (cons | ||
| 1741 | (choice | ||
| 1742 | :tag "Interpretation" | ||
| 1743 | (const :tag "Sequence (cycling hits every state)" sequence) | ||
| 1744 | (const :tag "Type (cycling directly to DONE)" type)) | ||
| 1745 | (repeat | ||
| 1746 | (string :tag "Keyword")))))) | ||
| 1747 | |||
| 1748 | (defvar org-todo-keywords-1 nil | ||
| 1749 | "All TODO and DONE keywords active in a buffer.") | ||
| 1750 | (make-variable-buffer-local 'org-todo-keywords-1) | ||
| 1751 | (defvar org-todo-keywords-for-agenda nil) | ||
| 1752 | (defvar org-done-keywords-for-agenda nil) | ||
| 1753 | (defvar org-not-done-keywords nil) | ||
| 1754 | (make-variable-buffer-local 'org-not-done-keywords) | ||
| 1755 | (defvar org-done-keywords nil) | ||
| 1756 | (make-variable-buffer-local 'org-done-keywords) | ||
| 1757 | (defvar org-todo-heads nil) | ||
| 1758 | (make-variable-buffer-local 'org-todo-heads) | ||
| 1759 | (defvar org-todo-sets nil) | ||
| 1760 | (make-variable-buffer-local 'org-todo-sets) | ||
| 1761 | (defvar org-todo-log-states nil) | ||
| 1762 | (make-variable-buffer-local 'org-todo-log-states) | ||
| 1763 | (defvar org-todo-kwd-alist nil) | ||
| 1764 | (make-variable-buffer-local 'org-todo-kwd-alist) | ||
| 1765 | (defvar org-todo-key-alist nil) | ||
| 1766 | (make-variable-buffer-local 'org-todo-key-alist) | ||
| 1767 | (defvar org-todo-key-trigger nil) | ||
| 1768 | (make-variable-buffer-local 'org-todo-key-trigger) | ||
| 1769 | |||
| 1770 | (defcustom org-todo-interpretation 'sequence | ||
| 1771 | "Controls how TODO keywords are interpreted. | ||
| 1772 | This variable is in principle obsolete and is only used for | ||
| 1773 | backward compatibility, if the interpretation of todo keywords is | ||
| 1774 | not given already in `org-todo-keywords'. See that variable for | ||
| 1775 | more information." | ||
| 1776 | :group 'org-todo | ||
| 1777 | :group 'org-keywords | ||
| 1778 | :type '(choice (const sequence) | ||
| 1779 | (const type))) | ||
| 1780 | |||
| 1781 | (defcustom org-use-fast-todo-selection 'prefix | ||
| 1782 | "Non-nil means, use the fast todo selection scheme with C-c C-t. | ||
| 1783 | This variable describes if and under what circumstances the cycling | ||
| 1784 | mechanism for TODO keywords will be replaced by a single-key, direct | ||
| 1785 | selection scheme. | ||
| 1786 | |||
| 1787 | When nil, fast selection is never used. | ||
| 1788 | |||
| 1789 | When the symbol `prefix', it will be used when `org-todo' is called with | ||
| 1790 | a prefix argument, i.e. `C-u C-c C-t' in an Org-mode buffer, and `C-u t' | ||
| 1791 | in an agenda buffer. | ||
| 1792 | |||
| 1793 | When t, fast selection is used by default. In this case, the prefix | ||
| 1794 | argument forces cycling instead. | ||
| 1795 | |||
| 1796 | In all cases, the special interface is only used if access keys have actually | ||
| 1797 | been assigned by the user, i.e. if keywords in the configuration are followed | ||
| 1798 | by a letter in parenthesis, like TODO(t)." | ||
| 1799 | :group 'org-todo | ||
| 1800 | :type '(choice | ||
| 1801 | (const :tag "Never" nil) | ||
| 1802 | (const :tag "By default" t) | ||
| 1803 | (const :tag "Only with C-u C-c C-t" prefix))) | ||
| 1804 | |||
| 1805 | (defcustom org-after-todo-state-change-hook nil | ||
| 1806 | "Hook which is run after the state of a TODO item was changed. | ||
| 1807 | The new state (a string with a TODO keyword, or nil) is available in the | ||
| 1808 | Lisp variable `state'." | ||
| 1809 | :group 'org-todo | ||
| 1810 | :type 'hook) | ||
| 1811 | |||
| 1812 | (defcustom org-log-done nil | ||
| 1813 | "Non-nil means, record a CLOSED timestamp when moving an entry to DONE. | ||
| 1814 | When equal to the list (done), also prompt for a closing note. | ||
| 1815 | This can also be configured on a per-file basis by adding one of | ||
| 1816 | the following lines anywhere in the buffer: | ||
| 1817 | |||
| 1818 | #+STARTUP: logdone | ||
| 1819 | #+STARTUP: lognotedone | ||
| 1820 | #+STARTUP: nologdone" | ||
| 1821 | :group 'org-todo | ||
| 1822 | :group 'org-progress | ||
| 1823 | :type '(choice | ||
| 1824 | (const :tag "No logging" nil) | ||
| 1825 | (const :tag "Record CLOSED timestamp" time) | ||
| 1826 | (const :tag "Record CLOSED timestamp with closing note." note))) | ||
| 1827 | |||
| 1828 | ;; Normalize old uses of org-log-done. | ||
| 1829 | (cond | ||
| 1830 | ((eq org-log-done t) (setq org-log-done 'time)) | ||
| 1831 | ((and (listp org-log-done) (memq 'done org-log-done)) | ||
| 1832 | (setq org-log-done 'note))) | ||
| 1833 | |||
| 1834 | ;; FIXME: document | ||
| 1835 | (defcustom org-log-note-clock-out nil | ||
| 1836 | "Non-nil means, recored a note when clocking out of an item. | ||
| 1837 | This can also be configured on a per-file basis by adding one of | ||
| 1838 | the following lines anywhere in the buffer: | ||
| 1839 | |||
| 1840 | #+STARTUP: lognoteclock-out | ||
| 1841 | #+STARTUP: nolognoteclock-out" | ||
| 1842 | :group 'org-todo | ||
| 1843 | :group 'org-progress | ||
| 1844 | :type 'boolean) | ||
| 1845 | |||
| 1846 | (defcustom org-log-done-with-time t | ||
| 1847 | "Non-nil means, the CLOSED time stamp will contain date and time. | ||
| 1848 | When nil, only the date will be recorded." | ||
| 1849 | :group 'org-progress | ||
| 1850 | :type 'boolean) | ||
| 1851 | |||
| 1852 | (defcustom org-log-note-headings | ||
| 1853 | '((done . "CLOSING NOTE %t") | ||
| 1854 | (state . "State %-12s %t") | ||
| 1855 | (clock-out . "")) | ||
| 1856 | "Headings for notes added when clocking out or closing TODO items. | ||
| 1857 | The value is an alist, with the car being a symbol indicating the note | ||
| 1858 | context, and the cdr is the heading to be used. The heading may also be the | ||
| 1859 | empty string. | ||
| 1860 | %t in the heading will be replaced by a time stamp. | ||
| 1861 | %s will be replaced by the new TODO state, in double quotes. | ||
| 1862 | %u will be replaced by the user name. | ||
| 1863 | %U will be replaced by the full user name." | ||
| 1864 | :group 'org-todo | ||
| 1865 | :group 'org-progress | ||
| 1866 | :type '(list :greedy t | ||
| 1867 | (cons (const :tag "Heading when closing an item" done) string) | ||
| 1868 | (cons (const :tag | ||
| 1869 | "Heading when changing todo state (todo sequence only)" | ||
| 1870 | state) string) | ||
| 1871 | (cons (const :tag "Heading when clocking out" clock-out) string))) | ||
| 1872 | |||
| 1873 | (defcustom org-log-states-order-reversed t | ||
| 1874 | "Non-nil means, the latest state change note will be directly after heading. | ||
| 1875 | When nil, the notes will be orderer according to time." | ||
| 1876 | :group 'org-todo | ||
| 1877 | :group 'org-progress | ||
| 1878 | :type 'boolean) | ||
| 1879 | |||
| 1880 | (defcustom org-log-repeat 'time | ||
| 1881 | "Non-nil means, record moving through the DONE state when triggering repeat. | ||
| 1882 | An auto-repeating tasks is immediately switched back to TODO when marked | ||
| 1883 | done. If you are not logging state changes (by adding \"@\" or \"!\" to | ||
| 1884 | the TODO keyword definition, or recording a cloing note by setting | ||
| 1885 | `org-log-done', there will be no record of the task moving trhough DONE. | ||
| 1886 | This variable forces taking a note anyway. Possible values are: | ||
| 1887 | |||
| 1888 | nil Don't force a record | ||
| 1889 | time Record a time stamp | ||
| 1890 | note Record a note | ||
| 1891 | |||
| 1892 | This option can also be set with on a per-file-basis with | ||
| 1893 | |||
| 1894 | #+STARTUP: logrepeat | ||
| 1895 | #+STARTUP: lognoterepeat | ||
| 1896 | #+STARTUP: nologrepeat | ||
| 1897 | |||
| 1898 | You can have local logging settings for a subtree by setting the LOGGING | ||
| 1899 | property to one or more of these keywords." | ||
| 1900 | :group 'org-todo | ||
| 1901 | :group 'org-progress | ||
| 1902 | :type '(choice | ||
| 1903 | (const :tag "Don't force a record" nil) | ||
| 1904 | (const :tag "Force recording the DONE state" time) | ||
| 1905 | (const :tag "Force recording a note with the DONE state" note))) | ||
| 1906 | |||
| 1907 | (defcustom org-clock-into-drawer 2 | ||
| 1908 | "Should clocking info be wrapped into a drawer? | ||
| 1909 | When t, clocking info will always be inserted into a :CLOCK: drawer. | ||
| 1910 | If necessary, the drawer will be created. | ||
| 1911 | When nil, the drawer will not be created, but used when present. | ||
| 1912 | When an integer and the number of clocking entries in an item | ||
| 1913 | reaches or exceeds this number, a drawer will be created." | ||
| 1914 | :group 'org-todo | ||
| 1915 | :group 'org-progress | ||
| 1916 | :type '(choice | ||
| 1917 | (const :tag "Always" t) | ||
| 1918 | (const :tag "Only when drawer exists" nil) | ||
| 1919 | (integer :tag "When at least N clock entries"))) | ||
| 1920 | |||
| 1921 | (defcustom org-clock-out-when-done t | ||
| 1922 | "When t, the clock will be stopped when the relevant entry is marked DONE. | ||
| 1923 | Nil means, clock will keep running until stopped explicitly with | ||
| 1924 | `C-c C-x C-o', or until the clock is started in a different item." | ||
| 1925 | :group 'org-progress | ||
| 1926 | :type 'boolean) | ||
| 1927 | |||
| 1928 | (defcustom org-clock-in-switch-to-state nil | ||
| 1929 | "Set task to a special todo state while clocking it. | ||
| 1930 | The value should be the state to which the entry should be switched." | ||
| 1931 | :group 'org-progress | ||
| 1932 | :group 'org-todo | ||
| 1933 | :type '(choice | ||
| 1934 | (const :tag "Don't force a state" nil) | ||
| 1935 | (string :tag "State"))) | ||
| 1936 | |||
| 1937 | (defgroup org-priorities nil | ||
| 1938 | "Priorities in Org-mode." | ||
| 1939 | :tag "Org Priorities" | ||
| 1940 | :group 'org-todo) | ||
| 1941 | |||
| 1942 | (defcustom org-highest-priority ?A | ||
| 1943 | "The highest priority of TODO items. A character like ?A, ?B etc. | ||
| 1944 | Must have a smaller ASCII number than `org-lowest-priority'." | ||
| 1945 | :group 'org-priorities | ||
| 1946 | :type 'character) | ||
| 1947 | |||
| 1948 | (defcustom org-lowest-priority ?C | ||
| 1949 | "The lowest priority of TODO items. A character like ?A, ?B etc. | ||
| 1950 | Must have a larger ASCII number than `org-highest-priority'." | ||
| 1951 | :group 'org-priorities | ||
| 1952 | :type 'character) | ||
| 1953 | |||
| 1954 | (defcustom org-default-priority ?B | ||
| 1955 | "The default priority of TODO items. | ||
| 1956 | This is the priority an item get if no explicit priority is given." | ||
| 1957 | :group 'org-priorities | ||
| 1958 | :type 'character) | ||
| 1959 | |||
| 1960 | (defcustom org-priority-start-cycle-with-default t | ||
| 1961 | "Non-nil means, start with default priority when starting to cycle. | ||
| 1962 | When this is nil, the first step in the cycle will be (depending on the | ||
| 1963 | command used) one higher or lower that the default priority." | ||
| 1964 | :group 'org-priorities | ||
| 1965 | :type 'boolean) | ||
| 1966 | |||
| 1967 | (defgroup org-time nil | ||
| 1968 | "Options concerning time stamps and deadlines in Org-mode." | ||
| 1969 | :tag "Org Time" | ||
| 1970 | :group 'org) | ||
| 1971 | |||
| 1972 | (defcustom org-insert-labeled-timestamps-at-point nil | ||
| 1973 | "Non-nil means, SCHEDULED and DEADLINE timestamps are inserted at point. | ||
| 1974 | When nil, these labeled time stamps are forces into the second line of an | ||
| 1975 | entry, just after the headline. When scheduling from the global TODO list, | ||
| 1976 | the time stamp will always be forced into the second line." | ||
| 1977 | :group 'org-time | ||
| 1978 | :type 'boolean) | ||
| 1979 | |||
| 1980 | (defconst org-time-stamp-formats '("<%Y-%m-%d %a>" . "<%Y-%m-%d %a %H:%M>") | ||
| 1981 | "Formats for `format-time-string' which are used for time stamps. | ||
| 1982 | It is not recommended to change this constant.") | ||
| 1983 | |||
| 1984 | (defcustom org-time-stamp-rounding-minutes '(0 5) | ||
| 1985 | "Number of minutes to round time stamps to. | ||
| 1986 | These are two values, the first applies when first creating a time stamp. | ||
| 1987 | The second applies when changing it with the commands `S-up' and `S-down'. | ||
| 1988 | When changing the time stamp, this means that it will change in steps | ||
| 1989 | of N minutes, as given by the second value. | ||
| 1990 | |||
| 1991 | When a setting is 0 or 1, insert the time unmodified. Useful rounding | ||
| 1992 | numbers should be factors of 60, so for example 5, 10, 15. | ||
| 1993 | |||
| 1994 | When this is larger than 1, you can still force an exact time-stamp by using | ||
| 1995 | a double prefix argument to a time-stamp command like `C-c .' or `C-c !', | ||
| 1996 | and by using a prefix arg to `S-up/down' to specify the exact number | ||
| 1997 | of minutes to shift." | ||
| 1998 | :group 'org-time | ||
| 1999 | :get '(lambda (var) ; Make sure all entries have 5 elements | ||
| 2000 | (if (integerp (default-value var)) | ||
| 2001 | (list (default-value var) 5) | ||
| 2002 | (default-value var))) | ||
| 2003 | :type '(list | ||
| 2004 | (integer :tag "when inserting times") | ||
| 2005 | (integer :tag "when modifying times"))) | ||
| 2006 | |||
| 2007 | ;; Make sure old customizations of this variable don't lead to problems. | ||
| 2008 | (when (integerp org-time-stamp-rounding-minutes) | ||
| 2009 | (setq org-time-stamp-rounding-minutes | ||
| 2010 | (list org-time-stamp-rounding-minutes | ||
| 2011 | org-time-stamp-rounding-minutes))) | ||
| 2012 | |||
| 2013 | (defcustom org-display-custom-times nil | ||
| 2014 | "Non-nil means, overlay custom formats over all time stamps. | ||
| 2015 | The formats are defined through the variable `org-time-stamp-custom-formats'. | ||
| 2016 | To turn this on on a per-file basis, insert anywhere in the file: | ||
| 2017 | #+STARTUP: customtime" | ||
| 2018 | :group 'org-time | ||
| 2019 | :set 'set-default | ||
| 2020 | :type 'sexp) | ||
| 2021 | (make-variable-buffer-local 'org-display-custom-times) | ||
| 2022 | |||
| 2023 | (defcustom org-time-stamp-custom-formats | ||
| 2024 | '("<%m/%d/%y %a>" . "<%m/%d/%y %a %H:%M>") ; american | ||
| 2025 | "Custom formats for time stamps. See `format-time-string' for the syntax. | ||
| 2026 | These are overlayed over the default ISO format if the variable | ||
| 2027 | `org-display-custom-times' is set. Time like %H:%M should be at the | ||
| 2028 | end of the second format." | ||
| 2029 | :group 'org-time | ||
| 2030 | :type 'sexp) | ||
| 2031 | |||
| 2032 | (defun org-time-stamp-format (&optional long inactive) | ||
| 2033 | "Get the right format for a time string." | ||
| 2034 | (let ((f (if long (cdr org-time-stamp-formats) | ||
| 2035 | (car org-time-stamp-formats)))) | ||
| 2036 | (if inactive | ||
| 2037 | (concat "[" (substring f 1 -1) "]") | ||
| 2038 | f))) | ||
| 2039 | |||
| 2040 | (defcustom org-read-date-prefer-future t | ||
| 2041 | "Non-nil means, assume future for incomplete date input from user. | ||
| 2042 | This affects the following situations: | ||
| 2043 | 1. The user gives a day, but no month. | ||
| 2044 | For example, if today is the 15th, and you enter \"3\", Org-mode will | ||
| 2045 | read this as the third of *next* month. However, if you enter \"17\", | ||
| 2046 | it will be considered as *this* month. | ||
| 2047 | 2. The user gives a month but not a year. | ||
| 2048 | For example, if it is april and you enter \"feb 2\", this will be read | ||
| 2049 | as feb 2, *next* year. \"May 5\", however, will be this year. | ||
| 2050 | |||
| 2051 | When this option is nil, the current month and year will always be used | ||
| 2052 | as defaults." | ||
| 2053 | :group 'org-time | ||
| 2054 | :type 'boolean) | ||
| 2055 | |||
| 2056 | (defcustom org-read-date-display-live t | ||
| 2057 | "Non-nil means, display current interpretation of date prompt live. | ||
| 2058 | This display will be in an overlay, in the minibuffer." | ||
| 2059 | :group 'org-time | ||
| 2060 | :type 'boolean) | ||
| 2061 | |||
| 2062 | (defcustom org-read-date-popup-calendar t | ||
| 2063 | "Non-nil means, pop up a calendar when prompting for a date. | ||
| 2064 | In the calendar, the date can be selected with mouse-1. However, the | ||
| 2065 | minibuffer will also be active, and you can simply enter the date as well. | ||
| 2066 | When nil, only the minibuffer will be available." | ||
| 2067 | :group 'org-time | ||
| 2068 | :type 'boolean) | ||
| 2069 | (if (fboundp 'defvaralias) | ||
| 2070 | (defvaralias 'org-popup-calendar-for-date-prompt | ||
| 2071 | 'org-read-date-popup-calendar)) | ||
| 2072 | |||
| 2073 | (defcustom org-extend-today-until 0 | ||
| 2074 | "The hour when your day really ends. | ||
| 2075 | This has influence for the following applications: | ||
| 2076 | - When switching the agenda to \"today\". It it is still earlier than | ||
| 2077 | the time given here, the day recognized as TODAY is actually yesterday. | ||
| 2078 | - When a date is read from the user and it is still before the time given | ||
| 2079 | here, the current date and time will be assumed to be yesterday, 23:59. | ||
| 2080 | |||
| 2081 | FIXME: | ||
| 2082 | IMPORTANT: This is still a very experimental feature, it may disappear | ||
| 2083 | again or it may be extended to mean more things." | ||
| 2084 | :group 'org-time | ||
| 2085 | :type 'number) | ||
| 2086 | |||
| 2087 | (defcustom org-edit-timestamp-down-means-later nil | ||
| 2088 | "Non-nil means, S-down will increase the time in a time stamp. | ||
| 2089 | When nil, S-up will increase." | ||
| 2090 | :group 'org-time | ||
| 2091 | :type 'boolean) | ||
| 2092 | |||
| 2093 | (defcustom org-calendar-follow-timestamp-change t | ||
| 2094 | "Non-nil means, make the calendar window follow timestamp changes. | ||
| 2095 | When a timestamp is modified and the calendar window is visible, it will be | ||
| 2096 | moved to the new date." | ||
| 2097 | :group 'org-time | ||
| 2098 | :type 'boolean) | ||
| 2099 | |||
| 2100 | (defcustom org-clock-heading-function nil | ||
| 2101 | "When non-nil, should be a function to create `org-clock-heading'. | ||
| 2102 | This is the string shown in the mode line when a clock is running. | ||
| 2103 | The function is called with point at the beginning of the headline." | ||
| 2104 | :group 'org-time ; FIXME: Should we have a separate group???? | ||
| 2105 | :type 'function) | ||
| 2106 | |||
| 2107 | (defgroup org-tags nil | ||
| 2108 | "Options concerning tags in Org-mode." | ||
| 2109 | :tag "Org Tags" | ||
| 2110 | :group 'org) | ||
| 2111 | |||
| 2112 | (defcustom org-tag-alist nil | ||
| 2113 | "List of tags allowed in Org-mode files. | ||
| 2114 | When this list is nil, Org-mode will base TAG input on what is already in the | ||
| 2115 | buffer. | ||
| 2116 | The value of this variable is an alist, the car of each entry must be a | ||
| 2117 | keyword as a string, the cdr may be a character that is used to select | ||
| 2118 | that tag through the fast-tag-selection interface. | ||
| 2119 | See the manual for details." | ||
| 2120 | :group 'org-tags | ||
| 2121 | :type '(repeat | ||
| 2122 | (choice | ||
| 2123 | (cons (string :tag "Tag name") | ||
| 2124 | (character :tag "Access char")) | ||
| 2125 | (const :tag "Start radio group" (:startgroup)) | ||
| 2126 | (const :tag "End radio group" (:endgroup))))) | ||
| 2127 | |||
| 2128 | (defcustom org-use-fast-tag-selection 'auto | ||
| 2129 | "Non-nil means, use fast tag selection scheme. | ||
| 2130 | This is a special interface to select and deselect tags with single keys. | ||
| 2131 | When nil, fast selection is never used. | ||
| 2132 | When the symbol `auto', fast selection is used if and only if selection | ||
| 2133 | characters for tags have been configured, either through the variable | ||
| 2134 | `org-tag-alist' or through a #+TAGS line in the buffer. | ||
| 2135 | When t, fast selection is always used and selection keys are assigned | ||
| 2136 | automatically if necessary." | ||
| 2137 | :group 'org-tags | ||
| 2138 | :type '(choice | ||
| 2139 | (const :tag "Always" t) | ||
| 2140 | (const :tag "Never" nil) | ||
| 2141 | (const :tag "When selection characters are configured" 'auto))) | ||
| 2142 | |||
| 2143 | (defcustom org-fast-tag-selection-single-key nil | ||
| 2144 | "Non-nil means, fast tag selection exits after first change. | ||
| 2145 | When nil, you have to press RET to exit it. | ||
| 2146 | During fast tag selection, you can toggle this flag with `C-c'. | ||
| 2147 | This variable can also have the value `expert'. In this case, the window | ||
| 2148 | displaying the tags menu is not even shown, until you press C-c again." | ||
| 2149 | :group 'org-tags | ||
| 2150 | :type '(choice | ||
| 2151 | (const :tag "No" nil) | ||
| 2152 | (const :tag "Yes" t) | ||
| 2153 | (const :tag "Expert" expert))) | ||
| 2154 | |||
| 2155 | (defvar org-fast-tag-selection-include-todo nil | ||
| 2156 | "Non-nil means, fast tags selection interface will also offer TODO states. | ||
| 2157 | This is an undocumented feature, you should not rely on it.") | ||
| 2158 | |||
| 2159 | (defcustom org-tags-column -80 | ||
| 2160 | "The column to which tags should be indented in a headline. | ||
| 2161 | If this number is positive, it specifies the column. If it is negative, | ||
| 2162 | it means that the tags should be flushright to that column. For example, | ||
| 2163 | -80 works well for a normal 80 character screen." | ||
| 2164 | :group 'org-tags | ||
| 2165 | :type 'integer) | ||
| 2166 | |||
| 2167 | (defcustom org-auto-align-tags t | ||
| 2168 | "Non-nil means, realign tags after pro/demotion of TODO state change. | ||
| 2169 | These operations change the length of a headline and therefore shift | ||
| 2170 | the tags around. With this options turned on, after each such operation | ||
| 2171 | the tags are again aligned to `org-tags-column'." | ||
| 2172 | :group 'org-tags | ||
| 2173 | :type 'boolean) | ||
| 2174 | |||
| 2175 | (defcustom org-use-tag-inheritance t | ||
| 2176 | "Non-nil means, tags in levels apply also for sublevels. | ||
| 2177 | When nil, only the tags directly given in a specific line apply there. | ||
| 2178 | If you turn off this option, you very likely want to turn on the | ||
| 2179 | companion option `org-tags-match-list-sublevels'." | ||
| 2180 | :group 'org-tags | ||
| 2181 | :type 'boolean) | ||
| 2182 | |||
| 2183 | (defcustom org-tags-match-list-sublevels nil | ||
| 2184 | "Non-nil means list also sublevels of headlines matching tag search. | ||
| 2185 | Because of tag inheritance (see variable `org-use-tag-inheritance'), | ||
| 2186 | the sublevels of a headline matching a tag search often also match | ||
| 2187 | the same search. Listing all of them can create very long lists. | ||
| 2188 | Setting this variable to nil causes subtrees of a match to be skipped. | ||
| 2189 | This option is off by default, because inheritance in on. If you turn | ||
| 2190 | inheritance off, you very likely want to turn this option on. | ||
| 2191 | |||
| 2192 | As a special case, if the tag search is restricted to TODO items, the | ||
| 2193 | value of this variable is ignored and sublevels are always checked, to | ||
| 2194 | make sure all corresponding TODO items find their way into the list." | ||
| 2195 | :group 'org-tags | ||
| 2196 | :type 'boolean) | ||
| 2197 | |||
| 2198 | (defvar org-tags-history nil | ||
| 2199 | "History of minibuffer reads for tags.") | ||
| 2200 | (defvar org-last-tags-completion-table nil | ||
| 2201 | "The last used completion table for tags.") | ||
| 2202 | (defvar org-after-tags-change-hook nil | ||
| 2203 | "Hook that is run after the tags in a line have changed.") | ||
| 2204 | |||
| 2205 | (defgroup org-properties nil | ||
| 2206 | "Options concerning properties in Org-mode." | ||
| 2207 | :tag "Org Properties" | ||
| 2208 | :group 'org) | ||
| 2209 | |||
| 2210 | (defcustom org-property-format "%-10s %s" | ||
| 2211 | "How property key/value pairs should be formatted by `indent-line'. | ||
| 2212 | When `indent-line' hits a property definition, it will format the line | ||
| 2213 | according to this format, mainly to make sure that the values are | ||
| 2214 | lined-up with respect to each other." | ||
| 2215 | :group 'org-properties | ||
| 2216 | :type 'string) | ||
| 2217 | |||
| 2218 | (defcustom org-use-property-inheritance nil | ||
| 2219 | "Non-nil means, properties apply also for sublevels. | ||
| 2220 | This setting is only relevant during property searches, not when querying | ||
| 2221 | an entry with `org-entry-get'. To retrieve a property with inheritance, | ||
| 2222 | you need to call `org-entry-get' with the inheritance flag. | ||
| 2223 | Turning this on can cause significant overhead when doing a search, so | ||
| 2224 | this is turned off by default. | ||
| 2225 | When nil, only the properties directly given in the current entry count. | ||
| 2226 | The value may also be a list of properties that shouldhave inheritance. | ||
| 2227 | |||
| 2228 | However, note that some special properties use inheritance under special | ||
| 2229 | circumstances (not in searches). Examples are CATEGORY, ARCHIVE, COLUMNS, | ||
| 2230 | and the properties ending in \"_ALL\" when they are used as descriptor | ||
| 2231 | for valid values of a property." | ||
| 2232 | :group 'org-properties | ||
| 2233 | :type '(choice | ||
| 2234 | (const :tag "Not" nil) | ||
| 2235 | (const :tag "Always" nil) | ||
| 2236 | (repeat :tag "Specific properties" (string :tag "Property")))) | ||
| 2237 | |||
| 2238 | (defcustom org-columns-default-format "%25ITEM %TODO %3PRIORITY %TAGS" | ||
| 2239 | "The default column format, if no other format has been defined. | ||
| 2240 | This variable can be set on the per-file basis by inserting a line | ||
| 2241 | |||
| 2242 | #+COLUMNS: %25ITEM ....." | ||
| 2243 | :group 'org-properties | ||
| 2244 | :type 'string) | ||
| 2245 | |||
| 2246 | (defcustom org-global-properties nil | ||
| 2247 | "List of property/value pairs that can be inherited by any entry. | ||
| 2248 | You can set buffer-local values for this by adding lines like | ||
| 2249 | |||
| 2250 | #+PROPERTY: NAME VALUE" | ||
| 2251 | :group 'org-properties | ||
| 2252 | :type '(repeat | ||
| 2253 | (cons (string :tag "Property") | ||
| 2254 | (string :tag "Value")))) | ||
| 2255 | |||
| 2256 | (defvar org-local-properties nil | ||
| 2257 | "List of property/value pairs that can be inherited by any entry. | ||
| 2258 | Valid for the current buffer. | ||
| 2259 | This variable is populated from #+PROPERTY lines.") | ||
| 2260 | |||
| 2261 | (defgroup org-agenda nil | ||
| 2262 | "Options concerning agenda views in Org-mode." | ||
| 2263 | :tag "Org Agenda" | ||
| 2264 | :group 'org) | ||
| 2265 | |||
| 2266 | (defvar org-category nil | ||
| 2267 | "Variable used by org files to set a category for agenda display. | ||
| 2268 | Such files should use a file variable to set it, for example | ||
| 2269 | |||
| 2270 | # -*- mode: org; org-category: \"ELisp\" | ||
| 2271 | |||
| 2272 | or contain a special line | ||
| 2273 | |||
| 2274 | #+CATEGORY: ELisp | ||
| 2275 | |||
| 2276 | If the file does not specify a category, then file's base name | ||
| 2277 | is used instead.") | ||
| 2278 | (make-variable-buffer-local 'org-category) | ||
| 2279 | |||
| 2280 | (defcustom org-agenda-files nil | ||
| 2281 | "The files to be used for agenda display. | ||
| 2282 | Entries may be added to this list with \\[org-agenda-file-to-front] and removed with | ||
| 2283 | \\[org-remove-file]. You can also use customize to edit the list. | ||
| 2284 | |||
| 2285 | If an entry is a directory, all files in that directory that are matched by | ||
| 2286 | `org-agenda-file-regexp' will be part of the file list. | ||
| 2287 | |||
| 2288 | If the value of the variable is not a list but a single file name, then | ||
| 2289 | the list of agenda files is actually stored and maintained in that file, one | ||
| 2290 | agenda file per line." | ||
| 2291 | :group 'org-agenda | ||
| 2292 | :type '(choice | ||
| 2293 | (repeat :tag "List of files and directories" file) | ||
| 2294 | (file :tag "Store list in a file\n" :value "~/.agenda_files"))) | ||
| 2295 | |||
| 2296 | (defcustom org-agenda-file-regexp "\\`[^.].*\\.org\\'" | ||
| 2297 | "Regular expression to match files for `org-agenda-files'. | ||
| 2298 | If any element in the list in that variable contains a directory instead | ||
| 2299 | of a normal file, all files in that directory that are matched by this | ||
| 2300 | regular expression will be included." | ||
| 2301 | :group 'org-agenda | ||
| 2302 | :type 'regexp) | ||
| 2303 | |||
| 2304 | (defcustom org-agenda-skip-unavailable-files nil | ||
| 2305 | "t means to just skip non-reachable files in `org-agenda-files'. | ||
| 2306 | Nil means to remove them, after a query, from the list." | ||
| 2307 | :group 'org-agenda | ||
| 2308 | :type 'boolean) | ||
| 2309 | |||
| 2310 | (defcustom org-agenda-text-search-extra-files nil | ||
| 2311 | "List of extra files to be searched by text search commands. | ||
| 2312 | These files will be search in addition to the agenda files bu the | ||
| 2313 | commands `org-search-view' (`C-c a s') and `org-occur-in-agenda-files'. | ||
| 2314 | Note that these files will only be searched for text search commands, | ||
| 2315 | not for the other agenda views like todo lists, tag earches or the weekly | ||
| 2316 | agenda. This variable is intended to list notes and possibly archive files | ||
| 2317 | that should also be searched by these two commands." | ||
| 2318 | :group 'org-agenda | ||
| 2319 | :type '(repeat file)) | ||
| 2320 | |||
| 2321 | (if (fboundp 'defvaralias) | ||
| 2322 | (defvaralias 'org-agenda-multi-occur-extra-files | ||
| 2323 | 'org-agenda-text-search-extra-files)) | ||
| 2324 | |||
| 2325 | (defcustom org-agenda-confirm-kill 1 | ||
| 2326 | "When set, remote killing from the agenda buffer needs confirmation. | ||
| 2327 | When t, a confirmation is always needed. When a number N, confirmation is | ||
| 2328 | only needed when the text to be killed contains more than N non-white lines." | ||
| 2329 | :group 'org-agenda | ||
| 2330 | :type '(choice | ||
| 2331 | (const :tag "Never" nil) | ||
| 2332 | (const :tag "Always" t) | ||
| 2333 | (number :tag "When more than N lines"))) | ||
| 2334 | |||
| 2335 | (defcustom org-calendar-to-agenda-key [?c] | ||
| 2336 | "The key to be installed in `calendar-mode-map' for switching to the agenda. | ||
| 2337 | The command `org-calendar-goto-agenda' will be bound to this key. The | ||
| 2338 | default is the character `c' because then `c' can be used to switch back and | ||
| 2339 | forth between agenda and calendar." | ||
| 2340 | :group 'org-agenda | ||
| 2341 | :type 'sexp) | ||
| 2342 | |||
| 2343 | (defcustom org-agenda-compact-blocks nil | ||
| 2344 | "Non-nil means, make the block agenda more compact. | ||
| 2345 | This is done by leaving out unnecessary lines." | ||
| 2346 | :group 'org-agenda | ||
| 2347 | :type nil) | ||
| 2348 | |||
| 2349 | (defgroup org-agenda-export nil | ||
| 2350 | "Options concerning exporting agenda views in Org-mode." | ||
| 2351 | :tag "Org Agenda Export" | ||
| 2352 | :group 'org-agenda) | ||
| 2353 | |||
| 2354 | (defcustom org-agenda-with-colors t | ||
| 2355 | "Non-nil means, use colors in agenda views." | ||
| 2356 | :group 'org-agenda-export | ||
| 2357 | :type 'boolean) | ||
| 2358 | |||
| 2359 | (defcustom org-agenda-exporter-settings nil | ||
| 2360 | "Alist of variable/value pairs that should be active during agenda export. | ||
| 2361 | This is a good place to set uptions for ps-print and for htmlize." | ||
| 2362 | :group 'org-agenda-export | ||
| 2363 | :type '(repeat | ||
| 2364 | (list | ||
| 2365 | (variable) | ||
| 2366 | (sexp :tag "Value")))) | ||
| 2367 | |||
| 2368 | (defcustom org-agenda-export-html-style "" | ||
| 2369 | "The style specification for exported HTML Agenda files. | ||
| 2370 | If this variable contains a string, it will replace the default <style> | ||
| 2371 | section as produced by `htmlize'. | ||
| 2372 | Since there are different ways of setting style information, this variable | ||
| 2373 | needs to contain the full HTML structure to provide a style, including the | ||
| 2374 | surrounding HTML tags. The style specifications should include definitions | ||
| 2375 | the fonts used by the agenda, here is an example: | ||
| 2376 | |||
| 2377 | <style type=\"text/css\"> | ||
| 2378 | p { font-weight: normal; color: gray; } | ||
| 2379 | .org-agenda-structure { | ||
| 2380 | font-size: 110%; | ||
| 2381 | color: #003399; | ||
| 2382 | font-weight: 600; | ||
| 2383 | } | ||
| 2384 | .org-todo { | ||
| 2385 | color: #cc6666; | ||
| 2386 | font-weight: bold; | ||
| 2387 | } | ||
| 2388 | .org-done { | ||
| 2389 | color: #339933; | ||
| 2390 | } | ||
| 2391 | .title { text-align: center; } | ||
| 2392 | .todo, .deadline { color: red; } | ||
| 2393 | .done { color: green; } | ||
| 2394 | </style> | ||
| 2395 | |||
| 2396 | or, if you want to keep the style in a file, | ||
| 2397 | |||
| 2398 | <link rel=\"stylesheet\" type=\"text/css\" href=\"mystyles.css\"> | ||
| 2399 | |||
| 2400 | As the value of this option simply gets inserted into the HTML <head> header, | ||
| 2401 | you can \"misuse\" it to also add other text to the header. However, | ||
| 2402 | <style>...</style> is required, if not present the variable will be ignored." | ||
| 2403 | :group 'org-agenda-export | ||
| 2404 | :group 'org-export-html | ||
| 2405 | :type 'string) | ||
| 2406 | |||
| 2407 | (defgroup org-agenda-custom-commands nil | ||
| 2408 | "Options concerning agenda views in Org-mode." | ||
| 2409 | :tag "Org Agenda Custom Commands" | ||
| 2410 | :group 'org-agenda) | ||
| 2411 | |||
| 2412 | (defconst org-sorting-choice | ||
| 2413 | '(choice | ||
| 2414 | (const time-up) (const time-down) | ||
| 2415 | (const category-keep) (const category-up) (const category-down) | ||
| 2416 | (const tag-down) (const tag-up) | ||
| 2417 | (const priority-up) (const priority-down)) | ||
| 2418 | "Sorting choices.") | ||
| 2419 | |||
| 2420 | (defconst org-agenda-custom-commands-local-options | ||
| 2421 | `(repeat :tag "Local settings for this command. Remember to quote values" | ||
| 2422 | (choice :tag "Setting" | ||
| 2423 | (list :tag "Any variable" | ||
| 2424 | (variable :tag "Variable") | ||
| 2425 | (sexp :tag "Value")) | ||
| 2426 | (list :tag "Files to be searched" | ||
| 2427 | (const org-agenda-files) | ||
| 2428 | (list | ||
| 2429 | (const :format "" quote) | ||
| 2430 | (repeat | ||
| 2431 | (file)))) | ||
| 2432 | (list :tag "Sorting strategy" | ||
| 2433 | (const org-agenda-sorting-strategy) | ||
| 2434 | (list | ||
| 2435 | (const :format "" quote) | ||
| 2436 | (repeat | ||
| 2437 | ,org-sorting-choice))) | ||
| 2438 | (list :tag "Prefix format" | ||
| 2439 | (const org-agenda-prefix-format :value " %-12:c%?-12t% s") | ||
| 2440 | (string)) | ||
| 2441 | (list :tag "Number of days in agenda" | ||
| 2442 | (const org-agenda-ndays) | ||
| 2443 | (integer :value 1)) | ||
| 2444 | (list :tag "Fixed starting date" | ||
| 2445 | (const org-agenda-start-day) | ||
| 2446 | (string :value "2007-11-01")) | ||
| 2447 | (list :tag "Start on day of week" | ||
| 2448 | (const org-agenda-start-on-weekday) | ||
| 2449 | (choice :value 1 | ||
| 2450 | (const :tag "Today" nil) | ||
| 2451 | (number :tag "Weekday No."))) | ||
| 2452 | (list :tag "Include data from diary" | ||
| 2453 | (const org-agenda-include-diary) | ||
| 2454 | (boolean)) | ||
| 2455 | (list :tag "Deadline Warning days" | ||
| 2456 | (const org-deadline-warning-days) | ||
| 2457 | (integer :value 1)) | ||
| 2458 | (list :tag "Standard skipping condition" | ||
| 2459 | :value (org-agenda-skip-function '(org-agenda-skip-entry-if)) | ||
| 2460 | (const org-agenda-skip-function) | ||
| 2461 | (list | ||
| 2462 | (const :format "" quote) | ||
| 2463 | (list | ||
| 2464 | (choice | ||
| 2465 | :tag "Skiping range" | ||
| 2466 | (const :tag "Skip entry" org-agenda-skip-entry-if) | ||
| 2467 | (const :tag "Skip subtree" org-agenda-skip-subtree-if)) | ||
| 2468 | (repeat :inline t :tag "Conditions for skipping" | ||
| 2469 | (choice | ||
| 2470 | :tag "Condition type" | ||
| 2471 | (list :tag "Regexp matches" :inline t (const :format "" 'regexp) (regexp)) | ||
| 2472 | (list :tag "Regexp does not match" :inline t (const :format "" 'notregexp) (regexp)) | ||
| 2473 | (const :tag "scheduled" 'scheduled) | ||
| 2474 | (const :tag "not scheduled" 'notscheduled) | ||
| 2475 | (const :tag "deadline" 'deadline) | ||
| 2476 | (const :tag "no deadline" 'notdeadline)))))) | ||
| 2477 | (list :tag "Non-standard skipping condition" | ||
| 2478 | :value (org-agenda-skip-function) | ||
| 2479 | (list | ||
| 2480 | (const org-agenda-skip-function) | ||
| 2481 | (sexp :tag "Function or form (quoted!)"))))) | ||
| 2482 | "Selection of examples for agenda command settings. | ||
| 2483 | This will be spliced into the custom type of | ||
| 2484 | `org-agenda-custom-commands'.") | ||
| 2485 | |||
| 2486 | |||
| 2487 | (defcustom org-agenda-custom-commands nil | ||
| 2488 | "Custom commands for the agenda. | ||
| 2489 | These commands will be offered on the splash screen displayed by the | ||
| 2490 | agenda dispatcher \\[org-agenda]. Each entry is a list like this: | ||
| 2491 | |||
| 2492 | (key desc type match settings files) | ||
| 2493 | |||
| 2494 | key The key (one or more characters as a string) to be associated | ||
| 2495 | with the command. | ||
| 2496 | desc A description of the command, when omitted or nil, a default | ||
| 2497 | description is built using MATCH. | ||
| 2498 | type The command type, any of the following symbols: | ||
| 2499 | agenda The daily/weekly agenda. | ||
| 2500 | todo Entries with a specific TODO keyword, in all agenda files. | ||
| 2501 | search Entries containing search words entry or headline. | ||
| 2502 | tags Tags/Property/TODO match in all agenda files. | ||
| 2503 | tags-todo Tags/P/T match in all agenda files, TODO entries only. | ||
| 2504 | todo-tree Sparse tree of specific TODO keyword in *current* file. | ||
| 2505 | tags-tree Sparse tree with all tags matches in *current* file. | ||
| 2506 | occur-tree Occur sparse tree for *current* file. | ||
| 2507 | ... A user-defined function. | ||
| 2508 | match What to search for: | ||
| 2509 | - a single keyword for TODO keyword searches | ||
| 2510 | - a tags match expression for tags searches | ||
| 2511 | - a word search expression for text searches. | ||
| 2512 | - a regular expression for occur searches | ||
| 2513 | For all other commands, this should be the empty string. | ||
| 2514 | settings A list of option settings, similar to that in a let form, so like | ||
| 2515 | this: ((opt1 val1) (opt2 val2) ...). The values will be | ||
| 2516 | evaluated at the moment of execution, so quote them when needed. | ||
| 2517 | files A list of files file to write the produced agenda buffer to | ||
| 2518 | with the command `org-store-agenda-views'. | ||
| 2519 | If a file name ends in \".html\", an HTML version of the buffer | ||
| 2520 | is written out. If it ends in \".ps\", a postscript version is | ||
| 2521 | produced. Otherwide, only the plain text is written to the file. | ||
| 2522 | |||
| 2523 | You can also define a set of commands, to create a composite agenda buffer. | ||
| 2524 | In this case, an entry looks like this: | ||
| 2525 | |||
| 2526 | (key desc (cmd1 cmd2 ...) general-settings-for-whole-set files) | ||
| 2527 | |||
| 2528 | where | ||
| 2529 | |||
| 2530 | desc A description string to be displayed in the dispatcher menu. | ||
| 2531 | cmd An agenda command, similar to the above. However, tree commands | ||
| 2532 | are no allowed, but instead you can get agenda and global todo list. | ||
| 2533 | So valid commands for a set are: | ||
| 2534 | (agenda \"\" settings) | ||
| 2535 | (alltodo \"\" settings) | ||
| 2536 | (stuck \"\" settings) | ||
| 2537 | (todo \"match\" settings files) | ||
| 2538 | (search \"match\" settings files) | ||
| 2539 | (tags \"match\" settings files) | ||
| 2540 | (tags-todo \"match\" settings files) | ||
| 2541 | |||
| 2542 | Each command can carry a list of options, and another set of options can be | ||
| 2543 | given for the whole set of commands. Individual command options take | ||
| 2544 | precedence over the general options. | ||
| 2545 | |||
| 2546 | When using several characters as key to a command, the first characters | ||
| 2547 | are prefix commands. For the dispatcher to display useful information, you | ||
| 2548 | should provide a description for the prefix, like | ||
| 2549 | |||
| 2550 | (setq org-agenda-custom-commands | ||
| 2551 | '((\"h\" . \"HOME + Name tag searches\") ; describe prefix \"h\" | ||
| 2552 | (\"hl\" tags \"+HOME+Lisa\") | ||
| 2553 | (\"hp\" tags \"+HOME+Peter\") | ||
| 2554 | (\"hk\" tags \"+HOME+Kim\")))" | ||
| 2555 | :group 'org-agenda-custom-commands | ||
| 2556 | :type `(repeat | ||
| 2557 | (choice :value ("x" "Describe command here" tags "" nil) | ||
| 2558 | (list :tag "Single command" | ||
| 2559 | (string :tag "Access Key(s) ") | ||
| 2560 | (option (string :tag "Description")) | ||
| 2561 | (choice | ||
| 2562 | (const :tag "Agenda" agenda) | ||
| 2563 | (const :tag "TODO list" alltodo) | ||
| 2564 | (const :tag "Search words" search) | ||
| 2565 | (const :tag "Stuck projects" stuck) | ||
| 2566 | (const :tag "Tags search (all agenda files)" tags) | ||
| 2567 | (const :tag "Tags search of TODO entries (all agenda files)" tags-todo) | ||
| 2568 | (const :tag "TODO keyword search (all agenda files)" todo) | ||
| 2569 | (const :tag "Tags sparse tree (current buffer)" tags-tree) | ||
| 2570 | (const :tag "TODO keyword tree (current buffer)" todo-tree) | ||
| 2571 | (const :tag "Occur tree (current buffer)" occur-tree) | ||
| 2572 | (sexp :tag "Other, user-defined function")) | ||
| 2573 | (string :tag "Match (only for some commands)") | ||
| 2574 | ,org-agenda-custom-commands-local-options | ||
| 2575 | (option (repeat :tag "Export" (file :tag "Export to")))) | ||
| 2576 | (list :tag "Command series, all agenda files" | ||
| 2577 | (string :tag "Access Key(s)") | ||
| 2578 | (string :tag "Description ") | ||
| 2579 | (repeat :tag "Component" | ||
| 2580 | (choice | ||
| 2581 | (list :tag "Agenda" | ||
| 2582 | (const :format "" agenda) | ||
| 2583 | (const :tag "" :format "" "") | ||
| 2584 | ,org-agenda-custom-commands-local-options) | ||
| 2585 | (list :tag "TODO list (all keywords)" | ||
| 2586 | (const :format "" alltodo) | ||
| 2587 | (const :tag "" :format "" "") | ||
| 2588 | ,org-agenda-custom-commands-local-options) | ||
| 2589 | (list :tag "Search words" | ||
| 2590 | (const :format "" search) | ||
| 2591 | (string :tag "Match") | ||
| 2592 | ,org-agenda-custom-commands-local-options) | ||
| 2593 | (list :tag "Stuck projects" | ||
| 2594 | (const :format "" stuck) | ||
| 2595 | (const :tag "" :format "" "") | ||
| 2596 | ,org-agenda-custom-commands-local-options) | ||
| 2597 | (list :tag "Tags search" | ||
| 2598 | (const :format "" tags) | ||
| 2599 | (string :tag "Match") | ||
| 2600 | ,org-agenda-custom-commands-local-options) | ||
| 2601 | (list :tag "Tags search, TODO entries only" | ||
| 2602 | (const :format "" tags-todo) | ||
| 2603 | (string :tag "Match") | ||
| 2604 | ,org-agenda-custom-commands-local-options) | ||
| 2605 | (list :tag "TODO keyword search" | ||
| 2606 | (const :format "" todo) | ||
| 2607 | (string :tag "Match") | ||
| 2608 | ,org-agenda-custom-commands-local-options) | ||
| 2609 | (list :tag "Other, user-defined function" | ||
| 2610 | (symbol :tag "function") | ||
| 2611 | (string :tag "Match") | ||
| 2612 | ,org-agenda-custom-commands-local-options))) | ||
| 2613 | |||
| 2614 | (repeat :tag "Settings for entire command set" | ||
| 2615 | (list (variable :tag "Any variable") | ||
| 2616 | (sexp :tag "Value"))) | ||
| 2617 | (option (repeat :tag "Export" (file :tag "Export to")))) | ||
| 2618 | (cons :tag "Prefix key documentation" | ||
| 2619 | (string :tag "Access Key(s)") | ||
| 2620 | (string :tag "Description "))))) | ||
| 2621 | |||
| 2622 | (defcustom org-agenda-query-register ?o | ||
| 2623 | "The register holding the current query string. | ||
| 2624 | The prupose of this is that if you construct a query string interactively, | ||
| 2625 | you can then use it to define a custom command." | ||
| 2626 | :group 'org-agenda-custom-commands | ||
| 2627 | :type 'character) | ||
| 2628 | |||
| 2629 | (defcustom org-stuck-projects | ||
| 2630 | '("+LEVEL=2/-DONE" ("TODO" "NEXT" "NEXTACTION") nil "") | ||
| 2631 | "How to identify stuck projects. | ||
| 2632 | This is a list of four items: | ||
| 2633 | 1. A tags/todo matcher string that is used to identify a project. | ||
| 2634 | The entire tree below a headline matched by this is considered one project. | ||
| 2635 | 2. A list of TODO keywords identifying non-stuck projects. | ||
| 2636 | If the project subtree contains any headline with one of these todo | ||
| 2637 | keywords, the project is considered to be not stuck. If you specify | ||
| 2638 | \"*\" as a keyword, any TODO keyword will mark the project unstuck. | ||
| 2639 | 3. A list of tags identifying non-stuck projects. | ||
| 2640 | If the project subtree contains any headline with one of these tags, | ||
| 2641 | the project is considered to be not stuck. If you specify \"*\" as | ||
| 2642 | a tag, any tag will mark the project unstuck. | ||
| 2643 | 4. An arbitrary regular expression matching non-stuck projects. | ||
| 2644 | |||
| 2645 | After defining this variable, you may use \\[org-agenda-list-stuck-projects] | ||
| 2646 | or `C-c a #' to produce the list." | ||
| 2647 | :group 'org-agenda-custom-commands | ||
| 2648 | :type '(list | ||
| 2649 | (string :tag "Tags/TODO match to identify a project") | ||
| 2650 | (repeat :tag "Projects are *not* stuck if they have an entry with TODO keyword any of" (string)) | ||
| 2651 | (repeat :tag "Projects are *not* stuck if they have an entry with TAG being any of" (string)) | ||
| 2652 | (regexp :tag "Projects are *not* stuck if this regexp matches\ninside the subtree"))) | ||
| 2653 | |||
| 2654 | |||
| 2655 | (defgroup org-agenda-skip nil | ||
| 2656 | "Options concerning skipping parts of agenda files." | ||
| 2657 | :tag "Org Agenda Skip" | ||
| 2658 | :group 'org-agenda) | ||
| 2659 | |||
| 2660 | (defcustom org-agenda-todo-list-sublevels t | ||
| 2661 | "Non-nil means, check also the sublevels of a TODO entry for TODO entries. | ||
| 2662 | When nil, the sublevels of a TODO entry are not checked, resulting in | ||
| 2663 | potentially much shorter TODO lists." | ||
| 2664 | :group 'org-agenda-skip | ||
| 2665 | :group 'org-todo | ||
| 2666 | :type 'boolean) | ||
| 2667 | |||
| 2668 | (defcustom org-agenda-todo-ignore-with-date nil | ||
| 2669 | "Non-nil means, don't show entries with a date in the global todo list. | ||
| 2670 | You can use this if you prefer to mark mere appointments with a TODO keyword, | ||
| 2671 | but don't want them to show up in the TODO list. | ||
| 2672 | When this is set, it also covers deadlines and scheduled items, the settings | ||
| 2673 | of `org-agenda-todo-ignore-scheduled' and `org-agenda-todo-ignore-deadlines' | ||
| 2674 | will be ignored." | ||
| 2675 | :group 'org-agenda-skip | ||
| 2676 | :group 'org-todo | ||
| 2677 | :type 'boolean) | ||
| 2678 | |||
| 2679 | (defcustom org-agenda-todo-ignore-scheduled nil | ||
| 2680 | "Non-nil means, don't show scheduled entries in the global todo list. | ||
| 2681 | The idea behind this is that by scheduling it, you have already taken care | ||
| 2682 | of this item. | ||
| 2683 | See also `org-agenda-todo-ignore-with-date'." | ||
| 2684 | :group 'org-agenda-skip | ||
| 2685 | :group 'org-todo | ||
| 2686 | :type 'boolean) | ||
| 2687 | |||
| 2688 | (defcustom org-agenda-todo-ignore-deadlines nil | ||
| 2689 | "Non-nil means, don't show near deadline entries in the global todo list. | ||
| 2690 | Near means closer than `org-deadline-warning-days' days. | ||
| 2691 | The idea behind this is that such items will appear in the agenda anyway. | ||
| 2692 | See also `org-agenda-todo-ignore-with-date'." | ||
| 2693 | :group 'org-agenda-skip | ||
| 2694 | :group 'org-todo | ||
| 2695 | :type 'boolean) | ||
| 2696 | |||
| 2697 | (defcustom org-agenda-skip-scheduled-if-done nil | ||
| 2698 | "Non-nil means don't show scheduled items in agenda when they are done. | ||
| 2699 | This is relevant for the daily/weekly agenda, not for the TODO list. And | ||
| 2700 | it applies only to the actual date of the scheduling. Warnings about | ||
| 2701 | an item with a past scheduling dates are always turned off when the item | ||
| 2702 | is DONE." | ||
| 2703 | :group 'org-agenda-skip | ||
| 2704 | :type 'boolean) | ||
| 2705 | |||
| 2706 | (defcustom org-agenda-skip-deadline-if-done nil | ||
| 2707 | "Non-nil means don't show deadines when the corresponding item is done. | ||
| 2708 | When nil, the deadline is still shown and should give you a happy feeling. | ||
| 2709 | This is relevant for the daily/weekly agenda. And it applied only to the | ||
| 2710 | actualy date of the deadline. Warnings about approching and past-due | ||
| 2711 | deadlines are always turned off when the item is DONE." | ||
| 2712 | :group 'org-agenda-skip | ||
| 2713 | :type 'boolean) | ||
| 2714 | |||
| 2715 | (defcustom org-agenda-skip-timestamp-if-done nil | ||
| 2716 | "Non-nil means don't select item by timestamp or -range if it is DONE." | ||
| 2717 | :group 'org-agenda-skip | ||
| 2718 | :type 'boolean) | ||
| 2719 | |||
| 2720 | (defcustom org-timeline-show-empty-dates 3 | ||
| 2721 | "Non-nil means, `org-timeline' also shows dates without an entry. | ||
| 2722 | When nil, only the days which actually have entries are shown. | ||
| 2723 | When t, all days between the first and the last date are shown. | ||
| 2724 | When an integer, show also empty dates, but if there is a gap of more than | ||
| 2725 | N days, just insert a special line indicating the size of the gap." | ||
| 2726 | :group 'org-agenda-skip | ||
| 2727 | :type '(choice | ||
| 2728 | (const :tag "None" nil) | ||
| 2729 | (const :tag "All" t) | ||
| 2730 | (number :tag "at most"))) | ||
| 2731 | |||
| 2732 | |||
| 2733 | (defgroup org-agenda-startup nil | ||
| 2734 | "Options concerning initial settings in the Agenda in Org Mode." | ||
| 2735 | :tag "Org Agenda Startup" | ||
| 2736 | :group 'org-agenda) | ||
| 2737 | |||
| 2738 | (defcustom org-finalize-agenda-hook nil | ||
| 2739 | "Hook run just before displaying an agenda buffer." | ||
| 2740 | :group 'org-agenda-startup | ||
| 2741 | :type 'hook) | ||
| 2742 | |||
| 2743 | (defcustom org-agenda-mouse-1-follows-link nil | ||
| 2744 | "Non-nil means, mouse-1 on a link will follow the link in the agenda. | ||
| 2745 | A longer mouse click will still set point. Does not work on XEmacs. | ||
| 2746 | Needs to be set before org.el is loaded." | ||
| 2747 | :group 'org-agenda-startup | ||
| 2748 | :type 'boolean) | ||
| 2749 | |||
| 2750 | (defcustom org-agenda-start-with-follow-mode nil | ||
| 2751 | "The initial value of follow-mode in a newly created agenda window." | ||
| 2752 | :group 'org-agenda-startup | ||
| 2753 | :type 'boolean) | ||
| 2754 | |||
| 2755 | (defgroup org-agenda-windows nil | ||
| 2756 | "Options concerning the windows used by the Agenda in Org Mode." | ||
| 2757 | :tag "Org Agenda Windows" | ||
| 2758 | :group 'org-agenda) | ||
| 2759 | |||
| 2760 | (defcustom org-agenda-window-setup 'reorganize-frame | ||
| 2761 | "How the agenda buffer should be displayed. | ||
| 2762 | Possible values for this option are: | ||
| 2763 | |||
| 2764 | current-window Show agenda in the current window, keeping all other windows. | ||
| 2765 | other-frame Use `switch-to-buffer-other-frame' to display agenda. | ||
| 2766 | other-window Use `switch-to-buffer-other-window' to display agenda. | ||
| 2767 | reorganize-frame Show only two windows on the current frame, the current | ||
| 2768 | window and the agenda. | ||
| 2769 | See also the variable `org-agenda-restore-windows-after-quit'." | ||
| 2770 | :group 'org-agenda-windows | ||
| 2771 | :type '(choice | ||
| 2772 | (const current-window) | ||
| 2773 | (const other-frame) | ||
| 2774 | (const other-window) | ||
| 2775 | (const reorganize-frame))) | ||
| 2776 | |||
| 2777 | (defcustom org-agenda-window-frame-fractions '(0.5 . 0.75) | ||
| 2778 | "The min and max height of the agenda window as a fraction of frame height. | ||
| 2779 | The value of the variable is a cons cell with two numbers between 0 and 1. | ||
| 2780 | It only matters if `org-agenda-window-setup' is `reorganize-frame'." | ||
| 2781 | :group 'org-agenda-windows | ||
| 2782 | :type '(cons (number :tag "Minimum") (number :tag "Maximum"))) | ||
| 2783 | |||
| 2784 | (defcustom org-agenda-restore-windows-after-quit nil | ||
| 2785 | "Non-nil means, restore window configuration open exiting agenda. | ||
| 2786 | Before the window configuration is changed for displaying the agenda, | ||
| 2787 | the current status is recorded. When the agenda is exited with | ||
| 2788 | `q' or `x' and this option is set, the old state is restored. If | ||
| 2789 | `org-agenda-window-setup' is `other-frame', the value of this | ||
| 2790 | option will be ignored.." | ||
| 2791 | :group 'org-agenda-windows | ||
| 2792 | :type 'boolean) | ||
| 2793 | |||
| 2794 | (defcustom org-indirect-buffer-display 'other-window | ||
| 2795 | "How should indirect tree buffers be displayed? | ||
| 2796 | This applies to indirect buffers created with the commands | ||
| 2797 | \\[org-tree-to-indirect-buffer] and \\[org-agenda-tree-to-indirect-buffer]. | ||
| 2798 | Valid values are: | ||
| 2799 | current-window Display in the current window | ||
| 2800 | other-window Just display in another window. | ||
| 2801 | dedicated-frame Create one new frame, and re-use it each time. | ||
| 2802 | new-frame Make a new frame each time. Note that in this case | ||
| 2803 | previously-made indirect buffers are kept, and you need to | ||
| 2804 | kill these buffers yourself." | ||
| 2805 | :group 'org-structure | ||
| 2806 | :group 'org-agenda-windows | ||
| 2807 | :type '(choice | ||
| 2808 | (const :tag "In current window" current-window) | ||
| 2809 | (const :tag "In current frame, other window" other-window) | ||
| 2810 | (const :tag "Each time a new frame" new-frame) | ||
| 2811 | (const :tag "One dedicated frame" dedicated-frame))) | ||
| 2812 | |||
| 2813 | (defgroup org-agenda-daily/weekly nil | ||
| 2814 | "Options concerning the daily/weekly agenda." | ||
| 2815 | :tag "Org Agenda Daily/Weekly" | ||
| 2816 | :group 'org-agenda) | ||
| 2817 | |||
| 2818 | (defcustom org-agenda-ndays 7 | ||
| 2819 | "Number of days to include in overview display. | ||
| 2820 | Should be 1 or 7." | ||
| 2821 | :group 'org-agenda-daily/weekly | ||
| 2822 | :type 'number) | ||
| 2823 | |||
| 2824 | (defcustom org-agenda-start-on-weekday 1 | ||
| 2825 | "Non-nil means, start the overview always on the specified weekday. | ||
| 2826 | 0 denotes Sunday, 1 denotes Monday etc. | ||
| 2827 | When nil, always start on the current day." | ||
| 2828 | :group 'org-agenda-daily/weekly | ||
| 2829 | :type '(choice (const :tag "Today" nil) | ||
| 2830 | (number :tag "Weekday No."))) | ||
| 2831 | |||
| 2832 | (defcustom org-agenda-show-all-dates t | ||
| 2833 | "Non-nil means, `org-agenda' shows every day in the selected range. | ||
| 2834 | When nil, only the days which actually have entries are shown." | ||
| 2835 | :group 'org-agenda-daily/weekly | ||
| 2836 | :type 'boolean) | ||
| 2837 | |||
| 2838 | (defcustom org-agenda-format-date 'org-agenda-format-date-aligned | ||
| 2839 | "Format string for displaying dates in the agenda. | ||
| 2840 | Used by the daily/weekly agenda and by the timeline. This should be | ||
| 2841 | a format string understood by `format-time-string', or a function returning | ||
| 2842 | the formatted date as a string. The function must take a single argument, | ||
| 2843 | a calendar-style date list like (month day year)." | ||
| 2844 | :group 'org-agenda-daily/weekly | ||
| 2845 | :type '(choice | ||
| 2846 | (string :tag "Format string") | ||
| 2847 | (function :tag "Function"))) | ||
| 2848 | |||
| 2849 | (defun org-agenda-format-date-aligned (date) | ||
| 2850 | "Format a date string for display in the daily/weekly agenda, or timeline. | ||
| 2851 | This function makes sure that dates are aligned for easy reading." | ||
| 2852 | (format "%-9s %2d %s %4d" | ||
| 2853 | (calendar-day-name date) | ||
| 2854 | (extract-calendar-day date) | ||
| 2855 | (calendar-month-name (extract-calendar-month date)) | ||
| 2856 | (extract-calendar-year date))) | ||
| 2857 | |||
| 2858 | (defcustom org-agenda-include-diary nil | ||
| 2859 | "If non-nil, include in the agenda entries from the Emacs Calendar's diary." | ||
| 2860 | :group 'org-agenda-daily/weekly | ||
| 2861 | :type 'boolean) | ||
| 2862 | |||
| 2863 | (defcustom org-agenda-include-all-todo nil | ||
| 2864 | "Set means weekly/daily agenda will always contain all TODO entries. | ||
| 2865 | The TODO entries will be listed at the top of the agenda, before | ||
| 2866 | the entries for specific days." | ||
| 2867 | :group 'org-agenda-daily/weekly | ||
| 2868 | :type 'boolean) | ||
| 2869 | |||
| 2870 | (defcustom org-agenda-repeating-timestamp-show-all t | ||
| 2871 | "Non-nil means, show all occurences of a repeating stamp in the agenda. | ||
| 2872 | When nil, only one occurence is shown, either today or the | ||
| 2873 | nearest into the future." | ||
| 2874 | :group 'org-agenda-daily/weekly | ||
| 2875 | :type 'boolean) | ||
| 2876 | |||
| 2877 | (defcustom org-deadline-warning-days 14 | ||
| 2878 | "No. of days before expiration during which a deadline becomes active. | ||
| 2879 | This variable governs the display in sparse trees and in the agenda. | ||
| 2880 | When 0 or negative, it means use this number (the absolute value of it) | ||
| 2881 | even if a deadline has a different individual lead time specified." | ||
| 2882 | :group 'org-time | ||
| 2883 | :group 'org-agenda-daily/weekly | ||
| 2884 | :type 'number) | ||
| 2885 | |||
| 2886 | (defcustom org-scheduled-past-days 10000 | ||
| 2887 | "No. of days to continue listing scheduled items that are not marked DONE. | ||
| 2888 | When an item is scheduled on a date, it shows up in the agenda on this | ||
| 2889 | day and will be listed until it is marked done for the number of days | ||
| 2890 | given here." | ||
| 2891 | :group 'org-agenda-daily/weekly | ||
| 2892 | :type 'number) | ||
| 2893 | |||
| 2894 | (defgroup org-agenda-time-grid nil | ||
| 2895 | "Options concerning the time grid in the Org-mode Agenda." | ||
| 2896 | :tag "Org Agenda Time Grid" | ||
| 2897 | :group 'org-agenda) | ||
| 2898 | |||
| 2899 | (defcustom org-agenda-use-time-grid t | ||
| 2900 | "Non-nil means, show a time grid in the agenda schedule. | ||
| 2901 | A time grid is a set of lines for specific times (like every two hours between | ||
| 2902 | 8:00 and 20:00). The items scheduled for a day at specific times are | ||
| 2903 | sorted in between these lines. | ||
| 2904 | For details about when the grid will be shown, and what it will look like, see | ||
| 2905 | the variable `org-agenda-time-grid'." | ||
| 2906 | :group 'org-agenda-time-grid | ||
| 2907 | :type 'boolean) | ||
| 2908 | |||
| 2909 | (defcustom org-agenda-time-grid | ||
| 2910 | '((daily today require-timed) | ||
| 2911 | "----------------" | ||
| 2912 | (800 1000 1200 1400 1600 1800 2000)) | ||
| 2913 | |||
| 2914 | "The settings for time grid for agenda display. | ||
| 2915 | This is a list of three items. The first item is again a list. It contains | ||
| 2916 | symbols specifying conditions when the grid should be displayed: | ||
| 2917 | |||
| 2918 | daily if the agenda shows a single day | ||
| 2919 | weekly if the agenda shows an entire week | ||
| 2920 | today show grid on current date, independent of daily/weekly display | ||
| 2921 | require-timed show grid only if at least one item has a time specification | ||
| 2922 | |||
| 2923 | The second item is a string which will be places behing the grid time. | ||
| 2924 | |||
| 2925 | The third item is a list of integers, indicating the times that should have | ||
| 2926 | a grid line." | ||
| 2927 | :group 'org-agenda-time-grid | ||
| 2928 | :type | ||
| 2929 | '(list | ||
| 2930 | (set :greedy t :tag "Grid Display Options" | ||
| 2931 | (const :tag "Show grid in single day agenda display" daily) | ||
| 2932 | (const :tag "Show grid in weekly agenda display" weekly) | ||
| 2933 | (const :tag "Always show grid for today" today) | ||
| 2934 | (const :tag "Show grid only if any timed entries are present" | ||
| 2935 | require-timed) | ||
| 2936 | (const :tag "Skip grid times already present in an entry" | ||
| 2937 | remove-match)) | ||
| 2938 | (string :tag "Grid String") | ||
| 2939 | (repeat :tag "Grid Times" (integer :tag "Time")))) | ||
| 2940 | |||
| 2941 | (defgroup org-agenda-sorting nil | ||
| 2942 | "Options concerning sorting in the Org-mode Agenda." | ||
| 2943 | :tag "Org Agenda Sorting" | ||
| 2944 | :group 'org-agenda) | ||
| 2945 | |||
| 2946 | (defcustom org-agenda-sorting-strategy | ||
| 2947 | '((agenda time-up category-keep priority-down) | ||
| 2948 | (todo category-keep priority-down) | ||
| 2949 | (tags category-keep priority-down) | ||
| 2950 | (search category-keep)) | ||
| 2951 | "Sorting structure for the agenda items of a single day. | ||
| 2952 | This is a list of symbols which will be used in sequence to determine | ||
| 2953 | if an entry should be listed before another entry. The following | ||
| 2954 | symbols are recognized: | ||
| 2955 | |||
| 2956 | time-up Put entries with time-of-day indications first, early first | ||
| 2957 | time-down Put entries with time-of-day indications first, late first | ||
| 2958 | category-keep Keep the default order of categories, corresponding to the | ||
| 2959 | sequence in `org-agenda-files'. | ||
| 2960 | category-up Sort alphabetically by category, A-Z. | ||
| 2961 | category-down Sort alphabetically by category, Z-A. | ||
| 2962 | tag-up Sort alphabetically by last tag, A-Z. | ||
| 2963 | tag-down Sort alphabetically by last tag, Z-A. | ||
| 2964 | priority-up Sort numerically by priority, high priority last. | ||
| 2965 | priority-down Sort numerically by priority, high priority first. | ||
| 2966 | |||
| 2967 | The different possibilities will be tried in sequence, and testing stops | ||
| 2968 | if one comparison returns a \"not-equal\". For example, the default | ||
| 2969 | '(time-up category-keep priority-down) | ||
| 2970 | means: Pull out all entries having a specified time of day and sort them, | ||
| 2971 | in order to make a time schedule for the current day the first thing in the | ||
| 2972 | agenda listing for the day. Of the entries without a time indication, keep | ||
| 2973 | the grouped in categories, don't sort the categories, but keep them in | ||
| 2974 | the sequence given in `org-agenda-files'. Within each category sort by | ||
| 2975 | priority. | ||
| 2976 | |||
| 2977 | Leaving out `category-keep' would mean that items will be sorted across | ||
| 2978 | categories by priority. | ||
| 2979 | |||
| 2980 | Instead of a single list, this can also be a set of list for specific | ||
| 2981 | contents, with a context symbol in the car of the list, any of | ||
| 2982 | `agenda', `todo', `tags' for the corresponding agenda views." | ||
| 2983 | :group 'org-agenda-sorting | ||
| 2984 | :type `(choice | ||
| 2985 | (repeat :tag "General" ,org-sorting-choice) | ||
| 2986 | (list :tag "Individually" | ||
| 2987 | (cons (const :tag "Strategy for Weekly/Daily agenda" agenda) | ||
| 2988 | (repeat ,org-sorting-choice)) | ||
| 2989 | (cons (const :tag "Strategy for TODO lists" todo) | ||
| 2990 | (repeat ,org-sorting-choice)) | ||
| 2991 | (cons (const :tag "Strategy for Tags matches" tags) | ||
| 2992 | (repeat ,org-sorting-choice))))) | ||
| 2993 | |||
| 2994 | (defcustom org-sort-agenda-notime-is-late t | ||
| 2995 | "Non-nil means, items without time are considered late. | ||
| 2996 | This is only relevant for sorting. When t, items which have no explicit | ||
| 2997 | time like 15:30 will be considered as 99:01, i.e. later than any items which | ||
| 2998 | do have a time. When nil, the default time is before 0:00. You can use this | ||
| 2999 | option to decide if the schedule for today should come before or after timeless | ||
| 3000 | agenda entries." | ||
| 3001 | :group 'org-agenda-sorting | ||
| 3002 | :type 'boolean) | ||
| 3003 | |||
| 3004 | (defgroup org-agenda-line-format nil | ||
| 3005 | "Options concerning the entry prefix in the Org-mode agenda display." | ||
| 3006 | :tag "Org Agenda Line Format" | ||
| 3007 | :group 'org-agenda) | ||
| 3008 | |||
| 3009 | (defcustom org-agenda-prefix-format | ||
| 3010 | '((agenda . " %-12:c%?-12t% s") | ||
| 3011 | (timeline . " % s") | ||
| 3012 | (todo . " %-12:c") | ||
| 3013 | (tags . " %-12:c") | ||
| 3014 | (search . " %-12:c")) | ||
| 3015 | "Format specifications for the prefix of items in the agenda views. | ||
| 3016 | An alist with four entries, for the different agenda types. The keys to the | ||
| 3017 | sublists are `agenda', `timeline', `todo', and `tags'. The values | ||
| 3018 | are format strings. | ||
| 3019 | This format works similar to a printf format, with the following meaning: | ||
| 3020 | |||
| 3021 | %c the category of the item, \"Diary\" for entries from the diary, or | ||
| 3022 | as given by the CATEGORY keyword or derived from the file name. | ||
| 3023 | %T the *last* tag of the item. Last because inherited tags come | ||
| 3024 | first in the list. | ||
| 3025 | %t the time-of-day specification if one applies to the entry, in the | ||
| 3026 | format HH:MM | ||
| 3027 | %s Scheduling/Deadline information, a short string | ||
| 3028 | |||
| 3029 | All specifiers work basically like the standard `%s' of printf, but may | ||
| 3030 | contain two additional characters: A question mark just after the `%' and | ||
| 3031 | a whitespace/punctuation character just before the final letter. | ||
| 3032 | |||
| 3033 | If the first character after `%' is a question mark, the entire field | ||
| 3034 | will only be included if the corresponding value applies to the | ||
| 3035 | current entry. This is useful for fields which should have fixed | ||
| 3036 | width when present, but zero width when absent. For example, | ||
| 3037 | \"%?-12t\" will result in a 12 character time field if a time of the | ||
| 3038 | day is specified, but will completely disappear in entries which do | ||
| 3039 | not contain a time. | ||
| 3040 | |||
| 3041 | If there is punctuation or whitespace character just before the final | ||
| 3042 | format letter, this character will be appended to the field value if | ||
| 3043 | the value is not empty. For example, the format \"%-12:c\" leads to | ||
| 3044 | \"Diary: \" if the category is \"Diary\". If the category were be | ||
| 3045 | empty, no additional colon would be interted. | ||
| 3046 | |||
| 3047 | The default value of this option is \" %-12:c%?-12t% s\", meaning: | ||
| 3048 | - Indent the line with two space characters | ||
| 3049 | - Give the category in a 12 chars wide field, padded with whitespace on | ||
| 3050 | the right (because of `-'). Append a colon if there is a category | ||
| 3051 | (because of `:'). | ||
| 3052 | - If there is a time-of-day, put it into a 12 chars wide field. If no | ||
| 3053 | time, don't put in an empty field, just skip it (because of '?'). | ||
| 3054 | - Finally, put the scheduling information and append a whitespace. | ||
| 3055 | |||
| 3056 | As another example, if you don't want the time-of-day of entries in | ||
| 3057 | the prefix, you could use: | ||
| 3058 | |||
| 3059 | (setq org-agenda-prefix-format \" %-11:c% s\") | ||
| 3060 | |||
| 3061 | See also the variables `org-agenda-remove-times-when-in-prefix' and | ||
| 3062 | `org-agenda-remove-tags'." | ||
| 3063 | :type '(choice | ||
| 3064 | (string :tag "General format") | ||
| 3065 | (list :greedy t :tag "View dependent" | ||
| 3066 | (cons (const agenda) (string :tag "Format")) | ||
| 3067 | (cons (const timeline) (string :tag "Format")) | ||
| 3068 | (cons (const todo) (string :tag "Format")) | ||
| 3069 | (cons (const tags) (string :tag "Format")) | ||
| 3070 | (cons (const search) (string :tag "Format")))) | ||
| 3071 | :group 'org-agenda-line-format) | ||
| 3072 | |||
| 3073 | (defvar org-prefix-format-compiled nil | ||
| 3074 | "The compiled version of the most recently used prefix format. | ||
| 3075 | See the variable `org-agenda-prefix-format'.") | ||
| 3076 | |||
| 3077 | (defcustom org-agenda-todo-keyword-format "%-1s" | ||
| 3078 | "Format for the TODO keyword in agenda lines. | ||
| 3079 | Set this to something like \"%-12s\" if you want all TODO keywords | ||
| 3080 | to occupy a fixed space in the agenda display." | ||
| 3081 | :group 'org-agenda-line-format | ||
| 3082 | :type 'string) | ||
| 3083 | |||
| 3084 | (defcustom org-agenda-scheduled-leaders '("Scheduled: " "Sched.%2dx: ") | ||
| 3085 | "Text preceeding scheduled items in the agenda view. | ||
| 3086 | This is a list with two strings. The first applies when the item is | ||
| 3087 | scheduled on the current day. The second applies when it has been scheduled | ||
| 3088 | previously, it may contain a %d to capture how many days ago the item was | ||
| 3089 | scheduled." | ||
| 3090 | :group 'org-agenda-line-format | ||
| 3091 | :type '(list | ||
| 3092 | (string :tag "Scheduled today ") | ||
| 3093 | (string :tag "Scheduled previously"))) | ||
| 3094 | |||
| 3095 | (defcustom org-agenda-deadline-leaders '("Deadline: " "In %3d d.: ") | ||
| 3096 | "Text preceeding deadline items in the agenda view. | ||
| 3097 | This is a list with two strings. The first applies when the item has its | ||
| 3098 | deadline on the current day. The second applies when it is in the past or | ||
| 3099 | in the future, it may contain %d to capture how many days away the deadline | ||
| 3100 | is (was)." | ||
| 3101 | :group 'org-agenda-line-format | ||
| 3102 | :type '(list | ||
| 3103 | (string :tag "Deadline today ") | ||
| 3104 | (string :tag "Deadline relative"))) | ||
| 3105 | |||
| 3106 | (defcustom org-agenda-remove-times-when-in-prefix t | ||
| 3107 | "Non-nil means, remove duplicate time specifications in agenda items. | ||
| 3108 | When the format `org-agenda-prefix-format' contains a `%t' specifier, a | ||
| 3109 | time-of-day specification in a headline or diary entry is extracted and | ||
| 3110 | placed into the prefix. If this option is non-nil, the original specification | ||
| 3111 | \(a timestamp or -range, or just a plain time(range) specification like | ||
| 3112 | 11:30-4pm) will be removed for agenda display. This makes the agenda less | ||
| 3113 | cluttered. | ||
| 3114 | The option can be t or nil. It may also be the symbol `beg', indicating | ||
| 3115 | that the time should only be removed what it is located at the beginning of | ||
| 3116 | the headline/diary entry." | ||
| 3117 | :group 'org-agenda-line-format | ||
| 3118 | :type '(choice | ||
| 3119 | (const :tag "Always" t) | ||
| 3120 | (const :tag "Never" nil) | ||
| 3121 | (const :tag "When at beginning of entry" beg))) | ||
| 3122 | |||
| 3123 | |||
| 3124 | (defcustom org-agenda-default-appointment-duration nil | ||
| 3125 | "Default duration for appointments that only have a starting time. | ||
| 3126 | When nil, no duration is specified in such cases. | ||
| 3127 | When non-nil, this must be the number of minutes, e.g. 60 for one hour." | ||
| 3128 | :group 'org-agenda-line-format | ||
| 3129 | :type '(choice | ||
| 3130 | (integer :tag "Minutes") | ||
| 3131 | (const :tag "No default duration"))) | ||
| 3132 | |||
| 3133 | |||
| 3134 | (defcustom org-agenda-remove-tags nil | ||
| 3135 | "Non-nil means, remove the tags from the headline copy in the agenda. | ||
| 3136 | When this is the symbol `prefix', only remove tags when | ||
| 3137 | `org-agenda-prefix-format' contains a `%T' specifier." | ||
| 3138 | :group 'org-agenda-line-format | ||
| 3139 | :type '(choice | ||
| 3140 | (const :tag "Always" t) | ||
| 3141 | (const :tag "Never" nil) | ||
| 3142 | (const :tag "When prefix format contains %T" prefix))) | ||
| 3143 | |||
| 3144 | (if (fboundp 'defvaralias) | ||
| 3145 | (defvaralias 'org-agenda-remove-tags-when-in-prefix | ||
| 3146 | 'org-agenda-remove-tags)) | ||
| 3147 | |||
| 3148 | (defcustom org-agenda-tags-column -80 | ||
| 3149 | "Shift tags in agenda items to this column. | ||
| 3150 | If this number is positive, it specifies the column. If it is negative, | ||
| 3151 | it means that the tags should be flushright to that column. For example, | ||
| 3152 | -80 works well for a normal 80 character screen." | ||
| 3153 | :group 'org-agenda-line-format | ||
| 3154 | :type 'integer) | ||
| 3155 | |||
| 3156 | (if (fboundp 'defvaralias) | ||
| 3157 | (defvaralias 'org-agenda-align-tags-to-column 'org-agenda-tags-column)) | ||
| 3158 | |||
| 3159 | (defcustom org-agenda-fontify-priorities t | ||
| 3160 | "Non-nil means, highlight low and high priorities in agenda. | ||
| 3161 | When t, the highest priority entries are bold, lowest priority italic. | ||
| 3162 | This may also be an association list of priority faces. The face may be | ||
| 3163 | a names face, or a list like `(:background \"Red\")'." | ||
| 3164 | :group 'org-agenda-line-format | ||
| 3165 | :type '(choice | ||
| 3166 | (const :tag "Never" nil) | ||
| 3167 | (const :tag "Defaults" t) | ||
| 3168 | (repeat :tag "Specify" | ||
| 3169 | (list (character :tag "Priority" :value ?A) | ||
| 3170 | (sexp :tag "face"))))) | ||
| 3171 | |||
| 3172 | (defgroup org-latex nil | ||
| 3173 | "Options for embedding LaTeX code into Org-mode." | ||
| 3174 | :tag "Org LaTeX" | ||
| 3175 | :group 'org) | ||
| 3176 | |||
| 3177 | (defcustom org-format-latex-options | ||
| 3178 | '(:foreground default :background default :scale 1.0 | ||
| 3179 | :html-foreground "Black" :html-background "Transparent" :html-scale 1.0 | ||
| 3180 | :matchers ("begin" "$" "$$" "\\(" "\\[")) | ||
| 3181 | "Options for creating images from LaTeX fragments. | ||
| 3182 | This is a property list with the following properties: | ||
| 3183 | :foreground the foreground color for images embedded in emacs, e.g. \"Black\". | ||
| 3184 | `default' means use the forground of the default face. | ||
| 3185 | :background the background color, or \"Transparent\". | ||
| 3186 | `default' means use the background of the default face. | ||
| 3187 | :scale a scaling factor for the size of the images | ||
| 3188 | :html-foreground, :html-background, :html-scale | ||
| 3189 | The same numbers for HTML export. | ||
| 3190 | :matchers a list indicating which matchers should be used to | ||
| 3191 | find LaTeX fragments. Valid members of this list are: | ||
| 3192 | \"begin\" find environments | ||
| 3193 | \"$\" find math expressions surrounded by $...$ | ||
| 3194 | \"$$\" find math expressions surrounded by $$....$$ | ||
| 3195 | \"\\(\" find math expressions surrounded by \\(...\\) | ||
| 3196 | \"\\ [\" find math expressions surrounded by \\ [...\\]" | ||
| 3197 | :group 'org-latex | ||
| 3198 | :type 'plist) | ||
| 3199 | |||
| 3200 | (defcustom org-format-latex-header "\\documentclass{article} | ||
| 3201 | \\usepackage{fullpage} % do not remove | ||
| 3202 | \\usepackage{amssymb} | ||
| 3203 | \\usepackage[usenames]{color} | ||
| 3204 | \\usepackage{amsmath} | ||
| 3205 | \\usepackage{latexsym} | ||
| 3206 | \\usepackage[mathscr]{eucal} | ||
| 3207 | \\pagestyle{empty} % do not remove" | ||
| 3208 | "The document header used for processing LaTeX fragments." | ||
| 3209 | :group 'org-latex | ||
| 3210 | :type 'string) | ||
| 3211 | |||
| 3212 | (defgroup org-export nil | ||
| 3213 | "Options for exporting org-listings." | ||
| 3214 | :tag "Org Export" | ||
| 3215 | :group 'org) | ||
| 3216 | |||
| 3217 | (defgroup org-export-general nil | ||
| 3218 | "General options for exporting Org-mode files." | ||
| 3219 | :tag "Org Export General" | ||
| 3220 | :group 'org-export) | ||
| 3221 | |||
| 3222 | ;; FIXME | ||
| 3223 | (defvar org-export-publishing-directory nil) | ||
| 3224 | |||
| 3225 | (defcustom org-export-with-special-strings t | ||
| 3226 | "Non-nil means, interpret \"\-\", \"--\" and \"---\" for export. | ||
| 3227 | When this option is turned on, these strings will be exported as: | ||
| 3228 | |||
| 3229 | Org HTML LaTeX | ||
| 3230 | -----+----------+-------- | ||
| 3231 | \\- ­ \\- | ||
| 3232 | -- – -- | ||
| 3233 | --- — --- | ||
| 3234 | ... … \ldots | ||
| 3235 | |||
| 3236 | This option can also be set with the +OPTIONS line, e.g. \"-:nil\"." | ||
| 3237 | :group 'org-export-translation | ||
| 3238 | :type 'boolean) | ||
| 3239 | |||
| 3240 | (defcustom org-export-language-setup | ||
| 3241 | '(("en" "Author" "Date" "Table of Contents") | ||
| 3242 | ("cs" "Autor" "Datum" "Obsah") | ||
| 3243 | ("da" "Ophavsmand" "Dato" "Indhold") | ||
| 3244 | ("de" "Autor" "Datum" "Inhaltsverzeichnis") | ||
| 3245 | ("es" "Autor" "Fecha" "\xcdndice") | ||
| 3246 | ("fr" "Auteur" "Date" "Table des mati\xe8res") | ||
| 3247 | ("it" "Autore" "Data" "Indice") | ||
| 3248 | ("nl" "Auteur" "Datum" "Inhoudsopgave") | ||
| 3249 | ("nn" "Forfattar" "Dato" "Innhold") ;; nn = Norsk (nynorsk) | ||
| 3250 | ("sv" "F\xf6rfattarens" "Datum" "Inneh\xe5ll")) | ||
| 3251 | "Terms used in export text, translated to different languages. | ||
| 3252 | Use the variable `org-export-default-language' to set the language, | ||
| 3253 | or use the +OPTION lines for a per-file setting." | ||
| 3254 | :group 'org-export-general | ||
| 3255 | :type '(repeat | ||
| 3256 | (list | ||
| 3257 | (string :tag "HTML language tag") | ||
| 3258 | (string :tag "Author") | ||
| 3259 | (string :tag "Date") | ||
| 3260 | (string :tag "Table of Contents")))) | ||
| 3261 | |||
| 3262 | (defcustom org-export-default-language "en" | ||
| 3263 | "The default language of HTML export, as a string. | ||
| 3264 | This should have an association in `org-export-language-setup'." | ||
| 3265 | :group 'org-export-general | ||
| 3266 | :type 'string) | ||
| 3267 | |||
| 3268 | (defcustom org-export-skip-text-before-1st-heading t | ||
| 3269 | "Non-nil means, skip all text before the first headline when exporting. | ||
| 3270 | When nil, that text is exported as well." | ||
| 3271 | :group 'org-export-general | ||
| 3272 | :type 'boolean) | ||
| 3273 | |||
| 3274 | (defcustom org-export-headline-levels 3 | ||
| 3275 | "The last level which is still exported as a headline. | ||
| 3276 | Inferior levels will produce itemize lists when exported. | ||
| 3277 | Note that a numeric prefix argument to an exporter function overrides | ||
| 3278 | this setting. | ||
| 3279 | |||
| 3280 | This option can also be set with the +OPTIONS line, e.g. \"H:2\"." | ||
| 3281 | :group 'org-export-general | ||
| 3282 | :type 'number) | ||
| 3283 | |||
| 3284 | (defcustom org-export-with-section-numbers t | ||
| 3285 | "Non-nil means, add section numbers to headlines when exporting. | ||
| 3286 | |||
| 3287 | This option can also be set with the +OPTIONS line, e.g. \"num:t\"." | ||
| 3288 | :group 'org-export-general | ||
| 3289 | :type 'boolean) | ||
| 3290 | |||
| 3291 | (defcustom org-export-with-toc t | ||
| 3292 | "Non-nil means, create a table of contents in exported files. | ||
| 3293 | The TOC contains headlines with levels up to`org-export-headline-levels'. | ||
| 3294 | When an integer, include levels up to N in the toc, this may then be | ||
| 3295 | different from `org-export-headline-levels', but it will not be allowed | ||
| 3296 | to be larger than the number of headline levels. | ||
| 3297 | When nil, no table of contents is made. | ||
| 3298 | |||
| 3299 | Headlines which contain any TODO items will be marked with \"(*)\" in | ||
| 3300 | ASCII export, and with red color in HTML output, if the option | ||
| 3301 | `org-export-mark-todo-in-toc' is set. | ||
| 3302 | |||
| 3303 | In HTML output, the TOC will be clickable. | ||
| 3304 | |||
| 3305 | This option can also be set with the +OPTIONS line, e.g. \"toc:nil\" | ||
| 3306 | or \"toc:3\"." | ||
| 3307 | :group 'org-export-general | ||
| 3308 | :type '(choice | ||
| 3309 | (const :tag "No Table of Contents" nil) | ||
| 3310 | (const :tag "Full Table of Contents" t) | ||
| 3311 | (integer :tag "TOC to level"))) | ||
| 3312 | |||
| 3313 | (defcustom org-export-mark-todo-in-toc nil | ||
| 3314 | "Non-nil means, mark TOC lines that contain any open TODO items." | ||
| 3315 | :group 'org-export-general | ||
| 3316 | :type 'boolean) | ||
| 3317 | |||
| 3318 | (defcustom org-export-preserve-breaks nil | ||
| 3319 | "Non-nil means, preserve all line breaks when exporting. | ||
| 3320 | Normally, in HTML output paragraphs will be reformatted. In ASCII | ||
| 3321 | export, line breaks will always be preserved, regardless of this variable. | ||
| 3322 | |||
| 3323 | This option can also be set with the +OPTIONS line, e.g. \"\\n:t\"." | ||
| 3324 | :group 'org-export-general | ||
| 3325 | :type 'boolean) | ||
| 3326 | |||
| 3327 | (defcustom org-export-with-archived-trees 'headline | ||
| 3328 | "Whether subtrees with the ARCHIVE tag should be exported. | ||
| 3329 | This can have three different values | ||
| 3330 | nil Do not export, pretend this tree is not present | ||
| 3331 | t Do export the entire tree | ||
| 3332 | headline Only export the headline, but skip the tree below it." | ||
| 3333 | :group 'org-export-general | ||
| 3334 | :group 'org-archive | ||
| 3335 | :type '(choice | ||
| 3336 | (const :tag "not at all" nil) | ||
| 3337 | (const :tag "headline only" 'headline) | ||
| 3338 | (const :tag "entirely" t))) | ||
| 3339 | |||
| 3340 | (defcustom org-export-author-info t | ||
| 3341 | "Non-nil means, insert author name and email into the exported file. | ||
| 3342 | |||
| 3343 | This option can also be set with the +OPTIONS line, | ||
| 3344 | e.g. \"author-info:nil\"." | ||
| 3345 | :group 'org-export-general | ||
| 3346 | :type 'boolean) | ||
| 3347 | |||
| 3348 | (defcustom org-export-time-stamp-file t | ||
| 3349 | "Non-nil means, insert a time stamp into the exported file. | ||
| 3350 | The time stamp shows when the file was created. | ||
| 3351 | |||
| 3352 | This option can also be set with the +OPTIONS line, | ||
| 3353 | e.g. \"timestamp:nil\"." | ||
| 3354 | :group 'org-export-general | ||
| 3355 | :type 'boolean) | ||
| 3356 | |||
| 3357 | (defcustom org-export-with-timestamps t | ||
| 3358 | "If nil, do not export time stamps and associated keywords." | ||
| 3359 | :group 'org-export-general | ||
| 3360 | :type 'boolean) | ||
| 3361 | |||
| 3362 | (defcustom org-export-remove-timestamps-from-toc t | ||
| 3363 | "If nil, remove timestamps from the table of contents entries." | ||
| 3364 | :group 'org-export-general | ||
| 3365 | :type 'boolean) | ||
| 3366 | |||
| 3367 | (defcustom org-export-with-tags 'not-in-toc | ||
| 3368 | "If nil, do not export tags, just remove them from headlines. | ||
| 3369 | If this is the symbol `not-in-toc', tags will be removed from table of | ||
| 3370 | contents entries, but still be shown in the headlines of the document. | ||
| 3371 | |||
| 3372 | This option can also be set with the +OPTIONS line, e.g. \"tags:nil\"." | ||
| 3373 | :group 'org-export-general | ||
| 3374 | :type '(choice | ||
| 3375 | (const :tag "Off" nil) | ||
| 3376 | (const :tag "Not in TOC" not-in-toc) | ||
| 3377 | (const :tag "On" t))) | ||
| 3378 | |||
| 3379 | (defcustom org-export-with-drawers nil | ||
| 3380 | "Non-nil means, export with drawers like the property drawer. | ||
| 3381 | When t, all drawers are exported. This may also be a list of | ||
| 3382 | drawer names to export." | ||
| 3383 | :group 'org-export-general | ||
| 3384 | :type '(choice | ||
| 3385 | (const :tag "All drawers" t) | ||
| 3386 | (const :tag "None" nil) | ||
| 3387 | (repeat :tag "Selected drawers" | ||
| 3388 | (string :tag "Drawer name")))) | ||
| 3389 | |||
| 3390 | (defgroup org-export-translation nil | ||
| 3391 | "Options for translating special ascii sequences for the export backends." | ||
| 3392 | :tag "Org Export Translation" | ||
| 3393 | :group 'org-export) | ||
| 3394 | |||
| 3395 | (defcustom org-export-with-emphasize t | ||
| 3396 | "Non-nil means, interpret *word*, /word/, and _word_ as emphasized text. | ||
| 3397 | If the export target supports emphasizing text, the word will be | ||
| 3398 | typeset in bold, italic, or underlined, respectively. Works only for | ||
| 3399 | single words, but you can say: I *really* *mean* *this*. | ||
| 3400 | Not all export backends support this. | ||
| 3401 | |||
| 3402 | This option can also be set with the +OPTIONS line, e.g. \"*:nil\"." | ||
| 3403 | :group 'org-export-translation | ||
| 3404 | :type 'boolean) | ||
| 3405 | |||
| 3406 | (defcustom org-export-with-footnotes t | ||
| 3407 | "If nil, export [1] as a footnote marker. | ||
| 3408 | Lines starting with [1] will be formatted as footnotes. | ||
| 3409 | |||
| 3410 | This option can also be set with the +OPTIONS line, e.g. \"f:nil\"." | ||
| 3411 | :group 'org-export-translation | ||
| 3412 | :type 'boolean) | ||
| 3413 | |||
| 3414 | (defcustom org-export-with-sub-superscripts t | ||
| 3415 | "Non-nil means, interpret \"_\" and \"^\" for export. | ||
| 3416 | When this option is turned on, you can use TeX-like syntax for sub- and | ||
| 3417 | superscripts. Several characters after \"_\" or \"^\" will be | ||
| 3418 | considered as a single item - so grouping with {} is normally not | ||
| 3419 | needed. For example, the following things will be parsed as single | ||
| 3420 | sub- or superscripts. | ||
| 3421 | |||
| 3422 | 10^24 or 10^tau several digits will be considered 1 item. | ||
| 3423 | 10^-12 or 10^-tau a leading sign with digits or a word | ||
| 3424 | x^2-y^3 will be read as x^2 - y^3, because items are | ||
| 3425 | terminated by almost any nonword/nondigit char. | ||
| 3426 | x_{i^2} or x^(2-i) braces or parenthesis do grouping. | ||
| 3427 | |||
| 3428 | Still, ambiguity is possible - so when in doubt use {} to enclose the | ||
| 3429 | sub/superscript. If you set this variable to the symbol `{}', | ||
| 3430 | the braces are *required* in order to trigger interpretations as | ||
| 3431 | sub/superscript. This can be helpful in documents that need \"_\" | ||
| 3432 | frequently in plain text. | ||
| 3433 | |||
| 3434 | Not all export backends support this, but HTML does. | ||
| 3435 | |||
| 3436 | This option can also be set with the +OPTIONS line, e.g. \"^:nil\"." | ||
| 3437 | :group 'org-export-translation | ||
| 3438 | :type '(choice | ||
| 3439 | (const :tag "Always interpret" t) | ||
| 3440 | (const :tag "Only with braces" {}) | ||
| 3441 | (const :tag "Never interpret" nil))) | ||
| 3442 | |||
| 3443 | (defcustom org-export-with-special-strings t | ||
| 3444 | "Non-nil means, interpret \"\-\", \"--\" and \"---\" for export. | ||
| 3445 | When this option is turned on, these strings will be exported as: | ||
| 3446 | |||
| 3447 | \\- : ­ | ||
| 3448 | -- : – | ||
| 3449 | --- : — | ||
| 3450 | |||
| 3451 | Not all export backends support this, but HTML does. | ||
| 3452 | |||
| 3453 | This option can also be set with the +OPTIONS line, e.g. \"-:nil\"." | ||
| 3454 | :group 'org-export-translation | ||
| 3455 | :type 'boolean) | ||
| 3456 | |||
| 3457 | (defcustom org-export-with-TeX-macros t | ||
| 3458 | "Non-nil means, interpret simple TeX-like macros when exporting. | ||
| 3459 | For example, HTML export converts \\alpha to α and \\AA to Å. | ||
| 3460 | No only real TeX macros will work here, but the standard HTML entities | ||
| 3461 | for math can be used as macro names as well. For a list of supported | ||
| 3462 | names in HTML export, see the constant `org-html-entities'. | ||
| 3463 | Not all export backends support this. | ||
| 3464 | |||
| 3465 | This option can also be set with the +OPTIONS line, e.g. \"TeX:nil\"." | ||
| 3466 | :group 'org-export-translation | ||
| 3467 | :group 'org-export-latex | ||
| 3468 | :type 'boolean) | ||
| 3469 | |||
| 3470 | (defcustom org-export-with-LaTeX-fragments nil | ||
| 3471 | "Non-nil means, convert LaTeX fragments to images when exporting to HTML. | ||
| 3472 | When set, the exporter will find LaTeX environments if the \\begin line is | ||
| 3473 | the first non-white thing on a line. It will also find the math delimiters | ||
| 3474 | like $a=b$ and \\( a=b \\) for inline math, $$a=b$$ and \\[ a=b \\] for | ||
| 3475 | display math. | ||
| 3476 | |||
| 3477 | This option can also be set with the +OPTIONS line, e.g. \"LaTeX:t\"." | ||
| 3478 | :group 'org-export-translation | ||
| 3479 | :group 'org-export-latex | ||
| 3480 | :type 'boolean) | ||
| 3481 | |||
| 3482 | (defcustom org-export-with-fixed-width t | ||
| 3483 | "Non-nil means, lines starting with \":\" will be in fixed width font. | ||
| 3484 | This can be used to have pre-formatted text, fragments of code etc. For | ||
| 3485 | example: | ||
| 3486 | : ;; Some Lisp examples | ||
| 3487 | : (while (defc cnt) | ||
| 3488 | : (ding)) | ||
| 3489 | will be looking just like this in also HTML. See also the QUOTE keyword. | ||
| 3490 | Not all export backends support this. | ||
| 3491 | |||
| 3492 | This option can also be set with the +OPTIONS line, e.g. \"::nil\"." | ||
| 3493 | :group 'org-export-translation | ||
| 3494 | :type 'boolean) | ||
| 3495 | |||
| 3496 | (defcustom org-match-sexp-depth 3 | ||
| 3497 | "Number of stacked braces for sub/superscript matching. | ||
| 3498 | This has to be set before loading org.el to be effective." | ||
| 3499 | :group 'org-export-translation | ||
| 3500 | :type 'integer) | ||
| 3501 | |||
| 3502 | (defgroup org-export-tables nil | ||
| 3503 | "Options for exporting tables in Org-mode." | ||
| 3504 | :tag "Org Export Tables" | ||
| 3505 | :group 'org-export) | ||
| 3506 | |||
| 3507 | (defcustom org-export-with-tables t | ||
| 3508 | "If non-nil, lines starting with \"|\" define a table. | ||
| 3509 | For example: | ||
| 3510 | |||
| 3511 | | Name | Address | Birthday | | ||
| 3512 | |-------------+----------+-----------| | ||
| 3513 | | Arthur Dent | England | 29.2.2100 | | ||
| 3514 | |||
| 3515 | Not all export backends support this. | ||
| 3516 | |||
| 3517 | This option can also be set with the +OPTIONS line, e.g. \"|:nil\"." | ||
| 3518 | :group 'org-export-tables | ||
| 3519 | :type 'boolean) | ||
| 3520 | |||
| 3521 | (defcustom org-export-highlight-first-table-line t | ||
| 3522 | "Non-nil means, highlight the first table line. | ||
| 3523 | In HTML export, this means use <th> instead of <td>. | ||
| 3524 | In tables created with table.el, this applies to the first table line. | ||
| 3525 | In Org-mode tables, all lines before the first horizontal separator | ||
| 3526 | line will be formatted with <th> tags." | ||
| 3527 | :group 'org-export-tables | ||
| 3528 | :type 'boolean) | ||
| 3529 | |||
| 3530 | (defcustom org-export-table-remove-special-lines t | ||
| 3531 | "Remove special lines and marking characters in calculating tables. | ||
| 3532 | This removes the special marking character column from tables that are set | ||
| 3533 | up for spreadsheet calculations. It also removes the entire lines | ||
| 3534 | marked with `!', `_', or `^'. The lines with `$' are kept, because | ||
| 3535 | the values of constants may be useful to have." | ||
| 3536 | :group 'org-export-tables | ||
| 3537 | :type 'boolean) | ||
| 3538 | |||
| 3539 | (defcustom org-export-prefer-native-exporter-for-tables nil | ||
| 3540 | "Non-nil means, always export tables created with table.el natively. | ||
| 3541 | Natively means, use the HTML code generator in table.el. | ||
| 3542 | When nil, Org-mode's own HTML generator is used when possible (i.e. if | ||
| 3543 | the table does not use row- or column-spanning). This has the | ||
| 3544 | advantage, that the automatic HTML conversions for math symbols and | ||
| 3545 | sub/superscripts can be applied. Org-mode's HTML generator is also | ||
| 3546 | much faster." | ||
| 3547 | :group 'org-export-tables | ||
| 3548 | :type 'boolean) | ||
| 3549 | |||
| 3550 | (defgroup org-export-ascii nil | ||
| 3551 | "Options specific for ASCII export of Org-mode files." | ||
| 3552 | :tag "Org Export ASCII" | ||
| 3553 | :group 'org-export) | ||
| 3554 | |||
| 3555 | (defcustom org-export-ascii-underline '(?\$ ?\# ?^ ?\~ ?\= ?\-) | ||
| 3556 | "Characters for underlining headings in ASCII export. | ||
| 3557 | In the given sequence, these characters will be used for level 1, 2, ..." | ||
| 3558 | :group 'org-export-ascii | ||
| 3559 | :type '(repeat character)) | ||
| 3560 | |||
| 3561 | (defcustom org-export-ascii-bullets '(?* ?+ ?-) | ||
| 3562 | "Bullet characters for headlines converted to lists in ASCII export. | ||
| 3563 | The first character is used for the first lest level generated in this | ||
| 3564 | way, and so on. If there are more levels than characters given here, | ||
| 3565 | the list will be repeated. | ||
| 3566 | Note that plain lists will keep the same bullets as the have in the | ||
| 3567 | Org-mode file." | ||
| 3568 | :group 'org-export-ascii | ||
| 3569 | :type '(repeat character)) | ||
| 3570 | |||
| 3571 | (defgroup org-export-xml nil | ||
| 3572 | "Options specific for XML export of Org-mode files." | ||
| 3573 | :tag "Org Export XML" | ||
| 3574 | :group 'org-export) | ||
| 3575 | |||
| 3576 | (defgroup org-export-html nil | ||
| 3577 | "Options specific for HTML export of Org-mode files." | ||
| 3578 | :tag "Org Export HTML" | ||
| 3579 | :group 'org-export) | ||
| 3580 | |||
| 3581 | (defcustom org-export-html-coding-system nil | ||
| 3582 | "" | ||
| 3583 | :group 'org-export-html | ||
| 3584 | :type 'coding-system) | ||
| 3585 | |||
| 3586 | (defcustom org-export-html-extension "html" | ||
| 3587 | "The extension for exported HTML files." | ||
| 3588 | :group 'org-export-html | ||
| 3589 | :type 'string) | ||
| 3590 | |||
| 3591 | (defcustom org-export-html-style | ||
| 3592 | "<style type=\"text/css\"> | ||
| 3593 | html { | ||
| 3594 | font-family: Times, serif; | ||
| 3595 | font-size: 12pt; | ||
| 3596 | } | ||
| 3597 | .title { text-align: center; } | ||
| 3598 | .todo { color: red; } | ||
| 3599 | .done { color: green; } | ||
| 3600 | .timestamp { color: grey } | ||
| 3601 | .timestamp-kwd { color: CadetBlue } | ||
| 3602 | .tag { background-color:lightblue; font-weight:normal } | ||
| 3603 | .target { background-color: lavender; } | ||
| 3604 | pre { | ||
| 3605 | border: 1pt solid #AEBDCC; | ||
| 3606 | background-color: #F3F5F7; | ||
| 3607 | padding: 5pt; | ||
| 3608 | font-family: courier, monospace; | ||
| 3609 | } | ||
| 3610 | table { border-collapse: collapse; } | ||
| 3611 | td, th { | ||
| 3612 | vertical-align: top; | ||
| 3613 | <!--border: 1pt solid #ADB9CC;--> | ||
| 3614 | } | ||
| 3615 | </style>" | ||
| 3616 | "The default style specification for exported HTML files. | ||
| 3617 | Since there are different ways of setting style information, this variable | ||
| 3618 | needs to contain the full HTML structure to provide a style, including the | ||
| 3619 | surrounding HTML tags. The style specifications should include definitions | ||
| 3620 | for new classes todo, done, title, and deadline. For example, valid values | ||
| 3621 | would be: | ||
| 3622 | |||
| 3623 | <style type=\"text/css\"> | ||
| 3624 | p { font-weight: normal; color: gray; } | ||
| 3625 | h1 { color: black; } | ||
| 3626 | .title { text-align: center; } | ||
| 3627 | .todo, .deadline { color: red; } | ||
| 3628 | .done { color: green; } | ||
| 3629 | </style> | ||
| 3630 | |||
| 3631 | or, if you want to keep the style in a file, | ||
| 3632 | |||
| 3633 | <link rel=\"stylesheet\" type=\"text/css\" href=\"mystyles.css\"> | ||
| 3634 | |||
| 3635 | As the value of this option simply gets inserted into the HTML <head> header, | ||
| 3636 | you can \"misuse\" it to add arbitrary text to the header." | ||
| 3637 | :group 'org-export-html | ||
| 3638 | :type 'string) | ||
| 3639 | |||
| 3640 | |||
| 3641 | (defcustom org-export-html-title-format "<h1 class=\"title\">%s</h1>\n" | ||
| 3642 | "Format for typesetting the document title in HTML export." | ||
| 3643 | :group 'org-export-html | ||
| 3644 | :type 'string) | ||
| 3645 | |||
| 3646 | (defcustom org-export-html-toplevel-hlevel 2 | ||
| 3647 | "The <H> level for level 1 headings in HTML export." | ||
| 3648 | :group 'org-export-html | ||
| 3649 | :type 'string) | ||
| 3650 | |||
| 3651 | (defcustom org-export-html-link-org-files-as-html t | ||
| 3652 | "Non-nil means, make file links to `file.org' point to `file.html'. | ||
| 3653 | When org-mode is exporting an org-mode file to HTML, links to | ||
| 3654 | non-html files are directly put into a href tag in HTML. | ||
| 3655 | However, links to other Org-mode files (recognized by the | ||
| 3656 | extension `.org.) should become links to the corresponding html | ||
| 3657 | file, assuming that the linked org-mode file will also be | ||
| 3658 | converted to HTML. | ||
| 3659 | When nil, the links still point to the plain `.org' file." | ||
| 3660 | :group 'org-export-html | ||
| 3661 | :type 'boolean) | ||
| 3662 | |||
| 3663 | (defcustom org-export-html-inline-images 'maybe | ||
| 3664 | "Non-nil means, inline images into exported HTML pages. | ||
| 3665 | This is done using an <img> tag. When nil, an anchor with href is used to | ||
| 3666 | link to the image. If this option is `maybe', then images in links with | ||
| 3667 | an empty description will be inlined, while images with a description will | ||
| 3668 | be linked only." | ||
| 3669 | :group 'org-export-html | ||
| 3670 | :type '(choice (const :tag "Never" nil) | ||
| 3671 | (const :tag "Always" t) | ||
| 3672 | (const :tag "When there is no description" maybe))) | ||
| 3673 | |||
| 3674 | ;; FIXME: rename | ||
| 3675 | (defcustom org-export-html-expand t | ||
| 3676 | "Non-nil means, for HTML export, treat @<...> as HTML tag. | ||
| 3677 | When nil, these tags will be exported as plain text and therefore | ||
| 3678 | not be interpreted by a browser. | ||
| 3679 | |||
| 3680 | This option can also be set with the +OPTIONS line, e.g. \"@:nil\"." | ||
| 3681 | :group 'org-export-html | ||
| 3682 | :type 'boolean) | ||
| 3683 | |||
| 3684 | (defcustom org-export-html-table-tag | ||
| 3685 | "<table border=\"2\" cellspacing=\"0\" cellpadding=\"6\" rules=\"groups\" frame=\"hsides\">" | ||
| 3686 | "The HTML tag that is used to start a table. | ||
| 3687 | This must be a <table> tag, but you may change the options like | ||
| 3688 | borders and spacing." | ||
| 3689 | :group 'org-export-html | ||
| 3690 | :type 'string) | ||
| 3691 | |||
| 3692 | (defcustom org-export-table-header-tags '("<th>" . "</th>") | ||
| 3693 | "The opening tag for table header fields. | ||
| 3694 | This is customizable so that alignment options can be specified." | ||
| 3695 | :group 'org-export-tables | ||
| 3696 | :type '(cons (string :tag "Opening tag") (string :tag "Closing tag"))) | ||
| 3697 | |||
| 3698 | (defcustom org-export-table-data-tags '("<td>" . "</td>") | ||
| 3699 | "The opening tag for table data fields. | ||
| 3700 | This is customizable so that alignment options can be specified." | ||
| 3701 | :group 'org-export-tables | ||
| 3702 | :type '(cons (string :tag "Opening tag") (string :tag "Closing tag"))) | ||
| 3703 | |||
| 3704 | (defcustom org-export-html-with-timestamp nil | ||
| 3705 | "If non-nil, write `org-export-html-html-helper-timestamp' | ||
| 3706 | into the exported HTML text. Otherwise, the buffer will just be saved | ||
| 3707 | to a file." | ||
| 3708 | :group 'org-export-html | ||
| 3709 | :type 'boolean) | ||
| 3710 | |||
| 3711 | (defcustom org-export-html-html-helper-timestamp | ||
| 3712 | "<br/><br/><hr><p><!-- hhmts start --> <!-- hhmts end --></p>\n" | ||
| 3713 | "The HTML tag used as timestamp delimiter for HTML-helper-mode." | ||
| 3714 | :group 'org-export-html | ||
| 3715 | :type 'string) | ||
| 3716 | |||
| 3717 | (defgroup org-export-icalendar nil | ||
| 3718 | "Options specific for iCalendar export of Org-mode files." | ||
| 3719 | :tag "Org Export iCalendar" | ||
| 3720 | :group 'org-export) | ||
| 3721 | |||
| 3722 | (defcustom org-combined-agenda-icalendar-file "~/org.ics" | ||
| 3723 | "The file name for the iCalendar file covering all agenda files. | ||
| 3724 | This file is created with the command \\[org-export-icalendar-all-agenda-files]. | ||
| 3725 | The file name should be absolute, the file will be overwritten without warning." | ||
| 3726 | :group 'org-export-icalendar | ||
| 3727 | :type 'file) | ||
| 3728 | |||
| 3729 | (defcustom org-icalendar-include-todo nil | ||
| 3730 | "Non-nil means, export to iCalendar files should also cover TODO items." | ||
| 3731 | :group 'org-export-icalendar | ||
| 3732 | :type '(choice | ||
| 3733 | (const :tag "None" nil) | ||
| 3734 | (const :tag "Unfinished" t) | ||
| 3735 | (const :tag "All" all))) | ||
| 3736 | |||
| 3737 | (defcustom org-icalendar-include-sexps t | ||
| 3738 | "Non-nil means, export to iCalendar files should also cover sexp entries. | ||
| 3739 | These are entries like in the diary, but directly in an Org-mode file." | ||
| 3740 | :group 'org-export-icalendar | ||
| 3741 | :type 'boolean) | ||
| 3742 | |||
| 3743 | (defcustom org-icalendar-include-body 100 | ||
| 3744 | "Amount of text below headline to be included in iCalendar export. | ||
| 3745 | This is a number of characters that should maximally be included. | ||
| 3746 | Properties, scheduling and clocking lines will always be removed. | ||
| 3747 | The text will be inserted into the DESCRIPTION field." | ||
| 3748 | :group 'org-export-icalendar | ||
| 3749 | :type '(choice | ||
| 3750 | (const :tag "Nothing" nil) | ||
| 3751 | (const :tag "Everything" t) | ||
| 3752 | (integer :tag "Max characters"))) | ||
| 3753 | |||
| 3754 | (defcustom org-icalendar-combined-name "OrgMode" | ||
| 3755 | "Calendar name for the combined iCalendar representing all agenda files." | ||
| 3756 | :group 'org-export-icalendar | ||
| 3757 | :type 'string) | ||
| 3758 | |||
| 3759 | (defgroup org-font-lock nil | ||
| 3760 | "Font-lock settings for highlighting in Org-mode." | ||
| 3761 | :tag "Org Font Lock" | ||
| 3762 | :group 'org) | ||
| 3763 | |||
| 3764 | (defcustom org-level-color-stars-only nil | ||
| 3765 | "Non-nil means fontify only the stars in each headline. | ||
| 3766 | When nil, the entire headline is fontified. | ||
| 3767 | Changing it requires restart of `font-lock-mode' to become effective | ||
| 3768 | also in regions already fontified." | ||
| 3769 | :group 'org-font-lock | ||
| 3770 | :type 'boolean) | ||
| 3771 | |||
| 3772 | (defcustom org-hide-leading-stars nil | ||
| 3773 | "Non-nil means, hide the first N-1 stars in a headline. | ||
| 3774 | This works by using the face `org-hide' for these stars. This | ||
| 3775 | face is white for a light background, and black for a dark | ||
| 3776 | background. You may have to customize the face `org-hide' to | ||
| 3777 | make this work. | ||
| 3778 | Changing it requires restart of `font-lock-mode' to become effective | ||
| 3779 | also in regions already fontified. | ||
| 3780 | You may also set this on a per-file basis by adding one of the following | ||
| 3781 | lines to the buffer: | ||
| 3782 | |||
| 3783 | #+STARTUP: hidestars | ||
| 3784 | #+STARTUP: showstars" | ||
| 3785 | :group 'org-font-lock | ||
| 3786 | :type 'boolean) | ||
| 3787 | |||
| 3788 | (defcustom org-fontify-done-headline nil | ||
| 3789 | "Non-nil means, change the face of a headline if it is marked DONE. | ||
| 3790 | Normally, only the TODO/DONE keyword indicates the state of a headline. | ||
| 3791 | When this is non-nil, the headline after the keyword is set to the | ||
| 3792 | `org-headline-done' as an additional indication." | ||
| 3793 | :group 'org-font-lock | ||
| 3794 | :type 'boolean) | ||
| 3795 | |||
| 3796 | (defcustom org-fontify-emphasized-text t | ||
| 3797 | "Non-nil means fontify *bold*, /italic/ and _underlined_ text. | ||
| 3798 | Changing this variable requires a restart of Emacs to take effect." | ||
| 3799 | :group 'org-font-lock | ||
| 3800 | :type 'boolean) | ||
| 3801 | |||
| 3802 | (defcustom org-highlight-latex-fragments-and-specials nil | ||
| 3803 | "Non-nil means, fontify what is treated specially by the exporters." | ||
| 3804 | :group 'org-font-lock | ||
| 3805 | :type 'boolean) | ||
| 3806 | |||
| 3807 | (defcustom org-hide-emphasis-markers nil | ||
| 3808 | "Non-nil mean font-lock should hide the emphasis marker characters." | ||
| 3809 | :group 'org-font-lock | ||
| 3810 | :type 'boolean) | ||
| 3811 | |||
| 3812 | (defvar org-emph-re nil | ||
| 3813 | "Regular expression for matching emphasis.") | ||
| 3814 | (defvar org-verbatim-re nil | ||
| 3815 | "Regular expression for matching verbatim text.") | ||
| 3816 | (defvar org-emphasis-regexp-components) ; defined just below | ||
| 3817 | (defvar org-emphasis-alist) ; defined just below | ||
| 3818 | (defun org-set-emph-re (var val) | ||
| 3819 | "Set variable and compute the emphasis regular expression." | ||
| 3820 | (set var val) | ||
| 3821 | (when (and (boundp 'org-emphasis-alist) | ||
| 3822 | (boundp 'org-emphasis-regexp-components) | ||
| 3823 | org-emphasis-alist org-emphasis-regexp-components) | ||
| 3824 | (let* ((e org-emphasis-regexp-components) | ||
| 3825 | (pre (car e)) | ||
| 3826 | (post (nth 1 e)) | ||
| 3827 | (border (nth 2 e)) | ||
| 3828 | (body (nth 3 e)) | ||
| 3829 | (nl (nth 4 e)) | ||
| 3830 | (stacked (and nil (nth 5 e))) ; stacked is no longer allowed, forced to nil | ||
| 3831 | (body1 (concat body "*?")) | ||
| 3832 | (markers (mapconcat 'car org-emphasis-alist "")) | ||
| 3833 | (vmarkers (mapconcat | ||
| 3834 | (lambda (x) (if (eq (nth 4 x) 'verbatim) (car x) "")) | ||
| 3835 | org-emphasis-alist ""))) | ||
| 3836 | ;; make sure special characters appear at the right position in the class | ||
| 3837 | (if (string-match "\\^" markers) | ||
| 3838 | (setq markers (concat (replace-match "" t t markers) "^"))) | ||
| 3839 | (if (string-match "-" markers) | ||
| 3840 | (setq markers (concat (replace-match "" t t markers) "-"))) | ||
| 3841 | (if (string-match "\\^" vmarkers) | ||
| 3842 | (setq vmarkers (concat (replace-match "" t t vmarkers) "^"))) | ||
| 3843 | (if (string-match "-" vmarkers) | ||
| 3844 | (setq vmarkers (concat (replace-match "" t t vmarkers) "-"))) | ||
| 3845 | (if (> nl 0) | ||
| 3846 | (setq body1 (concat body1 "\\(?:\n" body "*?\\)\\{0," | ||
| 3847 | (int-to-string nl) "\\}"))) | ||
| 3848 | ;; Make the regexp | ||
| 3849 | (setq org-emph-re | ||
| 3850 | (concat "\\([" pre (if (and nil stacked) markers) "]\\|^\\)" | ||
| 3851 | "\\(" | ||
| 3852 | "\\([" markers "]\\)" | ||
| 3853 | "\\(" | ||
| 3854 | "[^" border "]\\|" | ||
| 3855 | "[^" border (if (and nil stacked) markers) "]" | ||
| 3856 | body1 | ||
| 3857 | "[^" border (if (and nil stacked) markers) "]" | ||
| 3858 | "\\)" | ||
| 3859 | "\\3\\)" | ||
| 3860 | "\\([" post (if (and nil stacked) markers) "]\\|$\\)")) | ||
| 3861 | (setq org-verbatim-re | ||
| 3862 | (concat "\\([" pre "]\\|^\\)" | ||
| 3863 | "\\(" | ||
| 3864 | "\\([" vmarkers "]\\)" | ||
| 3865 | "\\(" | ||
| 3866 | "[^" border "]\\|" | ||
| 3867 | "[^" border "]" | ||
| 3868 | body1 | ||
| 3869 | "[^" border "]" | ||
| 3870 | "\\)" | ||
| 3871 | "\\3\\)" | ||
| 3872 | "\\([" post "]\\|$\\)"))))) | ||
| 3873 | |||
| 3874 | (defcustom org-emphasis-regexp-components | ||
| 3875 | '(" \t('\"" "- \t.,:?;'\")" " \t\r\n,\"'" "." 1) | ||
| 3876 | "Components used to build the regular expression for emphasis. | ||
| 3877 | This is a list with 6 entries. Terminology: In an emphasis string | ||
| 3878 | like \" *strong word* \", we call the initial space PREMATCH, the final | ||
| 3879 | space POSTMATCH, the stars MARKERS, \"s\" and \"d\" are BORDER characters | ||
| 3880 | and \"trong wor\" is the body. The different components in this variable | ||
| 3881 | specify what is allowed/forbidden in each part: | ||
| 3882 | |||
| 3883 | pre Chars allowed as prematch. Beginning of line will be allowed too. | ||
| 3884 | post Chars allowed as postmatch. End of line will be allowed too. | ||
| 3885 | border The chars *forbidden* as border characters. | ||
| 3886 | body-regexp A regexp like \".\" to match a body character. Don't use | ||
| 3887 | non-shy groups here, and don't allow newline here. | ||
| 3888 | newline The maximum number of newlines allowed in an emphasis exp. | ||
| 3889 | |||
| 3890 | Use customize to modify this, or restart Emacs after changing it." | ||
| 3891 | :group 'org-font-lock | ||
| 3892 | :set 'org-set-emph-re | ||
| 3893 | :type '(list | ||
| 3894 | (sexp :tag "Allowed chars in pre ") | ||
| 3895 | (sexp :tag "Allowed chars in post ") | ||
| 3896 | (sexp :tag "Forbidden chars in border ") | ||
| 3897 | (sexp :tag "Regexp for body ") | ||
| 3898 | (integer :tag "number of newlines allowed") | ||
| 3899 | (option (boolean :tag "Stacking (DISABLED) ")))) | ||
| 3900 | |||
| 3901 | (defcustom org-emphasis-alist | ||
| 3902 | '(("*" bold "<b>" "</b>") | ||
| 3903 | ("/" italic "<i>" "</i>") | ||
| 3904 | ("_" underline "<u>" "</u>") | ||
| 3905 | ("=" org-code "<code>" "</code>" verbatim) | ||
| 3906 | ("~" org-verbatim "" "" verbatim) | ||
| 3907 | ("+" (:strike-through t) "<del>" "</del>") | ||
| 3908 | ) | ||
| 3909 | "Special syntax for emphasized text. | ||
| 3910 | Text starting and ending with a special character will be emphasized, for | ||
| 3911 | example *bold*, _underlined_ and /italic/. This variable sets the marker | ||
| 3912 | characters, the face to be used by font-lock for highlighting in Org-mode | ||
| 3913 | Emacs buffers, and the HTML tags to be used for this. | ||
| 3914 | Use customize to modify this, or restart Emacs after changing it." | ||
| 3915 | :group 'org-font-lock | ||
| 3916 | :set 'org-set-emph-re | ||
| 3917 | :type '(repeat | ||
| 3918 | (list | ||
| 3919 | (string :tag "Marker character") | ||
| 3920 | (choice | ||
| 3921 | (face :tag "Font-lock-face") | ||
| 3922 | (plist :tag "Face property list")) | ||
| 3923 | (string :tag "HTML start tag") | ||
| 3924 | (string :tag "HTML end tag") | ||
| 3925 | (option (const verbatim))))) | ||
| 3926 | |||
| 3927 | ;;; The faces | ||
| 3928 | |||
| 3929 | (defgroup org-faces nil | ||
| 3930 | "Faces in Org-mode." | ||
| 3931 | :tag "Org Faces" | ||
| 3932 | :group 'org-font-lock) | ||
| 3933 | |||
| 3934 | (defun org-compatible-face (inherits specs) | ||
| 3935 | "Make a compatible face specification. | ||
| 3936 | If INHERITS is an existing face and if the Emacs version supports it, | ||
| 3937 | just inherit the face. If not, use SPECS to define the face. | ||
| 3938 | XEmacs and Emacs 21 do not know about the `min-colors' attribute. | ||
| 3939 | For them we convert a (min-colors 8) entry to a `tty' entry and move it | ||
| 3940 | to the top of the list. The `min-colors' attribute will be removed from | ||
| 3941 | any other entries, and any resulting duplicates will be removed entirely." | ||
| 3942 | (cond | ||
| 3943 | ((and inherits (facep inherits) | ||
| 3944 | (not (featurep 'xemacs)) (> emacs-major-version 22)) | ||
| 3945 | ;; In Emacs 23, we use inheritance where possible. | ||
| 3946 | ;; We only do this in Emacs 23, because only there the outline | ||
| 3947 | ;; faces have been changed to the original org-mode-level-faces. | ||
| 3948 | (list (list t :inherit inherits))) | ||
| 3949 | ((or (featurep 'xemacs) (< emacs-major-version 22)) | ||
| 3950 | ;; These do not understand the `min-colors' attribute. | ||
| 3951 | (let (r e a) | ||
| 3952 | (while (setq e (pop specs)) | ||
| 3953 | (cond | ||
| 3954 | ((memq (car e) '(t default)) (push e r)) | ||
| 3955 | ((setq a (member '(min-colors 8) (car e))) | ||
| 3956 | (nconc r (list (cons (cons '(type tty) (delq (car a) (car e))) | ||
| 3957 | (cdr e))))) | ||
| 3958 | ((setq a (assq 'min-colors (car e))) | ||
| 3959 | (setq e (cons (delq a (car e)) (cdr e))) | ||
| 3960 | (or (assoc (car e) r) (push e r))) | ||
| 3961 | (t (or (assoc (car e) r) (push e r))))) | ||
| 3962 | (nreverse r))) | ||
| 3963 | (t specs))) | ||
| 3964 | (put 'org-compatible-face 'lisp-indent-function 1) | ||
| 3965 | |||
| 3966 | (defface org-hide | ||
| 3967 | '((((background light)) (:foreground "white")) | ||
| 3968 | (((background dark)) (:foreground "black"))) | ||
| 3969 | "Face used to hide leading stars in headlines. | ||
| 3970 | The forground color of this face should be equal to the background | ||
| 3971 | color of the frame." | ||
| 3972 | :group 'org-faces) | ||
| 3973 | |||
| 3974 | (defface org-level-1 ;; font-lock-function-name-face | ||
| 3975 | (org-compatible-face 'outline-1 | ||
| 3976 | '((((class color) (min-colors 88) (background light)) (:foreground "Blue1")) | ||
| 3977 | (((class color) (min-colors 88) (background dark)) (:foreground "LightSkyBlue")) | ||
| 3978 | (((class color) (min-colors 16) (background light)) (:foreground "Blue")) | ||
| 3979 | (((class color) (min-colors 16) (background dark)) (:foreground "LightSkyBlue")) | ||
| 3980 | (((class color) (min-colors 8)) (:foreground "blue" :bold t)) | ||
| 3981 | (t (:bold t)))) | ||
| 3982 | "Face used for level 1 headlines." | ||
| 3983 | :group 'org-faces) | ||
| 3984 | |||
| 3985 | (defface org-level-2 ;; font-lock-variable-name-face | ||
| 3986 | (org-compatible-face 'outline-2 | ||
| 3987 | '((((class color) (min-colors 16) (background light)) (:foreground "DarkGoldenrod")) | ||
| 3988 | (((class color) (min-colors 16) (background dark)) (:foreground "LightGoldenrod")) | ||
| 3989 | (((class color) (min-colors 8) (background light)) (:foreground "yellow")) | ||
| 3990 | (((class color) (min-colors 8) (background dark)) (:foreground "yellow" :bold t)) | ||
| 3991 | (t (:bold t)))) | ||
| 3992 | "Face used for level 2 headlines." | ||
| 3993 | :group 'org-faces) | ||
| 3994 | |||
| 3995 | (defface org-level-3 ;; font-lock-keyword-face | ||
| 3996 | (org-compatible-face 'outline-3 | ||
| 3997 | '((((class color) (min-colors 88) (background light)) (:foreground "Purple")) | ||
| 3998 | (((class color) (min-colors 88) (background dark)) (:foreground "Cyan1")) | ||
| 3999 | (((class color) (min-colors 16) (background light)) (:foreground "Purple")) | ||
| 4000 | (((class color) (min-colors 16) (background dark)) (:foreground "Cyan")) | ||
| 4001 | (((class color) (min-colors 8) (background light)) (:foreground "purple" :bold t)) | ||
| 4002 | (((class color) (min-colors 8) (background dark)) (:foreground "cyan" :bold t)) | ||
| 4003 | (t (:bold t)))) | ||
| 4004 | "Face used for level 3 headlines." | ||
| 4005 | :group 'org-faces) | ||
| 4006 | |||
| 4007 | (defface org-level-4 ;; font-lock-comment-face | ||
| 4008 | (org-compatible-face 'outline-4 | ||
| 4009 | '((((class color) (min-colors 88) (background light)) (:foreground "Firebrick")) | ||
| 4010 | (((class color) (min-colors 88) (background dark)) (:foreground "chocolate1")) | ||
| 4011 | (((class color) (min-colors 16) (background light)) (:foreground "red")) | ||
| 4012 | (((class color) (min-colors 16) (background dark)) (:foreground "red1")) | ||
| 4013 | (((class color) (min-colors 8) (background light)) (:foreground "red" :bold t)) | ||
| 4014 | (((class color) (min-colors 8) (background dark)) (:foreground "red" :bold t)) | ||
| 4015 | (t (:bold t)))) | ||
| 4016 | "Face used for level 4 headlines." | ||
| 4017 | :group 'org-faces) | ||
| 4018 | |||
| 4019 | (defface org-level-5 ;; font-lock-type-face | ||
| 4020 | (org-compatible-face 'outline-5 | ||
| 4021 | '((((class color) (min-colors 16) (background light)) (:foreground "ForestGreen")) | ||
| 4022 | (((class color) (min-colors 16) (background dark)) (:foreground "PaleGreen")) | ||
| 4023 | (((class color) (min-colors 8)) (:foreground "green")))) | ||
| 4024 | "Face used for level 5 headlines." | ||
| 4025 | :group 'org-faces) | ||
| 4026 | |||
| 4027 | (defface org-level-6 ;; font-lock-constant-face | ||
| 4028 | (org-compatible-face 'outline-6 | ||
| 4029 | '((((class color) (min-colors 16) (background light)) (:foreground "CadetBlue")) | ||
| 4030 | (((class color) (min-colors 16) (background dark)) (:foreground "Aquamarine")) | ||
| 4031 | (((class color) (min-colors 8)) (:foreground "magenta")))) | ||
| 4032 | "Face used for level 6 headlines." | ||
| 4033 | :group 'org-faces) | ||
| 4034 | |||
| 4035 | (defface org-level-7 ;; font-lock-builtin-face | ||
| 4036 | (org-compatible-face 'outline-7 | ||
| 4037 | '((((class color) (min-colors 16) (background light)) (:foreground "Orchid")) | ||
| 4038 | (((class color) (min-colors 16) (background dark)) (:foreground "LightSteelBlue")) | ||
| 4039 | (((class color) (min-colors 8)) (:foreground "blue")))) | ||
| 4040 | "Face used for level 7 headlines." | ||
| 4041 | :group 'org-faces) | ||
| 4042 | |||
| 4043 | (defface org-level-8 ;; font-lock-string-face | ||
| 4044 | (org-compatible-face 'outline-8 | ||
| 4045 | '((((class color) (min-colors 16) (background light)) (:foreground "RosyBrown")) | ||
| 4046 | (((class color) (min-colors 16) (background dark)) (:foreground "LightSalmon")) | ||
| 4047 | (((class color) (min-colors 8)) (:foreground "green")))) | ||
| 4048 | "Face used for level 8 headlines." | ||
| 4049 | :group 'org-faces) | ||
| 4050 | |||
| 4051 | (defface org-special-keyword ;; font-lock-string-face | ||
| 4052 | (org-compatible-face nil | ||
| 4053 | '((((class color) (min-colors 16) (background light)) (:foreground "RosyBrown")) | ||
| 4054 | (((class color) (min-colors 16) (background dark)) (:foreground "LightSalmon")) | ||
| 4055 | (t (:italic t)))) | ||
| 4056 | "Face used for special keywords." | ||
| 4057 | :group 'org-faces) | ||
| 4058 | |||
| 4059 | (defface org-drawer ;; font-lock-function-name-face | ||
| 4060 | (org-compatible-face nil | ||
| 4061 | '((((class color) (min-colors 88) (background light)) (:foreground "Blue1")) | ||
| 4062 | (((class color) (min-colors 88) (background dark)) (:foreground "LightSkyBlue")) | ||
| 4063 | (((class color) (min-colors 16) (background light)) (:foreground "Blue")) | ||
| 4064 | (((class color) (min-colors 16) (background dark)) (:foreground "LightSkyBlue")) | ||
| 4065 | (((class color) (min-colors 8)) (:foreground "blue" :bold t)) | ||
| 4066 | (t (:bold t)))) | ||
| 4067 | "Face used for drawers." | ||
| 4068 | :group 'org-faces) | ||
| 4069 | |||
| 4070 | (defface org-property-value nil | ||
| 4071 | "Face used for the value of a property." | ||
| 4072 | :group 'org-faces) | ||
| 4073 | |||
| 4074 | (defface org-column | ||
| 4075 | (org-compatible-face nil | ||
| 4076 | '((((class color) (min-colors 16) (background light)) | ||
| 4077 | (:background "grey90")) | ||
| 4078 | (((class color) (min-colors 16) (background dark)) | ||
| 4079 | (:background "grey30")) | ||
| 4080 | (((class color) (min-colors 8)) | ||
| 4081 | (:background "cyan" :foreground "black")) | ||
| 4082 | (t (:inverse-video t)))) | ||
| 4083 | "Face for column display of entry properties." | ||
| 4084 | :group 'org-faces) | ||
| 4085 | |||
| 4086 | (when (fboundp 'set-face-attribute) | ||
| 4087 | ;; Make sure that a fixed-width face is used when we have a column table. | ||
| 4088 | (set-face-attribute 'org-column nil | ||
| 4089 | :height (face-attribute 'default :height) | ||
| 4090 | :family (face-attribute 'default :family))) | ||
| 4091 | |||
| 4092 | (defface org-warning | ||
| 4093 | (org-compatible-face 'font-lock-warning-face | ||
| 4094 | '((((class color) (min-colors 16) (background light)) (:foreground "Red1" :bold t)) | ||
| 4095 | (((class color) (min-colors 16) (background dark)) (:foreground "Pink" :bold t)) | ||
| 4096 | (((class color) (min-colors 8) (background light)) (:foreground "red" :bold t)) | ||
| 4097 | (((class color) (min-colors 8) (background dark)) (:foreground "red" :bold t)) | ||
| 4098 | (t (:bold t)))) | ||
| 4099 | "Face for deadlines and TODO keywords." | ||
| 4100 | :group 'org-faces) | ||
| 4101 | |||
| 4102 | (defface org-archived ; similar to shadow | ||
| 4103 | (org-compatible-face 'shadow | ||
| 4104 | '((((class color grayscale) (min-colors 88) (background light)) | ||
| 4105 | (:foreground "grey50")) | ||
| 4106 | (((class color grayscale) (min-colors 88) (background dark)) | ||
| 4107 | (:foreground "grey70")) | ||
| 4108 | (((class color) (min-colors 8) (background light)) | ||
| 4109 | (:foreground "green")) | ||
| 4110 | (((class color) (min-colors 8) (background dark)) | ||
| 4111 | (:foreground "yellow")))) | ||
| 4112 | "Face for headline with the ARCHIVE tag." | ||
| 4113 | :group 'org-faces) | ||
| 4114 | |||
| 4115 | (defface org-link | ||
| 4116 | '((((class color) (background light)) (:foreground "Purple" :underline t)) | ||
| 4117 | (((class color) (background dark)) (:foreground "Cyan" :underline t)) | ||
| 4118 | (t (:underline t))) | ||
| 4119 | "Face for links." | ||
| 4120 | :group 'org-faces) | ||
| 4121 | |||
| 4122 | (defface org-ellipsis | ||
| 4123 | '((((class color) (background light)) (:foreground "DarkGoldenrod" :underline t)) | ||
| 4124 | (((class color) (background dark)) (:foreground "LightGoldenrod" :underline t)) | ||
| 4125 | (t (:strike-through t))) | ||
| 4126 | "Face for the ellipsis in folded text." | ||
| 4127 | :group 'org-faces) | ||
| 4128 | |||
| 4129 | (defface org-target | ||
| 4130 | '((((class color) (background light)) (:underline t)) | ||
| 4131 | (((class color) (background dark)) (:underline t)) | ||
| 4132 | (t (:underline t))) | ||
| 4133 | "Face for links." | ||
| 4134 | :group 'org-faces) | ||
| 4135 | |||
| 4136 | (defface org-date | ||
| 4137 | '((((class color) (background light)) (:foreground "Purple" :underline t)) | ||
| 4138 | (((class color) (background dark)) (:foreground "Cyan" :underline t)) | ||
| 4139 | (t (:underline t))) | ||
| 4140 | "Face for links." | ||
| 4141 | :group 'org-faces) | ||
| 4142 | |||
| 4143 | (defface org-sexp-date | ||
| 4144 | '((((class color) (background light)) (:foreground "Purple")) | ||
| 4145 | (((class color) (background dark)) (:foreground "Cyan")) | ||
| 4146 | (t (:underline t))) | ||
| 4147 | "Face for links." | ||
| 4148 | :group 'org-faces) | ||
| 4149 | |||
| 4150 | (defface org-tag | ||
| 4151 | '((t (:bold t))) | ||
| 4152 | "Face for tags." | ||
| 4153 | :group 'org-faces) | ||
| 4154 | |||
| 4155 | (defface org-todo ; font-lock-warning-face | ||
| 4156 | (org-compatible-face nil | ||
| 4157 | '((((class color) (min-colors 16) (background light)) (:foreground "Red1" :bold t)) | ||
| 4158 | (((class color) (min-colors 16) (background dark)) (:foreground "Pink" :bold t)) | ||
| 4159 | (((class color) (min-colors 8) (background light)) (:foreground "red" :bold t)) | ||
| 4160 | (((class color) (min-colors 8) (background dark)) (:foreground "red" :bold t)) | ||
| 4161 | (t (:inverse-video t :bold t)))) | ||
| 4162 | "Face for TODO keywords." | ||
| 4163 | :group 'org-faces) | ||
| 4164 | |||
| 4165 | (defface org-done ;; font-lock-type-face | ||
| 4166 | (org-compatible-face nil | ||
| 4167 | '((((class color) (min-colors 16) (background light)) (:foreground "ForestGreen" :bold t)) | ||
| 4168 | (((class color) (min-colors 16) (background dark)) (:foreground "PaleGreen" :bold t)) | ||
| 4169 | (((class color) (min-colors 8)) (:foreground "green")) | ||
| 4170 | (t (:bold t)))) | ||
| 4171 | "Face used for todo keywords that indicate DONE items." | ||
| 4172 | :group 'org-faces) | ||
| 4173 | |||
| 4174 | (defface org-headline-done ;; font-lock-string-face | ||
| 4175 | (org-compatible-face nil | ||
| 4176 | '((((class color) (min-colors 16) (background light)) (:foreground "RosyBrown")) | ||
| 4177 | (((class color) (min-colors 16) (background dark)) (:foreground "LightSalmon")) | ||
| 4178 | (((class color) (min-colors 8) (background light)) (:bold nil)))) | ||
| 4179 | "Face used to indicate that a headline is DONE. | ||
| 4180 | This face is only used if `org-fontify-done-headline' is set. If applies | ||
| 4181 | to the part of the headline after the DONE keyword." | ||
| 4182 | :group 'org-faces) | ||
| 4183 | |||
| 4184 | (defcustom org-todo-keyword-faces nil | ||
| 4185 | "Faces for specific TODO keywords. | ||
| 4186 | This is a list of cons cells, with TODO keywords in the car | ||
| 4187 | and faces in the cdr. The face can be a symbol, or a property | ||
| 4188 | list of attributes, like (:foreground \"blue\" :weight bold :underline t)." | ||
| 4189 | :group 'org-faces | ||
| 4190 | :group 'org-todo | ||
| 4191 | :type '(repeat | ||
| 4192 | (cons | ||
| 4193 | (string :tag "keyword") | ||
| 4194 | (sexp :tag "face")))) | ||
| 4195 | |||
| 4196 | (defface org-table ;; font-lock-function-name-face | ||
| 4197 | (org-compatible-face nil | ||
| 4198 | '((((class color) (min-colors 88) (background light)) (:foreground "Blue1")) | ||
| 4199 | (((class color) (min-colors 88) (background dark)) (:foreground "LightSkyBlue")) | ||
| 4200 | (((class color) (min-colors 16) (background light)) (:foreground "Blue")) | ||
| 4201 | (((class color) (min-colors 16) (background dark)) (:foreground "LightSkyBlue")) | ||
| 4202 | (((class color) (min-colors 8) (background light)) (:foreground "blue")) | ||
| 4203 | (((class color) (min-colors 8) (background dark))))) | ||
| 4204 | "Face used for tables." | ||
| 4205 | :group 'org-faces) | ||
| 4206 | |||
| 4207 | (defface org-formula | ||
| 4208 | (org-compatible-face nil | ||
| 4209 | '((((class color) (min-colors 88) (background light)) (:foreground "Firebrick")) | ||
| 4210 | (((class color) (min-colors 88) (background dark)) (:foreground "chocolate1")) | ||
| 4211 | (((class color) (min-colors 8) (background light)) (:foreground "red")) | ||
| 4212 | (((class color) (min-colors 8) (background dark)) (:foreground "red")) | ||
| 4213 | (t (:bold t :italic t)))) | ||
| 4214 | "Face for formulas." | ||
| 4215 | :group 'org-faces) | ||
| 4216 | |||
| 4217 | (defface org-code | ||
| 4218 | (org-compatible-face nil | ||
| 4219 | '((((class color grayscale) (min-colors 88) (background light)) | ||
| 4220 | (:foreground "grey50")) | ||
| 4221 | (((class color grayscale) (min-colors 88) (background dark)) | ||
| 4222 | (:foreground "grey70")) | ||
| 4223 | (((class color) (min-colors 8) (background light)) | ||
| 4224 | (:foreground "green")) | ||
| 4225 | (((class color) (min-colors 8) (background dark)) | ||
| 4226 | (:foreground "yellow")))) | ||
| 4227 | "Face for fixed-with text like code snippets." | ||
| 4228 | :group 'org-faces | ||
| 4229 | :version "22.1") | ||
| 4230 | |||
| 4231 | (defface org-verbatim | ||
| 4232 | (org-compatible-face nil | ||
| 4233 | '((((class color grayscale) (min-colors 88) (background light)) | ||
| 4234 | (:foreground "grey50" :underline t)) | ||
| 4235 | (((class color grayscale) (min-colors 88) (background dark)) | ||
| 4236 | (:foreground "grey70" :underline t)) | ||
| 4237 | (((class color) (min-colors 8) (background light)) | ||
| 4238 | (:foreground "green" :underline t)) | ||
| 4239 | (((class color) (min-colors 8) (background dark)) | ||
| 4240 | (:foreground "yellow" :underline t)))) | ||
| 4241 | "Face for fixed-with text like code snippets." | ||
| 4242 | :group 'org-faces | ||
| 4243 | :version "22.1") | ||
| 4244 | |||
| 4245 | (defface org-agenda-structure ;; font-lock-function-name-face | ||
| 4246 | (org-compatible-face nil | ||
| 4247 | '((((class color) (min-colors 88) (background light)) (:foreground "Blue1")) | ||
| 4248 | (((class color) (min-colors 88) (background dark)) (:foreground "LightSkyBlue")) | ||
| 4249 | (((class color) (min-colors 16) (background light)) (:foreground "Blue")) | ||
| 4250 | (((class color) (min-colors 16) (background dark)) (:foreground "LightSkyBlue")) | ||
| 4251 | (((class color) (min-colors 8)) (:foreground "blue" :bold t)) | ||
| 4252 | (t (:bold t)))) | ||
| 4253 | "Face used in agenda for captions and dates." | ||
| 4254 | :group 'org-faces) | ||
| 4255 | |||
| 4256 | (defface org-scheduled-today | ||
| 4257 | (org-compatible-face nil | ||
| 4258 | '((((class color) (min-colors 88) (background light)) (:foreground "DarkGreen")) | ||
| 4259 | (((class color) (min-colors 88) (background dark)) (:foreground "PaleGreen")) | ||
| 4260 | (((class color) (min-colors 8)) (:foreground "green")) | ||
| 4261 | (t (:bold t :italic t)))) | ||
| 4262 | "Face for items scheduled for a certain day." | ||
| 4263 | :group 'org-faces) | ||
| 4264 | |||
| 4265 | (defface org-scheduled-previously | ||
| 4266 | (org-compatible-face nil | ||
| 4267 | '((((class color) (min-colors 88) (background light)) (:foreground "Firebrick")) | ||
| 4268 | (((class color) (min-colors 88) (background dark)) (:foreground "chocolate1")) | ||
| 4269 | (((class color) (min-colors 8) (background light)) (:foreground "red")) | ||
| 4270 | (((class color) (min-colors 8) (background dark)) (:foreground "red" :bold t)) | ||
| 4271 | (t (:bold t)))) | ||
| 4272 | "Face for items scheduled previously, and not yet done." | ||
| 4273 | :group 'org-faces) | ||
| 4274 | |||
| 4275 | (defface org-upcoming-deadline | ||
| 4276 | (org-compatible-face nil | ||
| 4277 | '((((class color) (min-colors 88) (background light)) (:foreground "Firebrick")) | ||
| 4278 | (((class color) (min-colors 88) (background dark)) (:foreground "chocolate1")) | ||
| 4279 | (((class color) (min-colors 8) (background light)) (:foreground "red")) | ||
| 4280 | (((class color) (min-colors 8) (background dark)) (:foreground "red" :bold t)) | ||
| 4281 | (t (:bold t)))) | ||
| 4282 | "Face for items scheduled previously, and not yet done." | ||
| 4283 | :group 'org-faces) | ||
| 4284 | |||
| 4285 | (defcustom org-agenda-deadline-faces | ||
| 4286 | '((1.0 . org-warning) | ||
| 4287 | (0.5 . org-upcoming-deadline) | ||
| 4288 | (0.0 . default)) | ||
| 4289 | "Faces for showing deadlines in the agenda. | ||
| 4290 | This is a list of cons cells. The cdr of each cell is a face to be used, | ||
| 4291 | and it can also just be like '(:foreground \"yellow\"). | ||
| 4292 | Each car is a fraction of the head-warning time that must have passed for | ||
| 4293 | this the face in the cdr to be used for display. The numbers must be | ||
| 4294 | given in descending order. The head-warning time is normally taken | ||
| 4295 | from `org-deadline-warning-days', but can also be specified in the deadline | ||
| 4296 | timestamp itself, like this: | ||
| 4297 | |||
| 4298 | DEADLINE: <2007-08-13 Mon -8d> | ||
| 4299 | |||
| 4300 | You may use d for days, w for weeks, m for months and y for years. Months | ||
| 4301 | and years will only be treated in an approximate fashion (30.4 days for a | ||
| 4302 | month and 365.24 days for a year)." | ||
| 4303 | :group 'org-faces | ||
| 4304 | :group 'org-agenda-daily/weekly | ||
| 4305 | :type '(repeat | ||
| 4306 | (cons | ||
| 4307 | (number :tag "Fraction of head-warning time passed") | ||
| 4308 | (sexp :tag "Face")))) | ||
| 4309 | |||
| 4310 | ;; FIXME: this is not a good face yet. | ||
| 4311 | (defface org-agenda-restriction-lock | ||
| 4312 | (org-compatible-face nil | ||
| 4313 | '((((class color) (min-colors 88) (background light)) (:background "yellow1")) | ||
| 4314 | (((class color) (min-colors 88) (background dark)) (:background "skyblue4")) | ||
| 4315 | (((class color) (min-colors 16) (background light)) (:background "yellow1")) | ||
| 4316 | (((class color) (min-colors 16) (background dark)) (:background "skyblue4")) | ||
| 4317 | (((class color) (min-colors 8)) (:background "cyan" :foreground "black")) | ||
| 4318 | (t (:inverse-video t)))) | ||
| 4319 | "Face for showing the agenda restriction lock." | ||
| 4320 | :group 'org-faces) | ||
| 4321 | |||
| 4322 | (defface org-time-grid ;; font-lock-variable-name-face | ||
| 4323 | (org-compatible-face nil | ||
| 4324 | '((((class color) (min-colors 16) (background light)) (:foreground "DarkGoldenrod")) | ||
| 4325 | (((class color) (min-colors 16) (background dark)) (:foreground "LightGoldenrod")) | ||
| 4326 | (((class color) (min-colors 8)) (:foreground "yellow" :weight light)))) | ||
| 4327 | "Face used for time grids." | ||
| 4328 | :group 'org-faces) | ||
| 4329 | |||
| 4330 | (defconst org-level-faces | ||
| 4331 | '(org-level-1 org-level-2 org-level-3 org-level-4 | ||
| 4332 | org-level-5 org-level-6 org-level-7 org-level-8 | ||
| 4333 | )) | ||
| 4334 | |||
| 4335 | (defcustom org-n-level-faces (length org-level-faces) | ||
| 4336 | "The number of different faces to be used for headlines. | ||
| 4337 | Org-mode defines 8 different headline faces, so this can be at most 8. | ||
| 4338 | If it is less than 8, the level-1 face gets re-used for level N+1 etc." | ||
| 4339 | :type 'number | ||
| 4340 | :group 'org-faces) | ||
| 4341 | |||
| 4342 | ;;; Functions and variables from ther packages | ||
| 4343 | ;; Declared here to avoid compiler warnings | ||
| 4344 | |||
| 4345 | (eval-and-compile | ||
| 4346 | (unless (fboundp 'declare-function) | ||
| 4347 | (defmacro declare-function (fn file &optional arglist fileonly)))) | ||
| 4348 | |||
| 4349 | ;; XEmacs only | ||
| 4350 | (defvar outline-mode-menu-heading) | ||
| 4351 | (defvar outline-mode-menu-show) | ||
| 4352 | (defvar outline-mode-menu-hide) | ||
| 4353 | (defvar zmacs-regions) ; XEmacs regions | ||
| 4354 | |||
| 4355 | ;; Emacs only | ||
| 4356 | (defvar mark-active) | ||
| 4357 | |||
| 4358 | ;; Various packages | ||
| 4359 | ;; FIXME: get the argument lists for the UNKNOWN stuff | ||
| 4360 | (declare-function add-to-diary-list "diary-lib" | ||
| 4361 | (date string specifier &optional marker globcolor literal)) | ||
| 4362 | (declare-function table--at-cell-p "table" (position &optional object at-column)) | ||
| 4363 | (declare-function Info-find-node "info" (filename nodename &optional no-going-back)) | ||
| 4364 | (declare-function bbdb "ext:bbdb-com" (string elidep)) | ||
| 4365 | (declare-function bbdb-company "ext:bbdb-com" (string elidep)) | ||
| 4366 | (declare-function bbdb-current-record "ext:bbdb-com" (&optional planning-on-modifying)) | ||
| 4367 | (declare-function bbdb-name "ext:bbdb-com" (string elidep)) | ||
| 4368 | (declare-function bbdb-record-getprop "ext:bbdb" (record property)) | ||
| 4369 | (declare-function bbdb-record-name "ext:bbdb" (record)) | ||
| 4370 | (declare-function bibtex-beginning-of-entry "bibtex" ()) | ||
| 4371 | (declare-function bibtex-generate-autokey "bibtex" ()) | ||
| 4372 | (declare-function bibtex-parse-entry "bibtex" (&optional content)) | ||
| 4373 | (declare-function bibtex-url "bibtex" (&optional pos no-browse)) | ||
| 4374 | (defvar calc-embedded-close-formula) | ||
| 4375 | (defvar calc-embedded-open-formula) | ||
| 4376 | (declare-function calendar-astro-date-string "cal-julian" (&optional date)) | ||
| 4377 | (declare-function calendar-bahai-date-string "cal-bahai" (&optional date)) | ||
| 4378 | (declare-function calendar-check-holidays "holidays" (date)) | ||
| 4379 | (declare-function calendar-chinese-date-string "cal-china" (&optional date)) | ||
| 4380 | (declare-function calendar-coptic-date-string "cal-coptic" (&optional date)) | ||
| 4381 | (declare-function calendar-ethiopic-date-string "cal-coptic" (&optional date)) | ||
| 4382 | (declare-function calendar-forward-day "cal-move" (arg)) | ||
| 4383 | (declare-function calendar-french-date-string "cal-french" (&optional date)) | ||
| 4384 | (declare-function calendar-goto-date "cal-move" (date)) | ||
| 4385 | (declare-function calendar-goto-today "cal-move" ()) | ||
| 4386 | (declare-function calendar-hebrew-date-string "cal-hebrew" (&optional date)) | ||
| 4387 | (declare-function calendar-islamic-date-string "cal-islam" (&optional date)) | ||
| 4388 | (declare-function calendar-iso-date-string "cal-iso" (&optional date)) | ||
| 4389 | (declare-function calendar-julian-date-string "cal-julian" (&optional date)) | ||
| 4390 | (declare-function calendar-mayan-date-string "cal-mayan" (&optional date)) | ||
| 4391 | (declare-function calendar-persian-date-string "cal-persia" (&optional date)) | ||
| 4392 | (defvar calendar-mode-map) | ||
| 4393 | (defvar original-date) ; dynamically scoped in calendar.el does scope this | ||
| 4394 | (declare-function cdlatex-tab "ext:cdlatex" ()) | ||
| 4395 | (declare-function dired-get-filename "dired" (&optional localp no-error-if-not-filep)) | ||
| 4396 | (declare-function elmo-folder-exists-p "ext:elmo" (folder) t) | ||
| 4397 | (declare-function elmo-message-entity-field "ext:elmo-msgdb" (entity field &optional type)) | ||
| 4398 | (declare-function elmo-message-field "ext:elmo" (folder number field &optional type) t) | ||
| 4399 | (declare-function elmo-msgdb-overview-get-entity "ext:elmo" (&rest unknown) t) | ||
| 4400 | (defvar font-lock-unfontify-region-function) | ||
| 4401 | (declare-function gnus-article-show-summary "gnus-art" ()) | ||
| 4402 | (declare-function gnus-summary-last-subject "gnus-sum" ()) | ||
| 4403 | (defvar gnus-other-frame-object) | ||
| 4404 | (defvar gnus-group-name) | ||
| 4405 | (defvar gnus-article-current) | ||
| 4406 | (defvar Info-current-file) | ||
| 4407 | (defvar Info-current-node) | ||
| 4408 | (declare-function mh-display-msg "mh-show" (msg-num folder-name)) | ||
| 4409 | (declare-function mh-find-path "mh-utils" ()) | ||
| 4410 | (declare-function mh-get-header-field "mh-utils" (field)) | ||
| 4411 | (declare-function mh-get-msg-num "mh-utils" (error-if-no-message)) | ||
| 4412 | (declare-function mh-header-display "mh-show" ()) | ||
| 4413 | (declare-function mh-index-previous-folder "mh-search" ()) | ||
| 4414 | (declare-function mh-normalize-folder-name "mh-utils" (folder &optional empty-string-okay dont-remove-trailing-slash return-nil-if-folder-empty)) | ||
| 4415 | (declare-function mh-search "mh-search" (folder search-regexp &optional redo-search-flag window-config)) | ||
| 4416 | (declare-function mh-search-choose "mh-search" (&optional searcher)) | ||
| 4417 | (declare-function mh-show "mh-show" (&optional message redisplay-flag)) | ||
| 4418 | (declare-function mh-show-buffer-message-number "mh-comp" (&optional buffer)) | ||
| 4419 | (declare-function mh-show-header-display "mh-show" t t) | ||
| 4420 | (declare-function mh-show-msg "mh-show" (msg)) | ||
| 4421 | (declare-function mh-show-show "mh-show" t t) | ||
| 4422 | (declare-function mh-visit-folder "mh-folder" (folder &optional range index-data)) | ||
| 4423 | (defvar mh-progs) | ||
| 4424 | (defvar mh-current-folder) | ||
| 4425 | (defvar mh-show-folder-buffer) | ||
| 4426 | (defvar mh-index-folder) | ||
| 4427 | (defvar mh-searcher) | ||
| 4428 | (declare-function org-export-latex-cleaned-string "org-export-latex" ()) | ||
| 4429 | (declare-function parse-time-string "parse-time" (string)) | ||
| 4430 | (declare-function remember "remember" (&optional initial)) | ||
| 4431 | (declare-function remember-buffer-desc "remember" ()) | ||
| 4432 | (declare-function remember-finalize "remember" ()) | ||
| 4433 | (defvar remember-save-after-remembering) | ||
| 4434 | (defvar remember-data-file) | ||
| 4435 | (defvar remember-register) | ||
| 4436 | (defvar remember-buffer) | ||
| 4437 | (defvar remember-handler-functions) | ||
| 4438 | (defvar remember-annotation-functions) | ||
| 4439 | (declare-function rmail-narrow-to-non-pruned-header "rmail" ()) | ||
| 4440 | (declare-function rmail-show-message "rmail" (&optional n no-summary)) | ||
| 4441 | (declare-function rmail-what-message "rmail" ()) | ||
| 4442 | (defvar rmail-current-message) | ||
| 4443 | (defvar texmathp-why) | ||
| 4444 | (declare-function vm-beginning-of-message "ext:vm-page" ()) | ||
| 4445 | (declare-function vm-follow-summary-cursor "ext:vm-motion" ()) | ||
| 4446 | (declare-function vm-get-header-contents "ext:vm-summary" (message header-name-regexp &optional clump-sep)) | ||
| 4447 | (declare-function vm-isearch-narrow "ext:vm-search" ()) | ||
| 4448 | (declare-function vm-isearch-update "ext:vm-search" ()) | ||
| 4449 | (declare-function vm-select-folder-buffer "ext:vm-macro" ()) | ||
| 4450 | (declare-function vm-su-message-id "ext:vm-summary" (m)) | ||
| 4451 | (declare-function vm-su-subject "ext:vm-summary" (m)) | ||
| 4452 | (declare-function vm-summarize "ext:vm-summary" (&optional display raise)) | ||
| 4453 | (defvar vm-message-pointer) | ||
| 4454 | (defvar vm-folder-directory) | ||
| 4455 | (defvar w3m-current-url) | ||
| 4456 | (defvar w3m-current-title) | ||
| 4457 | ;; backward compatibility to old version of wl | ||
| 4458 | (declare-function wl-summary-buffer-msgdb "ext:wl-folder" (&rest unknown) t) | ||
| 4459 | (declare-function wl-folder-get-elmo-folder "ext:wl-folder" (entity &optional no-cache)) | ||
| 4460 | (declare-function wl-summary-goto-folder-subr "ext:wl-summary" (&optional name scan-type other-window sticky interactive scoring force-exit)) | ||
| 4461 | (declare-function wl-summary-jump-to-msg-by-message-id "ext:wl-summary" (&optional id)) | ||
| 4462 | (declare-function wl-summary-line-from "ext:wl-summary" ()) | ||
| 4463 | (declare-function wl-summary-line-subject "ext:wl-summary" ()) | ||
| 4464 | (declare-function wl-summary-message-number "ext:wl-summary" ()) | ||
| 4465 | (declare-function wl-summary-redisplay "ext:wl-summary" (&optional arg)) | ||
| 4466 | (defvar wl-summary-buffer-elmo-folder) | ||
| 4467 | (defvar wl-summary-buffer-folder-name) | ||
| 4468 | (declare-function speedbar-line-directory "speedbar" (&optional depth)) | ||
| 4469 | |||
| 4470 | (defvar org-latex-regexps) | ||
| 4471 | (defvar constants-unit-system) | ||
| 4472 | |||
| 4473 | ;;; Variables for pre-computed regular expressions, all buffer local | ||
| 4474 | |||
| 4475 | (defvar org-drawer-regexp nil | ||
| 4476 | "Matches first line of a hidden block.") | ||
| 4477 | (make-variable-buffer-local 'org-drawer-regexp) | ||
| 4478 | (defvar org-todo-regexp nil | ||
| 4479 | "Matches any of the TODO state keywords.") | ||
| 4480 | (make-variable-buffer-local 'org-todo-regexp) | ||
| 4481 | (defvar org-not-done-regexp nil | ||
| 4482 | "Matches any of the TODO state keywords except the last one.") | ||
| 4483 | (make-variable-buffer-local 'org-not-done-regexp) | ||
| 4484 | (defvar org-todo-line-regexp nil | ||
| 4485 | "Matches a headline and puts TODO state into group 2 if present.") | ||
| 4486 | (make-variable-buffer-local 'org-todo-line-regexp) | ||
| 4487 | (defvar org-complex-heading-regexp nil | ||
| 4488 | "Matches a headline and puts everything into groups: | ||
| 4489 | group 1: the stars | ||
| 4490 | group 2: The todo keyword, maybe | ||
| 4491 | group 3: Priority cookie | ||
| 4492 | group 4: True headline | ||
| 4493 | group 5: Tags") | ||
| 4494 | (make-variable-buffer-local 'org-complex-heading-regexp) | ||
| 4495 | (defvar org-todo-line-tags-regexp nil | ||
| 4496 | "Matches a headline and puts TODO state into group 2 if present. | ||
| 4497 | Also put tags into group 4 if tags are present.") | ||
| 4498 | (make-variable-buffer-local 'org-todo-line-tags-regexp) | ||
| 4499 | (defvar org-nl-done-regexp nil | ||
| 4500 | "Matches newline followed by a headline with the DONE keyword.") | ||
| 4501 | (make-variable-buffer-local 'org-nl-done-regexp) | ||
| 4502 | (defvar org-looking-at-done-regexp nil | ||
| 4503 | "Matches the DONE keyword a point.") | ||
| 4504 | (make-variable-buffer-local 'org-looking-at-done-regexp) | ||
| 4505 | (defvar org-ds-keyword-length 12 | ||
| 4506 | "Maximum length of the Deadline and SCHEDULED keywords.") | ||
| 4507 | (make-variable-buffer-local 'org-ds-keyword-length) | ||
| 4508 | (defvar org-deadline-regexp nil | ||
| 4509 | "Matches the DEADLINE keyword.") | ||
| 4510 | (make-variable-buffer-local 'org-deadline-regexp) | ||
| 4511 | (defvar org-deadline-time-regexp nil | ||
| 4512 | "Matches the DEADLINE keyword together with a time stamp.") | ||
| 4513 | (make-variable-buffer-local 'org-deadline-time-regexp) | ||
| 4514 | (defvar org-deadline-line-regexp nil | ||
| 4515 | "Matches the DEADLINE keyword and the rest of the line.") | ||
| 4516 | (make-variable-buffer-local 'org-deadline-line-regexp) | ||
| 4517 | (defvar org-scheduled-regexp nil | ||
| 4518 | "Matches the SCHEDULED keyword.") | ||
| 4519 | (make-variable-buffer-local 'org-scheduled-regexp) | ||
| 4520 | (defvar org-scheduled-time-regexp nil | ||
| 4521 | "Matches the SCHEDULED keyword together with a time stamp.") | ||
| 4522 | (make-variable-buffer-local 'org-scheduled-time-regexp) | ||
| 4523 | (defvar org-closed-time-regexp nil | ||
| 4524 | "Matches the CLOSED keyword together with a time stamp.") | ||
| 4525 | (make-variable-buffer-local 'org-closed-time-regexp) | ||
| 4526 | |||
| 4527 | (defvar org-keyword-time-regexp nil | ||
| 4528 | "Matches any of the 4 keywords, together with the time stamp.") | ||
| 4529 | (make-variable-buffer-local 'org-keyword-time-regexp) | ||
| 4530 | (defvar org-keyword-time-not-clock-regexp nil | ||
| 4531 | "Matches any of the 3 keywords, together with the time stamp.") | ||
| 4532 | (make-variable-buffer-local 'org-keyword-time-not-clock-regexp) | ||
| 4533 | (defvar org-maybe-keyword-time-regexp nil | ||
| 4534 | "Matches a timestamp, possibly preceeded by a keyword.") | ||
| 4535 | (make-variable-buffer-local 'org-maybe-keyword-time-regexp) | ||
| 4536 | (defvar org-planning-or-clock-line-re nil | ||
| 4537 | "Matches a line with planning or clock info.") | ||
| 4538 | (make-variable-buffer-local 'org-planning-or-clock-line-re) | ||
| 4539 | |||
| 4540 | (defconst org-rm-props '(invisible t face t keymap t intangible t mouse-face t | ||
| 4541 | rear-nonsticky t mouse-map t fontified t) | ||
| 4542 | "Properties to remove when a string without properties is wanted.") | ||
| 4543 | |||
| 4544 | (defsubst org-match-string-no-properties (num &optional string) | ||
| 4545 | (if (featurep 'xemacs) | ||
| 4546 | (let ((s (match-string num string))) | ||
| 4547 | (remove-text-properties 0 (length s) org-rm-props s) | ||
| 4548 | s) | ||
| 4549 | (match-string-no-properties num string))) | ||
| 4550 | |||
| 4551 | (defsubst org-no-properties (s) | ||
| 4552 | (if (fboundp 'set-text-properties) | ||
| 4553 | (set-text-properties 0 (length s) nil s) | ||
| 4554 | (remove-text-properties 0 (length s) org-rm-props s)) | ||
| 4555 | s) | ||
| 4556 | |||
| 4557 | (defsubst org-get-alist-option (option key) | ||
| 4558 | (cond ((eq key t) t) | ||
| 4559 | ((eq option t) t) | ||
| 4560 | ((assoc key option) (cdr (assoc key option))) | ||
| 4561 | (t (cdr (assq 'default option))))) | ||
| 4562 | |||
| 4563 | (defsubst org-inhibit-invisibility () | ||
| 4564 | "Modified `buffer-invisibility-spec' for Emacs 21. | ||
| 4565 | Some ops with invisible text do not work correctly on Emacs 21. For these | ||
| 4566 | we turn off invisibility temporarily. Use this in a `let' form." | ||
| 4567 | (if (< emacs-major-version 22) nil buffer-invisibility-spec)) | ||
| 4568 | |||
| 4569 | (defsubst org-set-local (var value) | ||
| 4570 | "Make VAR local in current buffer and set it to VALUE." | ||
| 4571 | (set (make-variable-buffer-local var) value)) | ||
| 4572 | |||
| 4573 | (defsubst org-mode-p () | ||
| 4574 | "Check if the current buffer is in Org-mode." | ||
| 4575 | (eq major-mode 'org-mode)) | ||
| 4576 | |||
| 4577 | (defsubst org-last (list) | ||
| 4578 | "Return the last element of LIST." | ||
| 4579 | (car (last list))) | ||
| 4580 | |||
| 4581 | (defun org-let (list &rest body) | ||
| 4582 | (eval (cons 'let (cons list body)))) | ||
| 4583 | (put 'org-let 'lisp-indent-function 1) | ||
| 4584 | |||
| 4585 | (defun org-let2 (list1 list2 &rest body) | ||
| 4586 | (eval (cons 'let (cons list1 (list (cons 'let (cons list2 body))))))) | ||
| 4587 | (put 'org-let2 'lisp-indent-function 2) | ||
| 4588 | (defconst org-startup-options | ||
| 4589 | '(("fold" org-startup-folded t) | ||
| 4590 | ("overview" org-startup-folded t) | ||
| 4591 | ("nofold" org-startup-folded nil) | ||
| 4592 | ("showall" org-startup-folded nil) | ||
| 4593 | ("content" org-startup-folded content) | ||
| 4594 | ("hidestars" org-hide-leading-stars t) | ||
| 4595 | ("showstars" org-hide-leading-stars nil) | ||
| 4596 | ("odd" org-odd-levels-only t) | ||
| 4597 | ("oddeven" org-odd-levels-only nil) | ||
| 4598 | ("align" org-startup-align-all-tables t) | ||
| 4599 | ("noalign" org-startup-align-all-tables nil) | ||
| 4600 | ("customtime" org-display-custom-times t) | ||
| 4601 | ("logdone" org-log-done time) | ||
| 4602 | ("lognotedone" org-log-done note) | ||
| 4603 | ("nologdone" org-log-done nil) | ||
| 4604 | ("lognoteclock-out" org-log-note-clock-out t) | ||
| 4605 | ("nolognoteclock-out" org-log-note-clock-out nil) | ||
| 4606 | ("logrepeat" org-log-repeat state) | ||
| 4607 | ("lognoterepeat" org-log-repeat note) | ||
| 4608 | ("nologrepeat" org-log-repeat nil) | ||
| 4609 | ("constcgs" constants-unit-system cgs) | ||
| 4610 | ("constSI" constants-unit-system SI)) | ||
| 4611 | "Variable associated with STARTUP options for org-mode. | ||
| 4612 | Each element is a list of three items: The startup options as written | ||
| 4613 | in the #+STARTUP line, the corresponding variable, and the value to | ||
| 4614 | set this variable to if the option is found. An optional forth element PUSH | ||
| 4615 | means to push this value onto the list in the variable.") | ||
| 4616 | |||
| 4617 | (defun org-set-regexps-and-options () | ||
| 4618 | "Precompute regular expressions for current buffer." | ||
| 4619 | (when (org-mode-p) | ||
| 4620 | (org-set-local 'org-todo-kwd-alist nil) | ||
| 4621 | (org-set-local 'org-todo-key-alist nil) | ||
| 4622 | (org-set-local 'org-todo-key-trigger nil) | ||
| 4623 | (org-set-local 'org-todo-keywords-1 nil) | ||
| 4624 | (org-set-local 'org-done-keywords nil) | ||
| 4625 | (org-set-local 'org-todo-heads nil) | ||
| 4626 | (org-set-local 'org-todo-sets nil) | ||
| 4627 | (org-set-local 'org-todo-log-states nil) | ||
| 4628 | (let ((re (org-make-options-regexp | ||
| 4629 | '("CATEGORY" "SEQ_TODO" "TYP_TODO" "TODO" "COLUMNS" | ||
| 4630 | "STARTUP" "ARCHIVE" "TAGS" "LINK" "PRIORITIES" | ||
| 4631 | "CONSTANTS" "PROPERTY" "DRAWERS"))) | ||
| 4632 | (splitre "[ \t]+") | ||
| 4633 | kwds kws0 kwsa key log value cat arch tags const links hw dws | ||
| 4634 | tail sep kws1 prio props drawers) | ||
| 4635 | (save-excursion | ||
| 4636 | (save-restriction | ||
| 4637 | (widen) | ||
| 4638 | (goto-char (point-min)) | ||
| 4639 | (while (re-search-forward re nil t) | ||
| 4640 | (setq key (match-string 1) value (org-match-string-no-properties 2)) | ||
| 4641 | (cond | ||
| 4642 | ((equal key "CATEGORY") | ||
| 4643 | (if (string-match "[ \t]+$" value) | ||
| 4644 | (setq value (replace-match "" t t value))) | ||
| 4645 | (setq cat value)) | ||
| 4646 | ((member key '("SEQ_TODO" "TODO")) | ||
| 4647 | (push (cons 'sequence (org-split-string value splitre)) kwds)) | ||
| 4648 | ((equal key "TYP_TODO") | ||
| 4649 | (push (cons 'type (org-split-string value splitre)) kwds)) | ||
| 4650 | ((equal key "TAGS") | ||
| 4651 | (setq tags (append tags (org-split-string value splitre)))) | ||
| 4652 | ((equal key "COLUMNS") | ||
| 4653 | (org-set-local 'org-columns-default-format value)) | ||
| 4654 | ((equal key "LINK") | ||
| 4655 | (when (string-match "^\\(\\S-+\\)[ \t]+\\(.+\\)" value) | ||
| 4656 | (push (cons (match-string 1 value) | ||
| 4657 | (org-trim (match-string 2 value))) | ||
| 4658 | links))) | ||
| 4659 | ((equal key "PRIORITIES") | ||
| 4660 | (setq prio (org-split-string value " +"))) | ||
| 4661 | ((equal key "PROPERTY") | ||
| 4662 | (when (string-match "\\(\\S-+\\)\\s-+\\(.*\\)" value) | ||
| 4663 | (push (cons (match-string 1 value) (match-string 2 value)) | ||
| 4664 | props))) | ||
| 4665 | ((equal key "DRAWERS") | ||
| 4666 | (setq drawers (org-split-string value splitre))) | ||
| 4667 | ((equal key "CONSTANTS") | ||
| 4668 | (setq const (append const (org-split-string value splitre)))) | ||
| 4669 | ((equal key "STARTUP") | ||
| 4670 | (let ((opts (org-split-string value splitre)) | ||
| 4671 | l var val) | ||
| 4672 | (while (setq l (pop opts)) | ||
| 4673 | (when (setq l (assoc l org-startup-options)) | ||
| 4674 | (setq var (nth 1 l) val (nth 2 l)) | ||
| 4675 | (if (not (nth 3 l)) | ||
| 4676 | (set (make-local-variable var) val) | ||
| 4677 | (if (not (listp (symbol-value var))) | ||
| 4678 | (set (make-local-variable var) nil)) | ||
| 4679 | (set (make-local-variable var) (symbol-value var)) | ||
| 4680 | (add-to-list var val)))))) | ||
| 4681 | ((equal key "ARCHIVE") | ||
| 4682 | (string-match " *$" value) | ||
| 4683 | (setq arch (replace-match "" t t value)) | ||
| 4684 | (remove-text-properties 0 (length arch) | ||
| 4685 | '(face t fontified t) arch))) | ||
| 4686 | ))) | ||
| 4687 | (when cat | ||
| 4688 | (org-set-local 'org-category (intern cat)) | ||
| 4689 | (push (cons "CATEGORY" cat) props)) | ||
| 4690 | (when prio | ||
| 4691 | (if (< (length prio) 3) (setq prio '("A" "C" "B"))) | ||
| 4692 | (setq prio (mapcar 'string-to-char prio)) | ||
| 4693 | (org-set-local 'org-highest-priority (nth 0 prio)) | ||
| 4694 | (org-set-local 'org-lowest-priority (nth 1 prio)) | ||
| 4695 | (org-set-local 'org-default-priority (nth 2 prio))) | ||
| 4696 | (and props (org-set-local 'org-local-properties (nreverse props))) | ||
| 4697 | (and drawers (org-set-local 'org-drawers drawers)) | ||
| 4698 | (and arch (org-set-local 'org-archive-location arch)) | ||
| 4699 | (and links (setq org-link-abbrev-alist-local (nreverse links))) | ||
| 4700 | ;; Process the TODO keywords | ||
| 4701 | (unless kwds | ||
| 4702 | ;; Use the global values as if they had been given locally. | ||
| 4703 | (setq kwds (default-value 'org-todo-keywords)) | ||
| 4704 | (if (stringp (car kwds)) | ||
| 4705 | (setq kwds (list (cons org-todo-interpretation | ||
| 4706 | (default-value 'org-todo-keywords))))) | ||
| 4707 | (setq kwds (reverse kwds))) | ||
| 4708 | (setq kwds (nreverse kwds)) | ||
| 4709 | (let (inter kws kw) | ||
| 4710 | (while (setq kws (pop kwds)) | ||
| 4711 | (setq inter (pop kws) sep (member "|" kws) | ||
| 4712 | kws0 (delete "|" (copy-sequence kws)) | ||
| 4713 | kwsa nil | ||
| 4714 | kws1 (mapcar | ||
| 4715 | (lambda (x) | ||
| 4716 | ;; 1 2 | ||
| 4717 | (if (string-match "^\\(.*?\\)\\(?:(\\([^!@/]\\)?.*?)\\)?$" x) | ||
| 4718 | (progn | ||
| 4719 | (setq kw (match-string 1 x) | ||
| 4720 | key (and (match-end 2) (match-string 2 x)) | ||
| 4721 | log (org-extract-log-state-settings x)) | ||
| 4722 | (push (cons kw (and key (string-to-char key))) kwsa) | ||
| 4723 | (and log (push log org-todo-log-states)) | ||
| 4724 | kw) | ||
| 4725 | (error "Invalid TODO keyword %s" x))) | ||
| 4726 | kws0) | ||
| 4727 | kwsa (if kwsa (append '((:startgroup)) | ||
| 4728 | (nreverse kwsa) | ||
| 4729 | '((:endgroup)))) | ||
| 4730 | hw (car kws1) | ||
| 4731 | dws (if sep (org-remove-keyword-keys (cdr sep)) (last kws1)) | ||
| 4732 | tail (list inter hw (car dws) (org-last dws))) | ||
| 4733 | (add-to-list 'org-todo-heads hw 'append) | ||
| 4734 | (push kws1 org-todo-sets) | ||
| 4735 | (setq org-done-keywords (append org-done-keywords dws nil)) | ||
| 4736 | (setq org-todo-key-alist (append org-todo-key-alist kwsa)) | ||
| 4737 | (mapc (lambda (x) (push (cons x tail) org-todo-kwd-alist)) kws1) | ||
| 4738 | (setq org-todo-keywords-1 (append org-todo-keywords-1 kws1 nil))) | ||
| 4739 | (setq org-todo-sets (nreverse org-todo-sets) | ||
| 4740 | org-todo-kwd-alist (nreverse org-todo-kwd-alist) | ||
| 4741 | org-todo-key-trigger (delq nil (mapcar 'cdr org-todo-key-alist)) | ||
| 4742 | org-todo-key-alist (org-assign-fast-keys org-todo-key-alist))) | ||
| 4743 | ;; Process the constants | ||
| 4744 | (when const | ||
| 4745 | (let (e cst) | ||
| 4746 | (while (setq e (pop const)) | ||
| 4747 | (if (string-match "^\\([a-zA-Z0][_a-zA-Z0-9]*\\)=\\(.*\\)" e) | ||
| 4748 | (push (cons (match-string 1 e) (match-string 2 e)) cst))) | ||
| 4749 | (setq org-table-formula-constants-local cst))) | ||
| 4750 | |||
| 4751 | ;; Process the tags. | ||
| 4752 | (when tags | ||
| 4753 | (let (e tgs) | ||
| 4754 | (while (setq e (pop tags)) | ||
| 4755 | (cond | ||
| 4756 | ((equal e "{") (push '(:startgroup) tgs)) | ||
| 4757 | ((equal e "}") (push '(:endgroup) tgs)) | ||
| 4758 | ((string-match (org-re "^\\([[:alnum:]_@]+\\)(\\(.\\))$") e) | ||
| 4759 | (push (cons (match-string 1 e) | ||
| 4760 | (string-to-char (match-string 2 e))) | ||
| 4761 | tgs)) | ||
| 4762 | (t (push (list e) tgs)))) | ||
| 4763 | (org-set-local 'org-tag-alist nil) | ||
| 4764 | (while (setq e (pop tgs)) | ||
| 4765 | (or (and (stringp (car e)) | ||
| 4766 | (assoc (car e) org-tag-alist)) | ||
| 4767 | (push e org-tag-alist)))))) | ||
| 4768 | |||
| 4769 | ;; Compute the regular expressions and other local variables | ||
| 4770 | (if (not org-done-keywords) | ||
| 4771 | (setq org-done-keywords (list (org-last org-todo-keywords-1)))) | ||
| 4772 | (setq org-ds-keyword-length (+ 2 (max (length org-deadline-string) | ||
| 4773 | (length org-scheduled-string))) | ||
| 4774 | org-drawer-regexp | ||
| 4775 | (concat "^[ \t]*:\\(" | ||
| 4776 | (mapconcat 'regexp-quote org-drawers "\\|") | ||
| 4777 | "\\):[ \t]*$") | ||
| 4778 | org-not-done-keywords | ||
| 4779 | (org-delete-all org-done-keywords (copy-sequence org-todo-keywords-1)) | ||
| 4780 | org-todo-regexp | ||
| 4781 | (concat "\\<\\(" (mapconcat 'regexp-quote org-todo-keywords-1 | ||
| 4782 | "\\|") "\\)\\>") | ||
| 4783 | org-not-done-regexp | ||
| 4784 | (concat "\\<\\(" | ||
| 4785 | (mapconcat 'regexp-quote org-not-done-keywords "\\|") | ||
| 4786 | "\\)\\>") | ||
| 4787 | org-todo-line-regexp | ||
| 4788 | (concat "^\\(\\*+\\)[ \t]+\\(?:\\(" | ||
| 4789 | (mapconcat 'regexp-quote org-todo-keywords-1 "\\|") | ||
| 4790 | "\\)\\>\\)?[ \t]*\\(.*\\)") | ||
| 4791 | org-complex-heading-regexp | ||
| 4792 | (concat "^\\(\\*+\\)\\(?:[ \t]+\\(" | ||
| 4793 | (mapconcat 'regexp-quote org-todo-keywords-1 "\\|") | ||
| 4794 | "\\)\\>\\)?\\(?:[ \t]*\\(\\[#.\\]\\)\\)?[ \t]*\\(.*?\\)" | ||
| 4795 | "\\(?:[ \t]+\\(:[[:alnum:]_@:]+:\\)\\)?[ \t]*$") | ||
| 4796 | org-nl-done-regexp | ||
| 4797 | (concat "\n\\*+[ \t]+" | ||
| 4798 | "\\(?:" (mapconcat 'regexp-quote org-done-keywords "\\|") | ||
| 4799 | "\\)" "\\>") | ||
| 4800 | org-todo-line-tags-regexp | ||
| 4801 | (concat "^\\(\\*+\\)[ \t]+\\(?:\\(" | ||
| 4802 | (mapconcat 'regexp-quote org-todo-keywords-1 "\\|") | ||
| 4803 | (org-re | ||
| 4804 | "\\)\\>\\)? *\\(.*?\\([ \t]:[[:alnum:]:_@]+:[ \t]*\\)?$\\)")) | ||
| 4805 | org-looking-at-done-regexp | ||
| 4806 | (concat "^" "\\(?:" | ||
| 4807 | (mapconcat 'regexp-quote org-done-keywords "\\|") "\\)" | ||
| 4808 | "\\>") | ||
| 4809 | org-deadline-regexp (concat "\\<" org-deadline-string) | ||
| 4810 | org-deadline-time-regexp | ||
| 4811 | (concat "\\<" org-deadline-string " *<\\([^>]+\\)>") | ||
| 4812 | org-deadline-line-regexp | ||
| 4813 | (concat "\\<\\(" org-deadline-string "\\).*") | ||
| 4814 | org-scheduled-regexp | ||
| 4815 | (concat "\\<" org-scheduled-string) | ||
| 4816 | org-scheduled-time-regexp | ||
| 4817 | (concat "\\<" org-scheduled-string " *<\\([^>]+\\)>") | ||
| 4818 | org-closed-time-regexp | ||
| 4819 | (concat "\\<" org-closed-string " *\\[\\([^]]+\\)\\]") | ||
| 4820 | org-keyword-time-regexp | ||
| 4821 | (concat "\\<\\(" org-scheduled-string | ||
| 4822 | "\\|" org-deadline-string | ||
| 4823 | "\\|" org-closed-string | ||
| 4824 | "\\|" org-clock-string "\\)" | ||
| 4825 | " *[[<]\\([^]>]+\\)[]>]") | ||
| 4826 | org-keyword-time-not-clock-regexp | ||
| 4827 | (concat "\\<\\(" org-scheduled-string | ||
| 4828 | "\\|" org-deadline-string | ||
| 4829 | "\\|" org-closed-string | ||
| 4830 | "\\)" | ||
| 4831 | " *[[<]\\([^]>]+\\)[]>]") | ||
| 4832 | org-maybe-keyword-time-regexp | ||
| 4833 | (concat "\\(\\<\\(" org-scheduled-string | ||
| 4834 | "\\|" org-deadline-string | ||
| 4835 | "\\|" org-closed-string | ||
| 4836 | "\\|" org-clock-string "\\)\\)?" | ||
| 4837 | " *\\([[<][0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\} [^]\r\n>]*?[]>]\\|<%%([^\r\n>]*>\\)") | ||
| 4838 | org-planning-or-clock-line-re | ||
| 4839 | (concat "\\(?:^[ \t]*\\(" org-scheduled-string | ||
| 4840 | "\\|" org-deadline-string | ||
| 4841 | "\\|" org-closed-string "\\|" org-clock-string | ||
| 4842 | "\\)\\>\\)") | ||
| 4843 | ) | ||
| 4844 | (org-compute-latex-and-specials-regexp) | ||
| 4845 | (org-set-font-lock-defaults))) | ||
| 4846 | |||
| 4847 | (defun org-extract-log-state-settings (x) | ||
| 4848 | "Extract the log state setting from a TODO keyword string. | ||
| 4849 | This will extract info from a string like \"WAIT(w@/!)\"." | ||
| 4850 | (let (kw key log1 log2) | ||
| 4851 | (when (string-match "^\\(.*?\\)\\(?:(\\([^!@/]\\)?\\([!@]\\)?\\(?:/\\([!@]\\)\\)?)\\)?$" x) | ||
| 4852 | (setq kw (match-string 1 x) | ||
| 4853 | key (and (match-end 2) (match-string 2 x)) | ||
| 4854 | log1 (and (match-end 3) (match-string 3 x)) | ||
| 4855 | log2 (and (match-end 4) (match-string 4 x))) | ||
| 4856 | (and (or log1 log2) | ||
| 4857 | (list kw | ||
| 4858 | (and log1 (if (equal log1 "!") 'time 'note)) | ||
| 4859 | (and log2 (if (equal log2 "!") 'time 'note))))))) | ||
| 4860 | |||
| 4861 | (defun org-remove-keyword-keys (list) | ||
| 4862 | "Remove a pair of parenthesis at the end of each string in LIST." | ||
| 4863 | (mapcar (lambda (x) | ||
| 4864 | (if (string-match "(.*)$" x) | ||
| 4865 | (substring x 0 (match-beginning 0)) | ||
| 4866 | x)) | ||
| 4867 | list)) | ||
| 4868 | |||
| 4869 | ;; FIXME: this could be done much better, using second characters etc. | ||
| 4870 | (defun org-assign-fast-keys (alist) | ||
| 4871 | "Assign fast keys to a keyword-key alist. | ||
| 4872 | Respect keys that are already there." | ||
| 4873 | (let (new e k c c1 c2 (char ?a)) | ||
| 4874 | (while (setq e (pop alist)) | ||
| 4875 | (cond | ||
| 4876 | ((equal e '(:startgroup)) (push e new)) | ||
| 4877 | ((equal e '(:endgroup)) (push e new)) | ||
| 4878 | (t | ||
| 4879 | (setq k (car e) c2 nil) | ||
| 4880 | (if (cdr e) | ||
| 4881 | (setq c (cdr e)) | ||
| 4882 | ;; automatically assign a character. | ||
| 4883 | (setq c1 (string-to-char | ||
| 4884 | (downcase (substring | ||
| 4885 | k (if (= (string-to-char k) ?@) 1 0))))) | ||
| 4886 | (if (or (rassoc c1 new) (rassoc c1 alist)) | ||
| 4887 | (while (or (rassoc char new) (rassoc char alist)) | ||
| 4888 | (setq char (1+ char))) | ||
| 4889 | (setq c2 c1)) | ||
| 4890 | (setq c (or c2 char))) | ||
| 4891 | (push (cons k c) new)))) | ||
| 4892 | (nreverse new))) | ||
| 4893 | |||
| 4894 | ;;; Some variables ujsed in various places | ||
| 4895 | |||
| 4896 | (defvar org-window-configuration nil | ||
| 4897 | "Used in various places to store a window configuration.") | ||
| 4898 | (defvar org-finish-function nil | ||
| 4899 | "Function to be called when `C-c C-c' is used. | ||
| 4900 | This is for getting out of special buffers like remember.") | ||
| 4901 | |||
| 4902 | |||
| 4903 | ;; FIXME: Occasionally check by commenting these, to make sure | ||
| 4904 | ;; no other functions uses these, forgetting to let-bind them. | ||
| 4905 | (defvar entry) | ||
| 4906 | (defvar state) | ||
| 4907 | (defvar last-state) | ||
| 4908 | (defvar date) | ||
| 4909 | (defvar description) | ||
| 4910 | |||
| 4911 | ;; Defined somewhere in this file, but used before definition. | ||
| 4912 | (defvar orgtbl-mode-menu) ; defined when orgtbl mode get initialized | ||
| 4913 | (defvar org-agenda-buffer-name) | ||
| 4914 | (defvar org-agenda-undo-list) | ||
| 4915 | (defvar org-agenda-pending-undo-list) | ||
| 4916 | (defvar org-agenda-overriding-header) | ||
| 4917 | (defvar orgtbl-mode) | ||
| 4918 | (defvar org-html-entities) | ||
| 4919 | (defvar org-struct-menu) | ||
| 4920 | (defvar org-org-menu) | ||
| 4921 | (defvar org-tbl-menu) | ||
| 4922 | (defvar org-agenda-keymap) | ||
| 4923 | |||
| 4924 | ;;;; Emacs/XEmacs compatibility | ||
| 4925 | |||
| 4926 | ;; Overlay compatibility functions | ||
| 4927 | (defun org-make-overlay (beg end &optional buffer) | ||
| 4928 | (if (featurep 'xemacs) | ||
| 4929 | (make-extent beg end buffer) | ||
| 4930 | (make-overlay beg end buffer))) | ||
| 4931 | (defun org-delete-overlay (ovl) | ||
| 4932 | (if (featurep 'xemacs) (delete-extent ovl) (delete-overlay ovl))) | ||
| 4933 | (defun org-detach-overlay (ovl) | ||
| 4934 | (if (featurep 'xemacs) (detach-extent ovl) (delete-overlay ovl))) | ||
| 4935 | (defun org-move-overlay (ovl beg end &optional buffer) | ||
| 4936 | (if (featurep 'xemacs) | ||
| 4937 | (set-extent-endpoints ovl beg end (or buffer (current-buffer))) | ||
| 4938 | (move-overlay ovl beg end buffer))) | ||
| 4939 | (defun org-overlay-put (ovl prop value) | ||
| 4940 | (if (featurep 'xemacs) | ||
| 4941 | (set-extent-property ovl prop value) | ||
| 4942 | (overlay-put ovl prop value))) | ||
| 4943 | (defun org-overlay-display (ovl text &optional face evap) | ||
| 4944 | "Make overlay OVL display TEXT with face FACE." | ||
| 4945 | (if (featurep 'xemacs) | ||
| 4946 | (let ((gl (make-glyph text))) | ||
| 4947 | (and face (set-glyph-face gl face)) | ||
| 4948 | (set-extent-property ovl 'invisible t) | ||
| 4949 | (set-extent-property ovl 'end-glyph gl)) | ||
| 4950 | (overlay-put ovl 'display text) | ||
| 4951 | (if face (overlay-put ovl 'face face)) | ||
| 4952 | (if evap (overlay-put ovl 'evaporate t)))) | ||
| 4953 | (defun org-overlay-before-string (ovl text &optional face evap) | ||
| 4954 | "Make overlay OVL display TEXT with face FACE." | ||
| 4955 | (if (featurep 'xemacs) | ||
| 4956 | (let ((gl (make-glyph text))) | ||
| 4957 | (and face (set-glyph-face gl face)) | ||
| 4958 | (set-extent-property ovl 'begin-glyph gl)) | ||
| 4959 | (if face (org-add-props text nil 'face face)) | ||
| 4960 | (overlay-put ovl 'before-string text) | ||
| 4961 | (if evap (overlay-put ovl 'evaporate t)))) | ||
| 4962 | (defun org-overlay-get (ovl prop) | ||
| 4963 | (if (featurep 'xemacs) | ||
| 4964 | (extent-property ovl prop) | ||
| 4965 | (overlay-get ovl prop))) | ||
| 4966 | (defun org-overlays-at (pos) | ||
| 4967 | (if (featurep 'xemacs) (extents-at pos) (overlays-at pos))) | ||
| 4968 | (defun org-overlays-in (&optional start end) | ||
| 4969 | (if (featurep 'xemacs) | ||
| 4970 | (extent-list nil start end) | ||
| 4971 | (overlays-in start end))) | ||
| 4972 | (defun org-overlay-start (o) | ||
| 4973 | (if (featurep 'xemacs) (extent-start-position o) (overlay-start o))) | ||
| 4974 | (defun org-overlay-end (o) | ||
| 4975 | (if (featurep 'xemacs) (extent-end-position o) (overlay-end o))) | ||
| 4976 | (defun org-find-overlays (prop &optional pos delete) | ||
| 4977 | "Find all overlays specifying PROP at POS or point. | ||
| 4978 | If DELETE is non-nil, delete all those overlays." | ||
| 4979 | (let ((overlays (org-overlays-at (or pos (point)))) | ||
| 4980 | ov found) | ||
| 4981 | (while (setq ov (pop overlays)) | ||
| 4982 | (if (org-overlay-get ov prop) | ||
| 4983 | (if delete (org-delete-overlay ov) (push ov found)))) | ||
| 4984 | found)) | ||
| 4985 | |||
| 4986 | ;; Region compatibility | ||
| 4987 | |||
| 4988 | (defun org-add-hook (hook function &optional append local) | ||
| 4989 | "Add-hook, compatible with both Emacsen." | ||
| 4990 | (if (and local (featurep 'xemacs)) | ||
| 4991 | (add-local-hook hook function append) | ||
| 4992 | (add-hook hook function append local))) | ||
| 4993 | |||
| 4994 | (defvar org-ignore-region nil | ||
| 4995 | "To temporarily disable the active region.") | ||
| 4996 | |||
| 4997 | (defun org-region-active-p () | ||
| 4998 | "Is `transient-mark-mode' on and the region active? | ||
| 4999 | Works on both Emacs and XEmacs." | ||
| 5000 | (if org-ignore-region | ||
| 5001 | nil | ||
| 5002 | (if (featurep 'xemacs) | ||
| 5003 | (and zmacs-regions (region-active-p)) | ||
| 5004 | (if (fboundp 'use-region-p) | ||
| 5005 | (use-region-p) | ||
| 5006 | (and transient-mark-mode mark-active))))) ; Emacs 22 and before | ||
| 5007 | |||
| 5008 | ;; Invisibility compatibility | ||
| 5009 | |||
| 5010 | (defun org-add-to-invisibility-spec (arg) | ||
| 5011 | "Add elements to `buffer-invisibility-spec'. | ||
| 5012 | See documentation for `buffer-invisibility-spec' for the kind of elements | ||
| 5013 | that can be added." | ||
| 5014 | (cond | ||
| 5015 | ((fboundp 'add-to-invisibility-spec) | ||
| 5016 | (add-to-invisibility-spec arg)) | ||
| 5017 | ((or (null buffer-invisibility-spec) (eq buffer-invisibility-spec t)) | ||
| 5018 | (setq buffer-invisibility-spec (list arg))) | ||
| 5019 | (t | ||
| 5020 | (setq buffer-invisibility-spec | ||
| 5021 | (cons arg buffer-invisibility-spec))))) | ||
| 5022 | |||
| 5023 | (defun org-remove-from-invisibility-spec (arg) | ||
| 5024 | "Remove elements from `buffer-invisibility-spec'." | ||
| 5025 | (if (fboundp 'remove-from-invisibility-spec) | ||
| 5026 | (remove-from-invisibility-spec arg) | ||
| 5027 | (if (consp buffer-invisibility-spec) | ||
| 5028 | (setq buffer-invisibility-spec | ||
| 5029 | (delete arg buffer-invisibility-spec))))) | ||
| 5030 | |||
| 5031 | (defun org-in-invisibility-spec-p (arg) | ||
| 5032 | "Is ARG a member of `buffer-invisibility-spec'?" | ||
| 5033 | (if (consp buffer-invisibility-spec) | ||
| 5034 | (member arg buffer-invisibility-spec) | ||
| 5035 | nil)) | ||
| 5036 | |||
| 5037 | ;;;; Define the Org-mode | ||
| 5038 | |||
| 5039 | (if (and (not (keymapp outline-mode-map)) (featurep 'allout)) | ||
| 5040 | (error "Conflict with outdated version of allout.el. Load org.el before allout.el, or ugrade to newer allout, for example by switching to Emacs 22.")) | ||
| 5041 | |||
| 5042 | |||
| 5043 | ;; We use a before-change function to check if a table might need | ||
| 5044 | ;; an update. | ||
| 5045 | (defvar org-table-may-need-update t | ||
| 5046 | "Indicates that a table might need an update. | ||
| 5047 | This variable is set by `org-before-change-function'. | ||
| 5048 | `org-table-align' sets it back to nil.") | ||
| 5049 | (defvar org-mode-map) | ||
| 5050 | (defvar org-mode-hook nil) | ||
| 5051 | (defvar org-inhibit-startup nil) ; Dynamically-scoped param. | ||
| 5052 | (defvar org-agenda-keep-modes nil) ; Dynamically-scoped param. | ||
| 5053 | (defvar org-table-buffer-is-an nil) | ||
| 5054 | (defconst org-outline-regexp "\\*+ ") | ||
| 5055 | |||
| 5056 | ;;;###autoload | ||
| 5057 | (define-derived-mode org-mode outline-mode "Org" | ||
| 5058 | "Outline-based notes management and organizer, alias | ||
| 5059 | \"Carsten's outline-mode for keeping track of everything.\" | ||
| 5060 | |||
| 5061 | Org-mode develops organizational tasks around a NOTES file which | ||
| 5062 | contains information about projects as plain text. Org-mode is | ||
| 5063 | implemented on top of outline-mode, which is ideal to keep the content | ||
| 5064 | of large files well structured. It supports ToDo items, deadlines and | ||
| 5065 | time stamps, which magically appear in the diary listing of the Emacs | ||
| 5066 | calendar. Tables are easily created with a built-in table editor. | ||
| 5067 | Plain text URL-like links connect to websites, emails (VM), Usenet | ||
| 5068 | messages (Gnus), BBDB entries, and any files related to the project. | ||
| 5069 | For printing and sharing of notes, an Org-mode file (or a part of it) | ||
| 5070 | can be exported as a structured ASCII or HTML file. | ||
| 5071 | |||
| 5072 | The following commands are available: | ||
| 5073 | |||
| 5074 | \\{org-mode-map}" | ||
| 5075 | |||
| 5076 | ;; Get rid of Outline menus, they are not needed | ||
| 5077 | ;; Need to do this here because define-derived-mode sets up | ||
| 5078 | ;; the keymap so late. Still, it is a waste to call this each time | ||
| 5079 | ;; we switch another buffer into org-mode. | ||
| 5080 | (if (featurep 'xemacs) | ||
| 5081 | (when (boundp 'outline-mode-menu-heading) | ||
| 5082 | ;; Assume this is Greg's port, it used easymenu | ||
| 5083 | (easy-menu-remove outline-mode-menu-heading) | ||
| 5084 | (easy-menu-remove outline-mode-menu-show) | ||
| 5085 | (easy-menu-remove outline-mode-menu-hide)) | ||
| 5086 | (define-key org-mode-map [menu-bar headings] 'undefined) | ||
| 5087 | (define-key org-mode-map [menu-bar hide] 'undefined) | ||
| 5088 | (define-key org-mode-map [menu-bar show] 'undefined)) | ||
| 5089 | |||
| 5090 | (easy-menu-add org-org-menu) | ||
| 5091 | (easy-menu-add org-tbl-menu) | ||
| 5092 | (org-install-agenda-files-menu) | ||
| 5093 | (if org-descriptive-links (org-add-to-invisibility-spec '(org-link))) | ||
| 5094 | (org-add-to-invisibility-spec '(org-cwidth)) | ||
| 5095 | (when (featurep 'xemacs) | ||
| 5096 | (org-set-local 'line-move-ignore-invisible t)) | ||
| 5097 | (org-set-local 'outline-regexp org-outline-regexp) | ||
| 5098 | (org-set-local 'outline-level 'org-outline-level) | ||
| 5099 | (when (and org-ellipsis | ||
| 5100 | (fboundp 'set-display-table-slot) (boundp 'buffer-display-table) | ||
| 5101 | (fboundp 'make-glyph-code)) | ||
| 5102 | (unless org-display-table | ||
| 5103 | (setq org-display-table (make-display-table))) | ||
| 5104 | (set-display-table-slot | ||
| 5105 | org-display-table 4 | ||
| 5106 | (vconcat (mapcar | ||
| 5107 | (lambda (c) (make-glyph-code c (and (not (stringp org-ellipsis)) | ||
| 5108 | org-ellipsis))) | ||
| 5109 | (if (stringp org-ellipsis) org-ellipsis "...")))) | ||
| 5110 | (setq buffer-display-table org-display-table)) | ||
| 5111 | (org-set-regexps-and-options) | ||
| 5112 | ;; Calc embedded | ||
| 5113 | (org-set-local 'calc-embedded-open-mode "# ") | ||
| 5114 | (modify-syntax-entry ?# "<") | ||
| 5115 | (modify-syntax-entry ?@ "w") | ||
| 5116 | (if org-startup-truncated (setq truncate-lines t)) | ||
| 5117 | (org-set-local 'font-lock-unfontify-region-function | ||
| 5118 | 'org-unfontify-region) | ||
| 5119 | ;; Activate before-change-function | ||
| 5120 | (org-set-local 'org-table-may-need-update t) | ||
| 5121 | (org-add-hook 'before-change-functions 'org-before-change-function nil | ||
| 5122 | 'local) | ||
| 5123 | ;; Check for running clock before killing a buffer | ||
| 5124 | (org-add-hook 'kill-buffer-hook 'org-check-running-clock nil 'local) | ||
| 5125 | ;; Paragraphs and auto-filling | ||
| 5126 | (org-set-autofill-regexps) | ||
| 5127 | (setq indent-line-function 'org-indent-line-function) | ||
| 5128 | (org-update-radio-target-regexp) | ||
| 5129 | |||
| 5130 | ;; Comment characters | ||
| 5131 | ; (org-set-local 'comment-start "#") ;; FIXME: this breaks wrapping | ||
| 5132 | (org-set-local 'comment-padding " ") | ||
| 5133 | |||
| 5134 | ;; Align options lines | ||
| 5135 | (org-set-local | ||
| 5136 | 'align-mode-rules-list | ||
| 5137 | '((org-in-buffer-settings | ||
| 5138 | (regexp . "^#\\+[A-Z_]+:\\(\\s-*\\)\\S-+") | ||
| 5139 | (modes . '(org-mode))))) | ||
| 5140 | |||
| 5141 | ;; Imenu | ||
| 5142 | (org-set-local 'imenu-create-index-function | ||
| 5143 | 'org-imenu-get-tree) | ||
| 5144 | |||
| 5145 | ;; Make isearch reveal context | ||
| 5146 | (if (or (featurep 'xemacs) | ||
| 5147 | (not (boundp 'outline-isearch-open-invisible-function))) | ||
| 5148 | ;; Emacs 21 and XEmacs make use of the hook | ||
| 5149 | (org-add-hook 'isearch-mode-end-hook 'org-isearch-end 'append 'local) | ||
| 5150 | ;; Emacs 22 deals with this through a special variable | ||
| 5151 | (org-set-local 'outline-isearch-open-invisible-function | ||
| 5152 | (lambda (&rest ignore) (org-show-context 'isearch)))) | ||
| 5153 | |||
| 5154 | ;; If empty file that did not turn on org-mode automatically, make it to. | ||
| 5155 | (if (and org-insert-mode-line-in-empty-file | ||
| 5156 | (interactive-p) | ||
| 5157 | (= (point-min) (point-max))) | ||
| 5158 | (insert "# -*- mode: org -*-\n\n")) | ||
| 5159 | |||
| 5160 | (unless org-inhibit-startup | ||
| 5161 | (when org-startup-align-all-tables | ||
| 5162 | (let ((bmp (buffer-modified-p))) | ||
| 5163 | (org-table-map-tables 'org-table-align) | ||
| 5164 | (set-buffer-modified-p bmp))) | ||
| 5165 | (org-cycle-hide-drawers 'all) | ||
| 5166 | (cond | ||
| 5167 | ((eq org-startup-folded t) | ||
| 5168 | (org-cycle '(4))) | ||
| 5169 | ((eq org-startup-folded 'content) | ||
| 5170 | (let ((this-command 'org-cycle) (last-command 'org-cycle)) | ||
| 5171 | (org-cycle '(4)) (org-cycle '(4))))))) | ||
| 5172 | |||
| 5173 | (put 'org-mode 'flyspell-mode-predicate 'org-mode-flyspell-verify) | ||
| 5174 | |||
| 5175 | (defsubst org-call-with-arg (command arg) | ||
| 5176 | "Call COMMAND interactively, but pretend prefix are was ARG." | ||
| 5177 | (let ((current-prefix-arg arg)) (call-interactively command))) | ||
| 5178 | |||
| 5179 | (defsubst org-current-line (&optional pos) | ||
| 5180 | (save-excursion | ||
| 5181 | (and pos (goto-char pos)) | ||
| 5182 | ;; works also in narrowed buffer, because we start at 1, not point-min | ||
| 5183 | (+ (if (bolp) 1 0) (count-lines 1 (point))))) | ||
| 5184 | |||
| 5185 | (defun org-current-time () | ||
| 5186 | "Current time, possibly rounded to `org-time-stamp-rounding-minutes'." | ||
| 5187 | (if (> (car org-time-stamp-rounding-minutes) 1) | ||
| 5188 | (let ((r (car org-time-stamp-rounding-minutes)) | ||
| 5189 | (time (decode-time))) | ||
| 5190 | (apply 'encode-time | ||
| 5191 | (append (list 0 (* r (floor (+ .5 (/ (float (nth 1 time)) r))))) | ||
| 5192 | (nthcdr 2 time)))) | ||
| 5193 | (current-time))) | ||
| 5194 | |||
| 5195 | (defun org-add-props (string plist &rest props) | ||
| 5196 | "Add text properties to entire string, from beginning to end. | ||
| 5197 | PLIST may be a list of properties, PROPS are individual properties and values | ||
| 5198 | that will be added to PLIST. Returns the string that was modified." | ||
| 5199 | (add-text-properties | ||
| 5200 | 0 (length string) (if props (append plist props) plist) string) | ||
| 5201 | string) | ||
| 5202 | (put 'org-add-props 'lisp-indent-function 2) | ||
| 5203 | |||
| 5204 | |||
| 5205 | ;;;; Font-Lock stuff, including the activators | ||
| 5206 | |||
| 5207 | (defvar org-mouse-map (make-sparse-keymap)) | ||
| 5208 | (org-defkey org-mouse-map | ||
| 5209 | (if (featurep 'xemacs) [button2] [mouse-2]) 'org-open-at-mouse) | ||
| 5210 | (org-defkey org-mouse-map | ||
| 5211 | (if (featurep 'xemacs) [button3] [mouse-3]) 'org-find-file-at-mouse) | ||
| 5212 | (when org-mouse-1-follows-link | ||
| 5213 | (org-defkey org-mouse-map [follow-link] 'mouse-face)) | ||
| 5214 | (when org-tab-follows-link | ||
| 5215 | (org-defkey org-mouse-map [(tab)] 'org-open-at-point) | ||
| 5216 | (org-defkey org-mouse-map "\C-i" 'org-open-at-point)) | ||
| 5217 | (when org-return-follows-link | ||
| 5218 | (org-defkey org-mouse-map [(return)] 'org-open-at-point) | ||
| 5219 | (org-defkey org-mouse-map "\C-m" 'org-open-at-point)) | ||
| 5220 | |||
| 5221 | (require 'font-lock) | ||
| 5222 | |||
| 5223 | (defconst org-non-link-chars "]\t\n\r<>") | ||
| 5224 | (defvar org-link-types '("http" "https" "ftp" "mailto" "file" "news" "bbdb" "vm" | ||
| 5225 | "wl" "mhe" "rmail" "gnus" "shell" "info" "elisp" "message")) | ||
| 5226 | (defvar org-link-re-with-space nil | ||
| 5227 | "Matches a link with spaces, optional angular brackets around it.") | ||
| 5228 | (defvar org-link-re-with-space2 nil | ||
| 5229 | "Matches a link with spaces, optional angular brackets around it.") | ||
| 5230 | (defvar org-angle-link-re nil | ||
| 5231 | "Matches link with angular brackets, spaces are allowed.") | ||
| 5232 | (defvar org-plain-link-re nil | ||
| 5233 | "Matches plain link, without spaces.") | ||
| 5234 | (defvar org-bracket-link-regexp nil | ||
| 5235 | "Matches a link in double brackets.") | ||
| 5236 | (defvar org-bracket-link-analytic-regexp nil | ||
| 5237 | "Regular expression used to analyze links. | ||
| 5238 | Here is what the match groups contain after a match: | ||
| 5239 | 1: http: | ||
| 5240 | 2: http | ||
| 5241 | 3: path | ||
| 5242 | 4: [desc] | ||
| 5243 | 5: desc") | ||
| 5244 | (defvar org-any-link-re nil | ||
| 5245 | "Regular expression matching any link.") | ||
| 5246 | |||
| 5247 | (defun org-make-link-regexps () | ||
| 5248 | "Update the link regular expressions. | ||
| 5249 | This should be called after the variable `org-link-types' has changed." | ||
| 5250 | (setq org-link-re-with-space | ||
| 5251 | (concat | ||
| 5252 | "<?\\(" (mapconcat 'identity org-link-types "\\|") "\\):" | ||
| 5253 | "\\([^" org-non-link-chars " ]" | ||
| 5254 | "[^" org-non-link-chars "]*" | ||
| 5255 | "[^" org-non-link-chars " ]\\)>?") | ||
| 5256 | org-link-re-with-space2 | ||
| 5257 | (concat | ||
| 5258 | "<?\\(" (mapconcat 'identity org-link-types "\\|") "\\):" | ||
| 5259 | "\\([^" org-non-link-chars " ]" | ||
| 5260 | "[^]\t\n\r]*" | ||
| 5261 | "[^" org-non-link-chars " ]\\)>?") | ||
| 5262 | org-angle-link-re | ||
| 5263 | (concat | ||
| 5264 | "<\\(" (mapconcat 'identity org-link-types "\\|") "\\):" | ||
| 5265 | "\\([^" org-non-link-chars " ]" | ||
| 5266 | "[^" org-non-link-chars "]*" | ||
| 5267 | "\\)>") | ||
| 5268 | org-plain-link-re | ||
| 5269 | (concat | ||
| 5270 | "\\<\\(" (mapconcat 'identity org-link-types "\\|") "\\):" | ||
| 5271 | "\\([^]\t\n\r<>() ]+[^]\t\n\r<>,.;() ]\\)") | ||
| 5272 | org-bracket-link-regexp | ||
| 5273 | "\\[\\[\\([^][]+\\)\\]\\(\\[\\([^][]+\\)\\]\\)?\\]" | ||
| 5274 | org-bracket-link-analytic-regexp | ||
| 5275 | (concat | ||
| 5276 | "\\[\\[" | ||
| 5277 | "\\(\\(" (mapconcat 'identity org-link-types "\\|") "\\):\\)?" | ||
| 5278 | "\\([^]]+\\)" | ||
| 5279 | "\\]" | ||
| 5280 | "\\(\\[" "\\([^]]+\\)" "\\]\\)?" | ||
| 5281 | "\\]") | ||
| 5282 | org-any-link-re | ||
| 5283 | (concat "\\(" org-bracket-link-regexp "\\)\\|\\(" | ||
| 5284 | org-angle-link-re "\\)\\|\\(" | ||
| 5285 | org-plain-link-re "\\)"))) | ||
| 5286 | |||
| 5287 | (org-make-link-regexps) | ||
| 5288 | |||
| 5289 | (defconst org-ts-regexp "<\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\} [^\r\n>]*?\\)>" | ||
| 5290 | "Regular expression for fast time stamp matching.") | ||
| 5291 | (defconst org-ts-regexp-both "[[<]\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\} [^\r\n>]*?\\)[]>]" | ||
| 5292 | "Regular expression for fast time stamp matching.") | ||
| 5293 | (defconst org-ts-regexp0 "\\(\\([0-9]\\{4\\}\\)-\\([0-9]\\{2\\}\\)-\\([0-9]\\{2\\}\\) *\\([^]-+0-9>\r\n ]*\\)\\( \\([0-9]\\{2\\}\\):\\([0-9]\\{2\\}\\)\\)?\\)" | ||
| 5294 | "Regular expression matching time strings for analysis. | ||
| 5295 | This one does not require the space after the date, so it can be used | ||
| 5296 | on a string that terminates immediately after the date.") | ||
| 5297 | (defconst org-ts-regexp1 "\\(\\([0-9]\\{4\\}\\)-\\([0-9]\\{2\\}\\)-\\([0-9]\\{2\\}\\) +\\([^]-+0-9>\r\n ]*\\)\\( \\([0-9]\\{2\\}\\):\\([0-9]\\{2\\}\\)\\)?\\)" | ||
| 5298 | "Regular expression matching time strings for analysis.") | ||
| 5299 | (defconst org-ts-regexp2 (concat "<" org-ts-regexp1 "[^>\n]\\{0,16\\}>") | ||
| 5300 | "Regular expression matching time stamps, with groups.") | ||
| 5301 | (defconst org-ts-regexp3 (concat "[[<]" org-ts-regexp1 "[^]>\n]\\{0,16\\}[]>]") | ||
| 5302 | "Regular expression matching time stamps (also [..]), with groups.") | ||
| 5303 | (defconst org-tr-regexp (concat org-ts-regexp "--?-?" org-ts-regexp) | ||
| 5304 | "Regular expression matching a time stamp range.") | ||
| 5305 | (defconst org-tr-regexp-both | ||
| 5306 | (concat org-ts-regexp-both "--?-?" org-ts-regexp-both) | ||
| 5307 | "Regular expression matching a time stamp range.") | ||
| 5308 | (defconst org-tsr-regexp (concat org-ts-regexp "\\(--?-?" | ||
| 5309 | org-ts-regexp "\\)?") | ||
| 5310 | "Regular expression matching a time stamp or time stamp range.") | ||
| 5311 | (defconst org-tsr-regexp-both (concat org-ts-regexp-both "\\(--?-?" | ||
| 5312 | org-ts-regexp-both "\\)?") | ||
| 5313 | "Regular expression matching a time stamp or time stamp range. | ||
| 5314 | The time stamps may be either active or inactive.") | ||
| 5315 | |||
| 5316 | (defvar org-emph-face nil) | ||
| 5317 | |||
| 5318 | (defun org-do-emphasis-faces (limit) | ||
| 5319 | "Run through the buffer and add overlays to links." | ||
| 5320 | (let (rtn) | ||
| 5321 | (while (and (not rtn) (re-search-forward org-emph-re limit t)) | ||
| 5322 | (if (not (= (char-after (match-beginning 3)) | ||
| 5323 | (char-after (match-beginning 4)))) | ||
| 5324 | (progn | ||
| 5325 | (setq rtn t) | ||
| 5326 | (font-lock-prepend-text-property (match-beginning 2) (match-end 2) | ||
| 5327 | 'face | ||
| 5328 | (nth 1 (assoc (match-string 3) | ||
| 5329 | org-emphasis-alist))) | ||
| 5330 | (add-text-properties (match-beginning 2) (match-end 2) | ||
| 5331 | '(font-lock-multiline t)) | ||
| 5332 | (when org-hide-emphasis-markers | ||
| 5333 | (add-text-properties (match-end 4) (match-beginning 5) | ||
| 5334 | '(invisible org-link)) | ||
| 5335 | (add-text-properties (match-beginning 3) (match-end 3) | ||
| 5336 | '(invisible org-link))))) | ||
| 5337 | (backward-char 1)) | ||
| 5338 | rtn)) | ||
| 5339 | |||
| 5340 | (defun org-emphasize (&optional char) | ||
| 5341 | "Insert or change an emphasis, i.e. a font like bold or italic. | ||
| 5342 | If there is an active region, change that region to a new emphasis. | ||
| 5343 | If there is no region, just insert the marker characters and position | ||
| 5344 | the cursor between them. | ||
| 5345 | CHAR should be either the marker character, or the first character of the | ||
| 5346 | HTML tag associated with that emphasis. If CHAR is a space, the means | ||
| 5347 | to remove the emphasis of the selected region. | ||
| 5348 | If char is not given (for example in an interactive call) it | ||
| 5349 | will be prompted for." | ||
| 5350 | (interactive) | ||
| 5351 | (let ((eal org-emphasis-alist) e det | ||
| 5352 | (erc org-emphasis-regexp-components) | ||
| 5353 | (prompt "") | ||
| 5354 | (string "") beg end move tag c s) | ||
| 5355 | (if (org-region-active-p) | ||
| 5356 | (setq beg (region-beginning) end (region-end) | ||
| 5357 | string (buffer-substring beg end)) | ||
| 5358 | (setq move t)) | ||
| 5359 | |||
| 5360 | (while (setq e (pop eal)) | ||
| 5361 | (setq tag (car (org-split-string (nth 2 e) "[ <>/]+")) | ||
| 5362 | c (aref tag 0)) | ||
| 5363 | (push (cons c (string-to-char (car e))) det) | ||
| 5364 | (setq prompt (concat prompt (format " [%s%c]%s" (car e) c | ||
| 5365 | (substring tag 1))))) | ||
| 5366 | (unless char | ||
| 5367 | (message "%s" (concat "Emphasis marker or tag:" prompt)) | ||
| 5368 | (setq char (read-char-exclusive))) | ||
| 5369 | (setq char (or (cdr (assoc char det)) char)) | ||
| 5370 | (if (equal char ?\ ) | ||
| 5371 | (setq s "" move nil) | ||
| 5372 | (unless (assoc (char-to-string char) org-emphasis-alist) | ||
| 5373 | (error "No such emphasis marker: \"%c\"" char)) | ||
| 5374 | (setq s (char-to-string char))) | ||
| 5375 | (while (and (> (length string) 1) | ||
| 5376 | (equal (substring string 0 1) (substring string -1)) | ||
| 5377 | (assoc (substring string 0 1) org-emphasis-alist)) | ||
| 5378 | (setq string (substring string 1 -1))) | ||
| 5379 | (setq string (concat s string s)) | ||
| 5380 | (if beg (delete-region beg end)) | ||
| 5381 | (unless (or (bolp) | ||
| 5382 | (string-match (concat "[" (nth 0 erc) "\n]") | ||
| 5383 | (char-to-string (char-before (point))))) | ||
| 5384 | (insert " ")) | ||
| 5385 | (unless (string-match (concat "[" (nth 1 erc) "\n]") | ||
| 5386 | (char-to-string (char-after (point)))) | ||
| 5387 | (insert " ") (backward-char 1)) | ||
| 5388 | (insert string) | ||
| 5389 | (and move (backward-char 1)))) | ||
| 5390 | |||
| 5391 | (defconst org-nonsticky-props | ||
| 5392 | '(mouse-face highlight keymap invisible intangible help-echo org-linked-text)) | ||
| 5393 | |||
| 5394 | |||
| 5395 | (defun org-activate-plain-links (limit) | ||
| 5396 | "Run through the buffer and add overlays to links." | ||
| 5397 | (catch 'exit | ||
| 5398 | (let (f) | ||
| 5399 | (while (re-search-forward org-plain-link-re limit t) | ||
| 5400 | (setq f (get-text-property (match-beginning 0) 'face)) | ||
| 5401 | (if (or (eq f 'org-tag) | ||
| 5402 | (and (listp f) (memq 'org-tag f))) | ||
| 5403 | nil | ||
| 5404 | (add-text-properties (match-beginning 0) (match-end 0) | ||
| 5405 | (list 'mouse-face 'highlight | ||
| 5406 | 'rear-nonsticky org-nonsticky-props | ||
| 5407 | 'keymap org-mouse-map | ||
| 5408 | )) | ||
| 5409 | (throw 'exit t)))))) | ||
| 5410 | |||
| 5411 | (defun org-activate-code (limit) | ||
| 5412 | (if (re-search-forward "^[ \t]*\\(:.*\\)" limit t) | ||
| 5413 | (unless (get-text-property (match-beginning 1) 'face) | ||
| 5414 | (remove-text-properties (match-beginning 0) (match-end 0) | ||
| 5415 | '(display t invisible t intangible t)) | ||
| 5416 | t))) | ||
| 5417 | |||
| 5418 | (defun org-activate-angle-links (limit) | ||
| 5419 | "Run through the buffer and add overlays to links." | ||
| 5420 | (if (re-search-forward org-angle-link-re limit t) | ||
| 5421 | (progn | ||
| 5422 | (add-text-properties (match-beginning 0) (match-end 0) | ||
| 5423 | (list 'mouse-face 'highlight | ||
| 5424 | 'rear-nonsticky org-nonsticky-props | ||
| 5425 | 'keymap org-mouse-map | ||
| 5426 | )) | ||
| 5427 | t))) | ||
| 5428 | |||
| 5429 | (defmacro org-maybe-intangible (props) | ||
| 5430 | "Add '(intangigble t) to PROPS if Emacs version is earlier than Emacs 22. | ||
| 5431 | In emacs 21, invisible text is not avoided by the command loop, so the | ||
| 5432 | intangible property is needed to make sure point skips this text. | ||
| 5433 | In Emacs 22, this is not necessary. The intangible text property has | ||
| 5434 | led to problems with flyspell. These problems are fixed in flyspell.el, | ||
| 5435 | but we still avoid setting the property in Emacs 22 and later. | ||
| 5436 | We use a macro so that the test can happen at compilation time." | ||
| 5437 | (if (< emacs-major-version 22) | ||
| 5438 | `(append '(intangible t) ,props) | ||
| 5439 | props)) | ||
| 5440 | |||
| 5441 | (defun org-activate-bracket-links (limit) | ||
| 5442 | "Run through the buffer and add overlays to bracketed links." | ||
| 5443 | (if (re-search-forward org-bracket-link-regexp limit t) | ||
| 5444 | (let* ((help (concat "LINK: " | ||
| 5445 | (org-match-string-no-properties 1))) | ||
| 5446 | ;; FIXME: above we should remove the escapes. | ||
| 5447 | ;; but that requires another match, protecting match data, | ||
| 5448 | ;; a lot of overhead for font-lock. | ||
| 5449 | (ip (org-maybe-intangible | ||
| 5450 | (list 'invisible 'org-link 'rear-nonsticky org-nonsticky-props | ||
| 5451 | 'keymap org-mouse-map 'mouse-face 'highlight | ||
| 5452 | 'font-lock-multiline t 'help-echo help))) | ||
| 5453 | (vp (list 'rear-nonsticky org-nonsticky-props | ||
| 5454 | 'keymap org-mouse-map 'mouse-face 'highlight | ||
| 5455 | ' font-lock-multiline t 'help-echo help))) | ||
| 5456 | ;; We need to remove the invisible property here. Table narrowing | ||
| 5457 | ;; may have made some of this invisible. | ||
| 5458 | (remove-text-properties (match-beginning 0) (match-end 0) | ||
| 5459 | '(invisible nil)) | ||
| 5460 | (if (match-end 3) | ||
| 5461 | (progn | ||
| 5462 | (add-text-properties (match-beginning 0) (match-beginning 3) ip) | ||
| 5463 | (add-text-properties (match-beginning 3) (match-end 3) vp) | ||
| 5464 | (add-text-properties (match-end 3) (match-end 0) ip)) | ||
| 5465 | (add-text-properties (match-beginning 0) (match-beginning 1) ip) | ||
| 5466 | (add-text-properties (match-beginning 1) (match-end 1) vp) | ||
| 5467 | (add-text-properties (match-end 1) (match-end 0) ip)) | ||
| 5468 | t))) | ||
| 5469 | |||
| 5470 | (defun org-activate-dates (limit) | ||
| 5471 | "Run through the buffer and add overlays to dates." | ||
| 5472 | (if (re-search-forward org-tsr-regexp-both limit t) | ||
| 5473 | (progn | ||
| 5474 | (add-text-properties (match-beginning 0) (match-end 0) | ||
| 5475 | (list 'mouse-face 'highlight | ||
| 5476 | 'rear-nonsticky org-nonsticky-props | ||
| 5477 | 'keymap org-mouse-map)) | ||
| 5478 | (when org-display-custom-times | ||
| 5479 | (if (match-end 3) | ||
| 5480 | (org-display-custom-time (match-beginning 3) (match-end 3))) | ||
| 5481 | (org-display-custom-time (match-beginning 1) (match-end 1))) | ||
| 5482 | t))) | ||
| 5483 | |||
| 5484 | (defvar org-target-link-regexp nil | ||
| 5485 | "Regular expression matching radio targets in plain text.") | ||
| 5486 | (defvar org-target-regexp "<<\\([^<>\n\r]+\\)>>" | ||
| 5487 | "Regular expression matching a link target.") | ||
| 5488 | (defvar org-radio-target-regexp "<<<\\([^<>\n\r]+\\)>>>" | ||
| 5489 | "Regular expression matching a radio target.") | ||
| 5490 | (defvar org-any-target-regexp "<<<?\\([^<>\n\r]+\\)>>>?" ; FIXME, not exact, would match <<<aaa>> as a radio target. | ||
| 5491 | "Regular expression matching any target.") | ||
| 5492 | |||
| 5493 | (defun org-activate-target-links (limit) | ||
| 5494 | "Run through the buffer and add overlays to target matches." | ||
| 5495 | (when org-target-link-regexp | ||
| 5496 | (let ((case-fold-search t)) | ||
| 5497 | (if (re-search-forward org-target-link-regexp limit t) | ||
| 5498 | (progn | ||
| 5499 | (add-text-properties (match-beginning 0) (match-end 0) | ||
| 5500 | (list 'mouse-face 'highlight | ||
| 5501 | 'rear-nonsticky org-nonsticky-props | ||
| 5502 | 'keymap org-mouse-map | ||
| 5503 | 'help-echo "Radio target link" | ||
| 5504 | 'org-linked-text t)) | ||
| 5505 | t))))) | ||
| 5506 | |||
| 5507 | (defun org-update-radio-target-regexp () | ||
| 5508 | "Find all radio targets in this file and update the regular expression." | ||
| 5509 | (interactive) | ||
| 5510 | (when (memq 'radio org-activate-links) | ||
| 5511 | (setq org-target-link-regexp | ||
| 5512 | (org-make-target-link-regexp (org-all-targets 'radio))) | ||
| 5513 | (org-restart-font-lock))) | ||
| 5514 | |||
| 5515 | (defun org-hide-wide-columns (limit) | ||
| 5516 | (let (s e) | ||
| 5517 | (setq s (text-property-any (point) (or limit (point-max)) | ||
| 5518 | 'org-cwidth t)) | ||
| 5519 | (when s | ||
| 5520 | (setq e (next-single-property-change s 'org-cwidth)) | ||
| 5521 | (add-text-properties s e (org-maybe-intangible '(invisible org-cwidth))) | ||
| 5522 | (goto-char e) | ||
| 5523 | t))) | ||
| 5524 | |||
| 5525 | (defvar org-latex-and-specials-regexp nil | ||
| 5526 | "Regular expression for highlighting export special stuff.") | ||
| 5527 | (defvar org-match-substring-regexp) | ||
| 5528 | (defvar org-match-substring-with-braces-regexp) | ||
| 5529 | (defvar org-export-html-special-string-regexps) | ||
| 5530 | |||
| 5531 | (defun org-compute-latex-and-specials-regexp () | ||
| 5532 | "Compute regular expression for stuff treated specially by exporters." | ||
| 5533 | (if (not org-highlight-latex-fragments-and-specials) | ||
| 5534 | (org-set-local 'org-latex-and-specials-regexp nil) | ||
| 5535 | (let* | ||
| 5536 | ((matchers (plist-get org-format-latex-options :matchers)) | ||
| 5537 | (latexs (delq nil (mapcar (lambda (x) (if (member (car x) matchers) x)) | ||
| 5538 | org-latex-regexps))) | ||
| 5539 | (options (org-combine-plists (org-default-export-plist) | ||
| 5540 | (org-infile-export-plist))) | ||
| 5541 | (org-export-with-sub-superscripts (plist-get options :sub-superscript)) | ||
| 5542 | (org-export-with-LaTeX-fragments (plist-get options :LaTeX-fragments)) | ||
| 5543 | (org-export-with-TeX-macros (plist-get options :TeX-macros)) | ||
| 5544 | (org-export-html-expand (plist-get options :expand-quoted-html)) | ||
| 5545 | (org-export-with-special-strings (plist-get options :special-strings)) | ||
| 5546 | (re-sub | ||
| 5547 | (cond | ||
| 5548 | ((equal org-export-with-sub-superscripts '{}) | ||
| 5549 | (list org-match-substring-with-braces-regexp)) | ||
| 5550 | (org-export-with-sub-superscripts | ||
| 5551 | (list org-match-substring-regexp)) | ||
| 5552 | (t nil))) | ||
| 5553 | (re-latex | ||
| 5554 | (if org-export-with-LaTeX-fragments | ||
| 5555 | (mapcar (lambda (x) (nth 1 x)) latexs))) | ||
| 5556 | (re-macros | ||
| 5557 | (if org-export-with-TeX-macros | ||
| 5558 | (list (concat "\\\\" | ||
| 5559 | (regexp-opt | ||
| 5560 | (append (mapcar 'car org-html-entities) | ||
| 5561 | (if (boundp 'org-latex-entities) | ||
| 5562 | org-latex-entities nil)) | ||
| 5563 | 'words))) ; FIXME | ||
| 5564 | )) | ||
| 5565 | ;; (list "\\\\\\(?:[a-zA-Z]+\\)"))) | ||
| 5566 | (re-special (if org-export-with-special-strings | ||
| 5567 | (mapcar (lambda (x) (car x)) | ||
| 5568 | org-export-html-special-string-regexps))) | ||
| 5569 | (re-rest | ||
| 5570 | (delq nil | ||
| 5571 | (list | ||
| 5572 | (if org-export-html-expand "@<[^>\n]+>") | ||
| 5573 | )))) | ||
| 5574 | (org-set-local | ||
| 5575 | 'org-latex-and-specials-regexp | ||
| 5576 | (mapconcat 'identity (append re-latex re-sub re-macros re-special | ||
| 5577 | re-rest) "\\|"))))) | ||
| 5578 | |||
| 5579 | (defface org-latex-and-export-specials | ||
| 5580 | (let ((font (cond ((assq :inherit custom-face-attributes) | ||
| 5581 | '(:inherit underline)) | ||
| 5582 | (t '(:underline t))))) | ||
| 5583 | `((((class grayscale) (background light)) | ||
| 5584 | (:foreground "DimGray" ,@font)) | ||
| 5585 | (((class grayscale) (background dark)) | ||
| 5586 | (:foreground "LightGray" ,@font)) | ||
| 5587 | (((class color) (background light)) | ||
| 5588 | (:foreground "SaddleBrown")) | ||
| 5589 | (((class color) (background dark)) | ||
| 5590 | (:foreground "burlywood")) | ||
| 5591 | (t (,@font)))) | ||
| 5592 | "Face used to highlight math latex and other special exporter stuff." | ||
| 5593 | :group 'org-faces) | ||
| 5594 | |||
| 5595 | (defun org-do-latex-and-special-faces (limit) | ||
| 5596 | "Run through the buffer and add overlays to links." | ||
| 5597 | (when org-latex-and-specials-regexp | ||
| 5598 | (let (rtn d) | ||
| 5599 | (while (and (not rtn) (re-search-forward org-latex-and-specials-regexp | ||
| 5600 | limit t)) | ||
| 5601 | (if (not (memq (car-safe (get-text-property (1+ (match-beginning 0)) | ||
| 5602 | 'face)) | ||
| 5603 | '(org-code org-verbatim underline))) | ||
| 5604 | (progn | ||
| 5605 | (setq rtn t | ||
| 5606 | d (cond ((member (char-after (1+ (match-beginning 0))) | ||
| 5607 | '(?_ ?^)) 1) | ||
| 5608 | (t 0))) | ||
| 5609 | (font-lock-prepend-text-property | ||
| 5610 | (+ d (match-beginning 0)) (match-end 0) | ||
| 5611 | 'face 'org-latex-and-export-specials) | ||
| 5612 | (add-text-properties (+ d (match-beginning 0)) (match-end 0) | ||
| 5613 | '(font-lock-multiline t))))) | ||
| 5614 | rtn))) | ||
| 5615 | |||
| 5616 | (defun org-restart-font-lock () | ||
| 5617 | "Restart font-lock-mode, to force refontification." | ||
| 5618 | (when (and (boundp 'font-lock-mode) font-lock-mode) | ||
| 5619 | (font-lock-mode -1) | ||
| 5620 | (font-lock-mode 1))) | ||
| 5621 | |||
| 5622 | (defun org-all-targets (&optional radio) | ||
| 5623 | "Return a list of all targets in this file. | ||
| 5624 | With optional argument RADIO, only find radio targets." | ||
| 5625 | (let ((re (if radio org-radio-target-regexp org-target-regexp)) | ||
| 5626 | rtn) | ||
| 5627 | (save-excursion | ||
| 5628 | (goto-char (point-min)) | ||
| 5629 | (while (re-search-forward re nil t) | ||
| 5630 | (add-to-list 'rtn (downcase (org-match-string-no-properties 1)))) | ||
| 5631 | rtn))) | ||
| 5632 | |||
| 5633 | (defun org-make-target-link-regexp (targets) | ||
| 5634 | "Make regular expression matching all strings in TARGETS. | ||
| 5635 | The regular expression finds the targets also if there is a line break | ||
| 5636 | between words." | ||
| 5637 | (and targets | ||
| 5638 | (concat | ||
| 5639 | "\\<\\(" | ||
| 5640 | (mapconcat | ||
| 5641 | (lambda (x) | ||
| 5642 | (while (string-match " +" x) | ||
| 5643 | (setq x (replace-match "\\s-+" t t x))) | ||
| 5644 | x) | ||
| 5645 | targets | ||
| 5646 | "\\|") | ||
| 5647 | "\\)\\>"))) | ||
| 5648 | |||
| 5649 | (defun org-activate-tags (limit) | ||
| 5650 | (if (re-search-forward (org-re "^\\*+.*[ \t]\\(:[[:alnum:]_@:]+:\\)[ \r\n]") limit t) | ||
| 5651 | (progn | ||
| 5652 | (add-text-properties (match-beginning 1) (match-end 1) | ||
| 5653 | (list 'mouse-face 'highlight | ||
| 5654 | 'rear-nonsticky org-nonsticky-props | ||
| 5655 | 'keymap org-mouse-map)) | ||
| 5656 | t))) | ||
| 5657 | |||
| 5658 | (defun org-outline-level () | ||
| 5659 | (save-excursion | ||
| 5660 | (looking-at outline-regexp) | ||
| 5661 | (if (match-beginning 1) | ||
| 5662 | (+ (org-get-string-indentation (match-string 1)) 1000) | ||
| 5663 | (1- (- (match-end 0) (match-beginning 0)))))) | ||
| 5664 | |||
| 5665 | (defvar org-font-lock-keywords nil) | ||
| 5666 | |||
| 5667 | (defconst org-property-re (org-re "^[ \t]*\\(:\\([[:alnum:]_]+\\):\\)[ \t]*\\(\\S-.*\\)") | ||
| 5668 | "Regular expression matching a property line.") | ||
| 5669 | |||
| 5670 | (defun org-set-font-lock-defaults () | ||
| 5671 | (let* ((em org-fontify-emphasized-text) | ||
| 5672 | (lk org-activate-links) | ||
| 5673 | (org-font-lock-extra-keywords | ||
| 5674 | (list | ||
| 5675 | ;; Headlines | ||
| 5676 | '("^\\(\\**\\)\\(\\* \\)\\(.*\\)" (1 (org-get-level-face 1)) | ||
| 5677 | (2 (org-get-level-face 2)) (3 (org-get-level-face 3))) | ||
| 5678 | ;; Table lines | ||
| 5679 | '("^[ \t]*\\(\\(|\\|\\+-[-+]\\).*\\S-\\)" | ||
| 5680 | (1 'org-table t)) | ||
| 5681 | ;; Table internals | ||
| 5682 | '("^[ \t]*|\\(?:.*?|\\)? *\\(:?=[^|\n]*\\)" (1 'org-formula t)) | ||
| 5683 | '("^[ \t]*| *\\([#*]\\) *|" (1 'org-formula t)) | ||
| 5684 | '("^[ \t]*|\\( *\\([$!_^/]\\) *|.*\\)|" (1 'org-formula t)) | ||
| 5685 | ;; Drawers | ||
| 5686 | (list org-drawer-regexp '(0 'org-special-keyword t)) | ||
| 5687 | (list "^[ \t]*:END:" '(0 'org-special-keyword t)) | ||
| 5688 | ;; Properties | ||
| 5689 | (list org-property-re | ||
| 5690 | '(1 'org-special-keyword t) | ||
| 5691 | '(3 'org-property-value t)) | ||
| 5692 | (if org-format-transports-properties-p | ||
| 5693 | '("| *\\(<[0-9]+>\\) *" (1 'org-formula t))) | ||
| 5694 | ;; Links | ||
| 5695 | (if (memq 'tag lk) '(org-activate-tags (1 'org-tag prepend))) | ||
| 5696 | (if (memq 'angle lk) '(org-activate-angle-links (0 'org-link t))) | ||
| 5697 | (if (memq 'plain lk) '(org-activate-plain-links (0 'org-link t))) | ||
| 5698 | (if (memq 'bracket lk) '(org-activate-bracket-links (0 'org-link t))) | ||
| 5699 | (if (memq 'radio lk) '(org-activate-target-links (0 'org-link t))) | ||
| 5700 | (if (memq 'date lk) '(org-activate-dates (0 'org-date t))) | ||
| 5701 | '("^&?%%(.*\\|<%%([^>\n]*?>" (0 'org-sexp-date t)) | ||
| 5702 | '(org-hide-wide-columns (0 nil append)) | ||
| 5703 | ;; TODO lines | ||
| 5704 | (list (concat "^\\*+[ \t]+" org-todo-regexp) | ||
| 5705 | '(1 (org-get-todo-face 1) t)) | ||
| 5706 | ;; DONE | ||
| 5707 | (if org-fontify-done-headline | ||
| 5708 | (list (concat "^[*]+ +\\<\\(" | ||
| 5709 | (mapconcat 'regexp-quote org-done-keywords "\\|") | ||
| 5710 | "\\)\\(.*\\)") | ||
| 5711 | '(2 'org-headline-done t)) | ||
| 5712 | nil) | ||
| 5713 | ;; Priorities | ||
| 5714 | (list (concat "\\[#[A-Z0-9]\\]") '(0 'org-special-keyword t)) | ||
| 5715 | ;; Special keywords | ||
| 5716 | (list (concat "\\<" org-deadline-string) '(0 'org-special-keyword t)) | ||
| 5717 | (list (concat "\\<" org-scheduled-string) '(0 'org-special-keyword t)) | ||
| 5718 | (list (concat "\\<" org-closed-string) '(0 'org-special-keyword t)) | ||
| 5719 | (list (concat "\\<" org-clock-string) '(0 'org-special-keyword t)) | ||
| 5720 | ;; Emphasis | ||
| 5721 | (if em | ||
| 5722 | (if (featurep 'xemacs) | ||
| 5723 | '(org-do-emphasis-faces (0 nil append)) | ||
| 5724 | '(org-do-emphasis-faces))) | ||
| 5725 | ;; Checkboxes | ||
| 5726 | '("^[ \t]*\\([-+*]\\|[0-9]+[.)]\\) +\\(\\[[- X]\\]\\)" | ||
| 5727 | 2 'bold prepend) | ||
| 5728 | (if org-provide-checkbox-statistics | ||
| 5729 | '("\\[\\([0-9]*%\\)\\]\\|\\[\\([0-9]*\\)/\\([0-9]*\\)\\]" | ||
| 5730 | (0 (org-get-checkbox-statistics-face) t))) | ||
| 5731 | (list (concat "^\\*+ \\(.*:" org-archive-tag ":.*\\)") | ||
| 5732 | '(1 'org-archived prepend)) | ||
| 5733 | ;; Specials | ||
| 5734 | '(org-do-latex-and-special-faces) | ||
| 5735 | ;; Code | ||
| 5736 | '(org-activate-code (1 'org-code t)) | ||
| 5737 | ;; COMMENT | ||
| 5738 | (list (concat "^\\*+[ \t]+\\<\\(" org-comment-string | ||
| 5739 | "\\|" org-quote-string "\\)\\>") | ||
| 5740 | '(1 'org-special-keyword t)) | ||
| 5741 | '("^#.*" (0 'font-lock-comment-face t)) | ||
| 5742 | ))) | ||
| 5743 | (setq org-font-lock-extra-keywords (delq nil org-font-lock-extra-keywords)) | ||
| 5744 | ;; Now set the full font-lock-keywords | ||
| 5745 | (org-set-local 'org-font-lock-keywords org-font-lock-extra-keywords) | ||
| 5746 | (org-set-local 'font-lock-defaults | ||
| 5747 | '(org-font-lock-keywords t nil nil backward-paragraph)) | ||
| 5748 | (kill-local-variable 'font-lock-keywords) nil)) | ||
| 5749 | |||
| 5750 | (defvar org-m nil) | ||
| 5751 | (defvar org-l nil) | ||
| 5752 | (defvar org-f nil) | ||
| 5753 | (defun org-get-level-face (n) | ||
| 5754 | "Get the right face for match N in font-lock matching of healdines." | ||
| 5755 | (setq org-l (- (match-end 2) (match-beginning 1) 1)) | ||
| 5756 | (if org-odd-levels-only (setq org-l (1+ (/ org-l 2)))) | ||
| 5757 | (setq org-f (nth (% (1- org-l) org-n-level-faces) org-level-faces)) | ||
| 5758 | (cond | ||
| 5759 | ((eq n 1) (if org-hide-leading-stars 'org-hide org-f)) | ||
| 5760 | ((eq n 2) org-f) | ||
| 5761 | (t (if org-level-color-stars-only nil org-f)))) | ||
| 5762 | |||
| 5763 | (defun org-get-todo-face (kwd) | ||
| 5764 | "Get the right face for a TODO keyword KWD. | ||
| 5765 | If KWD is a number, get the corresponding match group." | ||
| 5766 | (if (numberp kwd) (setq kwd (match-string kwd))) | ||
| 5767 | (or (cdr (assoc kwd org-todo-keyword-faces)) | ||
| 5768 | (and (member kwd org-done-keywords) 'org-done) | ||
| 5769 | 'org-todo)) | ||
| 5770 | |||
| 5771 | (defun org-unfontify-region (beg end &optional maybe_loudly) | ||
| 5772 | "Remove fontification and activation overlays from links." | ||
| 5773 | (font-lock-default-unfontify-region beg end) | ||
| 5774 | (let* ((buffer-undo-list t) | ||
| 5775 | (inhibit-read-only t) (inhibit-point-motion-hooks t) | ||
| 5776 | (inhibit-modification-hooks t) | ||
| 5777 | deactivate-mark buffer-file-name buffer-file-truename) | ||
| 5778 | (remove-text-properties beg end | ||
| 5779 | '(mouse-face t keymap t org-linked-text t | ||
| 5780 | invisible t intangible t)))) | ||
| 5781 | |||
| 5782 | ;;;; Visibility cycling, including org-goto and indirect buffer | ||
| 5783 | |||
| 5784 | ;;; Cycling | ||
| 5785 | |||
| 5786 | (defvar org-cycle-global-status nil) | ||
| 5787 | (make-variable-buffer-local 'org-cycle-global-status) | ||
| 5788 | (defvar org-cycle-subtree-status nil) | ||
| 5789 | (make-variable-buffer-local 'org-cycle-subtree-status) | ||
| 5790 | |||
| 5791 | ;;;###autoload | ||
| 5792 | (defun org-cycle (&optional arg) | ||
| 5793 | "Visibility cycling for Org-mode. | ||
| 5794 | |||
| 5795 | - When this function is called with a prefix argument, rotate the entire | ||
| 5796 | buffer through 3 states (global cycling) | ||
| 5797 | 1. OVERVIEW: Show only top-level headlines. | ||
| 5798 | 2. CONTENTS: Show all headlines of all levels, but no body text. | ||
| 5799 | 3. SHOW ALL: Show everything. | ||
| 5800 | |||
| 5801 | - When point is at the beginning of a headline, rotate the subtree started | ||
| 5802 | by this line through 3 different states (local cycling) | ||
| 5803 | 1. FOLDED: Only the main headline is shown. | ||
| 5804 | 2. CHILDREN: The main headline and the direct children are shown. | ||
| 5805 | From this state, you can move to one of the children | ||
| 5806 | and zoom in further. | ||
| 5807 | 3. SUBTREE: Show the entire subtree, including body text. | ||
| 5808 | |||
| 5809 | - When there is a numeric prefix, go up to a heading with level ARG, do | ||
| 5810 | a `show-subtree' and return to the previous cursor position. If ARG | ||
| 5811 | is negative, go up that many levels. | ||
| 5812 | |||
| 5813 | - When point is not at the beginning of a headline, execute | ||
| 5814 | `indent-relative', like TAB normally does. See the option | ||
| 5815 | `org-cycle-emulate-tab' for details. | ||
| 5816 | |||
| 5817 | - Special case: if point is at the beginning of the buffer and there is | ||
| 5818 | no headline in line 1, this function will act as if called with prefix arg. | ||
| 5819 | But only if also the variable `org-cycle-global-at-bob' is t." | ||
| 5820 | (interactive "P") | ||
| 5821 | (let* ((outline-regexp | ||
| 5822 | (if (and (org-mode-p) org-cycle-include-plain-lists) | ||
| 5823 | "\\(?:\\*+ \\|\\([ \t]*\\)\\([-+*]\\|[0-9]+[.)]\\) \\)" | ||
| 5824 | outline-regexp)) | ||
| 5825 | (bob-special (and org-cycle-global-at-bob (bobp) | ||
| 5826 | (not (looking-at outline-regexp)))) | ||
| 5827 | (org-cycle-hook | ||
| 5828 | (if bob-special | ||
| 5829 | (delq 'org-optimize-window-after-visibility-change | ||
| 5830 | (copy-sequence org-cycle-hook)) | ||
| 5831 | org-cycle-hook)) | ||
| 5832 | (pos (point))) | ||
| 5833 | |||
| 5834 | (if (or bob-special (equal arg '(4))) | ||
| 5835 | ;; special case: use global cycling | ||
| 5836 | (setq arg t)) | ||
| 5837 | |||
| 5838 | (cond | ||
| 5839 | |||
| 5840 | ((org-at-table-p 'any) | ||
| 5841 | ;; Enter the table or move to the next field in the table | ||
| 5842 | (or (org-table-recognize-table.el) | ||
| 5843 | (progn | ||
| 5844 | (if arg (org-table-edit-field t) | ||
| 5845 | (org-table-justify-field-maybe) | ||
| 5846 | (call-interactively 'org-table-next-field))))) | ||
| 5847 | |||
| 5848 | ((eq arg t) ;; Global cycling | ||
| 5849 | |||
| 5850 | (cond | ||
| 5851 | ((and (eq last-command this-command) | ||
| 5852 | (eq org-cycle-global-status 'overview)) | ||
| 5853 | ;; We just created the overview - now do table of contents | ||
| 5854 | ;; This can be slow in very large buffers, so indicate action | ||
| 5855 | (message "CONTENTS...") | ||
| 5856 | (org-content) | ||
| 5857 | (message "CONTENTS...done") | ||
| 5858 | (setq org-cycle-global-status 'contents) | ||
| 5859 | (run-hook-with-args 'org-cycle-hook 'contents)) | ||
| 5860 | |||
| 5861 | ((and (eq last-command this-command) | ||
| 5862 | (eq org-cycle-global-status 'contents)) | ||
| 5863 | ;; We just showed the table of contents - now show everything | ||
| 5864 | (show-all) | ||
| 5865 | (message "SHOW ALL") | ||
| 5866 | (setq org-cycle-global-status 'all) | ||
| 5867 | (run-hook-with-args 'org-cycle-hook 'all)) | ||
| 5868 | |||
| 5869 | (t | ||
| 5870 | ;; Default action: go to overview | ||
| 5871 | (org-overview) | ||
| 5872 | (message "OVERVIEW") | ||
| 5873 | (setq org-cycle-global-status 'overview) | ||
| 5874 | (run-hook-with-args 'org-cycle-hook 'overview)))) | ||
| 5875 | |||
| 5876 | ((and org-drawers org-drawer-regexp | ||
| 5877 | (save-excursion | ||
| 5878 | (beginning-of-line 1) | ||
| 5879 | (looking-at org-drawer-regexp))) | ||
| 5880 | ;; Toggle block visibility | ||
| 5881 | (org-flag-drawer | ||
| 5882 | (not (get-char-property (match-end 0) 'invisible)))) | ||
| 5883 | |||
| 5884 | ((integerp arg) | ||
| 5885 | ;; Show-subtree, ARG levels up from here. | ||
| 5886 | (save-excursion | ||
| 5887 | (org-back-to-heading) | ||
| 5888 | (outline-up-heading (if (< arg 0) (- arg) | ||
| 5889 | (- (funcall outline-level) arg))) | ||
| 5890 | (org-show-subtree))) | ||
| 5891 | |||
| 5892 | ((and (save-excursion (beginning-of-line 1) (looking-at outline-regexp)) | ||
| 5893 | (or (bolp) (not (eq org-cycle-emulate-tab 'exc-hl-bol)))) | ||
| 5894 | ;; At a heading: rotate between three different views | ||
| 5895 | (org-back-to-heading) | ||
| 5896 | (let ((goal-column 0) eoh eol eos) | ||
| 5897 | ;; First, some boundaries | ||
| 5898 | (save-excursion | ||
| 5899 | (org-back-to-heading) | ||
| 5900 | (save-excursion | ||
| 5901 | (beginning-of-line 2) | ||
| 5902 | (while (and (not (eobp)) ;; this is like `next-line' | ||
| 5903 | (get-char-property (1- (point)) 'invisible)) | ||
| 5904 | (beginning-of-line 2)) (setq eol (point))) | ||
| 5905 | (outline-end-of-heading) (setq eoh (point)) | ||
| 5906 | (org-end-of-subtree t) | ||
| 5907 | (unless (eobp) | ||
| 5908 | (skip-chars-forward " \t\n") | ||
| 5909 | (beginning-of-line 1) ; in case this is an item | ||
| 5910 | ) | ||
| 5911 | (setq eos (1- (point)))) | ||
| 5912 | ;; Find out what to do next and set `this-command' | ||
| 5913 | (cond | ||
| 5914 | ((= eos eoh) | ||
| 5915 | ;; Nothing is hidden behind this heading | ||
| 5916 | (message "EMPTY ENTRY") | ||
| 5917 | (setq org-cycle-subtree-status nil) | ||
| 5918 | (save-excursion | ||
| 5919 | (goto-char eos) | ||
| 5920 | (outline-next-heading) | ||
| 5921 | (if (org-invisible-p) (org-flag-heading nil)))) | ||
| 5922 | ((or (>= eol eos) | ||
| 5923 | (not (string-match "\\S-" (buffer-substring eol eos)))) | ||
| 5924 | ;; Entire subtree is hidden in one line: open it | ||
| 5925 | (org-show-entry) | ||
| 5926 | (show-children) | ||
| 5927 | (message "CHILDREN") | ||
| 5928 | (save-excursion | ||
| 5929 | (goto-char eos) | ||
| 5930 | (outline-next-heading) | ||
| 5931 | (if (org-invisible-p) (org-flag-heading nil))) | ||
| 5932 | (setq org-cycle-subtree-status 'children) | ||
| 5933 | (run-hook-with-args 'org-cycle-hook 'children)) | ||
| 5934 | ((and (eq last-command this-command) | ||
| 5935 | (eq org-cycle-subtree-status 'children)) | ||
| 5936 | ;; We just showed the children, now show everything. | ||
| 5937 | (org-show-subtree) | ||
| 5938 | (message "SUBTREE") | ||
| 5939 | (setq org-cycle-subtree-status 'subtree) | ||
| 5940 | (run-hook-with-args 'org-cycle-hook 'subtree)) | ||
| 5941 | (t | ||
| 5942 | ;; Default action: hide the subtree. | ||
| 5943 | (hide-subtree) | ||
| 5944 | (message "FOLDED") | ||
| 5945 | (setq org-cycle-subtree-status 'folded) | ||
| 5946 | (run-hook-with-args 'org-cycle-hook 'folded))))) | ||
| 5947 | |||
| 5948 | ;; TAB emulation | ||
| 5949 | (buffer-read-only (org-back-to-heading)) | ||
| 5950 | |||
| 5951 | ((org-try-cdlatex-tab)) | ||
| 5952 | |||
| 5953 | ((and (eq org-cycle-emulate-tab 'exc-hl-bol) | ||
| 5954 | (or (not (bolp)) | ||
| 5955 | (not (looking-at outline-regexp)))) | ||
| 5956 | (call-interactively (global-key-binding "\t"))) | ||
| 5957 | |||
| 5958 | ((if (and (memq org-cycle-emulate-tab '(white whitestart)) | ||
| 5959 | (save-excursion (beginning-of-line 1) (looking-at "[ \t]*")) | ||
| 5960 | (or (and (eq org-cycle-emulate-tab 'white) | ||
| 5961 | (= (match-end 0) (point-at-eol))) | ||
| 5962 | (and (eq org-cycle-emulate-tab 'whitestart) | ||
| 5963 | (>= (match-end 0) pos)))) | ||
| 5964 | t | ||
| 5965 | (eq org-cycle-emulate-tab t)) | ||
| 5966 | ; (if (and (looking-at "[ \n\r\t]") | ||
| 5967 | ; (string-match "^[ \t]*$" (buffer-substring | ||
| 5968 | ; (point-at-bol) (point)))) | ||
| 5969 | ; (progn | ||
| 5970 | ; (beginning-of-line 1) | ||
| 5971 | ; (and (looking-at "[ \t]+") (replace-match "")))) | ||
| 5972 | (call-interactively (global-key-binding "\t"))) | ||
| 5973 | |||
| 5974 | (t (save-excursion | ||
| 5975 | (org-back-to-heading) | ||
| 5976 | (org-cycle)))))) | ||
| 5977 | |||
| 5978 | ;;;###autoload | ||
| 5979 | (defun org-global-cycle (&optional arg) | ||
| 5980 | "Cycle the global visibility. For details see `org-cycle'." | ||
| 5981 | (interactive "P") | ||
| 5982 | (let ((org-cycle-include-plain-lists | ||
| 5983 | (if (org-mode-p) org-cycle-include-plain-lists nil))) | ||
| 5984 | (if (integerp arg) | ||
| 5985 | (progn | ||
| 5986 | (show-all) | ||
| 5987 | (hide-sublevels arg) | ||
| 5988 | (setq org-cycle-global-status 'contents)) | ||
| 5989 | (org-cycle '(4))))) | ||
| 5990 | |||
| 5991 | (defun org-overview () | ||
| 5992 | "Switch to overview mode, shoing only top-level headlines. | ||
| 5993 | Really, this shows all headlines with level equal or greater than the level | ||
| 5994 | of the first headline in the buffer. This is important, because if the | ||
| 5995 | first headline is not level one, then (hide-sublevels 1) gives confusing | ||
| 5996 | results." | ||
| 5997 | (interactive) | ||
| 5998 | (let ((level (save-excursion | ||
| 5999 | (goto-char (point-min)) | ||
| 6000 | (if (re-search-forward (concat "^" outline-regexp) nil t) | ||
| 6001 | (progn | ||
| 6002 | (goto-char (match-beginning 0)) | ||
| 6003 | (funcall outline-level)))))) | ||
| 6004 | (and level (hide-sublevels level)))) | ||
| 6005 | |||
| 6006 | (defun org-content (&optional arg) | ||
| 6007 | "Show all headlines in the buffer, like a table of contents. | ||
| 6008 | With numerical argument N, show content up to level N." | ||
| 6009 | (interactive "P") | ||
| 6010 | (save-excursion | ||
| 6011 | ;; Visit all headings and show their offspring | ||
| 6012 | (and (integerp arg) (org-overview)) | ||
| 6013 | (goto-char (point-max)) | ||
| 6014 | (catch 'exit | ||
| 6015 | (while (and (progn (condition-case nil | ||
| 6016 | (outline-previous-visible-heading 1) | ||
| 6017 | (error (goto-char (point-min)))) | ||
| 6018 | t) | ||
| 6019 | (looking-at outline-regexp)) | ||
| 6020 | (if (integerp arg) | ||
| 6021 | (show-children (1- arg)) | ||
| 6022 | (show-branches)) | ||
| 6023 | (if (bobp) (throw 'exit nil)))))) | ||
| 6024 | |||
| 6025 | |||
| 6026 | (defun org-optimize-window-after-visibility-change (state) | ||
| 6027 | "Adjust the window after a change in outline visibility. | ||
| 6028 | This function is the default value of the hook `org-cycle-hook'." | ||
| 6029 | (when (get-buffer-window (current-buffer)) | ||
| 6030 | (cond | ||
| 6031 | ; ((eq state 'overview) (org-first-headline-recenter 1)) | ||
| 6032 | ; ((eq state 'overview) (org-beginning-of-line)) | ||
| 6033 | ((eq state 'content) nil) | ||
| 6034 | ((eq state 'all) nil) | ||
| 6035 | ((eq state 'folded) nil) | ||
| 6036 | ((eq state 'children) (or (org-subtree-end-visible-p) (recenter 1))) | ||
| 6037 | ((eq state 'subtree) (or (org-subtree-end-visible-p) (recenter 1)))))) | ||
| 6038 | |||
| 6039 | (defun org-compact-display-after-subtree-move () | ||
| 6040 | (let (beg end) | ||
| 6041 | (save-excursion | ||
| 6042 | (if (org-up-heading-safe) | ||
| 6043 | (progn | ||
| 6044 | (hide-subtree) | ||
| 6045 | (show-entry) | ||
| 6046 | (show-children) | ||
| 6047 | (org-cycle-show-empty-lines 'children) | ||
| 6048 | (org-cycle-hide-drawers 'children)) | ||
| 6049 | (org-overview))))) | ||
| 6050 | |||
| 6051 | (defun org-cycle-show-empty-lines (state) | ||
| 6052 | "Show empty lines above all visible headlines. | ||
| 6053 | The region to be covered depends on STATE when called through | ||
| 6054 | `org-cycle-hook'. Lisp program can use t for STATE to get the | ||
| 6055 | entire buffer covered. Note that an empty line is only shown if there | ||
| 6056 | are at least `org-cycle-separator-lines' empty lines before the headeline." | ||
| 6057 | (when (> org-cycle-separator-lines 0) | ||
| 6058 | (save-excursion | ||
| 6059 | (let* ((n org-cycle-separator-lines) | ||
| 6060 | (re (cond | ||
| 6061 | ((= n 1) "\\(\n[ \t]*\n\\*+\\) ") | ||
| 6062 | ((= n 2) "^[ \t]*\\(\n[ \t]*\n\\*+\\) ") | ||
| 6063 | (t (let ((ns (number-to-string (- n 2)))) | ||
| 6064 | (concat "^\\(?:[ \t]*\n\\)\\{" ns "," ns "\\}" | ||
| 6065 | "[ \t]*\\(\n[ \t]*\n\\*+\\) "))))) | ||
| 6066 | beg end) | ||
| 6067 | (cond | ||
| 6068 | ((memq state '(overview contents t)) | ||
| 6069 | (setq beg (point-min) end (point-max))) | ||
| 6070 | ((memq state '(children folded)) | ||
| 6071 | (setq beg (point) end (progn (org-end-of-subtree t t) | ||
| 6072 | (beginning-of-line 2) | ||
| 6073 | (point))))) | ||
| 6074 | (when beg | ||
| 6075 | (goto-char beg) | ||
| 6076 | (while (re-search-forward re end t) | ||
| 6077 | (if (not (get-char-property (match-end 1) 'invisible)) | ||
| 6078 | (outline-flag-region | ||
| 6079 | (match-beginning 1) (match-end 1) nil))))))) | ||
| 6080 | ;; Never hide empty lines at the end of the file. | ||
| 6081 | (save-excursion | ||
| 6082 | (goto-char (point-max)) | ||
| 6083 | (outline-previous-heading) | ||
| 6084 | (outline-end-of-heading) | ||
| 6085 | (if (and (looking-at "[ \t\n]+") | ||
| 6086 | (= (match-end 0) (point-max))) | ||
| 6087 | (outline-flag-region (point) (match-end 0) nil)))) | ||
| 6088 | |||
| 6089 | (defun org-subtree-end-visible-p () | ||
| 6090 | "Is the end of the current subtree visible?" | ||
| 6091 | (pos-visible-in-window-p | ||
| 6092 | (save-excursion (org-end-of-subtree t) (point)))) | ||
| 6093 | |||
| 6094 | (defun org-first-headline-recenter (&optional N) | ||
| 6095 | "Move cursor to the first headline and recenter the headline. | ||
| 6096 | Optional argument N means, put the headline into the Nth line of the window." | ||
| 6097 | (goto-char (point-min)) | ||
| 6098 | (when (re-search-forward (concat "^\\(" outline-regexp "\\)") nil t) | ||
| 6099 | (beginning-of-line) | ||
| 6100 | (recenter (prefix-numeric-value N)))) | ||
| 6101 | |||
| 6102 | ;;; Org-goto | ||
| 6103 | |||
| 6104 | (defvar org-goto-window-configuration nil) | ||
| 6105 | (defvar org-goto-marker nil) | ||
| 6106 | (defvar org-goto-map | ||
| 6107 | (let ((map (make-sparse-keymap))) | ||
| 6108 | (let ((cmds '(isearch-forward isearch-backward kill-ring-save set-mark-command mouse-drag-region universal-argument org-occur)) cmd) | ||
| 6109 | (while (setq cmd (pop cmds)) | ||
| 6110 | (substitute-key-definition cmd cmd map global-map))) | ||
| 6111 | (suppress-keymap map) | ||
| 6112 | (org-defkey map "\C-m" 'org-goto-ret) | ||
| 6113 | (org-defkey map [(return)] 'org-goto-ret) | ||
| 6114 | (org-defkey map [(left)] 'org-goto-left) | ||
| 6115 | (org-defkey map [(right)] 'org-goto-right) | ||
| 6116 | (org-defkey map [(control ?g)] 'org-goto-quit) | ||
| 6117 | (org-defkey map "\C-i" 'org-cycle) | ||
| 6118 | (org-defkey map [(tab)] 'org-cycle) | ||
| 6119 | (org-defkey map [(down)] 'outline-next-visible-heading) | ||
| 6120 | (org-defkey map [(up)] 'outline-previous-visible-heading) | ||
| 6121 | (if org-goto-auto-isearch | ||
| 6122 | (if (fboundp 'define-key-after) | ||
| 6123 | (define-key-after map [t] 'org-goto-local-auto-isearch) | ||
| 6124 | nil) | ||
| 6125 | (org-defkey map "q" 'org-goto-quit) | ||
| 6126 | (org-defkey map "n" 'outline-next-visible-heading) | ||
| 6127 | (org-defkey map "p" 'outline-previous-visible-heading) | ||
| 6128 | (org-defkey map "f" 'outline-forward-same-level) | ||
| 6129 | (org-defkey map "b" 'outline-backward-same-level) | ||
| 6130 | (org-defkey map "u" 'outline-up-heading)) | ||
| 6131 | (org-defkey map "/" 'org-occur) | ||
| 6132 | (org-defkey map "\C-c\C-n" 'outline-next-visible-heading) | ||
| 6133 | (org-defkey map "\C-c\C-p" 'outline-previous-visible-heading) | ||
| 6134 | (org-defkey map "\C-c\C-f" 'outline-forward-same-level) | ||
| 6135 | (org-defkey map "\C-c\C-b" 'outline-backward-same-level) | ||
| 6136 | (org-defkey map "\C-c\C-u" 'outline-up-heading) | ||
| 6137 | map)) | ||
| 6138 | |||
| 6139 | (defconst org-goto-help | ||
| 6140 | "Browse buffer copy, to find location or copy text. Just type for auto-isearch. | ||
| 6141 | RET=jump to location [Q]uit and return to previous location | ||
| 6142 | \[Up]/[Down]=next/prev headline TAB=cycle visibility [/] org-occur") | ||
| 6143 | |||
| 6144 | (defvar org-goto-start-pos) ; dynamically scoped parameter | ||
| 6145 | |||
| 6146 | (defun org-goto (&optional alternative-interface) | ||
| 6147 | "Look up a different location in the current file, keeping current visibility. | ||
| 6148 | |||
| 6149 | When you want look-up or go to a different location in a document, the | ||
| 6150 | fastest way is often to fold the entire buffer and then dive into the tree. | ||
| 6151 | This method has the disadvantage, that the previous location will be folded, | ||
| 6152 | which may not be what you want. | ||
| 6153 | |||
| 6154 | This command works around this by showing a copy of the current buffer | ||
| 6155 | in an indirect buffer, in overview mode. You can dive into the tree in | ||
| 6156 | that copy, use org-occur and incremental search to find a location. | ||
| 6157 | When pressing RET or `Q', the command returns to the original buffer in | ||
| 6158 | which the visibility is still unchanged. After RET is will also jump to | ||
| 6159 | the location selected in the indirect buffer and expose the | ||
| 6160 | the headline hierarchy above." | ||
| 6161 | (interactive "P") | ||
| 6162 | (let* ((org-refile-targets '((nil . (:maxlevel . 10)))) | ||
| 6163 | (org-refile-use-outline-path t) | ||
| 6164 | (interface | ||
| 6165 | (if (not alternative-interface) | ||
| 6166 | org-goto-interface | ||
| 6167 | (if (eq org-goto-interface 'outline) | ||
| 6168 | 'outline-path-completion | ||
| 6169 | 'outline))) | ||
| 6170 | (org-goto-start-pos (point)) | ||
| 6171 | (selected-point | ||
| 6172 | (if (eq interface 'outline) | ||
| 6173 | (car (org-get-location (current-buffer) org-goto-help)) | ||
| 6174 | (nth 3 (org-refile-get-location "Goto: "))))) | ||
| 6175 | (if selected-point | ||
| 6176 | (progn | ||
| 6177 | (org-mark-ring-push org-goto-start-pos) | ||
| 6178 | (goto-char selected-point) | ||
| 6179 | (if (or (org-invisible-p) (org-invisible-p2)) | ||
| 6180 | (org-show-context 'org-goto))) | ||
| 6181 | (message "Quit")))) | ||
| 6182 | |||
| 6183 | (defvar org-goto-selected-point nil) ; dynamically scoped parameter | ||
| 6184 | (defvar org-goto-exit-command nil) ; dynamically scoped parameter | ||
| 6185 | (defvar org-goto-local-auto-isearch-map) ; defined below | ||
| 6186 | |||
| 6187 | (defun org-get-location (buf help) | ||
| 6188 | "Let the user select a location in the Org-mode buffer BUF. | ||
| 6189 | This function uses a recursive edit. It returns the selected position | ||
| 6190 | or nil." | ||
| 6191 | (let ((isearch-mode-map org-goto-local-auto-isearch-map) | ||
| 6192 | (isearch-hide-immediately nil) | ||
| 6193 | (isearch-search-fun-function | ||
| 6194 | (lambda () 'org-goto-local-search-forward-headings)) | ||
| 6195 | (org-goto-selected-point org-goto-exit-command)) | ||
| 6196 | (save-excursion | ||
| 6197 | (save-window-excursion | ||
| 6198 | (delete-other-windows) | ||
| 6199 | (and (get-buffer "*org-goto*") (kill-buffer "*org-goto*")) | ||
| 6200 | (switch-to-buffer | ||
| 6201 | (condition-case nil | ||
| 6202 | (make-indirect-buffer (current-buffer) "*org-goto*") | ||
| 6203 | (error (make-indirect-buffer (current-buffer) "*org-goto*")))) | ||
| 6204 | (with-output-to-temp-buffer "*Help*" | ||
| 6205 | (princ help)) | ||
| 6206 | (shrink-window-if-larger-than-buffer (get-buffer-window "*Help*")) | ||
| 6207 | (setq buffer-read-only nil) | ||
| 6208 | (let ((org-startup-truncated t) | ||
| 6209 | (org-startup-folded nil) | ||
| 6210 | (org-startup-align-all-tables nil)) | ||
| 6211 | (org-mode) | ||
| 6212 | (org-overview)) | ||
| 6213 | (setq buffer-read-only t) | ||
| 6214 | (if (and (boundp 'org-goto-start-pos) | ||
| 6215 | (integer-or-marker-p org-goto-start-pos)) | ||
| 6216 | (let ((org-show-hierarchy-above t) | ||
| 6217 | (org-show-siblings t) | ||
| 6218 | (org-show-following-heading t)) | ||
| 6219 | (goto-char org-goto-start-pos) | ||
| 6220 | (and (org-invisible-p) (org-show-context))) | ||
| 6221 | (goto-char (point-min))) | ||
| 6222 | (org-beginning-of-line) | ||
| 6223 | (message "Select location and press RET") | ||
| 6224 | (use-local-map org-goto-map) | ||
| 6225 | (recursive-edit) | ||
| 6226 | )) | ||
| 6227 | (kill-buffer "*org-goto*") | ||
| 6228 | (cons org-goto-selected-point org-goto-exit-command))) | ||
| 6229 | |||
| 6230 | (defvar org-goto-local-auto-isearch-map (make-sparse-keymap)) | ||
| 6231 | (set-keymap-parent org-goto-local-auto-isearch-map isearch-mode-map) | ||
| 6232 | (define-key org-goto-local-auto-isearch-map "\C-i" 'isearch-other-control-char) | ||
| 6233 | (define-key org-goto-local-auto-isearch-map "\C-m" 'isearch-other-control-char) | ||
| 6234 | |||
| 6235 | (defun org-goto-local-search-forward-headings (string bound noerror) | ||
| 6236 | "Search and make sure that anu matches are in headlines." | ||
| 6237 | (catch 'return | ||
| 6238 | (while (search-forward string bound noerror) | ||
| 6239 | (when (let ((context (mapcar 'car (save-match-data (org-context))))) | ||
| 6240 | (and (member :headline context) | ||
| 6241 | (not (member :tags context)))) | ||
| 6242 | (throw 'return (point)))))) | ||
| 6243 | |||
| 6244 | (defun org-goto-local-auto-isearch () | ||
| 6245 | "Start isearch." | ||
| 6246 | (interactive) | ||
| 6247 | (goto-char (point-min)) | ||
| 6248 | (let ((keys (this-command-keys))) | ||
| 6249 | (when (eq (lookup-key isearch-mode-map keys) 'isearch-printing-char) | ||
| 6250 | (isearch-mode t) | ||
| 6251 | (isearch-process-search-char (string-to-char keys))))) | ||
| 6252 | |||
| 6253 | (defun org-goto-ret (&optional arg) | ||
| 6254 | "Finish `org-goto' by going to the new location." | ||
| 6255 | (interactive "P") | ||
| 6256 | (setq org-goto-selected-point (point) | ||
| 6257 | org-goto-exit-command 'return) | ||
| 6258 | (throw 'exit nil)) | ||
| 6259 | |||
| 6260 | (defun org-goto-left () | ||
| 6261 | "Finish `org-goto' by going to the new location." | ||
| 6262 | (interactive) | ||
| 6263 | (if (org-on-heading-p) | ||
| 6264 | (progn | ||
| 6265 | (beginning-of-line 1) | ||
| 6266 | (setq org-goto-selected-point (point) | ||
| 6267 | org-goto-exit-command 'left) | ||
| 6268 | (throw 'exit nil)) | ||
| 6269 | (error "Not on a heading"))) | ||
| 6270 | |||
| 6271 | (defun org-goto-right () | ||
| 6272 | "Finish `org-goto' by going to the new location." | ||
| 6273 | (interactive) | ||
| 6274 | (if (org-on-heading-p) | ||
| 6275 | (progn | ||
| 6276 | (setq org-goto-selected-point (point) | ||
| 6277 | org-goto-exit-command 'right) | ||
| 6278 | (throw 'exit nil)) | ||
| 6279 | (error "Not on a heading"))) | ||
| 6280 | |||
| 6281 | (defun org-goto-quit () | ||
| 6282 | "Finish `org-goto' without cursor motion." | ||
| 6283 | (interactive) | ||
| 6284 | (setq org-goto-selected-point nil) | ||
| 6285 | (setq org-goto-exit-command 'quit) | ||
| 6286 | (throw 'exit nil)) | ||
| 6287 | |||
| 6288 | ;;; Indirect buffer display of subtrees | ||
| 6289 | |||
| 6290 | (defvar org-indirect-dedicated-frame nil | ||
| 6291 | "This is the frame being used for indirect tree display.") | ||
| 6292 | (defvar org-last-indirect-buffer nil) | ||
| 6293 | |||
| 6294 | (defun org-tree-to-indirect-buffer (&optional arg) | ||
| 6295 | "Create indirect buffer and narrow it to current subtree. | ||
| 6296 | With numerical prefix ARG, go up to this level and then take that tree. | ||
| 6297 | If ARG is negative, go up that many levels. | ||
| 6298 | If `org-indirect-buffer-display' is not `new-frame', the command removes the | ||
| 6299 | indirect buffer previously made with this command, to avoid proliferation of | ||
| 6300 | indirect buffers. However, when you call the command with a `C-u' prefix, or | ||
| 6301 | when `org-indirect-buffer-display' is `new-frame', the last buffer | ||
| 6302 | is kept so that you can work with several indirect buffers at the same time. | ||
| 6303 | If `org-indirect-buffer-display' is `dedicated-frame', the C-u prefix also | ||
| 6304 | requests that a new frame be made for the new buffer, so that the dedicated | ||
| 6305 | frame is not changed." | ||
| 6306 | (interactive "P") | ||
| 6307 | (let ((cbuf (current-buffer)) | ||
| 6308 | (cwin (selected-window)) | ||
| 6309 | (pos (point)) | ||
| 6310 | beg end level heading ibuf) | ||
| 6311 | (save-excursion | ||
| 6312 | (org-back-to-heading t) | ||
| 6313 | (when (numberp arg) | ||
| 6314 | (setq level (org-outline-level)) | ||
| 6315 | (if (< arg 0) (setq arg (+ level arg))) | ||
| 6316 | (while (> (setq level (org-outline-level)) arg) | ||
| 6317 | (outline-up-heading 1 t))) | ||
| 6318 | (setq beg (point) | ||
| 6319 | heading (org-get-heading)) | ||
| 6320 | (org-end-of-subtree t) (setq end (point))) | ||
| 6321 | (if (and (buffer-live-p org-last-indirect-buffer) | ||
| 6322 | (not (eq org-indirect-buffer-display 'new-frame)) | ||
| 6323 | (not arg)) | ||
| 6324 | (kill-buffer org-last-indirect-buffer)) | ||
| 6325 | (setq ibuf (org-get-indirect-buffer cbuf) | ||
| 6326 | org-last-indirect-buffer ibuf) | ||
| 6327 | (cond | ||
| 6328 | ((or (eq org-indirect-buffer-display 'new-frame) | ||
| 6329 | (and arg (eq org-indirect-buffer-display 'dedicated-frame))) | ||
| 6330 | (select-frame (make-frame)) | ||
| 6331 | (delete-other-windows) | ||
| 6332 | (switch-to-buffer ibuf) | ||
| 6333 | (org-set-frame-title heading)) | ||
| 6334 | ((eq org-indirect-buffer-display 'dedicated-frame) | ||
| 6335 | (raise-frame | ||
| 6336 | (select-frame (or (and org-indirect-dedicated-frame | ||
| 6337 | (frame-live-p org-indirect-dedicated-frame) | ||
| 6338 | org-indirect-dedicated-frame) | ||
| 6339 | (setq org-indirect-dedicated-frame (make-frame))))) | ||
| 6340 | (delete-other-windows) | ||
| 6341 | (switch-to-buffer ibuf) | ||
| 6342 | (org-set-frame-title (concat "Indirect: " heading))) | ||
| 6343 | ((eq org-indirect-buffer-display 'current-window) | ||
| 6344 | (switch-to-buffer ibuf)) | ||
| 6345 | ((eq org-indirect-buffer-display 'other-window) | ||
| 6346 | (pop-to-buffer ibuf)) | ||
| 6347 | (t (error "Invalid value."))) | ||
| 6348 | (if (featurep 'xemacs) | ||
| 6349 | (save-excursion (org-mode) (turn-on-font-lock))) | ||
| 6350 | (narrow-to-region beg end) | ||
| 6351 | (show-all) | ||
| 6352 | (goto-char pos) | ||
| 6353 | (and (window-live-p cwin) (select-window cwin)))) | ||
| 6354 | |||
| 6355 | (defun org-get-indirect-buffer (&optional buffer) | ||
| 6356 | (setq buffer (or buffer (current-buffer))) | ||
| 6357 | (let ((n 1) (base (buffer-name buffer)) bname) | ||
| 6358 | (while (buffer-live-p | ||
| 6359 | (get-buffer (setq bname (concat base "-" (number-to-string n))))) | ||
| 6360 | (setq n (1+ n))) | ||
| 6361 | (condition-case nil | ||
| 6362 | (make-indirect-buffer buffer bname 'clone) | ||
| 6363 | (error (make-indirect-buffer buffer bname))))) | ||
| 6364 | |||
| 6365 | (defun org-set-frame-title (title) | ||
| 6366 | "Set the title of the current frame to the string TITLE." | ||
| 6367 | ;; FIXME: how to name a single frame in XEmacs??? | ||
| 6368 | (unless (featurep 'xemacs) | ||
| 6369 | (modify-frame-parameters (selected-frame) (list (cons 'name title))))) | ||
| 6370 | |||
| 6371 | ;;;; Structure editing | ||
| 6372 | |||
| 6373 | ;;; Inserting headlines | ||
| 6374 | |||
| 6375 | (defun org-insert-heading (&optional force-heading) | ||
| 6376 | "Insert a new heading or item with same depth at point. | ||
| 6377 | If point is in a plain list and FORCE-HEADING is nil, create a new list item. | ||
| 6378 | If point is at the beginning of a headline, insert a sibling before the | ||
| 6379 | current headline. If point is not at the beginning, do not split the line, | ||
| 6380 | but create the new hedline after the current line." | ||
| 6381 | (interactive "P") | ||
| 6382 | (if (= (buffer-size) 0) | ||
| 6383 | (insert "\n* ") | ||
| 6384 | (when (or force-heading (not (org-insert-item))) | ||
| 6385 | (let* ((head (save-excursion | ||
| 6386 | (condition-case nil | ||
| 6387 | (progn | ||
| 6388 | (org-back-to-heading) | ||
| 6389 | (match-string 0)) | ||
| 6390 | (error "*")))) | ||
| 6391 | (blank (cdr (assq 'heading org-blank-before-new-entry))) | ||
| 6392 | pos) | ||
| 6393 | (cond | ||
| 6394 | ((and (org-on-heading-p) (bolp) | ||
| 6395 | (or (bobp) | ||
| 6396 | (save-excursion (backward-char 1) (not (org-invisible-p))))) | ||
| 6397 | ;; insert before the current line | ||
| 6398 | (open-line (if blank 2 1))) | ||
| 6399 | ((and (bolp) | ||
| 6400 | (or (bobp) | ||
| 6401 | (save-excursion | ||
| 6402 | (backward-char 1) (not (org-invisible-p))))) | ||
| 6403 | ;; insert right here | ||
| 6404 | nil) | ||
| 6405 | (t | ||
| 6406 | ; ;; in the middle of the line | ||
| 6407 | ; (org-show-entry) | ||
| 6408 | ; (if (org-get-alist-option org-M-RET-may-split-line 'headline) | ||
| 6409 | ; (if (and | ||
| 6410 | ; (org-on-heading-p) | ||
| 6411 | ; (looking-at ".*?\\([ \t]+\\(:[[:alnum:]_@:]+:\\)\\)[ \r\n]")) | ||
| 6412 | ; ;; protect the tags | ||
| 6413 | ;; (let ((tags (match-string 2)) pos) | ||
| 6414 | ; (delete-region (match-beginning 1) (match-end 1)) | ||
| 6415 | ; (setq pos (point-at-bol)) | ||
| 6416 | ; (newline (if blank 2 1)) | ||
| 6417 | ; (save-excursion | ||
| 6418 | ; (goto-char pos) | ||
| 6419 | ; (end-of-line 1) | ||
| 6420 | ; (insert " " tags) | ||
| 6421 | ; (org-set-tags nil 'align))) | ||
| 6422 | ; (newline (if blank 2 1))) | ||
| 6423 | ; (newline (if blank 2 1)))) | ||
| 6424 | |||
| 6425 | |||
| 6426 | ;; in the middle of the line | ||
| 6427 | (org-show-entry) | ||
| 6428 | (let ((split | ||
| 6429 | (org-get-alist-option org-M-RET-may-split-line 'headline)) | ||
| 6430 | tags pos) | ||
| 6431 | (if (org-on-heading-p) | ||
| 6432 | (progn | ||
| 6433 | (looking-at ".*?\\([ \t]+\\(:[[:alnum:]_@:]+:\\)\\)?[ \t]*$") | ||
| 6434 | (setq tags (and (match-end 2) (match-string 2))) | ||
| 6435 | (and (match-end 1) | ||
| 6436 | (delete-region (match-beginning 1) (match-end 1))) | ||
| 6437 | (setq pos (point-at-bol)) | ||
| 6438 | (or split (end-of-line 1)) | ||
| 6439 | (delete-horizontal-space) | ||
| 6440 | (newline (if blank 2 1)) | ||
| 6441 | (when tags | ||
| 6442 | (save-excursion | ||
| 6443 | (goto-char pos) | ||
| 6444 | (end-of-line 1) | ||
| 6445 | (insert " " tags) | ||
| 6446 | (org-set-tags nil 'align)))) | ||
| 6447 | (or split (end-of-line 1)) | ||
| 6448 | (newline (if blank 2 1)))))) | ||
| 6449 | (insert head) (just-one-space) | ||
| 6450 | (setq pos (point)) | ||
| 6451 | (end-of-line 1) | ||
| 6452 | (unless (= (point) pos) (just-one-space) (backward-delete-char 1)) | ||
| 6453 | (run-hooks 'org-insert-heading-hook))))) | ||
| 6454 | |||
| 6455 | (defun org-insert-heading-after-current () | ||
| 6456 | "Insert a new heading with same level as current, after current subtree." | ||
| 6457 | (interactive) | ||
| 6458 | (org-back-to-heading) | ||
| 6459 | (org-insert-heading) | ||
| 6460 | (org-move-subtree-down) | ||
| 6461 | (end-of-line 1)) | ||
| 6462 | |||
| 6463 | (defun org-insert-todo-heading (arg) | ||
| 6464 | "Insert a new heading with the same level and TODO state as current heading. | ||
| 6465 | If the heading has no TODO state, or if the state is DONE, use the first | ||
| 6466 | state (TODO by default). Also with prefix arg, force first state." | ||
| 6467 | (interactive "P") | ||
| 6468 | (when (not (org-insert-item 'checkbox)) | ||
| 6469 | (org-insert-heading) | ||
| 6470 | (save-excursion | ||
| 6471 | (org-back-to-heading) | ||
| 6472 | (outline-previous-heading) | ||
| 6473 | (looking-at org-todo-line-regexp)) | ||
| 6474 | (if (or arg | ||
| 6475 | (not (match-beginning 2)) | ||
| 6476 | (member (match-string 2) org-done-keywords)) | ||
| 6477 | (insert (car org-todo-keywords-1) " ") | ||
| 6478 | (insert (match-string 2) " ")))) | ||
| 6479 | |||
| 6480 | (defun org-insert-subheading (arg) | ||
| 6481 | "Insert a new subheading and demote it. | ||
| 6482 | Works for outline headings and for plain lists alike." | ||
| 6483 | (interactive "P") | ||
| 6484 | (org-insert-heading arg) | ||
| 6485 | (cond | ||
| 6486 | ((org-on-heading-p) (org-do-demote)) | ||
| 6487 | ((org-at-item-p) (org-indent-item 1)))) | ||
| 6488 | |||
| 6489 | (defun org-insert-todo-subheading (arg) | ||
| 6490 | "Insert a new subheading with TODO keyword or checkbox and demote it. | ||
| 6491 | Works for outline headings and for plain lists alike." | ||
| 6492 | (interactive "P") | ||
| 6493 | (org-insert-todo-heading arg) | ||
| 6494 | (cond | ||
| 6495 | ((org-on-heading-p) (org-do-demote)) | ||
| 6496 | ((org-at-item-p) (org-indent-item 1)))) | ||
| 6497 | |||
| 6498 | ;;; Promotion and Demotion | ||
| 6499 | |||
| 6500 | (defun org-promote-subtree () | ||
| 6501 | "Promote the entire subtree. | ||
| 6502 | See also `org-promote'." | ||
| 6503 | (interactive) | ||
| 6504 | (save-excursion | ||
| 6505 | (org-map-tree 'org-promote)) | ||
| 6506 | (org-fix-position-after-promote)) | ||
| 6507 | |||
| 6508 | (defun org-demote-subtree () | ||
| 6509 | "Demote the entire subtree. See `org-demote'. | ||
| 6510 | See also `org-promote'." | ||
| 6511 | (interactive) | ||
| 6512 | (save-excursion | ||
| 6513 | (org-map-tree 'org-demote)) | ||
| 6514 | (org-fix-position-after-promote)) | ||
| 6515 | |||
| 6516 | |||
| 6517 | (defun org-do-promote () | ||
| 6518 | "Promote the current heading higher up the tree. | ||
| 6519 | If the region is active in `transient-mark-mode', promote all headings | ||
| 6520 | in the region." | ||
| 6521 | (interactive) | ||
| 6522 | (save-excursion | ||
| 6523 | (if (org-region-active-p) | ||
| 6524 | (org-map-region 'org-promote (region-beginning) (region-end)) | ||
| 6525 | (org-promote))) | ||
| 6526 | (org-fix-position-after-promote)) | ||
| 6527 | |||
| 6528 | (defun org-do-demote () | ||
| 6529 | "Demote the current heading lower down the tree. | ||
| 6530 | If the region is active in `transient-mark-mode', demote all headings | ||
| 6531 | in the region." | ||
| 6532 | (interactive) | ||
| 6533 | (save-excursion | ||
| 6534 | (if (org-region-active-p) | ||
| 6535 | (org-map-region 'org-demote (region-beginning) (region-end)) | ||
| 6536 | (org-demote))) | ||
| 6537 | (org-fix-position-after-promote)) | ||
| 6538 | |||
| 6539 | (defun org-fix-position-after-promote () | ||
| 6540 | "Make sure that after pro/demotion cursor position is right." | ||
| 6541 | (let ((pos (point))) | ||
| 6542 | (when (save-excursion | ||
| 6543 | (beginning-of-line 1) | ||
| 6544 | (looking-at org-todo-line-regexp) | ||
| 6545 | (or (equal pos (match-end 1)) (equal pos (match-end 2)))) | ||
| 6546 | (cond ((eobp) (insert " ")) | ||
| 6547 | ((eolp) (insert " ")) | ||
| 6548 | ((equal (char-after) ?\ ) (forward-char 1)))))) | ||
| 6549 | |||
| 6550 | (defun org-reduced-level (l) | ||
| 6551 | (if org-odd-levels-only (1+ (floor (/ l 2))) l)) | ||
| 6552 | |||
| 6553 | (defun org-get-valid-level (level &optional change) | ||
| 6554 | "Rectify a level change under the influence of `org-odd-levels-only' | ||
| 6555 | LEVEL is a current level, CHANGE is by how much the level should be | ||
| 6556 | modified. Even if CHANGE is nil, LEVEL may be returned modified because | ||
| 6557 | even level numbers will become the next higher odd number." | ||
| 6558 | (if org-odd-levels-only | ||
| 6559 | (cond ((or (not change) (= 0 change)) (1+ (* 2 (/ level 2)))) | ||
| 6560 | ((> change 0) (1+ (* 2 (/ (+ level (* 2 change)) 2)))) | ||
| 6561 | ((< change 0) (max 1 (1+ (* 2 (/ (+ level (* 2 change)) 2)))))) | ||
| 6562 | (max 1 (+ level change)))) | ||
| 6563 | |||
| 6564 | (define-obsolete-function-alias 'org-get-legal-level | ||
| 6565 | 'org-get-valid-level "23.1") | ||
| 6566 | |||
| 6567 | (defun org-promote () | ||
| 6568 | "Promote the current heading higher up the tree. | ||
| 6569 | If the region is active in `transient-mark-mode', promote all headings | ||
| 6570 | in the region." | ||
| 6571 | (org-back-to-heading t) | ||
| 6572 | (let* ((level (save-match-data (funcall outline-level))) | ||
| 6573 | (up-head (concat (make-string (org-get-valid-level level -1) ?*) " ")) | ||
| 6574 | (diff (abs (- level (length up-head) -1)))) | ||
| 6575 | (if (= level 1) (error "Cannot promote to level 0. UNDO to recover if necessary")) | ||
| 6576 | (replace-match up-head nil t) | ||
| 6577 | ;; Fixup tag positioning | ||
| 6578 | (and org-auto-align-tags (org-set-tags nil t)) | ||
| 6579 | (if org-adapt-indentation (org-fixup-indentation (- diff))))) | ||
| 6580 | |||
| 6581 | (defun org-demote () | ||
| 6582 | "Demote the current heading lower down the tree. | ||
| 6583 | If the region is active in `transient-mark-mode', demote all headings | ||
| 6584 | in the region." | ||
| 6585 | (org-back-to-heading t) | ||
| 6586 | (let* ((level (save-match-data (funcall outline-level))) | ||
| 6587 | (down-head (concat (make-string (org-get-valid-level level 1) ?*) " ")) | ||
| 6588 | (diff (abs (- level (length down-head) -1)))) | ||
| 6589 | (replace-match down-head nil t) | ||
| 6590 | ;; Fixup tag positioning | ||
| 6591 | (and org-auto-align-tags (org-set-tags nil t)) | ||
| 6592 | (if org-adapt-indentation (org-fixup-indentation diff)))) | ||
| 6593 | |||
| 6594 | (defun org-map-tree (fun) | ||
| 6595 | "Call FUN for every heading underneath the current one." | ||
| 6596 | (org-back-to-heading) | ||
| 6597 | (let ((level (funcall outline-level))) | ||
| 6598 | (save-excursion | ||
| 6599 | (funcall fun) | ||
| 6600 | (while (and (progn | ||
| 6601 | (outline-next-heading) | ||
| 6602 | (> (funcall outline-level) level)) | ||
| 6603 | (not (eobp))) | ||
| 6604 | (funcall fun))))) | ||
| 6605 | |||
| 6606 | (defun org-map-region (fun beg end) | ||
| 6607 | "Call FUN for every heading between BEG and END." | ||
| 6608 | (let ((org-ignore-region t)) | ||
| 6609 | (save-excursion | ||
| 6610 | (setq end (copy-marker end)) | ||
| 6611 | (goto-char beg) | ||
| 6612 | (if (and (re-search-forward (concat "^" outline-regexp) nil t) | ||
| 6613 | (< (point) end)) | ||
| 6614 | (funcall fun)) | ||
| 6615 | (while (and (progn | ||
| 6616 | (outline-next-heading) | ||
| 6617 | (< (point) end)) | ||
| 6618 | (not (eobp))) | ||
| 6619 | (funcall fun))))) | ||
| 6620 | |||
| 6621 | (defun org-fixup-indentation (diff) | ||
| 6622 | "Change the indentation in the current entry by DIFF | ||
| 6623 | However, if any line in the current entry has no indentation, or if it | ||
| 6624 | would end up with no indentation after the change, nothing at all is done." | ||
| 6625 | (save-excursion | ||
| 6626 | (let ((end (save-excursion (outline-next-heading) | ||
| 6627 | (point-marker))) | ||
| 6628 | (prohibit (if (> diff 0) | ||
| 6629 | "^\\S-" | ||
| 6630 | (concat "^ \\{0," (int-to-string (- diff)) "\\}\\S-"))) | ||
| 6631 | col) | ||
| 6632 | (unless (save-excursion (end-of-line 1) | ||
| 6633 | (re-search-forward prohibit end t)) | ||
| 6634 | (while (and (< (point) end) | ||
| 6635 | (re-search-forward "^[ \t]+" end t)) | ||
| 6636 | (goto-char (match-end 0)) | ||
| 6637 | (setq col (current-column)) | ||
| 6638 | (if (< diff 0) (replace-match "")) | ||
| 6639 | (indent-to (+ diff col)))) | ||
| 6640 | (move-marker end nil)))) | ||
| 6641 | |||
| 6642 | (defun org-convert-to-odd-levels () | ||
| 6643 | "Convert an org-mode file with all levels allowed to one with odd levels. | ||
| 6644 | This will leave level 1 alone, convert level 2 to level 3, level 3 to | ||
| 6645 | level 5 etc." | ||
| 6646 | (interactive) | ||
| 6647 | (when (yes-or-no-p "Are you sure you want to globally change levels to odd? ") | ||
| 6648 | (let ((org-odd-levels-only nil) n) | ||
| 6649 | (save-excursion | ||
| 6650 | (goto-char (point-min)) | ||
| 6651 | (while (re-search-forward "^\\*\\*+ " nil t) | ||
| 6652 | (setq n (- (length (match-string 0)) 2)) | ||
| 6653 | (while (>= (setq n (1- n)) 0) | ||
| 6654 | (org-demote)) | ||
| 6655 | (end-of-line 1)))))) | ||
| 6656 | |||
| 6657 | |||
| 6658 | (defun org-convert-to-oddeven-levels () | ||
| 6659 | "Convert an org-mode file with only odd levels to one with odd and even levels. | ||
| 6660 | This promotes level 3 to level 2, level 5 to level 3 etc. If the file contains a | ||
| 6661 | section with an even level, conversion would destroy the structure of the file. An error | ||
| 6662 | is signaled in this case." | ||
| 6663 | (interactive) | ||
| 6664 | (goto-char (point-min)) | ||
| 6665 | ;; First check if there are no even levels | ||
| 6666 | (when (re-search-forward "^\\(\\*\\*\\)+ " nil t) | ||
| 6667 | (org-show-context t) | ||
| 6668 | (error "Not all levels are odd in this file. Conversion not possible.")) | ||
| 6669 | (when (yes-or-no-p "Are you sure you want to globally change levels to odd-even? ") | ||
| 6670 | (let ((org-odd-levels-only nil) n) | ||
| 6671 | (save-excursion | ||
| 6672 | (goto-char (point-min)) | ||
| 6673 | (while (re-search-forward "^\\*\\*+ " nil t) | ||
| 6674 | (setq n (/ (1- (length (match-string 0))) 2)) | ||
| 6675 | (while (>= (setq n (1- n)) 0) | ||
| 6676 | (org-promote)) | ||
| 6677 | (end-of-line 1)))))) | ||
| 6678 | |||
| 6679 | (defun org-tr-level (n) | ||
| 6680 | "Make N odd if required." | ||
| 6681 | (if org-odd-levels-only (1+ (/ n 2)) n)) | ||
| 6682 | |||
| 6683 | ;;; Vertical tree motion, cutting and pasting of subtrees | ||
| 6684 | |||
| 6685 | (defun org-move-subtree-up (&optional arg) | ||
| 6686 | "Move the current subtree up past ARG headlines of the same level." | ||
| 6687 | (interactive "p") | ||
| 6688 | (org-move-subtree-down (- (prefix-numeric-value arg)))) | ||
| 6689 | |||
| 6690 | (defun org-move-subtree-down (&optional arg) | ||
| 6691 | "Move the current subtree down past ARG headlines of the same level." | ||
| 6692 | (interactive "p") | ||
| 6693 | (setq arg (prefix-numeric-value arg)) | ||
| 6694 | (let ((movfunc (if (> arg 0) 'outline-get-next-sibling | ||
| 6695 | 'outline-get-last-sibling)) | ||
| 6696 | (ins-point (make-marker)) | ||
| 6697 | (cnt (abs arg)) | ||
| 6698 | beg beg0 end txt folded ne-beg ne-end ne-ins ins-end) | ||
| 6699 | ;; Select the tree | ||
| 6700 | (org-back-to-heading) | ||
| 6701 | (setq beg0 (point)) | ||
| 6702 | (save-excursion | ||
| 6703 | (setq ne-beg (org-back-over-empty-lines)) | ||
| 6704 | (setq beg (point))) | ||
| 6705 | (save-match-data | ||
| 6706 | (save-excursion (outline-end-of-heading) | ||
| 6707 | (setq folded (org-invisible-p))) | ||
| 6708 | (outline-end-of-subtree)) | ||
| 6709 | (outline-next-heading) | ||
| 6710 | (setq ne-end (org-back-over-empty-lines)) | ||
| 6711 | (setq end (point)) | ||
| 6712 | (goto-char beg0) | ||
| 6713 | (when (and (> arg 0) (org-first-sibling-p) (< ne-end ne-beg)) | ||
| 6714 | ;; include less whitespace | ||
| 6715 | (save-excursion | ||
| 6716 | (goto-char beg) | ||
| 6717 | (forward-line (- ne-beg ne-end)) | ||
| 6718 | (setq beg (point)))) | ||
| 6719 | ;; Find insertion point, with error handling | ||
| 6720 | (while (> cnt 0) | ||
| 6721 | (or (and (funcall movfunc) (looking-at outline-regexp)) | ||
| 6722 | (progn (goto-char beg0) | ||
| 6723 | (error "Cannot move past superior level or buffer limit"))) | ||
| 6724 | (setq cnt (1- cnt))) | ||
| 6725 | (if (> arg 0) | ||
| 6726 | ;; Moving forward - still need to move over subtree | ||
| 6727 | (progn (org-end-of-subtree t t) | ||
| 6728 | (save-excursion | ||
| 6729 | (org-back-over-empty-lines) | ||
| 6730 | (or (bolp) (newline))))) | ||
| 6731 | (setq ne-ins (org-back-over-empty-lines)) | ||
| 6732 | (move-marker ins-point (point)) | ||
| 6733 | (setq txt (buffer-substring beg end)) | ||
| 6734 | (delete-region beg end) | ||
| 6735 | (outline-flag-region (1- beg) beg nil) | ||
| 6736 | (outline-flag-region (1- (point)) (point) nil) | ||
| 6737 | (insert txt) | ||
| 6738 | (or (bolp) (insert "\n")) | ||
| 6739 | (setq ins-end (point)) | ||
| 6740 | (goto-char ins-point) | ||
| 6741 | (org-skip-whitespace) | ||
| 6742 | (when (and (< arg 0) | ||
| 6743 | (org-first-sibling-p) | ||
| 6744 | (> ne-ins ne-beg)) | ||
| 6745 | ;; Move whitespace back to beginning | ||
| 6746 | (save-excursion | ||
| 6747 | (goto-char ins-end) | ||
| 6748 | (let ((kill-whole-line t)) | ||
| 6749 | (kill-line (- ne-ins ne-beg)) (point))) | ||
| 6750 | (insert (make-string (- ne-ins ne-beg) ?\n))) | ||
| 6751 | (move-marker ins-point nil) | ||
| 6752 | (org-compact-display-after-subtree-move) | ||
| 6753 | (unless folded | ||
| 6754 | (org-show-entry) | ||
| 6755 | (show-children) | ||
| 6756 | (org-cycle-hide-drawers 'children)))) | ||
| 6757 | |||
| 6758 | (defvar org-subtree-clip "" | ||
| 6759 | "Clipboard for cut and paste of subtrees. | ||
| 6760 | This is actually only a copy of the kill, because we use the normal kill | ||
| 6761 | ring. We need it to check if the kill was created by `org-copy-subtree'.") | ||
| 6762 | |||
| 6763 | (defvar org-subtree-clip-folded nil | ||
| 6764 | "Was the last copied subtree folded? | ||
| 6765 | This is used to fold the tree back after pasting.") | ||
| 6766 | |||
| 6767 | (defun org-cut-subtree (&optional n) | ||
| 6768 | "Cut the current subtree into the clipboard. | ||
| 6769 | With prefix arg N, cut this many sequential subtrees. | ||
| 6770 | This is a short-hand for marking the subtree and then cutting it." | ||
| 6771 | (interactive "p") | ||
| 6772 | (org-copy-subtree n 'cut)) | ||
| 6773 | |||
| 6774 | (defun org-copy-subtree (&optional n cut) | ||
| 6775 | "Cut the current subtree into the clipboard. | ||
| 6776 | With prefix arg N, cut this many sequential subtrees. | ||
| 6777 | This is a short-hand for marking the subtree and then copying it. | ||
| 6778 | If CUT is non-nil, actually cut the subtree." | ||
| 6779 | (interactive "p") | ||
| 6780 | (let (beg end folded (beg0 (point))) | ||
| 6781 | (if (interactive-p) | ||
| 6782 | (org-back-to-heading nil) ; take what looks like a subtree | ||
| 6783 | (org-back-to-heading t)) ; take what is really there | ||
| 6784 | (org-back-over-empty-lines) | ||
| 6785 | (setq beg (point)) | ||
| 6786 | (skip-chars-forward " \t\r\n") | ||
| 6787 | (save-match-data | ||
| 6788 | (save-excursion (outline-end-of-heading) | ||
| 6789 | (setq folded (org-invisible-p))) | ||
| 6790 | (condition-case nil | ||
| 6791 | (outline-forward-same-level (1- n)) | ||
| 6792 | (error nil)) | ||
| 6793 | (org-end-of-subtree t t)) | ||
| 6794 | (org-back-over-empty-lines) | ||
| 6795 | (setq end (point)) | ||
| 6796 | (goto-char beg0) | ||
| 6797 | (when (> end beg) | ||
| 6798 | (setq org-subtree-clip-folded folded) | ||
| 6799 | (if cut (kill-region beg end) (copy-region-as-kill beg end)) | ||
| 6800 | (setq org-subtree-clip (current-kill 0)) | ||
| 6801 | (message "%s: Subtree(s) with %d characters" | ||
| 6802 | (if cut "Cut" "Copied") | ||
| 6803 | (length org-subtree-clip))))) | ||
| 6804 | |||
| 6805 | (defun org-paste-subtree (&optional level tree) | ||
| 6806 | "Paste the clipboard as a subtree, with modification of headline level. | ||
| 6807 | The entire subtree is promoted or demoted in order to match a new headline | ||
| 6808 | level. By default, the new level is derived from the visible headings | ||
| 6809 | before and after the insertion point, and taken to be the inferior headline | ||
| 6810 | level of the two. So if the previous visible heading is level 3 and the | ||
| 6811 | next is level 4 (or vice versa), level 4 will be used for insertion. | ||
| 6812 | This makes sure that the subtree remains an independent subtree and does | ||
| 6813 | not swallow low level entries. | ||
| 6814 | |||
| 6815 | You can also force a different level, either by using a numeric prefix | ||
| 6816 | argument, or by inserting the heading marker by hand. For example, if the | ||
| 6817 | cursor is after \"*****\", then the tree will be shifted to level 5. | ||
| 6818 | |||
| 6819 | If you want to insert the tree as is, just use \\[yank]. | ||
| 6820 | |||
| 6821 | If optional TREE is given, use this text instead of the kill ring." | ||
| 6822 | (interactive "P") | ||
| 6823 | (unless (org-kill-is-subtree-p tree) | ||
| 6824 | (error "%s" | ||
| 6825 | (substitute-command-keys | ||
| 6826 | "The kill is not a (set of) tree(s) - please use \\[yank] to yank anyway"))) | ||
| 6827 | (let* ((txt (or tree (and kill-ring (current-kill 0)))) | ||
| 6828 | (^re (concat "^\\(" outline-regexp "\\)")) | ||
| 6829 | (re (concat "\\(" outline-regexp "\\)")) | ||
| 6830 | (^re_ (concat "\\(\\*+\\)[ \t]*")) | ||
| 6831 | |||
| 6832 | (old-level (if (string-match ^re txt) | ||
| 6833 | (- (match-end 0) (match-beginning 0) 1) | ||
| 6834 | -1)) | ||
| 6835 | (force-level (cond (level (prefix-numeric-value level)) | ||
| 6836 | ((string-match | ||
| 6837 | ^re_ (buffer-substring (point-at-bol) (point))) | ||
| 6838 | (- (match-end 1) (match-beginning 1))) | ||
| 6839 | (t nil))) | ||
| 6840 | (previous-level (save-excursion | ||
| 6841 | (condition-case nil | ||
| 6842 | (progn | ||
| 6843 | (outline-previous-visible-heading 1) | ||
| 6844 | (if (looking-at re) | ||
| 6845 | (- (match-end 0) (match-beginning 0) 1) | ||
| 6846 | 1)) | ||
| 6847 | (error 1)))) | ||
| 6848 | (next-level (save-excursion | ||
| 6849 | (condition-case nil | ||
| 6850 | (progn | ||
| 6851 | (or (looking-at outline-regexp) | ||
| 6852 | (outline-next-visible-heading 1)) | ||
| 6853 | (if (looking-at re) | ||
| 6854 | (- (match-end 0) (match-beginning 0) 1) | ||
| 6855 | 1)) | ||
| 6856 | (error 1)))) | ||
| 6857 | (new-level (or force-level (max previous-level next-level))) | ||
| 6858 | (shift (if (or (= old-level -1) | ||
| 6859 | (= new-level -1) | ||
| 6860 | (= old-level new-level)) | ||
| 6861 | 0 | ||
| 6862 | (- new-level old-level))) | ||
| 6863 | (delta (if (> shift 0) -1 1)) | ||
| 6864 | (func (if (> shift 0) 'org-demote 'org-promote)) | ||
| 6865 | (org-odd-levels-only nil) | ||
| 6866 | beg end) | ||
| 6867 | ;; Remove the forced level indicator | ||
| 6868 | (if force-level | ||
| 6869 | (delete-region (point-at-bol) (point))) | ||
| 6870 | ;; Paste | ||
| 6871 | (beginning-of-line 1) | ||
| 6872 | (org-back-over-empty-lines) ;; FIXME: correct fix???? | ||
| 6873 | (setq beg (point)) | ||
| 6874 | (insert-before-markers txt) ;; FIXME: correct fix???? | ||
| 6875 | (unless (string-match "\n\\'" txt) (insert "\n")) | ||
| 6876 | (setq end (point)) | ||
| 6877 | (goto-char beg) | ||
| 6878 | (skip-chars-forward " \t\n\r") | ||
| 6879 | (setq beg (point)) | ||
| 6880 | ;; Shift if necessary | ||
| 6881 | (unless (= shift 0) | ||
| 6882 | (save-restriction | ||
| 6883 | (narrow-to-region beg end) | ||
| 6884 | (while (not (= shift 0)) | ||
| 6885 | (org-map-region func (point-min) (point-max)) | ||
| 6886 | (setq shift (+ delta shift))) | ||
| 6887 | (goto-char (point-min)))) | ||
| 6888 | (when (interactive-p) | ||
| 6889 | (message "Clipboard pasted as level %d subtree" new-level)) | ||
| 6890 | (if (and kill-ring | ||
| 6891 | (eq org-subtree-clip (current-kill 0)) | ||
| 6892 | org-subtree-clip-folded) | ||
| 6893 | ;; The tree was folded before it was killed/copied | ||
| 6894 | (hide-subtree)))) | ||
| 6895 | |||
| 6896 | (defun org-kill-is-subtree-p (&optional txt) | ||
| 6897 | "Check if the current kill is an outline subtree, or a set of trees. | ||
| 6898 | Returns nil if kill does not start with a headline, or if the first | ||
| 6899 | headline level is not the largest headline level in the tree. | ||
| 6900 | So this will actually accept several entries of equal levels as well, | ||
| 6901 | which is OK for `org-paste-subtree'. | ||
| 6902 | If optional TXT is given, check this string instead of the current kill." | ||
| 6903 | (let* ((kill (or txt (and kill-ring (current-kill 0)) "")) | ||
| 6904 | (start-level (and kill | ||
| 6905 | (string-match (concat "\\`\\([ \t\n\r]*?\n\\)?\\(" | ||
| 6906 | org-outline-regexp "\\)") | ||
| 6907 | kill) | ||
| 6908 | (- (match-end 2) (match-beginning 2) 1))) | ||
| 6909 | (re (concat "^" org-outline-regexp)) | ||
| 6910 | (start (1+ (match-beginning 2)))) | ||
| 6911 | (if (not start-level) | ||
| 6912 | (progn | ||
| 6913 | nil) ;; does not even start with a heading | ||
| 6914 | (catch 'exit | ||
| 6915 | (while (setq start (string-match re kill (1+ start))) | ||
| 6916 | (when (< (- (match-end 0) (match-beginning 0) 1) start-level) | ||
| 6917 | (throw 'exit nil))) | ||
| 6918 | t)))) | ||
| 6919 | |||
| 6920 | (defun org-narrow-to-subtree () | ||
| 6921 | "Narrow buffer to the current subtree." | ||
| 6922 | (interactive) | ||
| 6923 | (save-excursion | ||
| 6924 | (save-match-data | ||
| 6925 | (narrow-to-region | ||
| 6926 | (progn (org-back-to-heading) (point)) | ||
| 6927 | (progn (org-end-of-subtree t t) (point)))))) | ||
| 6928 | |||
| 6929 | |||
| 6930 | ;;; Outline Sorting | ||
| 6931 | |||
| 6932 | (defun org-sort (with-case) | ||
| 6933 | "Call `org-sort-entries-or-items' or `org-table-sort-lines'. | ||
| 6934 | Optional argument WITH-CASE means sort case-sensitively." | ||
| 6935 | (interactive "P") | ||
| 6936 | (if (org-at-table-p) | ||
| 6937 | (org-call-with-arg 'org-table-sort-lines with-case) | ||
| 6938 | (org-call-with-arg 'org-sort-entries-or-items with-case))) | ||
| 6939 | |||
| 6940 | (defvar org-priority-regexp) ; defined later in the file | ||
| 6941 | |||
| 6942 | (defun org-sort-entries-or-items (&optional with-case sorting-type getkey-func property) | ||
| 6943 | "Sort entries on a certain level of an outline tree. | ||
| 6944 | If there is an active region, the entries in the region are sorted. | ||
| 6945 | Else, if the cursor is before the first entry, sort the top-level items. | ||
| 6946 | Else, the children of the entry at point are sorted. | ||
| 6947 | |||
| 6948 | Sorting can be alphabetically, numerically, and by date/time as given by | ||
| 6949 | the first time stamp in the entry. The command prompts for the sorting | ||
| 6950 | type unless it has been given to the function through the SORTING-TYPE | ||
| 6951 | argument, which needs to a character, any of (?n ?N ?a ?A ?t ?T ?p ?P ?f ?F). | ||
| 6952 | If the SORTING-TYPE is ?f or ?F, then GETKEY-FUNC specifies a function to be | ||
| 6953 | called with point at the beginning of the record. It must return either | ||
| 6954 | a string or a number that should serve as the sorting key for that record. | ||
| 6955 | |||
| 6956 | Comparing entries ignores case by default. However, with an optional argument | ||
| 6957 | WITH-CASE, the sorting considers case as well." | ||
| 6958 | (interactive "P") | ||
| 6959 | (let ((case-func (if with-case 'identity 'downcase)) | ||
| 6960 | start beg end stars re re2 | ||
| 6961 | txt what tmp plain-list-p) | ||
| 6962 | ;; Find beginning and end of region to sort | ||
| 6963 | (cond | ||
| 6964 | ((org-region-active-p) | ||
| 6965 | ;; we will sort the region | ||
| 6966 | (setq end (region-end) | ||
| 6967 | what "region") | ||
| 6968 | (goto-char (region-beginning)) | ||
| 6969 | (if (not (org-on-heading-p)) (outline-next-heading)) | ||
| 6970 | (setq start (point))) | ||
| 6971 | ((org-at-item-p) | ||
| 6972 | ;; we will sort this plain list | ||
| 6973 | (org-beginning-of-item-list) (setq start (point)) | ||
| 6974 | (org-end-of-item-list) (setq end (point)) | ||
| 6975 | (goto-char start) | ||
| 6976 | (setq plain-list-p t | ||
| 6977 | what "plain list")) | ||
| 6978 | ((or (org-on-heading-p) | ||
| 6979 | (condition-case nil (progn (org-back-to-heading) t) (error nil))) | ||
| 6980 | ;; we will sort the children of the current headline | ||
| 6981 | (org-back-to-heading) | ||
| 6982 | (setq start (point) | ||
| 6983 | end (progn (org-end-of-subtree t t) | ||
| 6984 | (org-back-over-empty-lines) | ||
| 6985 | (point)) | ||
| 6986 | what "children") | ||
| 6987 | (goto-char start) | ||
| 6988 | (show-subtree) | ||
| 6989 | (outline-next-heading)) | ||
| 6990 | (t | ||
| 6991 | ;; we will sort the top-level entries in this file | ||
| 6992 | (goto-char (point-min)) | ||
| 6993 | (or (org-on-heading-p) (outline-next-heading)) | ||
| 6994 | (setq start (point) end (point-max) what "top-level") | ||
| 6995 | (goto-char start) | ||
| 6996 | (show-all))) | ||
| 6997 | |||
| 6998 | (setq beg (point)) | ||
| 6999 | (if (>= beg end) (error "Nothing to sort")) | ||
| 7000 | |||
| 7001 | (unless plain-list-p | ||
| 7002 | (looking-at "\\(\\*+\\)") | ||
| 7003 | (setq stars (match-string 1) | ||
| 7004 | re (concat "^" (regexp-quote stars) " +") | ||
| 7005 | re2 (concat "^" (regexp-quote (substring stars 0 -1)) "[^*]") | ||
| 7006 | txt (buffer-substring beg end)) | ||
| 7007 | (if (not (equal (substring txt -1) "\n")) (setq txt (concat txt "\n"))) | ||
| 7008 | (if (and (not (equal stars "*")) (string-match re2 txt)) | ||
| 7009 | (error "Region to sort contains a level above the first entry"))) | ||
| 7010 | |||
| 7011 | (unless sorting-type | ||
| 7012 | (message | ||
| 7013 | (if plain-list-p | ||
| 7014 | "Sort %s: [a]lpha [n]umeric [t]ime [f]unc A/N/T/F means reversed:" | ||
| 7015 | "Sort %s: [a]lpha [n]umeric [t]ime [p]riority p[r]operty [f]unc A/N/T/P/F means reversed:") | ||
| 7016 | what) | ||
| 7017 | (setq sorting-type (read-char-exclusive)) | ||
| 7018 | |||
| 7019 | (and (= (downcase sorting-type) ?f) | ||
| 7020 | (setq getkey-func | ||
| 7021 | (completing-read "Sort using function: " | ||
| 7022 | obarray 'fboundp t nil nil)) | ||
| 7023 | (setq getkey-func (intern getkey-func))) | ||
| 7024 | |||
| 7025 | (and (= (downcase sorting-type) ?r) | ||
| 7026 | (setq property | ||
| 7027 | (completing-read "Property: " | ||
| 7028 | (mapcar 'list (org-buffer-property-keys t)) | ||
| 7029 | nil t)))) | ||
| 7030 | |||
| 7031 | (message "Sorting entries...") | ||
| 7032 | |||
| 7033 | (save-restriction | ||
| 7034 | (narrow-to-region start end) | ||
| 7035 | |||
| 7036 | (let ((dcst (downcase sorting-type)) | ||
| 7037 | (now (current-time))) | ||
| 7038 | (sort-subr | ||
| 7039 | (/= dcst sorting-type) | ||
| 7040 | ;; This function moves to the beginning character of the "record" to | ||
| 7041 | ;; be sorted. | ||
| 7042 | (if plain-list-p | ||
| 7043 | (lambda nil | ||
| 7044 | (if (org-at-item-p) t (goto-char (point-max)))) | ||
| 7045 | (lambda nil | ||
| 7046 | (if (re-search-forward re nil t) | ||
| 7047 | (goto-char (match-beginning 0)) | ||
| 7048 | (goto-char (point-max))))) | ||
| 7049 | ;; This function moves to the last character of the "record" being | ||
| 7050 | ;; sorted. | ||
| 7051 | (if plain-list-p | ||
| 7052 | 'org-end-of-item | ||
| 7053 | (lambda nil | ||
| 7054 | (save-match-data | ||
| 7055 | (condition-case nil | ||
| 7056 | (outline-forward-same-level 1) | ||
| 7057 | (error | ||
| 7058 | (goto-char (point-max))))))) | ||
| 7059 | |||
| 7060 | ;; This function returns the value that gets sorted against. | ||
| 7061 | (if plain-list-p | ||
| 7062 | (lambda nil | ||
| 7063 | (when (looking-at "[ \t]*[-+*0-9.)]+[ \t]+") | ||
| 7064 | (cond | ||
| 7065 | ((= dcst ?n) | ||
| 7066 | (string-to-number (buffer-substring (match-end 0) | ||
| 7067 | (point-at-eol)))) | ||
| 7068 | ((= dcst ?a) | ||
| 7069 | (buffer-substring (match-end 0) (point-at-eol))) | ||
| 7070 | ((= dcst ?t) | ||
| 7071 | (if (re-search-forward org-ts-regexp | ||
| 7072 | (point-at-eol) t) | ||
| 7073 | (org-time-string-to-time (match-string 0)) | ||
| 7074 | now)) | ||
| 7075 | ((= dcst ?f) | ||
| 7076 | (if getkey-func | ||
| 7077 | (progn | ||
| 7078 | (setq tmp (funcall getkey-func)) | ||
| 7079 | (if (stringp tmp) (setq tmp (funcall case-func tmp))) | ||
| 7080 | tmp) | ||
| 7081 | (error "Invalid key function `%s'" getkey-func))) | ||
| 7082 | (t (error "Invalid sorting type `%c'" sorting-type))))) | ||
| 7083 | (lambda nil | ||
| 7084 | (cond | ||
| 7085 | ((= dcst ?n) | ||
| 7086 | (if (looking-at outline-regexp) | ||
| 7087 | (string-to-number (buffer-substring (match-end 0) | ||
| 7088 | (point-at-eol))) | ||
| 7089 | nil)) | ||
| 7090 | ((= dcst ?a) | ||
| 7091 | (funcall case-func (buffer-substring (point-at-bol) | ||
| 7092 | (point-at-eol)))) | ||
| 7093 | ((= dcst ?t) | ||
| 7094 | (if (re-search-forward org-ts-regexp | ||
| 7095 | (save-excursion | ||
| 7096 | (forward-line 2) | ||
| 7097 | (point)) t) | ||
| 7098 | (org-time-string-to-time (match-string 0)) | ||
| 7099 | now)) | ||
| 7100 | ((= dcst ?p) | ||
| 7101 | (if (re-search-forward org-priority-regexp (point-at-eol) t) | ||
| 7102 | (string-to-char (match-string 2)) | ||
| 7103 | org-default-priority)) | ||
| 7104 | ((= dcst ?r) | ||
| 7105 | (or (org-entry-get nil property) "")) | ||
| 7106 | ((= dcst ?f) | ||
| 7107 | (if getkey-func | ||
| 7108 | (progn | ||
| 7109 | (setq tmp (funcall getkey-func)) | ||
| 7110 | (if (stringp tmp) (setq tmp (funcall case-func tmp))) | ||
| 7111 | tmp) | ||
| 7112 | (error "Invalid key function `%s'" getkey-func))) | ||
| 7113 | (t (error "Invalid sorting type `%c'" sorting-type))))) | ||
| 7114 | nil | ||
| 7115 | (cond | ||
| 7116 | ((= dcst ?a) 'string<) | ||
| 7117 | ((= dcst ?t) 'time-less-p) | ||
| 7118 | (t nil))))) | ||
| 7119 | (message "Sorting entries...done"))) | ||
| 7120 | |||
| 7121 | (defun org-do-sort (table what &optional with-case sorting-type) | ||
| 7122 | "Sort TABLE of WHAT according to SORTING-TYPE. | ||
| 7123 | The user will be prompted for the SORTING-TYPE if the call to this | ||
| 7124 | function does not specify it. WHAT is only for the prompt, to indicate | ||
| 7125 | what is being sorted. The sorting key will be extracted from | ||
| 7126 | the car of the elements of the table. | ||
| 7127 | If WITH-CASE is non-nil, the sorting will be case-sensitive." | ||
| 7128 | (unless sorting-type | ||
| 7129 | (message | ||
| 7130 | "Sort %s: [a]lphabetic. [n]umeric. [t]ime. A/N/T means reversed:" | ||
| 7131 | what) | ||
| 7132 | (setq sorting-type (read-char-exclusive))) | ||
| 7133 | (let ((dcst (downcase sorting-type)) | ||
| 7134 | extractfun comparefun) | ||
| 7135 | ;; Define the appropriate functions | ||
| 7136 | (cond | ||
| 7137 | ((= dcst ?n) | ||
| 7138 | (setq extractfun 'string-to-number | ||
| 7139 | comparefun (if (= dcst sorting-type) '< '>))) | ||
| 7140 | ((= dcst ?a) | ||
| 7141 | (setq extractfun (if with-case (lambda(x) (org-sort-remove-invisible x)) | ||
| 7142 | (lambda(x) (downcase (org-sort-remove-invisible x)))) | ||
| 7143 | comparefun (if (= dcst sorting-type) | ||
| 7144 | 'string< | ||
| 7145 | (lambda (a b) (and (not (string< a b)) | ||
| 7146 | (not (string= a b))))))) | ||
| 7147 | ((= dcst ?t) | ||
| 7148 | (setq extractfun | ||
| 7149 | (lambda (x) | ||
| 7150 | (if (string-match org-ts-regexp x) | ||
| 7151 | (time-to-seconds | ||
| 7152 | (org-time-string-to-time (match-string 0 x))) | ||
| 7153 | 0)) | ||
| 7154 | comparefun (if (= dcst sorting-type) '< '>))) | ||
| 7155 | (t (error "Invalid sorting type `%c'" sorting-type))) | ||
| 7156 | |||
| 7157 | (sort (mapcar (lambda (x) (cons (funcall extractfun (car x)) (cdr x))) | ||
| 7158 | table) | ||
| 7159 | (lambda (a b) (funcall comparefun (car a) (car b)))))) | ||
| 7160 | |||
| 7161 | ;;;; Plain list items, including checkboxes | ||
| 7162 | |||
| 7163 | ;;; Plain list items | ||
| 7164 | |||
| 7165 | (defun org-at-item-p () | ||
| 7166 | "Is point in a line starting a hand-formatted item?" | ||
| 7167 | (let ((llt org-plain-list-ordered-item-terminator)) | ||
| 7168 | (save-excursion | ||
| 7169 | (goto-char (point-at-bol)) | ||
| 7170 | (looking-at | ||
| 7171 | (cond | ||
| 7172 | ((eq llt t) "\\([ \t]*\\([-+]\\|\\([0-9]+[.)]\\)\\)\\|[ \t]+\\*\\)\\( \\|$\\)") | ||
| 7173 | ((= llt ?.) "\\([ \t]*\\([-+]\\|\\([0-9]+\\.\\)\\)\\|[ \t]+\\*\\)\\( \\|$\\)") | ||
| 7174 | ((= llt ?\)) "\\([ \t]*\\([-+]\\|\\([0-9]+))\\)\\|[ \t]+\\*\\)\\( \\|$\\)") | ||
| 7175 | (t (error "Invalid value of `org-plain-list-ordered-item-terminator'"))))))) | ||
| 7176 | |||
| 7177 | (defun org-in-item-p () | ||
| 7178 | "It the cursor inside a plain list item. | ||
| 7179 | Does not have to be the first line." | ||
| 7180 | (save-excursion | ||
| 7181 | (condition-case nil | ||
| 7182 | (progn | ||
| 7183 | (org-beginning-of-item) | ||
| 7184 | (org-at-item-p) | ||
| 7185 | t) | ||
| 7186 | (error nil)))) | ||
| 7187 | |||
| 7188 | (defun org-insert-item (&optional checkbox) | ||
| 7189 | "Insert a new item at the current level. | ||
| 7190 | Return t when things worked, nil when we are not in an item." | ||
| 7191 | (when (save-excursion | ||
| 7192 | (condition-case nil | ||
| 7193 | (progn | ||
| 7194 | (org-beginning-of-item) | ||
| 7195 | (org-at-item-p) | ||
| 7196 | (if (org-invisible-p) (error "Invisible item")) | ||
| 7197 | t) | ||
| 7198 | (error nil))) | ||
| 7199 | (let* ((bul (match-string 0)) | ||
| 7200 | (eow (save-excursion (beginning-of-line 1) (looking-at "[ \t]*") | ||
| 7201 | (match-end 0))) | ||
| 7202 | (blank (cdr (assq 'plain-list-item org-blank-before-new-entry))) | ||
| 7203 | pos) | ||
| 7204 | (cond | ||
| 7205 | ((and (org-at-item-p) (<= (point) eow)) | ||
| 7206 | ;; before the bullet | ||
| 7207 | (beginning-of-line 1) | ||
| 7208 | (open-line (if blank 2 1))) | ||
| 7209 | ((<= (point) eow) | ||
| 7210 | (beginning-of-line 1)) | ||
| 7211 | (t | ||
| 7212 | (unless (org-get-alist-option org-M-RET-may-split-line 'item) | ||
| 7213 | (end-of-line 1) | ||
| 7214 | (delete-horizontal-space)) | ||
| 7215 | (newline (if blank 2 1)))) | ||
| 7216 | (insert bul (if checkbox "[ ]" "")) | ||
| 7217 | (just-one-space) | ||
| 7218 | (setq pos (point)) | ||
| 7219 | (end-of-line 1) | ||
| 7220 | (unless (= (point) pos) (just-one-space) (backward-delete-char 1))) | ||
| 7221 | (org-maybe-renumber-ordered-list) | ||
| 7222 | (and checkbox (org-update-checkbox-count-maybe)) | ||
| 7223 | t)) | ||
| 7224 | |||
| 7225 | ;;; Checkboxes | ||
| 7226 | |||
| 7227 | (defun org-at-item-checkbox-p () | ||
| 7228 | "Is point at a line starting a plain-list item with a checklet?" | ||
| 7229 | (and (org-at-item-p) | ||
| 7230 | (save-excursion | ||
| 7231 | (goto-char (match-end 0)) | ||
| 7232 | (skip-chars-forward " \t") | ||
| 7233 | (looking-at "\\[[- X]\\]")))) | ||
| 7234 | |||
| 7235 | (defun org-toggle-checkbox (&optional arg) | ||
| 7236 | "Toggle the checkbox in the current line." | ||
| 7237 | (interactive "P") | ||
| 7238 | (catch 'exit | ||
| 7239 | (let (beg end status (firstnew 'unknown)) | ||
| 7240 | (cond | ||
| 7241 | ((org-region-active-p) | ||
| 7242 | (setq beg (region-beginning) end (region-end))) | ||
| 7243 | ((org-on-heading-p) | ||
| 7244 | (setq beg (point) end (save-excursion (outline-next-heading) (point)))) | ||
| 7245 | ((org-at-item-checkbox-p) | ||
| 7246 | (let ((pos (point))) | ||
| 7247 | (replace-match | ||
| 7248 | (cond (arg "[-]") | ||
| 7249 | ((member (match-string 0) '("[ ]" "[-]")) "[X]") | ||
| 7250 | (t "[ ]")) | ||
| 7251 | t t) | ||
| 7252 | (goto-char pos)) | ||
| 7253 | (throw 'exit t)) | ||
| 7254 | (t (error "Not at a checkbox or heading, and no active region"))) | ||
| 7255 | (save-excursion | ||
| 7256 | (goto-char beg) | ||
| 7257 | (while (< (point) end) | ||
| 7258 | (when (org-at-item-checkbox-p) | ||
| 7259 | (setq status (equal (match-string 0) "[X]")) | ||
| 7260 | (when (eq firstnew 'unknown) | ||
| 7261 | (setq firstnew (not status))) | ||
| 7262 | (replace-match | ||
| 7263 | (if (if arg (not status) firstnew) "[X]" "[ ]") t t)) | ||
| 7264 | (beginning-of-line 2))))) | ||
| 7265 | (org-update-checkbox-count-maybe)) | ||
| 7266 | |||
| 7267 | (defun org-update-checkbox-count-maybe () | ||
| 7268 | "Update checkbox statistics unless turned off by user." | ||
| 7269 | (when org-provide-checkbox-statistics | ||
| 7270 | (org-update-checkbox-count))) | ||
| 7271 | |||
| 7272 | (defun org-update-checkbox-count (&optional all) | ||
| 7273 | "Update the checkbox statistics in the current section. | ||
| 7274 | This will find all statistic cookies like [57%] and [6/12] and update them | ||
| 7275 | with the current numbers. With optional prefix argument ALL, do this for | ||
| 7276 | the whole buffer." | ||
| 7277 | (interactive "P") | ||
| 7278 | (save-excursion | ||
| 7279 | (let* ((buffer-invisibility-spec (org-inhibit-invisibility)) ; Emacs 21 | ||
| 7280 | (beg (condition-case nil | ||
| 7281 | (progn (outline-back-to-heading) (point)) | ||
| 7282 | (error (point-min)))) | ||
| 7283 | (end (move-marker (make-marker) | ||
| 7284 | (progn (outline-next-heading) (point)))) | ||
| 7285 | (re "\\(\\(\\[[0-9]*%\\]\\)\\|\\(\\[[0-9]*/[0-9]*\\]\\)\\)") | ||
| 7286 | (re-box "^[ \t]*\\([-+*]\\|[0-9]+[.)]\\) +\\(\\[[- X]\\]\\)") | ||
| 7287 | (re-find (concat re "\\|" re-box)) | ||
| 7288 | beg-cookie end-cookie is-percent c-on c-off lim | ||
| 7289 | eline curr-ind next-ind continue-from startsearch | ||
| 7290 | (cstat 0) | ||
| 7291 | ) | ||
| 7292 | (when all | ||
| 7293 | (goto-char (point-min)) | ||
| 7294 | (outline-next-heading) | ||
| 7295 | (setq beg (point) end (point-max))) | ||
| 7296 | (goto-char end) | ||
| 7297 | ;; find each statistic cookie | ||
| 7298 | (while (re-search-backward re-find beg t) | ||
| 7299 | (setq beg-cookie (match-beginning 1) | ||
| 7300 | end-cookie (match-end 1) | ||
| 7301 | cstat (+ cstat (if end-cookie 1 0)) | ||
| 7302 | startsearch (point-at-eol) | ||
| 7303 | continue-from (point-at-bol) | ||
| 7304 | is-percent (match-beginning 2) | ||
| 7305 | lim (cond | ||
| 7306 | ((org-on-heading-p) (outline-next-heading) (point)) | ||
| 7307 | ((org-at-item-p) (org-end-of-item) (point)) | ||
| 7308 | (t nil)) | ||
| 7309 | c-on 0 | ||
| 7310 | c-off 0) | ||
| 7311 | (when lim | ||
| 7312 | ;; find first checkbox for this cookie and gather | ||
| 7313 | ;; statistics from all that are at this indentation level | ||
| 7314 | (goto-char startsearch) | ||
| 7315 | (if (re-search-forward re-box lim t) | ||
| 7316 | (progn | ||
| 7317 | (org-beginning-of-item) | ||
| 7318 | (setq curr-ind (org-get-indentation)) | ||
| 7319 | (setq next-ind curr-ind) | ||
| 7320 | (while (= curr-ind next-ind) | ||
| 7321 | (save-excursion (end-of-line) (setq eline (point))) | ||
| 7322 | (if (re-search-forward re-box eline t) | ||
| 7323 | (if (member (match-string 2) '("[ ]" "[-]")) | ||
| 7324 | (setq c-off (1+ c-off)) | ||
| 7325 | (setq c-on (1+ c-on)) | ||
| 7326 | ) | ||
| 7327 | ) | ||
| 7328 | (org-end-of-item) | ||
| 7329 | (setq next-ind (org-get-indentation)) | ||
| 7330 | ))) | ||
| 7331 | (goto-char continue-from) | ||
| 7332 | ;; update cookie | ||
| 7333 | (when end-cookie | ||
| 7334 | (delete-region beg-cookie end-cookie) | ||
| 7335 | (goto-char beg-cookie) | ||
| 7336 | (insert | ||
| 7337 | (if is-percent | ||
| 7338 | (format "[%d%%]" (/ (* 100 c-on) (max 1 (+ c-on c-off)))) | ||
| 7339 | (format "[%d/%d]" c-on (+ c-on c-off))))) | ||
| 7340 | ;; update items checkbox if it has one | ||
| 7341 | (when (org-at-item-p) | ||
| 7342 | (org-beginning-of-item) | ||
| 7343 | (when (and (> (+ c-on c-off) 0) | ||
| 7344 | (re-search-forward re-box (point-at-eol) t)) | ||
| 7345 | (setq beg-cookie (match-beginning 2) | ||
| 7346 | end-cookie (match-end 2)) | ||
| 7347 | (delete-region beg-cookie end-cookie) | ||
| 7348 | (goto-char beg-cookie) | ||
| 7349 | (cond ((= c-off 0) (insert "[X]")) | ||
| 7350 | ((= c-on 0) (insert "[ ]")) | ||
| 7351 | (t (insert "[-]"))) | ||
| 7352 | ))) | ||
| 7353 | (goto-char continue-from)) | ||
| 7354 | (when (interactive-p) | ||
| 7355 | (message "Checkbox satistics updated %s (%d places)" | ||
| 7356 | (if all "in entire file" "in current outline entry") cstat))))) | ||
| 7357 | |||
| 7358 | (defun org-get-checkbox-statistics-face () | ||
| 7359 | "Select the face for checkbox statistics. | ||
| 7360 | The face will be `org-done' when all relevant boxes are checked. Otherwise | ||
| 7361 | it will be `org-todo'." | ||
| 7362 | (if (match-end 1) | ||
| 7363 | (if (equal (match-string 1) "100%") 'org-done 'org-todo) | ||
| 7364 | (if (and (> (match-end 2) (match-beginning 2)) | ||
| 7365 | (equal (match-string 2) (match-string 3))) | ||
| 7366 | 'org-done | ||
| 7367 | 'org-todo))) | ||
| 7368 | |||
| 7369 | (defun org-get-indentation (&optional line) | ||
| 7370 | "Get the indentation of the current line, interpreting tabs. | ||
| 7371 | When LINE is given, assume it represents a line and compute its indentation." | ||
| 7372 | (if line | ||
| 7373 | (if (string-match "^ *" (org-remove-tabs line)) | ||
| 7374 | (match-end 0)) | ||
| 7375 | (save-excursion | ||
| 7376 | (beginning-of-line 1) | ||
| 7377 | (skip-chars-forward " \t") | ||
| 7378 | (current-column)))) | ||
| 7379 | |||
| 7380 | (defun org-remove-tabs (s &optional width) | ||
| 7381 | "Replace tabulators in S with spaces. | ||
| 7382 | Assumes that s is a single line, starting in column 0." | ||
| 7383 | (setq width (or width tab-width)) | ||
| 7384 | (while (string-match "\t" s) | ||
| 7385 | (setq s (replace-match | ||
| 7386 | (make-string | ||
| 7387 | (- (* width (/ (+ (match-beginning 0) width) width)) | ||
| 7388 | (match-beginning 0)) ?\ ) | ||
| 7389 | t t s))) | ||
| 7390 | s) | ||
| 7391 | |||
| 7392 | (defun org-fix-indentation (line ind) | ||
| 7393 | "Fix indentation in LINE. | ||
| 7394 | IND is a cons cell with target and minimum indentation. | ||
| 7395 | If the current indenation in LINE is smaller than the minimum, | ||
| 7396 | leave it alone. If it is larger than ind, set it to the target." | ||
| 7397 | (let* ((l (org-remove-tabs line)) | ||
| 7398 | (i (org-get-indentation l)) | ||
| 7399 | (i1 (car ind)) (i2 (cdr ind))) | ||
| 7400 | (if (>= i i2) (setq l (substring line i2))) | ||
| 7401 | (if (> i1 0) | ||
| 7402 | (concat (make-string i1 ?\ ) l) | ||
| 7403 | l))) | ||
| 7404 | |||
| 7405 | (defcustom org-empty-line-terminates-plain-lists nil | ||
| 7406 | "Non-nil means, an empty line ends all plain list levels. | ||
| 7407 | When nil, empty lines are part of the preceeding item." | ||
| 7408 | :group 'org-plain-lists | ||
| 7409 | :type 'boolean) | ||
| 7410 | |||
| 7411 | (defun org-beginning-of-item () | ||
| 7412 | "Go to the beginning of the current hand-formatted item. | ||
| 7413 | If the cursor is not in an item, throw an error." | ||
| 7414 | (interactive) | ||
| 7415 | (let ((pos (point)) | ||
| 7416 | (limit (save-excursion | ||
| 7417 | (condition-case nil | ||
| 7418 | (progn | ||
| 7419 | (org-back-to-heading) | ||
| 7420 | (beginning-of-line 2) (point)) | ||
| 7421 | (error (point-min))))) | ||
| 7422 | (ind-empty (if org-empty-line-terminates-plain-lists 0 10000)) | ||
| 7423 | ind ind1) | ||
| 7424 | (if (org-at-item-p) | ||
| 7425 | (beginning-of-line 1) | ||
| 7426 | (beginning-of-line 1) | ||
| 7427 | (skip-chars-forward " \t") | ||
| 7428 | (setq ind (current-column)) | ||
| 7429 | (if (catch 'exit | ||
| 7430 | (while t | ||
| 7431 | (beginning-of-line 0) | ||
| 7432 | (if (or (bobp) (< (point) limit)) (throw 'exit nil)) | ||
| 7433 | |||
| 7434 | (if (looking-at "[ \t]*$") | ||
| 7435 | (setq ind1 ind-empty) | ||
| 7436 | (skip-chars-forward " \t") | ||
| 7437 | (setq ind1 (current-column))) | ||
| 7438 | (if (< ind1 ind) | ||
| 7439 | (progn (beginning-of-line 1) (throw 'exit (org-at-item-p)))))) | ||
| 7440 | nil | ||
| 7441 | (goto-char pos) | ||
| 7442 | (error "Not in an item"))))) | ||
| 7443 | |||
| 7444 | (defun org-end-of-item () | ||
| 7445 | "Go to the end of the current hand-formatted item. | ||
| 7446 | If the cursor is not in an item, throw an error." | ||
| 7447 | (interactive) | ||
| 7448 | (let* ((pos (point)) | ||
| 7449 | ind1 | ||
| 7450 | (ind-empty (if org-empty-line-terminates-plain-lists 0 10000)) | ||
| 7451 | (limit (save-excursion (outline-next-heading) (point))) | ||
| 7452 | (ind (save-excursion | ||
| 7453 | (org-beginning-of-item) | ||
| 7454 | (skip-chars-forward " \t") | ||
| 7455 | (current-column))) | ||
| 7456 | (end (catch 'exit | ||
| 7457 | (while t | ||
| 7458 | (beginning-of-line 2) | ||
| 7459 | (if (eobp) (throw 'exit (point))) | ||
| 7460 | (if (>= (point) limit) (throw 'exit (point-at-bol))) | ||
| 7461 | (if (looking-at "[ \t]*$") | ||
| 7462 | (setq ind1 ind-empty) | ||
| 7463 | (skip-chars-forward " \t") | ||
| 7464 | (setq ind1 (current-column))) | ||
| 7465 | (if (<= ind1 ind) | ||
| 7466 | (throw 'exit (point-at-bol))))))) | ||
| 7467 | (if end | ||
| 7468 | (goto-char end) | ||
| 7469 | (goto-char pos) | ||
| 7470 | (error "Not in an item")))) | ||
| 7471 | |||
| 7472 | (defun org-next-item () | ||
| 7473 | "Move to the beginning of the next item in the current plain list. | ||
| 7474 | Error if not at a plain list, or if this is the last item in the list." | ||
| 7475 | (interactive) | ||
| 7476 | (let (ind ind1 (pos (point))) | ||
| 7477 | (org-beginning-of-item) | ||
| 7478 | (setq ind (org-get-indentation)) | ||
| 7479 | (org-end-of-item) | ||
| 7480 | (setq ind1 (org-get-indentation)) | ||
| 7481 | (unless (and (org-at-item-p) (= ind ind1)) | ||
| 7482 | (goto-char pos) | ||
| 7483 | (error "On last item")))) | ||
| 7484 | |||
| 7485 | (defun org-previous-item () | ||
| 7486 | "Move to the beginning of the previous item in the current plain list. | ||
| 7487 | Error if not at a plain list, or if this is the first item in the list." | ||
| 7488 | (interactive) | ||
| 7489 | (let (beg ind ind1 (pos (point))) | ||
| 7490 | (org-beginning-of-item) | ||
| 7491 | (setq beg (point)) | ||
| 7492 | (setq ind (org-get-indentation)) | ||
| 7493 | (goto-char beg) | ||
| 7494 | (catch 'exit | ||
| 7495 | (while t | ||
| 7496 | (beginning-of-line 0) | ||
| 7497 | (if (looking-at "[ \t]*$") | ||
| 7498 | nil | ||
| 7499 | (if (<= (setq ind1 (org-get-indentation)) ind) | ||
| 7500 | (throw 'exit t))))) | ||
| 7501 | (condition-case nil | ||
| 7502 | (if (or (not (org-at-item-p)) | ||
| 7503 | (< ind1 (1- ind))) | ||
| 7504 | (error "") | ||
| 7505 | (org-beginning-of-item)) | ||
| 7506 | (error (goto-char pos) | ||
| 7507 | (error "On first item"))))) | ||
| 7508 | |||
| 7509 | (defun org-first-list-item-p () | ||
| 7510 | "Is this heading the item in a plain list?" | ||
| 7511 | (unless (org-at-item-p) | ||
| 7512 | (error "Not at a plain list item")) | ||
| 7513 | (org-beginning-of-item) | ||
| 7514 | (= (point) (save-excursion (org-beginning-of-item-list)))) | ||
| 7515 | |||
| 7516 | (defun org-move-item-down () | ||
| 7517 | "Move the plain list item at point down, i.e. swap with following item. | ||
| 7518 | Subitems (items with larger indentation) are considered part of the item, | ||
| 7519 | so this really moves item trees." | ||
| 7520 | (interactive) | ||
| 7521 | (let (beg beg0 end end0 ind ind1 (pos (point)) txt ne-end ne-beg) | ||
| 7522 | (org-beginning-of-item) | ||
| 7523 | (setq beg0 (point)) | ||
| 7524 | (save-excursion | ||
| 7525 | (setq ne-beg (org-back-over-empty-lines)) | ||
| 7526 | (setq beg (point))) | ||
| 7527 | (goto-char beg0) | ||
| 7528 | (setq ind (org-get-indentation)) | ||
| 7529 | (org-end-of-item) | ||
| 7530 | (setq end0 (point)) | ||
| 7531 | (setq ind1 (org-get-indentation)) | ||
| 7532 | (setq ne-end (org-back-over-empty-lines)) | ||
| 7533 | (setq end (point)) | ||
| 7534 | (goto-char beg0) | ||
| 7535 | (when (and (org-first-list-item-p) (< ne-end ne-beg)) | ||
| 7536 | ;; include less whitespace | ||
| 7537 | (save-excursion | ||
| 7538 | (goto-char beg) | ||
| 7539 | (forward-line (- ne-beg ne-end)) | ||
| 7540 | (setq beg (point)))) | ||
| 7541 | (goto-char end0) | ||
| 7542 | (if (and (org-at-item-p) (= ind ind1)) | ||
| 7543 | (progn | ||
| 7544 | (org-end-of-item) | ||
| 7545 | (org-back-over-empty-lines) | ||
| 7546 | (setq txt (buffer-substring beg end)) | ||
| 7547 | (save-excursion | ||
| 7548 | (delete-region beg end)) | ||
| 7549 | (setq pos (point)) | ||
| 7550 | (insert txt) | ||
| 7551 | (goto-char pos) (org-skip-whitespace) | ||
| 7552 | (org-maybe-renumber-ordered-list)) | ||
| 7553 | (goto-char pos) | ||
| 7554 | (error "Cannot move this item further down")))) | ||
| 7555 | |||
| 7556 | (defun org-move-item-up (arg) | ||
| 7557 | "Move the plain list item at point up, i.e. swap with previous item. | ||
| 7558 | Subitems (items with larger indentation) are considered part of the item, | ||
| 7559 | so this really moves item trees." | ||
| 7560 | (interactive "p") | ||
| 7561 | (let (beg beg0 end ind ind1 (pos (point)) txt | ||
| 7562 | ne-beg ne-ins ins-end) | ||
| 7563 | (org-beginning-of-item) | ||
| 7564 | (setq beg0 (point)) | ||
| 7565 | (setq ind (org-get-indentation)) | ||
| 7566 | (save-excursion | ||
| 7567 | (setq ne-beg (org-back-over-empty-lines)) | ||
| 7568 | (setq beg (point))) | ||
| 7569 | (goto-char beg0) | ||
| 7570 | (org-end-of-item) | ||
| 7571 | (setq end (point)) | ||
| 7572 | (goto-char beg0) | ||
| 7573 | (catch 'exit | ||
| 7574 | (while t | ||
| 7575 | (beginning-of-line 0) | ||
| 7576 | (if (looking-at "[ \t]*$") | ||
| 7577 | (if org-empty-line-terminates-plain-lists | ||
| 7578 | (progn | ||
| 7579 | (goto-char pos) | ||
| 7580 | (error "Cannot move this item further up")) | ||
| 7581 | nil) | ||
| 7582 | (if (<= (setq ind1 (org-get-indentation)) ind) | ||
| 7583 | (throw 'exit t))))) | ||
| 7584 | (condition-case nil | ||
| 7585 | (org-beginning-of-item) | ||
| 7586 | (error (goto-char beg) | ||
| 7587 | (error "Cannot move this item further up"))) | ||
| 7588 | (setq ind1 (org-get-indentation)) | ||
| 7589 | (if (and (org-at-item-p) (= ind ind1)) | ||
| 7590 | (progn | ||
| 7591 | (setq ne-ins (org-back-over-empty-lines)) | ||
| 7592 | (setq txt (buffer-substring beg end)) | ||
| 7593 | (save-excursion | ||
| 7594 | (delete-region beg end)) | ||
| 7595 | (setq pos (point)) | ||
| 7596 | (insert txt) | ||
| 7597 | (setq ins-end (point)) | ||
| 7598 | (goto-char pos) (org-skip-whitespace) | ||
| 7599 | |||
| 7600 | (when (and (org-first-list-item-p) (> ne-ins ne-beg)) | ||
| 7601 | ;; Move whitespace back to beginning | ||
| 7602 | (save-excursion | ||
| 7603 | (goto-char ins-end) | ||
| 7604 | (let ((kill-whole-line t)) | ||
| 7605 | (kill-line (- ne-ins ne-beg)) (point))) | ||
| 7606 | (insert (make-string (- ne-ins ne-beg) ?\n))) | ||
| 7607 | |||
| 7608 | (org-maybe-renumber-ordered-list)) | ||
| 7609 | (goto-char pos) | ||
| 7610 | (error "Cannot move this item further up")))) | ||
| 7611 | |||
| 7612 | (defun org-maybe-renumber-ordered-list () | ||
| 7613 | "Renumber the ordered list at point if setup allows it. | ||
| 7614 | This tests the user option `org-auto-renumber-ordered-lists' before | ||
| 7615 | doing the renumbering." | ||
| 7616 | (interactive) | ||
| 7617 | (when (and org-auto-renumber-ordered-lists | ||
| 7618 | (org-at-item-p)) | ||
| 7619 | (if (match-beginning 3) | ||
| 7620 | (org-renumber-ordered-list 1) | ||
| 7621 | (org-fix-bullet-type)))) | ||
| 7622 | |||
| 7623 | (defun org-maybe-renumber-ordered-list-safe () | ||
| 7624 | (condition-case nil | ||
| 7625 | (save-excursion | ||
| 7626 | (org-maybe-renumber-ordered-list)) | ||
| 7627 | (error nil))) | ||
| 7628 | |||
| 7629 | (defun org-cycle-list-bullet (&optional which) | ||
| 7630 | "Cycle through the different itemize/enumerate bullets. | ||
| 7631 | This cycle the entire list level through the sequence: | ||
| 7632 | |||
| 7633 | `-' -> `+' -> `*' -> `1.' -> `1)' | ||
| 7634 | |||
| 7635 | If WHICH is a string, use that as the new bullet. If WHICH is an integer, | ||
| 7636 | 0 meand `-', 1 means `+' etc." | ||
| 7637 | (interactive "P") | ||
| 7638 | (org-preserve-lc | ||
| 7639 | (org-beginning-of-item-list) | ||
| 7640 | (org-at-item-p) | ||
| 7641 | (beginning-of-line 1) | ||
| 7642 | (let ((current (match-string 0)) | ||
| 7643 | (prevp (eq which 'previous)) | ||
| 7644 | new) | ||
| 7645 | (setq new (cond | ||
| 7646 | ((and (numberp which) | ||
| 7647 | (nth (1- which) '("-" "+" "*" "1." "1)")))) | ||
| 7648 | ((string-match "-" current) (if prevp "1)" "+")) | ||
| 7649 | ((string-match "\\+" current) | ||
| 7650 | (if prevp "-" (if (looking-at "\\S-") "1." "*"))) | ||
| 7651 | ((string-match "\\*" current) (if prevp "+" "1.")) | ||
| 7652 | ((string-match "\\." current) (if prevp "*" "1)")) | ||
| 7653 | ((string-match ")" current) (if prevp "1." "-")) | ||
| 7654 | (t (error "This should not happen")))) | ||
| 7655 | (and (looking-at "\\([ \t]*\\)\\S-+") (replace-match (concat "\\1" new))) | ||
| 7656 | (org-fix-bullet-type) | ||
| 7657 | (org-maybe-renumber-ordered-list)))) | ||
| 7658 | |||
| 7659 | (defun org-get-string-indentation (s) | ||
| 7660 | "What indentation has S due to SPACE and TAB at the beginning of the string?" | ||
| 7661 | (let ((n -1) (i 0) (w tab-width) c) | ||
| 7662 | (catch 'exit | ||
| 7663 | (while (< (setq n (1+ n)) (length s)) | ||
| 7664 | (setq c (aref s n)) | ||
| 7665 | (cond ((= c ?\ ) (setq i (1+ i))) | ||
| 7666 | ((= c ?\t) (setq i (* (/ (+ w i) w) w))) | ||
| 7667 | (t (throw 'exit t))))) | ||
| 7668 | i)) | ||
| 7669 | |||
| 7670 | (defun org-renumber-ordered-list (arg) | ||
| 7671 | "Renumber an ordered plain list. | ||
| 7672 | Cursor needs to be in the first line of an item, the line that starts | ||
| 7673 | with something like \"1.\" or \"2)\"." | ||
| 7674 | (interactive "p") | ||
| 7675 | (unless (and (org-at-item-p) | ||
| 7676 | (match-beginning 3)) | ||
| 7677 | (error "This is not an ordered list")) | ||
| 7678 | (let ((line (org-current-line)) | ||
| 7679 | (col (current-column)) | ||
| 7680 | (ind (org-get-string-indentation | ||
| 7681 | (buffer-substring (point-at-bol) (match-beginning 3)))) | ||
| 7682 | ;; (term (substring (match-string 3) -1)) | ||
| 7683 | ind1 (n (1- arg)) | ||
| 7684 | fmt) | ||
| 7685 | ;; find where this list begins | ||
| 7686 | (org-beginning-of-item-list) | ||
| 7687 | (looking-at "[ \t]*[0-9]+\\([.)]\\)") | ||
| 7688 | (setq fmt (concat "%d" (match-string 1))) | ||
| 7689 | (beginning-of-line 0) | ||
| 7690 | ;; walk forward and replace these numbers | ||
| 7691 | (catch 'exit | ||
| 7692 | (while t | ||
| 7693 | (catch 'next | ||
| 7694 | (beginning-of-line 2) | ||
| 7695 | (if (eobp) (throw 'exit nil)) | ||
| 7696 | (if (looking-at "[ \t]*$") (throw 'next nil)) | ||
| 7697 | (skip-chars-forward " \t") (setq ind1 (current-column)) | ||
| 7698 | (if (> ind1 ind) (throw 'next t)) | ||
| 7699 | (if (< ind1 ind) (throw 'exit t)) | ||
| 7700 | (if (not (org-at-item-p)) (throw 'exit nil)) | ||
| 7701 | (delete-region (match-beginning 2) (match-end 2)) | ||
| 7702 | (goto-char (match-beginning 2)) | ||
| 7703 | (insert (format fmt (setq n (1+ n))))))) | ||
| 7704 | (goto-line line) | ||
| 7705 | (move-to-column col))) | ||
| 7706 | |||
| 7707 | (defun org-fix-bullet-type () | ||
| 7708 | "Make sure all items in this list have the same bullet as the firsst item." | ||
| 7709 | (interactive) | ||
| 7710 | (unless (org-at-item-p) (error "This is not a list")) | ||
| 7711 | (let ((line (org-current-line)) | ||
| 7712 | (col (current-column)) | ||
| 7713 | (ind (current-indentation)) | ||
| 7714 | ind1 bullet) | ||
| 7715 | ;; find where this list begins | ||
| 7716 | (org-beginning-of-item-list) | ||
| 7717 | (beginning-of-line 1) | ||
| 7718 | ;; find out what the bullet type is | ||
| 7719 | (looking-at "[ \t]*\\(\\S-+\\)") | ||
| 7720 | (setq bullet (match-string 1)) | ||
| 7721 | ;; walk forward and replace these numbers | ||
| 7722 | (beginning-of-line 0) | ||
| 7723 | (catch 'exit | ||
| 7724 | (while t | ||
| 7725 | (catch 'next | ||
| 7726 | (beginning-of-line 2) | ||
| 7727 | (if (eobp) (throw 'exit nil)) | ||
| 7728 | (if (looking-at "[ \t]*$") (throw 'next nil)) | ||
| 7729 | (skip-chars-forward " \t") (setq ind1 (current-column)) | ||
| 7730 | (if (> ind1 ind) (throw 'next t)) | ||
| 7731 | (if (< ind1 ind) (throw 'exit t)) | ||
| 7732 | (if (not (org-at-item-p)) (throw 'exit nil)) | ||
| 7733 | (skip-chars-forward " \t") | ||
| 7734 | (looking-at "\\S-+") | ||
| 7735 | (replace-match bullet)))) | ||
| 7736 | (goto-line line) | ||
| 7737 | (move-to-column col) | ||
| 7738 | (if (string-match "[0-9]" bullet) | ||
| 7739 | (org-renumber-ordered-list 1)))) | ||
| 7740 | |||
| 7741 | (defun org-beginning-of-item-list () | ||
| 7742 | "Go to the beginning of the current item list. | ||
| 7743 | I.e. to the first item in this list." | ||
| 7744 | (interactive) | ||
| 7745 | (org-beginning-of-item) | ||
| 7746 | (let ((pos (point-at-bol)) | ||
| 7747 | (ind (org-get-indentation)) | ||
| 7748 | ind1) | ||
| 7749 | ;; find where this list begins | ||
| 7750 | (catch 'exit | ||
| 7751 | (while t | ||
| 7752 | (catch 'next | ||
| 7753 | (beginning-of-line 0) | ||
| 7754 | (if (looking-at "[ \t]*$") | ||
| 7755 | (throw (if (bobp) 'exit 'next) t)) | ||
| 7756 | (skip-chars-forward " \t") (setq ind1 (current-column)) | ||
| 7757 | (if (or (< ind1 ind) | ||
| 7758 | (and (= ind1 ind) | ||
| 7759 | (not (org-at-item-p))) | ||
| 7760 | (bobp)) | ||
| 7761 | (throw 'exit t) | ||
| 7762 | (when (org-at-item-p) (setq pos (point-at-bol))))))) | ||
| 7763 | (goto-char pos))) | ||
| 7764 | |||
| 7765 | |||
| 7766 | (defun org-end-of-item-list () | ||
| 7767 | "Go to the end of the current item list. | ||
| 7768 | I.e. to the text after the last item." | ||
| 7769 | (interactive) | ||
| 7770 | (org-beginning-of-item) | ||
| 7771 | (let ((pos (point-at-bol)) | ||
| 7772 | (ind (org-get-indentation)) | ||
| 7773 | ind1) | ||
| 7774 | ;; find where this list begins | ||
| 7775 | (catch 'exit | ||
| 7776 | (while t | ||
| 7777 | (catch 'next | ||
| 7778 | (beginning-of-line 2) | ||
| 7779 | (if (looking-at "[ \t]*$") | ||
| 7780 | (throw (if (eobp) 'exit 'next) t)) | ||
| 7781 | (skip-chars-forward " \t") (setq ind1 (current-column)) | ||
| 7782 | (if (or (< ind1 ind) | ||
| 7783 | (and (= ind1 ind) | ||
| 7784 | (not (org-at-item-p))) | ||
| 7785 | (eobp)) | ||
| 7786 | (progn | ||
| 7787 | (setq pos (point-at-bol)) | ||
| 7788 | (throw 'exit t)))))) | ||
| 7789 | (goto-char pos))) | ||
| 7790 | |||
| 7791 | |||
| 7792 | (defvar org-last-indent-begin-marker (make-marker)) | ||
| 7793 | (defvar org-last-indent-end-marker (make-marker)) | ||
| 7794 | |||
| 7795 | (defun org-outdent-item (arg) | ||
| 7796 | "Outdent a local list item." | ||
| 7797 | (interactive "p") | ||
| 7798 | (org-indent-item (- arg))) | ||
| 7799 | |||
| 7800 | (defun org-indent-item (arg) | ||
| 7801 | "Indent a local list item." | ||
| 7802 | (interactive "p") | ||
| 7803 | (unless (org-at-item-p) | ||
| 7804 | (error "Not on an item")) | ||
| 7805 | (save-excursion | ||
| 7806 | (let (beg end ind ind1 tmp delta ind-down ind-up) | ||
| 7807 | (if (memq last-command '(org-shiftmetaright org-shiftmetaleft)) | ||
| 7808 | (setq beg org-last-indent-begin-marker | ||
| 7809 | end org-last-indent-end-marker) | ||
| 7810 | (org-beginning-of-item) | ||
| 7811 | (setq beg (move-marker org-last-indent-begin-marker (point))) | ||
| 7812 | (org-end-of-item) | ||
| 7813 | (setq end (move-marker org-last-indent-end-marker (point)))) | ||
| 7814 | (goto-char beg) | ||
| 7815 | (setq tmp (org-item-indent-positions) | ||
| 7816 | ind (car tmp) | ||
| 7817 | ind-down (nth 2 tmp) | ||
| 7818 | ind-up (nth 1 tmp) | ||
| 7819 | delta (if (> arg 0) | ||
| 7820 | (if ind-down (- ind-down ind) 2) | ||
| 7821 | (if ind-up (- ind-up ind) -2))) | ||
| 7822 | (if (< (+ delta ind) 0) (error "Cannot outdent beyond margin")) | ||
| 7823 | (while (< (point) end) | ||
| 7824 | (beginning-of-line 1) | ||
| 7825 | (skip-chars-forward " \t") (setq ind1 (current-column)) | ||
| 7826 | (delete-region (point-at-bol) (point)) | ||
| 7827 | (or (eolp) (indent-to-column (+ ind1 delta))) | ||
| 7828 | (beginning-of-line 2)))) | ||
| 7829 | (org-fix-bullet-type) | ||
| 7830 | (org-maybe-renumber-ordered-list-safe) | ||
| 7831 | (save-excursion | ||
| 7832 | (beginning-of-line 0) | ||
| 7833 | (condition-case nil (org-beginning-of-item) (error nil)) | ||
| 7834 | (org-maybe-renumber-ordered-list-safe))) | ||
| 7835 | |||
| 7836 | (defun org-item-indent-positions () | ||
| 7837 | "Return indentation for plain list items. | ||
| 7838 | This returns a list with three values: The current indentation, the | ||
| 7839 | parent indentation and the indentation a child should habe. | ||
| 7840 | Assumes cursor in item line." | ||
| 7841 | (let* ((bolpos (point-at-bol)) | ||
| 7842 | (ind (org-get-indentation)) | ||
| 7843 | ind-down ind-up pos) | ||
| 7844 | (save-excursion | ||
| 7845 | (org-beginning-of-item-list) | ||
| 7846 | (skip-chars-backward "\n\r \t") | ||
| 7847 | (when (org-in-item-p) | ||
| 7848 | (org-beginning-of-item) | ||
| 7849 | (setq ind-up (org-get-indentation)))) | ||
| 7850 | (setq pos (point)) | ||
| 7851 | (save-excursion | ||
| 7852 | (cond | ||
| 7853 | ((and (condition-case nil (progn (org-previous-item) t) | ||
| 7854 | (error nil)) | ||
| 7855 | (or (forward-char 1) t) | ||
| 7856 | (re-search-forward "^\\([ \t]*\\([-+]\\|\\([0-9]+[.)]\\)\\)\\|[ \t]+\\*\\)\\( \\|$\\)" bolpos t)) | ||
| 7857 | (setq ind-down (org-get-indentation))) | ||
| 7858 | ((and (goto-char pos) | ||
| 7859 | (org-at-item-p)) | ||
| 7860 | (goto-char (match-end 0)) | ||
| 7861 | (skip-chars-forward " \t") | ||
| 7862 | (setq ind-down (current-column))))) | ||
| 7863 | (list ind ind-up ind-down))) | ||
| 7864 | |||
| 7865 | ;;; The orgstruct minor mode | ||
| 7866 | |||
| 7867 | ;; Define a minor mode which can be used in other modes in order to | ||
| 7868 | ;; integrate the org-mode structure editing commands. | ||
| 7869 | |||
| 7870 | ;; This is really a hack, because the org-mode structure commands use | ||
| 7871 | ;; keys which normally belong to the major mode. Here is how it | ||
| 7872 | ;; works: The minor mode defines all the keys necessary to operate the | ||
| 7873 | ;; structure commands, but wraps the commands into a function which | ||
| 7874 | ;; tests if the cursor is currently at a headline or a plain list | ||
| 7875 | ;; item. If that is the case, the structure command is used, | ||
| 7876 | ;; temporarily setting many Org-mode variables like regular | ||
| 7877 | ;; expressions for filling etc. However, when any of those keys is | ||
| 7878 | ;; used at a different location, function uses `key-binding' to look | ||
| 7879 | ;; up if the key has an associated command in another currently active | ||
| 7880 | ;; keymap (minor modes, major mode, global), and executes that | ||
| 7881 | ;; command. There might be problems if any of the keys is otherwise | ||
| 7882 | ;; used as a prefix key. | ||
| 7883 | |||
| 7884 | ;; Another challenge is that the key binding for TAB can be tab or \C-i, | ||
| 7885 | ;; likewise the binding for RET can be return or \C-m. Orgtbl-mode | ||
| 7886 | ;; addresses this by checking explicitly for both bindings. | ||
| 7887 | |||
| 7888 | (defvar orgstruct-mode-map (make-sparse-keymap) | ||
| 7889 | "Keymap for the minor `orgstruct-mode'.") | ||
| 7890 | |||
| 7891 | (defvar org-local-vars nil | ||
| 7892 | "List of local variables, for use by `orgstruct-mode'") | ||
| 7893 | |||
| 7894 | ;;;###autoload | ||
| 7895 | (define-minor-mode orgstruct-mode | ||
| 7896 | "Toggle the minor more `orgstruct-mode'. | ||
| 7897 | This mode is for using Org-mode structure commands in other modes. | ||
| 7898 | The following key behave as if Org-mode was active, if the cursor | ||
| 7899 | is on a headline, or on a plain list item (both in the definition | ||
| 7900 | of Org-mode). | ||
| 7901 | |||
| 7902 | M-up Move entry/item up | ||
| 7903 | M-down Move entry/item down | ||
| 7904 | M-left Promote | ||
| 7905 | M-right Demote | ||
| 7906 | M-S-up Move entry/item up | ||
| 7907 | M-S-down Move entry/item down | ||
| 7908 | M-S-left Promote subtree | ||
| 7909 | M-S-right Demote subtree | ||
| 7910 | M-q Fill paragraph and items like in Org-mode | ||
| 7911 | C-c ^ Sort entries | ||
| 7912 | C-c - Cycle list bullet | ||
| 7913 | TAB Cycle item visibility | ||
| 7914 | M-RET Insert new heading/item | ||
| 7915 | S-M-RET Insert new TODO heading / Chekbox item | ||
| 7916 | C-c C-c Set tags / toggle checkbox" | ||
| 7917 | nil " OrgStruct" nil | ||
| 7918 | (and (orgstruct-setup) (defun orgstruct-setup () nil))) | ||
| 7919 | |||
| 7920 | ;;;###autoload | ||
| 7921 | (defun turn-on-orgstruct () | ||
| 7922 | "Unconditionally turn on `orgstruct-mode'." | ||
| 7923 | (orgstruct-mode 1)) | ||
| 7924 | |||
| 7925 | ;;;###autoload | ||
| 7926 | (defun turn-on-orgstruct++ () | ||
| 7927 | "Unconditionally turn on `orgstruct-mode', and force org-mode indentations. | ||
| 7928 | In addition to setting orgstruct-mode, this also exports all indentation and | ||
| 7929 | autofilling variables from org-mode into the buffer. Note that turning | ||
| 7930 | off orgstruct-mode will *not* remove these additional settings." | ||
| 7931 | (orgstruct-mode 1) | ||
| 7932 | (let (var val) | ||
| 7933 | (mapc | ||
| 7934 | (lambda (x) | ||
| 7935 | (when (string-match | ||
| 7936 | "^\\(paragraph-\\|auto-fill\\|fill-paragraph\\|adaptive-fill\\|indent-\\)" | ||
| 7937 | (symbol-name (car x))) | ||
| 7938 | (setq var (car x) val (nth 1 x)) | ||
| 7939 | (org-set-local var (if (eq (car-safe val) 'quote) (nth 1 val) val)))) | ||
| 7940 | org-local-vars))) | ||
| 7941 | |||
| 7942 | (defun orgstruct-error () | ||
| 7943 | "Error when there is no default binding for a structure key." | ||
| 7944 | (interactive) | ||
| 7945 | (error "This key has no function outside structure elements")) | ||
| 7946 | |||
| 7947 | (defun orgstruct-setup () | ||
| 7948 | "Setup orgstruct keymaps." | ||
| 7949 | (let ((nfunc 0) | ||
| 7950 | (bindings | ||
| 7951 | (list | ||
| 7952 | '([(meta up)] org-metaup) | ||
| 7953 | '([(meta down)] org-metadown) | ||
| 7954 | '([(meta left)] org-metaleft) | ||
| 7955 | '([(meta right)] org-metaright) | ||
| 7956 | '([(meta shift up)] org-shiftmetaup) | ||
| 7957 | '([(meta shift down)] org-shiftmetadown) | ||
| 7958 | '([(meta shift left)] org-shiftmetaleft) | ||
| 7959 | '([(meta shift right)] org-shiftmetaright) | ||
| 7960 | '([(shift up)] org-shiftup) | ||
| 7961 | '([(shift down)] org-shiftdown) | ||
| 7962 | '("\C-c\C-c" org-ctrl-c-ctrl-c) | ||
| 7963 | '("\M-q" fill-paragraph) | ||
| 7964 | '("\C-c^" org-sort) | ||
| 7965 | '("\C-c-" org-cycle-list-bullet))) | ||
| 7966 | elt key fun cmd) | ||
| 7967 | (while (setq elt (pop bindings)) | ||
| 7968 | (setq nfunc (1+ nfunc)) | ||
| 7969 | (setq key (org-key (car elt)) | ||
| 7970 | fun (nth 1 elt) | ||
| 7971 | cmd (orgstruct-make-binding fun nfunc key)) | ||
| 7972 | (org-defkey orgstruct-mode-map key cmd)) | ||
| 7973 | |||
| 7974 | ;; Special treatment needed for TAB and RET | ||
| 7975 | (org-defkey orgstruct-mode-map [(tab)] | ||
| 7976 | (orgstruct-make-binding 'org-cycle 102 [(tab)] "\C-i")) | ||
| 7977 | (org-defkey orgstruct-mode-map "\C-i" | ||
| 7978 | (orgstruct-make-binding 'org-cycle 103 "\C-i" [(tab)])) | ||
| 7979 | |||
| 7980 | (org-defkey orgstruct-mode-map "\M-\C-m" | ||
| 7981 | (orgstruct-make-binding 'org-insert-heading 105 | ||
| 7982 | "\M-\C-m" [(meta return)])) | ||
| 7983 | (org-defkey orgstruct-mode-map [(meta return)] | ||
| 7984 | (orgstruct-make-binding 'org-insert-heading 106 | ||
| 7985 | [(meta return)] "\M-\C-m")) | ||
| 7986 | |||
| 7987 | (org-defkey orgstruct-mode-map [(shift meta return)] | ||
| 7988 | (orgstruct-make-binding 'org-insert-todo-heading 107 | ||
| 7989 | [(meta return)] "\M-\C-m")) | ||
| 7990 | |||
| 7991 | (unless org-local-vars | ||
| 7992 | (setq org-local-vars (org-get-local-variables))) | ||
| 7993 | |||
| 7994 | t)) | ||
| 7995 | |||
| 7996 | (defun orgstruct-make-binding (fun n &rest keys) | ||
| 7997 | "Create a function for binding in the structure minor mode. | ||
| 7998 | FUN is the command to call inside a table. N is used to create a unique | ||
| 7999 | command name. KEYS are keys that should be checked in for a command | ||
| 8000 | to execute outside of tables." | ||
| 8001 | (eval | ||
| 8002 | (list 'defun | ||
| 8003 | (intern (concat "orgstruct-hijacker-command-" (int-to-string n))) | ||
| 8004 | '(arg) | ||
| 8005 | (concat "In Structure, run `" (symbol-name fun) "'.\n" | ||
| 8006 | "Outside of structure, run the binding of `" | ||
| 8007 | (mapconcat (lambda (x) (format "%s" x)) keys "' or `") | ||
| 8008 | "'.") | ||
| 8009 | '(interactive "p") | ||
| 8010 | (list 'if | ||
| 8011 | '(org-context-p 'headline 'item) | ||
| 8012 | (list 'org-run-like-in-org-mode (list 'quote fun)) | ||
| 8013 | (list 'let '(orgstruct-mode) | ||
| 8014 | (list 'call-interactively | ||
| 8015 | (append '(or) | ||
| 8016 | (mapcar (lambda (k) | ||
| 8017 | (list 'key-binding k)) | ||
| 8018 | keys) | ||
| 8019 | '('orgstruct-error)))))))) | ||
| 8020 | |||
| 8021 | (defun org-context-p (&rest contexts) | ||
| 8022 | "Check if local context is and of CONTEXTS. | ||
| 8023 | Possible values in the list of contexts are `table', `headline', and `item'." | ||
| 8024 | (let ((pos (point))) | ||
| 8025 | (goto-char (point-at-bol)) | ||
| 8026 | (prog1 (or (and (memq 'table contexts) | ||
| 8027 | (looking-at "[ \t]*|")) | ||
| 8028 | (and (memq 'headline contexts) | ||
| 8029 | (looking-at "\\*+")) | ||
| 8030 | (and (memq 'item contexts) | ||
| 8031 | (looking-at "[ \t]*\\([-+*] \\|[0-9]+[.)] \\)"))) | ||
| 8032 | (goto-char pos)))) | ||
| 8033 | |||
| 8034 | (defun org-get-local-variables () | ||
| 8035 | "Return a list of all local variables in an org-mode buffer." | ||
| 8036 | (let (varlist) | ||
| 8037 | (with-current-buffer (get-buffer-create "*Org tmp*") | ||
| 8038 | (erase-buffer) | ||
| 8039 | (org-mode) | ||
| 8040 | (setq varlist (buffer-local-variables))) | ||
| 8041 | (kill-buffer "*Org tmp*") | ||
| 8042 | (delq nil | ||
| 8043 | (mapcar | ||
| 8044 | (lambda (x) | ||
| 8045 | (setq x | ||
| 8046 | (if (symbolp x) | ||
| 8047 | (list x) | ||
| 8048 | (list (car x) (list 'quote (cdr x))))) | ||
| 8049 | (if (string-match | ||
| 8050 | "^\\(org-\\|orgtbl-\\|outline-\\|comment-\\|paragraph-\\|auto-fill\\|fill-paragraph\\|adaptive-fill\\|indent-\\)" | ||
| 8051 | (symbol-name (car x))) | ||
| 8052 | x nil)) | ||
| 8053 | varlist)))) | ||
| 8054 | |||
| 8055 | ;;;###autoload | ||
| 8056 | (defun org-run-like-in-org-mode (cmd) | ||
| 8057 | (unless org-local-vars | ||
| 8058 | (setq org-local-vars (org-get-local-variables))) | ||
| 8059 | (eval (list 'let org-local-vars | ||
| 8060 | (list 'call-interactively (list 'quote cmd))))) | ||
| 8061 | |||
| 8062 | ;;;; Archiving | ||
| 8063 | |||
| 8064 | (defalias 'org-advertized-archive-subtree 'org-archive-subtree) | ||
| 8065 | |||
| 8066 | (defun org-archive-subtree (&optional find-done) | ||
| 8067 | "Move the current subtree to the archive. | ||
| 8068 | The archive can be a certain top-level heading in the current file, or in | ||
| 8069 | a different file. The tree will be moved to that location, the subtree | ||
| 8070 | heading be marked DONE, and the current time will be added. | ||
| 8071 | |||
| 8072 | When called with prefix argument FIND-DONE, find whole trees without any | ||
| 8073 | open TODO items and archive them (after getting confirmation from the user). | ||
| 8074 | If the cursor is not at a headline when this comand is called, try all level | ||
| 8075 | 1 trees. If the cursor is on a headline, only try the direct children of | ||
| 8076 | this heading." | ||
| 8077 | (interactive "P") | ||
| 8078 | (if find-done | ||
| 8079 | (org-archive-all-done) | ||
| 8080 | ;; Save all relevant TODO keyword-relatex variables | ||
| 8081 | |||
| 8082 | (let ((tr-org-todo-line-regexp org-todo-line-regexp) ; keep despite compiler | ||
| 8083 | (tr-org-todo-keywords-1 org-todo-keywords-1) | ||
| 8084 | (tr-org-todo-kwd-alist org-todo-kwd-alist) | ||
| 8085 | (tr-org-done-keywords org-done-keywords) | ||
| 8086 | (tr-org-todo-regexp org-todo-regexp) | ||
| 8087 | (tr-org-todo-line-regexp org-todo-line-regexp) | ||
| 8088 | (tr-org-odd-levels-only org-odd-levels-only) | ||
| 8089 | (this-buffer (current-buffer)) | ||
| 8090 | (org-archive-location org-archive-location) | ||
| 8091 | (re "^#\\+ARCHIVE:[ \t]+\\(\\S-.*\\S-\\)[ \t]*$") | ||
| 8092 | ;; start of variables that will be used for saving context | ||
| 8093 | ;; The compiler complains about them - keep them anyway! | ||
| 8094 | (file (abbreviate-file-name (buffer-file-name))) | ||
| 8095 | (olpath (mapconcat 'identity (org-get-outline-path) "/")) | ||
| 8096 | (time (format-time-string | ||
| 8097 | (substring (cdr org-time-stamp-formats) 1 -1) | ||
| 8098 | (current-time))) | ||
| 8099 | afile heading buffer level newfile-p | ||
| 8100 | category todo priority | ||
| 8101 | ;; start of variables that will be used for savind context | ||
| 8102 | ltags itags prop) | ||
| 8103 | |||
| 8104 | ;; Try to find a local archive location | ||
| 8105 | (save-excursion | ||
| 8106 | (save-restriction | ||
| 8107 | (widen) | ||
| 8108 | (setq prop (org-entry-get nil "ARCHIVE" 'inherit)) | ||
| 8109 | (if (and prop (string-match "\\S-" prop)) | ||
| 8110 | (setq org-archive-location prop) | ||
| 8111 | (if (or (re-search-backward re nil t) | ||
| 8112 | (re-search-forward re nil t)) | ||
| 8113 | (setq org-archive-location (match-string 1)))))) | ||
| 8114 | |||
| 8115 | (if (string-match "\\(.*\\)::\\(.*\\)" org-archive-location) | ||
| 8116 | (progn | ||
| 8117 | (setq afile (format (match-string 1 org-archive-location) | ||
| 8118 | (file-name-nondirectory buffer-file-name)) | ||
| 8119 | heading (match-string 2 org-archive-location))) | ||
| 8120 | (error "Invalid `org-archive-location'")) | ||
| 8121 | (if (> (length afile) 0) | ||
| 8122 | (setq newfile-p (not (file-exists-p afile)) | ||
| 8123 | buffer (find-file-noselect afile)) | ||
| 8124 | (setq buffer (current-buffer))) | ||
| 8125 | (unless buffer | ||
| 8126 | (error "Cannot access file \"%s\"" afile)) | ||
| 8127 | (if (and (> (length heading) 0) | ||
| 8128 | (string-match "^\\*+" heading)) | ||
| 8129 | (setq level (match-end 0)) | ||
| 8130 | (setq heading nil level 0)) | ||
| 8131 | (save-excursion | ||
| 8132 | (org-back-to-heading t) | ||
| 8133 | ;; Get context information that will be lost by moving the tree | ||
| 8134 | (org-refresh-category-properties) | ||
| 8135 | (setq category (org-get-category) | ||
| 8136 | todo (and (looking-at org-todo-line-regexp) | ||
| 8137 | (match-string 2)) | ||
| 8138 | priority (org-get-priority (if (match-end 3) (match-string 3) "")) | ||
| 8139 | ltags (org-get-tags) | ||
| 8140 | itags (org-delete-all ltags (org-get-tags-at))) | ||
| 8141 | (setq ltags (mapconcat 'identity ltags " ") | ||
| 8142 | itags (mapconcat 'identity itags " ")) | ||
| 8143 | ;; We first only copy, in case something goes wrong | ||
| 8144 | ;; we need to protect this-command, to avoid kill-region sets it, | ||
| 8145 | ;; which would lead to duplication of subtrees | ||
| 8146 | (let (this-command) (org-copy-subtree)) | ||
| 8147 | (set-buffer buffer) | ||
| 8148 | ;; Enforce org-mode for the archive buffer | ||
| 8149 | (if (not (org-mode-p)) | ||
| 8150 | ;; Force the mode for future visits. | ||
| 8151 | (let ((org-insert-mode-line-in-empty-file t) | ||
| 8152 | (org-inhibit-startup t)) | ||
| 8153 | (call-interactively 'org-mode))) | ||
| 8154 | (when newfile-p | ||
| 8155 | (goto-char (point-max)) | ||
| 8156 | (insert (format "\nArchived entries from file %s\n\n" | ||
| 8157 | (buffer-file-name this-buffer)))) | ||
| 8158 | ;; Force the TODO keywords of the original buffer | ||
| 8159 | (let ((org-todo-line-regexp tr-org-todo-line-regexp) | ||
| 8160 | (org-todo-keywords-1 tr-org-todo-keywords-1) | ||
| 8161 | (org-todo-kwd-alist tr-org-todo-kwd-alist) | ||
| 8162 | (org-done-keywords tr-org-done-keywords) | ||
| 8163 | (org-todo-regexp tr-org-todo-regexp) | ||
| 8164 | (org-todo-line-regexp tr-org-todo-line-regexp) | ||
| 8165 | (org-odd-levels-only | ||
| 8166 | (if (local-variable-p 'org-odd-levels-only (current-buffer)) | ||
| 8167 | org-odd-levels-only | ||
| 8168 | tr-org-odd-levels-only))) | ||
| 8169 | (goto-char (point-min)) | ||
| 8170 | (show-all) | ||
| 8171 | (if heading | ||
| 8172 | (progn | ||
| 8173 | (if (re-search-forward | ||
| 8174 | (concat "^" (regexp-quote heading) | ||
| 8175 | (org-re "[ \t]*\\(:[[:alnum:]_@:]+:\\)?[ \t]*\\($\\|\r\\)")) | ||
| 8176 | nil t) | ||
| 8177 | (goto-char (match-end 0)) | ||
| 8178 | ;; Heading not found, just insert it at the end | ||
| 8179 | (goto-char (point-max)) | ||
| 8180 | (or (bolp) (insert "\n")) | ||
| 8181 | (insert "\n" heading "\n") | ||
| 8182 | (end-of-line 0)) | ||
| 8183 | ;; Make the subtree visible | ||
| 8184 | (show-subtree) | ||
| 8185 | (org-end-of-subtree t) | ||
| 8186 | (skip-chars-backward " \t\r\n") | ||
| 8187 | (and (looking-at "[ \t\r\n]*") | ||
| 8188 | (replace-match "\n\n"))) | ||
| 8189 | ;; No specific heading, just go to end of file. | ||
| 8190 | (goto-char (point-max)) (insert "\n")) | ||
| 8191 | ;; Paste | ||
| 8192 | (org-paste-subtree (org-get-valid-level level 1)) | ||
| 8193 | |||
| 8194 | ;; Mark the entry as done | ||
| 8195 | (when (and org-archive-mark-done | ||
| 8196 | (looking-at org-todo-line-regexp) | ||
| 8197 | (or (not (match-end 2)) | ||
| 8198 | (not (member (match-string 2) org-done-keywords)))) | ||
| 8199 | (let (org-log-done org-todo-log-states) | ||
| 8200 | (org-todo | ||
| 8201 | (car (or (member org-archive-mark-done org-done-keywords) | ||
| 8202 | org-done-keywords))))) | ||
| 8203 | |||
| 8204 | ;; Add the context info | ||
| 8205 | (when org-archive-save-context-info | ||
| 8206 | (let ((l org-archive-save-context-info) e n v) | ||
| 8207 | (while (setq e (pop l)) | ||
| 8208 | (when (and (setq v (symbol-value e)) | ||
| 8209 | (stringp v) (string-match "\\S-" v)) | ||
| 8210 | (setq n (concat "ARCHIVE_" (upcase (symbol-name e)))) | ||
| 8211 | (org-entry-put (point) n v))))) | ||
| 8212 | |||
| 8213 | ;; Save and kill the buffer, if it is not the same buffer. | ||
| 8214 | (if (not (eq this-buffer buffer)) | ||
| 8215 | (progn (save-buffer) (kill-buffer buffer))))) | ||
| 8216 | ;; Here we are back in the original buffer. Everything seems to have | ||
| 8217 | ;; worked. So now cut the tree and finish up. | ||
| 8218 | (let (this-command) (org-cut-subtree)) | ||
| 8219 | (if (and (not (eobp)) (looking-at "[ \t]*$")) (kill-line)) | ||
| 8220 | (message "Subtree archived %s" | ||
| 8221 | (if (eq this-buffer buffer) | ||
| 8222 | (concat "under heading: " heading) | ||
| 8223 | (concat "in file: " (abbreviate-file-name afile))))))) | ||
| 8224 | |||
| 8225 | (defun org-refresh-category-properties () | ||
| 8226 | "Refresh category text properties in teh buffer." | ||
| 8227 | (let ((def-cat (cond | ||
| 8228 | ((null org-category) | ||
| 8229 | (if buffer-file-name | ||
| 8230 | (file-name-sans-extension | ||
| 8231 | (file-name-nondirectory buffer-file-name)) | ||
| 8232 | "???")) | ||
| 8233 | ((symbolp org-category) (symbol-name org-category)) | ||
| 8234 | (t org-category))) | ||
| 8235 | beg end cat pos optionp) | ||
| 8236 | (org-unmodified | ||
| 8237 | (save-excursion | ||
| 8238 | (save-restriction | ||
| 8239 | (widen) | ||
| 8240 | (goto-char (point-min)) | ||
| 8241 | (put-text-property (point) (point-max) 'org-category def-cat) | ||
| 8242 | (while (re-search-forward | ||
| 8243 | "^\\(#\\+CATEGORY:\\|[ \t]*:CATEGORY:\\)\\(.*\\)" nil t) | ||
| 8244 | (setq pos (match-end 0) | ||
| 8245 | optionp (equal (char-after (match-beginning 0)) ?#) | ||
| 8246 | cat (org-trim (match-string 2))) | ||
| 8247 | (if optionp | ||
| 8248 | (setq beg (point-at-bol) end (point-max)) | ||
| 8249 | (org-back-to-heading t) | ||
| 8250 | (setq beg (point) end (org-end-of-subtree t t))) | ||
| 8251 | (put-text-property beg end 'org-category cat) | ||
| 8252 | (goto-char pos))))))) | ||
| 8253 | |||
| 8254 | (defun org-archive-all-done (&optional tag) | ||
| 8255 | "Archive sublevels of the current tree without open TODO items. | ||
| 8256 | If the cursor is not on a headline, try all level 1 trees. If | ||
| 8257 | it is on a headline, try all direct children. | ||
| 8258 | When TAG is non-nil, don't move trees, but mark them with the ARCHIVE tag." | ||
| 8259 | (let ((re (concat "^\\*+ +" org-not-done-regexp)) re1 | ||
| 8260 | (rea (concat ".*:" org-archive-tag ":")) | ||
| 8261 | (begm (make-marker)) | ||
| 8262 | (endm (make-marker)) | ||
| 8263 | (question (if tag "Set ARCHIVE tag (no open TODO items)? " | ||
| 8264 | "Move subtree to archive (no open TODO items)? ")) | ||
| 8265 | beg end (cntarch 0)) | ||
| 8266 | (if (org-on-heading-p) | ||
| 8267 | (progn | ||
| 8268 | (setq re1 (concat "^" (regexp-quote | ||
| 8269 | (make-string | ||
| 8270 | (1+ (- (match-end 0) (match-beginning 0) 1)) | ||
| 8271 | ?*)) | ||
| 8272 | " ")) | ||
| 8273 | (move-marker begm (point)) | ||
| 8274 | (move-marker endm (org-end-of-subtree t))) | ||
| 8275 | (setq re1 "^* ") | ||
| 8276 | (move-marker begm (point-min)) | ||
| 8277 | (move-marker endm (point-max))) | ||
| 8278 | (save-excursion | ||
| 8279 | (goto-char begm) | ||
| 8280 | (while (re-search-forward re1 endm t) | ||
| 8281 | (setq beg (match-beginning 0) | ||
| 8282 | end (save-excursion (org-end-of-subtree t) (point))) | ||
| 8283 | (goto-char beg) | ||
| 8284 | (if (re-search-forward re end t) | ||
| 8285 | (goto-char end) | ||
| 8286 | (goto-char beg) | ||
| 8287 | (if (and (or (not tag) (not (looking-at rea))) | ||
| 8288 | (y-or-n-p question)) | ||
| 8289 | (progn | ||
| 8290 | (if tag | ||
| 8291 | (org-toggle-tag org-archive-tag 'on) | ||
| 8292 | (org-archive-subtree)) | ||
| 8293 | (setq cntarch (1+ cntarch))) | ||
| 8294 | (goto-char end))))) | ||
| 8295 | (message "%d trees archived" cntarch))) | ||
| 8296 | |||
| 8297 | (defun org-cycle-hide-drawers (state) | ||
| 8298 | "Re-hide all drawers after a visibility state change." | ||
| 8299 | (when (and (org-mode-p) | ||
| 8300 | (not (memq state '(overview folded)))) | ||
| 8301 | (save-excursion | ||
| 8302 | (let* ((globalp (memq state '(contents all))) | ||
| 8303 | (beg (if globalp (point-min) (point))) | ||
| 8304 | (end (if globalp (point-max) (org-end-of-subtree t)))) | ||
| 8305 | (goto-char beg) | ||
| 8306 | (while (re-search-forward org-drawer-regexp end t) | ||
| 8307 | (org-flag-drawer t)))))) | ||
| 8308 | |||
| 8309 | (defun org-flag-drawer (flag) | ||
| 8310 | (save-excursion | ||
| 8311 | (beginning-of-line 1) | ||
| 8312 | (when (looking-at "^[ \t]*:[a-zA-Z][a-zA-Z0-9]*:") | ||
| 8313 | (let ((b (match-end 0)) | ||
| 8314 | (outline-regexp org-outline-regexp)) | ||
| 8315 | (if (re-search-forward | ||
| 8316 | "^[ \t]*:END:" | ||
| 8317 | (save-excursion (outline-next-heading) (point)) t) | ||
| 8318 | (outline-flag-region b (point-at-eol) flag) | ||
| 8319 | (error ":END: line missing")))))) | ||
| 8320 | |||
| 8321 | (defun org-cycle-hide-archived-subtrees (state) | ||
| 8322 | "Re-hide all archived subtrees after a visibility state change." | ||
| 8323 | (when (and (not org-cycle-open-archived-trees) | ||
| 8324 | (not (memq state '(overview folded)))) | ||
| 8325 | (save-excursion | ||
| 8326 | (let* ((globalp (memq state '(contents all))) | ||
| 8327 | (beg (if globalp (point-min) (point))) | ||
| 8328 | (end (if globalp (point-max) (org-end-of-subtree t)))) | ||
| 8329 | (org-hide-archived-subtrees beg end) | ||
| 8330 | (goto-char beg) | ||
| 8331 | (if (looking-at (concat ".*:" org-archive-tag ":")) | ||
| 8332 | (message "%s" (substitute-command-keys | ||
| 8333 | "Subtree is archived and stays closed. Use \\[org-force-cycle-archived] to cycle it anyway."))))))) | ||
| 8334 | |||
| 8335 | (defun org-force-cycle-archived () | ||
| 8336 | "Cycle subtree even if it is archived." | ||
| 8337 | (interactive) | ||
| 8338 | (setq this-command 'org-cycle) | ||
| 8339 | (let ((org-cycle-open-archived-trees t)) | ||
| 8340 | (call-interactively 'org-cycle))) | ||
| 8341 | |||
| 8342 | (defun org-hide-archived-subtrees (beg end) | ||
| 8343 | "Re-hide all archived subtrees after a visibility state change." | ||
| 8344 | (save-excursion | ||
| 8345 | (let* ((re (concat ":" org-archive-tag ":"))) | ||
| 8346 | (goto-char beg) | ||
| 8347 | (while (re-search-forward re end t) | ||
| 8348 | (and (org-on-heading-p) (hide-subtree)) | ||
| 8349 | (org-end-of-subtree t))))) | ||
| 8350 | |||
| 8351 | (defun org-toggle-tag (tag &optional onoff) | ||
| 8352 | "Toggle the tag TAG for the current line. | ||
| 8353 | If ONOFF is `on' or `off', don't toggle but set to this state." | ||
| 8354 | (unless (org-on-heading-p t) (error "Not on headling")) | ||
| 8355 | (let (res current) | ||
| 8356 | (save-excursion | ||
| 8357 | (beginning-of-line) | ||
| 8358 | (if (re-search-forward (org-re "[ \t]:\\([[:alnum:]_@:]+\\):[ \t]*$") | ||
| 8359 | (point-at-eol) t) | ||
| 8360 | (progn | ||
| 8361 | (setq current (match-string 1)) | ||
| 8362 | (replace-match "")) | ||
| 8363 | (setq current "")) | ||
| 8364 | (setq current (nreverse (org-split-string current ":"))) | ||
| 8365 | (cond | ||
| 8366 | ((eq onoff 'on) | ||
| 8367 | (setq res t) | ||
| 8368 | (or (member tag current) (push tag current))) | ||
| 8369 | ((eq onoff 'off) | ||
| 8370 | (or (not (member tag current)) (setq current (delete tag current)))) | ||
| 8371 | (t (if (member tag current) | ||
| 8372 | (setq current (delete tag current)) | ||
| 8373 | (setq res t) | ||
| 8374 | (push tag current)))) | ||
| 8375 | (end-of-line 1) | ||
| 8376 | (if current | ||
| 8377 | (progn | ||
| 8378 | (insert " :" (mapconcat 'identity (nreverse current) ":") ":") | ||
| 8379 | (org-set-tags nil t)) | ||
| 8380 | (delete-horizontal-space)) | ||
| 8381 | (run-hooks 'org-after-tags-change-hook)) | ||
| 8382 | res)) | ||
| 8383 | |||
| 8384 | (defun org-toggle-archive-tag (&optional arg) | ||
| 8385 | "Toggle the archive tag for the current headline. | ||
| 8386 | With prefix ARG, check all children of current headline and offer tagging | ||
| 8387 | the children that do not contain any open TODO items." | ||
| 8388 | (interactive "P") | ||
| 8389 | (if arg | ||
| 8390 | (org-archive-all-done 'tag) | ||
| 8391 | (let (set) | ||
| 8392 | (save-excursion | ||
| 8393 | (org-back-to-heading t) | ||
| 8394 | (setq set (org-toggle-tag org-archive-tag)) | ||
| 8395 | (when set (hide-subtree))) | ||
| 8396 | (and set (beginning-of-line 1)) | ||
| 8397 | (message "Subtree %s" (if set "archived" "unarchived"))))) | ||
| 8398 | |||
| 8399 | |||
| 8400 | ;;;; Tables | ||
| 8401 | |||
| 8402 | ;;; The table editor | ||
| 8403 | |||
| 8404 | ;; Watch out: Here we are talking about two different kind of tables. | ||
| 8405 | ;; Most of the code is for the tables created with the Org-mode table editor. | ||
| 8406 | ;; Sometimes, we talk about tables created and edited with the table.el | ||
| 8407 | ;; Emacs package. We call the former org-type tables, and the latter | ||
| 8408 | ;; table.el-type tables. | ||
| 8409 | |||
| 8410 | (defun org-before-change-function (beg end) | ||
| 8411 | "Every change indicates that a table might need an update." | ||
| 8412 | (setq org-table-may-need-update t)) | ||
| 8413 | |||
| 8414 | (defconst org-table-line-regexp "^[ \t]*|" | ||
| 8415 | "Detects an org-type table line.") | ||
| 8416 | (defconst org-table-dataline-regexp "^[ \t]*|[^-]" | ||
| 8417 | "Detects an org-type table line.") | ||
| 8418 | (defconst org-table-auto-recalculate-regexp "^[ \t]*| *# *\\(|\\|$\\)" | ||
| 8419 | "Detects a table line marked for automatic recalculation.") | ||
| 8420 | (defconst org-table-recalculate-regexp "^[ \t]*| *[#*] *\\(|\\|$\\)" | ||
| 8421 | "Detects a table line marked for automatic recalculation.") | ||
| 8422 | (defconst org-table-calculate-mark-regexp "^[ \t]*| *[!$^_#*] *\\(|\\|$\\)" | ||
| 8423 | "Detects a table line marked for automatic recalculation.") | ||
| 8424 | (defconst org-table-hline-regexp "^[ \t]*|-" | ||
| 8425 | "Detects an org-type table hline.") | ||
| 8426 | (defconst org-table1-hline-regexp "^[ \t]*\\+-[-+]" | ||
| 8427 | "Detects a table-type table hline.") | ||
| 8428 | (defconst org-table-any-line-regexp "^[ \t]*\\(|\\|\\+-[-+]\\)" | ||
| 8429 | "Detects an org-type or table-type table.") | ||
| 8430 | (defconst org-table-border-regexp "^[ \t]*[^| \t]" | ||
| 8431 | "Searching from within a table (any type) this finds the first line | ||
| 8432 | outside the table.") | ||
| 8433 | (defconst org-table-any-border-regexp "^[ \t]*[^|+ \t]" | ||
| 8434 | "Searching from within a table (any type) this finds the first line | ||
| 8435 | outside the table.") | ||
| 8436 | |||
| 8437 | (defvar org-table-last-highlighted-reference nil) | ||
| 8438 | (defvar org-table-formula-history nil) | ||
| 8439 | |||
| 8440 | (defvar org-table-column-names nil | ||
| 8441 | "Alist with column names, derived from the `!' line.") | ||
| 8442 | (defvar org-table-column-name-regexp nil | ||
| 8443 | "Regular expression matching the current column names.") | ||
| 8444 | (defvar org-table-local-parameters nil | ||
| 8445 | "Alist with parameter names, derived from the `$' line.") | ||
| 8446 | (defvar org-table-named-field-locations nil | ||
| 8447 | "Alist with locations of named fields.") | ||
| 8448 | |||
| 8449 | (defvar org-table-current-line-types nil | ||
| 8450 | "Table row types, non-nil only for the duration of a comand.") | ||
| 8451 | (defvar org-table-current-begin-line nil | ||
| 8452 | "Table begin line, non-nil only for the duration of a comand.") | ||
| 8453 | (defvar org-table-current-begin-pos nil | ||
| 8454 | "Table begin position, non-nil only for the duration of a comand.") | ||
| 8455 | (defvar org-table-dlines nil | ||
| 8456 | "Vector of data line line numbers in the current table.") | ||
| 8457 | (defvar org-table-hlines nil | ||
| 8458 | "Vector of hline line numbers in the current table.") | ||
| 8459 | |||
| 8460 | (defconst org-table-range-regexp | ||
| 8461 | "@\\([-+]?I*[-+]?[0-9]*\\)?\\(\\$[-+]?[0-9]+\\)?\\(\\.\\.@?\\([-+]?I*[-+]?[0-9]*\\)?\\(\\$[-+]?[0-9]+\\)?\\)?" | ||
| 8462 | ;; 1 2 3 4 5 | ||
| 8463 | "Regular expression for matching ranges in formulas.") | ||
| 8464 | |||
| 8465 | (defconst org-table-range-regexp2 | ||
| 8466 | (concat | ||
| 8467 | "\\(" "@[-0-9I$&]+" "\\|" "[a-zA-Z]\\{1,2\\}\\([0-9]+\\|&\\)" "\\|" "\\$[a-zA-Z0-9]+" "\\)" | ||
| 8468 | "\\.\\." | ||
| 8469 | "\\(" "@?[-0-9I$&]+" "\\|" "[a-zA-Z]\\{1,2\\}\\([0-9]+\\|&\\)" "\\|" "\\$[a-zA-Z0-9]+" "\\)") | ||
| 8470 | "Match a range for reference display.") | ||
| 8471 | |||
| 8472 | (defconst org-table-translate-regexp | ||
| 8473 | (concat "\\(" "@[-0-9I$]+" "\\|" "[a-zA-Z]\\{1,2\\}\\([0-9]+\\|&\\)" "\\)") | ||
| 8474 | "Match a reference that needs translation, for reference display.") | ||
| 8475 | |||
| 8476 | (defvar org-inhibit-highlight-removal nil) ; dynamically scoped param | ||
| 8477 | |||
| 8478 | (defun org-table-create-with-table.el () | ||
| 8479 | "Use the table.el package to insert a new table. | ||
| 8480 | If there is already a table at point, convert between Org-mode tables | ||
| 8481 | and table.el tables." | ||
| 8482 | (interactive) | ||
| 8483 | (require 'table) | ||
| 8484 | (cond | ||
| 8485 | ((org-at-table.el-p) | ||
| 8486 | (if (y-or-n-p "Convert table to Org-mode table? ") | ||
| 8487 | (org-table-convert))) | ||
| 8488 | ((org-at-table-p) | ||
| 8489 | (if (y-or-n-p "Convert table to table.el table? ") | ||
| 8490 | (org-table-convert))) | ||
| 8491 | (t (call-interactively 'table-insert)))) | ||
| 8492 | |||
| 8493 | (defun org-table-create-or-convert-from-region (arg) | ||
| 8494 | "Convert region to table, or create an empty table. | ||
| 8495 | If there is an active region, convert it to a table, using the function | ||
| 8496 | `org-table-convert-region'. See the documentation of that function | ||
| 8497 | to learn how the prefix argument is interpreted to determine the field | ||
| 8498 | separator. | ||
| 8499 | If there is no such region, create an empty table with `org-table-create'." | ||
| 8500 | (interactive "P") | ||
| 8501 | (if (org-region-active-p) | ||
| 8502 | (org-table-convert-region (region-beginning) (region-end) arg) | ||
| 8503 | (org-table-create arg))) | ||
| 8504 | |||
| 8505 | (defun org-table-create (&optional size) | ||
| 8506 | "Query for a size and insert a table skeleton. | ||
| 8507 | SIZE is a string Columns x Rows like for example \"3x2\"." | ||
| 8508 | (interactive "P") | ||
| 8509 | (unless size | ||
| 8510 | (setq size (read-string | ||
| 8511 | (concat "Table size Columns x Rows [e.g. " | ||
| 8512 | org-table-default-size "]: ") | ||
| 8513 | "" nil org-table-default-size))) | ||
| 8514 | |||
| 8515 | (let* ((pos (point)) | ||
| 8516 | (indent (make-string (current-column) ?\ )) | ||
| 8517 | (split (org-split-string size " *x *")) | ||
| 8518 | (rows (string-to-number (nth 1 split))) | ||
| 8519 | (columns (string-to-number (car split))) | ||
| 8520 | (line (concat (apply 'concat indent "|" (make-list columns " |")) | ||
| 8521 | "\n"))) | ||
| 8522 | (if (string-match "^[ \t]*$" (buffer-substring-no-properties | ||
| 8523 | (point-at-bol) (point))) | ||
| 8524 | (beginning-of-line 1) | ||
| 8525 | (newline)) | ||
| 8526 | ;; (mapcar (lambda (x) (insert line)) (make-list rows t)) | ||
| 8527 | (dotimes (i rows) (insert line)) | ||
| 8528 | (goto-char pos) | ||
| 8529 | (if (> rows 1) | ||
| 8530 | ;; Insert a hline after the first row. | ||
| 8531 | (progn | ||
| 8532 | (end-of-line 1) | ||
| 8533 | (insert "\n|-") | ||
| 8534 | (goto-char pos))) | ||
| 8535 | (org-table-align))) | ||
| 8536 | |||
| 8537 | (defun org-table-convert-region (beg0 end0 &optional separator) | ||
| 8538 | "Convert region to a table. | ||
| 8539 | The region goes from BEG0 to END0, but these borders will be moved | ||
| 8540 | slightly, to make sure a beginning of line in the first line is included. | ||
| 8541 | |||
| 8542 | SEPARATOR specifies the field separator in the lines. It can have the | ||
| 8543 | following values: | ||
| 8544 | |||
| 8545 | '(4) Use the comma as a field separator | ||
| 8546 | '(16) Use a TAB as field separator | ||
| 8547 | integer When a number, use that many spaces as field separator | ||
| 8548 | nil When nil, the command tries to be smart and figure out the | ||
| 8549 | separator in the following way: | ||
| 8550 | - when each line contains a TAB, assume TAB-separated material | ||
| 8551 | - when each line contains a comme, assume CSV material | ||
| 8552 | - else, assume one or more SPACE charcters as separator." | ||
| 8553 | (interactive "rP") | ||
| 8554 | (let* ((beg (min beg0 end0)) | ||
| 8555 | (end (max beg0 end0)) | ||
| 8556 | re) | ||
| 8557 | (goto-char beg) | ||
| 8558 | (beginning-of-line 1) | ||
| 8559 | (setq beg (move-marker (make-marker) (point))) | ||
| 8560 | (goto-char end) | ||
| 8561 | (if (bolp) (backward-char 1) (end-of-line 1)) | ||
| 8562 | (setq end (move-marker (make-marker) (point))) | ||
| 8563 | ;; Get the right field separator | ||
| 8564 | (unless separator | ||
| 8565 | (goto-char beg) | ||
| 8566 | (setq separator | ||
| 8567 | (cond | ||
| 8568 | ((not (re-search-forward "^[^\n\t]+$" end t)) '(16)) | ||
| 8569 | ((not (re-search-forward "^[^\n,]+$" end t)) '(4)) | ||
| 8570 | (t 1)))) | ||
| 8571 | (setq re (cond | ||
| 8572 | ((equal separator '(4)) "^\\|\"?[ \t]*,[ \t]*\"?") | ||
| 8573 | ((equal separator '(16)) "^\\|\t") | ||
| 8574 | ((integerp separator) | ||
| 8575 | (format "^ *\\| *\t *\\| \\{%d,\\}" separator)) | ||
| 8576 | (t (error "This should not happen")))) | ||
| 8577 | (goto-char beg) | ||
| 8578 | (while (re-search-forward re end t) | ||
| 8579 | (replace-match "| " t t)) | ||
| 8580 | (goto-char beg) | ||
| 8581 | (insert " ") | ||
| 8582 | (org-table-align))) | ||
| 8583 | |||
| 8584 | (defun org-table-import (file arg) | ||
| 8585 | "Import FILE as a table. | ||
| 8586 | The file is assumed to be tab-separated. Such files can be produced by most | ||
| 8587 | spreadsheet and database applications. If no tabs (at least one per line) | ||
| 8588 | are found, lines will be split on whitespace into fields." | ||
| 8589 | (interactive "f\nP") | ||
| 8590 | (or (bolp) (newline)) | ||
| 8591 | (let ((beg (point)) | ||
| 8592 | (pm (point-max))) | ||
| 8593 | (insert-file-contents file) | ||
| 8594 | (org-table-convert-region beg (+ (point) (- (point-max) pm)) arg))) | ||
| 8595 | |||
| 8596 | (defun org-table-export () | ||
| 8597 | "Export table as a tab-separated file. | ||
| 8598 | Such a file can be imported into a spreadsheet program like Excel." | ||
| 8599 | (interactive) | ||
| 8600 | (let* ((beg (org-table-begin)) | ||
| 8601 | (end (org-table-end)) | ||
| 8602 | (table (buffer-substring beg end)) | ||
| 8603 | (file (read-file-name "Export table to: ")) | ||
| 8604 | buf) | ||
| 8605 | (unless (or (not (file-exists-p file)) | ||
| 8606 | (y-or-n-p (format "Overwrite file %s? " file))) | ||
| 8607 | (error "Abort")) | ||
| 8608 | (with-current-buffer (find-file-noselect file) | ||
| 8609 | (setq buf (current-buffer)) | ||
| 8610 | (erase-buffer) | ||
| 8611 | (fundamental-mode) | ||
| 8612 | (insert table) | ||
| 8613 | (goto-char (point-min)) | ||
| 8614 | (while (re-search-forward "^[ \t]*|[ \t]*" nil t) | ||
| 8615 | (replace-match "" t t) | ||
| 8616 | (end-of-line 1)) | ||
| 8617 | (goto-char (point-min)) | ||
| 8618 | (while (re-search-forward "[ \t]*|[ \t]*$" nil t) | ||
| 8619 | (replace-match "" t t) | ||
| 8620 | (goto-char (min (1+ (point)) (point-max)))) | ||
| 8621 | (goto-char (point-min)) | ||
| 8622 | (while (re-search-forward "^-[-+]*$" nil t) | ||
| 8623 | (replace-match "") | ||
| 8624 | (if (looking-at "\n") | ||
| 8625 | (delete-char 1))) | ||
| 8626 | (goto-char (point-min)) | ||
| 8627 | (while (re-search-forward "[ \t]*|[ \t]*" nil t) | ||
| 8628 | (replace-match "\t" t t)) | ||
| 8629 | (save-buffer)) | ||
| 8630 | (kill-buffer buf))) | ||
| 8631 | |||
| 8632 | (defvar org-table-aligned-begin-marker (make-marker) | ||
| 8633 | "Marker at the beginning of the table last aligned. | ||
| 8634 | Used to check if cursor still is in that table, to minimize realignment.") | ||
| 8635 | (defvar org-table-aligned-end-marker (make-marker) | ||
| 8636 | "Marker at the end of the table last aligned. | ||
| 8637 | Used to check if cursor still is in that table, to minimize realignment.") | ||
| 8638 | (defvar org-table-last-alignment nil | ||
| 8639 | "List of flags for flushright alignment, from the last re-alignment. | ||
| 8640 | This is being used to correctly align a single field after TAB or RET.") | ||
| 8641 | (defvar org-table-last-column-widths nil | ||
| 8642 | "List of max width of fields in each column. | ||
| 8643 | This is being used to correctly align a single field after TAB or RET.") | ||
| 8644 | (defvar org-table-overlay-coordinates nil | ||
| 8645 | "Overlay coordinates after each align of a table.") | ||
| 8646 | (make-variable-buffer-local 'org-table-overlay-coordinates) | ||
| 8647 | |||
| 8648 | (defvar org-last-recalc-line nil) | ||
| 8649 | (defconst org-narrow-column-arrow "=>" | ||
| 8650 | "Used as display property in narrowed table columns.") | ||
| 8651 | |||
| 8652 | (defun org-table-align () | ||
| 8653 | "Align the table at point by aligning all vertical bars." | ||
| 8654 | (interactive) | ||
| 8655 | (let* ( | ||
| 8656 | ;; Limits of table | ||
| 8657 | (beg (org-table-begin)) | ||
| 8658 | (end (org-table-end)) | ||
| 8659 | ;; Current cursor position | ||
| 8660 | (linepos (org-current-line)) | ||
| 8661 | (colpos (org-table-current-column)) | ||
| 8662 | (winstart (window-start)) | ||
| 8663 | (winstartline (org-current-line (min winstart (1- (point-max))))) | ||
| 8664 | lines (new "") lengths l typenums ty fields maxfields i | ||
| 8665 | column | ||
| 8666 | (indent "") cnt frac | ||
| 8667 | rfmt hfmt | ||
| 8668 | (spaces '(1 . 1)) | ||
| 8669 | (sp1 (car spaces)) | ||
| 8670 | (sp2 (cdr spaces)) | ||
| 8671 | (rfmt1 (concat | ||
| 8672 | (make-string sp2 ?\ ) "%%%s%ds" (make-string sp1 ?\ ) "|")) | ||
| 8673 | (hfmt1 (concat | ||
| 8674 | (make-string sp2 ?-) "%s" (make-string sp1 ?-) "+")) | ||
| 8675 | emptystrings links dates emph narrow fmax f1 len c e) | ||
| 8676 | (untabify beg end) | ||
| 8677 | (remove-text-properties beg end '(org-cwidth t org-dwidth t display t)) | ||
| 8678 | ;; Check if we have links or dates | ||
| 8679 | (goto-char beg) | ||
| 8680 | (setq links (re-search-forward org-bracket-link-regexp end t)) | ||
| 8681 | (goto-char beg) | ||
| 8682 | (setq emph (and org-hide-emphasis-markers | ||
| 8683 | (re-search-forward org-emph-re end t))) | ||
| 8684 | (goto-char beg) | ||
| 8685 | (setq dates (and org-display-custom-times | ||
| 8686 | (re-search-forward org-ts-regexp-both end t))) | ||
| 8687 | ;; Make sure the link properties are right | ||
| 8688 | (when links (goto-char beg) (while (org-activate-bracket-links end))) | ||
| 8689 | ;; Make sure the date properties are right | ||
| 8690 | (when dates (goto-char beg) (while (org-activate-dates end))) | ||
| 8691 | (when emph (goto-char beg) (while (org-do-emphasis-faces end))) | ||
| 8692 | |||
| 8693 | ;; Check if we are narrowing any columns | ||
| 8694 | (goto-char beg) | ||
| 8695 | (setq narrow (and org-format-transports-properties-p | ||
| 8696 | (re-search-forward "<[0-9]+>" end t))) | ||
| 8697 | ;; Get the rows | ||
| 8698 | (setq lines (org-split-string | ||
| 8699 | (buffer-substring beg end) "\n")) | ||
| 8700 | ;; Store the indentation of the first line | ||
| 8701 | (if (string-match "^ *" (car lines)) | ||
| 8702 | (setq indent (make-string (- (match-end 0) (match-beginning 0)) ?\ ))) | ||
| 8703 | ;; Mark the hlines by setting the corresponding element to nil | ||
| 8704 | ;; At the same time, we remove trailing space. | ||
| 8705 | (setq lines (mapcar (lambda (l) | ||
| 8706 | (if (string-match "^ *|-" l) | ||
| 8707 | nil | ||
| 8708 | (if (string-match "[ \t]+$" l) | ||
| 8709 | (substring l 0 (match-beginning 0)) | ||
| 8710 | l))) | ||
| 8711 | lines)) | ||
| 8712 | ;; Get the data fields by splitting the lines. | ||
| 8713 | (setq fields (mapcar | ||
| 8714 | (lambda (l) | ||
| 8715 | (org-split-string l " *| *")) | ||
| 8716 | (delq nil (copy-sequence lines)))) | ||
| 8717 | ;; How many fields in the longest line? | ||
| 8718 | (condition-case nil | ||
| 8719 | (setq maxfields (apply 'max (mapcar 'length fields))) | ||
| 8720 | (error | ||
| 8721 | (kill-region beg end) | ||
| 8722 | (org-table-create org-table-default-size) | ||
| 8723 | (error "Empty table - created default table"))) | ||
| 8724 | ;; A list of empty strings to fill any short rows on output | ||
| 8725 | (setq emptystrings (make-list maxfields "")) | ||
| 8726 | ;; Check for special formatting. | ||
| 8727 | (setq i -1) | ||
| 8728 | (while (< (setq i (1+ i)) maxfields) ;; Loop over all columns | ||
| 8729 | (setq column (mapcar (lambda (x) (or (nth i x) "")) fields)) | ||
| 8730 | ;; Check if there is an explicit width specified | ||
| 8731 | (when narrow | ||
| 8732 | (setq c column fmax nil) | ||
| 8733 | (while c | ||
| 8734 | (setq e (pop c)) | ||
| 8735 | (if (and (stringp e) (string-match "^<\\([0-9]+\\)>$" e)) | ||
| 8736 | (setq fmax (string-to-number (match-string 1 e)) c nil))) | ||
| 8737 | ;; Find fields that are wider than fmax, and shorten them | ||
| 8738 | (when fmax | ||
| 8739 | (loop for xx in column do | ||
| 8740 | (when (and (stringp xx) | ||
| 8741 | (> (org-string-width xx) fmax)) | ||
| 8742 | (org-add-props xx nil | ||
| 8743 | 'help-echo | ||
| 8744 | (concat "Clipped table field, use C-c ` to edit. Full value is:\n" (org-no-properties (copy-sequence xx)))) | ||
| 8745 | (setq f1 (min fmax (or (string-match org-bracket-link-regexp xx) fmax))) | ||
| 8746 | (unless (> f1 1) | ||
| 8747 | (error "Cannot narrow field starting with wide link \"%s\"" | ||
| 8748 | (match-string 0 xx))) | ||
| 8749 | (add-text-properties f1 (length xx) (list 'org-cwidth t) xx) | ||
| 8750 | (add-text-properties (- f1 2) f1 | ||
| 8751 | (list 'display org-narrow-column-arrow) | ||
| 8752 | xx))))) | ||
| 8753 | ;; Get the maximum width for each column | ||
| 8754 | (push (apply 'max 1 (mapcar 'org-string-width column)) lengths) | ||
| 8755 | ;; Get the fraction of numbers, to decide about alignment of the column | ||
| 8756 | (setq cnt 0 frac 0.0) | ||
| 8757 | (loop for x in column do | ||
| 8758 | (if (equal x "") | ||
| 8759 | nil | ||
| 8760 | (setq frac ( / (+ (* frac cnt) | ||
| 8761 | (if (string-match org-table-number-regexp x) 1 0)) | ||
| 8762 | (setq cnt (1+ cnt)))))) | ||
| 8763 | (push (>= frac org-table-number-fraction) typenums)) | ||
| 8764 | (setq lengths (nreverse lengths) typenums (nreverse typenums)) | ||
| 8765 | |||
| 8766 | ;; Store the alignment of this table, for later editing of single fields | ||
| 8767 | (setq org-table-last-alignment typenums | ||
| 8768 | org-table-last-column-widths lengths) | ||
| 8769 | |||
| 8770 | ;; With invisible characters, `format' does not get the field width right | ||
| 8771 | ;; So we need to make these fields wide by hand. | ||
| 8772 | (when (or links emph) | ||
| 8773 | (loop for i from 0 upto (1- maxfields) do | ||
| 8774 | (setq len (nth i lengths)) | ||
| 8775 | (loop for j from 0 upto (1- (length fields)) do | ||
| 8776 | (setq c (nthcdr i (car (nthcdr j fields)))) | ||
| 8777 | (if (and (stringp (car c)) | ||
| 8778 | (text-property-any 0 (length (car c)) 'invisible 'org-link (car c)) | ||
| 8779 | ; (string-match org-bracket-link-regexp (car c)) | ||
| 8780 | (< (org-string-width (car c)) len)) | ||
| 8781 | (setcar c (concat (car c) (make-string (- len (org-string-width (car c))) ?\ ))))))) | ||
| 8782 | |||
| 8783 | ;; Compute the formats needed for output of the table | ||
| 8784 | (setq rfmt (concat indent "|") hfmt (concat indent "|")) | ||
| 8785 | (while (setq l (pop lengths)) | ||
| 8786 | (setq ty (if (pop typenums) "" "-")) ; number types flushright | ||
| 8787 | (setq rfmt (concat rfmt (format rfmt1 ty l)) | ||
| 8788 | hfmt (concat hfmt (format hfmt1 (make-string l ?-))))) | ||
| 8789 | (setq rfmt (concat rfmt "\n") | ||
| 8790 | hfmt (concat (substring hfmt 0 -1) "|\n")) | ||
| 8791 | |||
| 8792 | (setq new (mapconcat | ||
| 8793 | (lambda (l) | ||
| 8794 | (if l (apply 'format rfmt | ||
| 8795 | (append (pop fields) emptystrings)) | ||
| 8796 | hfmt)) | ||
| 8797 | lines "")) | ||
| 8798 | ;; Replace the old one | ||
| 8799 | (delete-region beg end) | ||
| 8800 | (move-marker end nil) | ||
| 8801 | (move-marker org-table-aligned-begin-marker (point)) | ||
| 8802 | (insert new) | ||
| 8803 | (move-marker org-table-aligned-end-marker (point)) | ||
| 8804 | (when (and orgtbl-mode (not (org-mode-p))) | ||
| 8805 | (goto-char org-table-aligned-begin-marker) | ||
| 8806 | (while (org-hide-wide-columns org-table-aligned-end-marker))) | ||
| 8807 | ;; Try to move to the old location | ||
| 8808 | (goto-line winstartline) | ||
| 8809 | (setq winstart (point-at-bol)) | ||
| 8810 | (goto-line linepos) | ||
| 8811 | (set-window-start (selected-window) winstart 'noforce) | ||
| 8812 | (org-table-goto-column colpos) | ||
| 8813 | (and org-table-overlay-coordinates (org-table-overlay-coordinates)) | ||
| 8814 | (setq org-table-may-need-update nil) | ||
| 8815 | )) | ||
| 8816 | |||
| 8817 | (defun org-string-width (s) | ||
| 8818 | "Compute width of string, ignoring invisible characters. | ||
| 8819 | This ignores character with invisibility property `org-link', and also | ||
| 8820 | characters with property `org-cwidth', because these will become invisible | ||
| 8821 | upon the next fontification round." | ||
| 8822 | (let (b l) | ||
| 8823 | (when (or (eq t buffer-invisibility-spec) | ||
| 8824 | (assq 'org-link buffer-invisibility-spec)) | ||
| 8825 | (while (setq b (text-property-any 0 (length s) | ||
| 8826 | 'invisible 'org-link s)) | ||
| 8827 | (setq s (concat (substring s 0 b) | ||
| 8828 | (substring s (or (next-single-property-change | ||
| 8829 | b 'invisible s) (length s))))))) | ||
| 8830 | (while (setq b (text-property-any 0 (length s) 'org-cwidth t s)) | ||
| 8831 | (setq s (concat (substring s 0 b) | ||
| 8832 | (substring s (or (next-single-property-change | ||
| 8833 | b 'org-cwidth s) (length s)))))) | ||
| 8834 | (setq l (string-width s) b -1) | ||
| 8835 | (while (setq b (text-property-any (1+ b) (length s) 'org-dwidth t s)) | ||
| 8836 | (setq l (- l (get-text-property b 'org-dwidth-n s)))) | ||
| 8837 | l)) | ||
| 8838 | |||
| 8839 | (defun org-table-begin (&optional table-type) | ||
| 8840 | "Find the beginning of the table and return its position. | ||
| 8841 | With argument TABLE-TYPE, go to the beginning of a table.el-type table." | ||
| 8842 | (save-excursion | ||
| 8843 | (if (not (re-search-backward | ||
| 8844 | (if table-type org-table-any-border-regexp | ||
| 8845 | org-table-border-regexp) | ||
| 8846 | nil t)) | ||
| 8847 | (progn (goto-char (point-min)) (point)) | ||
| 8848 | (goto-char (match-beginning 0)) | ||
| 8849 | (beginning-of-line 2) | ||
| 8850 | (point)))) | ||
| 8851 | |||
| 8852 | (defun org-table-end (&optional table-type) | ||
| 8853 | "Find the end of the table and return its position. | ||
| 8854 | With argument TABLE-TYPE, go to the end of a table.el-type table." | ||
| 8855 | (save-excursion | ||
| 8856 | (if (not (re-search-forward | ||
| 8857 | (if table-type org-table-any-border-regexp | ||
| 8858 | org-table-border-regexp) | ||
| 8859 | nil t)) | ||
| 8860 | (goto-char (point-max)) | ||
| 8861 | (goto-char (match-beginning 0))) | ||
| 8862 | (point-marker))) | ||
| 8863 | |||
| 8864 | (defun org-table-justify-field-maybe (&optional new) | ||
| 8865 | "Justify the current field, text to left, number to right. | ||
| 8866 | Optional argument NEW may specify text to replace the current field content." | ||
| 8867 | (cond | ||
| 8868 | ((and (not new) org-table-may-need-update)) ; Realignment will happen anyway | ||
| 8869 | ((org-at-table-hline-p)) | ||
| 8870 | ((and (not new) | ||
| 8871 | (or (not (equal (marker-buffer org-table-aligned-begin-marker) | ||
| 8872 | (current-buffer))) | ||
| 8873 | (< (point) org-table-aligned-begin-marker) | ||
| 8874 | (>= (point) org-table-aligned-end-marker))) | ||
| 8875 | ;; This is not the same table, force a full re-align | ||
| 8876 | (setq org-table-may-need-update t)) | ||
| 8877 | (t ;; realign the current field, based on previous full realign | ||
| 8878 | (let* ((pos (point)) s | ||
| 8879 | (col (org-table-current-column)) | ||
| 8880 | (num (if (> col 0) (nth (1- col) org-table-last-alignment))) | ||
| 8881 | l f n o e) | ||
| 8882 | (when (> col 0) | ||
| 8883 | (skip-chars-backward "^|\n") | ||
| 8884 | (if (looking-at " *\\([^|\n]*?\\) *\\(|\\|$\\)") | ||
| 8885 | (progn | ||
| 8886 | (setq s (match-string 1) | ||
| 8887 | o (match-string 0) | ||
| 8888 | l (max 1 (- (match-end 0) (match-beginning 0) 3)) | ||
| 8889 | e (not (= (match-beginning 2) (match-end 2)))) | ||
| 8890 | (setq f (format (if num " %%%ds %s" " %%-%ds %s") | ||
| 8891 | l (if e "|" (setq org-table-may-need-update t) "")) | ||
| 8892 | n (format f s)) | ||
| 8893 | (if new | ||
| 8894 | (if (<= (length new) l) ;; FIXME: length -> str-width? | ||
| 8895 | (setq n (format f new)) | ||
| 8896 | (setq n (concat new "|") org-table-may-need-update t))) | ||
| 8897 | (or (equal n o) | ||
| 8898 | (let (org-table-may-need-update) | ||
| 8899 | (replace-match n t t)))) | ||
| 8900 | (setq org-table-may-need-update t)) | ||
| 8901 | (goto-char pos)))))) | ||
| 8902 | |||
| 8903 | (defun org-table-next-field () | ||
| 8904 | "Go to the next field in the current table, creating new lines as needed. | ||
| 8905 | Before doing so, re-align the table if necessary." | ||
| 8906 | (interactive) | ||
| 8907 | (org-table-maybe-eval-formula) | ||
| 8908 | (org-table-maybe-recalculate-line) | ||
| 8909 | (if (and org-table-automatic-realign | ||
| 8910 | org-table-may-need-update) | ||
| 8911 | (org-table-align)) | ||
| 8912 | (let ((end (org-table-end))) | ||
| 8913 | (if (org-at-table-hline-p) | ||
| 8914 | (end-of-line 1)) | ||
| 8915 | (condition-case nil | ||
| 8916 | (progn | ||
| 8917 | (re-search-forward "|" end) | ||
| 8918 | (if (looking-at "[ \t]*$") | ||
| 8919 | (re-search-forward "|" end)) | ||
| 8920 | (if (and (looking-at "-") | ||
| 8921 | org-table-tab-jumps-over-hlines | ||
| 8922 | (re-search-forward "^[ \t]*|\\([^-]\\)" end t)) | ||
| 8923 | (goto-char (match-beginning 1))) | ||
| 8924 | (if (looking-at "-") | ||
| 8925 | (progn | ||
| 8926 | (beginning-of-line 0) | ||
| 8927 | (org-table-insert-row 'below)) | ||
| 8928 | (if (looking-at " ") (forward-char 1)))) | ||
| 8929 | (error | ||
| 8930 | (org-table-insert-row 'below))))) | ||
| 8931 | |||
| 8932 | (defun org-table-previous-field () | ||
| 8933 | "Go to the previous field in the table. | ||
| 8934 | Before doing so, re-align the table if necessary." | ||
| 8935 | (interactive) | ||
| 8936 | (org-table-justify-field-maybe) | ||
| 8937 | (org-table-maybe-recalculate-line) | ||
| 8938 | (if (and org-table-automatic-realign | ||
| 8939 | org-table-may-need-update) | ||
| 8940 | (org-table-align)) | ||
| 8941 | (if (org-at-table-hline-p) | ||
| 8942 | (end-of-line 1)) | ||
| 8943 | (re-search-backward "|" (org-table-begin)) | ||
| 8944 | (re-search-backward "|" (org-table-begin)) | ||
| 8945 | (while (looking-at "|\\(-\\|[ \t]*$\\)") | ||
| 8946 | (re-search-backward "|" (org-table-begin))) | ||
| 8947 | (if (looking-at "| ?") | ||
| 8948 | (goto-char (match-end 0)))) | ||
| 8949 | |||
| 8950 | (defun org-table-next-row () | ||
| 8951 | "Go to the next row (same column) in the current table. | ||
| 8952 | Before doing so, re-align the table if necessary." | ||
| 8953 | (interactive) | ||
| 8954 | (org-table-maybe-eval-formula) | ||
| 8955 | (org-table-maybe-recalculate-line) | ||
| 8956 | (if (or (looking-at "[ \t]*$") | ||
| 8957 | (save-excursion (skip-chars-backward " \t") (bolp))) | ||
| 8958 | (newline) | ||
| 8959 | (if (and org-table-automatic-realign | ||
| 8960 | org-table-may-need-update) | ||
| 8961 | (org-table-align)) | ||
| 8962 | (let ((col (org-table-current-column))) | ||
| 8963 | (beginning-of-line 2) | ||
| 8964 | (if (or (not (org-at-table-p)) | ||
| 8965 | (org-at-table-hline-p)) | ||
| 8966 | (progn | ||
| 8967 | (beginning-of-line 0) | ||
| 8968 | (org-table-insert-row 'below))) | ||
| 8969 | (org-table-goto-column col) | ||
| 8970 | (skip-chars-backward "^|\n\r") | ||
| 8971 | (if (looking-at " ") (forward-char 1))))) | ||
| 8972 | |||
| 8973 | (defun org-table-copy-down (n) | ||
| 8974 | "Copy a field down in the current column. | ||
| 8975 | If the field at the cursor is empty, copy into it the content of the nearest | ||
| 8976 | non-empty field above. With argument N, use the Nth non-empty field. | ||
| 8977 | If the current field is not empty, it is copied down to the next row, and | ||
| 8978 | the cursor is moved with it. Therefore, repeating this command causes the | ||
| 8979 | column to be filled row-by-row. | ||
| 8980 | If the variable `org-table-copy-increment' is non-nil and the field is an | ||
| 8981 | integer or a timestamp, it will be incremented while copying. In the case of | ||
| 8982 | a timestamp, if the cursor is on the year, change the year. If it is on the | ||
| 8983 | month or the day, change that. Point will stay on the current date field | ||
| 8984 | in order to easily repeat the interval." | ||
| 8985 | (interactive "p") | ||
| 8986 | (let* ((colpos (org-table-current-column)) | ||
| 8987 | (col (current-column)) | ||
| 8988 | (field (org-table-get-field)) | ||
| 8989 | (non-empty (string-match "[^ \t]" field)) | ||
| 8990 | (beg (org-table-begin)) | ||
| 8991 | txt) | ||
| 8992 | (org-table-check-inside-data-field) | ||
| 8993 | (if non-empty | ||
| 8994 | (progn | ||
| 8995 | (setq txt (org-trim field)) | ||
| 8996 | (org-table-next-row) | ||
| 8997 | (org-table-blank-field)) | ||
| 8998 | (save-excursion | ||
| 8999 | (setq txt | ||
| 9000 | (catch 'exit | ||
| 9001 | (while (progn (beginning-of-line 1) | ||
| 9002 | (re-search-backward org-table-dataline-regexp | ||
| 9003 | beg t)) | ||
| 9004 | (org-table-goto-column colpos t) | ||
| 9005 | (if (and (looking-at | ||
| 9006 | "|[ \t]*\\([^| \t][^|]*?\\)[ \t]*|") | ||
| 9007 | (= (setq n (1- n)) 0)) | ||
| 9008 | (throw 'exit (match-string 1)))))))) | ||
| 9009 | (if txt | ||
| 9010 | (progn | ||
| 9011 | (if (and org-table-copy-increment | ||
| 9012 | (string-match "^[0-9]+$" txt)) | ||
| 9013 | (setq txt (format "%d" (+ (string-to-number txt) 1)))) | ||
| 9014 | (insert txt) | ||
| 9015 | (move-to-column col) | ||
| 9016 | (if (and org-table-copy-increment (org-at-timestamp-p t)) | ||
| 9017 | (org-timestamp-up 1) | ||
| 9018 | (org-table-maybe-recalculate-line)) | ||
| 9019 | (org-table-align) | ||
| 9020 | (move-to-column col)) | ||
| 9021 | (error "No non-empty field found")))) | ||
| 9022 | |||
| 9023 | (defun org-table-check-inside-data-field () | ||
| 9024 | "Is point inside a table data field? | ||
| 9025 | I.e. not on a hline or before the first or after the last column? | ||
| 9026 | This actually throws an error, so it aborts the current command." | ||
| 9027 | (if (or (not (org-at-table-p)) | ||
| 9028 | (= (org-table-current-column) 0) | ||
| 9029 | (org-at-table-hline-p) | ||
| 9030 | (looking-at "[ \t]*$")) | ||
| 9031 | (error "Not in table data field"))) | ||
| 9032 | |||
| 9033 | (defvar org-table-clip nil | ||
| 9034 | "Clipboard for table regions.") | ||
| 9035 | |||
| 9036 | (defun org-table-blank-field () | ||
| 9037 | "Blank the current table field or active region." | ||
| 9038 | (interactive) | ||
| 9039 | (org-table-check-inside-data-field) | ||
| 9040 | (if (and (interactive-p) (org-region-active-p)) | ||
| 9041 | (let (org-table-clip) | ||
| 9042 | (org-table-cut-region (region-beginning) (region-end))) | ||
| 9043 | (skip-chars-backward "^|") | ||
| 9044 | (backward-char 1) | ||
| 9045 | (if (looking-at "|[^|\n]+") | ||
| 9046 | (let* ((pos (match-beginning 0)) | ||
| 9047 | (match (match-string 0)) | ||
| 9048 | (len (org-string-width match))) | ||
| 9049 | (replace-match (concat "|" (make-string (1- len) ?\ ))) | ||
| 9050 | (goto-char (+ 2 pos)) | ||
| 9051 | (substring match 1))))) | ||
| 9052 | |||
| 9053 | (defun org-table-get-field (&optional n replace) | ||
| 9054 | "Return the value of the field in column N of current row. | ||
| 9055 | N defaults to current field. | ||
| 9056 | If REPLACE is a string, replace field with this value. The return value | ||
| 9057 | is always the old value." | ||
| 9058 | (and n (org-table-goto-column n)) | ||
| 9059 | (skip-chars-backward "^|\n") | ||
| 9060 | (backward-char 1) | ||
| 9061 | (if (looking-at "|[^|\r\n]*") | ||
| 9062 | (let* ((pos (match-beginning 0)) | ||
| 9063 | (val (buffer-substring (1+ pos) (match-end 0)))) | ||
| 9064 | (if replace | ||
| 9065 | (replace-match (concat "|" replace) t t)) | ||
| 9066 | (goto-char (min (point-at-eol) (+ 2 pos))) | ||
| 9067 | val) | ||
| 9068 | (forward-char 1) "")) | ||
| 9069 | |||
| 9070 | (defun org-table-field-info (arg) | ||
| 9071 | "Show info about the current field, and highlight any reference at point." | ||
| 9072 | (interactive "P") | ||
| 9073 | (org-table-get-specials) | ||
| 9074 | (save-excursion | ||
| 9075 | (let* ((pos (point)) | ||
| 9076 | (col (org-table-current-column)) | ||
| 9077 | (cname (car (rassoc (int-to-string col) org-table-column-names))) | ||
| 9078 | (name (car (rassoc (list (org-current-line) col) | ||
| 9079 | org-table-named-field-locations))) | ||
| 9080 | (eql (org-table-get-stored-formulas)) | ||
| 9081 | (dline (org-table-current-dline)) | ||
| 9082 | (ref (format "@%d$%d" dline col)) | ||
| 9083 | (ref1 (org-table-convert-refs-to-an ref)) | ||
| 9084 | (fequation (or (assoc name eql) (assoc ref eql))) | ||
| 9085 | (cequation (assoc (int-to-string col) eql)) | ||
| 9086 | (eqn (or fequation cequation))) | ||
| 9087 | (goto-char pos) | ||
| 9088 | (condition-case nil | ||
| 9089 | (org-table-show-reference 'local) | ||
| 9090 | (error nil)) | ||
| 9091 | (message "line @%d, col $%s%s, ref @%d$%d or %s%s%s" | ||
| 9092 | dline col | ||
| 9093 | (if cname (concat " or $" cname) "") | ||
| 9094 | dline col ref1 | ||
| 9095 | (if name (concat " or $" name) "") | ||
| 9096 | ;; FIXME: formula info not correct if special table line | ||
| 9097 | (if eqn | ||
| 9098 | (concat ", formula: " | ||
| 9099 | (org-table-formula-to-user | ||
| 9100 | (concat | ||
| 9101 | (if (string-match "^[$@]"(car eqn)) "" "$") | ||
| 9102 | (car eqn) "=" (cdr eqn)))) | ||
| 9103 | ""))))) | ||
| 9104 | |||
| 9105 | (defun org-table-current-column () | ||
| 9106 | "Find out which column we are in. | ||
| 9107 | When called interactively, column is also displayed in echo area." | ||
| 9108 | (interactive) | ||
| 9109 | (if (interactive-p) (org-table-check-inside-data-field)) | ||
| 9110 | (save-excursion | ||
| 9111 | (let ((cnt 0) (pos (point))) | ||
| 9112 | (beginning-of-line 1) | ||
| 9113 | (while (search-forward "|" pos t) | ||
| 9114 | (setq cnt (1+ cnt))) | ||
| 9115 | (if (interactive-p) (message "This is table column %d" cnt)) | ||
| 9116 | cnt))) | ||
| 9117 | |||
| 9118 | (defun org-table-current-dline () | ||
| 9119 | "Find out what table data line we are in. | ||
| 9120 | Only datalins count for this." | ||
| 9121 | (interactive) | ||
| 9122 | (if (interactive-p) (org-table-check-inside-data-field)) | ||
| 9123 | (save-excursion | ||
| 9124 | (let ((cnt 0) (pos (point))) | ||
| 9125 | (goto-char (org-table-begin)) | ||
| 9126 | (while (<= (point) pos) | ||
| 9127 | (if (looking-at org-table-dataline-regexp) (setq cnt (1+ cnt))) | ||
| 9128 | (beginning-of-line 2)) | ||
| 9129 | (if (interactive-p) (message "This is table line %d" cnt)) | ||
| 9130 | cnt))) | ||
| 9131 | |||
| 9132 | (defun org-table-goto-column (n &optional on-delim force) | ||
| 9133 | "Move the cursor to the Nth column in the current table line. | ||
| 9134 | With optional argument ON-DELIM, stop with point before the left delimiter | ||
| 9135 | of the field. | ||
| 9136 | If there are less than N fields, just go to after the last delimiter. | ||
| 9137 | However, when FORCE is non-nil, create new columns if necessary." | ||
| 9138 | (interactive "p") | ||
| 9139 | (let ((pos (point-at-eol))) | ||
| 9140 | (beginning-of-line 1) | ||
| 9141 | (when (> n 0) | ||
| 9142 | (while (and (> (setq n (1- n)) -1) | ||
| 9143 | (or (search-forward "|" pos t) | ||
| 9144 | (and force | ||
| 9145 | (progn (end-of-line 1) | ||
| 9146 | (skip-chars-backward "^|") | ||
| 9147 | (insert " | ")))))) | ||
| 9148 | ; (backward-char 2) t))))) | ||
| 9149 | (when (and force (not (looking-at ".*|"))) | ||
| 9150 | (save-excursion (end-of-line 1) (insert " | "))) | ||
| 9151 | (if on-delim | ||
| 9152 | (backward-char 1) | ||
| 9153 | (if (looking-at " ") (forward-char 1)))))) | ||
| 9154 | |||
| 9155 | (defun org-at-table-p (&optional table-type) | ||
| 9156 | "Return t if the cursor is inside an org-type table. | ||
| 9157 | If TABLE-TYPE is non-nil, also check for table.el-type tables." | ||
| 9158 | (if org-enable-table-editor | ||
| 9159 | (save-excursion | ||
| 9160 | (beginning-of-line 1) | ||
| 9161 | (looking-at (if table-type org-table-any-line-regexp | ||
| 9162 | org-table-line-regexp))) | ||
| 9163 | nil)) | ||
| 9164 | |||
| 9165 | (defun org-at-table.el-p () | ||
| 9166 | "Return t if and only if we are at a table.el table." | ||
| 9167 | (and (org-at-table-p 'any) | ||
| 9168 | (save-excursion | ||
| 9169 | (goto-char (org-table-begin 'any)) | ||
| 9170 | (looking-at org-table1-hline-regexp)))) | ||
| 9171 | |||
| 9172 | (defun org-table-recognize-table.el () | ||
| 9173 | "If there is a table.el table nearby, recognize it and move into it." | ||
| 9174 | (if org-table-tab-recognizes-table.el | ||
| 9175 | (if (org-at-table.el-p) | ||
| 9176 | (progn | ||
| 9177 | (beginning-of-line 1) | ||
| 9178 | (if (looking-at org-table-dataline-regexp) | ||
| 9179 | nil | ||
| 9180 | (if (looking-at org-table1-hline-regexp) | ||
| 9181 | (progn | ||
| 9182 | (beginning-of-line 2) | ||
| 9183 | (if (looking-at org-table-any-border-regexp) | ||
| 9184 | (beginning-of-line -1))))) | ||
| 9185 | (if (re-search-forward "|" (org-table-end t) t) | ||
| 9186 | (progn | ||
| 9187 | (require 'table) | ||
| 9188 | (if (table--at-cell-p (point)) | ||
| 9189 | t | ||
| 9190 | (message "recognizing table.el table...") | ||
| 9191 | (table-recognize-table) | ||
| 9192 | (message "recognizing table.el table...done"))) | ||
| 9193 | (error "This should not happen...")) | ||
| 9194 | t) | ||
| 9195 | nil) | ||
| 9196 | nil)) | ||
| 9197 | |||
| 9198 | (defun org-at-table-hline-p () | ||
| 9199 | "Return t if the cursor is inside a hline in a table." | ||
| 9200 | (if org-enable-table-editor | ||
| 9201 | (save-excursion | ||
| 9202 | (beginning-of-line 1) | ||
| 9203 | (looking-at org-table-hline-regexp)) | ||
| 9204 | nil)) | ||
| 9205 | |||
| 9206 | (defun org-table-insert-column () | ||
| 9207 | "Insert a new column into the table." | ||
| 9208 | (interactive) | ||
| 9209 | (if (not (org-at-table-p)) | ||
| 9210 | (error "Not at a table")) | ||
| 9211 | (org-table-find-dataline) | ||
| 9212 | (let* ((col (max 1 (org-table-current-column))) | ||
| 9213 | (beg (org-table-begin)) | ||
| 9214 | (end (org-table-end)) | ||
| 9215 | ;; Current cursor position | ||
| 9216 | (linepos (org-current-line)) | ||
| 9217 | (colpos col)) | ||
| 9218 | (goto-char beg) | ||
| 9219 | (while (< (point) end) | ||
| 9220 | (if (org-at-table-hline-p) | ||
| 9221 | nil | ||
| 9222 | (org-table-goto-column col t) | ||
| 9223 | (insert "| ")) | ||
| 9224 | (beginning-of-line 2)) | ||
| 9225 | (move-marker end nil) | ||
| 9226 | (goto-line linepos) | ||
| 9227 | (org-table-goto-column colpos) | ||
| 9228 | (org-table-align) | ||
| 9229 | (org-table-fix-formulas "$" nil (1- col) 1))) | ||
| 9230 | |||
| 9231 | (defun org-table-find-dataline () | ||
| 9232 | "Find a dataline in the current table, which is needed for column commands." | ||
| 9233 | (if (and (org-at-table-p) | ||
| 9234 | (not (org-at-table-hline-p))) | ||
| 9235 | t | ||
| 9236 | (let ((col (current-column)) | ||
| 9237 | (end (org-table-end))) | ||
| 9238 | (move-to-column col) | ||
| 9239 | (while (and (< (point) end) | ||
| 9240 | (or (not (= (current-column) col)) | ||
| 9241 | (org-at-table-hline-p))) | ||
| 9242 | (beginning-of-line 2) | ||
| 9243 | (move-to-column col)) | ||
| 9244 | (if (and (org-at-table-p) | ||
| 9245 | (not (org-at-table-hline-p))) | ||
| 9246 | t | ||
| 9247 | (error | ||
| 9248 | "Please position cursor in a data line for column operations"))))) | ||
| 9249 | |||
| 9250 | (defun org-table-delete-column () | ||
| 9251 | "Delete a column from the table." | ||
| 9252 | (interactive) | ||
| 9253 | (if (not (org-at-table-p)) | ||
| 9254 | (error "Not at a table")) | ||
| 9255 | (org-table-find-dataline) | ||
| 9256 | (org-table-check-inside-data-field) | ||
| 9257 | (let* ((col (org-table-current-column)) | ||
| 9258 | (beg (org-table-begin)) | ||
| 9259 | (end (org-table-end)) | ||
| 9260 | ;; Current cursor position | ||
| 9261 | (linepos (org-current-line)) | ||
| 9262 | (colpos col)) | ||
| 9263 | (goto-char beg) | ||
| 9264 | (while (< (point) end) | ||
| 9265 | (if (org-at-table-hline-p) | ||
| 9266 | nil | ||
| 9267 | (org-table-goto-column col t) | ||
| 9268 | (and (looking-at "|[^|\n]+|") | ||
| 9269 | (replace-match "|"))) | ||
| 9270 | (beginning-of-line 2)) | ||
| 9271 | (move-marker end nil) | ||
| 9272 | (goto-line linepos) | ||
| 9273 | (org-table-goto-column colpos) | ||
| 9274 | (org-table-align) | ||
| 9275 | (org-table-fix-formulas "$" (list (cons (number-to-string col) "INVALID")) | ||
| 9276 | col -1 col))) | ||
| 9277 | |||
| 9278 | (defun org-table-move-column-right () | ||
| 9279 | "Move column to the right." | ||
| 9280 | (interactive) | ||
| 9281 | (org-table-move-column nil)) | ||
| 9282 | (defun org-table-move-column-left () | ||
| 9283 | "Move column to the left." | ||
| 9284 | (interactive) | ||
| 9285 | (org-table-move-column 'left)) | ||
| 9286 | |||
| 9287 | (defun org-table-move-column (&optional left) | ||
| 9288 | "Move the current column to the right. With arg LEFT, move to the left." | ||
| 9289 | (interactive "P") | ||
| 9290 | (if (not (org-at-table-p)) | ||
| 9291 | (error "Not at a table")) | ||
| 9292 | (org-table-find-dataline) | ||
| 9293 | (org-table-check-inside-data-field) | ||
| 9294 | (let* ((col (org-table-current-column)) | ||
| 9295 | (col1 (if left (1- col) col)) | ||
| 9296 | (beg (org-table-begin)) | ||
| 9297 | (end (org-table-end)) | ||
| 9298 | ;; Current cursor position | ||
| 9299 | (linepos (org-current-line)) | ||
| 9300 | (colpos (if left (1- col) (1+ col)))) | ||
| 9301 | (if (and left (= col 1)) | ||
| 9302 | (error "Cannot move column further left")) | ||
| 9303 | (if (and (not left) (looking-at "[^|\n]*|[^|\n]*$")) | ||
| 9304 | (error "Cannot move column further right")) | ||
| 9305 | (goto-char beg) | ||
| 9306 | (while (< (point) end) | ||
| 9307 | (if (org-at-table-hline-p) | ||
| 9308 | nil | ||
| 9309 | (org-table-goto-column col1 t) | ||
| 9310 | (and (looking-at "|\\([^|\n]+\\)|\\([^|\n]+\\)|") | ||
| 9311 | (replace-match "|\\2|\\1|"))) | ||
| 9312 | (beginning-of-line 2)) | ||
| 9313 | (move-marker end nil) | ||
| 9314 | (goto-line linepos) | ||
| 9315 | (org-table-goto-column colpos) | ||
| 9316 | (org-table-align) | ||
| 9317 | (org-table-fix-formulas | ||
| 9318 | "$" (list (cons (number-to-string col) (number-to-string colpos)) | ||
| 9319 | (cons (number-to-string colpos) (number-to-string col)))))) | ||
| 9320 | |||
| 9321 | (defun org-table-move-row-down () | ||
| 9322 | "Move table row down." | ||
| 9323 | (interactive) | ||
| 9324 | (org-table-move-row nil)) | ||
| 9325 | (defun org-table-move-row-up () | ||
| 9326 | "Move table row up." | ||
| 9327 | (interactive) | ||
| 9328 | (org-table-move-row 'up)) | ||
| 9329 | |||
| 9330 | (defun org-table-move-row (&optional up) | ||
| 9331 | "Move the current table line down. With arg UP, move it up." | ||
| 9332 | (interactive "P") | ||
| 9333 | (let* ((col (current-column)) | ||
| 9334 | (pos (point)) | ||
| 9335 | (hline1p (save-excursion (beginning-of-line 1) | ||
| 9336 | (looking-at org-table-hline-regexp))) | ||
| 9337 | (dline1 (org-table-current-dline)) | ||
| 9338 | (dline2 (+ dline1 (if up -1 1))) | ||
| 9339 | (tonew (if up 0 2)) | ||
| 9340 | txt hline2p) | ||
| 9341 | (beginning-of-line tonew) | ||
| 9342 | (unless (org-at-table-p) | ||
| 9343 | (goto-char pos) | ||
| 9344 | (error "Cannot move row further")) | ||
| 9345 | (setq hline2p (looking-at org-table-hline-regexp)) | ||
| 9346 | (goto-char pos) | ||
| 9347 | (beginning-of-line 1) | ||
| 9348 | (setq pos (point)) | ||
| 9349 | (setq txt (buffer-substring (point) (1+ (point-at-eol)))) | ||
| 9350 | (delete-region (point) (1+ (point-at-eol))) | ||
| 9351 | (beginning-of-line tonew) | ||
| 9352 | (insert txt) | ||
| 9353 | (beginning-of-line 0) | ||
| 9354 | (move-to-column col) | ||
| 9355 | (unless (or hline1p hline2p) | ||
| 9356 | (org-table-fix-formulas | ||
| 9357 | "@" (list (cons (number-to-string dline1) (number-to-string dline2)) | ||
| 9358 | (cons (number-to-string dline2) (number-to-string dline1))))))) | ||
| 9359 | |||
| 9360 | (defun org-table-insert-row (&optional arg) | ||
| 9361 | "Insert a new row above the current line into the table. | ||
| 9362 | With prefix ARG, insert below the current line." | ||
| 9363 | (interactive "P") | ||
| 9364 | (if (not (org-at-table-p)) | ||
| 9365 | (error "Not at a table")) | ||
| 9366 | (let* ((line (buffer-substring (point-at-bol) (point-at-eol))) | ||
| 9367 | (new (org-table-clean-line line))) | ||
| 9368 | ;; Fix the first field if necessary | ||
| 9369 | (if (string-match "^[ \t]*| *[#$] *|" line) | ||
| 9370 | (setq new (replace-match (match-string 0 line) t t new))) | ||
| 9371 | (beginning-of-line (if arg 2 1)) | ||
| 9372 | (let (org-table-may-need-update) (insert-before-markers new "\n")) | ||
| 9373 | (beginning-of-line 0) | ||
| 9374 | (re-search-forward "| ?" (point-at-eol) t) | ||
| 9375 | (and (or org-table-may-need-update org-table-overlay-coordinates) | ||
| 9376 | (org-table-align)) | ||
| 9377 | (org-table-fix-formulas "@" nil (1- (org-table-current-dline)) 1))) | ||
| 9378 | |||
| 9379 | (defun org-table-insert-hline (&optional above) | ||
| 9380 | "Insert a horizontal-line below the current line into the table. | ||
| 9381 | With prefix ABOVE, insert above the current line." | ||
| 9382 | (interactive "P") | ||
| 9383 | (if (not (org-at-table-p)) | ||
| 9384 | (error "Not at a table")) | ||
| 9385 | (let ((line (org-table-clean-line | ||
| 9386 | (buffer-substring (point-at-bol) (point-at-eol)))) | ||
| 9387 | (col (current-column))) | ||
| 9388 | (while (string-match "|\\( +\\)|" line) | ||
| 9389 | (setq line (replace-match | ||
| 9390 | (concat "+" (make-string (- (match-end 1) (match-beginning 1)) | ||
| 9391 | ?-) "|") t t line))) | ||
| 9392 | (and (string-match "\\+" line) (setq line (replace-match "|" t t line))) | ||
| 9393 | (beginning-of-line (if above 1 2)) | ||
| 9394 | (insert line "\n") | ||
| 9395 | (beginning-of-line (if above 1 -1)) | ||
| 9396 | (move-to-column col) | ||
| 9397 | (and org-table-overlay-coordinates (org-table-align)))) | ||
| 9398 | |||
| 9399 | (defun org-table-hline-and-move (&optional same-column) | ||
| 9400 | "Insert a hline and move to the row below that line." | ||
| 9401 | (interactive "P") | ||
| 9402 | (let ((col (org-table-current-column))) | ||
| 9403 | (org-table-maybe-eval-formula) | ||
| 9404 | (org-table-maybe-recalculate-line) | ||
| 9405 | (org-table-insert-hline) | ||
| 9406 | (end-of-line 2) | ||
| 9407 | (if (looking-at "\n[ \t]*|-") | ||
| 9408 | (progn (insert "\n|") (org-table-align)) | ||
| 9409 | (org-table-next-field)) | ||
| 9410 | (if same-column (org-table-goto-column col)))) | ||
| 9411 | |||
| 9412 | (defun org-table-clean-line (s) | ||
| 9413 | "Convert a table line S into a string with only \"|\" and space. | ||
| 9414 | In particular, this does handle wide and invisible characters." | ||
| 9415 | (if (string-match "^[ \t]*|-" s) | ||
| 9416 | ;; It's a hline, just map the characters | ||
| 9417 | (setq s (mapconcat (lambda (x) (if (member x '(?| ?+)) "|" " ")) s "")) | ||
| 9418 | (while (string-match "|\\([ \t]*?[^ \t\r\n|][^\r\n|]*\\)|" s) | ||
| 9419 | (setq s (replace-match | ||
| 9420 | (concat "|" (make-string (org-string-width (match-string 1 s)) | ||
| 9421 | ?\ ) "|") | ||
| 9422 | t t s))) | ||
| 9423 | s)) | ||
| 9424 | |||
| 9425 | (defun org-table-kill-row () | ||
| 9426 | "Delete the current row or horizontal line from the table." | ||
| 9427 | (interactive) | ||
| 9428 | (if (not (org-at-table-p)) | ||
| 9429 | (error "Not at a table")) | ||
| 9430 | (let ((col (current-column)) | ||
| 9431 | (dline (org-table-current-dline))) | ||
| 9432 | (kill-region (point-at-bol) (min (1+ (point-at-eol)) (point-max))) | ||
| 9433 | (if (not (org-at-table-p)) (beginning-of-line 0)) | ||
| 9434 | (move-to-column col) | ||
| 9435 | (org-table-fix-formulas "@" (list (cons (number-to-string dline) "INVALID")) | ||
| 9436 | dline -1 dline))) | ||
| 9437 | |||
| 9438 | (defun org-table-sort-lines (with-case &optional sorting-type) | ||
| 9439 | "Sort table lines according to the column at point. | ||
| 9440 | |||
| 9441 | The position of point indicates the column to be used for | ||
| 9442 | sorting, and the range of lines is the range between the nearest | ||
| 9443 | horizontal separator lines, or the entire table of no such lines | ||
| 9444 | exist. If point is before the first column, you will be prompted | ||
| 9445 | for the sorting column. If there is an active region, the mark | ||
| 9446 | specifies the first line and the sorting column, while point | ||
| 9447 | should be in the last line to be included into the sorting. | ||
| 9448 | |||
| 9449 | The command then prompts for the sorting type which can be | ||
| 9450 | alphabetically, numerically, or by time (as given in a time stamp | ||
| 9451 | in the field). Sorting in reverse order is also possible. | ||
| 9452 | |||
| 9453 | With prefix argument WITH-CASE, alphabetic sorting will be case-sensitive. | ||
| 9454 | |||
| 9455 | If SORTING-TYPE is specified when this function is called from a Lisp | ||
| 9456 | program, no prompting will take place. SORTING-TYPE must be a character, | ||
| 9457 | any of (?a ?A ?n ?N ?t ?T) where the capital letter indicate that sorting | ||
| 9458 | should be done in reverse order." | ||
| 9459 | (interactive "P") | ||
| 9460 | (let* ((thisline (org-current-line)) | ||
| 9461 | (thiscol (org-table-current-column)) | ||
| 9462 | beg end bcol ecol tend tbeg column lns pos) | ||
| 9463 | (when (equal thiscol 0) | ||
| 9464 | (if (interactive-p) | ||
| 9465 | (setq thiscol | ||
| 9466 | (string-to-number | ||
| 9467 | (read-string "Use column N for sorting: "))) | ||
| 9468 | (setq thiscol 1)) | ||
| 9469 | (org-table-goto-column thiscol)) | ||
| 9470 | (org-table-check-inside-data-field) | ||
| 9471 | (if (org-region-active-p) | ||
| 9472 | (progn | ||
| 9473 | (setq beg (region-beginning) end (region-end)) | ||
| 9474 | (goto-char beg) | ||
| 9475 | (setq column (org-table-current-column) | ||
| 9476 | beg (point-at-bol)) | ||
| 9477 | (goto-char end) | ||
| 9478 | (setq end (point-at-bol 2))) | ||
| 9479 | (setq column (org-table-current-column) | ||
| 9480 | pos (point) | ||
| 9481 | tbeg (org-table-begin) | ||
| 9482 | tend (org-table-end)) | ||
| 9483 | (if (re-search-backward org-table-hline-regexp tbeg t) | ||
| 9484 | (setq beg (point-at-bol 2)) | ||
| 9485 | (goto-char tbeg) | ||
| 9486 | (setq beg (point-at-bol 1))) | ||
| 9487 | (goto-char pos) | ||
| 9488 | (if (re-search-forward org-table-hline-regexp tend t) | ||
| 9489 | (setq end (point-at-bol 1)) | ||
| 9490 | (goto-char tend) | ||
| 9491 | (setq end (point-at-bol)))) | ||
| 9492 | (setq beg (move-marker (make-marker) beg) | ||
| 9493 | end (move-marker (make-marker) end)) | ||
| 9494 | (untabify beg end) | ||
| 9495 | (goto-char beg) | ||
| 9496 | (org-table-goto-column column) | ||
| 9497 | (skip-chars-backward "^|") | ||
| 9498 | (setq bcol (current-column)) | ||
| 9499 | (org-table-goto-column (1+ column)) | ||
| 9500 | (skip-chars-backward "^|") | ||
| 9501 | (setq ecol (1- (current-column))) | ||
| 9502 | (org-table-goto-column column) | ||
| 9503 | (setq lns (mapcar (lambda(x) (cons | ||
| 9504 | (org-sort-remove-invisible | ||
| 9505 | (nth (1- column) | ||
| 9506 | (org-split-string x "[ \t]*|[ \t]*"))) | ||
| 9507 | x)) | ||
| 9508 | (org-split-string (buffer-substring beg end) "\n"))) | ||
| 9509 | (setq lns (org-do-sort lns "Table" with-case sorting-type)) | ||
| 9510 | (delete-region beg end) | ||
| 9511 | (move-marker beg nil) | ||
| 9512 | (move-marker end nil) | ||
| 9513 | (insert (mapconcat 'cdr lns "\n") "\n") | ||
| 9514 | (goto-line thisline) | ||
| 9515 | (org-table-goto-column thiscol) | ||
| 9516 | (message "%d lines sorted, based on column %d" (length lns) column))) | ||
| 9517 | |||
| 9518 | ;; FIXME: maybe we will not need this? Table sorting is broken.... | ||
| 9519 | (defun org-sort-remove-invisible (s) | ||
| 9520 | (remove-text-properties 0 (length s) org-rm-props s) | ||
| 9521 | (while (string-match org-bracket-link-regexp s) | ||
| 9522 | (setq s (replace-match (if (match-end 2) | ||
| 9523 | (match-string 3 s) | ||
| 9524 | (match-string 1 s)) t t s))) | ||
| 9525 | s) | ||
| 9526 | |||
| 9527 | (defun org-table-cut-region (beg end) | ||
| 9528 | "Copy region in table to the clipboard and blank all relevant fields." | ||
| 9529 | (interactive "r") | ||
| 9530 | (org-table-copy-region beg end 'cut)) | ||
| 9531 | |||
| 9532 | (defun org-table-copy-region (beg end &optional cut) | ||
| 9533 | "Copy rectangular region in table to clipboard. | ||
| 9534 | A special clipboard is used which can only be accessed | ||
| 9535 | with `org-table-paste-rectangle'." | ||
| 9536 | (interactive "rP") | ||
| 9537 | (let* (l01 c01 l02 c02 l1 c1 l2 c2 ic1 ic2 | ||
| 9538 | region cols | ||
| 9539 | (rpl (if cut " " nil))) | ||
| 9540 | (goto-char beg) | ||
| 9541 | (org-table-check-inside-data-field) | ||
| 9542 | (setq l01 (org-current-line) | ||
| 9543 | c01 (org-table-current-column)) | ||
| 9544 | (goto-char end) | ||
| 9545 | (org-table-check-inside-data-field) | ||
| 9546 | (setq l02 (org-current-line) | ||
| 9547 | c02 (org-table-current-column)) | ||
| 9548 | (setq l1 (min l01 l02) l2 (max l01 l02) | ||
| 9549 | c1 (min c01 c02) c2 (max c01 c02)) | ||
| 9550 | (catch 'exit | ||
| 9551 | (while t | ||
| 9552 | (catch 'nextline | ||
| 9553 | (if (> l1 l2) (throw 'exit t)) | ||
| 9554 | (goto-line l1) | ||
| 9555 | (if (org-at-table-hline-p) (throw 'nextline (setq l1 (1+ l1)))) | ||
| 9556 | (setq cols nil ic1 c1 ic2 c2) | ||
| 9557 | (while (< ic1 (1+ ic2)) | ||
| 9558 | (push (org-table-get-field ic1 rpl) cols) | ||
| 9559 | (setq ic1 (1+ ic1))) | ||
| 9560 | (push (nreverse cols) region) | ||
| 9561 | (setq l1 (1+ l1))))) | ||
| 9562 | (setq org-table-clip (nreverse region)) | ||
| 9563 | (if cut (org-table-align)) | ||
| 9564 | org-table-clip)) | ||
| 9565 | |||
| 9566 | (defun org-table-paste-rectangle () | ||
| 9567 | "Paste a rectangular region into a table. | ||
| 9568 | The upper right corner ends up in the current field. All involved fields | ||
| 9569 | will be overwritten. If the rectangle does not fit into the present table, | ||
| 9570 | the table is enlarged as needed. The process ignores horizontal separator | ||
| 9571 | lines." | ||
| 9572 | (interactive) | ||
| 9573 | (unless (and org-table-clip (listp org-table-clip)) | ||
| 9574 | (error "First cut/copy a region to paste!")) | ||
| 9575 | (org-table-check-inside-data-field) | ||
| 9576 | (let* ((clip org-table-clip) | ||
| 9577 | (line (org-current-line)) | ||
| 9578 | (col (org-table-current-column)) | ||
| 9579 | (org-enable-table-editor t) | ||
| 9580 | (org-table-automatic-realign nil) | ||
| 9581 | c cols field) | ||
| 9582 | (while (setq cols (pop clip)) | ||
| 9583 | (while (org-at-table-hline-p) (beginning-of-line 2)) | ||
| 9584 | (if (not (org-at-table-p)) | ||
| 9585 | (progn (end-of-line 0) (org-table-next-field))) | ||
| 9586 | (setq c col) | ||
| 9587 | (while (setq field (pop cols)) | ||
| 9588 | (org-table-goto-column c nil 'force) | ||
| 9589 | (org-table-get-field nil field) | ||
| 9590 | (setq c (1+ c))) | ||
| 9591 | (beginning-of-line 2)) | ||
| 9592 | (goto-line line) | ||
| 9593 | (org-table-goto-column col) | ||
| 9594 | (org-table-align))) | ||
| 9595 | |||
| 9596 | (defun org-table-convert () | ||
| 9597 | "Convert from `org-mode' table to table.el and back. | ||
| 9598 | Obviously, this only works within limits. When an Org-mode table is | ||
| 9599 | converted to table.el, all horizontal separator lines get lost, because | ||
| 9600 | table.el uses these as cell boundaries and has no notion of horizontal lines. | ||
| 9601 | A table.el table can be converted to an Org-mode table only if it does not | ||
| 9602 | do row or column spanning. Multiline cells will become multiple cells. | ||
| 9603 | Beware, Org-mode does not test if the table can be successfully converted - it | ||
| 9604 | blindly applies a recipe that works for simple tables." | ||
| 9605 | (interactive) | ||
| 9606 | (require 'table) | ||
| 9607 | (if (org-at-table.el-p) | ||
| 9608 | ;; convert to Org-mode table | ||
| 9609 | (let ((beg (move-marker (make-marker) (org-table-begin t))) | ||
| 9610 | (end (move-marker (make-marker) (org-table-end t)))) | ||
| 9611 | (table-unrecognize-region beg end) | ||
| 9612 | (goto-char beg) | ||
| 9613 | (while (re-search-forward "^\\([ \t]*\\)\\+-.*\n" end t) | ||
| 9614 | (replace-match "")) | ||
| 9615 | (goto-char beg)) | ||
| 9616 | (if (org-at-table-p) | ||
| 9617 | ;; convert to table.el table | ||
| 9618 | (let ((beg (move-marker (make-marker) (org-table-begin))) | ||
| 9619 | (end (move-marker (make-marker) (org-table-end)))) | ||
| 9620 | ;; first, get rid of all horizontal lines | ||
| 9621 | (goto-char beg) | ||
| 9622 | (while (re-search-forward "^\\([ \t]*\\)|-.*\n" end t) | ||
| 9623 | (replace-match "")) | ||
| 9624 | ;; insert a hline before first | ||
| 9625 | (goto-char beg) | ||
| 9626 | (org-table-insert-hline 'above) | ||
| 9627 | (beginning-of-line -1) | ||
| 9628 | ;; insert a hline after each line | ||
| 9629 | (while (progn (beginning-of-line 3) (< (point) end)) | ||
| 9630 | (org-table-insert-hline)) | ||
| 9631 | (goto-char beg) | ||
| 9632 | (setq end (move-marker end (org-table-end))) | ||
| 9633 | ;; replace "+" at beginning and ending of hlines | ||
| 9634 | (while (re-search-forward "^\\([ \t]*\\)|-" end t) | ||
| 9635 | (replace-match "\\1+-")) | ||
| 9636 | (goto-char beg) | ||
| 9637 | (while (re-search-forward "-|[ \t]*$" end t) | ||
| 9638 | (replace-match "-+")) | ||
| 9639 | (goto-char beg))))) | ||
| 9640 | |||
| 9641 | (defun org-table-wrap-region (arg) | ||
| 9642 | "Wrap several fields in a column like a paragraph. | ||
| 9643 | This is useful if you'd like to spread the contents of a field over several | ||
| 9644 | lines, in order to keep the table compact. | ||
| 9645 | |||
| 9646 | If there is an active region, and both point and mark are in the same column, | ||
| 9647 | the text in the column is wrapped to minimum width for the given number of | ||
| 9648 | lines. Generally, this makes the table more compact. A prefix ARG may be | ||
| 9649 | used to change the number of desired lines. For example, `C-2 \\[org-table-wrap]' | ||
| 9650 | formats the selected text to two lines. If the region was longer than two | ||
| 9651 | lines, the remaining lines remain empty. A negative prefix argument reduces | ||
| 9652 | the current number of lines by that amount. The wrapped text is pasted back | ||
| 9653 | into the table. If you formatted it to more lines than it was before, fields | ||
| 9654 | further down in the table get overwritten - so you might need to make space in | ||
| 9655 | the table first. | ||
| 9656 | |||
| 9657 | If there is no region, the current field is split at the cursor position and | ||
| 9658 | the text fragment to the right of the cursor is prepended to the field one | ||
| 9659 | line down. | ||
| 9660 | |||
| 9661 | If there is no region, but you specify a prefix ARG, the current field gets | ||
| 9662 | blank, and the content is appended to the field above." | ||
| 9663 | (interactive "P") | ||
| 9664 | (org-table-check-inside-data-field) | ||
| 9665 | (if (org-region-active-p) | ||
| 9666 | ;; There is a region: fill as a paragraph | ||
| 9667 | (let* ((beg (region-beginning)) | ||
| 9668 | (cline (save-excursion (goto-char beg) (org-current-line))) | ||
| 9669 | (ccol (save-excursion (goto-char beg) (org-table-current-column))) | ||
| 9670 | nlines) | ||
| 9671 | (org-table-cut-region (region-beginning) (region-end)) | ||
| 9672 | (if (> (length (car org-table-clip)) 1) | ||
| 9673 | (error "Region must be limited to single column")) | ||
| 9674 | (setq nlines (if arg | ||
| 9675 | (if (< arg 1) | ||
| 9676 | (+ (length org-table-clip) arg) | ||
| 9677 | arg) | ||
| 9678 | (length org-table-clip))) | ||
| 9679 | (setq org-table-clip | ||
| 9680 | (mapcar 'list (org-wrap (mapconcat 'car org-table-clip " ") | ||
| 9681 | nil nlines))) | ||
| 9682 | (goto-line cline) | ||
| 9683 | (org-table-goto-column ccol) | ||
| 9684 | (org-table-paste-rectangle)) | ||
| 9685 | ;; No region, split the current field at point | ||
| 9686 | (unless (org-get-alist-option org-M-RET-may-split-line 'table) | ||
| 9687 | (skip-chars-forward "^\r\n|")) | ||
| 9688 | (if arg | ||
| 9689 | ;; combine with field above | ||
| 9690 | (let ((s (org-table-blank-field)) | ||
| 9691 | (col (org-table-current-column))) | ||
| 9692 | (beginning-of-line 0) | ||
| 9693 | (while (org-at-table-hline-p) (beginning-of-line 0)) | ||
| 9694 | (org-table-goto-column col) | ||
| 9695 | (skip-chars-forward "^|") | ||
| 9696 | (skip-chars-backward " ") | ||
| 9697 | (insert " " (org-trim s)) | ||
| 9698 | (org-table-align)) | ||
| 9699 | ;; split field | ||
| 9700 | (if (looking-at "\\([^|]+\\)+|") | ||
| 9701 | (let ((s (match-string 1))) | ||
| 9702 | (replace-match " |") | ||
| 9703 | (goto-char (match-beginning 0)) | ||
| 9704 | (org-table-next-row) | ||
| 9705 | (insert (org-trim s) " ") | ||
| 9706 | (org-table-align)) | ||
| 9707 | (org-table-next-row))))) | ||
| 9708 | |||
| 9709 | (defvar org-field-marker nil) | ||
| 9710 | |||
| 9711 | (defun org-table-edit-field (arg) | ||
| 9712 | "Edit table field in a different window. | ||
| 9713 | This is mainly useful for fields that contain hidden parts. | ||
| 9714 | When called with a \\[universal-argument] prefix, just make the full field visible so that | ||
| 9715 | it can be edited in place." | ||
| 9716 | (interactive "P") | ||
| 9717 | (if arg | ||
| 9718 | (let ((b (save-excursion (skip-chars-backward "^|") (point))) | ||
| 9719 | (e (save-excursion (skip-chars-forward "^|\r\n") (point)))) | ||
| 9720 | (remove-text-properties b e '(org-cwidth t invisible t | ||
| 9721 | display t intangible t)) | ||
| 9722 | (if (and (boundp 'font-lock-mode) font-lock-mode) | ||
| 9723 | (font-lock-fontify-block))) | ||
| 9724 | (let ((pos (move-marker (make-marker) (point))) | ||
| 9725 | (field (org-table-get-field)) | ||
| 9726 | (cw (current-window-configuration)) | ||
| 9727 | p) | ||
| 9728 | (org-switch-to-buffer-other-window "*Org tmp*") | ||
| 9729 | (erase-buffer) | ||
| 9730 | (insert "#\n# Edit field and finish with C-c C-c\n#\n") | ||
| 9731 | (let ((org-inhibit-startup t)) (org-mode)) | ||
| 9732 | (goto-char (setq p (point-max))) | ||
| 9733 | (insert (org-trim field)) | ||
| 9734 | (remove-text-properties p (point-max) | ||
| 9735 | '(invisible t org-cwidth t display t | ||
| 9736 | intangible t)) | ||
| 9737 | (goto-char p) | ||
| 9738 | (org-set-local 'org-finish-function 'org-table-finish-edit-field) | ||
| 9739 | (org-set-local 'org-window-configuration cw) | ||
| 9740 | (org-set-local 'org-field-marker pos) | ||
| 9741 | (message "Edit and finish with C-c C-c")))) | ||
| 9742 | |||
| 9743 | (defun org-table-finish-edit-field () | ||
| 9744 | "Finish editing a table data field. | ||
| 9745 | Remove all newline characters, insert the result into the table, realign | ||
| 9746 | the table and kill the editing buffer." | ||
| 9747 | (let ((pos org-field-marker) | ||
| 9748 | (cw org-window-configuration) | ||
| 9749 | (cb (current-buffer)) | ||
| 9750 | text) | ||
| 9751 | (goto-char (point-min)) | ||
| 9752 | (while (re-search-forward "^#.*\n?" nil t) (replace-match "")) | ||
| 9753 | (while (re-search-forward "\\([ \t]*\n[ \t]*\\)+" nil t) | ||
| 9754 | (replace-match " ")) | ||
| 9755 | (setq text (org-trim (buffer-string))) | ||
| 9756 | (set-window-configuration cw) | ||
| 9757 | (kill-buffer cb) | ||
| 9758 | (select-window (get-buffer-window (marker-buffer pos))) | ||
| 9759 | (goto-char pos) | ||
| 9760 | (move-marker pos nil) | ||
| 9761 | (org-table-check-inside-data-field) | ||
| 9762 | (org-table-get-field nil text) | ||
| 9763 | (org-table-align) | ||
| 9764 | (message "New field value inserted"))) | ||
| 9765 | |||
| 9766 | (defun org-trim (s) | ||
| 9767 | "Remove whitespace at beginning and end of string." | ||
| 9768 | (if (string-match "\\`[ \t\n\r]+" s) (setq s (replace-match "" t t s))) | ||
| 9769 | (if (string-match "[ \t\n\r]+\\'" s) (setq s (replace-match "" t t s))) | ||
| 9770 | s) | ||
| 9771 | |||
| 9772 | (defun org-wrap (string &optional width lines) | ||
| 9773 | "Wrap string to either a number of lines, or a width in characters. | ||
| 9774 | If WIDTH is non-nil, the string is wrapped to that width, however many lines | ||
| 9775 | that costs. If there is a word longer than WIDTH, the text is actually | ||
| 9776 | wrapped to the length of that word. | ||
| 9777 | IF WIDTH is nil and LINES is non-nil, the string is forced into at most that | ||
| 9778 | many lines, whatever width that takes. | ||
| 9779 | The return value is a list of lines, without newlines at the end." | ||
| 9780 | (let* ((words (org-split-string string "[ \t\n]+")) | ||
| 9781 | (maxword (apply 'max (mapcar 'org-string-width words))) | ||
| 9782 | w ll) | ||
| 9783 | (cond (width | ||
| 9784 | (org-do-wrap words (max maxword width))) | ||
| 9785 | (lines | ||
| 9786 | (setq w maxword) | ||
| 9787 | (setq ll (org-do-wrap words maxword)) | ||
| 9788 | (if (<= (length ll) lines) | ||
| 9789 | ll | ||
| 9790 | (setq ll words) | ||
| 9791 | (while (> (length ll) lines) | ||
| 9792 | (setq w (1+ w)) | ||
| 9793 | (setq ll (org-do-wrap words w))) | ||
| 9794 | ll)) | ||
| 9795 | (t (error "Cannot wrap this"))))) | ||
| 9796 | |||
| 9797 | |||
| 9798 | (defun org-do-wrap (words width) | ||
| 9799 | "Create lines of maximum width WIDTH (in characters) from word list WORDS." | ||
| 9800 | (let (lines line) | ||
| 9801 | (while words | ||
| 9802 | (setq line (pop words)) | ||
| 9803 | (while (and words (< (+ (length line) (length (car words))) width)) | ||
| 9804 | (setq line (concat line " " (pop words)))) | ||
| 9805 | (setq lines (push line lines))) | ||
| 9806 | (nreverse lines))) | ||
| 9807 | |||
| 9808 | (defun org-split-string (string &optional separators) | ||
| 9809 | "Splits STRING into substrings at SEPARATORS. | ||
| 9810 | No empty strings are returned if there are matches at the beginning | ||
| 9811 | and end of string." | ||
| 9812 | (let ((rexp (or separators "[ \f\t\n\r\v]+")) | ||
| 9813 | (start 0) | ||
| 9814 | notfirst | ||
| 9815 | (list nil)) | ||
| 9816 | (while (and (string-match rexp string | ||
| 9817 | (if (and notfirst | ||
| 9818 | (= start (match-beginning 0)) | ||
| 9819 | (< start (length string))) | ||
| 9820 | (1+ start) start)) | ||
| 9821 | (< (match-beginning 0) (length string))) | ||
| 9822 | (setq notfirst t) | ||
| 9823 | (or (eq (match-beginning 0) 0) | ||
| 9824 | (and (eq (match-beginning 0) (match-end 0)) | ||
| 9825 | (eq (match-beginning 0) start)) | ||
| 9826 | (setq list | ||
| 9827 | (cons (substring string start (match-beginning 0)) | ||
| 9828 | list))) | ||
| 9829 | (setq start (match-end 0))) | ||
| 9830 | (or (eq start (length string)) | ||
| 9831 | (setq list | ||
| 9832 | (cons (substring string start) | ||
| 9833 | list))) | ||
| 9834 | (nreverse list))) | ||
| 9835 | |||
| 9836 | (defun org-table-map-tables (function) | ||
| 9837 | "Apply FUNCTION to the start of all tables in the buffer." | ||
| 9838 | (save-excursion | ||
| 9839 | (save-restriction | ||
| 9840 | (widen) | ||
| 9841 | (goto-char (point-min)) | ||
| 9842 | (while (re-search-forward org-table-any-line-regexp nil t) | ||
| 9843 | (message "Mapping tables: %d%%" (/ (* 100.0 (point)) (buffer-size))) | ||
| 9844 | (beginning-of-line 1) | ||
| 9845 | (if (looking-at org-table-line-regexp) | ||
| 9846 | (save-excursion (funcall function))) | ||
| 9847 | (re-search-forward org-table-any-border-regexp nil 1)))) | ||
| 9848 | (message "Mapping tables: done")) | ||
| 9849 | |||
| 9850 | (defvar org-timecnt) ; dynamically scoped parameter | ||
| 9851 | |||
| 9852 | (defun org-table-sum (&optional beg end nlast) | ||
| 9853 | "Sum numbers in region of current table column. | ||
| 9854 | The result will be displayed in the echo area, and will be available | ||
| 9855 | as kill to be inserted with \\[yank]. | ||
| 9856 | |||
| 9857 | If there is an active region, it is interpreted as a rectangle and all | ||
| 9858 | numbers in that rectangle will be summed. If there is no active | ||
| 9859 | region and point is located in a table column, sum all numbers in that | ||
| 9860 | column. | ||
| 9861 | |||
| 9862 | If at least one number looks like a time HH:MM or HH:MM:SS, all other | ||
| 9863 | numbers are assumed to be times as well (in decimal hours) and the | ||
| 9864 | numbers are added as such. | ||
| 9865 | |||
| 9866 | If NLAST is a number, only the NLAST fields will actually be summed." | ||
| 9867 | (interactive) | ||
| 9868 | (save-excursion | ||
| 9869 | (let (col (org-timecnt 0) diff h m s org-table-clip) | ||
| 9870 | (cond | ||
| 9871 | ((and beg end)) ; beg and end given explicitly | ||
| 9872 | ((org-region-active-p) | ||
| 9873 | (setq beg (region-beginning) end (region-end))) | ||
| 9874 | (t | ||
| 9875 | (setq col (org-table-current-column)) | ||
| 9876 | (goto-char (org-table-begin)) | ||
| 9877 | (unless (re-search-forward "^[ \t]*|[^-]" nil t) | ||
| 9878 | (error "No table data")) | ||
| 9879 | (org-table-goto-column col) | ||
| 9880 | (setq beg (point)) | ||
| 9881 | (goto-char (org-table-end)) | ||
| 9882 | (unless (re-search-backward "^[ \t]*|[^-]" nil t) | ||
| 9883 | (error "No table data")) | ||
| 9884 | (org-table-goto-column col) | ||
| 9885 | (setq end (point)))) | ||
| 9886 | (let* ((items (apply 'append (org-table-copy-region beg end))) | ||
| 9887 | (items1 (cond ((not nlast) items) | ||
| 9888 | ((>= nlast (length items)) items) | ||
| 9889 | (t (setq items (reverse items)) | ||
| 9890 | (setcdr (nthcdr (1- nlast) items) nil) | ||
| 9891 | (nreverse items)))) | ||
| 9892 | (numbers (delq nil (mapcar 'org-table-get-number-for-summing | ||
| 9893 | items1))) | ||
| 9894 | (res (apply '+ numbers)) | ||
| 9895 | (sres (if (= org-timecnt 0) | ||
| 9896 | (format "%g" res) | ||
| 9897 | (setq diff (* 3600 res) | ||
| 9898 | h (floor (/ diff 3600)) diff (mod diff 3600) | ||
| 9899 | m (floor (/ diff 60)) diff (mod diff 60) | ||
| 9900 | s diff) | ||
| 9901 | (format "%d:%02d:%02d" h m s)))) | ||
| 9902 | (kill-new sres) | ||
| 9903 | (if (interactive-p) | ||
| 9904 | (message "%s" | ||
| 9905 | (substitute-command-keys | ||
| 9906 | (format "Sum of %d items: %-20s (\\[yank] will insert result into buffer)" | ||
| 9907 | (length numbers) sres)))) | ||
| 9908 | sres)))) | ||
| 9909 | |||
| 9910 | (defun org-table-get-number-for-summing (s) | ||
| 9911 | (let (n) | ||
| 9912 | (if (string-match "^ *|? *" s) | ||
| 9913 | (setq s (replace-match "" nil nil s))) | ||
| 9914 | (if (string-match " *|? *$" s) | ||
| 9915 | (setq s (replace-match "" nil nil s))) | ||
| 9916 | (setq n (string-to-number s)) | ||
| 9917 | (cond | ||
| 9918 | ((and (string-match "0" s) | ||
| 9919 | (string-match "\\`[-+ \t0.edED]+\\'" s)) 0) | ||
| 9920 | ((string-match "\\`[ \t]+\\'" s) nil) | ||
| 9921 | ((string-match "\\`\\([0-9]+\\):\\([0-9]+\\)\\(:\\([0-9]+\\)\\)?\\'" s) | ||
| 9922 | (let ((h (string-to-number (or (match-string 1 s) "0"))) | ||
| 9923 | (m (string-to-number (or (match-string 2 s) "0"))) | ||
| 9924 | (s (string-to-number (or (match-string 4 s) "0")))) | ||
| 9925 | (if (boundp 'org-timecnt) (setq org-timecnt (1+ org-timecnt))) | ||
| 9926 | (* 1.0 (+ h (/ m 60.0) (/ s 3600.0))))) | ||
| 9927 | ((equal n 0) nil) | ||
| 9928 | (t n)))) | ||
| 9929 | |||
| 9930 | (defun org-table-current-field-formula (&optional key noerror) | ||
| 9931 | "Return the formula active for the current field. | ||
| 9932 | Assumes that specials are in place. | ||
| 9933 | If KEY is given, return the key to this formula. | ||
| 9934 | Otherwise return the formula preceeded with \"=\" or \":=\"." | ||
| 9935 | (let* ((name (car (rassoc (list (org-current-line) | ||
| 9936 | (org-table-current-column)) | ||
| 9937 | org-table-named-field-locations))) | ||
| 9938 | (col (org-table-current-column)) | ||
| 9939 | (scol (int-to-string col)) | ||
| 9940 | (ref (format "@%d$%d" (org-table-current-dline) col)) | ||
| 9941 | (stored-list (org-table-get-stored-formulas noerror)) | ||
| 9942 | (ass (or (assoc name stored-list) | ||
| 9943 | (assoc ref stored-list) | ||
| 9944 | (assoc scol stored-list)))) | ||
| 9945 | (if key | ||
| 9946 | (car ass) | ||
| 9947 | (if ass (concat (if (string-match "^[0-9]+$" (car ass)) "=" ":=") | ||
| 9948 | (cdr ass)))))) | ||
| 9949 | |||
| 9950 | (defun org-table-get-formula (&optional equation named) | ||
| 9951 | "Read a formula from the minibuffer, offer stored formula as default. | ||
| 9952 | When NAMED is non-nil, look for a named equation." | ||
| 9953 | (let* ((stored-list (org-table-get-stored-formulas)) | ||
| 9954 | (name (car (rassoc (list (org-current-line) | ||
| 9955 | (org-table-current-column)) | ||
| 9956 | org-table-named-field-locations))) | ||
| 9957 | (ref (format "@%d$%d" (org-table-current-dline) | ||
| 9958 | (org-table-current-column))) | ||
| 9959 | (refass (assoc ref stored-list)) | ||
| 9960 | (scol (if named | ||
| 9961 | (if name name ref) | ||
| 9962 | (int-to-string (org-table-current-column)))) | ||
| 9963 | (dummy (and (or name refass) (not named) | ||
| 9964 | (not (y-or-n-p "Replace field formula with column formula? " )) | ||
| 9965 | (error "Abort"))) | ||
| 9966 | (name (or name ref)) | ||
| 9967 | (org-table-may-need-update nil) | ||
| 9968 | (stored (cdr (assoc scol stored-list))) | ||
| 9969 | (eq (cond | ||
| 9970 | ((and stored equation (string-match "^ *=? *$" equation)) | ||
| 9971 | stored) | ||
| 9972 | ((stringp equation) | ||
| 9973 | equation) | ||
| 9974 | (t (org-table-formula-from-user | ||
| 9975 | (read-string | ||
| 9976 | (org-table-formula-to-user | ||
| 9977 | (format "%s formula %s%s=" | ||
| 9978 | (if named "Field" "Column") | ||
| 9979 | (if (member (string-to-char scol) '(?$ ?@)) "" "$") | ||
| 9980 | scol)) | ||
| 9981 | (if stored (org-table-formula-to-user stored) "") | ||
| 9982 | 'org-table-formula-history | ||
| 9983 | ))))) | ||
| 9984 | mustsave) | ||
| 9985 | (when (not (string-match "\\S-" eq)) | ||
| 9986 | ;; remove formula | ||
| 9987 | (setq stored-list (delq (assoc scol stored-list) stored-list)) | ||
| 9988 | (org-table-store-formulas stored-list) | ||
| 9989 | (error "Formula removed")) | ||
| 9990 | (if (string-match "^ *=?" eq) (setq eq (replace-match "" t t eq))) | ||
| 9991 | (if (string-match " *$" eq) (setq eq (replace-match "" t t eq))) | ||
| 9992 | (if (and name (not named)) | ||
| 9993 | ;; We set the column equation, delete the named one. | ||
| 9994 | (setq stored-list (delq (assoc name stored-list) stored-list) | ||
| 9995 | mustsave t)) | ||
| 9996 | (if stored | ||
| 9997 | (setcdr (assoc scol stored-list) eq) | ||
| 9998 | (setq stored-list (cons (cons scol eq) stored-list))) | ||
| 9999 | (if (or mustsave (not (equal stored eq))) | ||
| 10000 | (org-table-store-formulas stored-list)) | ||
| 10001 | eq)) | ||
| 10002 | |||
| 10003 | (defun org-table-store-formulas (alist) | ||
| 10004 | "Store the list of formulas below the current table." | ||
| 10005 | (setq alist (sort alist 'org-table-formula-less-p)) | ||
| 10006 | (save-excursion | ||
| 10007 | (goto-char (org-table-end)) | ||
| 10008 | (if (looking-at "\\([ \t]*\n\\)*#\\+TBLFM:\\(.*\n?\\)") | ||
| 10009 | (progn | ||
| 10010 | ;; don't overwrite TBLFM, we might use text properties to store stuff | ||
| 10011 | (goto-char (match-beginning 2)) | ||
| 10012 | (delete-region (match-beginning 2) (match-end 0))) | ||
| 10013 | (insert "#+TBLFM:")) | ||
| 10014 | (insert " " | ||
| 10015 | (mapconcat (lambda (x) | ||
| 10016 | (concat | ||
| 10017 | (if (equal (string-to-char (car x)) ?@) "" "$") | ||
| 10018 | (car x) "=" (cdr x))) | ||
| 10019 | alist "::") | ||
| 10020 | "\n"))) | ||
| 10021 | |||
| 10022 | (defsubst org-table-formula-make-cmp-string (a) | ||
| 10023 | (when (string-match "^\\(@\\([0-9]+\\)\\)?\\(\\$?\\([0-9]+\\)\\)?\\(\\$?[a-zA-Z0-9]+\\)?" a) | ||
| 10024 | (concat | ||
| 10025 | (if (match-end 2) (format "@%05d" (string-to-number (match-string 2 a))) "") | ||
| 10026 | (if (match-end 4) (format "$%05d" (string-to-number (match-string 4 a))) "") | ||
| 10027 | (if (match-end 5) (concat "@@" (match-string 5 a)))))) | ||
| 10028 | |||
| 10029 | (defun org-table-formula-less-p (a b) | ||
| 10030 | "Compare two formulas for sorting." | ||
| 10031 | (let ((as (org-table-formula-make-cmp-string (car a))) | ||
| 10032 | (bs (org-table-formula-make-cmp-string (car b)))) | ||
| 10033 | (and as bs (string< as bs)))) | ||
| 10034 | |||
| 10035 | (defun org-table-get-stored-formulas (&optional noerror) | ||
| 10036 | "Return an alist with the stored formulas directly after current table." | ||
| 10037 | (interactive) | ||
| 10038 | (let (scol eq eq-alist strings string seen) | ||
| 10039 | (save-excursion | ||
| 10040 | (goto-char (org-table-end)) | ||
| 10041 | (when (looking-at "\\([ \t]*\n\\)*#\\+TBLFM: *\\(.*\\)") | ||
| 10042 | (setq strings (org-split-string (match-string 2) " *:: *")) | ||
| 10043 | (while (setq string (pop strings)) | ||
| 10044 | (when (string-match "\\(@[0-9]+\\$[0-9]+\\|\\$\\([a-zA-Z0-9]+\\)\\) *= *\\(.*[^ \t]\\)" string) | ||
| 10045 | (setq scol (if (match-end 2) | ||
| 10046 | (match-string 2 string) | ||
| 10047 | (match-string 1 string)) | ||
| 10048 | eq (match-string 3 string) | ||
| 10049 | eq-alist (cons (cons scol eq) eq-alist)) | ||
| 10050 | (if (member scol seen) | ||
| 10051 | (if noerror | ||
| 10052 | (progn | ||
| 10053 | (message "Double definition `$%s=' in TBLFM line, please fix by hand" scol) | ||
| 10054 | (ding) | ||
| 10055 | (sit-for 2)) | ||
| 10056 | (error "Double definition `$%s=' in TBLFM line, please fix by hand" scol)) | ||
| 10057 | (push scol seen)))))) | ||
| 10058 | (nreverse eq-alist))) | ||
| 10059 | |||
| 10060 | (defun org-table-fix-formulas (key replace &optional limit delta remove) | ||
| 10061 | "Modify the equations after the table structure has been edited. | ||
| 10062 | KEY is \"@\" or \"$\". REPLACE is an alist of numbers to replace. | ||
| 10063 | For all numbers larger than LIMIT, shift them by DELTA." | ||
| 10064 | (save-excursion | ||
| 10065 | (goto-char (org-table-end)) | ||
| 10066 | (when (looking-at "#\\+TBLFM:") | ||
| 10067 | (let ((re (concat key "\\([0-9]+\\)")) | ||
| 10068 | (re2 | ||
| 10069 | (when remove | ||
| 10070 | (if (equal key "$") | ||
| 10071 | (format "\\(@[0-9]+\\)?\\$%d=.*?\\(::\\|$\\)" remove) | ||
| 10072 | (format "@%d\\$[0-9]+=.*?\\(::\\|$\\)" remove)))) | ||
| 10073 | s n a) | ||
| 10074 | (when remove | ||
| 10075 | (while (re-search-forward re2 (point-at-eol) t) | ||
| 10076 | (replace-match ""))) | ||
| 10077 | (while (re-search-forward re (point-at-eol) t) | ||
| 10078 | (setq s (match-string 1) n (string-to-number s)) | ||
| 10079 | (cond | ||
| 10080 | ((setq a (assoc s replace)) | ||
| 10081 | (replace-match (concat key (cdr a)) t t)) | ||
| 10082 | ((and limit (> n limit)) | ||
| 10083 | (replace-match (concat key (int-to-string (+ n delta))) t t)))))))) | ||
| 10084 | |||
| 10085 | (defun org-table-get-specials () | ||
| 10086 | "Get the column names and local parameters for this table." | ||
| 10087 | (save-excursion | ||
| 10088 | (let ((beg (org-table-begin)) (end (org-table-end)) | ||
| 10089 | names name fields fields1 field cnt | ||
| 10090 | c v l line col types dlines hlines) | ||
| 10091 | (setq org-table-column-names nil | ||
| 10092 | org-table-local-parameters nil | ||
| 10093 | org-table-named-field-locations nil | ||
| 10094 | org-table-current-begin-line nil | ||
| 10095 | org-table-current-begin-pos nil | ||
| 10096 | org-table-current-line-types nil) | ||
| 10097 | (goto-char beg) | ||
| 10098 | (when (re-search-forward "^[ \t]*| *! *\\(|.*\\)" end t) | ||
| 10099 | (setq names (org-split-string (match-string 1) " *| *") | ||
| 10100 | cnt 1) | ||
| 10101 | (while (setq name (pop names)) | ||
| 10102 | (setq cnt (1+ cnt)) | ||
| 10103 | (if (string-match "^[a-zA-Z][a-zA-Z0-9]*$" name) | ||
| 10104 | (push (cons name (int-to-string cnt)) org-table-column-names)))) | ||
| 10105 | (setq org-table-column-names (nreverse org-table-column-names)) | ||
| 10106 | (setq org-table-column-name-regexp | ||
| 10107 | (concat "\\$\\(" (mapconcat 'car org-table-column-names "\\|") "\\)\\>")) | ||
| 10108 | (goto-char beg) | ||
| 10109 | (while (re-search-forward "^[ \t]*| *\\$ *\\(|.*\\)" end t) | ||
| 10110 | (setq fields (org-split-string (match-string 1) " *| *")) | ||
| 10111 | (while (setq field (pop fields)) | ||
| 10112 | (if (string-match "^\\([a-zA-Z][_a-zA-Z0-9]*\\|%\\) *= *\\(.*\\)" field) | ||
| 10113 | (push (cons (match-string 1 field) (match-string 2 field)) | ||
| 10114 | org-table-local-parameters)))) | ||
| 10115 | (goto-char beg) | ||
| 10116 | (while (re-search-forward "^[ \t]*| *\\([_^]\\) *\\(|.*\\)" end t) | ||
| 10117 | (setq c (match-string 1) | ||
| 10118 | fields (org-split-string (match-string 2) " *| *")) | ||
| 10119 | (save-excursion | ||
| 10120 | (beginning-of-line (if (equal c "_") 2 0)) | ||
| 10121 | (setq line (org-current-line) col 1) | ||
| 10122 | (and (looking-at "^[ \t]*|[^|]*\\(|.*\\)") | ||
| 10123 | (setq fields1 (org-split-string (match-string 1) " *| *")))) | ||
| 10124 | (while (and fields1 (setq field (pop fields))) | ||
| 10125 | (setq v (pop fields1) col (1+ col)) | ||
| 10126 | (when (and (stringp field) (stringp v) | ||
| 10127 | (string-match "^[a-zA-Z][a-zA-Z0-9]*$" field)) | ||
| 10128 | (push (cons field v) org-table-local-parameters) | ||
| 10129 | (push (list field line col) org-table-named-field-locations)))) | ||
| 10130 | ;; Analyse the line types | ||
| 10131 | (goto-char beg) | ||
| 10132 | (setq org-table-current-begin-line (org-current-line) | ||
| 10133 | org-table-current-begin-pos (point) | ||
| 10134 | l org-table-current-begin-line) | ||
| 10135 | (while (looking-at "[ \t]*|\\(-\\)?") | ||
| 10136 | (push (if (match-end 1) 'hline 'dline) types) | ||
| 10137 | (if (match-end 1) (push l hlines) (push l dlines)) | ||
| 10138 | (beginning-of-line 2) | ||
| 10139 | (setq l (1+ l))) | ||
| 10140 | (setq org-table-current-line-types (apply 'vector (nreverse types)) | ||
| 10141 | org-table-dlines (apply 'vector (cons nil (nreverse dlines))) | ||
| 10142 | org-table-hlines (apply 'vector (cons nil (nreverse hlines))))))) | ||
| 10143 | |||
| 10144 | (defun org-table-maybe-eval-formula () | ||
| 10145 | "Check if the current field starts with \"=\" or \":=\". | ||
| 10146 | If yes, store the formula and apply it." | ||
| 10147 | ;; We already know we are in a table. Get field will only return a formula | ||
| 10148 | ;; when appropriate. It might return a separator line, but no problem. | ||
| 10149 | (when org-table-formula-evaluate-inline | ||
| 10150 | (let* ((field (org-trim (or (org-table-get-field) ""))) | ||
| 10151 | named eq) | ||
| 10152 | (when (string-match "^:?=\\(.*\\)" field) | ||
| 10153 | (setq named (equal (string-to-char field) ?:) | ||
| 10154 | eq (match-string 1 field)) | ||
| 10155 | (if (or (fboundp 'calc-eval) | ||
| 10156 | (equal (substring eq 0 (min 2 (length eq))) "'(")) | ||
| 10157 | (org-table-eval-formula (if named '(4) nil) | ||
| 10158 | (org-table-formula-from-user eq)) | ||
| 10159 | (error "Calc does not seem to be installed, and is needed to evaluate the formula")))))) | ||
| 10160 | |||
| 10161 | (defvar org-recalc-commands nil | ||
| 10162 | "List of commands triggering the recalculation of a line. | ||
| 10163 | Will be filled automatically during use.") | ||
| 10164 | |||
| 10165 | (defvar org-recalc-marks | ||
| 10166 | '((" " . "Unmarked: no special line, no automatic recalculation") | ||
| 10167 | ("#" . "Automatically recalculate this line upon TAB, RET, and C-c C-c in the line") | ||
| 10168 | ("*" . "Recalculate only when entire table is recalculated with `C-u C-c *'") | ||
| 10169 | ("!" . "Column name definition line. Reference in formula as $name.") | ||
| 10170 | ("$" . "Parameter definition line name=value. Reference in formula as $name.") | ||
| 10171 | ("_" . "Names for values in row below this one.") | ||
| 10172 | ("^" . "Names for values in row above this one."))) | ||
| 10173 | |||
| 10174 | (defun org-table-rotate-recalc-marks (&optional newchar) | ||
| 10175 | "Rotate the recalculation mark in the first column. | ||
| 10176 | If in any row, the first field is not consistent with a mark, | ||
| 10177 | insert a new column for the markers. | ||
| 10178 | When there is an active region, change all the lines in the region, | ||
| 10179 | after prompting for the marking character. | ||
| 10180 | After each change, a message will be displayed indicating the meaning | ||
| 10181 | of the new mark." | ||
| 10182 | (interactive) | ||
| 10183 | (unless (org-at-table-p) (error "Not at a table")) | ||
| 10184 | (let* ((marks (append (mapcar 'car org-recalc-marks) '(" "))) | ||
| 10185 | (beg (org-table-begin)) | ||
| 10186 | (end (org-table-end)) | ||
| 10187 | (l (org-current-line)) | ||
| 10188 | (l1 (if (org-region-active-p) (org-current-line (region-beginning)))) | ||
| 10189 | (l2 (if (org-region-active-p) (org-current-line (region-end)))) | ||
| 10190 | (have-col | ||
| 10191 | (save-excursion | ||
| 10192 | (goto-char beg) | ||
| 10193 | (not (re-search-forward "^[ \t]*|[^-|][^|]*[^#!$*_^| \t][^|]*|" end t)))) | ||
| 10194 | (col (org-table-current-column)) | ||
| 10195 | (forcenew (car (assoc newchar org-recalc-marks))) | ||
| 10196 | epos new) | ||
| 10197 | (when l1 | ||
| 10198 | (message "Change region to what mark? Type # * ! $ or SPC: ") | ||
| 10199 | (setq newchar (char-to-string (read-char-exclusive)) | ||
| 10200 | forcenew (car (assoc newchar org-recalc-marks)))) | ||
| 10201 | (if (and newchar (not forcenew)) | ||
| 10202 | (error "Invalid NEWCHAR `%s' in `org-table-rotate-recalc-marks'" | ||
| 10203 | newchar)) | ||
| 10204 | (if l1 (goto-line l1)) | ||
| 10205 | (save-excursion | ||
| 10206 | (beginning-of-line 1) | ||
| 10207 | (unless (looking-at org-table-dataline-regexp) | ||
| 10208 | (error "Not at a table data line"))) | ||
| 10209 | (unless have-col | ||
| 10210 | (org-table-goto-column 1) | ||
| 10211 | (org-table-insert-column) | ||
| 10212 | (org-table-goto-column (1+ col))) | ||
| 10213 | (setq epos (point-at-eol)) | ||
| 10214 | (save-excursion | ||
| 10215 | (beginning-of-line 1) | ||
| 10216 | (org-table-get-field | ||
| 10217 | 1 (if (looking-at "^[ \t]*| *\\([#!$*^_ ]\\) *|") | ||
| 10218 | (concat " " | ||
| 10219 | (setq new (or forcenew | ||
| 10220 | (cadr (member (match-string 1) marks)))) | ||
| 10221 | " ") | ||
| 10222 | " # "))) | ||
| 10223 | (if (and l1 l2) | ||
| 10224 | (progn | ||
| 10225 | (goto-line l1) | ||
| 10226 | (while (progn (beginning-of-line 2) (not (= (org-current-line) l2))) | ||
| 10227 | (and (looking-at org-table-dataline-regexp) | ||
| 10228 | (org-table-get-field 1 (concat " " new " ")))) | ||
| 10229 | (goto-line l1))) | ||
| 10230 | (if (not (= epos (point-at-eol))) (org-table-align)) | ||
| 10231 | (goto-line l) | ||
| 10232 | (and (interactive-p) (message "%s" (cdr (assoc new org-recalc-marks)))))) | ||
| 10233 | |||
| 10234 | (defun org-table-maybe-recalculate-line () | ||
| 10235 | "Recompute the current line if marked for it, and if we haven't just done it." | ||
| 10236 | (interactive) | ||
| 10237 | (and org-table-allow-automatic-line-recalculation | ||
| 10238 | (not (and (memq last-command org-recalc-commands) | ||
| 10239 | (equal org-last-recalc-line (org-current-line)))) | ||
| 10240 | (save-excursion (beginning-of-line 1) | ||
| 10241 | (looking-at org-table-auto-recalculate-regexp)) | ||
| 10242 | (org-table-recalculate) t)) | ||
| 10243 | |||
| 10244 | (defvar org-table-formula-debug nil | ||
| 10245 | "Non-nil means, debug table formulas. | ||
| 10246 | When nil, simply write \"#ERROR\" in corrupted fields.") | ||
| 10247 | (make-variable-buffer-local 'org-table-formula-debug) | ||
| 10248 | |||
| 10249 | (defvar modes) | ||
| 10250 | (defsubst org-set-calc-mode (var &optional value) | ||
| 10251 | (if (stringp var) | ||
| 10252 | (setq var (assoc var '(("D" calc-angle-mode deg) | ||
| 10253 | ("R" calc-angle-mode rad) | ||
| 10254 | ("F" calc-prefer-frac t) | ||
| 10255 | ("S" calc-symbolic-mode t))) | ||
| 10256 | value (nth 2 var) var (nth 1 var))) | ||
| 10257 | (if (memq var modes) | ||
| 10258 | (setcar (cdr (memq var modes)) value) | ||
| 10259 | (cons var (cons value modes))) | ||
| 10260 | modes) | ||
| 10261 | |||
| 10262 | (defun org-table-eval-formula (&optional arg equation | ||
| 10263 | suppress-align suppress-const | ||
| 10264 | suppress-store suppress-analysis) | ||
| 10265 | "Replace the table field value at the cursor by the result of a calculation. | ||
| 10266 | |||
| 10267 | This function makes use of Dave Gillespie's Calc package, in my view the | ||
| 10268 | most exciting program ever written for GNU Emacs. So you need to have Calc | ||
| 10269 | installed in order to use this function. | ||
| 10270 | |||
| 10271 | In a table, this command replaces the value in the current field with the | ||
| 10272 | result of a formula. It also installs the formula as the \"current\" column | ||
| 10273 | formula, by storing it in a special line below the table. When called | ||
| 10274 | with a `C-u' prefix, the current field must ba a named field, and the | ||
| 10275 | formula is installed as valid in only this specific field. | ||
| 10276 | |||
| 10277 | When called with two `C-u' prefixes, insert the active equation | ||
| 10278 | for the field back into the current field, so that it can be | ||
| 10279 | edited there. This is useful in order to use \\[org-table-show-reference] | ||
| 10280 | to check the referenced fields. | ||
| 10281 | |||
| 10282 | When called, the command first prompts for a formula, which is read in | ||
| 10283 | the minibuffer. Previously entered formulas are available through the | ||
| 10284 | history list, and the last used formula is offered as a default. | ||
| 10285 | These stored formulas are adapted correctly when moving, inserting, or | ||
| 10286 | deleting columns with the corresponding commands. | ||
| 10287 | |||
| 10288 | The formula can be any algebraic expression understood by the Calc package. | ||
| 10289 | For details, see the Org-mode manual. | ||
| 10290 | |||
| 10291 | This function can also be called from Lisp programs and offers | ||
| 10292 | additional arguments: EQUATION can be the formula to apply. If this | ||
| 10293 | argument is given, the user will not be prompted. SUPPRESS-ALIGN is | ||
| 10294 | used to speed-up recursive calls by by-passing unnecessary aligns. | ||
| 10295 | SUPPRESS-CONST suppresses the interpretation of constants in the | ||
| 10296 | formula, assuming that this has been done already outside the function. | ||
| 10297 | SUPPRESS-STORE means the formula should not be stored, either because | ||
| 10298 | it is already stored, or because it is a modified equation that should | ||
| 10299 | not overwrite the stored one." | ||
| 10300 | (interactive "P") | ||
| 10301 | (org-table-check-inside-data-field) | ||
| 10302 | (or suppress-analysis (org-table-get-specials)) | ||
| 10303 | (if (equal arg '(16)) | ||
| 10304 | (let ((eq (org-table-current-field-formula))) | ||
| 10305 | (or eq (error "No equation active for current field")) | ||
| 10306 | (org-table-get-field nil eq) | ||
| 10307 | (org-table-align) | ||
| 10308 | (setq org-table-may-need-update t)) | ||
| 10309 | (let* (fields | ||
| 10310 | (ndown (if (integerp arg) arg 1)) | ||
| 10311 | (org-table-automatic-realign nil) | ||
| 10312 | (case-fold-search nil) | ||
| 10313 | (down (> ndown 1)) | ||
| 10314 | (formula (if (and equation suppress-store) | ||
| 10315 | equation | ||
| 10316 | (org-table-get-formula equation (equal arg '(4))))) | ||
| 10317 | (n0 (org-table-current-column)) | ||
| 10318 | (modes (copy-sequence org-calc-default-modes)) | ||
| 10319 | (numbers nil) ; was a variable, now fixed default | ||
| 10320 | (keep-empty nil) | ||
| 10321 | n form form0 bw fmt x ev orig c lispp literal) | ||
| 10322 | ;; Parse the format string. Since we have a lot of modes, this is | ||
| 10323 | ;; a lot of work. However, I think calc still uses most of the time. | ||
| 10324 | (if (string-match ";" formula) | ||
| 10325 | (let ((tmp (org-split-string formula ";"))) | ||
| 10326 | (setq formula (car tmp) | ||
| 10327 | fmt (concat (cdr (assoc "%" org-table-local-parameters)) | ||
| 10328 | (nth 1 tmp))) | ||
| 10329 | (while (string-match "\\([pnfse]\\)\\(-?[0-9]+\\)" fmt) | ||
| 10330 | (setq c (string-to-char (match-string 1 fmt)) | ||
| 10331 | n (string-to-number (match-string 2 fmt))) | ||
| 10332 | (if (= c ?p) | ||
| 10333 | (setq modes (org-set-calc-mode 'calc-internal-prec n)) | ||
| 10334 | (setq modes (org-set-calc-mode | ||
| 10335 | 'calc-float-format | ||
| 10336 | (list (cdr (assoc c '((?n . float) (?f . fix) | ||
| 10337 | (?s . sci) (?e . eng)))) | ||
| 10338 | n)))) | ||
| 10339 | (setq fmt (replace-match "" t t fmt))) | ||
| 10340 | (if (string-match "[NT]" fmt) | ||
| 10341 | (setq numbers (equal (match-string 0 fmt) "N") | ||
| 10342 | fmt (replace-match "" t t fmt))) | ||
| 10343 | (if (string-match "L" fmt) | ||
| 10344 | (setq literal t | ||
| 10345 | fmt (replace-match "" t t fmt))) | ||
| 10346 | (if (string-match "E" fmt) | ||
| 10347 | (setq keep-empty t | ||
| 10348 | fmt (replace-match "" t t fmt))) | ||
| 10349 | (while (string-match "[DRFS]" fmt) | ||
| 10350 | (setq modes (org-set-calc-mode (match-string 0 fmt))) | ||
| 10351 | (setq fmt (replace-match "" t t fmt))) | ||
| 10352 | (unless (string-match "\\S-" fmt) | ||
| 10353 | (setq fmt nil)))) | ||
| 10354 | (if (and (not suppress-const) org-table-formula-use-constants) | ||
| 10355 | (setq formula (org-table-formula-substitute-names formula))) | ||
| 10356 | (setq orig (or (get-text-property 1 :orig-formula formula) "?")) | ||
| 10357 | (while (> ndown 0) | ||
| 10358 | (setq fields (org-split-string | ||
| 10359 | (org-no-properties | ||
| 10360 | (buffer-substring (point-at-bol) (point-at-eol))) | ||
| 10361 | " *| *")) | ||
| 10362 | (if (eq numbers t) | ||
| 10363 | (setq fields (mapcar | ||
| 10364 | (lambda (x) (number-to-string (string-to-number x))) | ||
| 10365 | fields))) | ||
| 10366 | (setq ndown (1- ndown)) | ||
| 10367 | (setq form (copy-sequence formula) | ||
| 10368 | lispp (and (> (length form) 2)(equal (substring form 0 2) "'("))) | ||
| 10369 | (if (and lispp literal) (setq lispp 'literal)) | ||
| 10370 | ;; Check for old vertical references | ||
| 10371 | (setq form (org-rewrite-old-row-references form)) | ||
| 10372 | ;; Insert complex ranges | ||
| 10373 | (while (string-match org-table-range-regexp form) | ||
| 10374 | (setq form | ||
| 10375 | (replace-match | ||
| 10376 | (save-match-data | ||
| 10377 | (org-table-make-reference | ||
| 10378 | (org-table-get-range (match-string 0 form) nil n0) | ||
| 10379 | keep-empty numbers lispp)) | ||
| 10380 | t t form))) | ||
| 10381 | ;; Insert simple ranges | ||
| 10382 | (while (string-match "\\$\\([0-9]+\\)\\.\\.\\$\\([0-9]+\\)" form) | ||
| 10383 | (setq form | ||
| 10384 | (replace-match | ||
| 10385 | (save-match-data | ||
| 10386 | (org-table-make-reference | ||
| 10387 | (org-sublist | ||
| 10388 | fields (string-to-number (match-string 1 form)) | ||
| 10389 | (string-to-number (match-string 2 form))) | ||
| 10390 | keep-empty numbers lispp)) | ||
| 10391 | t t form))) | ||
| 10392 | (setq form0 form) | ||
| 10393 | ;; Insert the references to fields in same row | ||
| 10394 | (while (string-match "\\$\\([0-9]+\\)" form) | ||
| 10395 | (setq n (string-to-number (match-string 1 form)) | ||
| 10396 | x (nth (1- (if (= n 0) n0 n)) fields)) | ||
| 10397 | (unless x (error "Invalid field specifier \"%s\"" | ||
| 10398 | (match-string 0 form))) | ||
| 10399 | (setq form (replace-match | ||
| 10400 | (save-match-data | ||
| 10401 | (org-table-make-reference x nil numbers lispp)) | ||
| 10402 | t t form))) | ||
| 10403 | |||
| 10404 | (if lispp | ||
| 10405 | (setq ev (condition-case nil | ||
| 10406 | (eval (eval (read form))) | ||
| 10407 | (error "#ERROR")) | ||
| 10408 | ev (if (numberp ev) (number-to-string ev) ev)) | ||
| 10409 | (or (fboundp 'calc-eval) | ||
| 10410 | (error "Calc does not seem to be installed, and is needed to evaluate the formula")) | ||
| 10411 | (setq ev (calc-eval (cons form modes) | ||
| 10412 | (if numbers 'num)))) | ||
| 10413 | |||
| 10414 | (when org-table-formula-debug | ||
| 10415 | (with-output-to-temp-buffer "*Substitution History*" | ||
| 10416 | (princ (format "Substitution history of formula | ||
| 10417 | Orig: %s | ||
| 10418 | $xyz-> %s | ||
| 10419 | @r$c-> %s | ||
| 10420 | $1-> %s\n" orig formula form0 form)) | ||
| 10421 | (if (listp ev) | ||
| 10422 | (princ (format " %s^\nError: %s" | ||
| 10423 | (make-string (car ev) ?\-) (nth 1 ev))) | ||
| 10424 | (princ (format "Result: %s\nFormat: %s\nFinal: %s" | ||
| 10425 | ev (or fmt "NONE") | ||
| 10426 | (if fmt (format fmt (string-to-number ev)) ev))))) | ||
| 10427 | (setq bw (get-buffer-window "*Substitution History*")) | ||
| 10428 | (shrink-window-if-larger-than-buffer bw) | ||
| 10429 | (unless (and (interactive-p) (not ndown)) | ||
| 10430 | (unless (let (inhibit-redisplay) | ||
| 10431 | (y-or-n-p "Debugging Formula. Continue to next? ")) | ||
| 10432 | (org-table-align) | ||
| 10433 | (error "Abort")) | ||
| 10434 | (delete-window bw) | ||
| 10435 | (message ""))) | ||
| 10436 | (if (listp ev) (setq fmt nil ev "#ERROR")) | ||
| 10437 | (org-table-justify-field-maybe | ||
| 10438 | (if fmt (format fmt (string-to-number ev)) ev)) | ||
| 10439 | (if (and down (> ndown 0) (looking-at ".*\n[ \t]*|[^-]")) | ||
| 10440 | (call-interactively 'org-return) | ||
| 10441 | (setq ndown 0))) | ||
| 10442 | (and down (org-table-maybe-recalculate-line)) | ||
| 10443 | (or suppress-align (and org-table-may-need-update | ||
| 10444 | (org-table-align)))))) | ||
| 10445 | |||
| 10446 | (defun org-table-put-field-property (prop value) | ||
| 10447 | (save-excursion | ||
| 10448 | (put-text-property (progn (skip-chars-backward "^|") (point)) | ||
| 10449 | (progn (skip-chars-forward "^|") (point)) | ||
| 10450 | prop value))) | ||
| 10451 | |||
| 10452 | (defun org-table-get-range (desc &optional tbeg col highlight) | ||
| 10453 | "Get a calc vector from a column, accorting to descriptor DESC. | ||
| 10454 | Optional arguments TBEG and COL can give the beginning of the table and | ||
| 10455 | the current column, to avoid unnecessary parsing. | ||
| 10456 | HIGHLIGHT means, just highlight the range." | ||
| 10457 | (if (not (equal (string-to-char desc) ?@)) | ||
| 10458 | (setq desc (concat "@" desc))) | ||
| 10459 | (save-excursion | ||
| 10460 | (or tbeg (setq tbeg (org-table-begin))) | ||
| 10461 | (or col (setq col (org-table-current-column))) | ||
| 10462 | (let ((thisline (org-current-line)) | ||
| 10463 | beg end c1 c2 r1 r2 rangep tmp) | ||
| 10464 | (unless (string-match org-table-range-regexp desc) | ||
| 10465 | (error "Invalid table range specifier `%s'" desc)) | ||
| 10466 | (setq rangep (match-end 3) | ||
| 10467 | r1 (and (match-end 1) (match-string 1 desc)) | ||
| 10468 | r2 (and (match-end 4) (match-string 4 desc)) | ||
| 10469 | c1 (and (match-end 2) (substring (match-string 2 desc) 1)) | ||
| 10470 | c2 (and (match-end 5) (substring (match-string 5 desc) 1))) | ||
| 10471 | |||
| 10472 | (and c1 (setq c1 (+ (string-to-number c1) | ||
| 10473 | (if (memq (string-to-char c1) '(?- ?+)) col 0)))) | ||
| 10474 | (and c2 (setq c2 (+ (string-to-number c2) | ||
| 10475 | (if (memq (string-to-char c2) '(?- ?+)) col 0)))) | ||
| 10476 | (if (equal r1 "") (setq r1 nil)) | ||
| 10477 | (if (equal r2 "") (setq r2 nil)) | ||
| 10478 | (if r1 (setq r1 (org-table-get-descriptor-line r1))) | ||
| 10479 | (if r2 (setq r2 (org-table-get-descriptor-line r2))) | ||
| 10480 | ; (setq r2 (or r2 r1) c2 (or c2 c1)) | ||
| 10481 | (if (not r1) (setq r1 thisline)) | ||
| 10482 | (if (not r2) (setq r2 thisline)) | ||
| 10483 | (if (not c1) (setq c1 col)) | ||
| 10484 | (if (not c2) (setq c2 col)) | ||
| 10485 | (if (or (not rangep) (and (= r1 r2) (= c1 c2))) | ||
| 10486 | ;; just one field | ||
| 10487 | (progn | ||
| 10488 | (goto-line r1) | ||
| 10489 | (while (not (looking-at org-table-dataline-regexp)) | ||
| 10490 | (beginning-of-line 2)) | ||
| 10491 | (prog1 (org-trim (org-table-get-field c1)) | ||
| 10492 | (if highlight (org-table-highlight-rectangle (point) (point))))) | ||
| 10493 | ;; A range, return a vector | ||
| 10494 | ;; First sort the numbers to get a regular ractangle | ||
| 10495 | (if (< r2 r1) (setq tmp r1 r1 r2 r2 tmp)) | ||
| 10496 | (if (< c2 c1) (setq tmp c1 c1 c2 c2 tmp)) | ||
| 10497 | (goto-line r1) | ||
| 10498 | (while (not (looking-at org-table-dataline-regexp)) | ||
| 10499 | (beginning-of-line 2)) | ||
| 10500 | (org-table-goto-column c1) | ||
| 10501 | (setq beg (point)) | ||
| 10502 | (goto-line r2) | ||
| 10503 | (while (not (looking-at org-table-dataline-regexp)) | ||
| 10504 | (beginning-of-line 0)) | ||
| 10505 | (org-table-goto-column c2) | ||
| 10506 | (setq end (point)) | ||
| 10507 | (if highlight | ||
| 10508 | (org-table-highlight-rectangle | ||
| 10509 | beg (progn (skip-chars-forward "^|\n") (point)))) | ||
| 10510 | ;; return string representation of calc vector | ||
| 10511 | (mapcar 'org-trim | ||
| 10512 | (apply 'append (org-table-copy-region beg end))))))) | ||
| 10513 | |||
| 10514 | (defun org-table-get-descriptor-line (desc &optional cline bline table) | ||
| 10515 | "Analyze descriptor DESC and retrieve the corresponding line number. | ||
| 10516 | The cursor is currently in line CLINE, the table begins in line BLINE, | ||
| 10517 | and TABLE is a vector with line types." | ||
| 10518 | (if (string-match "^[0-9]+$" desc) | ||
| 10519 | (aref org-table-dlines (string-to-number desc)) | ||
| 10520 | (setq cline (or cline (org-current-line)) | ||
| 10521 | bline (or bline org-table-current-begin-line) | ||
| 10522 | table (or table org-table-current-line-types)) | ||
| 10523 | (if (or | ||
| 10524 | (not (string-match "^\\(\\([-+]\\)?\\(I+\\)\\)?\\(\\([-+]\\)?\\([0-9]+\\)\\)?" desc)) | ||
| 10525 | ;; 1 2 3 4 5 6 | ||
| 10526 | (and (not (match-end 3)) (not (match-end 6))) | ||
| 10527 | (and (match-end 3) (match-end 6) (not (match-end 5)))) | ||
| 10528 | (error "invalid row descriptor `%s'" desc)) | ||
| 10529 | (let* ((hdir (and (match-end 2) (match-string 2 desc))) | ||
| 10530 | (hn (if (match-end 3) (- (match-end 3) (match-beginning 3)) nil)) | ||
| 10531 | (odir (and (match-end 5) (match-string 5 desc))) | ||
| 10532 | (on (if (match-end 6) (string-to-number (match-string 6 desc)))) | ||
| 10533 | (i (- cline bline)) | ||
| 10534 | (rel (and (match-end 6) | ||
| 10535 | (or (and (match-end 1) (not (match-end 3))) | ||
| 10536 | (match-end 5))))) | ||
| 10537 | (if (and hn (not hdir)) | ||
| 10538 | (progn | ||
| 10539 | (setq i 0 hdir "+") | ||
| 10540 | (if (eq (aref table 0) 'hline) (setq hn (1- hn))))) | ||
| 10541 | (if (and (not hn) on (not odir)) | ||
| 10542 | (error "should never happen");;(aref org-table-dlines on) | ||
| 10543 | (if (and hn (> hn 0)) | ||
| 10544 | (setq i (org-find-row-type table i 'hline (equal hdir "-") nil hn))) | ||
| 10545 | (if on | ||
| 10546 | (setq i (org-find-row-type table i 'dline (equal odir "-") rel on))) | ||
| 10547 | (+ bline i))))) | ||
| 10548 | |||
| 10549 | (defun org-find-row-type (table i type backwards relative n) | ||
| 10550 | (let ((l (length table))) | ||
| 10551 | (while (> n 0) | ||
| 10552 | (while (and (setq i (+ i (if backwards -1 1))) | ||
| 10553 | (>= i 0) (< i l) | ||
| 10554 | (not (eq (aref table i) type)) | ||
| 10555 | (if (and relative (eq (aref table i) 'hline)) | ||
| 10556 | (progn (setq i (- i (if backwards -1 1)) n 1) nil) | ||
| 10557 | t))) | ||
| 10558 | (setq n (1- n))) | ||
| 10559 | (if (or (< i 0) (>= i l)) | ||
| 10560 | (error "Row descriptior leads outside table") | ||
| 10561 | i))) | ||
| 10562 | |||
| 10563 | (defun org-rewrite-old-row-references (s) | ||
| 10564 | (if (string-match "&[-+0-9I]" s) | ||
| 10565 | (error "Formula contains old &row reference, please rewrite using @-syntax") | ||
| 10566 | s)) | ||
| 10567 | |||
| 10568 | (defun org-table-make-reference (elements keep-empty numbers lispp) | ||
| 10569 | "Convert list ELEMENTS to something appropriate to insert into formula. | ||
| 10570 | KEEP-EMPTY indicated to keep empty fields, default is to skip them. | ||
| 10571 | NUMBERS indicates that everything should be converted to numbers. | ||
| 10572 | LISPP means to return something appropriate for a Lisp list." | ||
| 10573 | (if (stringp elements) ; just a single val | ||
| 10574 | (if lispp | ||
| 10575 | (if (eq lispp 'literal) | ||
| 10576 | elements | ||
| 10577 | (prin1-to-string (if numbers (string-to-number elements) elements))) | ||
| 10578 | (if (equal elements "") (setq elements "0")) | ||
| 10579 | (if numbers (number-to-string (string-to-number elements)) elements)) | ||
| 10580 | (unless keep-empty | ||
| 10581 | (setq elements | ||
| 10582 | (delq nil | ||
| 10583 | (mapcar (lambda (x) (if (string-match "\\S-" x) x nil)) | ||
| 10584 | elements)))) | ||
| 10585 | (setq elements (or elements '("0"))) | ||
| 10586 | (if lispp | ||
| 10587 | (mapconcat | ||
| 10588 | (lambda (x) | ||
| 10589 | (if (eq lispp 'literal) | ||
| 10590 | x | ||
| 10591 | (prin1-to-string (if numbers (string-to-number x) x)))) | ||
| 10592 | elements " ") | ||
| 10593 | (concat "[" (mapconcat | ||
| 10594 | (lambda (x) | ||
| 10595 | (if numbers (number-to-string (string-to-number x)) x)) | ||
| 10596 | elements | ||
| 10597 | ",") "]")))) | ||
| 10598 | |||
| 10599 | (defun org-table-recalculate (&optional all noalign) | ||
| 10600 | "Recalculate the current table line by applying all stored formulas. | ||
| 10601 | With prefix arg ALL, do this for all lines in the table." | ||
| 10602 | (interactive "P") | ||
| 10603 | (or (memq this-command org-recalc-commands) | ||
| 10604 | (setq org-recalc-commands (cons this-command org-recalc-commands))) | ||
| 10605 | (unless (org-at-table-p) (error "Not at a table")) | ||
| 10606 | (if (equal all '(16)) | ||
| 10607 | (org-table-iterate) | ||
| 10608 | (org-table-get-specials) | ||
| 10609 | (let* ((eqlist (sort (org-table-get-stored-formulas) | ||
| 10610 | (lambda (a b) (string< (car a) (car b))))) | ||
| 10611 | (inhibit-redisplay (not debug-on-error)) | ||
| 10612 | (line-re org-table-dataline-regexp) | ||
| 10613 | (thisline (org-current-line)) | ||
| 10614 | (thiscol (org-table-current-column)) | ||
| 10615 | beg end entry eqlnum eqlname eqlname1 eql (cnt 0) eq a name) | ||
| 10616 | ;; Insert constants in all formulas | ||
| 10617 | (setq eqlist | ||
| 10618 | (mapcar (lambda (x) | ||
| 10619 | (setcdr x (org-table-formula-substitute-names (cdr x))) | ||
| 10620 | x) | ||
| 10621 | eqlist)) | ||
| 10622 | ;; Split the equation list | ||
| 10623 | (while (setq eq (pop eqlist)) | ||
| 10624 | (if (<= (string-to-char (car eq)) ?9) | ||
| 10625 | (push eq eqlnum) | ||
| 10626 | (push eq eqlname))) | ||
| 10627 | (setq eqlnum (nreverse eqlnum) eqlname (nreverse eqlname)) | ||
| 10628 | (if all | ||
| 10629 | (progn | ||
| 10630 | (setq end (move-marker (make-marker) (1+ (org-table-end)))) | ||
| 10631 | (goto-char (setq beg (org-table-begin))) | ||
| 10632 | (if (re-search-forward org-table-calculate-mark-regexp end t) | ||
| 10633 | ;; This is a table with marked lines, compute selected lines | ||
| 10634 | (setq line-re org-table-recalculate-regexp) | ||
| 10635 | ;; Move forward to the first non-header line | ||
| 10636 | (if (and (re-search-forward org-table-dataline-regexp end t) | ||
| 10637 | (re-search-forward org-table-hline-regexp end t) | ||
| 10638 | (re-search-forward org-table-dataline-regexp end t)) | ||
| 10639 | (setq beg (match-beginning 0)) | ||
| 10640 | nil))) ;; just leave beg where it is | ||
| 10641 | (setq beg (point-at-bol) | ||
| 10642 | end (move-marker (make-marker) (1+ (point-at-eol))))) | ||
| 10643 | (goto-char beg) | ||
| 10644 | (and all (message "Re-applying formulas to full table...")) | ||
| 10645 | |||
| 10646 | ;; First find the named fields, and mark them untouchanble | ||
| 10647 | (remove-text-properties beg end '(org-untouchable t)) | ||
| 10648 | (while (setq eq (pop eqlname)) | ||
| 10649 | (setq name (car eq) | ||
| 10650 | a (assoc name org-table-named-field-locations)) | ||
| 10651 | (and (not a) | ||
| 10652 | (string-match "@\\([0-9]+\\)\\$\\([0-9]+\\)" name) | ||
| 10653 | (setq a (list name | ||
| 10654 | (aref org-table-dlines | ||
| 10655 | (string-to-number (match-string 1 name))) | ||
| 10656 | (string-to-number (match-string 2 name))))) | ||
| 10657 | (when (and a (or all (equal (nth 1 a) thisline))) | ||
| 10658 | (message "Re-applying formula to field: %s" name) | ||
| 10659 | (goto-line (nth 1 a)) | ||
| 10660 | (org-table-goto-column (nth 2 a)) | ||
| 10661 | (push (append a (list (cdr eq))) eqlname1) | ||
| 10662 | (org-table-put-field-property :org-untouchable t))) | ||
| 10663 | |||
| 10664 | ;; Now evauluate the column formulas, but skip fields covered by | ||
| 10665 | ;; field formulas | ||
| 10666 | (goto-char beg) | ||
| 10667 | (while (re-search-forward line-re end t) | ||
| 10668 | (unless (string-match "^ *[_^!$/] *$" (org-table-get-field 1)) | ||
| 10669 | ;; Unprotected line, recalculate | ||
| 10670 | (and all (message "Re-applying formulas to full table...(line %d)" | ||
| 10671 | (setq cnt (1+ cnt)))) | ||
| 10672 | (setq org-last-recalc-line (org-current-line)) | ||
| 10673 | (setq eql eqlnum) | ||
| 10674 | (while (setq entry (pop eql)) | ||
| 10675 | (goto-line org-last-recalc-line) | ||
| 10676 | (org-table-goto-column (string-to-number (car entry)) nil 'force) | ||
| 10677 | (unless (get-text-property (point) :org-untouchable) | ||
| 10678 | (org-table-eval-formula nil (cdr entry) | ||
| 10679 | 'noalign 'nocst 'nostore 'noanalysis))))) | ||
| 10680 | |||
| 10681 | ;; Now evaluate the field formulas | ||
| 10682 | (while (setq eq (pop eqlname1)) | ||
| 10683 | (message "Re-applying formula to field: %s" (car eq)) | ||
| 10684 | (goto-line (nth 1 eq)) | ||
| 10685 | (org-table-goto-column (nth 2 eq)) | ||
| 10686 | (org-table-eval-formula nil (nth 3 eq) 'noalign 'nocst | ||
| 10687 | 'nostore 'noanalysis)) | ||
| 10688 | |||
| 10689 | (goto-line thisline) | ||
| 10690 | (org-table-goto-column thiscol) | ||
| 10691 | (remove-text-properties (point-min) (point-max) '(org-untouchable t)) | ||
| 10692 | (or noalign (and org-table-may-need-update (org-table-align)) | ||
| 10693 | (and all (message "Re-applying formulas to %d lines...done" cnt))) | ||
| 10694 | |||
| 10695 | ;; back to initial position | ||
| 10696 | (message "Re-applying formulas...done") | ||
| 10697 | (goto-line thisline) | ||
| 10698 | (org-table-goto-column thiscol) | ||
| 10699 | (or noalign (and org-table-may-need-update (org-table-align)) | ||
| 10700 | (and all (message "Re-applying formulas...done")))))) | ||
| 10701 | |||
| 10702 | (defun org-table-iterate (&optional arg) | ||
| 10703 | "Recalculate the table until it does not change anymore." | ||
| 10704 | (interactive "P") | ||
| 10705 | (let ((imax (if arg (prefix-numeric-value arg) 10)) | ||
| 10706 | (i 0) | ||
| 10707 | (lasttbl (buffer-substring (org-table-begin) (org-table-end))) | ||
| 10708 | thistbl) | ||
| 10709 | (catch 'exit | ||
| 10710 | (while (< i imax) | ||
| 10711 | (setq i (1+ i)) | ||
| 10712 | (org-table-recalculate 'all) | ||
| 10713 | (setq thistbl (buffer-substring (org-table-begin) (org-table-end))) | ||
| 10714 | (if (not (string= lasttbl thistbl)) | ||
| 10715 | (setq lasttbl thistbl) | ||
| 10716 | (if (> i 1) | ||
| 10717 | (message "Convergence after %d iterations" i) | ||
| 10718 | (message "Table was already stable")) | ||
| 10719 | (throw 'exit t))) | ||
| 10720 | (error "No convergence after %d iterations" i)))) | ||
| 10721 | |||
| 10722 | (defun org-table-formula-substitute-names (f) | ||
| 10723 | "Replace $const with values in string F." | ||
| 10724 | (let ((start 0) a (f1 f) (pp (/= (string-to-char f) ?'))) | ||
| 10725 | ;; First, check for column names | ||
| 10726 | (while (setq start (string-match org-table-column-name-regexp f start)) | ||
| 10727 | (setq start (1+ start)) | ||
| 10728 | (setq a (assoc (match-string 1 f) org-table-column-names)) | ||
| 10729 | (setq f (replace-match (concat "$" (cdr a)) t t f))) | ||
| 10730 | ;; Parameters and constants | ||
| 10731 | (setq start 0) | ||
| 10732 | (while (setq start (string-match "\\$\\([a-zA-Z][_a-zA-Z0-9]*\\)" f start)) | ||
| 10733 | (setq start (1+ start)) | ||
| 10734 | (if (setq a (save-match-data | ||
| 10735 | (org-table-get-constant (match-string 1 f)))) | ||
| 10736 | (setq f (replace-match | ||
| 10737 | (concat (if pp "(") a (if pp ")")) t t f)))) | ||
| 10738 | (if org-table-formula-debug | ||
| 10739 | (put-text-property 0 (length f) :orig-formula f1 f)) | ||
| 10740 | f)) | ||
| 10741 | |||
| 10742 | (defun org-table-get-constant (const) | ||
| 10743 | "Find the value for a parameter or constant in a formula. | ||
| 10744 | Parameters get priority." | ||
| 10745 | (or (cdr (assoc const org-table-local-parameters)) | ||
| 10746 | (cdr (assoc const org-table-formula-constants-local)) | ||
| 10747 | (cdr (assoc const org-table-formula-constants)) | ||
| 10748 | (and (fboundp 'constants-get) (constants-get const)) | ||
| 10749 | (and (string= (substring const 0 (min 5 (length const))) "PROP_") | ||
| 10750 | (org-entry-get nil (substring const 5) 'inherit)) | ||
| 10751 | "#UNDEFINED_NAME")) | ||
| 10752 | |||
| 10753 | (defvar org-table-fedit-map | ||
| 10754 | (let ((map (make-sparse-keymap))) | ||
| 10755 | (org-defkey map "\C-x\C-s" 'org-table-fedit-finish) | ||
| 10756 | (org-defkey map "\C-c\C-s" 'org-table-fedit-finish) | ||
| 10757 | (org-defkey map "\C-c\C-c" 'org-table-fedit-finish) | ||
| 10758 | (org-defkey map "\C-c\C-q" 'org-table-fedit-abort) | ||
| 10759 | (org-defkey map "\C-c?" 'org-table-show-reference) | ||
| 10760 | (org-defkey map [(meta shift up)] 'org-table-fedit-line-up) | ||
| 10761 | (org-defkey map [(meta shift down)] 'org-table-fedit-line-down) | ||
| 10762 | (org-defkey map [(shift up)] 'org-table-fedit-ref-up) | ||
| 10763 | (org-defkey map [(shift down)] 'org-table-fedit-ref-down) | ||
| 10764 | (org-defkey map [(shift left)] 'org-table-fedit-ref-left) | ||
| 10765 | (org-defkey map [(shift right)] 'org-table-fedit-ref-right) | ||
| 10766 | (org-defkey map [(meta up)] 'org-table-fedit-scroll-down) | ||
| 10767 | (org-defkey map [(meta down)] 'org-table-fedit-scroll) | ||
| 10768 | (org-defkey map [(meta tab)] 'lisp-complete-symbol) | ||
| 10769 | (org-defkey map "\M-\C-i" 'lisp-complete-symbol) | ||
| 10770 | (org-defkey map [(tab)] 'org-table-fedit-lisp-indent) | ||
| 10771 | (org-defkey map "\C-i" 'org-table-fedit-lisp-indent) | ||
| 10772 | (org-defkey map "\C-c\C-r" 'org-table-fedit-toggle-ref-type) | ||
| 10773 | (org-defkey map "\C-c}" 'org-table-fedit-toggle-coordinates) | ||
| 10774 | map)) | ||
| 10775 | |||
| 10776 | (easy-menu-define org-table-fedit-menu org-table-fedit-map "Org Edit Formulas Menu" | ||
| 10777 | '("Edit-Formulas" | ||
| 10778 | ["Finish and Install" org-table-fedit-finish t] | ||
| 10779 | ["Finish, Install, and Apply" (org-table-fedit-finish t) :keys "C-u C-c C-c"] | ||
| 10780 | ["Abort" org-table-fedit-abort t] | ||
| 10781 | "--" | ||
| 10782 | ["Pretty-Print Lisp Formula" org-table-fedit-lisp-indent t] | ||
| 10783 | ["Complete Lisp Symbol" lisp-complete-symbol t] | ||
| 10784 | "--" | ||
| 10785 | "Shift Reference at Point" | ||
| 10786 | ["Up" org-table-fedit-ref-up t] | ||
| 10787 | ["Down" org-table-fedit-ref-down t] | ||
| 10788 | ["Left" org-table-fedit-ref-left t] | ||
| 10789 | ["Right" org-table-fedit-ref-right t] | ||
| 10790 | "-" | ||
| 10791 | "Change Test Row for Column Formulas" | ||
| 10792 | ["Up" org-table-fedit-line-up t] | ||
| 10793 | ["Down" org-table-fedit-line-down t] | ||
| 10794 | "--" | ||
| 10795 | ["Scroll Table Window" org-table-fedit-scroll t] | ||
| 10796 | ["Scroll Table Window down" org-table-fedit-scroll-down t] | ||
| 10797 | ["Show Table Grid" org-table-fedit-toggle-coordinates | ||
| 10798 | :style toggle :selected (with-current-buffer (marker-buffer org-pos) | ||
| 10799 | org-table-overlay-coordinates)] | ||
| 10800 | "--" | ||
| 10801 | ["Standard Refs (B3 instead of @3$2)" org-table-fedit-toggle-ref-type | ||
| 10802 | :style toggle :selected org-table-buffer-is-an])) | ||
| 10803 | |||
| 10804 | (defvar org-pos) | ||
| 10805 | |||
| 10806 | (defun org-table-edit-formulas () | ||
| 10807 | "Edit the formulas of the current table in a separate buffer." | ||
| 10808 | (interactive) | ||
| 10809 | (when (save-excursion (beginning-of-line 1) (looking-at "#\\+TBLFM")) | ||
| 10810 | (beginning-of-line 0)) | ||
| 10811 | (unless (org-at-table-p) (error "Not at a table")) | ||
| 10812 | (org-table-get-specials) | ||
| 10813 | (let ((key (org-table-current-field-formula 'key 'noerror)) | ||
| 10814 | (eql (sort (org-table-get-stored-formulas 'noerror) | ||
| 10815 | 'org-table-formula-less-p)) | ||
| 10816 | (pos (move-marker (make-marker) (point))) | ||
| 10817 | (startline 1) | ||
| 10818 | (wc (current-window-configuration)) | ||
| 10819 | (titles '((column . "# Column Formulas\n") | ||
| 10820 | (field . "# Field Formulas\n") | ||
| 10821 | (named . "# Named Field Formulas\n"))) | ||
| 10822 | entry s type title) | ||
| 10823 | (org-switch-to-buffer-other-window "*Edit Formulas*") | ||
| 10824 | (erase-buffer) | ||
| 10825 | ;; Keep global-font-lock-mode from turning on font-lock-mode | ||
| 10826 | (let ((font-lock-global-modes '(not fundamental-mode))) | ||
| 10827 | (fundamental-mode)) | ||
| 10828 | (org-set-local 'font-lock-global-modes (list 'not major-mode)) | ||
| 10829 | (org-set-local 'org-pos pos) | ||
| 10830 | (org-set-local 'org-window-configuration wc) | ||
| 10831 | (use-local-map org-table-fedit-map) | ||
| 10832 | (org-add-hook 'post-command-hook 'org-table-fedit-post-command t t) | ||
| 10833 | (easy-menu-add org-table-fedit-menu) | ||
| 10834 | (setq startline (org-current-line)) | ||
| 10835 | (while (setq entry (pop eql)) | ||
| 10836 | (setq type (cond | ||
| 10837 | ((equal (string-to-char (car entry)) ?@) 'field) | ||
| 10838 | ((string-match "^[0-9]" (car entry)) 'column) | ||
| 10839 | (t 'named))) | ||
| 10840 | (when (setq title (assq type titles)) | ||
| 10841 | (or (bobp) (insert "\n")) | ||
| 10842 | (insert (org-add-props (cdr title) nil 'face font-lock-comment-face)) | ||
| 10843 | (setq titles (delq title titles))) | ||
| 10844 | (if (equal key (car entry)) (setq startline (org-current-line))) | ||
| 10845 | (setq s (concat (if (equal (string-to-char (car entry)) ?@) "" "$") | ||
| 10846 | (car entry) " = " (cdr entry) "\n")) | ||
| 10847 | (remove-text-properties 0 (length s) '(face nil) s) | ||
| 10848 | (insert s)) | ||
| 10849 | (if (eq org-table-use-standard-references t) | ||
| 10850 | (org-table-fedit-toggle-ref-type)) | ||
| 10851 | (goto-line startline) | ||
| 10852 | (message "Edit formulas and finish with `C-c C-c'. See menu for more commands."))) | ||
| 10853 | |||
| 10854 | (defun org-table-fedit-post-command () | ||
| 10855 | (when (not (memq this-command '(lisp-complete-symbol))) | ||
| 10856 | (let ((win (selected-window))) | ||
| 10857 | (save-excursion | ||
| 10858 | (condition-case nil | ||
| 10859 | (org-table-show-reference) | ||
| 10860 | (error nil)) | ||
| 10861 | (select-window win))))) | ||
| 10862 | |||
| 10863 | (defun org-table-formula-to-user (s) | ||
| 10864 | "Convert a formula from internal to user representation." | ||
| 10865 | (if (eq org-table-use-standard-references t) | ||
| 10866 | (org-table-convert-refs-to-an s) | ||
| 10867 | s)) | ||
| 10868 | |||
| 10869 | (defun org-table-formula-from-user (s) | ||
| 10870 | "Convert a formula from user to internal representation." | ||
| 10871 | (if org-table-use-standard-references | ||
| 10872 | (org-table-convert-refs-to-rc s) | ||
| 10873 | s)) | ||
| 10874 | |||
| 10875 | (defun org-table-convert-refs-to-rc (s) | ||
| 10876 | "Convert spreadsheet references from AB7 to @7$28. | ||
| 10877 | Works for single references, but also for entire formulas and even the | ||
| 10878 | full TBLFM line." | ||
| 10879 | (let ((start 0)) | ||
| 10880 | (while (string-match "\\<\\([a-zA-Z]+\\)\\([0-9]+\\>\\|&\\)\\|\\(;[^\r\n:]+\\)" s start) | ||
| 10881 | (cond | ||
| 10882 | ((match-end 3) | ||
| 10883 | ;; format match, just advance | ||
| 10884 | (setq start (match-end 0))) | ||
| 10885 | ((and (> (match-beginning 0) 0) | ||
| 10886 | (equal ?. (aref s (max (1- (match-beginning 0)) 0))) | ||
| 10887 | (not (equal ?. (aref s (max (- (match-beginning 0) 2) 0))))) | ||
| 10888 | ;; 3.e5 or something like this. | ||
| 10889 | (setq start (match-end 0))) | ||
| 10890 | (t | ||
| 10891 | (setq start (match-beginning 0) | ||
| 10892 | s (replace-match | ||
| 10893 | (if (equal (match-string 2 s) "&") | ||
| 10894 | (format "$%d" (org-letters-to-number (match-string 1 s))) | ||
| 10895 | (format "@%d$%d" | ||
| 10896 | (string-to-number (match-string 2 s)) | ||
| 10897 | (org-letters-to-number (match-string 1 s)))) | ||
| 10898 | t t s))))) | ||
| 10899 | s)) | ||
| 10900 | |||
| 10901 | (defun org-table-convert-refs-to-an (s) | ||
| 10902 | "Convert spreadsheet references from to @7$28 to AB7. | ||
| 10903 | Works for single references, but also for entire formulas and even the | ||
| 10904 | full TBLFM line." | ||
| 10905 | (while (string-match "@\\([0-9]+\\)\\$\\([0-9]+\\)" s) | ||
| 10906 | (setq s (replace-match | ||
| 10907 | (format "%s%d" | ||
| 10908 | (org-number-to-letters | ||
| 10909 | (string-to-number (match-string 2 s))) | ||
| 10910 | (string-to-number (match-string 1 s))) | ||
| 10911 | t t s))) | ||
| 10912 | (while (string-match "\\(^\\|[^0-9a-zA-Z]\\)\\$\\([0-9]+\\)" s) | ||
| 10913 | (setq s (replace-match (concat "\\1" | ||
| 10914 | (org-number-to-letters | ||
| 10915 | (string-to-number (match-string 2 s))) "&") | ||
| 10916 | t nil s))) | ||
| 10917 | s) | ||
| 10918 | |||
| 10919 | (defun org-letters-to-number (s) | ||
| 10920 | "Convert a base 26 number represented by letters into an integer. | ||
| 10921 | For example: AB -> 28." | ||
| 10922 | (let ((n 0)) | ||
| 10923 | (setq s (upcase s)) | ||
| 10924 | (while (> (length s) 0) | ||
| 10925 | (setq n (+ (* n 26) (string-to-char s) (- ?A) 1) | ||
| 10926 | s (substring s 1))) | ||
| 10927 | n)) | ||
| 10928 | |||
| 10929 | (defun org-number-to-letters (n) | ||
| 10930 | "Convert an integer into a base 26 number represented by letters. | ||
| 10931 | For example: 28 -> AB." | ||
| 10932 | (let ((s "")) | ||
| 10933 | (while (> n 0) | ||
| 10934 | (setq s (concat (char-to-string (+ (mod (1- n) 26) ?A)) s) | ||
| 10935 | n (/ (1- n) 26))) | ||
| 10936 | s)) | ||
| 10937 | |||
| 10938 | (defun org-table-fedit-convert-buffer (function) | ||
| 10939 | "Convert all references in this buffer, using FUNTION." | ||
| 10940 | (let ((line (org-current-line))) | ||
| 10941 | (goto-char (point-min)) | ||
| 10942 | (while (not (eobp)) | ||
| 10943 | (insert (funcall function (buffer-substring (point) (point-at-eol)))) | ||
| 10944 | (delete-region (point) (point-at-eol)) | ||
| 10945 | (or (eobp) (forward-char 1))) | ||
| 10946 | (goto-line line))) | ||
| 10947 | |||
| 10948 | (defun org-table-fedit-toggle-ref-type () | ||
| 10949 | "Convert all references in the buffer from B3 to @3$2 and back." | ||
| 10950 | (interactive) | ||
| 10951 | (org-set-local 'org-table-buffer-is-an (not org-table-buffer-is-an)) | ||
| 10952 | (org-table-fedit-convert-buffer | ||
| 10953 | (if org-table-buffer-is-an | ||
| 10954 | 'org-table-convert-refs-to-an 'org-table-convert-refs-to-rc)) | ||
| 10955 | (message "Reference type switched to %s" | ||
| 10956 | (if org-table-buffer-is-an "A1 etc" "@row$column"))) | ||
| 10957 | |||
| 10958 | (defun org-table-fedit-ref-up () | ||
| 10959 | "Shift the reference at point one row/hline up." | ||
| 10960 | (interactive) | ||
| 10961 | (org-table-fedit-shift-reference 'up)) | ||
| 10962 | (defun org-table-fedit-ref-down () | ||
| 10963 | "Shift the reference at point one row/hline down." | ||
| 10964 | (interactive) | ||
| 10965 | (org-table-fedit-shift-reference 'down)) | ||
| 10966 | (defun org-table-fedit-ref-left () | ||
| 10967 | "Shift the reference at point one field to the left." | ||
| 10968 | (interactive) | ||
| 10969 | (org-table-fedit-shift-reference 'left)) | ||
| 10970 | (defun org-table-fedit-ref-right () | ||
| 10971 | "Shift the reference at point one field to the right." | ||
| 10972 | (interactive) | ||
| 10973 | (org-table-fedit-shift-reference 'right)) | ||
| 10974 | |||
| 10975 | (defun org-table-fedit-shift-reference (dir) | ||
| 10976 | (cond | ||
| 10977 | ((org-at-regexp-p "\\(\\<[a-zA-Z]\\)&") | ||
| 10978 | (if (memq dir '(left right)) | ||
| 10979 | (org-rematch-and-replace 1 (eq dir 'left)) | ||
| 10980 | (error "Cannot shift reference in this direction"))) | ||
| 10981 | ((org-at-regexp-p "\\(\\<[a-zA-Z]\\{1,2\\}\\)\\([0-9]+\\)") | ||
| 10982 | ;; A B3-like reference | ||
| 10983 | (if (memq dir '(up down)) | ||
| 10984 | (org-rematch-and-replace 2 (eq dir 'up)) | ||
| 10985 | (org-rematch-and-replace 1 (eq dir 'left)))) | ||
| 10986 | ((org-at-regexp-p | ||
| 10987 | "\\(@\\|\\.\\.\\)\\([-+]?\\(I+\\>\\|[0-9]+\\)\\)\\(\\$\\([-+]?[0-9]+\\)\\)?") | ||
| 10988 | ;; An internal reference | ||
| 10989 | (if (memq dir '(up down)) | ||
| 10990 | (org-rematch-and-replace 2 (eq dir 'up) (match-end 3)) | ||
| 10991 | (org-rematch-and-replace 5 (eq dir 'left)))))) | ||
| 10992 | |||
| 10993 | (defun org-rematch-and-replace (n &optional decr hline) | ||
| 10994 | "Re-match the group N, and replace it with the shifted refrence." | ||
| 10995 | (or (match-end n) (error "Cannot shift reference in this direction")) | ||
| 10996 | (goto-char (match-beginning n)) | ||
| 10997 | (and (looking-at (regexp-quote (match-string n))) | ||
| 10998 | (replace-match (org-shift-refpart (match-string 0) decr hline) | ||
| 10999 | t t))) | ||
| 11000 | |||
| 11001 | (defun org-shift-refpart (ref &optional decr hline) | ||
| 11002 | "Shift a refrence part REF. | ||
| 11003 | If DECR is set, decrease the references row/column, else increase. | ||
| 11004 | If HLINE is set, this may be a hline reference, it certainly is not | ||
| 11005 | a translation reference." | ||
| 11006 | (save-match-data | ||
| 11007 | (let* ((sign (string-match "^[-+]" ref)) n) | ||
| 11008 | |||
| 11009 | (if sign (setq sign (substring ref 0 1) ref (substring ref 1))) | ||
| 11010 | (cond | ||
| 11011 | ((and hline (string-match "^I+" ref)) | ||
| 11012 | (setq n (string-to-number (concat sign (number-to-string (length ref))))) | ||
| 11013 | (setq n (+ n (if decr -1 1))) | ||
| 11014 | (if (= n 0) (setq n (+ n (if decr -1 1)))) | ||
| 11015 | (if sign | ||
| 11016 | (setq sign (if (< n 0) "-" "+") n (abs n)) | ||
| 11017 | (setq n (max 1 n))) | ||
| 11018 | (concat sign (make-string n ?I))) | ||
| 11019 | |||
| 11020 | ((string-match "^[0-9]+" ref) | ||
| 11021 | (setq n (string-to-number (concat sign ref))) | ||
| 11022 | (setq n (+ n (if decr -1 1))) | ||
| 11023 | (if sign | ||
| 11024 | (concat (if (< n 0) "-" "+") (number-to-string (abs n))) | ||
| 11025 | (number-to-string (max 1 n)))) | ||
| 11026 | |||
| 11027 | ((string-match "^[a-zA-Z]+" ref) | ||
| 11028 | (org-number-to-letters | ||
| 11029 | (max 1 (+ (org-letters-to-number ref) (if decr -1 1))))) | ||
| 11030 | |||
| 11031 | (t (error "Cannot shift reference")))))) | ||
| 11032 | |||
| 11033 | (defun org-table-fedit-toggle-coordinates () | ||
| 11034 | "Toggle the display of coordinates in the refrenced table." | ||
| 11035 | (interactive) | ||
| 11036 | (let ((pos (marker-position org-pos))) | ||
| 11037 | (with-current-buffer (marker-buffer org-pos) | ||
| 11038 | (save-excursion | ||
| 11039 | (goto-char pos) | ||
| 11040 | (org-table-toggle-coordinate-overlays))))) | ||
| 11041 | |||
| 11042 | (defun org-table-fedit-finish (&optional arg) | ||
| 11043 | "Parse the buffer for formula definitions and install them. | ||
| 11044 | With prefix ARG, apply the new formulas to the table." | ||
| 11045 | (interactive "P") | ||
| 11046 | (org-table-remove-rectangle-highlight) | ||
| 11047 | (if org-table-use-standard-references | ||
| 11048 | (progn | ||
| 11049 | (org-table-fedit-convert-buffer 'org-table-convert-refs-to-rc) | ||
| 11050 | (setq org-table-buffer-is-an nil))) | ||
| 11051 | (let ((pos org-pos) eql var form) | ||
| 11052 | (goto-char (point-min)) | ||
| 11053 | (while (re-search-forward | ||
| 11054 | "^\\(@[0-9]+\\$[0-9]+\\|\\$\\([a-zA-Z0-9]+\\)\\) *= *\\(.*\\(\n[ \t]+.*$\\)*\\)" | ||
| 11055 | nil t) | ||
| 11056 | (setq var (if (match-end 2) (match-string 2) (match-string 1)) | ||
| 11057 | form (match-string 3)) | ||
| 11058 | (setq form (org-trim form)) | ||
| 11059 | (when (not (equal form "")) | ||
| 11060 | (while (string-match "[ \t]*\n[ \t]*" form) | ||
| 11061 | (setq form (replace-match " " t t form))) | ||
| 11062 | (when (assoc var eql) | ||
| 11063 | (error "Double formulas for %s" var)) | ||
| 11064 | (push (cons var form) eql))) | ||
| 11065 | (setq org-pos nil) | ||
| 11066 | (set-window-configuration org-window-configuration) | ||
| 11067 | (select-window (get-buffer-window (marker-buffer pos))) | ||
| 11068 | (goto-char pos) | ||
| 11069 | (unless (org-at-table-p) | ||
| 11070 | (error "Lost table position - cannot install formulae")) | ||
| 11071 | (org-table-store-formulas eql) | ||
| 11072 | (move-marker pos nil) | ||
| 11073 | (kill-buffer "*Edit Formulas*") | ||
| 11074 | (if arg | ||
| 11075 | (org-table-recalculate 'all) | ||
| 11076 | (message "New formulas installed - press C-u C-c C-c to apply.")))) | ||
| 11077 | |||
| 11078 | (defun org-table-fedit-abort () | ||
| 11079 | "Abort editing formulas, without installing the changes." | ||
| 11080 | (interactive) | ||
| 11081 | (org-table-remove-rectangle-highlight) | ||
| 11082 | (let ((pos org-pos)) | ||
| 11083 | (set-window-configuration org-window-configuration) | ||
| 11084 | (select-window (get-buffer-window (marker-buffer pos))) | ||
| 11085 | (goto-char pos) | ||
| 11086 | (move-marker pos nil) | ||
| 11087 | (message "Formula editing aborted without installing changes"))) | ||
| 11088 | |||
| 11089 | (defun org-table-fedit-lisp-indent () | ||
| 11090 | "Pretty-print and re-indent Lisp expressions in the Formula Editor." | ||
| 11091 | (interactive) | ||
| 11092 | (let ((pos (point)) beg end ind) | ||
| 11093 | (beginning-of-line 1) | ||
| 11094 | (cond | ||
| 11095 | ((looking-at "[ \t]") | ||
| 11096 | (goto-char pos) | ||
| 11097 | (call-interactively 'lisp-indent-line)) | ||
| 11098 | ((looking-at "[$&@0-9a-zA-Z]+ *= *[^ \t\n']") (goto-char pos)) | ||
| 11099 | ((not (fboundp 'pp-buffer)) | ||
| 11100 | (error "Cannot pretty-print. Command `pp-buffer' is not available.")) | ||
| 11101 | ((looking-at "[$&@0-9a-zA-Z]+ *= *'(") | ||
| 11102 | (goto-char (- (match-end 0) 2)) | ||
| 11103 | (setq beg (point)) | ||
| 11104 | (setq ind (make-string (current-column) ?\ )) | ||
| 11105 | (condition-case nil (forward-sexp 1) | ||
| 11106 | (error | ||
| 11107 | (error "Cannot pretty-print Lisp expression: Unbalanced parenthesis"))) | ||
| 11108 | (setq end (point)) | ||
| 11109 | (save-restriction | ||
| 11110 | (narrow-to-region beg end) | ||
| 11111 | (if (eq last-command this-command) | ||
| 11112 | (progn | ||
| 11113 | (goto-char (point-min)) | ||
| 11114 | (setq this-command nil) | ||
| 11115 | (while (re-search-forward "[ \t]*\n[ \t]*" nil t) | ||
| 11116 | (replace-match " "))) | ||
| 11117 | (pp-buffer) | ||
| 11118 | (untabify (point-min) (point-max)) | ||
| 11119 | (goto-char (1+ (point-min))) | ||
| 11120 | (while (re-search-forward "^." nil t) | ||
| 11121 | (beginning-of-line 1) | ||
| 11122 | (insert ind)) | ||
| 11123 | (goto-char (point-max)) | ||
| 11124 | (backward-delete-char 1))) | ||
| 11125 | (goto-char beg)) | ||
| 11126 | (t nil)))) | ||
| 11127 | |||
| 11128 | (defvar org-show-positions nil) | ||
| 11129 | |||
| 11130 | (defun org-table-show-reference (&optional local) | ||
| 11131 | "Show the location/value of the $ expression at point." | ||
| 11132 | (interactive) | ||
| 11133 | (org-table-remove-rectangle-highlight) | ||
| 11134 | (catch 'exit | ||
| 11135 | (let ((pos (if local (point) org-pos)) | ||
| 11136 | (face2 'highlight) | ||
| 11137 | (org-inhibit-highlight-removal t) | ||
| 11138 | (win (selected-window)) | ||
| 11139 | (org-show-positions nil) | ||
| 11140 | var name e what match dest) | ||
| 11141 | (if local (org-table-get-specials)) | ||
| 11142 | (setq what (cond | ||
| 11143 | ((or (org-at-regexp-p org-table-range-regexp2) | ||
| 11144 | (org-at-regexp-p org-table-translate-regexp) | ||
| 11145 | (org-at-regexp-p org-table-range-regexp)) | ||
| 11146 | (setq match | ||
| 11147 | (save-match-data | ||
| 11148 | (org-table-convert-refs-to-rc (match-string 0)))) | ||
| 11149 | 'range) | ||
| 11150 | ((org-at-regexp-p "\\$[a-zA-Z][a-zA-Z0-9]*") 'name) | ||
| 11151 | ((org-at-regexp-p "\\$[0-9]+") 'column) | ||
| 11152 | ((not local) nil) | ||
| 11153 | (t (error "No reference at point"))) | ||
| 11154 | match (and what (or match (match-string 0)))) | ||
| 11155 | (when (and match (not (equal (match-beginning 0) (point-at-bol)))) | ||
| 11156 | (org-table-add-rectangle-overlay (match-beginning 0) (match-end 0) | ||
| 11157 | 'secondary-selection)) | ||
| 11158 | (org-add-hook 'before-change-functions | ||
| 11159 | 'org-table-remove-rectangle-highlight) | ||
| 11160 | (if (eq what 'name) (setq var (substring match 1))) | ||
| 11161 | (when (eq what 'range) | ||
| 11162 | (or (equal (string-to-char match) ?@) (setq match (concat "@" match))) | ||
| 11163 | (setq match (org-table-formula-substitute-names match))) | ||
| 11164 | (unless local | ||
| 11165 | (save-excursion | ||
| 11166 | (end-of-line 1) | ||
| 11167 | (re-search-backward "^\\S-" nil t) | ||
| 11168 | (beginning-of-line 1) | ||
| 11169 | (when (looking-at "\\(\\$[0-9a-zA-Z]+\\|@[0-9]+\\$[0-9]+\\|[a-zA-Z]+\\([0-9]+\\|&\\)\\) *=") | ||
| 11170 | (setq dest | ||
| 11171 | (save-match-data | ||
| 11172 | (org-table-convert-refs-to-rc (match-string 1)))) | ||
| 11173 | (org-table-add-rectangle-overlay | ||
| 11174 | (match-beginning 1) (match-end 1) face2)))) | ||
| 11175 | (if (and (markerp pos) (marker-buffer pos)) | ||
| 11176 | (if (get-buffer-window (marker-buffer pos)) | ||
| 11177 | (select-window (get-buffer-window (marker-buffer pos))) | ||
| 11178 | (org-switch-to-buffer-other-window (get-buffer-window | ||
| 11179 | (marker-buffer pos))))) | ||
| 11180 | (goto-char pos) | ||
| 11181 | (org-table-force-dataline) | ||
| 11182 | (when dest | ||
| 11183 | (setq name (substring dest 1)) | ||
| 11184 | (cond | ||
| 11185 | ((string-match "^\\$[a-zA-Z][a-zA-Z0-9]*" dest) | ||
| 11186 | (setq e (assoc name org-table-named-field-locations)) | ||
| 11187 | (goto-line (nth 1 e)) | ||
| 11188 | (org-table-goto-column (nth 2 e))) | ||
| 11189 | ((string-match "^@\\([0-9]+\\)\\$\\([0-9]+\\)" dest) | ||
| 11190 | (let ((l (string-to-number (match-string 1 dest))) | ||
| 11191 | (c (string-to-number (match-string 2 dest)))) | ||
| 11192 | (goto-line (aref org-table-dlines l)) | ||
| 11193 | (org-table-goto-column c))) | ||
| 11194 | (t (org-table-goto-column (string-to-number name)))) | ||
| 11195 | (move-marker pos (point)) | ||
| 11196 | (org-table-highlight-rectangle nil nil face2)) | ||
| 11197 | (cond | ||
| 11198 | ((equal dest match)) | ||
| 11199 | ((not match)) | ||
| 11200 | ((eq what 'range) | ||
| 11201 | (condition-case nil | ||
| 11202 | (save-excursion | ||
| 11203 | (org-table-get-range match nil nil 'highlight)) | ||
| 11204 | (error nil))) | ||
| 11205 | ((setq e (assoc var org-table-named-field-locations)) | ||
| 11206 | (goto-line (nth 1 e)) | ||
| 11207 | (org-table-goto-column (nth 2 e)) | ||
| 11208 | (org-table-highlight-rectangle (point) (point)) | ||
| 11209 | (message "Named field, column %d of line %d" (nth 2 e) (nth 1 e))) | ||
| 11210 | ((setq e (assoc var org-table-column-names)) | ||
| 11211 | (org-table-goto-column (string-to-number (cdr e))) | ||
| 11212 | (org-table-highlight-rectangle (point) (point)) | ||
| 11213 | (goto-char (org-table-begin)) | ||
| 11214 | (if (re-search-forward (concat "^[ \t]*| *! *.*?| *\\(" var "\\) *|") | ||
| 11215 | (org-table-end) t) | ||
| 11216 | (progn | ||
| 11217 | (goto-char (match-beginning 1)) | ||
| 11218 | (org-table-highlight-rectangle) | ||
| 11219 | (message "Named column (column %s)" (cdr e))) | ||
| 11220 | (error "Column name not found"))) | ||
| 11221 | ((eq what 'column) | ||
| 11222 | ;; column number | ||
| 11223 | (org-table-goto-column (string-to-number (substring match 1))) | ||
| 11224 | (org-table-highlight-rectangle (point) (point)) | ||
| 11225 | (message "Column %s" (substring match 1))) | ||
| 11226 | ((setq e (assoc var org-table-local-parameters)) | ||
| 11227 | (goto-char (org-table-begin)) | ||
| 11228 | (if (re-search-forward (concat "^[ \t]*| *\\$ *.*?| *\\(" var "=\\)") nil t) | ||
| 11229 | (progn | ||
| 11230 | (goto-char (match-beginning 1)) | ||
| 11231 | (org-table-highlight-rectangle) | ||
| 11232 | (message "Local parameter.")) | ||
| 11233 | (error "Parameter not found"))) | ||
| 11234 | (t | ||
| 11235 | (cond | ||
| 11236 | ((not var) (error "No reference at point")) | ||
| 11237 | ((setq e (assoc var org-table-formula-constants-local)) | ||
| 11238 | (message "Local Constant: $%s=%s in #+CONSTANTS line." | ||
| 11239 | var (cdr e))) | ||
| 11240 | ((setq e (assoc var org-table-formula-constants)) | ||
| 11241 | (message "Constant: $%s=%s in `org-table-formula-constants'." | ||
| 11242 | var (cdr e))) | ||
| 11243 | ((setq e (and (fboundp 'constants-get) (constants-get var))) | ||
| 11244 | (message "Constant: $%s=%s, from `constants.el'%s." | ||
| 11245 | var e (format " (%s units)" constants-unit-system))) | ||
| 11246 | (t (error "Undefined name $%s" var))))) | ||
| 11247 | (goto-char pos) | ||
| 11248 | (when (and org-show-positions | ||
| 11249 | (not (memq this-command '(org-table-fedit-scroll | ||
| 11250 | org-table-fedit-scroll-down)))) | ||
| 11251 | (push pos org-show-positions) | ||
| 11252 | (push org-table-current-begin-pos org-show-positions) | ||
| 11253 | (let ((min (apply 'min org-show-positions)) | ||
| 11254 | (max (apply 'max org-show-positions))) | ||
| 11255 | (goto-char min) (recenter 0) | ||
| 11256 | (goto-char max) | ||
| 11257 | (or (pos-visible-in-window-p max) (recenter -1)))) | ||
| 11258 | (select-window win)))) | ||
| 11259 | |||
| 11260 | (defun org-table-force-dataline () | ||
| 11261 | "Make sure the cursor is in a dataline in a table." | ||
| 11262 | (unless (save-excursion | ||
| 11263 | (beginning-of-line 1) | ||
| 11264 | (looking-at org-table-dataline-regexp)) | ||
| 11265 | (let* ((re org-table-dataline-regexp) | ||
| 11266 | (p1 (save-excursion (re-search-forward re nil 'move))) | ||
| 11267 | (p2 (save-excursion (re-search-backward re nil 'move)))) | ||
| 11268 | (cond ((and p1 p2) | ||
| 11269 | (goto-char (if (< (abs (- p1 (point))) (abs (- p2 (point)))) | ||
| 11270 | p1 p2))) | ||
| 11271 | ((or p1 p2) (goto-char (or p1 p2))) | ||
| 11272 | (t (error "No table dataline around here")))))) | ||
| 11273 | |||
| 11274 | (defun org-table-fedit-line-up () | ||
| 11275 | "Move cursor one line up in the window showing the table." | ||
| 11276 | (interactive) | ||
| 11277 | (org-table-fedit-move 'previous-line)) | ||
| 11278 | |||
| 11279 | (defun org-table-fedit-line-down () | ||
| 11280 | "Move cursor one line down in the window showing the table." | ||
| 11281 | (interactive) | ||
| 11282 | (org-table-fedit-move 'next-line)) | ||
| 11283 | |||
| 11284 | (defun org-table-fedit-move (command) | ||
| 11285 | "Move the cursor in the window shoinw the table. | ||
| 11286 | Use COMMAND to do the motion, repeat if necessary to end up in a data line." | ||
| 11287 | (let ((org-table-allow-automatic-line-recalculation nil) | ||
| 11288 | (pos org-pos) (win (selected-window)) p) | ||
| 11289 | (select-window (get-buffer-window (marker-buffer org-pos))) | ||
| 11290 | (setq p (point)) | ||
| 11291 | (call-interactively command) | ||
| 11292 | (while (and (org-at-table-p) | ||
| 11293 | (org-at-table-hline-p)) | ||
| 11294 | (call-interactively command)) | ||
| 11295 | (or (org-at-table-p) (goto-char p)) | ||
| 11296 | (move-marker pos (point)) | ||
| 11297 | (select-window win))) | ||
| 11298 | |||
| 11299 | (defun org-table-fedit-scroll (N) | ||
| 11300 | (interactive "p") | ||
| 11301 | (let ((other-window-scroll-buffer (marker-buffer org-pos))) | ||
| 11302 | (scroll-other-window N))) | ||
| 11303 | |||
| 11304 | (defun org-table-fedit-scroll-down (N) | ||
| 11305 | (interactive "p") | ||
| 11306 | (org-table-fedit-scroll (- N))) | ||
| 11307 | |||
| 11308 | (defvar org-table-rectangle-overlays nil) | ||
| 11309 | |||
| 11310 | (defun org-table-add-rectangle-overlay (beg end &optional face) | ||
| 11311 | "Add a new overlay." | ||
| 11312 | (let ((ov (org-make-overlay beg end))) | ||
| 11313 | (org-overlay-put ov 'face (or face 'secondary-selection)) | ||
| 11314 | (push ov org-table-rectangle-overlays))) | ||
| 11315 | |||
| 11316 | (defun org-table-highlight-rectangle (&optional beg end face) | ||
| 11317 | "Highlight rectangular region in a table." | ||
| 11318 | (setq beg (or beg (point)) end (or end (point))) | ||
| 11319 | (let ((b (min beg end)) | ||
| 11320 | (e (max beg end)) | ||
| 11321 | l1 c1 l2 c2 tmp) | ||
| 11322 | (and (boundp 'org-show-positions) | ||
| 11323 | (setq org-show-positions (cons b (cons e org-show-positions)))) | ||
| 11324 | (goto-char (min beg end)) | ||
| 11325 | (setq l1 (org-current-line) | ||
| 11326 | c1 (org-table-current-column)) | ||
| 11327 | (goto-char (max beg end)) | ||
| 11328 | (setq l2 (org-current-line) | ||
| 11329 | c2 (org-table-current-column)) | ||
| 11330 | (if (> c1 c2) (setq tmp c1 c1 c2 c2 tmp)) | ||
| 11331 | (goto-line l1) | ||
| 11332 | (beginning-of-line 1) | ||
| 11333 | (loop for line from l1 to l2 do | ||
| 11334 | (when (looking-at org-table-dataline-regexp) | ||
| 11335 | (org-table-goto-column c1) | ||
| 11336 | (skip-chars-backward "^|\n") (setq beg (point)) | ||
| 11337 | (org-table-goto-column c2) | ||
| 11338 | (skip-chars-forward "^|\n") (setq end (point)) | ||
| 11339 | (org-table-add-rectangle-overlay beg end face)) | ||
| 11340 | (beginning-of-line 2)) | ||
| 11341 | (goto-char b)) | ||
| 11342 | (add-hook 'before-change-functions 'org-table-remove-rectangle-highlight)) | ||
| 11343 | |||
| 11344 | (defun org-table-remove-rectangle-highlight (&rest ignore) | ||
| 11345 | "Remove the rectangle overlays." | ||
| 11346 | (unless org-inhibit-highlight-removal | ||
| 11347 | (remove-hook 'before-change-functions 'org-table-remove-rectangle-highlight) | ||
| 11348 | (mapc 'org-delete-overlay org-table-rectangle-overlays) | ||
| 11349 | (setq org-table-rectangle-overlays nil))) | ||
| 11350 | |||
| 11351 | (defvar org-table-coordinate-overlays nil | ||
| 11352 | "Collects the cooordinate grid overlays, so that they can be removed.") | ||
| 11353 | (make-variable-buffer-local 'org-table-coordinate-overlays) | ||
| 11354 | |||
| 11355 | (defun org-table-overlay-coordinates () | ||
| 11356 | "Add overlays to the table at point, to show row/column coordinates." | ||
| 11357 | (interactive) | ||
| 11358 | (mapc 'org-delete-overlay org-table-coordinate-overlays) | ||
| 11359 | (setq org-table-coordinate-overlays nil) | ||
| 11360 | (save-excursion | ||
| 11361 | (let ((id 0) (ih 0) hline eol s1 s2 str ic ov beg) | ||
| 11362 | (goto-char (org-table-begin)) | ||
| 11363 | (while (org-at-table-p) | ||
| 11364 | (setq eol (point-at-eol)) | ||
| 11365 | (setq ov (org-make-overlay (point-at-bol) (1+ (point-at-bol)))) | ||
| 11366 | (push ov org-table-coordinate-overlays) | ||
| 11367 | (setq hline (looking-at org-table-hline-regexp)) | ||
| 11368 | (setq str (if hline (format "I*%-2d" (setq ih (1+ ih))) | ||
| 11369 | (format "%4d" (setq id (1+ id))))) | ||
| 11370 | (org-overlay-before-string ov str 'org-special-keyword 'evaporate) | ||
| 11371 | (when hline | ||
| 11372 | (setq ic 0) | ||
| 11373 | (while (re-search-forward "[+|]\\(-+\\)" eol t) | ||
| 11374 | (setq beg (1+ (match-beginning 0)) | ||
| 11375 | ic (1+ ic) | ||
| 11376 | s1 (concat "$" (int-to-string ic)) | ||
| 11377 | s2 (org-number-to-letters ic) | ||
| 11378 | str (if (eq org-table-use-standard-references t) s2 s1)) | ||
| 11379 | (setq ov (org-make-overlay beg (+ beg (length str)))) | ||
| 11380 | (push ov org-table-coordinate-overlays) | ||
| 11381 | (org-overlay-display ov str 'org-special-keyword 'evaporate))) | ||
| 11382 | (beginning-of-line 2))))) | ||
| 11383 | |||
| 11384 | (defun org-table-toggle-coordinate-overlays () | ||
| 11385 | "Toggle the display of Row/Column numbers in tables." | ||
| 11386 | (interactive) | ||
| 11387 | (setq org-table-overlay-coordinates (not org-table-overlay-coordinates)) | ||
| 11388 | (message "Row/Column number display turned %s" | ||
| 11389 | (if org-table-overlay-coordinates "on" "off")) | ||
| 11390 | (if (and (org-at-table-p) org-table-overlay-coordinates) | ||
| 11391 | (org-table-align)) | ||
| 11392 | (unless org-table-overlay-coordinates | ||
| 11393 | (mapc 'org-delete-overlay org-table-coordinate-overlays) | ||
| 11394 | (setq org-table-coordinate-overlays nil))) | ||
| 11395 | |||
| 11396 | (defun org-table-toggle-formula-debugger () | ||
| 11397 | "Toggle the formula debugger in tables." | ||
| 11398 | (interactive) | ||
| 11399 | (setq org-table-formula-debug (not org-table-formula-debug)) | ||
| 11400 | (message "Formula debugging has been turned %s" | ||
| 11401 | (if org-table-formula-debug "on" "off"))) | ||
| 11402 | |||
| 11403 | ;;; The orgtbl minor mode | ||
| 11404 | |||
| 11405 | ;; Define a minor mode which can be used in other modes in order to | ||
| 11406 | ;; integrate the org-mode table editor. | ||
| 11407 | |||
| 11408 | ;; This is really a hack, because the org-mode table editor uses several | ||
| 11409 | ;; keys which normally belong to the major mode, for example the TAB and | ||
| 11410 | ;; RET keys. Here is how it works: The minor mode defines all the keys | ||
| 11411 | ;; necessary to operate the table editor, but wraps the commands into a | ||
| 11412 | ;; function which tests if the cursor is currently inside a table. If that | ||
| 11413 | ;; is the case, the table editor command is executed. However, when any of | ||
| 11414 | ;; those keys is used outside a table, the function uses `key-binding' to | ||
| 11415 | ;; look up if the key has an associated command in another currently active | ||
| 11416 | ;; keymap (minor modes, major mode, global), and executes that command. | ||
| 11417 | ;; There might be problems if any of the keys used by the table editor is | ||
| 11418 | ;; otherwise used as a prefix key. | ||
| 11419 | |||
| 11420 | ;; Another challenge is that the key binding for TAB can be tab or \C-i, | ||
| 11421 | ;; likewise the binding for RET can be return or \C-m. Orgtbl-mode | ||
| 11422 | ;; addresses this by checking explicitly for both bindings. | ||
| 11423 | |||
| 11424 | ;; The optimized version (see variable `orgtbl-optimized') takes over | ||
| 11425 | ;; all keys which are bound to `self-insert-command' in the *global map*. | ||
| 11426 | ;; Some modes bind other commands to simple characters, for example | ||
| 11427 | ;; AUCTeX binds the double quote to `Tex-insert-quote'. With orgtbl-mode | ||
| 11428 | ;; active, this binding is ignored inside tables and replaced with a | ||
| 11429 | ;; modified self-insert. | ||
| 11430 | |||
| 11431 | (defvar orgtbl-mode nil | ||
| 11432 | "Variable controlling `orgtbl-mode', a minor mode enabling the `org-mode' | ||
| 11433 | table editor in arbitrary modes.") | ||
| 11434 | (make-variable-buffer-local 'orgtbl-mode) | ||
| 11435 | |||
| 11436 | (defvar orgtbl-mode-map (make-keymap) | ||
| 11437 | "Keymap for `orgtbl-mode'.") | ||
| 11438 | |||
| 11439 | ;;;###autoload | ||
| 11440 | (defun turn-on-orgtbl () | ||
| 11441 | "Unconditionally turn on `orgtbl-mode'." | ||
| 11442 | (orgtbl-mode 1)) | ||
| 11443 | |||
| 11444 | (defvar org-old-auto-fill-inhibit-regexp nil | ||
| 11445 | "Local variable used by `orgtbl-mode'") | ||
| 11446 | |||
| 11447 | (defconst orgtbl-line-start-regexp "[ \t]*\\(|\\|#\\+\\(TBLFM\\|ORGTBL\\):\\)" | ||
| 11448 | "Matches a line belonging to an orgtbl.") | ||
| 11449 | |||
| 11450 | (defconst orgtbl-extra-font-lock-keywords | ||
| 11451 | (list (list (concat "^" orgtbl-line-start-regexp ".*") | ||
| 11452 | 0 (quote 'org-table) 'prepend)) | ||
| 11453 | "Extra font-lock-keywords to be added when orgtbl-mode is active.") | ||
| 11454 | |||
| 11455 | ;;;###autoload | ||
| 11456 | (defun orgtbl-mode (&optional arg) | ||
| 11457 | "The `org-mode' table editor as a minor mode for use in other modes." | ||
| 11458 | (interactive) | ||
| 11459 | (if (org-mode-p) | ||
| 11460 | ;; Exit without error, in case some hook functions calls this | ||
| 11461 | ;; by accident in org-mode. | ||
| 11462 | (message "Orgtbl-mode is not useful in org-mode, command ignored") | ||
| 11463 | (setq orgtbl-mode | ||
| 11464 | (if arg (> (prefix-numeric-value arg) 0) (not orgtbl-mode))) | ||
| 11465 | (if orgtbl-mode | ||
| 11466 | (progn | ||
| 11467 | (and (orgtbl-setup) (defun orgtbl-setup () nil)) | ||
| 11468 | ;; Make sure we are first in minor-mode-map-alist | ||
| 11469 | (let ((c (assq 'orgtbl-mode minor-mode-map-alist))) | ||
| 11470 | (and c (setq minor-mode-map-alist | ||
| 11471 | (cons c (delq c minor-mode-map-alist))))) | ||
| 11472 | (org-set-local (quote org-table-may-need-update) t) | ||
| 11473 | (org-add-hook 'before-change-functions 'org-before-change-function | ||
| 11474 | nil 'local) | ||
| 11475 | (org-set-local 'org-old-auto-fill-inhibit-regexp | ||
| 11476 | auto-fill-inhibit-regexp) | ||
| 11477 | (org-set-local 'auto-fill-inhibit-regexp | ||
| 11478 | (if auto-fill-inhibit-regexp | ||
| 11479 | (concat orgtbl-line-start-regexp "\\|" | ||
| 11480 | auto-fill-inhibit-regexp) | ||
| 11481 | orgtbl-line-start-regexp)) | ||
| 11482 | (org-add-to-invisibility-spec '(org-cwidth)) | ||
| 11483 | (when (fboundp 'font-lock-add-keywords) | ||
| 11484 | (font-lock-add-keywords nil orgtbl-extra-font-lock-keywords) | ||
| 11485 | (org-restart-font-lock)) | ||
| 11486 | (easy-menu-add orgtbl-mode-menu) | ||
| 11487 | (run-hooks 'orgtbl-mode-hook)) | ||
| 11488 | (setq auto-fill-inhibit-regexp org-old-auto-fill-inhibit-regexp) | ||
| 11489 | (org-cleanup-narrow-column-properties) | ||
| 11490 | (org-remove-from-invisibility-spec '(org-cwidth)) | ||
| 11491 | (remove-hook 'before-change-functions 'org-before-change-function t) | ||
| 11492 | (when (fboundp 'font-lock-remove-keywords) | ||
| 11493 | (font-lock-remove-keywords nil orgtbl-extra-font-lock-keywords) | ||
| 11494 | (org-restart-font-lock)) | ||
| 11495 | (easy-menu-remove orgtbl-mode-menu) | ||
| 11496 | (force-mode-line-update 'all)))) | ||
| 11497 | |||
| 11498 | (defun org-cleanup-narrow-column-properties () | ||
| 11499 | "Remove all properties related to narrow-column invisibility." | ||
| 11500 | (let ((s 1)) | ||
| 11501 | (while (setq s (text-property-any s (point-max) | ||
| 11502 | 'display org-narrow-column-arrow)) | ||
| 11503 | (remove-text-properties s (1+ s) '(display t))) | ||
| 11504 | (setq s 1) | ||
| 11505 | (while (setq s (text-property-any s (point-max) 'org-cwidth 1)) | ||
| 11506 | (remove-text-properties s (1+ s) '(org-cwidth t))) | ||
| 11507 | (setq s 1) | ||
| 11508 | (while (setq s (text-property-any s (point-max) 'invisible 'org-cwidth)) | ||
| 11509 | (remove-text-properties s (1+ s) '(invisible t))))) | ||
| 11510 | |||
| 11511 | ;; Install it as a minor mode. | ||
| 11512 | (put 'orgtbl-mode :included t) | ||
| 11513 | (put 'orgtbl-mode :menu-tag "Org Table Mode") | ||
| 11514 | (add-minor-mode 'orgtbl-mode " OrgTbl" orgtbl-mode-map) | ||
| 11515 | |||
| 11516 | (defun orgtbl-make-binding (fun n &rest keys) | ||
| 11517 | "Create a function for binding in the table minor mode. | ||
| 11518 | FUN is the command to call inside a table. N is used to create a unique | ||
| 11519 | command name. KEYS are keys that should be checked in for a command | ||
| 11520 | to execute outside of tables." | ||
| 11521 | (eval | ||
| 11522 | (list 'defun | ||
| 11523 | (intern (concat "orgtbl-hijacker-command-" (int-to-string n))) | ||
| 11524 | '(arg) | ||
| 11525 | (concat "In tables, run `" (symbol-name fun) "'.\n" | ||
| 11526 | "Outside of tables, run the binding of `" | ||
| 11527 | (mapconcat (lambda (x) (format "%s" x)) keys "' or `") | ||
| 11528 | "'.") | ||
| 11529 | '(interactive "p") | ||
| 11530 | (list 'if | ||
| 11531 | '(org-at-table-p) | ||
| 11532 | (list 'call-interactively (list 'quote fun)) | ||
| 11533 | (list 'let '(orgtbl-mode) | ||
| 11534 | (list 'call-interactively | ||
| 11535 | (append '(or) | ||
| 11536 | (mapcar (lambda (k) | ||
| 11537 | (list 'key-binding k)) | ||
| 11538 | keys) | ||
| 11539 | '('orgtbl-error)))))))) | ||
| 11540 | |||
| 11541 | (defun orgtbl-error () | ||
| 11542 | "Error when there is no default binding for a table key." | ||
| 11543 | (interactive) | ||
| 11544 | (error "This key has no function outside tables")) | ||
| 11545 | |||
| 11546 | (defun orgtbl-setup () | ||
| 11547 | "Setup orgtbl keymaps." | ||
| 11548 | (let ((nfunc 0) | ||
| 11549 | (bindings | ||
| 11550 | (list | ||
| 11551 | '([(meta shift left)] org-table-delete-column) | ||
| 11552 | '([(meta left)] org-table-move-column-left) | ||
| 11553 | '([(meta right)] org-table-move-column-right) | ||
| 11554 | '([(meta shift right)] org-table-insert-column) | ||
| 11555 | '([(meta shift up)] org-table-kill-row) | ||
| 11556 | '([(meta shift down)] org-table-insert-row) | ||
| 11557 | '([(meta up)] org-table-move-row-up) | ||
| 11558 | '([(meta down)] org-table-move-row-down) | ||
| 11559 | '("\C-c\C-w" org-table-cut-region) | ||
| 11560 | '("\C-c\M-w" org-table-copy-region) | ||
| 11561 | '("\C-c\C-y" org-table-paste-rectangle) | ||
| 11562 | '("\C-c-" org-table-insert-hline) | ||
| 11563 | '("\C-c}" org-table-toggle-coordinate-overlays) | ||
| 11564 | '("\C-c{" org-table-toggle-formula-debugger) | ||
| 11565 | '("\C-m" org-table-next-row) | ||
| 11566 | '([(shift return)] org-table-copy-down) | ||
| 11567 | '("\C-c\C-q" org-table-wrap-region) | ||
| 11568 | '("\C-c?" org-table-field-info) | ||
| 11569 | '("\C-c " org-table-blank-field) | ||
| 11570 | '("\C-c+" org-table-sum) | ||
| 11571 | '("\C-c=" org-table-eval-formula) | ||
| 11572 | '("\C-c'" org-table-edit-formulas) | ||
| 11573 | '("\C-c`" org-table-edit-field) | ||
| 11574 | '("\C-c*" org-table-recalculate) | ||
| 11575 | '("\C-c|" org-table-create-or-convert-from-region) | ||
| 11576 | '("\C-c^" org-table-sort-lines) | ||
| 11577 | '([(control ?#)] org-table-rotate-recalc-marks))) | ||
| 11578 | elt key fun cmd) | ||
| 11579 | (while (setq elt (pop bindings)) | ||
| 11580 | (setq nfunc (1+ nfunc)) | ||
| 11581 | (setq key (org-key (car elt)) | ||
| 11582 | fun (nth 1 elt) | ||
| 11583 | cmd (orgtbl-make-binding fun nfunc key)) | ||
| 11584 | (org-defkey orgtbl-mode-map key cmd)) | ||
| 11585 | |||
| 11586 | ;; Special treatment needed for TAB and RET | ||
| 11587 | (org-defkey orgtbl-mode-map [(return)] | ||
| 11588 | (orgtbl-make-binding 'orgtbl-ret 100 [(return)] "\C-m")) | ||
| 11589 | (org-defkey orgtbl-mode-map "\C-m" | ||
| 11590 | (orgtbl-make-binding 'orgtbl-ret 101 "\C-m" [(return)])) | ||
| 11591 | |||
| 11592 | (org-defkey orgtbl-mode-map [(tab)] | ||
| 11593 | (orgtbl-make-binding 'orgtbl-tab 102 [(tab)] "\C-i")) | ||
| 11594 | (org-defkey orgtbl-mode-map "\C-i" | ||
| 11595 | (orgtbl-make-binding 'orgtbl-tab 103 "\C-i" [(tab)])) | ||
| 11596 | |||
| 11597 | (org-defkey orgtbl-mode-map [(shift tab)] | ||
| 11598 | (orgtbl-make-binding 'org-table-previous-field 104 | ||
| 11599 | [(shift tab)] [(tab)] "\C-i")) | ||
| 11600 | |||
| 11601 | (org-defkey orgtbl-mode-map "\M-\C-m" | ||
| 11602 | (orgtbl-make-binding 'org-table-wrap-region 105 | ||
| 11603 | "\M-\C-m" [(meta return)])) | ||
| 11604 | (org-defkey orgtbl-mode-map [(meta return)] | ||
| 11605 | (orgtbl-make-binding 'org-table-wrap-region 106 | ||
| 11606 | [(meta return)] "\M-\C-m")) | ||
| 11607 | |||
| 11608 | (org-defkey orgtbl-mode-map "\C-c\C-c" 'orgtbl-ctrl-c-ctrl-c) | ||
| 11609 | (when orgtbl-optimized | ||
| 11610 | ;; If the user wants maximum table support, we need to hijack | ||
| 11611 | ;; some standard editing functions | ||
| 11612 | (org-remap orgtbl-mode-map | ||
| 11613 | 'self-insert-command 'orgtbl-self-insert-command | ||
| 11614 | 'delete-char 'org-delete-char | ||
| 11615 | 'delete-backward-char 'org-delete-backward-char) | ||
| 11616 | (org-defkey orgtbl-mode-map "|" 'org-force-self-insert)) | ||
| 11617 | (easy-menu-define orgtbl-mode-menu orgtbl-mode-map "OrgTbl menu" | ||
| 11618 | '("OrgTbl" | ||
| 11619 | ["Align" org-ctrl-c-ctrl-c :active (org-at-table-p) :keys "C-c C-c"] | ||
| 11620 | ["Next Field" org-cycle :active (org-at-table-p) :keys "TAB"] | ||
| 11621 | ["Previous Field" org-shifttab :active (org-at-table-p) :keys "S-TAB"] | ||
| 11622 | ["Next Row" org-return :active (org-at-table-p) :keys "RET"] | ||
| 11623 | "--" | ||
| 11624 | ["Blank Field" org-table-blank-field :active (org-at-table-p) :keys "C-c SPC"] | ||
| 11625 | ["Edit Field" org-table-edit-field :active (org-at-table-p) :keys "C-c ` "] | ||
| 11626 | ["Copy Field from Above" | ||
| 11627 | org-table-copy-down :active (org-at-table-p) :keys "S-RET"] | ||
| 11628 | "--" | ||
| 11629 | ("Column" | ||
| 11630 | ["Move Column Left" org-metaleft :active (org-at-table-p) :keys "M-<left>"] | ||
| 11631 | ["Move Column Right" org-metaright :active (org-at-table-p) :keys "M-<right>"] | ||
| 11632 | ["Delete Column" org-shiftmetaleft :active (org-at-table-p) :keys "M-S-<left>"] | ||
| 11633 | ["Insert Column" org-shiftmetaright :active (org-at-table-p) :keys "M-S-<right>"]) | ||
| 11634 | ("Row" | ||
| 11635 | ["Move Row Up" org-metaup :active (org-at-table-p) :keys "M-<up>"] | ||
| 11636 | ["Move Row Down" org-metadown :active (org-at-table-p) :keys "M-<down>"] | ||
| 11637 | ["Delete Row" org-shiftmetaup :active (org-at-table-p) :keys "M-S-<up>"] | ||
| 11638 | ["Insert Row" org-shiftmetadown :active (org-at-table-p) :keys "M-S-<down>"] | ||
| 11639 | ["Sort lines in region" org-table-sort-lines :active (org-at-table-p) :keys "C-c ^"] | ||
| 11640 | "--" | ||
| 11641 | ["Insert Hline" org-table-insert-hline :active (org-at-table-p) :keys "C-c -"]) | ||
| 11642 | ("Rectangle" | ||
| 11643 | ["Copy Rectangle" org-copy-special :active (org-at-table-p)] | ||
| 11644 | ["Cut Rectangle" org-cut-special :active (org-at-table-p)] | ||
| 11645 | ["Paste Rectangle" org-paste-special :active (org-at-table-p)] | ||
| 11646 | ["Fill Rectangle" org-table-wrap-region :active (org-at-table-p)]) | ||
| 11647 | "--" | ||
| 11648 | ("Radio tables" | ||
| 11649 | ["Insert table template" orgtbl-insert-radio-table | ||
| 11650 | (assq major-mode orgtbl-radio-table-templates)] | ||
| 11651 | ["Comment/uncomment table" orgtbl-toggle-comment t]) | ||
| 11652 | "--" | ||
| 11653 | ["Set Column Formula" org-table-eval-formula :active (org-at-table-p) :keys "C-c ="] | ||
| 11654 | ["Set Field Formula" (org-table-eval-formula '(4)) :active (org-at-table-p) :keys "C-u C-c ="] | ||
| 11655 | ["Edit Formulas" org-table-edit-formulas :active (org-at-table-p) :keys "C-c '"] | ||
| 11656 | ["Recalculate line" org-table-recalculate :active (org-at-table-p) :keys "C-c *"] | ||
| 11657 | ["Recalculate all" (org-table-recalculate '(4)) :active (org-at-table-p) :keys "C-u C-c *"] | ||
| 11658 | ["Iterate all" (org-table-recalculate '(16)) :active (org-at-table-p) :keys "C-u C-u C-c *"] | ||
| 11659 | ["Toggle Recalculate Mark" org-table-rotate-recalc-marks :active (org-at-table-p) :keys "C-c #"] | ||
| 11660 | ["Sum Column/Rectangle" org-table-sum | ||
| 11661 | :active (or (org-at-table-p) (org-region-active-p)) :keys "C-c +"] | ||
| 11662 | ["Which Column?" org-table-current-column :active (org-at-table-p) :keys "C-c ?"] | ||
| 11663 | ["Debug Formulas" | ||
| 11664 | org-table-toggle-formula-debugger :active (org-at-table-p) | ||
| 11665 | :keys "C-c {" | ||
| 11666 | :style toggle :selected org-table-formula-debug] | ||
| 11667 | ["Show Col/Row Numbers" | ||
| 11668 | org-table-toggle-coordinate-overlays :active (org-at-table-p) | ||
| 11669 | :keys "C-c }" | ||
| 11670 | :style toggle :selected org-table-overlay-coordinates] | ||
| 11671 | )) | ||
| 11672 | t)) | ||
| 11673 | |||
| 11674 | (defun orgtbl-ctrl-c-ctrl-c (arg) | ||
| 11675 | "If the cursor is inside a table, realign the table. | ||
| 11676 | It it is a table to be sent away to a receiver, do it. | ||
| 11677 | With prefix arg, also recompute table." | ||
| 11678 | (interactive "P") | ||
| 11679 | (let ((pos (point)) action) | ||
| 11680 | (save-excursion | ||
| 11681 | (beginning-of-line 1) | ||
| 11682 | (setq action (cond ((looking-at "#\\+ORGTBL:.*\n[ \t]*|") (match-end 0)) | ||
| 11683 | ((looking-at "[ \t]*|") pos) | ||
| 11684 | ((looking-at "#\\+TBLFM:") 'recalc)))) | ||
| 11685 | (cond | ||
| 11686 | ((integerp action) | ||
| 11687 | (goto-char action) | ||
| 11688 | (org-table-maybe-eval-formula) | ||
| 11689 | (if arg | ||
| 11690 | (call-interactively 'org-table-recalculate) | ||
| 11691 | (org-table-maybe-recalculate-line)) | ||
| 11692 | (call-interactively 'org-table-align) | ||
| 11693 | (orgtbl-send-table 'maybe)) | ||
| 11694 | ((eq action 'recalc) | ||
| 11695 | (save-excursion | ||
| 11696 | (beginning-of-line 1) | ||
| 11697 | (skip-chars-backward " \r\n\t") | ||
| 11698 | (if (org-at-table-p) | ||
| 11699 | (org-call-with-arg 'org-table-recalculate t)))) | ||
| 11700 | (t (let (orgtbl-mode) | ||
| 11701 | (call-interactively (key-binding "\C-c\C-c"))))))) | ||
| 11702 | |||
| 11703 | (defun orgtbl-tab (arg) | ||
| 11704 | "Justification and field motion for `orgtbl-mode'." | ||
| 11705 | (interactive "P") | ||
| 11706 | (if arg (org-table-edit-field t) | ||
| 11707 | (org-table-justify-field-maybe) | ||
| 11708 | (org-table-next-field))) | ||
| 11709 | |||
| 11710 | (defun orgtbl-ret () | ||
| 11711 | "Justification and field motion for `orgtbl-mode'." | ||
| 11712 | (interactive) | ||
| 11713 | (org-table-justify-field-maybe) | ||
| 11714 | (org-table-next-row)) | ||
| 11715 | |||
| 11716 | (defun orgtbl-self-insert-command (N) | ||
| 11717 | "Like `self-insert-command', use overwrite-mode for whitespace in tables. | ||
| 11718 | If the cursor is in a table looking at whitespace, the whitespace is | ||
| 11719 | overwritten, and the table is not marked as requiring realignment." | ||
| 11720 | (interactive "p") | ||
| 11721 | (if (and (org-at-table-p) | ||
| 11722 | (or | ||
| 11723 | (and org-table-auto-blank-field | ||
| 11724 | (member last-command | ||
| 11725 | '(orgtbl-hijacker-command-100 | ||
| 11726 | orgtbl-hijacker-command-101 | ||
| 11727 | orgtbl-hijacker-command-102 | ||
| 11728 | orgtbl-hijacker-command-103 | ||
| 11729 | orgtbl-hijacker-command-104 | ||
| 11730 | orgtbl-hijacker-command-105)) | ||
| 11731 | (org-table-blank-field)) | ||
| 11732 | t) | ||
| 11733 | (eq N 1) | ||
| 11734 | (looking-at "[^|\n]* +|")) | ||
| 11735 | (let (org-table-may-need-update) | ||
| 11736 | (goto-char (1- (match-end 0))) | ||
| 11737 | (delete-backward-char 1) | ||
| 11738 | (goto-char (match-beginning 0)) | ||
| 11739 | (self-insert-command N)) | ||
| 11740 | (setq org-table-may-need-update t) | ||
| 11741 | (let (orgtbl-mode) | ||
| 11742 | (call-interactively (key-binding (vector last-input-event)))))) | ||
| 11743 | |||
| 11744 | (defun org-force-self-insert (N) | ||
| 11745 | "Needed to enforce self-insert under remapping." | ||
| 11746 | (interactive "p") | ||
| 11747 | (self-insert-command N)) | ||
| 11748 | |||
| 11749 | (defvar orgtbl-exp-regexp "^\\([-+]?[0-9][0-9.]*\\)[eE]\\([-+]?[0-9]+\\)$" | ||
| 11750 | "Regula expression matching exponentials as produced by calc.") | ||
| 11751 | |||
| 11752 | (defvar org-table-clean-did-remove-column nil) | ||
| 11753 | |||
| 11754 | (defun orgtbl-export (table target) | ||
| 11755 | (let ((func (intern (concat "orgtbl-to-" (symbol-name target)))) | ||
| 11756 | (lines (org-split-string table "[ \t]*\n[ \t]*")) | ||
| 11757 | org-table-last-alignment org-table-last-column-widths | ||
| 11758 | maxcol column) | ||
| 11759 | (if (not (fboundp func)) | ||
| 11760 | (error "Cannot export orgtbl table to %s" target)) | ||
| 11761 | (setq lines (org-table-clean-before-export lines)) | ||
| 11762 | (setq table | ||
| 11763 | (mapcar | ||
| 11764 | (lambda (x) | ||
| 11765 | (if (string-match org-table-hline-regexp x) | ||
| 11766 | 'hline | ||
| 11767 | (org-split-string (org-trim x) "\\s-*|\\s-*"))) | ||
| 11768 | lines)) | ||
| 11769 | (setq maxcol (apply 'max (mapcar (lambda (x) (if (listp x) (length x) 0)) | ||
| 11770 | table))) | ||
| 11771 | (loop for i from (1- maxcol) downto 0 do | ||
| 11772 | (setq column (mapcar (lambda (x) (if (listp x) (nth i x) nil)) table)) | ||
| 11773 | (setq column (delq nil column)) | ||
| 11774 | (push (apply 'max (mapcar 'string-width column)) org-table-last-column-widths) | ||
| 11775 | (push (> (/ (apply '+ (mapcar (lambda (x) (if (string-match org-table-number-regexp x) 1 0)) column)) maxcol) org-table-number-fraction) org-table-last-alignment)) | ||
| 11776 | (funcall func table nil))) | ||
| 11777 | |||
| 11778 | (defun orgtbl-send-table (&optional maybe) | ||
| 11779 | "Send a tranformed version of this table to the receiver position. | ||
| 11780 | With argument MAYBE, fail quietly if no transformation is defined for | ||
| 11781 | this table." | ||
| 11782 | (interactive) | ||
| 11783 | (catch 'exit | ||
| 11784 | (unless (org-at-table-p) (error "Not at a table")) | ||
| 11785 | ;; when non-interactive, we assume align has just happened. | ||
| 11786 | (when (interactive-p) (org-table-align)) | ||
| 11787 | (save-excursion | ||
| 11788 | (goto-char (org-table-begin)) | ||
| 11789 | (beginning-of-line 0) | ||
| 11790 | (unless (looking-at "#\\+ORGTBL: *SEND +\\([a-zA-Z0-9_]+\\) +\\([^ \t\r\n]+\\)\\( +.*\\)?") | ||
| 11791 | (if maybe | ||
| 11792 | (throw 'exit nil) | ||
| 11793 | (error "Don't know how to transform this table.")))) | ||
| 11794 | (let* ((name (match-string 1)) | ||
| 11795 | beg | ||
| 11796 | (transform (intern (match-string 2))) | ||
| 11797 | (params (if (match-end 3) (read (concat "(" (match-string 3) ")")))) | ||
| 11798 | (skip (plist-get params :skip)) | ||
| 11799 | (skipcols (plist-get params :skipcols)) | ||
| 11800 | (txt (buffer-substring-no-properties | ||
| 11801 | (org-table-begin) (org-table-end))) | ||
| 11802 | (lines (nthcdr (or skip 0) (org-split-string txt "[ \t]*\n[ \t]*"))) | ||
| 11803 | (lines (org-table-clean-before-export lines)) | ||
| 11804 | (i0 (if org-table-clean-did-remove-column 2 1)) | ||
| 11805 | (table (mapcar | ||
| 11806 | (lambda (x) | ||
| 11807 | (if (string-match org-table-hline-regexp x) | ||
| 11808 | 'hline | ||
| 11809 | (org-remove-by-index | ||
| 11810 | (org-split-string (org-trim x) "\\s-*|\\s-*") | ||
| 11811 | skipcols i0))) | ||
| 11812 | lines)) | ||
| 11813 | (fun (if (= i0 2) 'cdr 'identity)) | ||
| 11814 | (org-table-last-alignment | ||
| 11815 | (org-remove-by-index (funcall fun org-table-last-alignment) | ||
| 11816 | skipcols i0)) | ||
| 11817 | (org-table-last-column-widths | ||
| 11818 | (org-remove-by-index (funcall fun org-table-last-column-widths) | ||
| 11819 | skipcols i0))) | ||
| 11820 | |||
| 11821 | (unless (fboundp transform) | ||
| 11822 | (error "No such transformation function %s" transform)) | ||
| 11823 | (setq txt (funcall transform table params)) | ||
| 11824 | ;; Find the insertion place | ||
| 11825 | (save-excursion | ||
| 11826 | (goto-char (point-min)) | ||
| 11827 | (unless (re-search-forward | ||
| 11828 | (concat "BEGIN RECEIVE ORGTBL +" name "\\([ \t]\\|$\\)") nil t) | ||
| 11829 | (error "Don't know where to insert translated table")) | ||
| 11830 | (goto-char (match-beginning 0)) | ||
| 11831 | (beginning-of-line 2) | ||
| 11832 | (setq beg (point)) | ||
| 11833 | (unless (re-search-forward (concat "END RECEIVE ORGTBL +" name) nil t) | ||
| 11834 | (error "Cannot find end of insertion region")) | ||
| 11835 | (beginning-of-line 1) | ||
| 11836 | (delete-region beg (point)) | ||
| 11837 | (goto-char beg) | ||
| 11838 | (insert txt "\n")) | ||
| 11839 | (message "Table converted and installed at receiver location")))) | ||
| 11840 | |||
| 11841 | (defun org-remove-by-index (list indices &optional i0) | ||
| 11842 | "Remove the elements in LIST with indices in INDICES. | ||
| 11843 | First element has index 0, or I0 if given." | ||
| 11844 | (if (not indices) | ||
| 11845 | list | ||
| 11846 | (if (integerp indices) (setq indices (list indices))) | ||
| 11847 | (setq i0 (1- (or i0 0))) | ||
| 11848 | (delq :rm (mapcar (lambda (x) | ||
| 11849 | (setq i0 (1+ i0)) | ||
| 11850 | (if (memq i0 indices) :rm x)) | ||
| 11851 | list)))) | ||
| 11852 | |||
| 11853 | (defun orgtbl-toggle-comment () | ||
| 11854 | "Comment or uncomment the orgtbl at point." | ||
| 11855 | (interactive) | ||
| 11856 | (let* ((re1 (concat "^" (regexp-quote comment-start) orgtbl-line-start-regexp)) | ||
| 11857 | (re2 (concat "^" orgtbl-line-start-regexp)) | ||
| 11858 | (commented (save-excursion (beginning-of-line 1) | ||
| 11859 | (cond ((looking-at re1) t) | ||
| 11860 | ((looking-at re2) nil) | ||
| 11861 | (t (error "Not at an org table"))))) | ||
| 11862 | (re (if commented re1 re2)) | ||
| 11863 | beg end) | ||
| 11864 | (save-excursion | ||
| 11865 | (beginning-of-line 1) | ||
| 11866 | (while (looking-at re) (beginning-of-line 0)) | ||
| 11867 | (beginning-of-line 2) | ||
| 11868 | (setq beg (point)) | ||
| 11869 | (while (looking-at re) (beginning-of-line 2)) | ||
| 11870 | (setq end (point))) | ||
| 11871 | (comment-region beg end (if commented '(4) nil)))) | ||
| 11872 | |||
| 11873 | (defun orgtbl-insert-radio-table () | ||
| 11874 | "Insert a radio table template appropriate for this major mode." | ||
| 11875 | (interactive) | ||
| 11876 | (let* ((e (assq major-mode orgtbl-radio-table-templates)) | ||
| 11877 | (txt (nth 1 e)) | ||
| 11878 | name pos) | ||
| 11879 | (unless e (error "No radio table setup defined for %s" major-mode)) | ||
| 11880 | (setq name (read-string "Table name: ")) | ||
| 11881 | (while (string-match "%n" txt) | ||
| 11882 | (setq txt (replace-match name t t txt))) | ||
| 11883 | (or (bolp) (insert "\n")) | ||
| 11884 | (setq pos (point)) | ||
| 11885 | (insert txt) | ||
| 11886 | (goto-char pos))) | ||
| 11887 | |||
| 11888 | (defun org-get-param (params header i sym &optional hsym) | ||
| 11889 | "Get parameter value for symbol SYM. | ||
| 11890 | If this is a header line, actually get the value for the symbol with an | ||
| 11891 | additional \"h\" inserted after the colon. | ||
| 11892 | If the value is a protperty list, get the element for the current column. | ||
| 11893 | Assumes variables VAL, PARAMS, HEAD and I to be scoped into the function." | ||
| 11894 | (let ((val (plist-get params sym))) | ||
| 11895 | (and hsym header (setq val (or (plist-get params hsym) val))) | ||
| 11896 | (if (consp val) (plist-get val i) val))) | ||
| 11897 | |||
| 11898 | (defun orgtbl-to-generic (table params) | ||
| 11899 | "Convert the orgtbl-mode TABLE to some other format. | ||
| 11900 | This generic routine can be used for many standard cases. | ||
| 11901 | TABLE is a list, each entry either the symbol `hline' for a horizontal | ||
| 11902 | separator line, or a list of fields for that line. | ||
| 11903 | PARAMS is a property list of parameters that can influence the conversion. | ||
| 11904 | For the generic converter, some parameters are obligatory: You need to | ||
| 11905 | specify either :lfmt, or all of (:lstart :lend :sep). If you do not use | ||
| 11906 | :splice, you must have :tstart and :tend. | ||
| 11907 | |||
| 11908 | Valid parameters are | ||
| 11909 | |||
| 11910 | :tstart String to start the table. Ignored when :splice is t. | ||
| 11911 | :tend String to end the table. Ignored when :splice is t. | ||
| 11912 | |||
| 11913 | :splice When set to t, return only table body lines, don't wrap | ||
| 11914 | them into :tstart and :tend. Default is nil. | ||
| 11915 | |||
| 11916 | :hline String to be inserted on horizontal separation lines. | ||
| 11917 | May be nil to ignore hlines. | ||
| 11918 | |||
| 11919 | :lstart String to start a new table line. | ||
| 11920 | :lend String to end a table line | ||
| 11921 | :sep Separator between two fields | ||
| 11922 | :lfmt Format for entire line, with enough %s to capture all fields. | ||
| 11923 | If this is present, :lstart, :lend, and :sep are ignored. | ||
| 11924 | :fmt A format to be used to wrap the field, should contain | ||
| 11925 | %s for the original field value. For example, to wrap | ||
| 11926 | everything in dollars, you could use :fmt \"$%s$\". | ||
| 11927 | This may also be a property list with column numbers and | ||
| 11928 | formats. For example :fmt (2 \"$%s$\" 4 \"%s%%\") | ||
| 11929 | |||
| 11930 | :hlstart :hlend :hlsep :hlfmt :hfmt | ||
| 11931 | Same as above, specific for the header lines in the table. | ||
| 11932 | All lines before the first hline are treated as header. | ||
| 11933 | If any of these is not present, the data line value is used. | ||
| 11934 | |||
| 11935 | :efmt Use this format to print numbers with exponentials. | ||
| 11936 | The format should have %s twice for inserting mantissa | ||
| 11937 | and exponent, for example \"%s\\\\times10^{%s}\". This | ||
| 11938 | may also be a property list with column numbers and | ||
| 11939 | formats. :fmt will still be applied after :efmt. | ||
| 11940 | |||
| 11941 | In addition to this, the parameters :skip and :skipcols are always handled | ||
| 11942 | directly by `orgtbl-send-table'. See manual." | ||
| 11943 | (interactive) | ||
| 11944 | (let* ((p params) | ||
| 11945 | (splicep (plist-get p :splice)) | ||
| 11946 | (hline (plist-get p :hline)) | ||
| 11947 | rtn line i fm efm lfmt h) | ||
| 11948 | |||
| 11949 | ;; Do we have a header? | ||
| 11950 | (if (and (not splicep) (listp (car table)) (memq 'hline table)) | ||
| 11951 | (setq h t)) | ||
| 11952 | |||
| 11953 | ;; Put header | ||
| 11954 | (unless splicep | ||
| 11955 | (push (or (plist-get p :tstart) "ERROR: no :tstart") rtn)) | ||
| 11956 | |||
| 11957 | ;; Now loop over all lines | ||
| 11958 | (while (setq line (pop table)) | ||
| 11959 | (if (eq line 'hline) | ||
| 11960 | ;; A horizontal separator line | ||
| 11961 | (progn (if hline (push hline rtn)) | ||
| 11962 | (setq h nil)) ; no longer in header | ||
| 11963 | ;; A normal line. Convert the fields, push line onto the result list | ||
| 11964 | (setq i 0) | ||
| 11965 | (setq line | ||
| 11966 | (mapcar | ||
| 11967 | (lambda (f) | ||
| 11968 | (setq i (1+ i) | ||
| 11969 | fm (org-get-param p h i :fmt :hfmt) | ||
| 11970 | efm (org-get-param p h i :efmt)) | ||
| 11971 | (if (and efm (string-match orgtbl-exp-regexp f)) | ||
| 11972 | (setq f (format | ||
| 11973 | efm (match-string 1 f) (match-string 2 f)))) | ||
| 11974 | (if fm (setq f (format fm f))) | ||
| 11975 | f) | ||
| 11976 | line)) | ||
| 11977 | (if (setq lfmt (org-get-param p h i :lfmt :hlfmt)) | ||
| 11978 | (push (apply 'format lfmt line) rtn) | ||
| 11979 | (push (concat | ||
| 11980 | (org-get-param p h i :lstart :hlstart) | ||
| 11981 | (mapconcat 'identity line (org-get-param p h i :sep :hsep)) | ||
| 11982 | (org-get-param p h i :lend :hlend)) | ||
| 11983 | rtn)))) | ||
| 11984 | |||
| 11985 | (unless splicep | ||
| 11986 | (push (or (plist-get p :tend) "ERROR: no :tend") rtn)) | ||
| 11987 | |||
| 11988 | (mapconcat 'identity (nreverse rtn) "\n"))) | ||
| 11989 | |||
| 11990 | (defun orgtbl-to-latex (table params) | ||
| 11991 | "Convert the orgtbl-mode TABLE to LaTeX. | ||
| 11992 | TABLE is a list, each entry either the symbol `hline' for a horizontal | ||
| 11993 | separator line, or a list of fields for that line. | ||
| 11994 | PARAMS is a property list of parameters that can influence the conversion. | ||
| 11995 | Supports all parameters from `orgtbl-to-generic'. Most important for | ||
| 11996 | LaTeX are: | ||
| 11997 | |||
| 11998 | :splice When set to t, return only table body lines, don't wrap | ||
| 11999 | them into a tabular environment. Default is nil. | ||
| 12000 | |||
| 12001 | :fmt A format to be used to wrap the field, should contain %s for the | ||
| 12002 | original field value. For example, to wrap everything in dollars, | ||
| 12003 | use :fmt \"$%s$\". This may also be a property list with column | ||
| 12004 | numbers and formats. For example :fmt (2 \"$%s$\" 4 \"%s%%\") | ||
| 12005 | |||
| 12006 | :efmt Format for transforming numbers with exponentials. The format | ||
| 12007 | should have %s twice for inserting mantissa and exponent, for | ||
| 12008 | example \"%s\\\\times10^{%s}\". LaTeX default is \"%s\\\\,(%s)\". | ||
| 12009 | This may also be a property list with column numbers and formats. | ||
| 12010 | |||
| 12011 | The general parameters :skip and :skipcols have already been applied when | ||
| 12012 | this function is called." | ||
| 12013 | (let* ((alignment (mapconcat (lambda (x) (if x "r" "l")) | ||
| 12014 | org-table-last-alignment "")) | ||
| 12015 | (params2 | ||
| 12016 | (list | ||
| 12017 | :tstart (concat "\\begin{tabular}{" alignment "}") | ||
| 12018 | :tend "\\end{tabular}" | ||
| 12019 | :lstart "" :lend " \\\\" :sep " & " | ||
| 12020 | :efmt "%s\\,(%s)" :hline "\\hline"))) | ||
| 12021 | (orgtbl-to-generic table (org-combine-plists params2 params)))) | ||
| 12022 | |||
| 12023 | (defun orgtbl-to-html (table params) | ||
| 12024 | "Convert the orgtbl-mode TABLE to LaTeX. | ||
| 12025 | TABLE is a list, each entry either the symbol `hline' for a horizontal | ||
| 12026 | separator line, or a list of fields for that line. | ||
| 12027 | PARAMS is a property list of parameters that can influence the conversion. | ||
| 12028 | Currently this function recognizes the following parameters: | ||
| 12029 | |||
| 12030 | :splice When set to t, return only table body lines, don't wrap | ||
| 12031 | them into a <table> environment. Default is nil. | ||
| 12032 | |||
| 12033 | The general parameters :skip and :skipcols have already been applied when | ||
| 12034 | this function is called. The function does *not* use `orgtbl-to-generic', | ||
| 12035 | so you cannot specify parameters for it." | ||
| 12036 | (let* ((splicep (plist-get params :splice)) | ||
| 12037 | html) | ||
| 12038 | ;; Just call the formatter we already have | ||
| 12039 | ;; We need to make text lines for it, so put the fields back together. | ||
| 12040 | (setq html (org-format-org-table-html | ||
| 12041 | (mapcar | ||
| 12042 | (lambda (x) | ||
| 12043 | (if (eq x 'hline) | ||
| 12044 | "|----+----|" | ||
| 12045 | (concat "| " (mapconcat 'identity x " | ") " |"))) | ||
| 12046 | table) | ||
| 12047 | splicep)) | ||
| 12048 | (if (string-match "\n+\\'" html) | ||
| 12049 | (setq html (replace-match "" t t html))) | ||
| 12050 | html)) | ||
| 12051 | |||
| 12052 | (defun orgtbl-to-texinfo (table params) | ||
| 12053 | "Convert the orgtbl-mode TABLE to TeXInfo. | ||
| 12054 | TABLE is a list, each entry either the symbol `hline' for a horizontal | ||
| 12055 | separator line, or a list of fields for that line. | ||
| 12056 | PARAMS is a property list of parameters that can influence the conversion. | ||
| 12057 | Supports all parameters from `orgtbl-to-generic'. Most important for | ||
| 12058 | TeXInfo are: | ||
| 12059 | |||
| 12060 | :splice nil/t When set to t, return only table body lines, don't wrap | ||
| 12061 | them into a multitable environment. Default is nil. | ||
| 12062 | |||
| 12063 | :fmt fmt A format to be used to wrap the field, should contain | ||
| 12064 | %s for the original field value. For example, to wrap | ||
| 12065 | everything in @kbd{}, you could use :fmt \"@kbd{%s}\". | ||
| 12066 | This may also be a property list with column numbers and | ||
| 12067 | formats. For example :fmt (2 \"@kbd{%s}\" 4 \"@code{%s}\"). | ||
| 12068 | |||
| 12069 | :cf \"f1 f2..\" The column fractions for the table. By default these | ||
| 12070 | are computed automatically from the width of the columns | ||
| 12071 | under org-mode. | ||
| 12072 | |||
| 12073 | The general parameters :skip and :skipcols have already been applied when | ||
| 12074 | this function is called." | ||
| 12075 | (let* ((total (float (apply '+ org-table-last-column-widths))) | ||
| 12076 | (colfrac (or (plist-get params :cf) | ||
| 12077 | (mapconcat | ||
| 12078 | (lambda (x) (format "%.3f" (/ (float x) total))) | ||
| 12079 | org-table-last-column-widths " "))) | ||
| 12080 | (params2 | ||
| 12081 | (list | ||
| 12082 | :tstart (concat "@multitable @columnfractions " colfrac) | ||
| 12083 | :tend "@end multitable" | ||
| 12084 | :lstart "@item " :lend "" :sep " @tab " | ||
| 12085 | :hlstart "@headitem "))) | ||
| 12086 | (orgtbl-to-generic table (org-combine-plists params2 params)))) | ||
| 12087 | |||
| 12088 | ;;;; Link Stuff | ||
| 12089 | |||
| 12090 | ;;; Link abbreviations | ||
| 12091 | |||
| 12092 | (defun org-link-expand-abbrev (link) | ||
| 12093 | "Apply replacements as defined in `org-link-abbrev-alist." | ||
| 12094 | (if (string-match "^\\([a-zA-Z][-_a-zA-Z0-9]*\\)\\(::?\\(.*\\)\\)?$" link) | ||
| 12095 | (let* ((key (match-string 1 link)) | ||
| 12096 | (as (or (assoc key org-link-abbrev-alist-local) | ||
| 12097 | (assoc key org-link-abbrev-alist))) | ||
| 12098 | (tag (and (match-end 2) (match-string 3 link))) | ||
| 12099 | rpl) | ||
| 12100 | (if (not as) | ||
| 12101 | link | ||
| 12102 | (setq rpl (cdr as)) | ||
| 12103 | (cond | ||
| 12104 | ((symbolp rpl) (funcall rpl tag)) | ||
| 12105 | ((string-match "%s" rpl) (replace-match (or tag "") t t rpl)) | ||
| 12106 | (t (concat rpl tag))))) | ||
| 12107 | link)) | ||
| 12108 | |||
| 12109 | ;;; Storing and inserting links | ||
| 12110 | |||
| 12111 | (defvar org-insert-link-history nil | ||
| 12112 | "Minibuffer history for links inserted with `org-insert-link'.") | ||
| 12113 | |||
| 12114 | (defvar org-stored-links nil | ||
| 12115 | "Contains the links stored with `org-store-link'.") | ||
| 12116 | |||
| 12117 | (defvar org-store-link-plist nil | ||
| 12118 | "Plist with info about the most recently link created with `org-store-link'.") | ||
| 12119 | |||
| 12120 | (defvar org-link-protocols nil | ||
| 12121 | "Link protocols added to Org-mode using `org-add-link-type'.") | ||
| 12122 | |||
| 12123 | (defvar org-store-link-functions nil | ||
| 12124 | "List of functions that are called to create and store a link. | ||
| 12125 | Each function will be called in turn until one returns a non-nil | ||
| 12126 | value. Each function should check if it is responsible for creating | ||
| 12127 | this link (for example by looking at the major mode). | ||
| 12128 | If not, it must exit and return nil. | ||
| 12129 | If yes, it should return a non-nil value after a calling | ||
| 12130 | `org-store-link-props' with a list of properties and values. | ||
| 12131 | Special properties are: | ||
| 12132 | |||
| 12133 | :type The link prefix. like \"http\". This must be given. | ||
| 12134 | :link The link, like \"http://www.astro.uva.nl/~dominik\". | ||
| 12135 | This is obligatory as well. | ||
| 12136 | :description Optional default description for the second pair | ||
| 12137 | of brackets in an Org-mode link. The user can still change | ||
| 12138 | this when inserting this link into an Org-mode buffer. | ||
| 12139 | |||
| 12140 | In addition to these, any additional properties can be specified | ||
| 12141 | and then used in remember templates.") | ||
| 12142 | |||
| 12143 | (defun org-add-link-type (type &optional follow publish) | ||
| 12144 | "Add TYPE to the list of `org-link-types'. | ||
| 12145 | Re-compute all regular expressions depending on `org-link-types' | ||
| 12146 | FOLLOW and PUBLISH are two functions. Both take the link path as | ||
| 12147 | an argument. | ||
| 12148 | FOLLOW should do whatever is necessary to follow the link, for example | ||
| 12149 | to find a file or display a mail message. | ||
| 12150 | |||
| 12151 | PUBLISH takes the path and retuns the string that should be used when | ||
| 12152 | this document is published. FIMXE: This is actually not yet implemented." | ||
| 12153 | (add-to-list 'org-link-types type t) | ||
| 12154 | (org-make-link-regexps) | ||
| 12155 | (add-to-list 'org-link-protocols | ||
| 12156 | (list type follow publish))) | ||
| 12157 | |||
| 12158 | (defun org-add-agenda-custom-command (entry) | ||
| 12159 | "Replace or add a command in `org-agenda-custom-commands'. | ||
| 12160 | This is mostly for hacking and trying a new command - once the command | ||
| 12161 | works you probably want to add it to `org-agenda-custom-commands' for good." | ||
| 12162 | (let ((ass (assoc (car entry) org-agenda-custom-commands))) | ||
| 12163 | (if ass | ||
| 12164 | (setcdr ass (cdr entry)) | ||
| 12165 | (push entry org-agenda-custom-commands)))) | ||
| 12166 | |||
| 12167 | ;;;###autoload | ||
| 12168 | (defun org-store-link (arg) | ||
| 12169 | "\\<org-mode-map>Store an org-link to the current location. | ||
| 12170 | This link is added to `org-stored-links' and can later be inserted | ||
| 12171 | into an org-buffer with \\[org-insert-link]. | ||
| 12172 | |||
| 12173 | For some link types, a prefix arg is interpreted: | ||
| 12174 | For links to usenet articles, arg negates `org-usenet-links-prefer-google'. | ||
| 12175 | For file links, arg negates `org-context-in-file-links'." | ||
| 12176 | (interactive "P") | ||
| 12177 | (require 'org-irc) | ||
| 12178 | (setq org-store-link-plist nil) ; reset | ||
| 12179 | (let (link cpltxt desc description search txt) | ||
| 12180 | (cond | ||
| 12181 | |||
| 12182 | ((run-hook-with-args-until-success 'org-store-link-functions) | ||
| 12183 | (setq link (plist-get org-store-link-plist :link) | ||
| 12184 | desc (or (plist-get org-store-link-plist :description) link))) | ||
| 12185 | |||
| 12186 | ((eq major-mode 'bbdb-mode) | ||
| 12187 | (let ((name (bbdb-record-name (bbdb-current-record))) | ||
| 12188 | (company (bbdb-record-getprop (bbdb-current-record) 'company))) | ||
| 12189 | (setq cpltxt (concat "bbdb:" (or name company)) | ||
| 12190 | link (org-make-link cpltxt)) | ||
| 12191 | (org-store-link-props :type "bbdb" :name name :company company))) | ||
| 12192 | |||
| 12193 | ((eq major-mode 'Info-mode) | ||
| 12194 | (setq link (org-make-link "info:" | ||
| 12195 | (file-name-nondirectory Info-current-file) | ||
| 12196 | ":" Info-current-node)) | ||
| 12197 | (setq cpltxt (concat (file-name-nondirectory Info-current-file) | ||
| 12198 | ":" Info-current-node)) | ||
| 12199 | (org-store-link-props :type "info" :file Info-current-file | ||
| 12200 | :node Info-current-node)) | ||
| 12201 | |||
| 12202 | ((eq major-mode 'calendar-mode) | ||
| 12203 | (let ((cd (calendar-cursor-to-date))) | ||
| 12204 | (setq link | ||
| 12205 | (format-time-string | ||
| 12206 | (car org-time-stamp-formats) | ||
| 12207 | (apply 'encode-time | ||
| 12208 | (list 0 0 0 (nth 1 cd) (nth 0 cd) (nth 2 cd) | ||
| 12209 | nil nil nil)))) | ||
| 12210 | (org-store-link-props :type "calendar" :date cd))) | ||
| 12211 | |||
| 12212 | ((or (eq major-mode 'vm-summary-mode) | ||
| 12213 | (eq major-mode 'vm-presentation-mode)) | ||
| 12214 | (and (eq major-mode 'vm-presentation-mode) (vm-summarize)) | ||
| 12215 | (vm-follow-summary-cursor) | ||
| 12216 | (save-excursion | ||
| 12217 | (vm-select-folder-buffer) | ||
| 12218 | (let* ((message (car vm-message-pointer)) | ||
| 12219 | (folder buffer-file-name) | ||
| 12220 | (subject (vm-su-subject message)) | ||
| 12221 | (to (vm-get-header-contents message "To")) | ||
| 12222 | (from (vm-get-header-contents message "From")) | ||
| 12223 | (message-id (vm-su-message-id message))) | ||
| 12224 | (org-store-link-props :type "vm" :from from :to to :subject subject | ||
| 12225 | :message-id message-id) | ||
| 12226 | (setq message-id (org-remove-angle-brackets message-id)) | ||
| 12227 | (setq folder (abbreviate-file-name folder)) | ||
| 12228 | (if (string-match (concat "^" (regexp-quote vm-folder-directory)) | ||
| 12229 | folder) | ||
| 12230 | (setq folder (replace-match "" t t folder))) | ||
| 12231 | (setq cpltxt (org-email-link-description)) | ||
| 12232 | (setq link (org-make-link "vm:" folder "#" message-id))))) | ||
| 12233 | |||
| 12234 | ((eq major-mode 'wl-summary-mode) | ||
| 12235 | (let* ((msgnum (wl-summary-message-number)) | ||
| 12236 | (message-id (elmo-message-field wl-summary-buffer-elmo-folder | ||
| 12237 | msgnum 'message-id)) | ||
| 12238 | (wl-message-entity | ||
| 12239 | (if (fboundp 'elmo-message-entity) | ||
| 12240 | (elmo-message-entity | ||
| 12241 | wl-summary-buffer-elmo-folder msgnum) | ||
| 12242 | (elmo-msgdb-overview-get-entity | ||
| 12243 | msgnum (wl-summary-buffer-msgdb)))) | ||
| 12244 | (from (wl-summary-line-from)) | ||
| 12245 | (to (car (elmo-message-entity-field wl-message-entity 'to))) | ||
| 12246 | (subject (let (wl-thr-indent-string wl-parent-message-entity) | ||
| 12247 | (wl-summary-line-subject)))) | ||
| 12248 | (org-store-link-props :type "wl" :from from :to to | ||
| 12249 | :subject subject :message-id message-id) | ||
| 12250 | (setq message-id (org-remove-angle-brackets message-id)) | ||
| 12251 | (setq cpltxt (org-email-link-description)) | ||
| 12252 | (setq link (org-make-link "wl:" wl-summary-buffer-folder-name | ||
| 12253 | "#" message-id)))) | ||
| 12254 | |||
| 12255 | ((or (equal major-mode 'mh-folder-mode) | ||
| 12256 | (equal major-mode 'mh-show-mode)) | ||
| 12257 | (let ((from (org-mhe-get-header "From:")) | ||
| 12258 | (to (org-mhe-get-header "To:")) | ||
| 12259 | (message-id (org-mhe-get-header "Message-Id:")) | ||
| 12260 | (subject (org-mhe-get-header "Subject:"))) | ||
| 12261 | (org-store-link-props :type "mh" :from from :to to | ||
| 12262 | :subject subject :message-id message-id) | ||
| 12263 | (setq cpltxt (org-email-link-description)) | ||
| 12264 | (setq link (org-make-link "mhe:" (org-mhe-get-message-real-folder) "#" | ||
| 12265 | (org-remove-angle-brackets message-id))))) | ||
| 12266 | |||
| 12267 | ((or (eq major-mode 'rmail-mode) | ||
| 12268 | (eq major-mode 'rmail-summary-mode)) | ||
| 12269 | (save-window-excursion | ||
| 12270 | (save-restriction | ||
| 12271 | (when (eq major-mode 'rmail-summary-mode) | ||
| 12272 | (rmail-show-message rmail-current-message)) | ||
| 12273 | (rmail-narrow-to-non-pruned-header) | ||
| 12274 | (let ((folder buffer-file-name) | ||
| 12275 | (message-id (mail-fetch-field "message-id")) | ||
| 12276 | (from (mail-fetch-field "from")) | ||
| 12277 | (to (mail-fetch-field "to")) | ||
| 12278 | (subject (mail-fetch-field "subject"))) | ||
| 12279 | (org-store-link-props | ||
| 12280 | :type "rmail" :from from :to to | ||
| 12281 | :subject subject :message-id message-id) | ||
| 12282 | (setq message-id (org-remove-angle-brackets message-id)) | ||
| 12283 | (setq cpltxt (org-email-link-description)) | ||
| 12284 | (setq link (org-make-link "rmail:" folder "#" message-id))) | ||
| 12285 | (rmail-show-message rmail-current-message)))) | ||
| 12286 | |||
| 12287 | ((eq major-mode 'gnus-group-mode) | ||
| 12288 | (let ((group (cond ((fboundp 'gnus-group-group-name) ; depending on Gnus | ||
| 12289 | (gnus-group-group-name)) ; version | ||
| 12290 | ((fboundp 'gnus-group-name) | ||
| 12291 | (gnus-group-name)) | ||
| 12292 | (t "???")))) | ||
| 12293 | (unless group (error "Not on a group")) | ||
| 12294 | (org-store-link-props :type "gnus" :group group) | ||
| 12295 | (setq cpltxt (concat | ||
| 12296 | (if (org-xor arg org-usenet-links-prefer-google) | ||
| 12297 | "http://groups.google.com/groups?group=" | ||
| 12298 | "gnus:") | ||
| 12299 | group) | ||
| 12300 | link (org-make-link cpltxt)))) | ||
| 12301 | |||
| 12302 | ((memq major-mode '(gnus-summary-mode gnus-article-mode)) | ||
| 12303 | (and (eq major-mode 'gnus-article-mode) (gnus-article-show-summary)) | ||
| 12304 | (let* ((group gnus-newsgroup-name) | ||
| 12305 | (article (gnus-summary-article-number)) | ||
| 12306 | (header (gnus-summary-article-header article)) | ||
| 12307 | (from (mail-header-from header)) | ||
| 12308 | (message-id (mail-header-id header)) | ||
| 12309 | (date (mail-header-date header)) | ||
| 12310 | (subject (gnus-summary-subject-string))) | ||
| 12311 | (org-store-link-props :type "gnus" :from from :subject subject | ||
| 12312 | :message-id message-id :group group) | ||
| 12313 | (setq cpltxt (org-email-link-description)) | ||
| 12314 | (if (org-xor arg org-usenet-links-prefer-google) | ||
| 12315 | (setq link | ||
| 12316 | (concat | ||
| 12317 | cpltxt "\n " | ||
| 12318 | (format "http://groups.google.com/groups?as_umsgid=%s" | ||
| 12319 | (org-fixup-message-id-for-http message-id)))) | ||
| 12320 | (setq link (org-make-link "gnus:" group | ||
| 12321 | "#" (number-to-string article)))))) | ||
| 12322 | |||
| 12323 | ((eq major-mode 'w3-mode) | ||
| 12324 | (setq cpltxt (url-view-url t) | ||
| 12325 | link (org-make-link cpltxt)) | ||
| 12326 | (org-store-link-props :type "w3" :url (url-view-url t))) | ||
| 12327 | |||
| 12328 | ((eq major-mode 'w3m-mode) | ||
| 12329 | (setq cpltxt (or w3m-current-title w3m-current-url) | ||
| 12330 | link (org-make-link w3m-current-url)) | ||
| 12331 | (org-store-link-props :type "w3m" :url (url-view-url t))) | ||
| 12332 | |||
| 12333 | ((setq search (run-hook-with-args-until-success | ||
| 12334 | 'org-create-file-search-functions)) | ||
| 12335 | (setq link (concat "file:" (abbreviate-file-name buffer-file-name) | ||
| 12336 | "::" search)) | ||
| 12337 | (setq cpltxt (or description link))) | ||
| 12338 | |||
| 12339 | ((eq major-mode 'image-mode) | ||
| 12340 | (setq cpltxt (concat "file:" | ||
| 12341 | (abbreviate-file-name buffer-file-name)) | ||
| 12342 | link (org-make-link cpltxt)) | ||
| 12343 | (org-store-link-props :type "image" :file buffer-file-name)) | ||
| 12344 | |||
| 12345 | ((eq major-mode 'dired-mode) | ||
| 12346 | ;; link to the file in the current line | ||
| 12347 | (setq cpltxt (concat "file:" | ||
| 12348 | (abbreviate-file-name | ||
| 12349 | (expand-file-name | ||
| 12350 | (dired-get-filename nil t)))) | ||
| 12351 | link (org-make-link cpltxt))) | ||
| 12352 | |||
| 12353 | ((and buffer-file-name (org-mode-p)) | ||
| 12354 | ;; Just link to current headline | ||
| 12355 | (setq cpltxt (concat "file:" | ||
| 12356 | (abbreviate-file-name buffer-file-name))) | ||
| 12357 | ;; Add a context search string | ||
| 12358 | (when (org-xor org-context-in-file-links arg) | ||
| 12359 | ;; Check if we are on a target | ||
| 12360 | (if (org-in-regexp "<<\\(.*?\\)>>") | ||
| 12361 | (setq cpltxt (concat cpltxt "::" (match-string 1))) | ||
| 12362 | (setq txt (cond | ||
| 12363 | ((org-on-heading-p) nil) | ||
| 12364 | ((org-region-active-p) | ||
| 12365 | (buffer-substring (region-beginning) (region-end))) | ||
| 12366 | (t (buffer-substring (point-at-bol) (point-at-eol))))) | ||
| 12367 | (when (or (null txt) (string-match "\\S-" txt)) | ||
| 12368 | (setq cpltxt | ||
| 12369 | (concat cpltxt "::" (org-make-org-heading-search-string txt)) | ||
| 12370 | desc "NONE")))) | ||
| 12371 | (if (string-match "::\\'" cpltxt) | ||
| 12372 | (setq cpltxt (substring cpltxt 0 -2))) | ||
| 12373 | (setq link (org-make-link cpltxt))) | ||
| 12374 | |||
| 12375 | ((buffer-file-name (buffer-base-buffer)) | ||
| 12376 | ;; Just link to this file here. | ||
| 12377 | (setq cpltxt (concat "file:" | ||
| 12378 | (abbreviate-file-name | ||
| 12379 | (buffer-file-name (buffer-base-buffer))))) | ||
| 12380 | ;; Add a context string | ||
| 12381 | (when (org-xor org-context-in-file-links arg) | ||
| 12382 | (setq txt (if (org-region-active-p) | ||
| 12383 | (buffer-substring (region-beginning) (region-end)) | ||
| 12384 | (buffer-substring (point-at-bol) (point-at-eol)))) | ||
| 12385 | ;; Only use search option if there is some text. | ||
| 12386 | (when (string-match "\\S-" txt) | ||
| 12387 | (setq cpltxt | ||
| 12388 | (concat cpltxt "::" (org-make-org-heading-search-string txt)) | ||
| 12389 | desc "NONE"))) | ||
| 12390 | (setq link (org-make-link cpltxt))) | ||
| 12391 | |||
| 12392 | ((interactive-p) | ||
| 12393 | (error "Cannot link to a buffer which is not visiting a file")) | ||
| 12394 | |||
| 12395 | (t (setq link nil))) | ||
| 12396 | |||
| 12397 | (if (consp link) (setq cpltxt (car link) link (cdr link))) | ||
| 12398 | (setq link (or link cpltxt) | ||
| 12399 | desc (or desc cpltxt)) | ||
| 12400 | (if (equal desc "NONE") (setq desc nil)) | ||
| 12401 | |||
| 12402 | (if (and (interactive-p) link) | ||
| 12403 | (progn | ||
| 12404 | (setq org-stored-links | ||
| 12405 | (cons (list link desc) org-stored-links)) | ||
| 12406 | (message "Stored: %s" (or desc link))) | ||
| 12407 | (and link (org-make-link-string link desc))))) | ||
| 12408 | |||
| 12409 | (defun org-store-link-props (&rest plist) | ||
| 12410 | "Store link properties, extract names and addresses." | ||
| 12411 | (let (x adr) | ||
| 12412 | (when (setq x (plist-get plist :from)) | ||
| 12413 | (setq adr (mail-extract-address-components x)) | ||
| 12414 | (plist-put plist :fromname (car adr)) | ||
| 12415 | (plist-put plist :fromaddress (nth 1 adr))) | ||
| 12416 | (when (setq x (plist-get plist :to)) | ||
| 12417 | (setq adr (mail-extract-address-components x)) | ||
| 12418 | (plist-put plist :toname (car adr)) | ||
| 12419 | (plist-put plist :toaddress (nth 1 adr)))) | ||
| 12420 | (let ((from (plist-get plist :from)) | ||
| 12421 | (to (plist-get plist :to))) | ||
| 12422 | (when (and from to org-from-is-user-regexp) | ||
| 12423 | (plist-put plist :fromto | ||
| 12424 | (if (string-match org-from-is-user-regexp from) | ||
| 12425 | (concat "to %t") | ||
| 12426 | (concat "from %f"))))) | ||
| 12427 | (setq org-store-link-plist plist)) | ||
| 12428 | |||
| 12429 | (defun org-email-link-description (&optional fmt) | ||
| 12430 | "Return the description part of an email link. | ||
| 12431 | This takes information from `org-store-link-plist' and formats it | ||
| 12432 | according to FMT (default from `org-email-link-description-format')." | ||
| 12433 | (setq fmt (or fmt org-email-link-description-format)) | ||
| 12434 | (let* ((p org-store-link-plist) | ||
| 12435 | (to (plist-get p :toaddress)) | ||
| 12436 | (from (plist-get p :fromaddress)) | ||
| 12437 | (table | ||
| 12438 | (list | ||
| 12439 | (cons "%c" (plist-get p :fromto)) | ||
| 12440 | (cons "%F" (plist-get p :from)) | ||
| 12441 | (cons "%f" (or (plist-get p :fromname) (plist-get p :fromaddress) "?")) | ||
| 12442 | (cons "%T" (plist-get p :to)) | ||
| 12443 | (cons "%t" (or (plist-get p :toname) (plist-get p :toaddress) "?")) | ||
| 12444 | (cons "%s" (plist-get p :subject)) | ||
| 12445 | (cons "%m" (plist-get p :message-id))))) | ||
| 12446 | (when (string-match "%c" fmt) | ||
| 12447 | ;; Check if the user wrote this message | ||
| 12448 | (if (and org-from-is-user-regexp from to | ||
| 12449 | (save-match-data (string-match org-from-is-user-regexp from))) | ||
| 12450 | (setq fmt (replace-match "to %t" t t fmt)) | ||
| 12451 | (setq fmt (replace-match "from %f" t t fmt)))) | ||
| 12452 | (org-replace-escapes fmt table))) | ||
| 12453 | |||
| 12454 | (defun org-make-org-heading-search-string (&optional string heading) | ||
| 12455 | "Make search string for STRING or current headline." | ||
| 12456 | (interactive) | ||
| 12457 | (let ((s (or string (org-get-heading)))) | ||
| 12458 | (unless (and string (not heading)) | ||
| 12459 | ;; We are using a headline, clean up garbage in there. | ||
| 12460 | (if (string-match org-todo-regexp s) | ||
| 12461 | (setq s (replace-match "" t t s))) | ||
| 12462 | (if (string-match (org-re ":[[:alnum:]_@:]+:[ \t]*$") s) | ||
| 12463 | (setq s (replace-match "" t t s))) | ||
| 12464 | (setq s (org-trim s)) | ||
| 12465 | (if (string-match (concat "^\\(" org-quote-string "\\|" | ||
| 12466 | org-comment-string "\\)") s) | ||
| 12467 | (setq s (replace-match "" t t s))) | ||
| 12468 | (while (string-match org-ts-regexp s) | ||
| 12469 | (setq s (replace-match "" t t s)))) | ||
| 12470 | (while (string-match "[^a-zA-Z_0-9 \t]+" s) | ||
| 12471 | (setq s (replace-match " " t t s))) | ||
| 12472 | (or string (setq s (concat "*" s))) ; Add * for headlines | ||
| 12473 | (mapconcat 'identity (org-split-string s "[ \t]+") " "))) | ||
| 12474 | |||
| 12475 | (defun org-make-link (&rest strings) | ||
| 12476 | "Concatenate STRINGS." | ||
| 12477 | (apply 'concat strings)) | ||
| 12478 | |||
| 12479 | (defun org-make-link-string (link &optional description) | ||
| 12480 | "Make a link with brackets, consisting of LINK and DESCRIPTION." | ||
| 12481 | (unless (string-match "\\S-" link) | ||
| 12482 | (error "Empty link")) | ||
| 12483 | (when (stringp description) | ||
| 12484 | ;; Remove brackets from the description, they are fatal. | ||
| 12485 | (while (string-match "\\[" description) | ||
| 12486 | (setq description (replace-match "{" t t description))) | ||
| 12487 | (while (string-match "\\]" description) | ||
| 12488 | (setq description (replace-match "}" t t description)))) | ||
| 12489 | (when (equal (org-link-escape link) description) | ||
| 12490 | ;; No description needed, it is identical | ||
| 12491 | (setq description nil)) | ||
| 12492 | (when (and (not description) | ||
| 12493 | (not (equal link (org-link-escape link)))) | ||
| 12494 | (setq description link)) | ||
| 12495 | (concat "[[" (org-link-escape link) "]" | ||
| 12496 | (if description (concat "[" description "]") "") | ||
| 12497 | "]")) | ||
| 12498 | |||
| 12499 | (defconst org-link-escape-chars | ||
| 12500 | '((?\ . "%20") | ||
| 12501 | (?\[ . "%5B") | ||
| 12502 | (?\] . "%5D") | ||
| 12503 | (?\340 . "%E0") ; `a | ||
| 12504 | (?\342 . "%E2") ; ^a | ||
| 12505 | (?\347 . "%E7") ; ,c | ||
| 12506 | (?\350 . "%E8") ; `e | ||
| 12507 | (?\351 . "%E9") ; 'e | ||
| 12508 | (?\352 . "%EA") ; ^e | ||
| 12509 | (?\356 . "%EE") ; ^i | ||
| 12510 | (?\364 . "%F4") ; ^o | ||
| 12511 | (?\371 . "%F9") ; `u | ||
| 12512 | (?\373 . "%FB") ; ^u | ||
| 12513 | (?\; . "%3B") | ||
| 12514 | (?? . "%3F") | ||
| 12515 | (?= . "%3D") | ||
| 12516 | (?+ . "%2B") | ||
| 12517 | ) | ||
| 12518 | "Association list of escapes for some characters problematic in links. | ||
| 12519 | This is the list that is used for internal purposes.") | ||
| 12520 | |||
| 12521 | (defconst org-link-escape-chars-browser | ||
| 12522 | '((?\ . "%20")) ; 32 for the SPC char | ||
| 12523 | "Association list of escapes for some characters problematic in links. | ||
| 12524 | This is the list that is used before handing over to the browser.") | ||
| 12525 | |||
| 12526 | (defun org-link-escape (text &optional table) | ||
| 12527 | "Escape charaters in TEXT that are problematic for links." | ||
| 12528 | (setq table (or table org-link-escape-chars)) | ||
| 12529 | (when text | ||
| 12530 | (let ((re (mapconcat (lambda (x) (regexp-quote | ||
| 12531 | (char-to-string (car x)))) | ||
| 12532 | table "\\|"))) | ||
| 12533 | (while (string-match re text) | ||
| 12534 | (setq text | ||
| 12535 | (replace-match | ||
| 12536 | (cdr (assoc (string-to-char (match-string 0 text)) | ||
| 12537 | table)) | ||
| 12538 | t t text))) | ||
| 12539 | text))) | ||
| 12540 | |||
| 12541 | (defun org-link-unescape (text &optional table) | ||
| 12542 | "Reverse the action of `org-link-escape'." | ||
| 12543 | (setq table (or table org-link-escape-chars)) | ||
| 12544 | (when text | ||
| 12545 | (let ((re (mapconcat (lambda (x) (regexp-quote (cdr x))) | ||
| 12546 | table "\\|"))) | ||
| 12547 | (while (string-match re text) | ||
| 12548 | (setq text | ||
| 12549 | (replace-match | ||
| 12550 | (char-to-string (car (rassoc (match-string 0 text) table))) | ||
| 12551 | t t text))) | ||
| 12552 | text))) | ||
| 12553 | |||
| 12554 | (defun org-xor (a b) | ||
| 12555 | "Exclusive or." | ||
| 12556 | (if a (not b) b)) | ||
| 12557 | |||
| 12558 | (defun org-get-header (header) | ||
| 12559 | "Find a header field in the current buffer." | ||
| 12560 | (save-excursion | ||
| 12561 | (goto-char (point-min)) | ||
| 12562 | (let ((case-fold-search t) s) | ||
| 12563 | (cond | ||
| 12564 | ((eq header 'from) | ||
| 12565 | (if (re-search-forward "^From:\\s-+\\(.*\\)" nil t) | ||
| 12566 | (setq s (match-string 1))) | ||
| 12567 | (while (string-match "\"" s) | ||
| 12568 | (setq s (replace-match "" t t s))) | ||
| 12569 | (if (string-match "[<(].*" s) | ||
| 12570 | (setq s (replace-match "" t t s)))) | ||
| 12571 | ((eq header 'message-id) | ||
| 12572 | (if (re-search-forward "^message-id:\\s-+\\(.*\\)" nil t) | ||
| 12573 | (setq s (match-string 1)))) | ||
| 12574 | ((eq header 'subject) | ||
| 12575 | (if (re-search-forward "^subject:\\s-+\\(.*\\)" nil t) | ||
| 12576 | (setq s (match-string 1))))) | ||
| 12577 | (if (string-match "\\`[ \t\]+" s) (setq s (replace-match "" t t s))) | ||
| 12578 | (if (string-match "[ \t\]+\\'" s) (setq s (replace-match "" t t s))) | ||
| 12579 | s))) | ||
| 12580 | |||
| 12581 | |||
| 12582 | (defun org-fixup-message-id-for-http (s) | ||
| 12583 | "Replace special characters in a message id, so it can be used in an http query." | ||
| 12584 | (while (string-match "<" s) | ||
| 12585 | (setq s (replace-match "%3C" t t s))) | ||
| 12586 | (while (string-match ">" s) | ||
| 12587 | (setq s (replace-match "%3E" t t s))) | ||
| 12588 | (while (string-match "@" s) | ||
| 12589 | (setq s (replace-match "%40" t t s))) | ||
| 12590 | s) | ||
| 12591 | |||
| 12592 | ;;;###autoload | ||
| 12593 | (defun org-insert-link-global () | ||
| 12594 | "Insert a link like Org-mode does. | ||
| 12595 | This command can be called in any mode to insert a link in Org-mode syntax." | ||
| 12596 | (interactive) | ||
| 12597 | (org-run-like-in-org-mode 'org-insert-link)) | ||
| 12598 | |||
| 12599 | (defun org-insert-link (&optional complete-file) | ||
| 12600 | "Insert a link. At the prompt, enter the link. | ||
| 12601 | |||
| 12602 | Completion can be used to select a link previously stored with | ||
| 12603 | `org-store-link'. When the empty string is entered (i.e. if you just | ||
| 12604 | press RET at the prompt), the link defaults to the most recently | ||
| 12605 | stored link. As SPC triggers completion in the minibuffer, you need to | ||
| 12606 | use M-SPC or C-q SPC to force the insertion of a space character. | ||
| 12607 | |||
| 12608 | You will also be prompted for a description, and if one is given, it will | ||
| 12609 | be displayed in the buffer instead of the link. | ||
| 12610 | |||
| 12611 | If there is already a link at point, this command will allow you to edit link | ||
| 12612 | and description parts. | ||
| 12613 | |||
| 12614 | With a \\[universal-argument] prefix, prompts for a file to link to. The file name can be | ||
| 12615 | selected using completion. The path to the file will be relative to | ||
| 12616 | the current directory if the file is in the current directory or a | ||
| 12617 | subdirectory. Otherwise, the link will be the absolute path as | ||
| 12618 | completed in the minibuffer (i.e. normally ~/path/to/file). | ||
| 12619 | |||
| 12620 | With two \\[universal-argument] prefixes, enforce an absolute path even if the file | ||
| 12621 | is in the current directory or below. | ||
| 12622 | With three \\[universal-argument] prefixes, negate the meaning of | ||
| 12623 | `org-keep-stored-link-after-insertion'." | ||
| 12624 | (interactive "P") | ||
| 12625 | (let* ((wcf (current-window-configuration)) | ||
| 12626 | (region (if (org-region-active-p) | ||
| 12627 | (buffer-substring (region-beginning) (region-end)))) | ||
| 12628 | (remove (and region (list (region-beginning) (region-end)))) | ||
| 12629 | (desc region) | ||
| 12630 | tmphist ; byte-compile incorrectly complains about this | ||
| 12631 | link entry file) | ||
| 12632 | (cond | ||
| 12633 | ((org-in-regexp org-bracket-link-regexp 1) | ||
| 12634 | ;; We do have a link at point, and we are going to edit it. | ||
| 12635 | (setq remove (list (match-beginning 0) (match-end 0))) | ||
| 12636 | (setq desc (if (match-end 3) (org-match-string-no-properties 3))) | ||
| 12637 | (setq link (read-string "Link: " | ||
| 12638 | (org-link-unescape | ||
| 12639 | (org-match-string-no-properties 1))))) | ||
| 12640 | ((or (org-in-regexp org-angle-link-re) | ||
| 12641 | (org-in-regexp org-plain-link-re)) | ||
| 12642 | ;; Convert to bracket link | ||
| 12643 | (setq remove (list (match-beginning 0) (match-end 0)) | ||
| 12644 | link (read-string "Link: " | ||
| 12645 | (org-remove-angle-brackets (match-string 0))))) | ||
| 12646 | ((equal complete-file '(4)) | ||
| 12647 | ;; Completing read for file names. | ||
| 12648 | (setq file (read-file-name "File: ")) | ||
| 12649 | (let ((pwd (file-name-as-directory (expand-file-name "."))) | ||
| 12650 | (pwd1 (file-name-as-directory (abbreviate-file-name | ||
| 12651 | (expand-file-name "."))))) | ||
| 12652 | (cond | ||
| 12653 | ((equal complete-file '(16)) | ||
| 12654 | (setq link (org-make-link | ||
| 12655 | "file:" | ||
| 12656 | (abbreviate-file-name (expand-file-name file))))) | ||
| 12657 | ((string-match (concat "^" (regexp-quote pwd1) "\\(.+\\)") file) | ||
| 12658 | (setq link (org-make-link "file:" (match-string 1 file)))) | ||
| 12659 | ((string-match (concat "^" (regexp-quote pwd) "\\(.+\\)") | ||
| 12660 | (expand-file-name file)) | ||
| 12661 | (setq link (org-make-link | ||
| 12662 | "file:" (match-string 1 (expand-file-name file))))) | ||
| 12663 | (t (setq link (org-make-link "file:" file)))))) | ||
| 12664 | (t | ||
| 12665 | ;; Read link, with completion for stored links. | ||
| 12666 | (with-output-to-temp-buffer "*Org Links*" | ||
| 12667 | (princ "Insert a link. Use TAB to complete valid link prefixes.\n") | ||
| 12668 | (when org-stored-links | ||
| 12669 | (princ "\nStored links are available with <up>/<down> or M-p/n (most recent with RET):\n\n") | ||
| 12670 | (princ (mapconcat | ||
| 12671 | (lambda (x) | ||
| 12672 | (if (nth 1 x) (concat (car x) " (" (nth 1 x) ")") (car x))) | ||
| 12673 | (reverse org-stored-links) "\n")))) | ||
| 12674 | (let ((cw (selected-window))) | ||
| 12675 | (select-window (get-buffer-window "*Org Links*")) | ||
| 12676 | (shrink-window-if-larger-than-buffer) | ||
| 12677 | (setq truncate-lines t) | ||
| 12678 | (select-window cw)) | ||
| 12679 | ;; Fake a link history, containing the stored links. | ||
| 12680 | (setq tmphist (append (mapcar 'car org-stored-links) | ||
| 12681 | org-insert-link-history)) | ||
| 12682 | (unwind-protect | ||
| 12683 | (setq link (org-completing-read | ||
| 12684 | "Link: " | ||
| 12685 | (append | ||
| 12686 | (mapcar (lambda (x) (list (concat (car x) ":"))) | ||
| 12687 | (append org-link-abbrev-alist-local org-link-abbrev-alist)) | ||
| 12688 | (mapcar (lambda (x) (list (concat x ":"))) | ||
| 12689 | org-link-types)) | ||
| 12690 | nil nil nil | ||
| 12691 | 'tmphist | ||
| 12692 | (or (car (car org-stored-links))))) | ||
| 12693 | (set-window-configuration wcf) | ||
| 12694 | (kill-buffer "*Org Links*")) | ||
| 12695 | (setq entry (assoc link org-stored-links)) | ||
| 12696 | (or entry (push link org-insert-link-history)) | ||
| 12697 | (if (funcall (if (equal complete-file '(64)) 'not 'identity) | ||
| 12698 | (not org-keep-stored-link-after-insertion)) | ||
| 12699 | (setq org-stored-links (delq (assoc link org-stored-links) | ||
| 12700 | org-stored-links))) | ||
| 12701 | (setq desc (or desc (nth 1 entry))))) | ||
| 12702 | |||
| 12703 | (if (string-match org-plain-link-re link) | ||
| 12704 | ;; URL-like link, normalize the use of angular brackets. | ||
| 12705 | (setq link (org-make-link (org-remove-angle-brackets link)))) | ||
| 12706 | |||
| 12707 | ;; Check if we are linking to the current file with a search option | ||
| 12708 | ;; If yes, simplify the link by using only the search option. | ||
| 12709 | (when (and buffer-file-name | ||
| 12710 | (string-match "\\<file:\\(.+?\\)::\\([^>]+\\)" link)) | ||
| 12711 | (let* ((path (match-string 1 link)) | ||
| 12712 | (case-fold-search nil) | ||
| 12713 | (search (match-string 2 link))) | ||
| 12714 | (save-match-data | ||
| 12715 | (if (equal (file-truename buffer-file-name) (file-truename path)) | ||
| 12716 | ;; We are linking to this same file, with a search option | ||
| 12717 | (setq link search))))) | ||
| 12718 | |||
| 12719 | ;; Check if we can/should use a relative path. If yes, simplify the link | ||
| 12720 | (when (string-match "\\<file:\\(.*\\)" link) | ||
| 12721 | (let* ((path (match-string 1 link)) | ||
| 12722 | (origpath path) | ||
| 12723 | (case-fold-search nil)) | ||
| 12724 | (cond | ||
| 12725 | ((eq org-link-file-path-type 'absolute) | ||
| 12726 | (setq path (abbreviate-file-name (expand-file-name path)))) | ||
| 12727 | ((eq org-link-file-path-type 'noabbrev) | ||
| 12728 | (setq path (expand-file-name path))) | ||
| 12729 | ((eq org-link-file-path-type 'relative) | ||
| 12730 | (setq path (file-relative-name path))) | ||
| 12731 | (t | ||
| 12732 | (save-match-data | ||
| 12733 | (if (string-match (concat "^" (regexp-quote | ||
| 12734 | (file-name-as-directory | ||
| 12735 | (expand-file-name ".")))) | ||
| 12736 | (expand-file-name path)) | ||
| 12737 | ;; We are linking a file with relative path name. | ||
| 12738 | (setq path (substring (expand-file-name path) | ||
| 12739 | (match-end 0))))))) | ||
| 12740 | (setq link (concat "file:" path)) | ||
| 12741 | (if (equal desc origpath) | ||
| 12742 | (setq desc path)))) | ||
| 12743 | |||
| 12744 | (setq desc (read-string "Description: " desc)) | ||
| 12745 | (unless (string-match "\\S-" desc) (setq desc nil)) | ||
| 12746 | (if remove (apply 'delete-region remove)) | ||
| 12747 | (insert (org-make-link-string link desc)))) | ||
| 12748 | |||
| 12749 | (defun org-completing-read (&rest args) | ||
| 12750 | (let ((minibuffer-local-completion-map | ||
| 12751 | (copy-keymap minibuffer-local-completion-map))) | ||
| 12752 | (org-defkey minibuffer-local-completion-map " " 'self-insert-command) | ||
| 12753 | (apply 'completing-read args))) | ||
| 12754 | |||
| 12755 | ;;; Opening/following a link | ||
| 12756 | (defvar org-link-search-failed nil) | ||
| 12757 | |||
| 12758 | (defun org-next-link () | ||
| 12759 | "Move forward to the next link. | ||
| 12760 | If the link is in hidden text, expose it." | ||
| 12761 | (interactive) | ||
| 12762 | (when (and org-link-search-failed (eq this-command last-command)) | ||
| 12763 | (goto-char (point-min)) | ||
| 12764 | (message "Link search wrapped back to beginning of buffer")) | ||
| 12765 | (setq org-link-search-failed nil) | ||
| 12766 | (let* ((pos (point)) | ||
| 12767 | (ct (org-context)) | ||
| 12768 | (a (assoc :link ct))) | ||
| 12769 | (if a (goto-char (nth 2 a))) | ||
| 12770 | (if (re-search-forward org-any-link-re nil t) | ||
| 12771 | (progn | ||
| 12772 | (goto-char (match-beginning 0)) | ||
| 12773 | (if (org-invisible-p) (org-show-context))) | ||
| 12774 | (goto-char pos) | ||
| 12775 | (setq org-link-search-failed t) | ||
| 12776 | (error "No further link found")))) | ||
| 12777 | |||
| 12778 | (defun org-previous-link () | ||
| 12779 | "Move backward to the previous link. | ||
| 12780 | If the link is in hidden text, expose it." | ||
| 12781 | (interactive) | ||
| 12782 | (when (and org-link-search-failed (eq this-command last-command)) | ||
| 12783 | (goto-char (point-max)) | ||
| 12784 | (message "Link search wrapped back to end of buffer")) | ||
| 12785 | (setq org-link-search-failed nil) | ||
| 12786 | (let* ((pos (point)) | ||
| 12787 | (ct (org-context)) | ||
| 12788 | (a (assoc :link ct))) | ||
| 12789 | (if a (goto-char (nth 1 a))) | ||
| 12790 | (if (re-search-backward org-any-link-re nil t) | ||
| 12791 | (progn | ||
| 12792 | (goto-char (match-beginning 0)) | ||
| 12793 | (if (org-invisible-p) (org-show-context))) | ||
| 12794 | (goto-char pos) | ||
| 12795 | (setq org-link-search-failed t) | ||
| 12796 | (error "No further link found")))) | ||
| 12797 | |||
| 12798 | (defun org-find-file-at-mouse (ev) | ||
| 12799 | "Open file link or URL at mouse." | ||
| 12800 | (interactive "e") | ||
| 12801 | (mouse-set-point ev) | ||
| 12802 | (org-open-at-point 'in-emacs)) | ||
| 12803 | |||
| 12804 | (defun org-open-at-mouse (ev) | ||
| 12805 | "Open file link or URL at mouse." | ||
| 12806 | (interactive "e") | ||
| 12807 | (mouse-set-point ev) | ||
| 12808 | (org-open-at-point)) | ||
| 12809 | |||
| 12810 | (defvar org-window-config-before-follow-link nil | ||
| 12811 | "The window configuration before following a link. | ||
| 12812 | This is saved in case the need arises to restore it.") | ||
| 12813 | |||
| 12814 | (defvar org-open-link-marker (make-marker) | ||
| 12815 | "Marker pointing to the location where `org-open-at-point; was called.") | ||
| 12816 | |||
| 12817 | ;;;###autoload | ||
| 12818 | (defun org-open-at-point-global () | ||
| 12819 | "Follow a link like Org-mode does. | ||
| 12820 | This command can be called in any mode to follow a link that has | ||
| 12821 | Org-mode syntax." | ||
| 12822 | (interactive) | ||
| 12823 | (org-run-like-in-org-mode 'org-open-at-point)) | ||
| 12824 | |||
| 12825 | (defun org-open-at-point (&optional in-emacs) | ||
| 12826 | "Open link at or after point. | ||
| 12827 | If there is no link at point, this function will search forward up to | ||
| 12828 | the end of the current subtree. | ||
| 12829 | Normally, files will be opened by an appropriate application. If the | ||
| 12830 | optional argument IN-EMACS is non-nil, Emacs will visit the file." | ||
| 12831 | (interactive "P") | ||
| 12832 | (require 'org-irc) | ||
| 12833 | (move-marker org-open-link-marker (point)) | ||
| 12834 | (setq org-window-config-before-follow-link (current-window-configuration)) | ||
| 12835 | (org-remove-occur-highlights nil nil t) | ||
| 12836 | (if (org-at-timestamp-p t) | ||
| 12837 | (org-follow-timestamp-link) | ||
| 12838 | (let (type path link line search (pos (point))) | ||
| 12839 | (catch 'match | ||
| 12840 | (save-excursion | ||
| 12841 | (skip-chars-forward "^]\n\r") | ||
| 12842 | (when (org-in-regexp org-bracket-link-regexp) | ||
| 12843 | (setq link (org-link-unescape (org-match-string-no-properties 1))) | ||
| 12844 | (while (string-match " *\n *" link) | ||
| 12845 | (setq link (replace-match " " t t link))) | ||
| 12846 | (setq link (org-link-expand-abbrev link)) | ||
| 12847 | (if (string-match org-link-re-with-space2 link) | ||
| 12848 | (setq type (match-string 1 link) path (match-string 2 link)) | ||
| 12849 | (setq type "thisfile" path link)) | ||
| 12850 | (throw 'match t))) | ||
| 12851 | |||
| 12852 | (when (get-text-property (point) 'org-linked-text) | ||
| 12853 | (setq type "thisfile" | ||
| 12854 | pos (if (get-text-property (1+ (point)) 'org-linked-text) | ||
| 12855 | (1+ (point)) (point)) | ||
| 12856 | path (buffer-substring | ||
| 12857 | (previous-single-property-change pos 'org-linked-text) | ||
| 12858 | (next-single-property-change pos 'org-linked-text))) | ||
| 12859 | (throw 'match t)) | ||
| 12860 | |||
| 12861 | (save-excursion | ||
| 12862 | (when (or (org-in-regexp org-angle-link-re) | ||
| 12863 | (org-in-regexp org-plain-link-re)) | ||
| 12864 | (setq type (match-string 1) path (match-string 2)) | ||
| 12865 | (throw 'match t))) | ||
| 12866 | (when (org-in-regexp "\\<\\([^><\n]+\\)\\>") | ||
| 12867 | (setq type "tree-match" | ||
| 12868 | path (match-string 1)) | ||
| 12869 | (throw 'match t)) | ||
| 12870 | (save-excursion | ||
| 12871 | (when (org-in-regexp (org-re "\\(:[[:alnum:]_@:]+\\):[ \t]*$")) | ||
| 12872 | (setq type "tags" | ||
| 12873 | path (match-string 1)) | ||
| 12874 | (while (string-match ":" path) | ||
| 12875 | (setq path (replace-match "+" t t path))) | ||
| 12876 | (throw 'match t)))) | ||
| 12877 | (unless path | ||
| 12878 | (error "No link found")) | ||
| 12879 | ;; Remove any trailing spaces in path | ||
| 12880 | (if (string-match " +\\'" path) | ||
| 12881 | (setq path (replace-match "" t t path))) | ||
| 12882 | |||
| 12883 | (cond | ||
| 12884 | |||
| 12885 | ((assoc type org-link-protocols) | ||
| 12886 | (funcall (nth 1 (assoc type org-link-protocols)) path)) | ||
| 12887 | |||
| 12888 | ((equal type "mailto") | ||
| 12889 | (let ((cmd (car org-link-mailto-program)) | ||
| 12890 | (args (cdr org-link-mailto-program)) args1 | ||
| 12891 | (address path) (subject "") a) | ||
| 12892 | (if (string-match "\\(.*\\)::\\(.*\\)" path) | ||
| 12893 | (setq address (match-string 1 path) | ||
| 12894 | subject (org-link-escape (match-string 2 path)))) | ||
| 12895 | (while args | ||
| 12896 | (cond | ||
| 12897 | ((not (stringp (car args))) (push (pop args) args1)) | ||
| 12898 | (t (setq a (pop args)) | ||
| 12899 | (if (string-match "%a" a) | ||
| 12900 | (setq a (replace-match address t t a))) | ||
| 12901 | (if (string-match "%s" a) | ||
| 12902 | (setq a (replace-match subject t t a))) | ||
| 12903 | (push a args1)))) | ||
| 12904 | (apply cmd (nreverse args1)))) | ||
| 12905 | |||
| 12906 | ((member type '("http" "https" "ftp" "news")) | ||
| 12907 | (browse-url (concat type ":" (org-link-escape | ||
| 12908 | path org-link-escape-chars-browser)))) | ||
| 12909 | |||
| 12910 | ((member type '("message")) | ||
| 12911 | (browse-url (concat type ":" path))) | ||
| 12912 | |||
| 12913 | ((string= type "tags") | ||
| 12914 | (org-tags-view in-emacs path)) | ||
| 12915 | ((string= type "thisfile") | ||
| 12916 | (if in-emacs | ||
| 12917 | (switch-to-buffer-other-window | ||
| 12918 | (org-get-buffer-for-internal-link (current-buffer))) | ||
| 12919 | (org-mark-ring-push)) | ||
| 12920 | (let ((cmd `(org-link-search | ||
| 12921 | ,path | ||
| 12922 | ,(cond ((equal in-emacs '(4)) 'occur) | ||
| 12923 | ((equal in-emacs '(16)) 'org-occur) | ||
| 12924 | (t nil)) | ||
| 12925 | ,pos))) | ||
| 12926 | (condition-case nil (eval cmd) | ||
| 12927 | (error (progn (widen) (eval cmd)))))) | ||
| 12928 | |||
| 12929 | ((string= type "tree-match") | ||
| 12930 | (org-occur (concat "\\[" (regexp-quote path) "\\]"))) | ||
| 12931 | |||
| 12932 | ((string= type "file") | ||
| 12933 | (if (string-match "::\\([0-9]+\\)\\'" path) | ||
| 12934 | (setq line (string-to-number (match-string 1 path)) | ||
| 12935 | path (substring path 0 (match-beginning 0))) | ||
| 12936 | (if (string-match "::\\(.+\\)\\'" path) | ||
| 12937 | (setq search (match-string 1 path) | ||
| 12938 | path (substring path 0 (match-beginning 0))))) | ||
| 12939 | (if (string-match "[*?{]" (file-name-nondirectory path)) | ||
| 12940 | (dired path) | ||
| 12941 | (org-open-file path in-emacs line search))) | ||
| 12942 | |||
| 12943 | ((string= type "news") | ||
| 12944 | (org-follow-gnus-link path)) | ||
| 12945 | |||
| 12946 | ((string= type "bbdb") | ||
| 12947 | (org-follow-bbdb-link path)) | ||
| 12948 | |||
| 12949 | ((string= type "info") | ||
| 12950 | (org-follow-info-link path)) | ||
| 12951 | |||
| 12952 | ((string= type "gnus") | ||
| 12953 | (let (group article) | ||
| 12954 | (if (not (string-match "\\`\\([^#]+\\)\\(#\\(.*\\)\\)?" path)) | ||
| 12955 | (error "Error in Gnus link")) | ||
| 12956 | (setq group (match-string 1 path) | ||
| 12957 | article (match-string 3 path)) | ||
| 12958 | (org-follow-gnus-link group article))) | ||
| 12959 | |||
| 12960 | ((string= type "vm") | ||
| 12961 | (let (folder article) | ||
| 12962 | (if (not (string-match "\\`\\([^#]+\\)\\(#\\(.*\\)\\)?" path)) | ||
| 12963 | (error "Error in VM link")) | ||
| 12964 | (setq folder (match-string 1 path) | ||
| 12965 | article (match-string 3 path)) | ||
| 12966 | ;; in-emacs is the prefix arg, will be interpreted as read-only | ||
| 12967 | (org-follow-vm-link folder article in-emacs))) | ||
| 12968 | |||
| 12969 | ((string= type "wl") | ||
| 12970 | (let (folder article) | ||
| 12971 | (if (not (string-match "\\`\\([^#]+\\)\\(#\\(.*\\)\\)?" path)) | ||
| 12972 | (error "Error in Wanderlust link")) | ||
| 12973 | (setq folder (match-string 1 path) | ||
| 12974 | article (match-string 3 path)) | ||
| 12975 | (org-follow-wl-link folder article))) | ||
| 12976 | |||
| 12977 | ((string= type "mhe") | ||
| 12978 | (let (folder article) | ||
| 12979 | (if (not (string-match "\\`\\([^#]+\\)\\(#\\(.*\\)\\)?" path)) | ||
| 12980 | (error "Error in MHE link")) | ||
| 12981 | (setq folder (match-string 1 path) | ||
| 12982 | article (match-string 3 path)) | ||
| 12983 | (org-follow-mhe-link folder article))) | ||
| 12984 | |||
| 12985 | ((string= type "rmail") | ||
| 12986 | (let (folder article) | ||
| 12987 | (if (not (string-match "\\`\\([^#]+\\)\\(#\\(.*\\)\\)?" path)) | ||
| 12988 | (error "Error in RMAIL link")) | ||
| 12989 | (setq folder (match-string 1 path) | ||
| 12990 | article (match-string 3 path)) | ||
| 12991 | (org-follow-rmail-link folder article))) | ||
| 12992 | |||
| 12993 | ((string= type "shell") | ||
| 12994 | (let ((cmd path)) | ||
| 12995 | (if (or (not org-confirm-shell-link-function) | ||
| 12996 | (funcall org-confirm-shell-link-function | ||
| 12997 | (format "Execute \"%s\" in shell? " | ||
| 12998 | (org-add-props cmd nil | ||
| 12999 | 'face 'org-warning)))) | ||
| 13000 | (progn | ||
| 13001 | (message "Executing %s" cmd) | ||
| 13002 | (shell-command cmd)) | ||
| 13003 | (error "Abort")))) | ||
| 13004 | |||
| 13005 | ((string= type "elisp") | ||
| 13006 | (let ((cmd path)) | ||
| 13007 | (if (or (not org-confirm-elisp-link-function) | ||
| 13008 | (funcall org-confirm-elisp-link-function | ||
| 13009 | (format "Execute \"%s\" as elisp? " | ||
| 13010 | (org-add-props cmd nil | ||
| 13011 | 'face 'org-warning)))) | ||
| 13012 | (message "%s => %s" cmd (eval (read cmd))) | ||
| 13013 | (error "Abort")))) | ||
| 13014 | |||
| 13015 | (t | ||
| 13016 | (browse-url-at-point))))) | ||
| 13017 | (move-marker org-open-link-marker nil) | ||
| 13018 | (run-hook-with-args 'org-follow-link-hook)) | ||
| 13019 | |||
| 13020 | ;;; File search | ||
| 13021 | |||
| 13022 | (defvar org-create-file-search-functions nil | ||
| 13023 | "List of functions to construct the right search string for a file link. | ||
| 13024 | These functions are called in turn with point at the location to | ||
| 13025 | which the link should point. | ||
| 13026 | |||
| 13027 | A function in the hook should first test if it would like to | ||
| 13028 | handle this file type, for example by checking the major-mode or | ||
| 13029 | the file extension. If it decides not to handle this file, it | ||
| 13030 | should just return nil to give other functions a chance. If it | ||
| 13031 | does handle the file, it must return the search string to be used | ||
| 13032 | when following the link. The search string will be part of the | ||
| 13033 | file link, given after a double colon, and `org-open-at-point' | ||
| 13034 | will automatically search for it. If special measures must be | ||
| 13035 | taken to make the search successful, another function should be | ||
| 13036 | added to the companion hook `org-execute-file-search-functions', | ||
| 13037 | which see. | ||
| 13038 | |||
| 13039 | A function in this hook may also use `setq' to set the variable | ||
| 13040 | `description' to provide a suggestion for the descriptive text to | ||
| 13041 | be used for this link when it gets inserted into an Org-mode | ||
| 13042 | buffer with \\[org-insert-link].") | ||
| 13043 | |||
| 13044 | (defvar org-execute-file-search-functions nil | ||
| 13045 | "List of functions to execute a file search triggered by a link. | ||
| 13046 | |||
| 13047 | Functions added to this hook must accept a single argument, the | ||
| 13048 | search string that was part of the file link, the part after the | ||
| 13049 | double colon. The function must first check if it would like to | ||
| 13050 | handle this search, for example by checking the major-mode or the | ||
| 13051 | file extension. If it decides not to handle this search, it | ||
| 13052 | should just return nil to give other functions a chance. If it | ||
| 13053 | does handle the search, it must return a non-nil value to keep | ||
| 13054 | other functions from trying. | ||
| 13055 | |||
| 13056 | Each function can access the current prefix argument through the | ||
| 13057 | variable `current-prefix-argument'. Note that a single prefix is | ||
| 13058 | used to force opening a link in Emacs, so it may be good to only | ||
| 13059 | use a numeric or double prefix to guide the search function. | ||
| 13060 | |||
| 13061 | In case this is needed, a function in this hook can also restore | ||
| 13062 | the window configuration before `org-open-at-point' was called using: | ||
| 13063 | |||
| 13064 | (set-window-configuration org-window-config-before-follow-link)") | ||
| 13065 | |||
| 13066 | (defun org-link-search (s &optional type avoid-pos) | ||
| 13067 | "Search for a link search option. | ||
| 13068 | If S is surrounded by forward slashes, it is interpreted as a | ||
| 13069 | regular expression. In org-mode files, this will create an `org-occur' | ||
| 13070 | sparse tree. In ordinary files, `occur' will be used to list matches. | ||
| 13071 | If the current buffer is in `dired-mode', grep will be used to search | ||
| 13072 | in all files. If AVOID-POS is given, ignore matches near that position." | ||
| 13073 | (let ((case-fold-search t) | ||
| 13074 | (s0 (mapconcat 'identity (org-split-string s "[ \t\r\n]+") " ")) | ||
| 13075 | (markers (concat "\\(?:" (mapconcat (lambda (x) (regexp-quote (car x))) | ||
| 13076 | (append '(("") (" ") ("\t") ("\n")) | ||
| 13077 | org-emphasis-alist) | ||
| 13078 | "\\|") "\\)")) | ||
| 13079 | (pos (point)) | ||
| 13080 | (pre "") (post "") | ||
| 13081 | words re0 re1 re2 re3 re4 re5 re2a reall) | ||
| 13082 | (cond | ||
| 13083 | ;; First check if there are any special | ||
| 13084 | ((run-hook-with-args-until-success 'org-execute-file-search-functions s)) | ||
| 13085 | ;; Now try the builtin stuff | ||
| 13086 | ((save-excursion | ||
| 13087 | (goto-char (point-min)) | ||
| 13088 | (and | ||
| 13089 | (re-search-forward | ||
| 13090 | (concat "<<" (regexp-quote s0) ">>") nil t) | ||
| 13091 | (setq pos (match-beginning 0)))) | ||
| 13092 | ;; There is an exact target for this | ||
| 13093 | (goto-char pos)) | ||
| 13094 | ((string-match "^/\\(.*\\)/$" s) | ||
| 13095 | ;; A regular expression | ||
| 13096 | (cond | ||
| 13097 | ((org-mode-p) | ||
| 13098 | (org-occur (match-string 1 s))) | ||
| 13099 | ;;((eq major-mode 'dired-mode) | ||
| 13100 | ;; (grep (concat "grep -n -e '" (match-string 1 s) "' *"))) | ||
| 13101 | (t (org-do-occur (match-string 1 s))))) | ||
| 13102 | (t | ||
| 13103 | ;; A normal search strings | ||
| 13104 | (when (equal (string-to-char s) ?*) | ||
| 13105 | ;; Anchor on headlines, post may include tags. | ||
| 13106 | (setq pre "^\\*+[ \t]+\\(?:\\sw+\\)?[ \t]*" | ||
| 13107 | post (org-re "[ \t]*\\(?:[ \t]+:[[:alnum:]_@:+]:[ \t]*\\)?$") | ||
| 13108 | s (substring s 1))) | ||
| 13109 | (remove-text-properties | ||
| 13110 | 0 (length s) | ||
| 13111 | '(face nil mouse-face nil keymap nil fontified nil) s) | ||
| 13112 | ;; Make a series of regular expressions to find a match | ||
| 13113 | (setq words (org-split-string s "[ \n\r\t]+") | ||
| 13114 | re0 (concat "\\(<<" (regexp-quote s0) ">>\\)") | ||
| 13115 | re2 (concat markers "\\(" (mapconcat 'downcase words "[ \t]+") | ||
| 13116 | "\\)" markers) | ||
| 13117 | re2a (concat "[ \t\r\n]\\(" (mapconcat 'downcase words "[ \t\r\n]+") "\\)[ \t\r\n]") | ||
| 13118 | re4 (concat "[^a-zA-Z_]\\(" (mapconcat 'downcase words "[^a-zA-Z_\r\n]+") "\\)[^a-zA-Z_]") | ||
| 13119 | re1 (concat pre re2 post) | ||
| 13120 | re3 (concat pre re4 post) | ||
| 13121 | re5 (concat pre ".*" re4) | ||
| 13122 | re2 (concat pre re2) | ||
| 13123 | re2a (concat pre re2a) | ||
| 13124 | re4 (concat pre re4) | ||
| 13125 | reall (concat "\\(" re0 "\\)\\|\\(" re1 "\\)\\|\\(" re2 | ||
| 13126 | "\\)\\|\\(" re3 "\\)\\|\\(" re4 "\\)\\|\\(" | ||
| 13127 | re5 "\\)" | ||
| 13128 | )) | ||
| 13129 | (cond | ||
| 13130 | ((eq type 'org-occur) (org-occur reall)) | ||
| 13131 | ((eq type 'occur) (org-do-occur (downcase reall) 'cleanup)) | ||
| 13132 | (t (goto-char (point-min)) | ||
| 13133 | (if (or (org-search-not-self 1 re0 nil t) | ||
| 13134 | (org-search-not-self 1 re1 nil t) | ||
| 13135 | (org-search-not-self 1 re2 nil t) | ||
| 13136 | (org-search-not-self 1 re2a nil t) | ||
| 13137 | (org-search-not-self 1 re3 nil t) | ||
| 13138 | (org-search-not-self 1 re4 nil t) | ||
| 13139 | (org-search-not-self 1 re5 nil t) | ||
| 13140 | ) | ||
| 13141 | (goto-char (match-beginning 1)) | ||
| 13142 | (goto-char pos) | ||
| 13143 | (error "No match"))))) | ||
| 13144 | (t | ||
| 13145 | ;; Normal string-search | ||
| 13146 | (goto-char (point-min)) | ||
| 13147 | (if (search-forward s nil t) | ||
| 13148 | (goto-char (match-beginning 0)) | ||
| 13149 | (error "No match")))) | ||
| 13150 | (and (org-mode-p) (org-show-context 'link-search)))) | ||
| 13151 | |||
| 13152 | (defun org-search-not-self (group &rest args) | ||
| 13153 | "Execute `re-search-forward', but only accept matches that do not | ||
| 13154 | enclose the position of `org-open-link-marker'." | ||
| 13155 | (let ((m org-open-link-marker)) | ||
| 13156 | (catch 'exit | ||
| 13157 | (while (apply 're-search-forward args) | ||
| 13158 | (unless (get-text-property (match-end group) 'intangible) ; Emacs 21 | ||
| 13159 | (goto-char (match-end group)) | ||
| 13160 | (if (and (or (not (eq (marker-buffer m) (current-buffer))) | ||
| 13161 | (> (match-beginning 0) (marker-position m)) | ||
| 13162 | (< (match-end 0) (marker-position m))) | ||
| 13163 | (save-match-data | ||
| 13164 | (or (not (org-in-regexp | ||
| 13165 | org-bracket-link-analytic-regexp 1)) | ||
| 13166 | (not (match-end 4)) ; no description | ||
| 13167 | (and (<= (match-beginning 4) (point)) | ||
| 13168 | (>= (match-end 4) (point)))))) | ||
| 13169 | (throw 'exit (point)))))))) | ||
| 13170 | |||
| 13171 | (defun org-get-buffer-for-internal-link (buffer) | ||
| 13172 | "Return a buffer to be used for displaying the link target of internal links." | ||
| 13173 | (cond | ||
| 13174 | ((not org-display-internal-link-with-indirect-buffer) | ||
| 13175 | buffer) | ||
| 13176 | ((string-match "(Clone)$" (buffer-name buffer)) | ||
| 13177 | (message "Buffer is already a clone, not making another one") | ||
| 13178 | ;; we also do not modify visibility in this case | ||
| 13179 | buffer) | ||
| 13180 | (t ; make a new indirect buffer for displaying the link | ||
| 13181 | (let* ((bn (buffer-name buffer)) | ||
| 13182 | (ibn (concat bn "(Clone)")) | ||
| 13183 | (ib (or (get-buffer ibn) (make-indirect-buffer buffer ibn 'clone)))) | ||
| 13184 | (with-current-buffer ib (org-overview)) | ||
| 13185 | ib)))) | ||
| 13186 | |||
| 13187 | (defun org-do-occur (regexp &optional cleanup) | ||
| 13188 | "Call the Emacs command `occur'. | ||
| 13189 | If CLEANUP is non-nil, remove the printout of the regular expression | ||
| 13190 | in the *Occur* buffer. This is useful if the regex is long and not useful | ||
| 13191 | to read." | ||
| 13192 | (occur regexp) | ||
| 13193 | (when cleanup | ||
| 13194 | (let ((cwin (selected-window)) win beg end) | ||
| 13195 | (when (setq win (get-buffer-window "*Occur*")) | ||
| 13196 | (select-window win)) | ||
| 13197 | (goto-char (point-min)) | ||
| 13198 | (when (re-search-forward "match[a-z]+" nil t) | ||
| 13199 | (setq beg (match-end 0)) | ||
| 13200 | (if (re-search-forward "^[ \t]*[0-9]+" nil t) | ||
| 13201 | (setq end (1- (match-beginning 0))))) | ||
| 13202 | (and beg end (let ((inhibit-read-only t)) (delete-region beg end))) | ||
| 13203 | (goto-char (point-min)) | ||
| 13204 | (select-window cwin)))) | ||
| 13205 | |||
| 13206 | ;;; The mark ring for links jumps | ||
| 13207 | |||
| 13208 | (defvar org-mark-ring nil | ||
| 13209 | "Mark ring for positions before jumps in Org-mode.") | ||
| 13210 | (defvar org-mark-ring-last-goto nil | ||
| 13211 | "Last position in the mark ring used to go back.") | ||
| 13212 | ;; Fill and close the ring | ||
| 13213 | (setq org-mark-ring nil org-mark-ring-last-goto nil) ;; in case file is reloaded | ||
| 13214 | (loop for i from 1 to org-mark-ring-length do | ||
| 13215 | (push (make-marker) org-mark-ring)) | ||
| 13216 | (setcdr (nthcdr (1- org-mark-ring-length) org-mark-ring) | ||
| 13217 | org-mark-ring) | ||
| 13218 | |||
| 13219 | (defun org-mark-ring-push (&optional pos buffer) | ||
| 13220 | "Put the current position or POS into the mark ring and rotate it." | ||
| 13221 | (interactive) | ||
| 13222 | (setq pos (or pos (point))) | ||
| 13223 | (setq org-mark-ring (nthcdr (1- org-mark-ring-length) org-mark-ring)) | ||
| 13224 | (move-marker (car org-mark-ring) | ||
| 13225 | (or pos (point)) | ||
| 13226 | (or buffer (current-buffer))) | ||
| 13227 | (message "%s" | ||
| 13228 | (substitute-command-keys | ||
| 13229 | "Position saved to mark ring, go back with \\[org-mark-ring-goto]."))) | ||
| 13230 | |||
| 13231 | (defun org-mark-ring-goto (&optional n) | ||
| 13232 | "Jump to the previous position in the mark ring. | ||
| 13233 | With prefix arg N, jump back that many stored positions. When | ||
| 13234 | called several times in succession, walk through the entire ring. | ||
| 13235 | Org-mode commands jumping to a different position in the current file, | ||
| 13236 | or to another Org-mode file, automatically push the old position | ||
| 13237 | onto the ring." | ||
| 13238 | (interactive "p") | ||
| 13239 | (let (p m) | ||
| 13240 | (if (eq last-command this-command) | ||
| 13241 | (setq p (nthcdr n (or org-mark-ring-last-goto org-mark-ring))) | ||
| 13242 | (setq p org-mark-ring)) | ||
| 13243 | (setq org-mark-ring-last-goto p) | ||
| 13244 | (setq m (car p)) | ||
| 13245 | (switch-to-buffer (marker-buffer m)) | ||
| 13246 | (goto-char m) | ||
| 13247 | (if (or (org-invisible-p) (org-invisible-p2)) (org-show-context 'mark-goto)))) | ||
| 13248 | |||
| 13249 | (defun org-remove-angle-brackets (s) | ||
| 13250 | (if (equal (substring s 0 1) "<") (setq s (substring s 1))) | ||
| 13251 | (if (equal (substring s -1) ">") (setq s (substring s 0 -1))) | ||
| 13252 | s) | ||
| 13253 | (defun org-add-angle-brackets (s) | ||
| 13254 | (if (equal (substring s 0 1) "<") nil (setq s (concat "<" s))) | ||
| 13255 | (if (equal (substring s -1) ">") nil (setq s (concat s ">"))) | ||
| 13256 | s) | ||
| 13257 | |||
| 13258 | ;;; Following specific links | ||
| 13259 | |||
| 13260 | (defun org-follow-timestamp-link () | ||
| 13261 | (cond | ||
| 13262 | ((org-at-date-range-p t) | ||
| 13263 | (let ((org-agenda-start-on-weekday) | ||
| 13264 | (t1 (match-string 1)) | ||
| 13265 | (t2 (match-string 2))) | ||
| 13266 | (setq t1 (time-to-days (org-time-string-to-time t1)) | ||
| 13267 | t2 (time-to-days (org-time-string-to-time t2))) | ||
| 13268 | (org-agenda-list nil t1 (1+ (- t2 t1))))) | ||
| 13269 | ((org-at-timestamp-p t) | ||
| 13270 | (org-agenda-list nil (time-to-days (org-time-string-to-time | ||
| 13271 | (substring (match-string 1) 0 10))) | ||
| 13272 | 1)) | ||
| 13273 | (t (error "This should not happen")))) | ||
| 13274 | |||
| 13275 | |||
| 13276 | (defun org-follow-bbdb-link (name) | ||
| 13277 | "Follow a BBDB link to NAME." | ||
| 13278 | (require 'bbdb) | ||
| 13279 | (let ((inhibit-redisplay (not debug-on-error)) | ||
| 13280 | (bbdb-electric-p nil)) | ||
| 13281 | (catch 'exit | ||
| 13282 | ;; Exact match on name | ||
| 13283 | (bbdb-name (concat "\\`" name "\\'") nil) | ||
| 13284 | (if (< 0 (buffer-size (get-buffer "*BBDB*"))) (throw 'exit nil)) | ||
| 13285 | ;; Exact match on name | ||
| 13286 | (bbdb-company (concat "\\`" name "\\'") nil) | ||
| 13287 | (if (< 0 (buffer-size (get-buffer "*BBDB*"))) (throw 'exit nil)) | ||
| 13288 | ;; Partial match on name | ||
| 13289 | (bbdb-name name nil) | ||
| 13290 | (if (< 0 (buffer-size (get-buffer "*BBDB*"))) (throw 'exit nil)) | ||
| 13291 | ;; Partial match on company | ||
| 13292 | (bbdb-company name nil) | ||
| 13293 | (if (< 0 (buffer-size (get-buffer "*BBDB*"))) (throw 'exit nil)) | ||
| 13294 | ;; General match including network address and notes | ||
| 13295 | (bbdb name nil) | ||
| 13296 | (when (= 0 (buffer-size (get-buffer "*BBDB*"))) | ||
| 13297 | (delete-window (get-buffer-window "*BBDB*")) | ||
| 13298 | (error "No matching BBDB record"))))) | ||
| 13299 | |||
| 13300 | (defun org-follow-info-link (name) | ||
| 13301 | "Follow an info file & node link to NAME." | ||
| 13302 | (if (or (string-match "\\(.*\\)::?\\(.*\\)" name) | ||
| 13303 | (string-match "\\(.*\\)" name)) | ||
| 13304 | (progn | ||
| 13305 | (require 'info) | ||
| 13306 | (if (match-string 2 name) ; If there isn't a node, choose "Top" | ||
| 13307 | (Info-find-node (match-string 1 name) (match-string 2 name)) | ||
| 13308 | (Info-find-node (match-string 1 name) "Top"))) | ||
| 13309 | (message "Could not open: %s" name))) | ||
| 13310 | |||
| 13311 | (defun org-follow-gnus-link (&optional group article) | ||
| 13312 | "Follow a Gnus link to GROUP and ARTICLE." | ||
| 13313 | (require 'gnus) | ||
| 13314 | (funcall (cdr (assq 'gnus org-link-frame-setup))) | ||
| 13315 | (if gnus-other-frame-object (select-frame gnus-other-frame-object)) | ||
| 13316 | (cond ((and group article) | ||
| 13317 | (gnus-group-read-group 1 nil group) | ||
| 13318 | (gnus-summary-goto-article (string-to-number article) nil t)) | ||
| 13319 | (group (gnus-group-jump-to-group group)))) | ||
| 13320 | |||
| 13321 | (defun org-follow-vm-link (&optional folder article readonly) | ||
| 13322 | "Follow a VM link to FOLDER and ARTICLE." | ||
| 13323 | (require 'vm) | ||
| 13324 | (setq article (org-add-angle-brackets article)) | ||
| 13325 | (if (string-match "^//\\([a-zA-Z]+@\\)?\\([^:]+\\):\\(.*\\)" folder) | ||
| 13326 | ;; ange-ftp or efs or tramp access | ||
| 13327 | (let ((user (or (match-string 1 folder) (user-login-name))) | ||
| 13328 | (host (match-string 2 folder)) | ||
| 13329 | (file (match-string 3 folder))) | ||
| 13330 | (cond | ||
| 13331 | ((featurep 'tramp) | ||
| 13332 | ;; use tramp to access the file | ||
| 13333 | (if (featurep 'xemacs) | ||
| 13334 | (setq folder (format "[%s@%s]%s" user host file)) | ||
| 13335 | (setq folder (format "/%s@%s:%s" user host file)))) | ||
| 13336 | (t | ||
| 13337 | ;; use ange-ftp or efs | ||
| 13338 | (require (if (featurep 'xemacs) 'efs 'ange-ftp)) | ||
| 13339 | (setq folder (format "/%s@%s:%s" user host file)))))) | ||
| 13340 | (when folder | ||
| 13341 | (funcall (cdr (assq 'vm org-link-frame-setup)) folder readonly) | ||
| 13342 | (sit-for 0.1) | ||
| 13343 | (when article | ||
| 13344 | (vm-select-folder-buffer) | ||
| 13345 | (widen) | ||
| 13346 | (let ((case-fold-search t)) | ||
| 13347 | (goto-char (point-min)) | ||
| 13348 | (if (not (re-search-forward | ||
| 13349 | (concat "^" "message-id: *" (regexp-quote article)))) | ||
| 13350 | (error "Could not find the specified message in this folder")) | ||
| 13351 | (vm-isearch-update) | ||
| 13352 | (vm-isearch-narrow) | ||
| 13353 | (vm-beginning-of-message) | ||
| 13354 | (vm-summarize))))) | ||
| 13355 | |||
| 13356 | (defun org-follow-wl-link (folder article) | ||
| 13357 | "Follow a Wanderlust link to FOLDER and ARTICLE." | ||
| 13358 | (if (and (string= folder "%") | ||
| 13359 | article | ||
| 13360 | (string-match "^\\([^#]+\\)\\(#\\(.*\\)\\)?" article)) | ||
| 13361 | ;; XXX: imap-uw supports folders starting with '#' such as "#mh/inbox". | ||
| 13362 | ;; Thus, we recompose folder and article ids. | ||
| 13363 | (setq folder (format "%s#%s" folder (match-string 1 article)) | ||
| 13364 | article (match-string 3 article))) | ||
| 13365 | (if (not (elmo-folder-exists-p (wl-folder-get-elmo-folder folder))) | ||
| 13366 | (error "No such folder: %s" folder)) | ||
| 13367 | (wl-summary-goto-folder-subr folder 'no-sync t nil t nil nil) | ||
| 13368 | (and article | ||
| 13369 | (wl-summary-jump-to-msg-by-message-id (org-add-angle-brackets article)) | ||
| 13370 | (wl-summary-redisplay))) | ||
| 13371 | |||
| 13372 | (defun org-follow-rmail-link (folder article) | ||
| 13373 | "Follow an RMAIL link to FOLDER and ARTICLE." | ||
| 13374 | (setq article (org-add-angle-brackets article)) | ||
| 13375 | (let (message-number) | ||
| 13376 | (save-excursion | ||
| 13377 | (save-window-excursion | ||
| 13378 | (rmail (if (string= folder "RMAIL") rmail-file-name folder)) | ||
| 13379 | (setq message-number | ||
| 13380 | (save-restriction | ||
| 13381 | (widen) | ||
| 13382 | (goto-char (point-max)) | ||
| 13383 | (if (re-search-backward | ||
| 13384 | (concat "^Message-ID:\\s-+" (regexp-quote | ||
| 13385 | (or article ""))) | ||
| 13386 | nil t) | ||
| 13387 | (rmail-what-message)))))) | ||
| 13388 | (if message-number | ||
| 13389 | (progn | ||
| 13390 | (rmail (if (string= folder "RMAIL") rmail-file-name folder)) | ||
| 13391 | (rmail-show-message message-number) | ||
| 13392 | message-number) | ||
| 13393 | (error "Message not found")))) | ||
| 13394 | |||
| 13395 | ;;; mh-e integration based on planner-mode | ||
| 13396 | (defun org-mhe-get-message-real-folder () | ||
| 13397 | "Return the name of the current message real folder, so if you use | ||
| 13398 | sequences, it will now work." | ||
| 13399 | (save-excursion | ||
| 13400 | (let* ((folder | ||
| 13401 | (if (equal major-mode 'mh-folder-mode) | ||
| 13402 | mh-current-folder | ||
| 13403 | ;; Refer to the show buffer | ||
| 13404 | mh-show-folder-buffer)) | ||
| 13405 | (end-index | ||
| 13406 | (if (boundp 'mh-index-folder) | ||
| 13407 | (min (length mh-index-folder) (length folder)))) | ||
| 13408 | ) | ||
| 13409 | ;; a simple test on mh-index-data does not work, because | ||
| 13410 | ;; mh-index-data is always nil in a show buffer. | ||
| 13411 | (if (and (boundp 'mh-index-folder) | ||
| 13412 | (string= mh-index-folder (substring folder 0 end-index))) | ||
| 13413 | (if (equal major-mode 'mh-show-mode) | ||
| 13414 | (save-window-excursion | ||
| 13415 | (let (pop-up-frames) | ||
| 13416 | (when (buffer-live-p (get-buffer folder)) | ||
| 13417 | (progn | ||
| 13418 | (pop-to-buffer folder) | ||
| 13419 | (org-mhe-get-message-folder-from-index) | ||
| 13420 | ) | ||
| 13421 | ))) | ||
| 13422 | (org-mhe-get-message-folder-from-index) | ||
| 13423 | ) | ||
| 13424 | folder | ||
| 13425 | ) | ||
| 13426 | ))) | ||
| 13427 | |||
| 13428 | (defun org-mhe-get-message-folder-from-index () | ||
| 13429 | "Returns the name of the message folder in a index folder buffer." | ||
| 13430 | (save-excursion | ||
| 13431 | (mh-index-previous-folder) | ||
| 13432 | (re-search-forward "^\\(+.*\\)$" nil t) | ||
| 13433 | (message "%s" (match-string 1)))) | ||
| 13434 | |||
| 13435 | (defun org-mhe-get-message-folder () | ||
| 13436 | "Return the name of the current message folder. Be careful if you | ||
| 13437 | use sequences." | ||
| 13438 | (save-excursion | ||
| 13439 | (if (equal major-mode 'mh-folder-mode) | ||
| 13440 | mh-current-folder | ||
| 13441 | ;; Refer to the show buffer | ||
| 13442 | mh-show-folder-buffer))) | ||
| 13443 | |||
| 13444 | (defun org-mhe-get-message-num () | ||
| 13445 | "Return the number of the current message. Be careful if you | ||
| 13446 | use sequences." | ||
| 13447 | (save-excursion | ||
| 13448 | (if (equal major-mode 'mh-folder-mode) | ||
| 13449 | (mh-get-msg-num nil) | ||
| 13450 | ;; Refer to the show buffer | ||
| 13451 | (mh-show-buffer-message-number)))) | ||
| 13452 | |||
| 13453 | (defun org-mhe-get-header (header) | ||
| 13454 | "Return a header of the message in folder mode. This will create a | ||
| 13455 | show buffer for the corresponding message. If you have a more clever | ||
| 13456 | idea..." | ||
| 13457 | (let* ((folder (org-mhe-get-message-folder)) | ||
| 13458 | (num (org-mhe-get-message-num)) | ||
| 13459 | (buffer (get-buffer-create (concat "show-" folder))) | ||
| 13460 | (header-field)) | ||
| 13461 | (with-current-buffer buffer | ||
| 13462 | (mh-display-msg num folder) | ||
| 13463 | (if (equal major-mode 'mh-folder-mode) | ||
| 13464 | (mh-header-display) | ||
| 13465 | (mh-show-header-display)) | ||
| 13466 | (set-buffer buffer) | ||
| 13467 | (setq header-field (mh-get-header-field header)) | ||
| 13468 | (if (equal major-mode 'mh-folder-mode) | ||
| 13469 | (mh-show) | ||
| 13470 | (mh-show-show)) | ||
| 13471 | header-field))) | ||
| 13472 | |||
| 13473 | (defun org-follow-mhe-link (folder article) | ||
| 13474 | "Follow an MHE link to FOLDER and ARTICLE. | ||
| 13475 | If ARTICLE is nil FOLDER is shown. If the configuration variable | ||
| 13476 | `org-mhe-search-all-folders' is t and `mh-searcher' is pick, | ||
| 13477 | ARTICLE is searched in all folders. Indexed searches (swish++, | ||
| 13478 | namazu, and others supported by MH-E) will always search in all | ||
| 13479 | folders." | ||
| 13480 | (require 'mh-e) | ||
| 13481 | (require 'mh-search) | ||
| 13482 | (require 'mh-utils) | ||
| 13483 | (mh-find-path) | ||
| 13484 | (if (not article) | ||
| 13485 | (mh-visit-folder (mh-normalize-folder-name folder)) | ||
| 13486 | (setq article (org-add-angle-brackets article)) | ||
| 13487 | (mh-search-choose) | ||
| 13488 | (if (equal mh-searcher 'pick) | ||
| 13489 | (progn | ||
| 13490 | (mh-search folder (list "--message-id" article)) | ||
| 13491 | (when (and org-mhe-search-all-folders | ||
| 13492 | (not (org-mhe-get-message-real-folder))) | ||
| 13493 | (kill-this-buffer) | ||
| 13494 | (mh-search "+" (list "--message-id" article)))) | ||
| 13495 | (mh-search "+" article)) | ||
| 13496 | (if (org-mhe-get-message-real-folder) | ||
| 13497 | (mh-show-msg 1) | ||
| 13498 | (kill-this-buffer) | ||
| 13499 | (error "Message not found")))) | ||
| 13500 | |||
| 13501 | ;;; BibTeX links | ||
| 13502 | |||
| 13503 | ;; Use the custom search meachnism to construct and use search strings for | ||
| 13504 | ;; file links to BibTeX database entries. | ||
| 13505 | |||
| 13506 | (defun org-create-file-search-in-bibtex () | ||
| 13507 | "Create the search string and description for a BibTeX database entry." | ||
| 13508 | (when (eq major-mode 'bibtex-mode) | ||
| 13509 | ;; yes, we want to construct this search string. | ||
| 13510 | ;; Make a good description for this entry, using names, year and the title | ||
| 13511 | ;; Put it into the `description' variable which is dynamically scoped. | ||
| 13512 | (let ((bibtex-autokey-names 1) | ||
| 13513 | (bibtex-autokey-names-stretch 1) | ||
| 13514 | (bibtex-autokey-name-case-convert-function 'identity) | ||
| 13515 | (bibtex-autokey-name-separator " & ") | ||
| 13516 | (bibtex-autokey-additional-names " et al.") | ||
| 13517 | (bibtex-autokey-year-length 4) | ||
| 13518 | (bibtex-autokey-name-year-separator " ") | ||
| 13519 | (bibtex-autokey-titlewords 3) | ||
| 13520 | (bibtex-autokey-titleword-separator " ") | ||
| 13521 | (bibtex-autokey-titleword-case-convert-function 'identity) | ||
| 13522 | (bibtex-autokey-titleword-length 'infty) | ||
| 13523 | (bibtex-autokey-year-title-separator ": ")) | ||
| 13524 | (setq description (bibtex-generate-autokey))) | ||
| 13525 | ;; Now parse the entry, get the key and return it. | ||
| 13526 | (save-excursion | ||
| 13527 | (bibtex-beginning-of-entry) | ||
| 13528 | (cdr (assoc "=key=" (bibtex-parse-entry)))))) | ||
| 13529 | |||
| 13530 | (defun org-execute-file-search-in-bibtex (s) | ||
| 13531 | "Find the link search string S as a key for a database entry." | ||
| 13532 | (when (eq major-mode 'bibtex-mode) | ||
| 13533 | ;; Yes, we want to do the search in this file. | ||
| 13534 | ;; We construct a regexp that searches for "@entrytype{" followed by the key | ||
| 13535 | (goto-char (point-min)) | ||
| 13536 | (and (re-search-forward (concat "@[a-zA-Z]+[ \t\n]*{[ \t\n]*" | ||
| 13537 | (regexp-quote s) "[ \t\n]*,") nil t) | ||
| 13538 | (goto-char (match-beginning 0))) | ||
| 13539 | (if (and (match-beginning 0) (equal current-prefix-arg '(16))) | ||
| 13540 | ;; Use double prefix to indicate that any web link should be browsed | ||
| 13541 | (let ((b (current-buffer)) (p (point))) | ||
| 13542 | ;; Restore the window configuration because we just use the web link | ||
| 13543 | (set-window-configuration org-window-config-before-follow-link) | ||
| 13544 | (save-excursion (set-buffer b) (goto-char p) | ||
| 13545 | (bibtex-url))) | ||
| 13546 | (recenter 0)) ; Move entry start to beginning of window | ||
| 13547 | ;; return t to indicate that the search is done. | ||
| 13548 | t)) | ||
| 13549 | |||
| 13550 | ;; Finally add the functions to the right hooks. | ||
| 13551 | (add-hook 'org-create-file-search-functions 'org-create-file-search-in-bibtex) | ||
| 13552 | (add-hook 'org-execute-file-search-functions 'org-execute-file-search-in-bibtex) | ||
| 13553 | |||
| 13554 | ;; end of Bibtex link setup | ||
| 13555 | |||
| 13556 | ;;; Following file links | ||
| 13557 | |||
| 13558 | (defun org-open-file (path &optional in-emacs line search) | ||
| 13559 | "Open the file at PATH. | ||
| 13560 | First, this expands any special file name abbreviations. Then the | ||
| 13561 | configuration variable `org-file-apps' is checked if it contains an | ||
| 13562 | entry for this file type, and if yes, the corresponding command is launched. | ||
| 13563 | If no application is found, Emacs simply visits the file. | ||
| 13564 | With optional argument IN-EMACS, Emacs will visit the file. | ||
| 13565 | Optional LINE specifies a line to go to, optional SEARCH a string to | ||
| 13566 | search for. If LINE or SEARCH is given, the file will always be | ||
| 13567 | opened in Emacs. | ||
| 13568 | If the file does not exist, an error is thrown." | ||
| 13569 | (setq in-emacs (or in-emacs line search)) | ||
| 13570 | (let* ((file (if (equal path "") | ||
| 13571 | buffer-file-name | ||
| 13572 | (substitute-in-file-name (expand-file-name path)))) | ||
| 13573 | (apps (append org-file-apps (org-default-apps))) | ||
| 13574 | (remp (and (assq 'remote apps) (org-file-remote-p file))) | ||
| 13575 | (dirp (if remp nil (file-directory-p file))) | ||
| 13576 | (dfile (downcase file)) | ||
| 13577 | (old-buffer (current-buffer)) | ||
| 13578 | (old-pos (point)) | ||
| 13579 | (old-mode major-mode) | ||
| 13580 | ext cmd) | ||
| 13581 | (if (string-match "^.*\\.\\([a-zA-Z0-9]+\\.gz\\)$" dfile) | ||
| 13582 | (setq ext (match-string 1 dfile)) | ||
| 13583 | (if (string-match "^.*\\.\\([a-zA-Z0-9]+\\)$" dfile) | ||
| 13584 | (setq ext (match-string 1 dfile)))) | ||
| 13585 | (if in-emacs | ||
| 13586 | (setq cmd 'emacs) | ||
| 13587 | (setq cmd (or (and remp (cdr (assoc 'remote apps))) | ||
| 13588 | (and dirp (cdr (assoc 'directory apps))) | ||
| 13589 | (cdr (assoc ext apps)) | ||
| 13590 | (cdr (assoc t apps))))) | ||
| 13591 | (when (eq cmd 'mailcap) | ||
| 13592 | (require 'mailcap) | ||
| 13593 | (mailcap-parse-mailcaps) | ||
| 13594 | (let* ((mime-type (mailcap-extension-to-mime (or ext ""))) | ||
| 13595 | (command (mailcap-mime-info mime-type))) | ||
| 13596 | (if (stringp command) | ||
| 13597 | (setq cmd command) | ||
| 13598 | (setq cmd 'emacs)))) | ||
| 13599 | (if (and (not (eq cmd 'emacs)) ; Emacs has no problems with non-ex files | ||
| 13600 | (not (file-exists-p file)) | ||
| 13601 | (not org-open-non-existing-files)) | ||
| 13602 | (error "No such file: %s" file)) | ||
| 13603 | (cond | ||
| 13604 | ((and (stringp cmd) (not (string-match "^\\s-*$" cmd))) | ||
| 13605 | ;; Remove quotes around the file name - we'll use shell-quote-argument. | ||
| 13606 | (while (string-match "['\"]%s['\"]" cmd) | ||
| 13607 | (setq cmd (replace-match "%s" t t cmd))) | ||
| 13608 | (while (string-match "%s" cmd) | ||
| 13609 | (setq cmd (replace-match | ||
| 13610 | (save-match-data (shell-quote-argument file)) | ||
| 13611 | t t cmd))) | ||
| 13612 | (save-window-excursion | ||
| 13613 | (start-process-shell-command cmd nil cmd))) | ||
| 13614 | ((or (stringp cmd) | ||
| 13615 | (eq cmd 'emacs)) | ||
| 13616 | (funcall (cdr (assq 'file org-link-frame-setup)) file) | ||
| 13617 | (widen) | ||
| 13618 | (if line (goto-line line) | ||
| 13619 | (if search (org-link-search search)))) | ||
| 13620 | ((consp cmd) | ||
| 13621 | (eval cmd)) | ||
| 13622 | (t (funcall (cdr (assq 'file org-link-frame-setup)) file))) | ||
| 13623 | (and (org-mode-p) (eq old-mode 'org-mode) | ||
| 13624 | (or (not (equal old-buffer (current-buffer))) | ||
| 13625 | (not (equal old-pos (point)))) | ||
| 13626 | (org-mark-ring-push old-pos old-buffer)))) | ||
| 13627 | |||
| 13628 | (defun org-default-apps () | ||
| 13629 | "Return the default applications for this operating system." | ||
| 13630 | (cond | ||
| 13631 | ((eq system-type 'darwin) | ||
| 13632 | org-file-apps-defaults-macosx) | ||
| 13633 | ((eq system-type 'windows-nt) | ||
| 13634 | org-file-apps-defaults-windowsnt) | ||
| 13635 | (t org-file-apps-defaults-gnu))) | ||
| 13636 | |||
| 13637 | (defvar ange-ftp-name-format) ; to silence the XEmacs compiler. | ||
| 13638 | (defun org-file-remote-p (file) | ||
| 13639 | "Test whether FILE specifies a location on a remote system. | ||
| 13640 | Return non-nil if the location is indeed remote. | ||
| 13641 | |||
| 13642 | For example, the filename \"/user@host:/foo\" specifies a location | ||
| 13643 | on the system \"/user@host:\"." | ||
| 13644 | (cond ((fboundp 'file-remote-p) | ||
| 13645 | (file-remote-p file)) | ||
| 13646 | ((fboundp 'tramp-handle-file-remote-p) | ||
| 13647 | (tramp-handle-file-remote-p file)) | ||
| 13648 | ((and (boundp 'ange-ftp-name-format) | ||
| 13649 | (string-match (car ange-ftp-name-format) file)) | ||
| 13650 | t) | ||
| 13651 | (t nil))) | ||
| 13652 | |||
| 13653 | |||
| 13654 | ;;;; Hooks for remember.el, and refiling | ||
| 13655 | |||
| 13656 | (defvar annotation) ; from remember.el, dynamically scoped in `remember-mode' | ||
| 13657 | (defvar initial) ; from remember.el, dynamically scoped in `remember-mode' | ||
| 13658 | |||
| 13659 | ;;;###autoload | ||
| 13660 | (defun org-remember-insinuate () | ||
| 13661 | "Setup remember.el for use wiht Org-mode." | ||
| 13662 | (require 'remember) | ||
| 13663 | (setq remember-annotation-functions '(org-remember-annotation)) | ||
| 13664 | (setq remember-handler-functions '(org-remember-handler)) | ||
| 13665 | (add-hook 'remember-mode-hook 'org-remember-apply-template)) | ||
| 13666 | |||
| 13667 | ;;;###autoload | ||
| 13668 | (defun org-remember-annotation () | ||
| 13669 | "Return a link to the current location as an annotation for remember.el. | ||
| 13670 | If you are using Org-mode files as target for data storage with | ||
| 13671 | remember.el, then the annotations should include a link compatible with the | ||
| 13672 | conventions in Org-mode. This function returns such a link." | ||
| 13673 | (org-store-link nil)) | ||
| 13674 | |||
| 13675 | (defconst org-remember-help | ||
| 13676 | "Select a destination location for the note. | ||
| 13677 | UP/DOWN=headline TAB=cycle visibility [Q]uit RET/<left>/<right>=Store | ||
| 13678 | RET on headline -> Store as sublevel entry to current headline | ||
| 13679 | RET at beg-of-buf -> Append to file as level 2 headline | ||
| 13680 | <left>/<right> -> before/after current headline, same headings level") | ||
| 13681 | |||
| 13682 | (defvar org-remember-previous-location nil) | ||
| 13683 | (defvar org-force-remember-template-char) ;; dynamically scoped | ||
| 13684 | |||
| 13685 | ;; Save the major mode of the buffer we called remember from | ||
| 13686 | (defvar org-select-template-temp-major-mode nil) | ||
| 13687 | |||
| 13688 | ;; Temporary store the buffer where remember was called from | ||
| 13689 | (defvar org-select-template-original-buffer nil) | ||
| 13690 | |||
| 13691 | (defun org-select-remember-template (&optional use-char) | ||
| 13692 | (when org-remember-templates | ||
| 13693 | (let* ((pre-selected-templates | ||
| 13694 | (mapcar | ||
| 13695 | (lambda (tpl) | ||
| 13696 | (let ((ctxt (nth 5 tpl)) | ||
| 13697 | (mode org-select-template-temp-major-mode) | ||
| 13698 | (buf org-select-template-original-buffer)) | ||
| 13699 | (and (or (not ctxt) (eq ctxt t) | ||
| 13700 | (and (listp ctxt) (memq mode ctxt)) | ||
| 13701 | (and (functionp ctxt) | ||
| 13702 | (with-current-buffer buf | ||
| 13703 | ;; Protect the user-defined function from error | ||
| 13704 | (condition-case nil (funcall ctxt) (error nil))))) | ||
| 13705 | tpl))) | ||
| 13706 | org-remember-templates)) | ||
| 13707 | ;; If no template at this point, add the default templates: | ||
| 13708 | (pre-selected-templates1 | ||
| 13709 | (if (not (delq nil pre-selected-templates)) | ||
| 13710 | (mapcar (lambda(x) (if (not (nth 5 x)) x)) | ||
| 13711 | org-remember-templates) | ||
| 13712 | pre-selected-templates)) | ||
| 13713 | ;; Then unconditionnally add template for any contexts | ||
| 13714 | (pre-selected-templates2 | ||
| 13715 | (append (mapcar (lambda(x) (if (eq (nth 5 x) t) x)) | ||
| 13716 | org-remember-templates) | ||
| 13717 | (delq nil pre-selected-templates1))) | ||
| 13718 | (templates (mapcar (lambda (x) | ||
| 13719 | (if (stringp (car x)) | ||
| 13720 | (append (list (nth 1 x) (car x)) (cddr x)) | ||
| 13721 | (append (list (car x) "") (cdr x)))) | ||
| 13722 | (delq nil pre-selected-templates2))) | ||
| 13723 | (char (or use-char | ||
| 13724 | (cond | ||
| 13725 | ((= (length templates) 1) | ||
| 13726 | (caar templates)) | ||
| 13727 | ((and (boundp 'org-force-remember-template-char) | ||
| 13728 | org-force-remember-template-char) | ||
| 13729 | (if (stringp org-force-remember-template-char) | ||
| 13730 | (string-to-char org-force-remember-template-char) | ||
| 13731 | org-force-remember-template-char)) | ||
| 13732 | (t | ||
| 13733 | (message "Select template: %s" | ||
| 13734 | (mapconcat | ||
| 13735 | (lambda (x) | ||
| 13736 | (cond | ||
| 13737 | ((not (string-match "\\S-" (nth 1 x))) | ||
| 13738 | (format "[%c]" (car x))) | ||
| 13739 | ((equal (downcase (car x)) | ||
| 13740 | (downcase (aref (nth 1 x) 0))) | ||
| 13741 | (format "[%c]%s" (car x) | ||
| 13742 | (substring (nth 1 x) 1))) | ||
| 13743 | (t (format "[%c]%s" (car x) (nth 1 x))))) | ||
| 13744 | templates " ")) | ||
| 13745 | (let ((inhibit-quit t) (char0 (read-char-exclusive))) | ||
| 13746 | (when (equal char0 ?\C-g) | ||
| 13747 | (jump-to-register remember-register) | ||
| 13748 | (kill-buffer remember-buffer)) | ||
| 13749 | char0)))))) | ||
| 13750 | (cddr (assoc char templates))))) | ||
| 13751 | |||
| 13752 | (defvar x-last-selected-text) | ||
| 13753 | (defvar x-last-selected-text-primary) | ||
| 13754 | |||
| 13755 | ;;;###autoload | ||
| 13756 | (defun org-remember-apply-template (&optional use-char skip-interactive) | ||
| 13757 | "Initialize *remember* buffer with template, invoke `org-mode'. | ||
| 13758 | This function should be placed into `remember-mode-hook' and in fact requires | ||
| 13759 | to be run from that hook to function properly." | ||
| 13760 | (if org-remember-templates | ||
| 13761 | (let* ((entry (org-select-remember-template use-char)) | ||
| 13762 | (tpl (car entry)) | ||
| 13763 | (plist-p (if org-store-link-plist t nil)) | ||
| 13764 | (file (if (and (nth 1 entry) (stringp (nth 1 entry)) | ||
| 13765 | (string-match "\\S-" (nth 1 entry))) | ||
| 13766 | (nth 1 entry) | ||
| 13767 | org-default-notes-file)) | ||
| 13768 | (headline (nth 2 entry)) | ||
| 13769 | (v-c (or (and (eq window-system 'x) | ||
| 13770 | (fboundp 'x-cut-buffer-or-selection-value) | ||
| 13771 | (x-cut-buffer-or-selection-value)) | ||
| 13772 | (org-bound-and-true-p x-last-selected-text) | ||
| 13773 | (org-bound-and-true-p x-last-selected-text-primary) | ||
| 13774 | (and (> (length kill-ring) 0) (current-kill 0)))) | ||
| 13775 | (v-t (format-time-string (car org-time-stamp-formats) (org-current-time))) | ||
| 13776 | (v-T (format-time-string (cdr org-time-stamp-formats) (org-current-time))) | ||
| 13777 | (v-u (concat "[" (substring v-t 1 -1) "]")) | ||
| 13778 | (v-U (concat "[" (substring v-T 1 -1) "]")) | ||
| 13779 | ;; `initial' and `annotation' are bound in `remember' | ||
| 13780 | (v-i (if (boundp 'initial) initial)) | ||
| 13781 | (v-a (if (and (boundp 'annotation) annotation) | ||
| 13782 | (if (equal annotation "[[]]") "" annotation) | ||
| 13783 | "")) | ||
| 13784 | (v-A (if (and v-a | ||
| 13785 | (string-match "\\[\\(\\[.*?\\]\\)\\(\\[.*?\\]\\)?\\]" v-a)) | ||
| 13786 | (replace-match "[\\1[%^{Link description}]]" nil nil v-a) | ||
| 13787 | v-a)) | ||
| 13788 | (v-n user-full-name) | ||
| 13789 | (org-startup-folded nil) | ||
| 13790 | org-time-was-given org-end-time-was-given x | ||
| 13791 | prompt completions char time pos default histvar) | ||
| 13792 | (setq org-store-link-plist | ||
| 13793 | (append (list :annotation v-a :initial v-i) | ||
| 13794 | org-store-link-plist)) | ||
| 13795 | (unless tpl (setq tpl "") (message "No template") (ding) (sit-for 1)) | ||
| 13796 | (erase-buffer) | ||
| 13797 | (insert (substitute-command-keys | ||
| 13798 | (format | ||
| 13799 | "## Filing location: Select interactively, default, or last used: | ||
| 13800 | ## %s to select file and header location interactively. | ||
| 13801 | ## %s \"%s\" -> \"* %s\" | ||
| 13802 | ## C-u C-u C-c C-c \"%s\" -> \"* %s\" | ||
| 13803 | ## To switch templates, use `\\[org-remember]'. To abort use `C-c C-k'.\n\n" | ||
| 13804 | (if org-remember-store-without-prompt " C-u C-c C-c" " C-c C-c") | ||
| 13805 | (if org-remember-store-without-prompt " C-c C-c" " C-u C-c C-c") | ||
| 13806 | (abbreviate-file-name (or file org-default-notes-file)) | ||
| 13807 | (or headline "") | ||
| 13808 | (or (car org-remember-previous-location) "???") | ||
| 13809 | (or (cdr org-remember-previous-location) "???")))) | ||
| 13810 | (insert tpl) (goto-char (point-min)) | ||
| 13811 | ;; Simple %-escapes | ||
| 13812 | (while (re-search-forward "%\\([tTuUaiAc]\\)" nil t) | ||
| 13813 | (when (and initial (equal (match-string 0) "%i")) | ||
| 13814 | (save-match-data | ||
| 13815 | (let* ((lead (buffer-substring | ||
| 13816 | (point-at-bol) (match-beginning 0)))) | ||
| 13817 | (setq v-i (mapconcat 'identity | ||
| 13818 | (org-split-string initial "\n") | ||
| 13819 | (concat "\n" lead)))))) | ||
| 13820 | (replace-match | ||
| 13821 | (or (eval (intern (concat "v-" (match-string 1)))) "") | ||
| 13822 | t t)) | ||
| 13823 | |||
| 13824 | ;; %[] Insert contents of a file. | ||
| 13825 | (goto-char (point-min)) | ||
| 13826 | (while (re-search-forward "%\\[\\(.+\\)\\]" nil t) | ||
| 13827 | (let ((start (match-beginning 0)) | ||
| 13828 | (end (match-end 0)) | ||
| 13829 | (filename (expand-file-name (match-string 1)))) | ||
| 13830 | (goto-char start) | ||
| 13831 | (delete-region start end) | ||
| 13832 | (condition-case error | ||
| 13833 | (insert-file-contents filename) | ||
| 13834 | (error (insert (format "%%![Couldn't insert %s: %s]" | ||
| 13835 | filename error)))))) | ||
| 13836 | ;; %() embedded elisp | ||
| 13837 | (goto-char (point-min)) | ||
| 13838 | (while (re-search-forward "%\\((.+)\\)" nil t) | ||
| 13839 | (goto-char (match-beginning 0)) | ||
| 13840 | (let ((template-start (point))) | ||
| 13841 | (forward-char 1) | ||
| 13842 | (let ((result | ||
| 13843 | (condition-case error | ||
| 13844 | (eval (read (current-buffer))) | ||
| 13845 | (error (format "%%![Error: %s]" error))))) | ||
| 13846 | (delete-region template-start (point)) | ||
| 13847 | (insert result)))) | ||
| 13848 | |||
| 13849 | ;; From the property list | ||
| 13850 | (when plist-p | ||
| 13851 | (goto-char (point-min)) | ||
| 13852 | (while (re-search-forward "%\\(:[-a-zA-Z]+\\)" nil t) | ||
| 13853 | (and (setq x (or (plist-get org-store-link-plist | ||
| 13854 | (intern (match-string 1))) "")) | ||
| 13855 | (replace-match x t t)))) | ||
| 13856 | |||
| 13857 | ;; Turn on org-mode in the remember buffer, set local variables | ||
| 13858 | (org-mode) | ||
| 13859 | (org-set-local 'org-finish-function 'org-remember-finalize) | ||
| 13860 | (if (and file (string-match "\\S-" file) (not (file-directory-p file))) | ||
| 13861 | (org-set-local 'org-default-notes-file file)) | ||
| 13862 | (if (and headline (stringp headline) (string-match "\\S-" headline)) | ||
| 13863 | (org-set-local 'org-remember-default-headline headline)) | ||
| 13864 | ;; Interactive template entries | ||
| 13865 | (goto-char (point-min)) | ||
| 13866 | (while (re-search-forward "%^\\({\\([^}]*\\)}\\)?\\([gGuUtT]\\)?" nil t) | ||
| 13867 | (setq char (if (match-end 3) (match-string 3)) | ||
| 13868 | prompt (if (match-end 2) (match-string 2))) | ||
| 13869 | (goto-char (match-beginning 0)) | ||
| 13870 | (replace-match "") | ||
| 13871 | (setq completions nil default nil) | ||
| 13872 | (when prompt | ||
| 13873 | (setq completions (org-split-string prompt "|") | ||
| 13874 | prompt (pop completions) | ||
| 13875 | default (car completions) | ||
| 13876 | histvar (intern (concat | ||
| 13877 | "org-remember-template-prompt-history::" | ||
| 13878 | (or prompt ""))) | ||
| 13879 | completions (mapcar 'list completions))) | ||
| 13880 | (cond | ||
| 13881 | ((member char '("G" "g")) | ||
| 13882 | (let* ((org-last-tags-completion-table | ||
| 13883 | (org-global-tags-completion-table | ||
| 13884 | (if (equal char "G") (org-agenda-files) (and file (list file))))) | ||
| 13885 | (org-add-colon-after-tag-completion t) | ||
| 13886 | (ins (completing-read | ||
| 13887 | (if prompt (concat prompt ": ") "Tags: ") | ||
| 13888 | 'org-tags-completion-function nil nil nil | ||
| 13889 | 'org-tags-history))) | ||
| 13890 | (setq ins (mapconcat 'identity | ||
| 13891 | (org-split-string ins (org-re "[^[:alnum:]_@]+")) | ||
| 13892 | ":")) | ||
| 13893 | (when (string-match "\\S-" ins) | ||
| 13894 | (or (equal (char-before) ?:) (insert ":")) | ||
| 13895 | (insert ins) | ||
| 13896 | (or (equal (char-after) ?:) (insert ":"))))) | ||
| 13897 | (char | ||
| 13898 | (setq org-time-was-given (equal (upcase char) char)) | ||
| 13899 | (setq time (org-read-date (equal (upcase char) "U") t nil | ||
| 13900 | prompt)) | ||
| 13901 | (org-insert-time-stamp time org-time-was-given | ||
| 13902 | (member char '("u" "U")) | ||
| 13903 | nil nil (list org-end-time-was-given))) | ||
| 13904 | (t | ||
| 13905 | (insert (org-completing-read | ||
| 13906 | (concat (if prompt prompt "Enter string") | ||
| 13907 | (if default (concat " [" default "]")) | ||
| 13908 | ": ") | ||
| 13909 | completions nil nil nil histvar default))))) | ||
| 13910 | (goto-char (point-min)) | ||
| 13911 | (if (re-search-forward "%\\?" nil t) | ||
| 13912 | (replace-match "") | ||
| 13913 | (and (re-search-forward "^[^#\n]" nil t) (backward-char 1)))) | ||
| 13914 | (org-mode) | ||
| 13915 | (org-set-local 'org-finish-function 'org-remember-finalize)) | ||
| 13916 | (when (save-excursion | ||
| 13917 | (goto-char (point-min)) | ||
| 13918 | (re-search-forward "%!" nil t)) | ||
| 13919 | (replace-match "") | ||
| 13920 | (add-hook 'post-command-hook 'org-remember-finish-immediately 'append))) | ||
| 13921 | |||
| 13922 | (defun org-remember-finish-immediately () | ||
| 13923 | "File remember note immediately. | ||
| 13924 | This should be run in `post-command-hook' and will remove itself | ||
| 13925 | from that hook." | ||
| 13926 | (remove-hook 'post-command-hook 'org-remember-finish-immediately) | ||
| 13927 | (when org-finish-function | ||
| 13928 | (funcall org-finish-function))) | ||
| 13929 | |||
| 13930 | (defvar org-clock-marker) ; Defined below | ||
| 13931 | (defun org-remember-finalize () | ||
| 13932 | "Finalize the remember process." | ||
| 13933 | (unless (fboundp 'remember-finalize) | ||
| 13934 | (defalias 'remember-finalize 'remember-buffer)) | ||
| 13935 | (when (and org-clock-marker | ||
| 13936 | (equal (marker-buffer org-clock-marker) (current-buffer))) | ||
| 13937 | ;; FIXME: test this, this is w/o notetaking! | ||
| 13938 | (let (org-log-note-clock-out) (org-clock-out))) | ||
| 13939 | (when buffer-file-name | ||
| 13940 | (save-buffer) | ||
| 13941 | (setq buffer-file-name nil)) | ||
| 13942 | (remember-finalize)) | ||
| 13943 | |||
| 13944 | ;;;###autoload | ||
| 13945 | (defun org-remember (&optional goto org-force-remember-template-char) | ||
| 13946 | "Call `remember'. If this is already a remember buffer, re-apply template. | ||
| 13947 | If there is an active region, make sure remember uses it as initial content | ||
| 13948 | of the remember buffer. | ||
| 13949 | |||
| 13950 | When called interactively with a `C-u' prefix argument GOTO, don't remember | ||
| 13951 | anything, just go to the file/headline where the selected template usually | ||
| 13952 | stores its notes. With a double prefix arg `C-u C-u', go to the last | ||
| 13953 | note stored by remember. | ||
| 13954 | |||
| 13955 | Lisp programs can set ORG-FORCE-REMEMBER-TEMPLATE-CHAR to a character | ||
| 13956 | associated with a template in `org-remember-templates'." | ||
| 13957 | (interactive "P") | ||
| 13958 | (cond | ||
| 13959 | ((equal goto '(4)) (org-go-to-remember-target)) | ||
| 13960 | ((equal goto '(16)) (org-remember-goto-last-stored)) | ||
| 13961 | (t | ||
| 13962 | ;; set temporary variables that will be needed in | ||
| 13963 | ;; `org-select-remember-template' | ||
| 13964 | (setq org-select-template-temp-major-mode major-mode) | ||
| 13965 | (setq org-select-template-original-buffer (current-buffer)) | ||
| 13966 | (if (memq org-finish-function '(remember-buffer remember-finalize)) | ||
| 13967 | (progn | ||
| 13968 | (when (< (length org-remember-templates) 2) | ||
| 13969 | (error "No other template available")) | ||
| 13970 | (erase-buffer) | ||
| 13971 | (let ((annotation (plist-get org-store-link-plist :annotation)) | ||
| 13972 | (initial (plist-get org-store-link-plist :initial))) | ||
| 13973 | (org-remember-apply-template)) | ||
| 13974 | (message "Press C-c C-c to remember data")) | ||
| 13975 | (if (org-region-active-p) | ||
| 13976 | (remember (buffer-substring (point) (mark))) | ||
| 13977 | (call-interactively 'remember)))))) | ||
| 13978 | |||
| 13979 | (defun org-remember-goto-last-stored () | ||
| 13980 | "Go to the location where the last remember note was stored." | ||
| 13981 | (interactive) | ||
| 13982 | (bookmark-jump "org-remember-last-stored") | ||
| 13983 | (message "This is the last note stored by remember")) | ||
| 13984 | |||
| 13985 | (defun org-go-to-remember-target (&optional template-key) | ||
| 13986 | "Go to the target location of a remember template. | ||
| 13987 | The user is queried for the template." | ||
| 13988 | (interactive) | ||
| 13989 | (let* (org-select-template-temp-major-mode | ||
| 13990 | (entry (org-select-remember-template template-key)) | ||
| 13991 | (file (nth 1 entry)) | ||
| 13992 | (heading (nth 2 entry)) | ||
| 13993 | visiting) | ||
| 13994 | (unless (and file (stringp file) (string-match "\\S-" file)) | ||
| 13995 | (setq file org-default-notes-file)) | ||
| 13996 | (unless (and heading (stringp heading) (string-match "\\S-" heading)) | ||
| 13997 | (setq heading org-remember-default-headline)) | ||
| 13998 | (setq visiting (org-find-base-buffer-visiting file)) | ||
| 13999 | (if (not visiting) (find-file-noselect file)) | ||
| 14000 | (switch-to-buffer (or visiting (get-file-buffer file))) | ||
| 14001 | (widen) | ||
| 14002 | (goto-char (point-min)) | ||
| 14003 | (if (re-search-forward | ||
| 14004 | (concat "^\\*+[ \t]+" (regexp-quote heading) | ||
| 14005 | (org-re "\\([ \t]+:[[:alnum:]@_:]*\\)?[ \t]*$")) | ||
| 14006 | nil t) | ||
| 14007 | (goto-char (match-beginning 0)) | ||
| 14008 | (error "Target headline not found: %s" heading)))) | ||
| 14009 | |||
| 14010 | (defvar org-note-abort nil) ; dynamically scoped | ||
| 14011 | |||
| 14012 | ;;;###autoload | ||
| 14013 | (defun org-remember-handler () | ||
| 14014 | "Store stuff from remember.el into an org file. | ||
| 14015 | First prompts for an org file. If the user just presses return, the value | ||
| 14016 | of `org-default-notes-file' is used. | ||
| 14017 | Then the command offers the headings tree of the selected file in order to | ||
| 14018 | file the text at a specific location. | ||
| 14019 | You can either immediately press RET to get the note appended to the | ||
| 14020 | file, or you can use vertical cursor motion and visibility cycling (TAB) to | ||
| 14021 | find a better place. Then press RET or <left> or <right> in insert the note. | ||
| 14022 | |||
| 14023 | Key Cursor position Note gets inserted | ||
| 14024 | ----------------------------------------------------------------------------- | ||
| 14025 | RET buffer-start as level 1 heading at end of file | ||
| 14026 | RET on headline as sublevel of the heading at cursor | ||
| 14027 | RET no heading at cursor position, level taken from context. | ||
| 14028 | Or use prefix arg to specify level manually. | ||
| 14029 | <left> on headline as same level, before current heading | ||
| 14030 | <right> on headline as same level, after current heading | ||
| 14031 | |||
| 14032 | So the fastest way to store the note is to press RET RET to append it to | ||
| 14033 | the default file. This way your current train of thought is not | ||
| 14034 | interrupted, in accordance with the principles of remember.el. | ||
| 14035 | You can also get the fast execution without prompting by using | ||
| 14036 | C-u C-c C-c to exit the remember buffer. See also the variable | ||
| 14037 | `org-remember-store-without-prompt'. | ||
| 14038 | |||
| 14039 | Before being stored away, the function ensures that the text has a | ||
| 14040 | headline, i.e. a first line that starts with a \"*\". If not, a headline | ||
| 14041 | is constructed from the current date and some additional data. | ||
| 14042 | |||
| 14043 | If the variable `org-adapt-indentation' is non-nil, the entire text is | ||
| 14044 | also indented so that it starts in the same column as the headline | ||
| 14045 | \(i.e. after the stars). | ||
| 14046 | |||
| 14047 | See also the variable `org-reverse-note-order'." | ||
| 14048 | (goto-char (point-min)) | ||
| 14049 | (while (looking-at "^[ \t]*\n\\|^##.*\n") | ||
| 14050 | (replace-match "")) | ||
| 14051 | (goto-char (point-max)) | ||
| 14052 | (beginning-of-line 1) | ||
| 14053 | (while (looking-at "[ \t]*$\\|##.*") | ||
| 14054 | (delete-region (1- (point)) (point-max)) | ||
| 14055 | (beginning-of-line 1)) | ||
| 14056 | (catch 'quit | ||
| 14057 | (if org-note-abort (throw 'quit nil)) | ||
| 14058 | (let* ((txt (buffer-substring (point-min) (point-max))) | ||
| 14059 | (fastp (org-xor (equal current-prefix-arg '(4)) | ||
| 14060 | org-remember-store-without-prompt)) | ||
| 14061 | (file (cond | ||
| 14062 | (fastp org-default-notes-file) | ||
| 14063 | ((and (eq org-remember-interactive-interface 'refile) | ||
| 14064 | org-refile-targets) | ||
| 14065 | org-default-notes-file) | ||
| 14066 | ((not (and (equal current-prefix-arg '(16)) | ||
| 14067 | org-remember-previous-location)) | ||
| 14068 | (org-get-org-file)))) | ||
| 14069 | (heading org-remember-default-headline) | ||
| 14070 | (visiting (and file (org-find-base-buffer-visiting file))) | ||
| 14071 | (org-startup-folded nil) | ||
| 14072 | (org-startup-align-all-tables nil) | ||
| 14073 | (org-goto-start-pos 1) | ||
| 14074 | spos exitcmd level indent reversed) | ||
| 14075 | (if (and (equal current-prefix-arg '(16)) org-remember-previous-location) | ||
| 14076 | (setq file (car org-remember-previous-location) | ||
| 14077 | heading (cdr org-remember-previous-location) | ||
| 14078 | fastp t)) | ||
| 14079 | (setq current-prefix-arg nil) | ||
| 14080 | (if (string-match "[ \t\n]+\\'" txt) | ||
| 14081 | (setq txt (replace-match "" t t txt))) | ||
| 14082 | ;; Modify text so that it becomes a nice subtree which can be inserted | ||
| 14083 | ;; into an org tree. | ||
| 14084 | (let* ((lines (split-string txt "\n")) | ||
| 14085 | first) | ||
| 14086 | (setq first (car lines) lines (cdr lines)) | ||
| 14087 | (if (string-match "^\\*+ " first) | ||
| 14088 | ;; Is already a headline | ||
| 14089 | (setq indent nil) | ||
| 14090 | ;; We need to add a headline: Use time and first buffer line | ||
| 14091 | (setq lines (cons first lines) | ||
| 14092 | first (concat "* " (current-time-string) | ||
| 14093 | " (" (remember-buffer-desc) ")") | ||
| 14094 | indent " ")) | ||
| 14095 | (if (and org-adapt-indentation indent) | ||
| 14096 | (setq lines (mapcar | ||
| 14097 | (lambda (x) | ||
| 14098 | (if (string-match "\\S-" x) | ||
| 14099 | (concat indent x) x)) | ||
| 14100 | lines))) | ||
| 14101 | (setq txt (concat first "\n" | ||
| 14102 | (mapconcat 'identity lines "\n")))) | ||
| 14103 | (if (string-match "\n[ \t]*\n[ \t\n]*\\'" txt) | ||
| 14104 | (setq txt (replace-match "\n\n" t t txt)) | ||
| 14105 | (if (string-match "[ \t\n]*\\'" txt) | ||
| 14106 | (setq txt (replace-match "\n" t t txt)))) | ||
| 14107 | ;; Put the modified text back into the remember buffer, for refile. | ||
| 14108 | (erase-buffer) | ||
| 14109 | (insert txt) | ||
| 14110 | (goto-char (point-min)) | ||
| 14111 | (when (and (eq org-remember-interactive-interface 'refile) | ||
| 14112 | (not fastp)) | ||
| 14113 | (org-refile nil (or visiting (find-file-noselect file))) | ||
| 14114 | (throw 'quit t)) | ||
| 14115 | ;; Find the file | ||
| 14116 | (if (not visiting) (find-file-noselect file)) | ||
| 14117 | (with-current-buffer (or visiting (get-file-buffer file)) | ||
| 14118 | (unless (org-mode-p) | ||
| 14119 | (error "Target files for remember notes must be in Org-mode")) | ||
| 14120 | (save-excursion | ||
| 14121 | (save-restriction | ||
| 14122 | (widen) | ||
| 14123 | (and (goto-char (point-min)) | ||
| 14124 | (not (re-search-forward "^\\* " nil t)) | ||
| 14125 | (insert "\n* " (or heading "Notes") "\n")) | ||
| 14126 | (setq reversed (org-notes-order-reversed-p)) | ||
| 14127 | |||
| 14128 | ;; Find the default location | ||
| 14129 | (when (and heading (stringp heading) (string-match "\\S-" heading)) | ||
| 14130 | (goto-char (point-min)) | ||
| 14131 | (if (re-search-forward | ||
| 14132 | (concat "^\\*+[ \t]+" (regexp-quote heading) | ||
| 14133 | (org-re "\\([ \t]+:[[:alnum:]@_:]*\\)?[ \t]*$")) | ||
| 14134 | nil t) | ||
| 14135 | (setq org-goto-start-pos (match-beginning 0)) | ||
| 14136 | (when fastp | ||
| 14137 | (goto-char (point-max)) | ||
| 14138 | (unless (bolp) (newline)) | ||
| 14139 | (insert "* " heading "\n") | ||
| 14140 | (setq org-goto-start-pos (point-at-bol 0))))) | ||
| 14141 | |||
| 14142 | ;; Ask the User for a location, using the appropriate interface | ||
| 14143 | (cond | ||
| 14144 | (fastp (setq spos org-goto-start-pos | ||
| 14145 | exitcmd 'return)) | ||
| 14146 | ((eq org-remember-interactive-interface 'outline) | ||
| 14147 | (setq spos (org-get-location (current-buffer) | ||
| 14148 | org-remember-help) | ||
| 14149 | exitcmd (cdr spos) | ||
| 14150 | spos (car spos))) | ||
| 14151 | ((eq org-remember-interactive-interface 'outline-path-completion) | ||
| 14152 | (let ((org-refile-targets '((nil . (:maxlevel . 10)))) | ||
| 14153 | (org-refile-use-outline-path t)) | ||
| 14154 | (setq spos (org-refile-get-location "Heading: ") | ||
| 14155 | exitcmd 'return | ||
| 14156 | spos (nth 3 spos)))) | ||
| 14157 | (t (error "this should not hapen"))) | ||
| 14158 | (if (not spos) (throw 'quit nil)) ; return nil to show we did | ||
| 14159 | ; not handle this note | ||
| 14160 | (goto-char spos) | ||
| 14161 | (cond ((org-on-heading-p t) | ||
| 14162 | (org-back-to-heading t) | ||
| 14163 | (setq level (funcall outline-level)) | ||
| 14164 | (cond | ||
| 14165 | ((eq exitcmd 'return) | ||
| 14166 | ;; sublevel of current | ||
| 14167 | (setq org-remember-previous-location | ||
| 14168 | (cons (abbreviate-file-name file) | ||
| 14169 | (org-get-heading 'notags))) | ||
| 14170 | (if reversed | ||
| 14171 | (outline-next-heading) | ||
| 14172 | (org-end-of-subtree t) | ||
| 14173 | (if (not (bolp)) | ||
| 14174 | (if (looking-at "[ \t]*\n") | ||
| 14175 | (beginning-of-line 2) | ||
| 14176 | (end-of-line 1) | ||
| 14177 | (insert "\n")))) | ||
| 14178 | (bookmark-set "org-remember-last-stored") | ||
| 14179 | (org-paste-subtree (org-get-valid-level level 1) txt)) | ||
| 14180 | ((eq exitcmd 'left) | ||
| 14181 | ;; before current | ||
| 14182 | (bookmark-set "org-remember-last-stored") | ||
| 14183 | (org-paste-subtree level txt)) | ||
| 14184 | ((eq exitcmd 'right) | ||
| 14185 | ;; after current | ||
| 14186 | (org-end-of-subtree t) | ||
| 14187 | (bookmark-set "org-remember-last-stored") | ||
| 14188 | (org-paste-subtree level txt)) | ||
| 14189 | (t (error "This should not happen")))) | ||
| 14190 | |||
| 14191 | ((and (bobp) (not reversed)) | ||
| 14192 | ;; Put it at the end, one level below level 1 | ||
| 14193 | (save-restriction | ||
| 14194 | (widen) | ||
| 14195 | (goto-char (point-max)) | ||
| 14196 | (if (not (bolp)) (newline)) | ||
| 14197 | (bookmark-set "org-remember-last-stored") | ||
| 14198 | (org-paste-subtree (org-get-valid-level 1 1) txt))) | ||
| 14199 | |||
| 14200 | ((and (bobp) reversed) | ||
| 14201 | ;; Put it at the start, as level 1 | ||
| 14202 | (save-restriction | ||
| 14203 | (widen) | ||
| 14204 | (goto-char (point-min)) | ||
| 14205 | (re-search-forward "^\\*+ " nil t) | ||
| 14206 | (beginning-of-line 1) | ||
| 14207 | (bookmark-set "org-remember-last-stored") | ||
| 14208 | (org-paste-subtree 1 txt))) | ||
| 14209 | (t | ||
| 14210 | ;; Put it right there, with automatic level determined by | ||
| 14211 | ;; org-paste-subtree or from prefix arg | ||
| 14212 | (bookmark-set "org-remember-last-stored") | ||
| 14213 | (org-paste-subtree | ||
| 14214 | (if (numberp current-prefix-arg) current-prefix-arg) | ||
| 14215 | txt))) | ||
| 14216 | (when remember-save-after-remembering | ||
| 14217 | (save-buffer) | ||
| 14218 | (if (not visiting) (kill-buffer (current-buffer))))))))) | ||
| 14219 | |||
| 14220 | t) ;; return t to indicate that we took care of this note. | ||
| 14221 | |||
| 14222 | (defun org-get-org-file () | ||
| 14223 | "Read a filename, with default directory `org-directory'." | ||
| 14224 | (let ((default (or org-default-notes-file remember-data-file))) | ||
| 14225 | (read-file-name (format "File name [%s]: " default) | ||
| 14226 | (file-name-as-directory org-directory) | ||
| 14227 | default))) | ||
| 14228 | |||
| 14229 | (defun org-notes-order-reversed-p () | ||
| 14230 | "Check if the current file should receive notes in reversed order." | ||
| 14231 | (cond | ||
| 14232 | ((not org-reverse-note-order) nil) | ||
| 14233 | ((eq t org-reverse-note-order) t) | ||
| 14234 | ((not (listp org-reverse-note-order)) nil) | ||
| 14235 | (t (catch 'exit | ||
| 14236 | (let ((all org-reverse-note-order) | ||
| 14237 | entry) | ||
| 14238 | (while (setq entry (pop all)) | ||
| 14239 | (if (string-match (car entry) buffer-file-name) | ||
| 14240 | (throw 'exit (cdr entry)))) | ||
| 14241 | nil))))) | ||
| 14242 | |||
| 14243 | ;;; Refiling | ||
| 14244 | |||
| 14245 | (defvar org-refile-target-table nil | ||
| 14246 | "The list of refile targets, created by `org-refile'.") | ||
| 14247 | |||
| 14248 | (defvar org-agenda-new-buffers nil | ||
| 14249 | "Buffers created to visit agenda files.") | ||
| 14250 | |||
| 14251 | (defun org-get-refile-targets (&optional default-buffer) | ||
| 14252 | "Produce a table with refile targets." | ||
| 14253 | (let ((entries (or org-refile-targets '((nil . (:level . 1))))) | ||
| 14254 | targets txt re files f desc descre) | ||
| 14255 | (with-current-buffer (or default-buffer (current-buffer)) | ||
| 14256 | (while (setq entry (pop entries)) | ||
| 14257 | (setq files (car entry) desc (cdr entry)) | ||
| 14258 | (cond | ||
| 14259 | ((null files) (setq files (list (current-buffer)))) | ||
| 14260 | ((eq files 'org-agenda-files) | ||
| 14261 | (setq files (org-agenda-files 'unrestricted))) | ||
| 14262 | ((and (symbolp files) (fboundp files)) | ||
| 14263 | (setq files (funcall files))) | ||
| 14264 | ((and (symbolp files) (boundp files)) | ||
| 14265 | (setq files (symbol-value files)))) | ||
| 14266 | (if (stringp files) (setq files (list files))) | ||
| 14267 | (cond | ||
| 14268 | ((eq (car desc) :tag) | ||
| 14269 | (setq descre (concat "^\\*+[ \t]+.*?:" (regexp-quote (cdr desc)) ":"))) | ||
| 14270 | ((eq (car desc) :todo) | ||
| 14271 | (setq descre (concat "^\\*+[ \t]+" (regexp-quote (cdr desc)) "[ \t]"))) | ||
| 14272 | ((eq (car desc) :regexp) | ||
| 14273 | (setq descre (cdr desc))) | ||
| 14274 | ((eq (car desc) :level) | ||
| 14275 | (setq descre (concat "^\\*\\{" (number-to-string | ||
| 14276 | (if org-odd-levels-only | ||
| 14277 | (1- (* 2 (cdr desc))) | ||
| 14278 | (cdr desc))) | ||
| 14279 | "\\}[ \t]"))) | ||
| 14280 | ((eq (car desc) :maxlevel) | ||
| 14281 | (setq descre (concat "^\\*\\{1," (number-to-string | ||
| 14282 | (if org-odd-levels-only | ||
| 14283 | (1- (* 2 (cdr desc))) | ||
| 14284 | (cdr desc))) | ||
| 14285 | "\\}[ \t]"))) | ||
| 14286 | (t (error "Bad refiling target description %s" desc))) | ||
| 14287 | (while (setq f (pop files)) | ||
| 14288 | (save-excursion | ||
| 14289 | (set-buffer (if (bufferp f) f (org-get-agenda-file-buffer f))) | ||
| 14290 | (if (bufferp f) (setq f (buffer-file-name (buffer-base-buffer f)))) | ||
| 14291 | (save-excursion | ||
| 14292 | (save-restriction | ||
| 14293 | (widen) | ||
| 14294 | (goto-char (point-min)) | ||
| 14295 | (while (re-search-forward descre nil t) | ||
| 14296 | (goto-char (point-at-bol)) | ||
| 14297 | (when (looking-at org-complex-heading-regexp) | ||
| 14298 | (setq txt (match-string 4) | ||
| 14299 | re (concat "^" (regexp-quote | ||
| 14300 | (buffer-substring (match-beginning 1) | ||
| 14301 | (match-end 4))))) | ||
| 14302 | (if (match-end 5) (setq re (concat re "[ \t]+" | ||
| 14303 | (regexp-quote | ||
| 14304 | (match-string 5))))) | ||
| 14305 | (setq re (concat re "[ \t]*$")) | ||
| 14306 | (when org-refile-use-outline-path | ||
| 14307 | (setq txt (mapconcat 'identity | ||
| 14308 | (append | ||
| 14309 | (if (eq org-refile-use-outline-path 'file) | ||
| 14310 | (list (file-name-nondirectory | ||
| 14311 | (buffer-file-name (buffer-base-buffer)))) | ||
| 14312 | (if (eq org-refile-use-outline-path 'full-file-path) | ||
| 14313 | (list (buffer-file-name (buffer-base-buffer))))) | ||
| 14314 | (org-get-outline-path) | ||
| 14315 | (list txt)) | ||
| 14316 | "/"))) | ||
| 14317 | (push (list txt f re (point)) targets)) | ||
| 14318 | (goto-char (point-at-eol)))))))) | ||
| 14319 | (nreverse targets)))) | ||
| 14320 | |||
| 14321 | (defun org-get-outline-path () | ||
| 14322 | "Return the outline path to the current entry, as a list." | ||
| 14323 | (let (rtn) | ||
| 14324 | (save-excursion | ||
| 14325 | (while (org-up-heading-safe) | ||
| 14326 | (when (looking-at org-complex-heading-regexp) | ||
| 14327 | (push (org-match-string-no-properties 4) rtn))) | ||
| 14328 | rtn))) | ||
| 14329 | |||
| 14330 | (defvar org-refile-history nil | ||
| 14331 | "History for refiling operations.") | ||
| 14332 | |||
| 14333 | (defun org-refile (&optional goto default-buffer) | ||
| 14334 | "Move the entry at point to another heading. | ||
| 14335 | The list of target headings is compiled using the information in | ||
| 14336 | `org-refile-targets', which see. This list is created upon first use, and | ||
| 14337 | you can update it by calling this command with a double prefix (`C-u C-u'). | ||
| 14338 | FIXME: Can we find a better way of updating? | ||
| 14339 | |||
| 14340 | At the target location, the entry is filed as a subitem of the target heading. | ||
| 14341 | Depending on `org-reverse-note-order', the new subitem will either be the | ||
| 14342 | first of the last subitem. | ||
| 14343 | |||
| 14344 | With prefix arg GOTO, the command will only visit the target location, | ||
| 14345 | not actually move anything. | ||
| 14346 | With a double prefix `C-c C-c', go to the location where the last refiling | ||
| 14347 | operation has put the subtree. | ||
| 14348 | |||
| 14349 | With a double prefix argument, the command can be used to jump to any | ||
| 14350 | heading in the current buffer." | ||
| 14351 | (interactive "P") | ||
| 14352 | (let* ((cbuf (current-buffer)) | ||
| 14353 | (filename (buffer-file-name (buffer-base-buffer cbuf))) | ||
| 14354 | pos it nbuf file re level reversed) | ||
| 14355 | (if (equal goto '(16)) | ||
| 14356 | (org-refile-goto-last-stored) | ||
| 14357 | (when (setq it (org-refile-get-location | ||
| 14358 | (if goto "Goto: " "Refile to: ") default-buffer)) | ||
| 14359 | (setq file (nth 1 it) | ||
| 14360 | re (nth 2 it) | ||
| 14361 | pos (nth 3 it)) | ||
| 14362 | (setq nbuf (or (find-buffer-visiting file) | ||
| 14363 | (find-file-noselect file))) | ||
| 14364 | (if goto | ||
| 14365 | (progn | ||
| 14366 | (switch-to-buffer nbuf) | ||
| 14367 | (goto-char pos) | ||
| 14368 | (org-show-context 'org-goto)) | ||
| 14369 | (org-copy-special) | ||
| 14370 | (save-excursion | ||
| 14371 | (set-buffer (setq nbuf (or (find-buffer-visiting file) | ||
| 14372 | (find-file-noselect file)))) | ||
| 14373 | (setq reversed (org-notes-order-reversed-p)) | ||
| 14374 | (save-excursion | ||
| 14375 | (save-restriction | ||
| 14376 | (widen) | ||
| 14377 | (goto-char pos) | ||
| 14378 | (looking-at outline-regexp) | ||
| 14379 | (setq level (org-get-valid-level (funcall outline-level) 1)) | ||
| 14380 | (goto-char | ||
| 14381 | (if reversed | ||
| 14382 | (outline-next-heading) | ||
| 14383 | (or (save-excursion (outline-get-next-sibling)) | ||
| 14384 | (org-end-of-subtree t t) | ||
| 14385 | (point-max)))) | ||
| 14386 | (bookmark-set "org-refile-last-stored") | ||
| 14387 | (org-paste-subtree level)))) | ||
| 14388 | (org-cut-special) | ||
| 14389 | (message "Entry refiled to \"%s\"" (car it))))))) | ||
| 14390 | |||
| 14391 | (defun org-refile-goto-last-stored () | ||
| 14392 | "Go to the location where the last refile was stored." | ||
| 14393 | (interactive) | ||
| 14394 | (bookmark-jump "org-refile-last-stored") | ||
| 14395 | (message "This is the location of the last refile")) | ||
| 14396 | |||
| 14397 | (defun org-refile-get-location (&optional prompt default-buffer) | ||
| 14398 | "Prompt the user for a refile location, using PROMPT." | ||
| 14399 | (let ((org-refile-targets org-refile-targets) | ||
| 14400 | (org-refile-use-outline-path org-refile-use-outline-path)) | ||
| 14401 | (setq org-refile-target-table (org-get-refile-targets default-buffer))) | ||
| 14402 | (unless org-refile-target-table | ||
| 14403 | (error "No refile targets")) | ||
| 14404 | (let* ((cbuf (current-buffer)) | ||
| 14405 | (filename (buffer-file-name (buffer-base-buffer cbuf))) | ||
| 14406 | (fname (and filename (file-truename filename))) | ||
| 14407 | (tbl (mapcar | ||
| 14408 | (lambda (x) | ||
| 14409 | (if (not (equal fname (file-truename (nth 1 x)))) | ||
| 14410 | (cons (concat (car x) " (" (file-name-nondirectory | ||
| 14411 | (nth 1 x)) ")") | ||
| 14412 | (cdr x)) | ||
| 14413 | x)) | ||
| 14414 | org-refile-target-table)) | ||
| 14415 | (completion-ignore-case t)) | ||
| 14416 | (assoc (completing-read prompt tbl nil t nil 'org-refile-history) | ||
| 14417 | tbl))) | ||
| 14418 | |||
| 14419 | ;;;; Dynamic blocks | ||
| 14420 | |||
| 14421 | (defun org-find-dblock (name) | ||
| 14422 | "Find the first dynamic block with name NAME in the buffer. | ||
| 14423 | If not found, stay at current position and return nil." | ||
| 14424 | (let (pos) | ||
| 14425 | (save-excursion | ||
| 14426 | (goto-char (point-min)) | ||
| 14427 | (setq pos (and (re-search-forward (concat "^#\\+BEGIN:[ \t]+" name "\\>") | ||
| 14428 | nil t) | ||
| 14429 | (match-beginning 0)))) | ||
| 14430 | (if pos (goto-char pos)) | ||
| 14431 | pos)) | ||
| 14432 | |||
| 14433 | (defconst org-dblock-start-re | ||
| 14434 | "^#\\+BEGIN:[ \t]+\\(\\S-+\\)\\([ \t]+\\(.*\\)\\)?" | ||
| 14435 | "Matches the startline of a dynamic block, with parameters.") | ||
| 14436 | |||
| 14437 | (defconst org-dblock-end-re "^#\\+END\\([: \t\r\n]\\|$\\)" | ||
| 14438 | "Matches the end of a dyhamic block.") | ||
| 14439 | |||
| 14440 | (defun org-create-dblock (plist) | ||
| 14441 | "Create a dynamic block section, with parameters taken from PLIST. | ||
| 14442 | PLIST must containe a :name entry which is used as name of the block." | ||
| 14443 | (unless (bolp) (newline)) | ||
| 14444 | (let ((name (plist-get plist :name))) | ||
| 14445 | (insert "#+BEGIN: " name) | ||
| 14446 | (while plist | ||
| 14447 | (if (eq (car plist) :name) | ||
| 14448 | (setq plist (cddr plist)) | ||
| 14449 | (insert " " (prin1-to-string (pop plist))))) | ||
| 14450 | (insert "\n\n#+END:\n") | ||
| 14451 | (beginning-of-line -2))) | ||
| 14452 | |||
| 14453 | (defun org-prepare-dblock () | ||
| 14454 | "Prepare dynamic block for refresh. | ||
| 14455 | This empties the block, puts the cursor at the insert position and returns | ||
| 14456 | the property list including an extra property :name with the block name." | ||
| 14457 | (unless (looking-at org-dblock-start-re) | ||
| 14458 | (error "Not at a dynamic block")) | ||
| 14459 | (let* ((begdel (1+ (match-end 0))) | ||
| 14460 | (name (org-no-properties (match-string 1))) | ||
| 14461 | (params (append (list :name name) | ||
| 14462 | (read (concat "(" (match-string 3) ")"))))) | ||
| 14463 | (unless (re-search-forward org-dblock-end-re nil t) | ||
| 14464 | (error "Dynamic block not terminated")) | ||
| 14465 | (setq params | ||
| 14466 | (append params | ||
| 14467 | (list :content (buffer-substring | ||
| 14468 | begdel (match-beginning 0))))) | ||
| 14469 | (delete-region begdel (match-beginning 0)) | ||
| 14470 | (goto-char begdel) | ||
| 14471 | (open-line 1) | ||
| 14472 | params)) | ||
| 14473 | |||
| 14474 | (defun org-map-dblocks (&optional command) | ||
| 14475 | "Apply COMMAND to all dynamic blocks in the current buffer. | ||
| 14476 | If COMMAND is not given, use `org-update-dblock'." | ||
| 14477 | (let ((cmd (or command 'org-update-dblock)) | ||
| 14478 | pos) | ||
| 14479 | (save-excursion | ||
| 14480 | (goto-char (point-min)) | ||
| 14481 | (while (re-search-forward org-dblock-start-re nil t) | ||
| 14482 | (goto-char (setq pos (match-beginning 0))) | ||
| 14483 | (condition-case nil | ||
| 14484 | (funcall cmd) | ||
| 14485 | (error (message "Error during update of dynamic block"))) | ||
| 14486 | (goto-char pos) | ||
| 14487 | (unless (re-search-forward org-dblock-end-re nil t) | ||
| 14488 | (error "Dynamic block not terminated")))))) | ||
| 14489 | |||
| 14490 | (defun org-dblock-update (&optional arg) | ||
| 14491 | "User command for updating dynamic blocks. | ||
| 14492 | Update the dynamic block at point. With prefix ARG, update all dynamic | ||
| 14493 | blocks in the buffer." | ||
| 14494 | (interactive "P") | ||
| 14495 | (if arg | ||
| 14496 | (org-update-all-dblocks) | ||
| 14497 | (or (looking-at org-dblock-start-re) | ||
| 14498 | (org-beginning-of-dblock)) | ||
| 14499 | (org-update-dblock))) | ||
| 14500 | |||
| 14501 | (defun org-update-dblock () | ||
| 14502 | "Update the dynamic block at point | ||
| 14503 | This means to empty the block, parse for parameters and then call | ||
| 14504 | the correct writing function." | ||
| 14505 | (save-window-excursion | ||
| 14506 | (let* ((pos (point)) | ||
| 14507 | (line (org-current-line)) | ||
| 14508 | (params (org-prepare-dblock)) | ||
| 14509 | (name (plist-get params :name)) | ||
| 14510 | (cmd (intern (concat "org-dblock-write:" name)))) | ||
| 14511 | (message "Updating dynamic block `%s' at line %d..." name line) | ||
| 14512 | (funcall cmd params) | ||
| 14513 | (message "Updating dynamic block `%s' at line %d...done" name line) | ||
| 14514 | (goto-char pos)))) | ||
| 14515 | |||
| 14516 | (defun org-beginning-of-dblock () | ||
| 14517 | "Find the beginning of the dynamic block at point. | ||
| 14518 | Error if there is no scuh block at point." | ||
| 14519 | (let ((pos (point)) | ||
| 14520 | beg) | ||
| 14521 | (end-of-line 1) | ||
| 14522 | (if (and (re-search-backward org-dblock-start-re nil t) | ||
| 14523 | (setq beg (match-beginning 0)) | ||
| 14524 | (re-search-forward org-dblock-end-re nil t) | ||
| 14525 | (> (match-end 0) pos)) | ||
| 14526 | (goto-char beg) | ||
| 14527 | (goto-char pos) | ||
| 14528 | (error "Not in a dynamic block")))) | ||
| 14529 | |||
| 14530 | (defun org-update-all-dblocks () | ||
| 14531 | "Update all dynamic blocks in the buffer. | ||
| 14532 | This function can be used in a hook." | ||
| 14533 | (when (org-mode-p) | ||
| 14534 | (org-map-dblocks 'org-update-dblock))) | ||
| 14535 | |||
| 14536 | |||
| 14537 | ;;;; Completion | ||
| 14538 | |||
| 14539 | (defconst org-additional-option-like-keywords | ||
| 14540 | '("BEGIN_HTML" "BEGIN_LaTeX" "END_HTML" "END_LaTeX" | ||
| 14541 | "ORGTBL" "HTML:" "LaTeX:" "BEGIN:" "END:" "DATE:" "TBLFM" | ||
| 14542 | "BEGIN_EXAMPLE" "END_EXAMPLE")) | ||
| 14543 | |||
| 14544 | (defun org-complete (&optional arg) | ||
| 14545 | "Perform completion on word at point. | ||
| 14546 | At the beginning of a headline, this completes TODO keywords as given in | ||
| 14547 | `org-todo-keywords'. | ||
| 14548 | If the current word is preceded by a backslash, completes the TeX symbols | ||
| 14549 | that are supported for HTML support. | ||
| 14550 | If the current word is preceded by \"#+\", completes special words for | ||
| 14551 | setting file options. | ||
| 14552 | In the line after \"#+STARTUP:, complete valid keywords.\" | ||
| 14553 | At all other locations, this simply calls the value of | ||
| 14554 | `org-completion-fallback-command'." | ||
| 14555 | (interactive "P") | ||
| 14556 | (org-without-partial-completion | ||
| 14557 | (catch 'exit | ||
| 14558 | (let* ((end (point)) | ||
| 14559 | (beg1 (save-excursion | ||
| 14560 | (skip-chars-backward (org-re "[:alnum:]_@")) | ||
| 14561 | (point))) | ||
| 14562 | (beg (save-excursion | ||
| 14563 | (skip-chars-backward "a-zA-Z0-9_:$") | ||
| 14564 | (point))) | ||
| 14565 | (confirm (lambda (x) (stringp (car x)))) | ||
| 14566 | (searchhead (equal (char-before beg) ?*)) | ||
| 14567 | (tag (and (equal (char-before beg1) ?:) | ||
| 14568 | (equal (char-after (point-at-bol)) ?*))) | ||
| 14569 | (prop (and (equal (char-before beg1) ?:) | ||
| 14570 | (not (equal (char-after (point-at-bol)) ?*)))) | ||
| 14571 | (texp (equal (char-before beg) ?\\)) | ||
| 14572 | (link (equal (char-before beg) ?\[)) | ||
| 14573 | (opt (equal (buffer-substring (max (point-at-bol) (- beg 2)) | ||
| 14574 | beg) | ||
| 14575 | "#+")) | ||
| 14576 | (startup (string-match "^#\\+STARTUP:.*" | ||
| 14577 | (buffer-substring (point-at-bol) (point)))) | ||
| 14578 | (completion-ignore-case opt) | ||
| 14579 | (type nil) | ||
| 14580 | (tbl nil) | ||
| 14581 | (table (cond | ||
| 14582 | (opt | ||
| 14583 | (setq type :opt) | ||
| 14584 | (append | ||
| 14585 | (mapcar | ||
| 14586 | (lambda (x) | ||
| 14587 | (string-match "^#\\+\\(\\([A-Z_]+:?\\).*\\)" x) | ||
| 14588 | (cons (match-string 2 x) (match-string 1 x))) | ||
| 14589 | (org-split-string (org-get-current-options) "\n")) | ||
| 14590 | (mapcar 'list org-additional-option-like-keywords))) | ||
| 14591 | (startup | ||
| 14592 | (setq type :startup) | ||
| 14593 | org-startup-options) | ||
| 14594 | (link (append org-link-abbrev-alist-local | ||
| 14595 | org-link-abbrev-alist)) | ||
| 14596 | (texp | ||
| 14597 | (setq type :tex) | ||
| 14598 | org-html-entities) | ||
| 14599 | ((string-match "\\`\\*+[ \t]+\\'" | ||
| 14600 | (buffer-substring (point-at-bol) beg)) | ||
| 14601 | (setq type :todo) | ||
| 14602 | (mapcar 'list org-todo-keywords-1)) | ||
| 14603 | (searchhead | ||
| 14604 | (setq type :searchhead) | ||
| 14605 | (save-excursion | ||
| 14606 | (goto-char (point-min)) | ||
| 14607 | (while (re-search-forward org-todo-line-regexp nil t) | ||
| 14608 | (push (list | ||
| 14609 | (org-make-org-heading-search-string | ||
| 14610 | (match-string 3) t)) | ||
| 14611 | tbl))) | ||
| 14612 | tbl) | ||
| 14613 | (tag (setq type :tag beg beg1) | ||
| 14614 | (or org-tag-alist (org-get-buffer-tags))) | ||
| 14615 | (prop (setq type :prop beg beg1) | ||
| 14616 | (mapcar 'list (org-buffer-property-keys nil t t))) | ||
| 14617 | (t (progn | ||
| 14618 | (call-interactively org-completion-fallback-command) | ||
| 14619 | (throw 'exit nil))))) | ||
| 14620 | (pattern (buffer-substring-no-properties beg end)) | ||
| 14621 | (completion (try-completion pattern table confirm))) | ||
| 14622 | (cond ((eq completion t) | ||
| 14623 | (if (not (assoc (upcase pattern) table)) | ||
| 14624 | (message "Already complete") | ||
| 14625 | (if (equal type :opt) | ||
| 14626 | (insert (substring (cdr (assoc (upcase pattern) table)) | ||
| 14627 | (length pattern))) | ||
| 14628 | (if (memq type '(:tag :prop)) (insert ":"))))) | ||
| 14629 | ((null completion) | ||
| 14630 | (message "Can't find completion for \"%s\"" pattern) | ||
| 14631 | (ding)) | ||
| 14632 | ((not (string= pattern completion)) | ||
| 14633 | (delete-region beg end) | ||
| 14634 | (if (string-match " +$" completion) | ||
| 14635 | (setq completion (replace-match "" t t completion))) | ||
| 14636 | (insert completion) | ||
| 14637 | (if (get-buffer-window "*Completions*") | ||
| 14638 | (delete-window (get-buffer-window "*Completions*"))) | ||
| 14639 | (if (assoc completion table) | ||
| 14640 | (if (eq type :todo) (insert " ") | ||
| 14641 | (if (memq type '(:tag :prop)) (insert ":")))) | ||
| 14642 | (if (and (equal type :opt) (assoc completion table)) | ||
| 14643 | (message "%s" (substitute-command-keys | ||
| 14644 | "Press \\[org-complete] again to insert example settings")))) | ||
| 14645 | (t | ||
| 14646 | (message "Making completion list...") | ||
| 14647 | (let ((list (sort (all-completions pattern table confirm) | ||
| 14648 | 'string<))) | ||
| 14649 | (with-output-to-temp-buffer "*Completions*" | ||
| 14650 | (condition-case nil | ||
| 14651 | ;; Protection needed for XEmacs and emacs 21 | ||
| 14652 | (display-completion-list list pattern) | ||
| 14653 | (error (display-completion-list list))))) | ||
| 14654 | (message "Making completion list...%s" "done"))))))) | ||
| 14655 | |||
| 14656 | ;;;; TODO, DEADLINE, Comments | ||
| 14657 | |||
| 14658 | (defun org-toggle-comment () | ||
| 14659 | "Change the COMMENT state of an entry." | ||
| 14660 | (interactive) | ||
| 14661 | (save-excursion | ||
| 14662 | (org-back-to-heading) | ||
| 14663 | (let (case-fold-search) | ||
| 14664 | (if (looking-at (concat outline-regexp | ||
| 14665 | "\\( *\\<" org-comment-string "\\>[ \t]*\\)")) | ||
| 14666 | (replace-match "" t t nil 1) | ||
| 14667 | (if (looking-at outline-regexp) | ||
| 14668 | (progn | ||
| 14669 | (goto-char (match-end 0)) | ||
| 14670 | (insert org-comment-string " "))))))) | ||
| 14671 | |||
| 14672 | (defvar org-last-todo-state-is-todo nil | ||
| 14673 | "This is non-nil when the last TODO state change led to a TODO state. | ||
| 14674 | If the last change removed the TODO tag or switched to DONE, then | ||
| 14675 | this is nil.") | ||
| 14676 | |||
| 14677 | (defvar org-setting-tags nil) ; dynamically skiped | ||
| 14678 | |||
| 14679 | ;; FIXME: better place | ||
| 14680 | (defun org-property-or-variable-value (var &optional inherit) | ||
| 14681 | "Check if there is a property fixing the value of VAR. | ||
| 14682 | If yes, return this value. If not, return the current value of the variable." | ||
| 14683 | (let ((prop (org-entry-get nil (symbol-name var) inherit))) | ||
| 14684 | (if (and prop (stringp prop) (string-match "\\S-" prop)) | ||
| 14685 | (read prop) | ||
| 14686 | (symbol-value var)))) | ||
| 14687 | |||
| 14688 | (defun org-parse-local-options (string var) | ||
| 14689 | "Parse STRING for startup setting relevant for variable VAR." | ||
| 14690 | (let ((rtn (symbol-value var)) | ||
| 14691 | e opts) | ||
| 14692 | (save-match-data | ||
| 14693 | (if (or (not string) (not (string-match "\\S-" string))) | ||
| 14694 | rtn | ||
| 14695 | (setq opts (delq nil (mapcar (lambda (x) | ||
| 14696 | (setq e (assoc x org-startup-options)) | ||
| 14697 | (if (eq (nth 1 e) var) e nil)) | ||
| 14698 | (org-split-string string "[ \t]+")))) | ||
| 14699 | (if (not opts) | ||
| 14700 | rtn | ||
| 14701 | (setq rtn nil) | ||
| 14702 | (while (setq e (pop opts)) | ||
| 14703 | (if (not (nth 3 e)) | ||
| 14704 | (setq rtn (nth 2 e)) | ||
| 14705 | (if (not (listp rtn)) (setq rtn nil)) | ||
| 14706 | (push (nth 2 e) rtn))) | ||
| 14707 | rtn))))) | ||
| 14708 | |||
| 14709 | (defvar org-blocker-hook nil | ||
| 14710 | "Hook for functions that are allowed to block a state change. | ||
| 14711 | |||
| 14712 | Each function gets as its single argument a property list, see | ||
| 14713 | `org-trigger-hook' for more information about this list. | ||
| 14714 | |||
| 14715 | If any of the functions in this hook returns nil, the state change | ||
| 14716 | is blocked.") | ||
| 14717 | |||
| 14718 | (defvar org-trigger-hook nil | ||
| 14719 | "Hook for functions that are triggered by a state change. | ||
| 14720 | |||
| 14721 | Each function gets as its single argument a property list with at least | ||
| 14722 | the following elements: | ||
| 14723 | |||
| 14724 | (:type type-of-change :position pos-at-entry-start | ||
| 14725 | :from old-state :to new-state) | ||
| 14726 | |||
| 14727 | Depending on the type, more properties may be present. | ||
| 14728 | |||
| 14729 | This mechanism is currently implemented for: | ||
| 14730 | |||
| 14731 | TODO state changes | ||
| 14732 | ------------------ | ||
| 14733 | :type todo-state-change | ||
| 14734 | :from previous state (keyword as a string), or nil | ||
| 14735 | :to new state (keyword as a string), or nil") | ||
| 14736 | |||
| 14737 | |||
| 14738 | (defun org-todo (&optional arg) | ||
| 14739 | "Change the TODO state of an item. | ||
| 14740 | The state of an item is given by a keyword at the start of the heading, | ||
| 14741 | like | ||
| 14742 | *** TODO Write paper | ||
| 14743 | *** DONE Call mom | ||
| 14744 | |||
| 14745 | The different keywords are specified in the variable `org-todo-keywords'. | ||
| 14746 | By default the available states are \"TODO\" and \"DONE\". | ||
| 14747 | So for this example: when the item starts with TODO, it is changed to DONE. | ||
| 14748 | When it starts with DONE, the DONE is removed. And when neither TODO nor | ||
| 14749 | DONE are present, add TODO at the beginning of the heading. | ||
| 14750 | |||
| 14751 | With C-u prefix arg, use completion to determine the new state. | ||
| 14752 | With numeric prefix arg, switch to that state. | ||
| 14753 | |||
| 14754 | For calling through lisp, arg is also interpreted in the following way: | ||
| 14755 | 'none -> empty state | ||
| 14756 | \"\"(empty string) -> switch to empty state | ||
| 14757 | 'done -> switch to DONE | ||
| 14758 | 'nextset -> switch to the next set of keywords | ||
| 14759 | 'previousset -> switch to the previous set of keywords | ||
| 14760 | \"WAITING\" -> switch to the specified keyword, but only if it | ||
| 14761 | really is a member of `org-todo-keywords'." | ||
| 14762 | (interactive "P") | ||
| 14763 | (save-excursion | ||
| 14764 | (catch 'exit | ||
| 14765 | (org-back-to-heading) | ||
| 14766 | (if (looking-at outline-regexp) (goto-char (1- (match-end 0)))) | ||
| 14767 | (or (looking-at (concat " +" org-todo-regexp " *")) | ||
| 14768 | (looking-at " *")) | ||
| 14769 | (let* ((match-data (match-data)) | ||
| 14770 | (startpos (point-at-bol)) | ||
| 14771 | (logging (save-match-data (org-entry-get nil "LOGGING" t))) | ||
| 14772 | (org-log-done org-log-done) | ||
| 14773 | (org-log-repeat org-log-repeat) | ||
| 14774 | (org-todo-log-states org-todo-log-states) | ||
| 14775 | (this (match-string 1)) | ||
| 14776 | (hl-pos (match-beginning 0)) | ||
| 14777 | (head (org-get-todo-sequence-head this)) | ||
| 14778 | (ass (assoc head org-todo-kwd-alist)) | ||
| 14779 | (interpret (nth 1 ass)) | ||
| 14780 | (done-word (nth 3 ass)) | ||
| 14781 | (final-done-word (nth 4 ass)) | ||
| 14782 | (last-state (or this "")) | ||
| 14783 | (completion-ignore-case t) | ||
| 14784 | (member (member this org-todo-keywords-1)) | ||
| 14785 | (tail (cdr member)) | ||
| 14786 | (state (cond | ||
| 14787 | ((and org-todo-key-trigger | ||
| 14788 | (or (and (equal arg '(4)) (eq org-use-fast-todo-selection 'prefix)) | ||
| 14789 | (and (not arg) org-use-fast-todo-selection | ||
| 14790 | (not (eq org-use-fast-todo-selection 'prefix))))) | ||
| 14791 | ;; Use fast selection | ||
| 14792 | (org-fast-todo-selection)) | ||
| 14793 | ((and (equal arg '(4)) | ||
| 14794 | (or (not org-use-fast-todo-selection) | ||
| 14795 | (not org-todo-key-trigger))) | ||
| 14796 | ;; Read a state with completion | ||
| 14797 | (completing-read "State: " (mapcar (lambda(x) (list x)) | ||
| 14798 | org-todo-keywords-1) | ||
| 14799 | nil t)) | ||
| 14800 | ((eq arg 'right) | ||
| 14801 | (if this | ||
| 14802 | (if tail (car tail) nil) | ||
| 14803 | (car org-todo-keywords-1))) | ||
| 14804 | ((eq arg 'left) | ||
| 14805 | (if (equal member org-todo-keywords-1) | ||
| 14806 | nil | ||
| 14807 | (if this | ||
| 14808 | (nth (- (length org-todo-keywords-1) (length tail) 2) | ||
| 14809 | org-todo-keywords-1) | ||
| 14810 | (org-last org-todo-keywords-1)))) | ||
| 14811 | ((and (eq org-use-fast-todo-selection t) (equal arg '(4)) | ||
| 14812 | (setq arg nil))) ; hack to fall back to cycling | ||
| 14813 | (arg | ||
| 14814 | ;; user or caller requests a specific state | ||
| 14815 | (cond | ||
| 14816 | ((equal arg "") nil) | ||
| 14817 | ((eq arg 'none) nil) | ||
| 14818 | ((eq arg 'done) (or done-word (car org-done-keywords))) | ||
| 14819 | ((eq arg 'nextset) | ||
| 14820 | (or (car (cdr (member head org-todo-heads))) | ||
| 14821 | (car org-todo-heads))) | ||
| 14822 | ((eq arg 'previousset) | ||
| 14823 | (let ((org-todo-heads (reverse org-todo-heads))) | ||
| 14824 | (or (car (cdr (member head org-todo-heads))) | ||
| 14825 | (car org-todo-heads)))) | ||
| 14826 | ((car (member arg org-todo-keywords-1))) | ||
| 14827 | ((nth (1- (prefix-numeric-value arg)) | ||
| 14828 | org-todo-keywords-1)))) | ||
| 14829 | ((null member) (or head (car org-todo-keywords-1))) | ||
| 14830 | ((equal this final-done-word) nil) ;; -> make empty | ||
| 14831 | ((null tail) nil) ;; -> first entry | ||
| 14832 | ((eq interpret 'sequence) | ||
| 14833 | (car tail)) | ||
| 14834 | ((memq interpret '(type priority)) | ||
| 14835 | (if (eq this-command last-command) | ||
| 14836 | (car tail) | ||
| 14837 | (if (> (length tail) 0) | ||
| 14838 | (or done-word (car org-done-keywords)) | ||
| 14839 | nil))) | ||
| 14840 | (t nil))) | ||
| 14841 | (next (if state (concat " " state " ") " ")) | ||
| 14842 | (change-plist (list :type 'todo-state-change :from this :to state | ||
| 14843 | :position startpos)) | ||
| 14844 | dolog now-done-p) | ||
| 14845 | (when org-blocker-hook | ||
| 14846 | (unless (save-excursion | ||
| 14847 | (save-match-data | ||
| 14848 | (run-hook-with-args-until-failure | ||
| 14849 | 'org-blocker-hook change-plist))) | ||
| 14850 | (if (interactive-p) | ||
| 14851 | (error "TODO state change from %s to %s blocked" this state) | ||
| 14852 | ;; fail silently | ||
| 14853 | (message "TODO state change from %s to %s blocked" this state) | ||
| 14854 | (throw 'exit nil)))) | ||
| 14855 | (store-match-data match-data) | ||
| 14856 | (replace-match next t t) | ||
| 14857 | (unless (pos-visible-in-window-p hl-pos) | ||
| 14858 | (message "TODO state changed to %s" (org-trim next))) | ||
| 14859 | (unless head | ||
| 14860 | (setq head (org-get-todo-sequence-head state) | ||
| 14861 | ass (assoc head org-todo-kwd-alist) | ||
| 14862 | interpret (nth 1 ass) | ||
| 14863 | done-word (nth 3 ass) | ||
| 14864 | final-done-word (nth 4 ass))) | ||
| 14865 | (when (memq arg '(nextset previousset)) | ||
| 14866 | (message "Keyword-Set %d/%d: %s" | ||
| 14867 | (- (length org-todo-sets) -1 | ||
| 14868 | (length (memq (assoc state org-todo-sets) org-todo-sets))) | ||
| 14869 | (length org-todo-sets) | ||
| 14870 | (mapconcat 'identity (assoc state org-todo-sets) " "))) | ||
| 14871 | (setq org-last-todo-state-is-todo | ||
| 14872 | (not (member state org-done-keywords))) | ||
| 14873 | (setq now-done-p (and (member state org-done-keywords) | ||
| 14874 | (not (member this org-done-keywords)))) | ||
| 14875 | (and logging (org-local-logging logging)) | ||
| 14876 | (when (and (or org-todo-log-states org-log-done) | ||
| 14877 | (not (memq arg '(nextset previousset)))) | ||
| 14878 | ;; we need to look at recording a time and note | ||
| 14879 | (setq dolog (or (nth 1 (assoc state org-todo-log-states)) | ||
| 14880 | (nth 2 (assoc this org-todo-log-states)))) | ||
| 14881 | (when (and state | ||
| 14882 | (member state org-not-done-keywords) | ||
| 14883 | (not (member this org-not-done-keywords))) | ||
| 14884 | ;; This is now a todo state and was not one before | ||
| 14885 | ;; If there was a CLOSED time stamp, get rid of it. | ||
| 14886 | (org-add-planning-info nil nil 'closed)) | ||
| 14887 | (when (and now-done-p org-log-done) | ||
| 14888 | ;; It is now done, and it was not done before | ||
| 14889 | (org-add-planning-info 'closed (org-current-time)) | ||
| 14890 | (if (and (not dolog) (eq 'note org-log-done)) | ||
| 14891 | (org-add-log-maybe 'done state 'findpos 'note))) | ||
| 14892 | (when (and state dolog) | ||
| 14893 | ;; This is a non-nil state, and we need to log it | ||
| 14894 | (org-add-log-maybe 'state state 'findpos dolog))) | ||
| 14895 | ;; Fixup tag positioning | ||
| 14896 | (and org-auto-align-tags (not org-setting-tags) (org-set-tags nil t)) | ||
| 14897 | (run-hooks 'org-after-todo-state-change-hook) | ||
| 14898 | (if (and arg (not (member state org-done-keywords))) | ||
| 14899 | (setq head (org-get-todo-sequence-head state))) | ||
| 14900 | (put-text-property (point-at-bol) (point-at-eol) 'org-todo-head head) | ||
| 14901 | ;; Do we need to trigger a repeat? | ||
| 14902 | (when now-done-p (org-auto-repeat-maybe state)) | ||
| 14903 | ;; Fixup cursor location if close to the keyword | ||
| 14904 | (if (and (outline-on-heading-p) | ||
| 14905 | (not (bolp)) | ||
| 14906 | (save-excursion (beginning-of-line 1) | ||
| 14907 | (looking-at org-todo-line-regexp)) | ||
| 14908 | (< (point) (+ 2 (or (match-end 2) (match-end 1))))) | ||
| 14909 | (progn | ||
| 14910 | (goto-char (or (match-end 2) (match-end 1))) | ||
| 14911 | (just-one-space))) | ||
| 14912 | (when org-trigger-hook | ||
| 14913 | (save-excursion | ||
| 14914 | (run-hook-with-args 'org-trigger-hook change-plist))))))) | ||
| 14915 | |||
| 14916 | (defun org-local-logging (value) | ||
| 14917 | "Get logging settings from a property VALUE." | ||
| 14918 | (let* (words w a) | ||
| 14919 | ;; directly set the variables, they are already local. | ||
| 14920 | (setq org-log-done nil | ||
| 14921 | org-log-repeat nil | ||
| 14922 | org-todo-log-states nil) | ||
| 14923 | (setq words (org-split-string value)) | ||
| 14924 | (while (setq w (pop words)) | ||
| 14925 | (cond | ||
| 14926 | ((setq a (assoc w org-startup-options)) | ||
| 14927 | (and (member (nth 1 a) '(org-log-done org-log-repeat)) | ||
| 14928 | (set (nth 1 a) (nth 2 a)))) | ||
| 14929 | ((setq a (org-extract-log-state-settings w)) | ||
| 14930 | (and (member (car a) org-todo-keywords-1) | ||
| 14931 | (push a org-todo-log-states))))))) | ||
| 14932 | |||
| 14933 | (defun org-get-todo-sequence-head (kwd) | ||
| 14934 | "Return the head of the TODO sequence to which KWD belongs. | ||
| 14935 | If KWD is not set, check if there is a text property remembering the | ||
| 14936 | right sequence." | ||
| 14937 | (let (p) | ||
| 14938 | (cond | ||
| 14939 | ((not kwd) | ||
| 14940 | (or (get-text-property (point-at-bol) 'org-todo-head) | ||
| 14941 | (progn | ||
| 14942 | (setq p (next-single-property-change (point-at-bol) 'org-todo-head | ||
| 14943 | nil (point-at-eol))) | ||
| 14944 | (get-text-property p 'org-todo-head)))) | ||
| 14945 | ((not (member kwd org-todo-keywords-1)) | ||
| 14946 | (car org-todo-keywords-1)) | ||
| 14947 | (t (nth 2 (assoc kwd org-todo-kwd-alist)))))) | ||
| 14948 | |||
| 14949 | (defun org-fast-todo-selection () | ||
| 14950 | "Fast TODO keyword selection with single keys. | ||
| 14951 | Returns the new TODO keyword, or nil if no state change should occur." | ||
| 14952 | (let* ((fulltable org-todo-key-alist) | ||
| 14953 | (done-keywords org-done-keywords) ;; needed for the faces. | ||
| 14954 | (maxlen (apply 'max (mapcar | ||
| 14955 | (lambda (x) | ||
| 14956 | (if (stringp (car x)) (string-width (car x)) 0)) | ||
| 14957 | fulltable))) | ||
| 14958 | (expert nil) | ||
| 14959 | (fwidth (+ maxlen 3 1 3)) | ||
| 14960 | (ncol (/ (- (window-width) 4) fwidth)) | ||
| 14961 | tg cnt e c tbl | ||
| 14962 | groups ingroup) | ||
| 14963 | (save-window-excursion | ||
| 14964 | (if expert | ||
| 14965 | (set-buffer (get-buffer-create " *Org todo*")) | ||
| 14966 | (org-switch-to-buffer-other-window (get-buffer-create " *Org todo*"))) | ||
| 14967 | (erase-buffer) | ||
| 14968 | (org-set-local 'org-done-keywords done-keywords) | ||
| 14969 | (setq tbl fulltable cnt 0) | ||
| 14970 | (while (setq e (pop tbl)) | ||
| 14971 | (cond | ||
| 14972 | ((equal e '(:startgroup)) | ||
| 14973 | (push '() groups) (setq ingroup t) | ||
| 14974 | (when (not (= cnt 0)) | ||
| 14975 | (setq cnt 0) | ||
| 14976 | (insert "\n")) | ||
| 14977 | (insert "{ ")) | ||
| 14978 | ((equal e '(:endgroup)) | ||
| 14979 | (setq ingroup nil cnt 0) | ||
| 14980 | (insert "}\n")) | ||
| 14981 | (t | ||
| 14982 | (setq tg (car e) c (cdr e)) | ||
| 14983 | (if ingroup (push tg (car groups))) | ||
| 14984 | (setq tg (org-add-props tg nil 'face | ||
| 14985 | (org-get-todo-face tg))) | ||
| 14986 | (if (and (= cnt 0) (not ingroup)) (insert " ")) | ||
| 14987 | (insert "[" c "] " tg (make-string | ||
| 14988 | (- fwidth 4 (length tg)) ?\ )) | ||
| 14989 | (when (= (setq cnt (1+ cnt)) ncol) | ||
| 14990 | (insert "\n") | ||
| 14991 | (if ingroup (insert " ")) | ||
| 14992 | (setq cnt 0))))) | ||
| 14993 | (insert "\n") | ||
| 14994 | (goto-char (point-min)) | ||
| 14995 | (if (and (not expert) (fboundp 'fit-window-to-buffer)) | ||
| 14996 | (fit-window-to-buffer)) | ||
| 14997 | (message "[a-z..]:Set [SPC]:clear") | ||
| 14998 | (setq c (let ((inhibit-quit t)) (read-char-exclusive))) | ||
| 14999 | (cond | ||
| 15000 | ((or (= c ?\C-g) | ||
| 15001 | (and (= c ?q) (not (rassoc c fulltable)))) | ||
| 15002 | (setq quit-flag t)) | ||
| 15003 | ((= c ?\ ) nil) | ||
| 15004 | ((setq e (rassoc c fulltable) tg (car e)) | ||
| 15005 | tg) | ||
| 15006 | (t (setq quit-flag t)))))) | ||
| 15007 | |||
| 15008 | (defun org-get-repeat () | ||
| 15009 | "Check if tere is a deadline/schedule with repeater in this entry." | ||
| 15010 | (save-match-data | ||
| 15011 | (save-excursion | ||
| 15012 | (org-back-to-heading t) | ||
| 15013 | (if (re-search-forward | ||
| 15014 | org-repeat-re (save-excursion (outline-next-heading) (point)) t) | ||
| 15015 | (match-string 1))))) | ||
| 15016 | |||
| 15017 | (defvar org-last-changed-timestamp) | ||
| 15018 | (defvar org-log-post-message) | ||
| 15019 | (defvar org-log-note-purpose) | ||
| 15020 | (defun org-auto-repeat-maybe (done-word) | ||
| 15021 | "Check if the current headline contains a repeated deadline/schedule. | ||
| 15022 | If yes, set TODO state back to what it was and change the base date | ||
| 15023 | of repeating deadline/scheduled time stamps to new date. | ||
| 15024 | This function is run automatically after each state change to a DONE state." | ||
| 15025 | ;; last-state is dynamically scoped into this function | ||
| 15026 | (let* ((repeat (org-get-repeat)) | ||
| 15027 | (aa (assoc last-state org-todo-kwd-alist)) | ||
| 15028 | (interpret (nth 1 aa)) | ||
| 15029 | (head (nth 2 aa)) | ||
| 15030 | (whata '(("d" . day) ("m" . month) ("y" . year))) | ||
| 15031 | (msg "Entry repeats: ") | ||
| 15032 | (org-log-done nil) | ||
| 15033 | (org-todo-log-states nil) | ||
| 15034 | (nshiftmax 10) (nshift 0) | ||
| 15035 | re type n what ts mb0 time) | ||
| 15036 | (when repeat | ||
| 15037 | (if (eq org-log-repeat t) (setq org-log-repeat 'state)) | ||
| 15038 | (org-todo (if (eq interpret 'type) last-state head)) | ||
| 15039 | (when (and org-log-repeat | ||
| 15040 | (or (not (memq 'org-add-log-note | ||
| 15041 | (default-value 'post-command-hook))) | ||
| 15042 | (eq org-log-note-purpose 'done))) | ||
| 15043 | ;; Make sure a note is taken; | ||
| 15044 | (org-add-log-maybe 'state (or done-word (car org-done-keywords)) | ||
| 15045 | 'findpos org-log-repeat)) | ||
| 15046 | (org-back-to-heading t) | ||
| 15047 | (org-add-planning-info nil nil 'closed) | ||
| 15048 | (setq re (concat "\\(" org-scheduled-time-regexp "\\)\\|\\(" | ||
| 15049 | org-deadline-time-regexp "\\)\\|\\(" | ||
| 15050 | org-ts-regexp "\\)")) | ||
| 15051 | (while (re-search-forward | ||
| 15052 | re (save-excursion (outline-next-heading) (point)) t) | ||
| 15053 | (setq type (if (match-end 1) org-scheduled-string | ||
| 15054 | (if (match-end 3) org-deadline-string "Plain:")) | ||
| 15055 | ts (match-string (if (match-end 2) 2 (if (match-end 4) 4 0))) | ||
| 15056 | mb0 (match-beginning 0)) | ||
| 15057 | (when (string-match "\\([.+]\\)?\\(\\+[0-9]+\\)\\([dwmy]\\)" ts) | ||
| 15058 | (setq n (string-to-number (match-string 2 ts)) | ||
| 15059 | what (match-string 3 ts)) | ||
| 15060 | (if (equal what "w") (setq n (* n 7) what "d")) | ||
| 15061 | ;; Preparation, see if we need to modify the start date for the change | ||
| 15062 | (when (match-end 1) | ||
| 15063 | (setq time (save-match-data (org-time-string-to-time ts))) | ||
| 15064 | (cond | ||
| 15065 | ((equal (match-string 1 ts) ".") | ||
| 15066 | ;; Shift starting date to today | ||
| 15067 | (org-timestamp-change | ||
| 15068 | (- (time-to-days (current-time)) (time-to-days time)) | ||
| 15069 | 'day)) | ||
| 15070 | ((equal (match-string 1 ts) "+") | ||
| 15071 | (while (< (time-to-days time) (time-to-days (current-time))) | ||
| 15072 | (when (= (incf nshift) nshiftmax) | ||
| 15073 | (or (y-or-n-p (message "%d repeater intervals were not enough to shift date past today. Continue? " nshift)) | ||
| 15074 | (error "Abort"))) | ||
| 15075 | (org-timestamp-change n (cdr (assoc what whata))) | ||
| 15076 | (sit-for .0001) ;; so we can watch the date shifting | ||
| 15077 | (org-at-timestamp-p t) | ||
| 15078 | (setq ts (match-string 1)) | ||
| 15079 | (setq time (save-match-data (org-time-string-to-time ts)))) | ||
| 15080 | (org-timestamp-change (- n) (cdr (assoc what whata))) | ||
| 15081 | ;; rematch, so that we have everything in place for the real shift | ||
| 15082 | (org-at-timestamp-p t) | ||
| 15083 | (setq ts (match-string 1)) | ||
| 15084 | (string-match "\\([.+]\\)?\\(\\+[0-9]+\\)\\([dwmy]\\)" ts)))) | ||
| 15085 | (org-timestamp-change n (cdr (assoc what whata))) | ||
| 15086 | (setq msg (concat msg type org-last-changed-timestamp " ")))) | ||
| 15087 | (setq org-log-post-message msg) | ||
| 15088 | (message "%s" msg)))) | ||
| 15089 | |||
| 15090 | (defun org-show-todo-tree (arg) | ||
| 15091 | "Make a compact tree which shows all headlines marked with TODO. | ||
| 15092 | The tree will show the lines where the regexp matches, and all higher | ||
| 15093 | headlines above the match. | ||
| 15094 | With a \\[universal-argument] prefix, also show the DONE entries. | ||
| 15095 | With a numeric prefix N, construct a sparse tree for the Nth element | ||
| 15096 | of `org-todo-keywords-1'." | ||
| 15097 | (interactive "P") | ||
| 15098 | (let ((case-fold-search nil) | ||
| 15099 | (kwd-re | ||
| 15100 | (cond ((null arg) org-not-done-regexp) | ||
| 15101 | ((equal arg '(4)) | ||
| 15102 | (let ((kwd (completing-read "Keyword (or KWD1|KWD2|...): " | ||
| 15103 | (mapcar 'list org-todo-keywords-1)))) | ||
| 15104 | (concat "\\(" | ||
| 15105 | (mapconcat 'identity (org-split-string kwd "|") "\\|") | ||
| 15106 | "\\)\\>"))) | ||
| 15107 | ((<= (prefix-numeric-value arg) (length org-todo-keywords-1)) | ||
| 15108 | (regexp-quote (nth (1- (prefix-numeric-value arg)) | ||
| 15109 | org-todo-keywords-1))) | ||
| 15110 | (t (error "Invalid prefix argument: %s" arg))))) | ||
| 15111 | (message "%d TODO entries found" | ||
| 15112 | (org-occur (concat "^" outline-regexp " *" kwd-re ))))) | ||
| 15113 | |||
| 15114 | (defun org-deadline (&optional remove) | ||
| 15115 | "Insert the \"DEADLINE:\" string with a timestamp to make a deadline. | ||
| 15116 | With argument REMOVE, remove any deadline from the item." | ||
| 15117 | (interactive "P") | ||
| 15118 | (if remove | ||
| 15119 | (progn | ||
| 15120 | (org-remove-timestamp-with-keyword org-deadline-string) | ||
| 15121 | (message "Item no longer has a deadline.")) | ||
| 15122 | (org-add-planning-info 'deadline nil 'closed))) | ||
| 15123 | |||
| 15124 | (defun org-schedule (&optional remove) | ||
| 15125 | "Insert the SCHEDULED: string with a timestamp to schedule a TODO item. | ||
| 15126 | With argument REMOVE, remove any scheduling date from the item." | ||
| 15127 | (interactive "P") | ||
| 15128 | (if remove | ||
| 15129 | (progn | ||
| 15130 | (org-remove-timestamp-with-keyword org-scheduled-string) | ||
| 15131 | (message "Item is no longer scheduled.")) | ||
| 15132 | (org-add-planning-info 'scheduled nil 'closed))) | ||
| 15133 | |||
| 15134 | (defun org-remove-timestamp-with-keyword (keyword) | ||
| 15135 | "Remove all time stamps with KEYWORD in the current entry." | ||
| 15136 | (let ((re (concat "\\<" (regexp-quote keyword) " +<[^>\n]+>[ \t]*")) | ||
| 15137 | beg) | ||
| 15138 | (save-excursion | ||
| 15139 | (org-back-to-heading t) | ||
| 15140 | (setq beg (point)) | ||
| 15141 | (org-end-of-subtree t t) | ||
| 15142 | (while (re-search-backward re beg t) | ||
| 15143 | (replace-match "") | ||
| 15144 | (unless (string-match "\\S-" (buffer-substring (point-at-bol) (point))) | ||
| 15145 | (delete-region (point-at-bol) (min (1+ (point)) (point-max)))))))) | ||
| 15146 | |||
| 15147 | (defun org-add-planning-info (what &optional time &rest remove) | ||
| 15148 | "Insert new timestamp with keyword in the line directly after the headline. | ||
| 15149 | WHAT indicates what kind of time stamp to add. TIME indicated the time to use. | ||
| 15150 | If non is given, the user is prompted for a date. | ||
| 15151 | REMOVE indicates what kind of entries to remove. An old WHAT entry will also | ||
| 15152 | be removed." | ||
| 15153 | (interactive) | ||
| 15154 | (let (org-time-was-given org-end-time-was-given) | ||
| 15155 | (when what (setq time (or time (org-read-date nil 'to-time)))) | ||
| 15156 | (when (and org-insert-labeled-timestamps-at-point | ||
| 15157 | (member what '(scheduled deadline))) | ||
| 15158 | (insert | ||
| 15159 | (if (eq what 'scheduled) org-scheduled-string org-deadline-string) " ") | ||
| 15160 | (org-insert-time-stamp time org-time-was-given | ||
| 15161 | nil nil nil (list org-end-time-was-given)) | ||
| 15162 | (setq what nil)) | ||
| 15163 | (save-excursion | ||
| 15164 | (save-restriction | ||
| 15165 | (let (col list elt ts buffer-invisibility-spec) | ||
| 15166 | (org-back-to-heading t) | ||
| 15167 | (looking-at (concat outline-regexp "\\( *\\)[^\r\n]*")) | ||
| 15168 | (goto-char (match-end 1)) | ||
| 15169 | (setq col (current-column)) | ||
| 15170 | (goto-char (match-end 0)) | ||
| 15171 | (if (eobp) (insert "\n") (forward-char 1)) | ||
| 15172 | (if (and (not (looking-at outline-regexp)) | ||
| 15173 | (looking-at (concat "[^\r\n]*?" org-keyword-time-regexp | ||
| 15174 | "[^\r\n]*")) | ||
| 15175 | (not (equal (match-string 1) org-clock-string))) | ||
| 15176 | (narrow-to-region (match-beginning 0) (match-end 0)) | ||
| 15177 | (insert-before-markers "\n") | ||
| 15178 | (backward-char 1) | ||
| 15179 | (narrow-to-region (point) (point)) | ||
| 15180 | (indent-to-column col)) | ||
| 15181 | ;; Check if we have to remove something. | ||
| 15182 | (setq list (cons what remove)) | ||
| 15183 | (while list | ||
| 15184 | (setq elt (pop list)) | ||
| 15185 | (goto-char (point-min)) | ||
| 15186 | (when (or (and (eq elt 'scheduled) | ||
| 15187 | (re-search-forward org-scheduled-time-regexp nil t)) | ||
| 15188 | (and (eq elt 'deadline) | ||
| 15189 | (re-search-forward org-deadline-time-regexp nil t)) | ||
| 15190 | (and (eq elt 'closed) | ||
| 15191 | (re-search-forward org-closed-time-regexp nil t))) | ||
| 15192 | (replace-match "") | ||
| 15193 | (if (looking-at "--+<[^>]+>") (replace-match "")) | ||
| 15194 | (if (looking-at " +") (replace-match "")))) | ||
| 15195 | (goto-char (point-max)) | ||
| 15196 | (when what | ||
| 15197 | (insert | ||
| 15198 | (if (not (equal (char-before) ?\ )) " " "") | ||
| 15199 | (cond ((eq what 'scheduled) org-scheduled-string) | ||
| 15200 | ((eq what 'deadline) org-deadline-string) | ||
| 15201 | ((eq what 'closed) org-closed-string)) | ||
| 15202 | " ") | ||
| 15203 | (setq ts (org-insert-time-stamp | ||
| 15204 | time | ||
| 15205 | (or org-time-was-given | ||
| 15206 | (and (eq what 'closed) org-log-done-with-time)) | ||
| 15207 | (eq what 'closed) | ||
| 15208 | nil nil (list org-end-time-was-given))) | ||
| 15209 | (end-of-line 1)) | ||
| 15210 | (goto-char (point-min)) | ||
| 15211 | (widen) | ||
| 15212 | (if (looking-at "[ \t]+\r?\n") | ||
| 15213 | (replace-match "")) | ||
| 15214 | ts))))) | ||
| 15215 | |||
| 15216 | (defvar org-log-note-marker (make-marker)) | ||
| 15217 | (defvar org-log-note-purpose nil) | ||
| 15218 | (defvar org-log-note-state nil) | ||
| 15219 | (defvar org-log-note-how nil) | ||
| 15220 | (defvar org-log-note-window-configuration nil) | ||
| 15221 | (defvar org-log-note-return-to (make-marker)) | ||
| 15222 | (defvar org-log-post-message nil | ||
| 15223 | "Message to be displayed after a log note has been stored. | ||
| 15224 | The auto-repeater uses this.") | ||
| 15225 | |||
| 15226 | (defun org-add-log-maybe (&optional purpose state findpos how) | ||
| 15227 | "Set up the post command hook to take a note. | ||
| 15228 | If this is about to TODO state change, the new state is expected in STATE. | ||
| 15229 | When FINDPOS is non-nil, find the correct position for the note in | ||
| 15230 | the current entry. If not, assume that it can be inserted at point." | ||
| 15231 | (save-excursion | ||
| 15232 | (when findpos | ||
| 15233 | (org-back-to-heading t) | ||
| 15234 | (looking-at (concat outline-regexp "\\( *\\)[^\r\n]*" | ||
| 15235 | "\\(\n[^\r\n]*?" org-keyword-time-not-clock-regexp | ||
| 15236 | "[^\r\n]*\\)?")) | ||
| 15237 | (goto-char (match-end 0)) | ||
| 15238 | (unless org-log-states-order-reversed | ||
| 15239 | (and (= (char-after) ?\n) (forward-char 1)) | ||
| 15240 | (org-skip-over-state-notes) | ||
| 15241 | (skip-chars-backward " \t\n\r"))) | ||
| 15242 | (move-marker org-log-note-marker (point)) | ||
| 15243 | (setq org-log-note-purpose purpose | ||
| 15244 | org-log-note-state state | ||
| 15245 | org-log-note-how how) | ||
| 15246 | (add-hook 'post-command-hook 'org-add-log-note 'append))) | ||
| 15247 | |||
| 15248 | (defun org-skip-over-state-notes () | ||
| 15249 | "Skip past the list of State notes in an entry." | ||
| 15250 | (if (looking-at "\n[ \t]*- State") (forward-char 1)) | ||
| 15251 | (while (looking-at "[ \t]*- State") | ||
| 15252 | (condition-case nil | ||
| 15253 | (org-next-item) | ||
| 15254 | (error (org-end-of-item))))) | ||
| 15255 | |||
| 15256 | (defun org-add-log-note (&optional purpose) | ||
| 15257 | "Pop up a window for taking a note, and add this note later at point." | ||
| 15258 | (remove-hook 'post-command-hook 'org-add-log-note) | ||
| 15259 | (setq org-log-note-window-configuration (current-window-configuration)) | ||
| 15260 | (delete-other-windows) | ||
| 15261 | (move-marker org-log-note-return-to (point)) | ||
| 15262 | (switch-to-buffer (marker-buffer org-log-note-marker)) | ||
| 15263 | (goto-char org-log-note-marker) | ||
| 15264 | (org-switch-to-buffer-other-window "*Org Note*") | ||
| 15265 | (erase-buffer) | ||
| 15266 | (if (memq org-log-note-how '(time state)) ; FIXME: time or state???????????? | ||
| 15267 | (org-store-log-note) | ||
| 15268 | (let ((org-inhibit-startup t)) (org-mode)) | ||
| 15269 | (insert (format "# Insert note for %s. | ||
| 15270 | # Finish with C-c C-c, or cancel with C-c C-k.\n\n" | ||
| 15271 | (cond | ||
| 15272 | ((eq org-log-note-purpose 'clock-out) "stopped clock") | ||
| 15273 | ((eq org-log-note-purpose 'done) "closed todo item") | ||
| 15274 | ((eq org-log-note-purpose 'state) | ||
| 15275 | (format "state change to \"%s\"" org-log-note-state)) | ||
| 15276 | (t (error "This should not happen"))))) | ||
| 15277 | (org-set-local 'org-finish-function 'org-store-log-note))) | ||
| 15278 | |||
| 15279 | (defun org-store-log-note () | ||
| 15280 | "Finish taking a log note, and insert it to where it belongs." | ||
| 15281 | (let ((txt (buffer-string)) | ||
| 15282 | (note (cdr (assq org-log-note-purpose org-log-note-headings))) | ||
| 15283 | lines ind) | ||
| 15284 | (kill-buffer (current-buffer)) | ||
| 15285 | (while (string-match "\\`#.*\n[ \t\n]*" txt) | ||
| 15286 | (setq txt (replace-match "" t t txt))) | ||
| 15287 | (if (string-match "\\s-+\\'" txt) | ||
| 15288 | (setq txt (replace-match "" t t txt))) | ||
| 15289 | (setq lines (org-split-string txt "\n")) | ||
| 15290 | (when (and note (string-match "\\S-" note)) | ||
| 15291 | (setq note | ||
| 15292 | (org-replace-escapes | ||
| 15293 | note | ||
| 15294 | (list (cons "%u" (user-login-name)) | ||
| 15295 | (cons "%U" user-full-name) | ||
| 15296 | (cons "%t" (format-time-string | ||
| 15297 | (org-time-stamp-format 'long 'inactive) | ||
| 15298 | (current-time))) | ||
| 15299 | (cons "%s" (if org-log-note-state | ||
| 15300 | (concat "\"" org-log-note-state "\"") | ||
| 15301 | ""))))) | ||
| 15302 | (if lines (setq note (concat note " \\\\"))) | ||
| 15303 | (push note lines)) | ||
| 15304 | (when (or current-prefix-arg org-note-abort) (setq lines nil)) | ||
| 15305 | (when lines | ||
| 15306 | (save-excursion | ||
| 15307 | (set-buffer (marker-buffer org-log-note-marker)) | ||
| 15308 | (save-excursion | ||
| 15309 | (goto-char org-log-note-marker) | ||
| 15310 | (move-marker org-log-note-marker nil) | ||
| 15311 | (end-of-line 1) | ||
| 15312 | (if (not (bolp)) (let ((inhibit-read-only t)) (insert "\n"))) | ||
| 15313 | (indent-relative nil) | ||
| 15314 | (insert "- " (pop lines)) | ||
| 15315 | (org-indent-line-function) | ||
| 15316 | (beginning-of-line 1) | ||
| 15317 | (looking-at "[ \t]*") | ||
| 15318 | (setq ind (concat (match-string 0) " ")) | ||
| 15319 | (end-of-line 1) | ||
| 15320 | (while lines (insert "\n" ind (pop lines))))))) | ||
| 15321 | (set-window-configuration org-log-note-window-configuration) | ||
| 15322 | (with-current-buffer (marker-buffer org-log-note-return-to) | ||
| 15323 | (goto-char org-log-note-return-to)) | ||
| 15324 | (move-marker org-log-note-return-to nil) | ||
| 15325 | (and org-log-post-message (message "%s" org-log-post-message))) | ||
| 15326 | |||
| 15327 | ;; FIXME: what else would be useful? | ||
| 15328 | ;; - priority | ||
| 15329 | ;; - date | ||
| 15330 | |||
| 15331 | (defun org-sparse-tree (&optional arg) | ||
| 15332 | "Create a sparse tree, prompt for the details. | ||
| 15333 | This command can create sparse trees. You first need to select the type | ||
| 15334 | of match used to create the tree: | ||
| 15335 | |||
| 15336 | t Show entries with a specific TODO keyword. | ||
| 15337 | T Show entries selected by a tags match. | ||
| 15338 | p Enter a property name and its value (both with completion on existing | ||
| 15339 | names/values) and show entries with that property. | ||
| 15340 | r Show entries matching a regular expression | ||
| 15341 | d Show deadlines due within `org-deadline-warning-days'." | ||
| 15342 | (interactive "P") | ||
| 15343 | (let (ans kwd value) | ||
| 15344 | (message "Sparse tree: [/]regexp [t]odo-kwd [T]ag [p]roperty [d]eadlines [b]efore-date") | ||
| 15345 | (setq ans (read-char-exclusive)) | ||
| 15346 | (cond | ||
| 15347 | ((equal ans ?d) | ||
| 15348 | (call-interactively 'org-check-deadlines)) | ||
| 15349 | ((equal ans ?b) | ||
| 15350 | (call-interactively 'org-check-before-date)) | ||
| 15351 | ((equal ans ?t) | ||
| 15352 | (org-show-todo-tree '(4))) | ||
| 15353 | ((equal ans ?T) | ||
| 15354 | (call-interactively 'org-tags-sparse-tree)) | ||
| 15355 | ((member ans '(?p ?P)) | ||
| 15356 | (setq kwd (completing-read "Property: " | ||
| 15357 | (mapcar 'list (org-buffer-property-keys)))) | ||
| 15358 | (setq value (completing-read "Value: " | ||
| 15359 | (mapcar 'list (org-property-values kwd)))) | ||
| 15360 | (unless (string-match "\\`{.*}\\'" value) | ||
| 15361 | (setq value (concat "\"" value "\""))) | ||
| 15362 | (org-tags-sparse-tree arg (concat kwd "=" value))) | ||
| 15363 | ((member ans '(?r ?R ?/)) | ||
| 15364 | (call-interactively 'org-occur)) | ||
| 15365 | (t (error "No such sparse tree command \"%c\"" ans))))) | ||
| 15366 | |||
| 15367 | (defvar org-occur-highlights nil | ||
| 15368 | "List of overlays used for occur matches.") | ||
| 15369 | (make-variable-buffer-local 'org-occur-highlights) | ||
| 15370 | (defvar org-occur-parameters nil | ||
| 15371 | "Parameters of the active org-occur calls. | ||
| 15372 | This is a list, each call to org-occur pushes as cons cell, | ||
| 15373 | containing the regular expression and the callback, onto the list. | ||
| 15374 | The list can contain several entries if `org-occur' has been called | ||
| 15375 | several time with the KEEP-PREVIOUS argument. Otherwise, this list | ||
| 15376 | will only contain one set of parameters. When the highlights are | ||
| 15377 | removed (for example with `C-c C-c', or with the next edit (depending | ||
| 15378 | on `org-remove-highlights-with-change'), this variable is emptied | ||
| 15379 | as well.") | ||
| 15380 | (make-variable-buffer-local 'org-occur-parameters) | ||
| 15381 | |||
| 15382 | (defun org-occur (regexp &optional keep-previous callback) | ||
| 15383 | "Make a compact tree which shows all matches of REGEXP. | ||
| 15384 | The tree will show the lines where the regexp matches, and all higher | ||
| 15385 | headlines above the match. It will also show the heading after the match, | ||
| 15386 | to make sure editing the matching entry is easy. | ||
| 15387 | If KEEP-PREVIOUS is non-nil, highlighting and exposing done by a previous | ||
| 15388 | call to `org-occur' will be kept, to allow stacking of calls to this | ||
| 15389 | command. | ||
| 15390 | If CALLBACK is non-nil, it is a function which is called to confirm | ||
| 15391 | that the match should indeed be shown." | ||
| 15392 | (interactive "sRegexp: \nP") | ||
| 15393 | (unless keep-previous | ||
| 15394 | (org-remove-occur-highlights nil nil t)) | ||
| 15395 | (push (cons regexp callback) org-occur-parameters) | ||
| 15396 | (let ((cnt 0)) | ||
| 15397 | (save-excursion | ||
| 15398 | (goto-char (point-min)) | ||
| 15399 | (if (or (not keep-previous) ; do not want to keep | ||
| 15400 | (not org-occur-highlights)) ; no previous matches | ||
| 15401 | ;; hide everything | ||
| 15402 | (org-overview)) | ||
| 15403 | (while (re-search-forward regexp nil t) | ||
| 15404 | (when (or (not callback) | ||
| 15405 | (save-match-data (funcall callback))) | ||
| 15406 | (setq cnt (1+ cnt)) | ||
| 15407 | (when org-highlight-sparse-tree-matches | ||
| 15408 | (org-highlight-new-match (match-beginning 0) (match-end 0))) | ||
| 15409 | (org-show-context 'occur-tree)))) | ||
| 15410 | (when org-remove-highlights-with-change | ||
| 15411 | (org-add-hook 'before-change-functions 'org-remove-occur-highlights | ||
| 15412 | nil 'local)) | ||
| 15413 | (unless org-sparse-tree-open-archived-trees | ||
| 15414 | (org-hide-archived-subtrees (point-min) (point-max))) | ||
| 15415 | (run-hooks 'org-occur-hook) | ||
| 15416 | (if (interactive-p) | ||
| 15417 | (message "%d match(es) for regexp %s" cnt regexp)) | ||
| 15418 | cnt)) | ||
| 15419 | |||
| 15420 | (defun org-show-context (&optional key) | ||
| 15421 | "Make sure point and context and visible. | ||
| 15422 | How much context is shown depends upon the variables | ||
| 15423 | `org-show-hierarchy-above', `org-show-following-heading'. and | ||
| 15424 | `org-show-siblings'." | ||
| 15425 | (let ((heading-p (org-on-heading-p t)) | ||
| 15426 | (hierarchy-p (org-get-alist-option org-show-hierarchy-above key)) | ||
| 15427 | (following-p (org-get-alist-option org-show-following-heading key)) | ||
| 15428 | (entry-p (org-get-alist-option org-show-entry-below key)) | ||
| 15429 | (siblings-p (org-get-alist-option org-show-siblings key))) | ||
| 15430 | (catch 'exit | ||
| 15431 | ;; Show heading or entry text | ||
| 15432 | (if (and heading-p (not entry-p)) | ||
| 15433 | (org-flag-heading nil) ; only show the heading | ||
| 15434 | (and (or entry-p (org-invisible-p) (org-invisible-p2)) | ||
| 15435 | (org-show-hidden-entry))) ; show entire entry | ||
| 15436 | (when following-p | ||
| 15437 | ;; Show next sibling, or heading below text | ||
| 15438 | (save-excursion | ||
| 15439 | (and (if heading-p (org-goto-sibling) (outline-next-heading)) | ||
| 15440 | (org-flag-heading nil)))) | ||
| 15441 | (when siblings-p (org-show-siblings)) | ||
| 15442 | (when hierarchy-p | ||
| 15443 | ;; show all higher headings, possibly with siblings | ||
| 15444 | (save-excursion | ||
| 15445 | (while (and (condition-case nil | ||
| 15446 | (progn (org-up-heading-all 1) t) | ||
| 15447 | (error nil)) | ||
| 15448 | (not (bobp))) | ||
| 15449 | (org-flag-heading nil) | ||
| 15450 | (when siblings-p (org-show-siblings)))))))) | ||
| 15451 | |||
| 15452 | (defun org-reveal (&optional siblings) | ||
| 15453 | "Show current entry, hierarchy above it, and the following headline. | ||
| 15454 | This can be used to show a consistent set of context around locations | ||
| 15455 | exposed with `org-show-hierarchy-above' or `org-show-following-heading' | ||
| 15456 | not t for the search context. | ||
| 15457 | |||
| 15458 | With optional argument SIBLINGS, on each level of the hierarchy all | ||
| 15459 | siblings are shown. This repairs the tree structure to what it would | ||
| 15460 | look like when opened with hierarchical calls to `org-cycle'." | ||
| 15461 | (interactive "P") | ||
| 15462 | (let ((org-show-hierarchy-above t) | ||
| 15463 | (org-show-following-heading t) | ||
| 15464 | (org-show-siblings (if siblings t org-show-siblings))) | ||
| 15465 | (org-show-context nil))) | ||
| 15466 | |||
| 15467 | (defun org-highlight-new-match (beg end) | ||
| 15468 | "Highlight from BEG to END and mark the highlight is an occur headline." | ||
| 15469 | (let ((ov (org-make-overlay beg end))) | ||
| 15470 | (org-overlay-put ov 'face 'secondary-selection) | ||
| 15471 | (push ov org-occur-highlights))) | ||
| 15472 | |||
| 15473 | (defun org-remove-occur-highlights (&optional beg end noremove) | ||
| 15474 | "Remove the occur highlights from the buffer. | ||
| 15475 | BEG and END are ignored. If NOREMOVE is nil, remove this function | ||
| 15476 | from the `before-change-functions' in the current buffer." | ||
| 15477 | (interactive) | ||
| 15478 | (unless org-inhibit-highlight-removal | ||
| 15479 | (mapc 'org-delete-overlay org-occur-highlights) | ||
| 15480 | (setq org-occur-highlights nil) | ||
| 15481 | (setq org-occur-parameters nil) | ||
| 15482 | (unless noremove | ||
| 15483 | (remove-hook 'before-change-functions | ||
| 15484 | 'org-remove-occur-highlights 'local)))) | ||
| 15485 | |||
| 15486 | ;;;; Priorities | ||
| 15487 | |||
| 15488 | (defvar org-priority-regexp ".*?\\(\\[#\\([A-Z0-9]\\)\\] ?\\)" | ||
| 15489 | "Regular expression matching the priority indicator.") | ||
| 15490 | |||
| 15491 | (defvar org-remove-priority-next-time nil) | ||
| 15492 | |||
| 15493 | (defun org-priority-up () | ||
| 15494 | "Increase the priority of the current item." | ||
| 15495 | (interactive) | ||
| 15496 | (org-priority 'up)) | ||
| 15497 | |||
| 15498 | (defun org-priority-down () | ||
| 15499 | "Decrease the priority of the current item." | ||
| 15500 | (interactive) | ||
| 15501 | (org-priority 'down)) | ||
| 15502 | |||
| 15503 | (defun org-priority (&optional action) | ||
| 15504 | "Change the priority of an item by ARG. | ||
| 15505 | ACTION can be `set', `up', `down', or a character." | ||
| 15506 | (interactive) | ||
| 15507 | (setq action (or action 'set)) | ||
| 15508 | (let (current new news have remove) | ||
| 15509 | (save-excursion | ||
| 15510 | (org-back-to-heading) | ||
| 15511 | (if (looking-at org-priority-regexp) | ||
| 15512 | (setq current (string-to-char (match-string 2)) | ||
| 15513 | have t) | ||
| 15514 | (setq current org-default-priority)) | ||
| 15515 | (cond | ||
| 15516 | ((or (eq action 'set) (integerp action)) | ||
| 15517 | (if (integerp action) | ||
| 15518 | (setq new action) | ||
| 15519 | (message "Priority %c-%c, SPC to remove: " org-highest-priority org-lowest-priority) | ||
| 15520 | (setq new (read-char-exclusive))) | ||
| 15521 | (if (and (= (upcase org-highest-priority) org-highest-priority) | ||
| 15522 | (= (upcase org-lowest-priority) org-lowest-priority)) | ||
| 15523 | (setq new (upcase new))) | ||
| 15524 | (cond ((equal new ?\ ) (setq remove t)) | ||
| 15525 | ((or (< (upcase new) org-highest-priority) (> (upcase new) org-lowest-priority)) | ||
| 15526 | (error "Priority must be between `%c' and `%c'" | ||
| 15527 | org-highest-priority org-lowest-priority)))) | ||
| 15528 | ((eq action 'up) | ||
| 15529 | (if (and (not have) (eq last-command this-command)) | ||
| 15530 | (setq new org-lowest-priority) | ||
| 15531 | (setq new (if (and org-priority-start-cycle-with-default (not have)) | ||
| 15532 | org-default-priority (1- current))))) | ||
| 15533 | ((eq action 'down) | ||
| 15534 | (if (and (not have) (eq last-command this-command)) | ||
| 15535 | (setq new org-highest-priority) | ||
| 15536 | (setq new (if (and org-priority-start-cycle-with-default (not have)) | ||
| 15537 | org-default-priority (1+ current))))) | ||
| 15538 | (t (error "Invalid action"))) | ||
| 15539 | (if (or (< (upcase new) org-highest-priority) | ||
| 15540 | (> (upcase new) org-lowest-priority)) | ||
| 15541 | (setq remove t)) | ||
| 15542 | (setq news (format "%c" new)) | ||
| 15543 | (if have | ||
| 15544 | (if remove | ||
| 15545 | (replace-match "" t t nil 1) | ||
| 15546 | (replace-match news t t nil 2)) | ||
| 15547 | (if remove | ||
| 15548 | (error "No priority cookie found in line") | ||
| 15549 | (looking-at org-todo-line-regexp) | ||
| 15550 | (if (match-end 2) | ||
| 15551 | (progn | ||
| 15552 | (goto-char (match-end 2)) | ||
| 15553 | (insert " [#" news "]")) | ||
| 15554 | (goto-char (match-beginning 3)) | ||
| 15555 | (insert "[#" news "] "))))) | ||
| 15556 | (org-preserve-lc (org-set-tags nil 'align)) | ||
| 15557 | (if remove | ||
| 15558 | (message "Priority removed") | ||
| 15559 | (message "Priority of current item set to %s" news)))) | ||
| 15560 | |||
| 15561 | |||
| 15562 | (defun org-get-priority (s) | ||
| 15563 | "Find priority cookie and return priority." | ||
| 15564 | (save-match-data | ||
| 15565 | (if (not (string-match org-priority-regexp s)) | ||
| 15566 | (* 1000 (- org-lowest-priority org-default-priority)) | ||
| 15567 | (* 1000 (- org-lowest-priority | ||
| 15568 | (string-to-char (match-string 2 s))))))) | ||
| 15569 | |||
| 15570 | ;;;; Tags | ||
| 15571 | |||
| 15572 | (defun org-scan-tags (action matcher &optional todo-only) | ||
| 15573 | "Scan headline tags with inheritance and produce output ACTION. | ||
| 15574 | ACTION can be `sparse-tree' or `agenda'. MATCHER is a Lisp form to be | ||
| 15575 | evaluated, testing if a given set of tags qualifies a headline for | ||
| 15576 | inclusion. When TODO-ONLY is non-nil, only lines with a TODO keyword | ||
| 15577 | are included in the output." | ||
| 15578 | (let* ((re (concat "[\n\r]" outline-regexp " *\\(\\<\\(" | ||
| 15579 | (mapconcat 'regexp-quote org-todo-keywords-1 "\\|") | ||
| 15580 | (org-re | ||
| 15581 | "\\>\\)\\)? *\\(.*?\\)\\(:[[:alnum:]_@:]+:\\)?[ \t]*$"))) | ||
| 15582 | (props (list 'face nil | ||
| 15583 | 'done-face 'org-done | ||
| 15584 | 'undone-face nil | ||
| 15585 | 'mouse-face 'highlight | ||
| 15586 | 'org-not-done-regexp org-not-done-regexp | ||
| 15587 | 'org-todo-regexp org-todo-regexp | ||
| 15588 | 'keymap org-agenda-keymap | ||
| 15589 | 'help-echo | ||
| 15590 | (format "mouse-2 or RET jump to org file %s" | ||
| 15591 | (abbreviate-file-name | ||
| 15592 | (or (buffer-file-name (buffer-base-buffer)) | ||
| 15593 | (buffer-name (buffer-base-buffer))))))) | ||
| 15594 | (case-fold-search nil) | ||
| 15595 | lspos | ||
| 15596 | tags tags-list tags-alist (llast 0) rtn level category i txt | ||
| 15597 | todo marker entry priority) | ||
| 15598 | (save-excursion | ||
| 15599 | (goto-char (point-min)) | ||
| 15600 | (when (eq action 'sparse-tree) | ||
| 15601 | (org-overview) | ||
| 15602 | (org-remove-occur-highlights)) | ||
| 15603 | (while (re-search-forward re nil t) | ||
| 15604 | (catch :skip | ||
| 15605 | (setq todo (if (match-end 1) (match-string 2)) | ||
| 15606 | tags (if (match-end 4) (match-string 4))) | ||
| 15607 | (goto-char (setq lspos (1+ (match-beginning 0)))) | ||
| 15608 | (setq level (org-reduced-level (funcall outline-level)) | ||
| 15609 | category (org-get-category)) | ||
| 15610 | (setq i llast llast level) | ||
| 15611 | ;; remove tag lists from same and sublevels | ||
| 15612 | (while (>= i level) | ||
| 15613 | (when (setq entry (assoc i tags-alist)) | ||
| 15614 | (setq tags-alist (delete entry tags-alist))) | ||
| 15615 | (setq i (1- i))) | ||
| 15616 | ;; add the nex tags | ||
| 15617 | (when tags | ||
| 15618 | (setq tags (mapcar 'downcase (org-split-string tags ":")) | ||
| 15619 | tags-alist | ||
| 15620 | (cons (cons level tags) tags-alist))) | ||
| 15621 | ;; compile tags for current headline | ||
| 15622 | (setq tags-list | ||
| 15623 | (if org-use-tag-inheritance | ||
| 15624 | (apply 'append (mapcar 'cdr tags-alist)) | ||
| 15625 | tags)) | ||
| 15626 | (when (and (or (not todo-only) (member todo org-not-done-keywords)) | ||
| 15627 | (eval matcher) | ||
| 15628 | (or (not org-agenda-skip-archived-trees) | ||
| 15629 | (not (member org-archive-tag tags-list)))) | ||
| 15630 | (and (eq action 'agenda) (org-agenda-skip)) | ||
| 15631 | ;; list this headline | ||
| 15632 | |||
| 15633 | (if (eq action 'sparse-tree) | ||
| 15634 | (progn | ||
| 15635 | (and org-highlight-sparse-tree-matches | ||
| 15636 | (org-get-heading) (match-end 0) | ||
| 15637 | (org-highlight-new-match | ||
| 15638 | (match-beginning 0) (match-beginning 1))) | ||
| 15639 | (org-show-context 'tags-tree)) | ||
| 15640 | (setq txt (org-format-agenda-item | ||
| 15641 | "" | ||
| 15642 | (concat | ||
| 15643 | (if org-tags-match-list-sublevels | ||
| 15644 | (make-string (1- level) ?.) "") | ||
| 15645 | (org-get-heading)) | ||
| 15646 | category tags-list) | ||
| 15647 | priority (org-get-priority txt)) | ||
| 15648 | (goto-char lspos) | ||
| 15649 | (setq marker (org-agenda-new-marker)) | ||
| 15650 | (org-add-props txt props | ||
| 15651 | 'org-marker marker 'org-hd-marker marker 'org-category category | ||
| 15652 | 'priority priority 'type "tagsmatch") | ||
| 15653 | (push txt rtn)) | ||
| 15654 | ;; if we are to skip sublevels, jump to end of subtree | ||
| 15655 | (or org-tags-match-list-sublevels (org-end-of-subtree t)))))) | ||
| 15656 | (when (and (eq action 'sparse-tree) | ||
| 15657 | (not org-sparse-tree-open-archived-trees)) | ||
| 15658 | (org-hide-archived-subtrees (point-min) (point-max))) | ||
| 15659 | (nreverse rtn))) | ||
| 15660 | |||
| 15661 | (defvar todo-only) ;; dynamically scoped | ||
| 15662 | |||
| 15663 | (defun org-tags-sparse-tree (&optional todo-only match) | ||
| 15664 | "Create a sparse tree according to tags string MATCH. | ||
| 15665 | MATCH can contain positive and negative selection of tags, like | ||
| 15666 | \"+WORK+URGENT-WITHBOSS\". | ||
| 15667 | If optional argument TODO_ONLY is non-nil, only select lines that are | ||
| 15668 | also TODO lines." | ||
| 15669 | (interactive "P") | ||
| 15670 | (org-prepare-agenda-buffers (list (current-buffer))) | ||
| 15671 | (org-scan-tags 'sparse-tree (cdr (org-make-tags-matcher match)) todo-only)) | ||
| 15672 | |||
| 15673 | (defvar org-cached-props nil) | ||
| 15674 | (defun org-cached-entry-get (pom property) | ||
| 15675 | (if (or (eq t org-use-property-inheritance) | ||
| 15676 | (member property org-use-property-inheritance)) | ||
| 15677 | ;; Caching is not possible, check it directly | ||
| 15678 | (org-entry-get pom property 'inherit) | ||
| 15679 | ;; Get all properties, so that we can do complicated checks easily | ||
| 15680 | (cdr (assoc property (or org-cached-props | ||
| 15681 | (setq org-cached-props | ||
| 15682 | (org-entry-properties pom))))))) | ||
| 15683 | |||
| 15684 | (defun org-global-tags-completion-table (&optional files) | ||
| 15685 | "Return the list of all tags in all agenda buffer/files." | ||
| 15686 | (save-excursion | ||
| 15687 | (org-uniquify | ||
| 15688 | (delq nil | ||
| 15689 | (apply 'append | ||
| 15690 | (mapcar | ||
| 15691 | (lambda (file) | ||
| 15692 | (set-buffer (find-file-noselect file)) | ||
| 15693 | (append (org-get-buffer-tags) | ||
| 15694 | (mapcar (lambda (x) (if (stringp (car-safe x)) | ||
| 15695 | (list (car-safe x)) nil)) | ||
| 15696 | org-tag-alist))) | ||
| 15697 | (if (and files (car files)) | ||
| 15698 | files | ||
| 15699 | (org-agenda-files)))))))) | ||
| 15700 | |||
| 15701 | (defun org-make-tags-matcher (match) | ||
| 15702 | "Create the TAGS//TODO matcher form for the selection string MATCH." | ||
| 15703 | ;; todo-only is scoped dynamically into this function, and the function | ||
| 15704 | ;; may change it it the matcher asksk for it. | ||
| 15705 | (unless match | ||
| 15706 | ;; Get a new match request, with completion | ||
| 15707 | (let ((org-last-tags-completion-table | ||
| 15708 | (org-global-tags-completion-table))) | ||
| 15709 | (setq match (completing-read | ||
| 15710 | "Match: " 'org-tags-completion-function nil nil nil | ||
| 15711 | 'org-tags-history)))) | ||
| 15712 | |||
| 15713 | ;; Parse the string and create a lisp form | ||
| 15714 | (let ((match0 match) | ||
| 15715 | (re (org-re "^&?\\([-+:]\\)?\\({[^}]+}\\|LEVEL=\\([0-9]+\\)\\|\\([[:alnum:]_]+\\)=\\({[^}]+}\\|\"[^\"]*\"\\)\\|[[:alnum:]_@]+\\)")) | ||
| 15716 | minus tag mm | ||
| 15717 | tagsmatch todomatch tagsmatcher todomatcher kwd matcher | ||
| 15718 | orterms term orlist re-p level-p prop-p pn pv cat-p gv) | ||
| 15719 | (if (string-match "/+" match) | ||
| 15720 | ;; match contains also a todo-matching request | ||
| 15721 | (progn | ||
| 15722 | (setq tagsmatch (substring match 0 (match-beginning 0)) | ||
| 15723 | todomatch (substring match (match-end 0))) | ||
| 15724 | (if (string-match "^!" todomatch) | ||
| 15725 | (setq todo-only t todomatch (substring todomatch 1))) | ||
| 15726 | (if (string-match "^\\s-*$" todomatch) | ||
| 15727 | (setq todomatch nil))) | ||
| 15728 | ;; only matching tags | ||
| 15729 | (setq tagsmatch match todomatch nil)) | ||
| 15730 | |||
| 15731 | ;; Make the tags matcher | ||
| 15732 | (if (or (not tagsmatch) (not (string-match "\\S-" tagsmatch))) | ||
| 15733 | (setq tagsmatcher t) | ||
| 15734 | (setq orterms (org-split-string tagsmatch "|") orlist nil) | ||
| 15735 | (while (setq term (pop orterms)) | ||
| 15736 | (while (and (equal (substring term -1) "\\") orterms) | ||
| 15737 | (setq term (concat term "|" (pop orterms)))) ; repair bad split | ||
| 15738 | (while (string-match re term) | ||
| 15739 | (setq minus (and (match-end 1) | ||
| 15740 | (equal (match-string 1 term) "-")) | ||
| 15741 | tag (match-string 2 term) | ||
| 15742 | re-p (equal (string-to-char tag) ?{) | ||
| 15743 | level-p (match-end 3) | ||
| 15744 | prop-p (match-end 4) | ||
| 15745 | mm (cond | ||
| 15746 | (re-p `(org-match-any-p ,(substring tag 1 -1) tags-list)) | ||
| 15747 | (level-p `(= level ,(string-to-number | ||
| 15748 | (match-string 3 term)))) | ||
| 15749 | (prop-p | ||
| 15750 | (setq pn (match-string 4 term) | ||
| 15751 | pv (match-string 5 term) | ||
| 15752 | cat-p (equal pn "CATEGORY") | ||
| 15753 | re-p (equal (string-to-char pv) ?{) | ||
| 15754 | pv (substring pv 1 -1)) | ||
| 15755 | (if (equal pn "CATEGORY") | ||
| 15756 | (setq gv '(get-text-property (point) 'org-category)) | ||
| 15757 | (setq gv `(org-cached-entry-get nil ,pn))) | ||
| 15758 | (if re-p | ||
| 15759 | `(string-match ,pv (or ,gv "")) | ||
| 15760 | `(equal ,pv (or ,gv "")))) | ||
| 15761 | (t `(member ,(downcase tag) tags-list))) | ||
| 15762 | mm (if minus (list 'not mm) mm) | ||
| 15763 | term (substring term (match-end 0))) | ||
| 15764 | (push mm tagsmatcher)) | ||
| 15765 | (push (if (> (length tagsmatcher) 1) | ||
| 15766 | (cons 'and tagsmatcher) | ||
| 15767 | (car tagsmatcher)) | ||
| 15768 | orlist) | ||
| 15769 | (setq tagsmatcher nil)) | ||
| 15770 | (setq tagsmatcher (if (> (length orlist) 1) (cons 'or orlist) (car orlist))) | ||
| 15771 | (setq tagsmatcher | ||
| 15772 | (list 'progn '(setq org-cached-props nil) tagsmatcher))) | ||
| 15773 | |||
| 15774 | ;; Make the todo matcher | ||
| 15775 | (if (or (not todomatch) (not (string-match "\\S-" todomatch))) | ||
| 15776 | (setq todomatcher t) | ||
| 15777 | (setq orterms (org-split-string todomatch "|") orlist nil) | ||
| 15778 | (while (setq term (pop orterms)) | ||
| 15779 | (while (string-match re term) | ||
| 15780 | (setq minus (and (match-end 1) | ||
| 15781 | (equal (match-string 1 term) "-")) | ||
| 15782 | kwd (match-string 2 term) | ||
| 15783 | re-p (equal (string-to-char kwd) ?{) | ||
| 15784 | term (substring term (match-end 0)) | ||
| 15785 | mm (if re-p | ||
| 15786 | `(string-match ,(substring kwd 1 -1) todo) | ||
| 15787 | (list 'equal 'todo kwd)) | ||
| 15788 | mm (if minus (list 'not mm) mm)) | ||
| 15789 | (push mm todomatcher)) | ||
| 15790 | (push (if (> (length todomatcher) 1) | ||
| 15791 | (cons 'and todomatcher) | ||
| 15792 | (car todomatcher)) | ||
| 15793 | orlist) | ||
| 15794 | (setq todomatcher nil)) | ||
| 15795 | (setq todomatcher (if (> (length orlist) 1) | ||
| 15796 | (cons 'or orlist) (car orlist)))) | ||
| 15797 | |||
| 15798 | ;; Return the string and lisp forms of the matcher | ||
| 15799 | (setq matcher (if todomatcher | ||
| 15800 | (list 'and tagsmatcher todomatcher) | ||
| 15801 | tagsmatcher)) | ||
| 15802 | (cons match0 matcher))) | ||
| 15803 | |||
| 15804 | (defun org-match-any-p (re list) | ||
| 15805 | "Does re match any element of list?" | ||
| 15806 | (setq list (mapcar (lambda (x) (string-match re x)) list)) | ||
| 15807 | (delq nil list)) | ||
| 15808 | |||
| 15809 | (defvar org-add-colon-after-tag-completion nil) ;; dynamically skoped param | ||
| 15810 | (defvar org-tags-overlay (org-make-overlay 1 1)) | ||
| 15811 | (org-detach-overlay org-tags-overlay) | ||
| 15812 | |||
| 15813 | (defun org-align-tags-here (to-col) | ||
| 15814 | ;; Assumes that this is a headline | ||
| 15815 | (let ((pos (point)) (col (current-column)) tags) | ||
| 15816 | (beginning-of-line 1) | ||
| 15817 | (if (and (looking-at (org-re ".*?\\([ \t]+\\)\\(:[[:alnum:]_@:]+:\\)[ \t]*$")) | ||
| 15818 | (< pos (match-beginning 2))) | ||
| 15819 | (progn | ||
| 15820 | (setq tags (match-string 2)) | ||
| 15821 | (goto-char (match-beginning 1)) | ||
| 15822 | (insert " ") | ||
| 15823 | (delete-region (point) (1+ (match-end 0))) | ||
| 15824 | (backward-char 1) | ||
| 15825 | (move-to-column | ||
| 15826 | (max (1+ (current-column)) | ||
| 15827 | (1+ col) | ||
| 15828 | (if (> to-col 0) | ||
| 15829 | to-col | ||
| 15830 | (- (abs to-col) (length tags)))) | ||
| 15831 | t) | ||
| 15832 | (insert tags) | ||
| 15833 | (move-to-column (min (current-column) col) t)) | ||
| 15834 | (goto-char pos)))) | ||
| 15835 | |||
| 15836 | (defun org-set-tags (&optional arg just-align) | ||
| 15837 | "Set the tags for the current headline. | ||
| 15838 | With prefix ARG, realign all tags in headings in the current buffer." | ||
| 15839 | (interactive "P") | ||
| 15840 | (let* ((re (concat "^" outline-regexp)) | ||
| 15841 | (current (org-get-tags-string)) | ||
| 15842 | (col (current-column)) | ||
| 15843 | (org-setting-tags t) | ||
| 15844 | table current-tags inherited-tags ; computed below when needed | ||
| 15845 | tags p0 c0 c1 rpl) | ||
| 15846 | (if arg | ||
| 15847 | (save-excursion | ||
| 15848 | (goto-char (point-min)) | ||
| 15849 | (let ((buffer-invisibility-spec (org-inhibit-invisibility))) | ||
| 15850 | (while (re-search-forward re nil t) | ||
| 15851 | (org-set-tags nil t) | ||
| 15852 | (end-of-line 1))) | ||
| 15853 | (message "All tags realigned to column %d" org-tags-column)) | ||
| 15854 | (if just-align | ||
| 15855 | (setq tags current) | ||
| 15856 | ;; Get a new set of tags from the user | ||
| 15857 | (save-excursion | ||
| 15858 | (setq table (or org-tag-alist (org-get-buffer-tags)) | ||
| 15859 | org-last-tags-completion-table table | ||
| 15860 | current-tags (org-split-string current ":") | ||
| 15861 | inherited-tags (nreverse | ||
| 15862 | (nthcdr (length current-tags) | ||
| 15863 | (nreverse (org-get-tags-at)))) | ||
| 15864 | tags | ||
| 15865 | (if (or (eq t org-use-fast-tag-selection) | ||
| 15866 | (and org-use-fast-tag-selection | ||
| 15867 | (delq nil (mapcar 'cdr table)))) | ||
| 15868 | (org-fast-tag-selection | ||
| 15869 | current-tags inherited-tags table | ||
| 15870 | (if org-fast-tag-selection-include-todo org-todo-key-alist)) | ||
| 15871 | (let ((org-add-colon-after-tag-completion t)) | ||
| 15872 | (org-trim | ||
| 15873 | (org-without-partial-completion | ||
| 15874 | (completing-read "Tags: " 'org-tags-completion-function | ||
| 15875 | nil nil current 'org-tags-history))))))) | ||
| 15876 | (while (string-match "[-+&]+" tags) | ||
| 15877 | ;; No boolean logic, just a list | ||
| 15878 | (setq tags (replace-match ":" t t tags)))) | ||
| 15879 | |||
| 15880 | (if (string-match "\\`[\t ]*\\'" tags) | ||
| 15881 | (setq tags "") | ||
| 15882 | (unless (string-match ":$" tags) (setq tags (concat tags ":"))) | ||
| 15883 | (unless (string-match "^:" tags) (setq tags (concat ":" tags)))) | ||
| 15884 | |||
| 15885 | ;; Insert new tags at the correct column | ||
| 15886 | (beginning-of-line 1) | ||
| 15887 | (cond | ||
| 15888 | ((and (equal current "") (equal tags ""))) | ||
| 15889 | ((re-search-forward | ||
| 15890 | (concat "\\([ \t]*" (regexp-quote current) "\\)[ \t]*$") | ||
| 15891 | (point-at-eol) t) | ||
| 15892 | (if (equal tags "") | ||
| 15893 | (setq rpl "") | ||
| 15894 | (goto-char (match-beginning 0)) | ||
| 15895 | (setq c0 (current-column) p0 (point) | ||
| 15896 | c1 (max (1+ c0) (if (> org-tags-column 0) | ||
| 15897 | org-tags-column | ||
| 15898 | (- (- org-tags-column) (length tags)))) | ||
| 15899 | rpl (concat (make-string (max 0 (- c1 c0)) ?\ ) tags))) | ||
| 15900 | (replace-match rpl t t) | ||
| 15901 | (and (not (featurep 'xemacs)) c0 indent-tabs-mode (tabify p0 (point))) | ||
| 15902 | tags) | ||
| 15903 | (t (error "Tags alignment failed"))) | ||
| 15904 | (move-to-column col) | ||
| 15905 | (unless just-align | ||
| 15906 | (run-hooks 'org-after-tags-change-hook))))) | ||
| 15907 | |||
| 15908 | (defun org-change-tag-in-region (beg end tag off) | ||
| 15909 | "Add or remove TAG for each entry in the region. | ||
| 15910 | This works in the agenda, and also in an org-mode buffer." | ||
| 15911 | (interactive | ||
| 15912 | (list (region-beginning) (region-end) | ||
| 15913 | (let ((org-last-tags-completion-table | ||
| 15914 | (if (org-mode-p) | ||
| 15915 | (org-get-buffer-tags) | ||
| 15916 | (org-global-tags-completion-table)))) | ||
| 15917 | (completing-read | ||
| 15918 | "Tag: " 'org-tags-completion-function nil nil nil | ||
| 15919 | 'org-tags-history)) | ||
| 15920 | (progn | ||
| 15921 | (message "[s]et or [r]emove? ") | ||
| 15922 | (equal (read-char-exclusive) ?r)))) | ||
| 15923 | (if (fboundp 'deactivate-mark) (deactivate-mark)) | ||
| 15924 | (let ((agendap (equal major-mode 'org-agenda-mode)) | ||
| 15925 | l1 l2 m buf pos newhead (cnt 0)) | ||
| 15926 | (goto-char end) | ||
| 15927 | (setq l2 (1- (org-current-line))) | ||
| 15928 | (goto-char beg) | ||
| 15929 | (setq l1 (org-current-line)) | ||
| 15930 | (loop for l from l1 to l2 do | ||
| 15931 | (goto-line l) | ||
| 15932 | (setq m (get-text-property (point) 'org-hd-marker)) | ||
| 15933 | (when (or (and (org-mode-p) (org-on-heading-p)) | ||
| 15934 | (and agendap m)) | ||
| 15935 | (setq buf (if agendap (marker-buffer m) (current-buffer)) | ||
| 15936 | pos (if agendap m (point))) | ||
| 15937 | (with-current-buffer buf | ||
| 15938 | (save-excursion | ||
| 15939 | (save-restriction | ||
| 15940 | (goto-char pos) | ||
| 15941 | (setq cnt (1+ cnt)) | ||
| 15942 | (org-toggle-tag tag (if off 'off 'on)) | ||
| 15943 | (setq newhead (org-get-heading))))) | ||
| 15944 | (and agendap (org-agenda-change-all-lines newhead m)))) | ||
| 15945 | (message "Tag :%s: %s in %d headings" tag (if off "removed" "set") cnt))) | ||
| 15946 | |||
| 15947 | (defun org-tags-completion-function (string predicate &optional flag) | ||
| 15948 | (let (s1 s2 rtn (ctable org-last-tags-completion-table) | ||
| 15949 | (confirm (lambda (x) (stringp (car x))))) | ||
| 15950 | (if (string-match "^\\(.*[-+:&|]\\)\\([^-+:&|]*\\)$" string) | ||
| 15951 | (setq s1 (match-string 1 string) | ||
| 15952 | s2 (match-string 2 string)) | ||
| 15953 | (setq s1 "" s2 string)) | ||
| 15954 | (cond | ||
| 15955 | ((eq flag nil) | ||
| 15956 | ;; try completion | ||
| 15957 | (setq rtn (try-completion s2 ctable confirm)) | ||
| 15958 | (if (stringp rtn) | ||
| 15959 | (setq rtn | ||
| 15960 | (concat s1 s2 (substring rtn (length s2)) | ||
| 15961 | (if (and org-add-colon-after-tag-completion | ||
| 15962 | (assoc rtn ctable)) | ||
| 15963 | ":" "")))) | ||
| 15964 | rtn) | ||
| 15965 | ((eq flag t) | ||
| 15966 | ;; all-completions | ||
| 15967 | (all-completions s2 ctable confirm) | ||
| 15968 | ) | ||
| 15969 | ((eq flag 'lambda) | ||
| 15970 | ;; exact match? | ||
| 15971 | (assoc s2 ctable))) | ||
| 15972 | )) | ||
| 15973 | |||
| 15974 | (defun org-fast-tag-insert (kwd tags face &optional end) | ||
| 15975 | "Insert KDW, and the TAGS, the latter with face FACE. Also inser END." | ||
| 15976 | (insert (format "%-12s" (concat kwd ":")) | ||
| 15977 | (org-add-props (mapconcat 'identity tags " ") nil 'face face) | ||
| 15978 | (or end ""))) | ||
| 15979 | |||
| 15980 | (defun org-fast-tag-show-exit (flag) | ||
| 15981 | (save-excursion | ||
| 15982 | (goto-line 3) | ||
| 15983 | (if (re-search-forward "[ \t]+Next change exits" (point-at-eol) t) | ||
| 15984 | (replace-match "")) | ||
| 15985 | (when flag | ||
| 15986 | (end-of-line 1) | ||
| 15987 | (move-to-column (- (window-width) 19) t) | ||
| 15988 | (insert (org-add-props " Next change exits" nil 'face 'org-warning))))) | ||
| 15989 | |||
| 15990 | (defun org-set-current-tags-overlay (current prefix) | ||
| 15991 | (let ((s (concat ":" (mapconcat 'identity current ":") ":"))) | ||
| 15992 | (if (featurep 'xemacs) | ||
| 15993 | (org-overlay-display org-tags-overlay (concat prefix s) | ||
| 15994 | 'secondary-selection) | ||
| 15995 | (put-text-property 0 (length s) 'face '(secondary-selection org-tag) s) | ||
| 15996 | (org-overlay-display org-tags-overlay (concat prefix s))))) | ||
| 15997 | |||
| 15998 | (defun org-fast-tag-selection (current inherited table &optional todo-table) | ||
| 15999 | "Fast tag selection with single keys. | ||
| 16000 | CURRENT is the current list of tags in the headline, INHERITED is the | ||
| 16001 | list of inherited tags, and TABLE is an alist of tags and corresponding keys, | ||
| 16002 | possibly with grouping information. TODO-TABLE is a similar table with | ||
| 16003 | TODO keywords, should these have keys assigned to them. | ||
| 16004 | If the keys are nil, a-z are automatically assigned. | ||
| 16005 | Returns the new tags string, or nil to not change the current settings." | ||
| 16006 | (let* ((fulltable (append table todo-table)) | ||
| 16007 | (maxlen (apply 'max (mapcar | ||
| 16008 | (lambda (x) | ||
| 16009 | (if (stringp (car x)) (string-width (car x)) 0)) | ||
| 16010 | fulltable))) | ||
| 16011 | (buf (current-buffer)) | ||
| 16012 | (expert (eq org-fast-tag-selection-single-key 'expert)) | ||
| 16013 | (buffer-tags nil) | ||
| 16014 | (fwidth (+ maxlen 3 1 3)) | ||
| 16015 | (ncol (/ (- (window-width) 4) fwidth)) | ||
| 16016 | (i-face 'org-done) | ||
| 16017 | (c-face 'org-todo) | ||
| 16018 | tg cnt e c char c1 c2 ntable tbl rtn | ||
| 16019 | ov-start ov-end ov-prefix | ||
| 16020 | (exit-after-next org-fast-tag-selection-single-key) | ||
| 16021 | (done-keywords org-done-keywords) | ||
| 16022 | groups ingroup) | ||
| 16023 | (save-excursion | ||
| 16024 | (beginning-of-line 1) | ||
| 16025 | (if (looking-at | ||
| 16026 | (org-re ".*[ \t]\\(:[[:alnum:]_@:]+:\\)[ \t]*$")) | ||
| 16027 | (setq ov-start (match-beginning 1) | ||
| 16028 | ov-end (match-end 1) | ||
| 16029 | ov-prefix "") | ||
| 16030 | (setq ov-start (1- (point-at-eol)) | ||
| 16031 | ov-end (1+ ov-start)) | ||
| 16032 | (skip-chars-forward "^\n\r") | ||
| 16033 | (setq ov-prefix | ||
| 16034 | (concat | ||
| 16035 | (buffer-substring (1- (point)) (point)) | ||
| 16036 | (if (> (current-column) org-tags-column) | ||
| 16037 | " " | ||
| 16038 | (make-string (- org-tags-column (current-column)) ?\ )))))) | ||
| 16039 | (org-move-overlay org-tags-overlay ov-start ov-end) | ||
| 16040 | (save-window-excursion | ||
| 16041 | (if expert | ||
| 16042 | (set-buffer (get-buffer-create " *Org tags*")) | ||
| 16043 | (delete-other-windows) | ||
| 16044 | (split-window-vertically) | ||
| 16045 | (org-switch-to-buffer-other-window (get-buffer-create " *Org tags*"))) | ||
| 16046 | (erase-buffer) | ||
| 16047 | (org-set-local 'org-done-keywords done-keywords) | ||
| 16048 | (org-fast-tag-insert "Inherited" inherited i-face "\n") | ||
| 16049 | (org-fast-tag-insert "Current" current c-face "\n\n") | ||
| 16050 | (org-fast-tag-show-exit exit-after-next) | ||
| 16051 | (org-set-current-tags-overlay current ov-prefix) | ||
| 16052 | (setq tbl fulltable char ?a cnt 0) | ||
| 16053 | (while (setq e (pop tbl)) | ||
| 16054 | (cond | ||
| 16055 | ((equal e '(:startgroup)) | ||
| 16056 | (push '() groups) (setq ingroup t) | ||
| 16057 | (when (not (= cnt 0)) | ||
| 16058 | (setq cnt 0) | ||
| 16059 | (insert "\n")) | ||
| 16060 | (insert "{ ")) | ||
| 16061 | ((equal e '(:endgroup)) | ||
| 16062 | (setq ingroup nil cnt 0) | ||
| 16063 | (insert "}\n")) | ||
| 16064 | (t | ||
| 16065 | (setq tg (car e) c2 nil) | ||
| 16066 | (if (cdr e) | ||
| 16067 | (setq c (cdr e)) | ||
| 16068 | ;; automatically assign a character. | ||
| 16069 | (setq c1 (string-to-char | ||
| 16070 | (downcase (substring | ||
| 16071 | tg (if (= (string-to-char tg) ?@) 1 0))))) | ||
| 16072 | (if (or (rassoc c1 ntable) (rassoc c1 table)) | ||
| 16073 | (while (or (rassoc char ntable) (rassoc char table)) | ||
| 16074 | (setq char (1+ char))) | ||
| 16075 | (setq c2 c1)) | ||
| 16076 | (setq c (or c2 char))) | ||
| 16077 | (if ingroup (push tg (car groups))) | ||
| 16078 | (setq tg (org-add-props tg nil 'face | ||
| 16079 | (cond | ||
| 16080 | ((not (assoc tg table)) | ||
| 16081 | (org-get-todo-face tg)) | ||
| 16082 | ((member tg current) c-face) | ||
| 16083 | ((member tg inherited) i-face) | ||
| 16084 | (t nil)))) | ||
| 16085 | (if (and (= cnt 0) (not ingroup)) (insert " ")) | ||
| 16086 | (insert "[" c "] " tg (make-string | ||
| 16087 | (- fwidth 4 (length tg)) ?\ )) | ||
| 16088 | (push (cons tg c) ntable) | ||
| 16089 | (when (= (setq cnt (1+ cnt)) ncol) | ||
| 16090 | (insert "\n") | ||
| 16091 | (if ingroup (insert " ")) | ||
| 16092 | (setq cnt 0))))) | ||
| 16093 | (setq ntable (nreverse ntable)) | ||
| 16094 | (insert "\n") | ||
| 16095 | (goto-char (point-min)) | ||
| 16096 | (if (and (not expert) (fboundp 'fit-window-to-buffer)) | ||
| 16097 | (fit-window-to-buffer)) | ||
| 16098 | (setq rtn | ||
| 16099 | (catch 'exit | ||
| 16100 | (while t | ||
| 16101 | (message "[a-z..]:Toggle [SPC]:clear [RET]:accept [TAB]:free%s%s" | ||
| 16102 | (if groups " [!] no groups" " [!]groups") | ||
| 16103 | (if expert " [C-c]:window" (if exit-after-next " [C-c]:single" " [C-c]:multi"))) | ||
| 16104 | (setq c (let ((inhibit-quit t)) (read-char-exclusive))) | ||
| 16105 | (cond | ||
| 16106 | ((= c ?\r) (throw 'exit t)) | ||
| 16107 | ((= c ?!) | ||
| 16108 | (setq groups (not groups)) | ||
| 16109 | (goto-char (point-min)) | ||
| 16110 | (while (re-search-forward "[{}]" nil t) (replace-match " "))) | ||
| 16111 | ((= c ?\C-c) | ||
| 16112 | (if (not expert) | ||
| 16113 | (org-fast-tag-show-exit | ||
| 16114 | (setq exit-after-next (not exit-after-next))) | ||
| 16115 | (setq expert nil) | ||
| 16116 | (delete-other-windows) | ||
| 16117 | (split-window-vertically) | ||
| 16118 | (org-switch-to-buffer-other-window " *Org tags*") | ||
| 16119 | (and (fboundp 'fit-window-to-buffer) | ||
| 16120 | (fit-window-to-buffer)))) | ||
| 16121 | ((or (= c ?\C-g) | ||
| 16122 | (and (= c ?q) (not (rassoc c ntable)))) | ||
| 16123 | (org-detach-overlay org-tags-overlay) | ||
| 16124 | (setq quit-flag t)) | ||
| 16125 | ((= c ?\ ) | ||
| 16126 | (setq current nil) | ||
| 16127 | (if exit-after-next (setq exit-after-next 'now))) | ||
| 16128 | ((= c ?\t) | ||
| 16129 | (condition-case nil | ||
| 16130 | (setq tg (completing-read | ||
| 16131 | "Tag: " | ||
| 16132 | (or buffer-tags | ||
| 16133 | (with-current-buffer buf | ||
| 16134 | (org-get-buffer-tags))))) | ||
| 16135 | (quit (setq tg ""))) | ||
| 16136 | (when (string-match "\\S-" tg) | ||
| 16137 | (add-to-list 'buffer-tags (list tg)) | ||
| 16138 | (if (member tg current) | ||
| 16139 | (setq current (delete tg current)) | ||
| 16140 | (push tg current))) | ||
| 16141 | (if exit-after-next (setq exit-after-next 'now))) | ||
| 16142 | ((setq e (rassoc c todo-table) tg (car e)) | ||
| 16143 | (with-current-buffer buf | ||
| 16144 | (save-excursion (org-todo tg))) | ||
| 16145 | (if exit-after-next (setq exit-after-next 'now))) | ||
| 16146 | ((setq e (rassoc c ntable) tg (car e)) | ||
| 16147 | (if (member tg current) | ||
| 16148 | (setq current (delete tg current)) | ||
| 16149 | (loop for g in groups do | ||
| 16150 | (if (member tg g) | ||
| 16151 | (mapc (lambda (x) | ||
| 16152 | (setq current (delete x current))) | ||
| 16153 | g))) | ||
| 16154 | (push tg current)) | ||
| 16155 | (if exit-after-next (setq exit-after-next 'now)))) | ||
| 16156 | |||
| 16157 | ;; Create a sorted list | ||
| 16158 | (setq current | ||
| 16159 | (sort current | ||
| 16160 | (lambda (a b) | ||
| 16161 | (assoc b (cdr (memq (assoc a ntable) ntable)))))) | ||
| 16162 | (if (eq exit-after-next 'now) (throw 'exit t)) | ||
| 16163 | (goto-char (point-min)) | ||
| 16164 | (beginning-of-line 2) | ||
| 16165 | (delete-region (point) (point-at-eol)) | ||
| 16166 | (org-fast-tag-insert "Current" current c-face) | ||
| 16167 | (org-set-current-tags-overlay current ov-prefix) | ||
| 16168 | (while (re-search-forward | ||
| 16169 | (org-re "\\[.\\] \\([[:alnum:]_@]+\\)") nil t) | ||
| 16170 | (setq tg (match-string 1)) | ||
| 16171 | (add-text-properties | ||
| 16172 | (match-beginning 1) (match-end 1) | ||
| 16173 | (list 'face | ||
| 16174 | (cond | ||
| 16175 | ((member tg current) c-face) | ||
| 16176 | ((member tg inherited) i-face) | ||
| 16177 | (t (get-text-property (match-beginning 1) 'face)))))) | ||
| 16178 | (goto-char (point-min))))) | ||
| 16179 | (org-detach-overlay org-tags-overlay) | ||
| 16180 | (if rtn | ||
| 16181 | (mapconcat 'identity current ":") | ||
| 16182 | nil)))) | ||
| 16183 | |||
| 16184 | (defun org-get-tags-string () | ||
| 16185 | "Get the TAGS string in the current headline." | ||
| 16186 | (unless (org-on-heading-p t) | ||
| 16187 | (error "Not on a heading")) | ||
| 16188 | (save-excursion | ||
| 16189 | (beginning-of-line 1) | ||
| 16190 | (if (looking-at (org-re ".*[ \t]\\(:[[:alnum:]_@:]+:\\)[ \t]*$")) | ||
| 16191 | (org-match-string-no-properties 1) | ||
| 16192 | ""))) | ||
| 16193 | |||
| 16194 | (defun org-get-tags () | ||
| 16195 | "Get the list of tags specified in the current headline." | ||
| 16196 | (org-split-string (org-get-tags-string) ":")) | ||
| 16197 | |||
| 16198 | (defun org-get-buffer-tags () | ||
| 16199 | "Get a table of all tags used in the buffer, for completion." | ||
| 16200 | (let (tags) | ||
| 16201 | (save-excursion | ||
| 16202 | (goto-char (point-min)) | ||
| 16203 | (while (re-search-forward | ||
| 16204 | (org-re "[ \t]:\\([[:alnum:]_@:]+\\):[ \t\r\n]") nil t) | ||
| 16205 | (when (equal (char-after (point-at-bol 0)) ?*) | ||
| 16206 | (mapc (lambda (x) (add-to-list 'tags x)) | ||
| 16207 | (org-split-string (org-match-string-no-properties 1) ":"))))) | ||
| 16208 | (mapcar 'list tags))) | ||
| 16209 | |||
| 16210 | |||
| 16211 | ;;;; Properties | ||
| 16212 | |||
| 16213 | ;;; Setting and retrieving properties | ||
| 16214 | |||
| 16215 | (defconst org-special-properties | ||
| 16216 | '("TODO" "TAGS" "ALLTAGS" "DEADLINE" "SCHEDULED" "CLOCK" "PRIORITY" | ||
| 16217 | "TIMESTAMP" "TIMESTAMP_IA") | ||
| 16218 | "The special properties valid in Org-mode. | ||
| 16219 | |||
| 16220 | These are properties that are not defined in the property drawer, | ||
| 16221 | but in some other way.") | ||
| 16222 | |||
| 16223 | (defconst org-default-properties | ||
| 16224 | '("ARCHIVE" "CATEGORY" "SUMMARY" "DESCRIPTION" | ||
| 16225 | "LOCATION" "LOGGING" "COLUMNS") | ||
| 16226 | "Some properties that are used by Org-mode for various purposes. | ||
| 16227 | Being in this list makes sure that they are offered for completion.") | ||
| 16228 | |||
| 16229 | (defconst org-property-start-re "^[ \t]*:PROPERTIES:[ \t]*$" | ||
| 16230 | "Regular expression matching the first line of a property drawer.") | ||
| 16231 | |||
| 16232 | (defconst org-property-end-re "^[ \t]*:END:[ \t]*$" | ||
| 16233 | "Regular expression matching the first line of a property drawer.") | ||
| 16234 | |||
| 16235 | (defun org-property-action () | ||
| 16236 | "Do an action on properties." | ||
| 16237 | (interactive) | ||
| 16238 | (let (c) | ||
| 16239 | (org-at-property-p) | ||
| 16240 | (message "Property Action: [s]et [d]elete [D]elete globally [c]ompute") | ||
| 16241 | (setq c (read-char-exclusive)) | ||
| 16242 | (cond | ||
| 16243 | ((equal c ?s) | ||
| 16244 | (call-interactively 'org-set-property)) | ||
| 16245 | ((equal c ?d) | ||
| 16246 | (call-interactively 'org-delete-property)) | ||
| 16247 | ((equal c ?D) | ||
| 16248 | (call-interactively 'org-delete-property-globally)) | ||
| 16249 | ((equal c ?c) | ||
| 16250 | (call-interactively 'org-compute-property-at-point)) | ||
| 16251 | (t (error "No such property action %c" c))))) | ||
| 16252 | |||
| 16253 | (defun org-at-property-p () | ||
| 16254 | "Is the cursor in a property line?" | ||
| 16255 | ;; FIXME: Does not check if we are actually in the drawer. | ||
| 16256 | ;; FIXME: also returns true on any drawers..... | ||
| 16257 | ;; This is used by C-c C-c for property action. | ||
| 16258 | (save-excursion | ||
| 16259 | (beginning-of-line 1) | ||
| 16260 | (looking-at (org-re "^[ \t]*\\(:\\([[:alpha:]][[:alnum:]_-]*\\):\\)[ \t]*\\(.*\\)")))) | ||
| 16261 | |||
| 16262 | (defmacro org-with-point-at (pom &rest body) | ||
| 16263 | "Move to buffer and point of point-or-marker POM for the duration of BODY." | ||
| 16264 | (declare (indent 1) (debug t)) | ||
| 16265 | `(save-excursion | ||
| 16266 | (if (markerp pom) (set-buffer (marker-buffer pom))) | ||
| 16267 | (save-excursion | ||
| 16268 | (goto-char (or pom (point))) | ||
| 16269 | ,@body))) | ||
| 16270 | |||
| 16271 | (defun org-get-property-block (&optional beg end force) | ||
| 16272 | "Return the (beg . end) range of the body of the property drawer. | ||
| 16273 | BEG and END can be beginning and end of subtree, if not given | ||
| 16274 | they will be found. | ||
| 16275 | If the drawer does not exist and FORCE is non-nil, create the drawer." | ||
| 16276 | (catch 'exit | ||
| 16277 | (save-excursion | ||
| 16278 | (let* ((beg (or beg (progn (org-back-to-heading t) (point)))) | ||
| 16279 | (end (or end (progn (outline-next-heading) (point))))) | ||
| 16280 | (goto-char beg) | ||
| 16281 | (if (re-search-forward org-property-start-re end t) | ||
| 16282 | (setq beg (1+ (match-end 0))) | ||
| 16283 | (if force | ||
| 16284 | (save-excursion | ||
| 16285 | (org-insert-property-drawer) | ||
| 16286 | (setq end (progn (outline-next-heading) (point)))) | ||
| 16287 | (throw 'exit nil)) | ||
| 16288 | (goto-char beg) | ||
| 16289 | (if (re-search-forward org-property-start-re end t) | ||
| 16290 | (setq beg (1+ (match-end 0))))) | ||
| 16291 | (if (re-search-forward org-property-end-re end t) | ||
| 16292 | (setq end (match-beginning 0)) | ||
| 16293 | (or force (throw 'exit nil)) | ||
| 16294 | (goto-char beg) | ||
| 16295 | (setq end beg) | ||
| 16296 | (org-indent-line-function) | ||
| 16297 | (insert ":END:\n")) | ||
| 16298 | (cons beg end))))) | ||
| 16299 | |||
| 16300 | (defun org-entry-properties (&optional pom which) | ||
| 16301 | "Get all properties of the entry at point-or-marker POM. | ||
| 16302 | This includes the TODO keyword, the tags, time strings for deadline, | ||
| 16303 | scheduled, and clocking, and any additional properties defined in the | ||
| 16304 | entry. The return value is an alist, keys may occur multiple times | ||
| 16305 | if the property key was used several times. | ||
| 16306 | POM may also be nil, in which case the current entry is used. | ||
| 16307 | If WHICH is nil or `all', get all properties. If WHICH is | ||
| 16308 | `special' or `standard', only get that subclass." | ||
| 16309 | (setq which (or which 'all)) | ||
| 16310 | (org-with-point-at pom | ||
| 16311 | (let ((clockstr (substring org-clock-string 0 -1)) | ||
| 16312 | (excluded '("TODO" "TAGS" "ALLTAGS" "PRIORITY")) | ||
| 16313 | beg end range props sum-props key value string clocksum) | ||
| 16314 | (save-excursion | ||
| 16315 | (when (condition-case nil (org-back-to-heading t) (error nil)) | ||
| 16316 | (setq beg (point)) | ||
| 16317 | (setq sum-props (get-text-property (point) 'org-summaries)) | ||
| 16318 | (setq clocksum (get-text-property (point) :org-clock-minutes)) | ||
| 16319 | (outline-next-heading) | ||
| 16320 | (setq end (point)) | ||
| 16321 | (when (memq which '(all special)) | ||
| 16322 | ;; Get the special properties, like TODO and tags | ||
| 16323 | (goto-char beg) | ||
| 16324 | (when (and (looking-at org-todo-line-regexp) (match-end 2)) | ||
| 16325 | (push (cons "TODO" (org-match-string-no-properties 2)) props)) | ||
| 16326 | (when (looking-at org-priority-regexp) | ||
| 16327 | (push (cons "PRIORITY" (org-match-string-no-properties 2)) props)) | ||
| 16328 | (when (and (setq value (org-get-tags-string)) | ||
| 16329 | (string-match "\\S-" value)) | ||
| 16330 | (push (cons "TAGS" value) props)) | ||
| 16331 | (when (setq value (org-get-tags-at)) | ||
| 16332 | (push (cons "ALLTAGS" (concat ":" (mapconcat 'identity value ":") ":")) | ||
| 16333 | props)) | ||
| 16334 | (while (re-search-forward org-maybe-keyword-time-regexp end t) | ||
| 16335 | (setq key (if (match-end 1) (substring (org-match-string-no-properties 1) 0 -1)) | ||
| 16336 | string (if (equal key clockstr) | ||
| 16337 | (org-no-properties | ||
| 16338 | (org-trim | ||
| 16339 | (buffer-substring | ||
| 16340 | (match-beginning 3) (goto-char (point-at-eol))))) | ||
| 16341 | (substring (org-match-string-no-properties 3) 1 -1))) | ||
| 16342 | (unless key | ||
| 16343 | (if (= (char-after (match-beginning 3)) ?\[) | ||
| 16344 | (setq key "TIMESTAMP_IA") | ||
| 16345 | (setq key "TIMESTAMP"))) | ||
| 16346 | (when (or (equal key clockstr) (not (assoc key props))) | ||
| 16347 | (push (cons key string) props))) | ||
| 16348 | |||
| 16349 | ) | ||
| 16350 | |||
| 16351 | (when (memq which '(all standard)) | ||
| 16352 | ;; Get the standard properties, like :PORP: ... | ||
| 16353 | (setq range (org-get-property-block beg end)) | ||
| 16354 | (when range | ||
| 16355 | (goto-char (car range)) | ||
| 16356 | (while (re-search-forward | ||
| 16357 | (org-re "^[ \t]*:\\([[:alpha:]][[:alnum:]_-]*\\):[ \t]*\\(\\S-.*\\)?") | ||
| 16358 | (cdr range) t) | ||
| 16359 | (setq key (org-match-string-no-properties 1) | ||
| 16360 | value (org-trim (or (org-match-string-no-properties 2) ""))) | ||
| 16361 | (unless (member key excluded) | ||
| 16362 | (push (cons key (or value "")) props))))) | ||
| 16363 | (if clocksum | ||
| 16364 | (push (cons "CLOCKSUM" | ||
| 16365 | (org-column-number-to-string (/ (float clocksum) 60.) | ||
| 16366 | 'add_times)) | ||
| 16367 | props)) | ||
| 16368 | (append sum-props (nreverse props))))))) | ||
| 16369 | |||
| 16370 | (defun org-entry-get (pom property &optional inherit) | ||
| 16371 | "Get value of PROPERTY for entry at point-or-marker POM. | ||
| 16372 | If INHERIT is non-nil and the entry does not have the property, | ||
| 16373 | then also check higher levels of the hierarchy. | ||
| 16374 | If the property is present but empty, the return value is the empty string. | ||
| 16375 | If the property is not present at all, nil is returned." | ||
| 16376 | (org-with-point-at pom | ||
| 16377 | (if inherit | ||
| 16378 | (org-entry-get-with-inheritance property) | ||
| 16379 | (if (member property org-special-properties) | ||
| 16380 | ;; We need a special property. Use brute force, get all properties. | ||
| 16381 | (cdr (assoc property (org-entry-properties nil 'special))) | ||
| 16382 | (let ((range (org-get-property-block))) | ||
| 16383 | (if (and range | ||
| 16384 | (goto-char (car range)) | ||
| 16385 | (re-search-forward | ||
| 16386 | (concat "^[ \t]*:" property ":[ \t]*\\(.*\\S-\\)?") | ||
| 16387 | (cdr range) t)) | ||
| 16388 | ;; Found the property, return it. | ||
| 16389 | (if (match-end 1) | ||
| 16390 | (org-match-string-no-properties 1) | ||
| 16391 | ""))))))) | ||
| 16392 | |||
| 16393 | (defun org-entry-delete (pom property) | ||
| 16394 | "Delete the property PROPERTY from entry at point-or-marker POM." | ||
| 16395 | (org-with-point-at pom | ||
| 16396 | (if (member property org-special-properties) | ||
| 16397 | nil ; cannot delete these properties. | ||
| 16398 | (let ((range (org-get-property-block))) | ||
| 16399 | (if (and range | ||
| 16400 | (goto-char (car range)) | ||
| 16401 | (re-search-forward | ||
| 16402 | (concat "^[ \t]*:" property ":[ \t]*\\(.*\\S-\\)") | ||
| 16403 | (cdr range) t)) | ||
| 16404 | (progn | ||
| 16405 | (delete-region (match-beginning 0) (1+ (point-at-eol))) | ||
| 16406 | t) | ||
| 16407 | nil))))) | ||
| 16408 | |||
| 16409 | ;; Multi-values properties are properties that contain multiple values | ||
| 16410 | ;; These values are assumed to be single words, separated by whitespace. | ||
| 16411 | (defun org-entry-add-to-multivalued-property (pom property value) | ||
| 16412 | "Add VALUE to the words in the PROPERTY in entry at point-or-marker POM." | ||
| 16413 | (let* ((old (org-entry-get pom property)) | ||
| 16414 | (values (and old (org-split-string old "[ \t]")))) | ||
| 16415 | (unless (member value values) | ||
| 16416 | (setq values (cons value values)) | ||
| 16417 | (org-entry-put pom property | ||
| 16418 | (mapconcat 'identity values " "))))) | ||
| 16419 | |||
| 16420 | (defun org-entry-remove-from-multivalued-property (pom property value) | ||
| 16421 | "Remove VALUE from words in the PROPERTY in entry at point-or-marker POM." | ||
| 16422 | (let* ((old (org-entry-get pom property)) | ||
| 16423 | (values (and old (org-split-string old "[ \t]")))) | ||
| 16424 | (when (member value values) | ||
| 16425 | (setq values (delete value values)) | ||
| 16426 | (org-entry-put pom property | ||
| 16427 | (mapconcat 'identity values " "))))) | ||
| 16428 | |||
| 16429 | (defun org-entry-member-in-multivalued-property (pom property value) | ||
| 16430 | "Is VALUE one of the words in the PROPERTY in entry at point-or-marker POM?" | ||
| 16431 | (let* ((old (org-entry-get pom property)) | ||
| 16432 | (values (and old (org-split-string old "[ \t]")))) | ||
| 16433 | (member value values))) | ||
| 16434 | |||
| 16435 | (defvar org-entry-property-inherited-from (make-marker)) | ||
| 16436 | |||
| 16437 | (defun org-entry-get-with-inheritance (property) | ||
| 16438 | "Get entry property, and search higher levels if not present." | ||
| 16439 | (let (tmp) | ||
| 16440 | (save-excursion | ||
| 16441 | (save-restriction | ||
| 16442 | (widen) | ||
| 16443 | (catch 'ex | ||
| 16444 | (while t | ||
| 16445 | (when (setq tmp (org-entry-get nil property)) | ||
| 16446 | (org-back-to-heading t) | ||
| 16447 | (move-marker org-entry-property-inherited-from (point)) | ||
| 16448 | (throw 'ex tmp)) | ||
| 16449 | (or (org-up-heading-safe) (throw 'ex nil))))) | ||
| 16450 | (or tmp (cdr (assoc property org-local-properties)) | ||
| 16451 | (cdr (assoc property org-global-properties)))))) | ||
| 16452 | |||
| 16453 | (defun org-entry-put (pom property value) | ||
| 16454 | "Set PROPERTY to VALUE for entry at point-or-marker POM." | ||
| 16455 | (org-with-point-at pom | ||
| 16456 | (org-back-to-heading t) | ||
| 16457 | (let ((beg (point)) (end (save-excursion (outline-next-heading) (point))) | ||
| 16458 | range) | ||
| 16459 | (cond | ||
| 16460 | ((equal property "TODO") | ||
| 16461 | (when (and (stringp value) (string-match "\\S-" value) | ||
| 16462 | (not (member value org-todo-keywords-1))) | ||
| 16463 | (error "\"%s\" is not a valid TODO state" value)) | ||
| 16464 | (if (or (not value) | ||
| 16465 | (not (string-match "\\S-" value))) | ||
| 16466 | (setq value 'none)) | ||
| 16467 | (org-todo value) | ||
| 16468 | (org-set-tags nil 'align)) | ||
| 16469 | ((equal property "PRIORITY") | ||
| 16470 | (org-priority (if (and value (stringp value) (string-match "\\S-" value)) | ||
| 16471 | (string-to-char value) ?\ )) | ||
| 16472 | (org-set-tags nil 'align)) | ||
| 16473 | ((equal property "SCHEDULED") | ||
| 16474 | (if (re-search-forward org-scheduled-time-regexp end t) | ||
| 16475 | (cond | ||
| 16476 | ((eq value 'earlier) (org-timestamp-change -1 'day)) | ||
| 16477 | ((eq value 'later) (org-timestamp-change 1 'day)) | ||
| 16478 | (t (call-interactively 'org-schedule))) | ||
| 16479 | (call-interactively 'org-schedule))) | ||
| 16480 | ((equal property "DEADLINE") | ||
| 16481 | (if (re-search-forward org-deadline-time-regexp end t) | ||
| 16482 | (cond | ||
| 16483 | ((eq value 'earlier) (org-timestamp-change -1 'day)) | ||
| 16484 | ((eq value 'later) (org-timestamp-change 1 'day)) | ||
| 16485 | (t (call-interactively 'org-deadline))) | ||
| 16486 | (call-interactively 'org-deadline))) | ||
| 16487 | ((member property org-special-properties) | ||
| 16488 | (error "The %s property can not yet be set with `org-entry-put'" | ||
| 16489 | property)) | ||
| 16490 | (t ; a non-special property | ||
| 16491 | (let ((buffer-invisibility-spec (org-inhibit-invisibility))) ; Emacs 21 | ||
| 16492 | (setq range (org-get-property-block beg end 'force)) | ||
| 16493 | (goto-char (car range)) | ||
| 16494 | (if (re-search-forward | ||
| 16495 | (concat "^[ \t]*:" property ":\\(.*\\)") (cdr range) t) | ||
| 16496 | (progn | ||
| 16497 | (delete-region (match-beginning 1) (match-end 1)) | ||
| 16498 | (goto-char (match-beginning 1))) | ||
| 16499 | (goto-char (cdr range)) | ||
| 16500 | (insert "\n") | ||
| 16501 | (backward-char 1) | ||
| 16502 | (org-indent-line-function) | ||
| 16503 | (insert ":" property ":")) | ||
| 16504 | (and value (insert " " value)) | ||
| 16505 | (org-indent-line-function))))))) | ||
| 16506 | |||
| 16507 | (defun org-buffer-property-keys (&optional include-specials include-defaults include-columns) | ||
| 16508 | "Get all property keys in the current buffer. | ||
| 16509 | With INCLUDE-SPECIALS, also list the special properties that relect things | ||
| 16510 | like tags and TODO state. | ||
| 16511 | With INCLUDE-DEFAULTS, also include properties that has special meaning | ||
| 16512 | internally: ARCHIVE, CATEGORY, SUMMARY, DESCRIPTION, LOCATION, and LOGGING. | ||
| 16513 | With INCLUDE-COLUMNS, also include property names given in COLUMN | ||
| 16514 | formats in the current buffer." | ||
| 16515 | (let (rtn range cfmt cols s p) | ||
| 16516 | (save-excursion | ||
| 16517 | (save-restriction | ||
| 16518 | (widen) | ||
| 16519 | (goto-char (point-min)) | ||
| 16520 | (while (re-search-forward org-property-start-re nil t) | ||
| 16521 | (setq range (org-get-property-block)) | ||
| 16522 | (goto-char (car range)) | ||
| 16523 | (while (re-search-forward | ||
| 16524 | (org-re "^[ \t]*:\\([-[:alnum:]_]+\\):") | ||
| 16525 | (cdr range) t) | ||
| 16526 | (add-to-list 'rtn (org-match-string-no-properties 1))) | ||
| 16527 | (outline-next-heading)))) | ||
| 16528 | |||
| 16529 | (when include-specials | ||
| 16530 | (setq rtn (append org-special-properties rtn))) | ||
| 16531 | |||
| 16532 | (when include-defaults | ||
| 16533 | (mapc (lambda (x) (add-to-list 'rtn x)) org-default-properties)) | ||
| 16534 | |||
| 16535 | (when include-columns | ||
| 16536 | (save-excursion | ||
| 16537 | (save-restriction | ||
| 16538 | (widen) | ||
| 16539 | (goto-char (point-min)) | ||
| 16540 | (while (re-search-forward | ||
| 16541 | "^\\(#\\+COLUMNS:\\|[ \t]*:COLUMNS:\\)[ \t]*\\(.*\\)" | ||
| 16542 | nil t) | ||
| 16543 | (setq cfmt (match-string 2) s 0) | ||
| 16544 | (while (string-match (org-re "%[0-9]*\\([-[:alnum:]_]+\\)") | ||
| 16545 | cfmt s) | ||
| 16546 | (setq s (match-end 0) | ||
| 16547 | p (match-string 1 cfmt)) | ||
| 16548 | (unless (or (equal p "ITEM") | ||
| 16549 | (member p org-special-properties)) | ||
| 16550 | (add-to-list 'rtn (match-string 1 cfmt)))))))) | ||
| 16551 | |||
| 16552 | (sort rtn (lambda (a b) (string< (upcase a) (upcase b)))))) | ||
| 16553 | |||
| 16554 | (defun org-property-values (key) | ||
| 16555 | "Return a list of all values of property KEY." | ||
| 16556 | (save-excursion | ||
| 16557 | (save-restriction | ||
| 16558 | (widen) | ||
| 16559 | (goto-char (point-min)) | ||
| 16560 | (let ((re (concat "^[ \t]*:" key ":[ \t]*\\(\\S-.*\\)")) | ||
| 16561 | values) | ||
| 16562 | (while (re-search-forward re nil t) | ||
| 16563 | (add-to-list 'values (org-trim (match-string 1)))) | ||
| 16564 | (delete "" values))))) | ||
| 16565 | |||
| 16566 | (defun org-insert-property-drawer () | ||
| 16567 | "Insert a property drawer into the current entry." | ||
| 16568 | (interactive) | ||
| 16569 | (org-back-to-heading t) | ||
| 16570 | (looking-at outline-regexp) | ||
| 16571 | (let ((indent (- (match-end 0)(match-beginning 0))) | ||
| 16572 | (beg (point)) | ||
| 16573 | (re (concat "^[ \t]*" org-keyword-time-regexp)) | ||
| 16574 | end hiddenp) | ||
| 16575 | (outline-next-heading) | ||
| 16576 | (setq end (point)) | ||
| 16577 | (goto-char beg) | ||
| 16578 | (while (re-search-forward re end t)) | ||
| 16579 | (setq hiddenp (org-invisible-p)) | ||
| 16580 | (end-of-line 1) | ||
| 16581 | (and (equal (char-after) ?\n) (forward-char 1)) | ||
| 16582 | (org-skip-over-state-notes) | ||
| 16583 | (skip-chars-backward " \t\n\r") | ||
| 16584 | (if (eq (char-before) ?*) (forward-char 1)) | ||
| 16585 | (let ((inhibit-read-only t)) (insert "\n:PROPERTIES:\n:END:")) | ||
| 16586 | (beginning-of-line 0) | ||
| 16587 | (indent-to-column indent) | ||
| 16588 | (beginning-of-line 2) | ||
| 16589 | (indent-to-column indent) | ||
| 16590 | (beginning-of-line 0) | ||
| 16591 | (if hiddenp | ||
| 16592 | (save-excursion | ||
| 16593 | (org-back-to-heading t) | ||
| 16594 | (hide-entry)) | ||
| 16595 | (org-flag-drawer t)))) | ||
| 16596 | |||
| 16597 | (defun org-set-property (property value) | ||
| 16598 | "In the current entry, set PROPERTY to VALUE. | ||
| 16599 | When called interactively, this will prompt for a property name, offering | ||
| 16600 | completion on existing and default properties. And then it will prompt | ||
| 16601 | for a value, offering competion either on allowed values (via an inherited | ||
| 16602 | xxx_ALL property) or on existing values in other instances of this property | ||
| 16603 | in the current file." | ||
| 16604 | (interactive | ||
| 16605 | (let* ((prop (completing-read | ||
| 16606 | "Property: " (mapcar 'list (org-buffer-property-keys nil t t)))) | ||
| 16607 | (cur (org-entry-get nil prop)) | ||
| 16608 | (allowed (org-property-get-allowed-values nil prop 'table)) | ||
| 16609 | (existing (mapcar 'list (org-property-values prop))) | ||
| 16610 | (val (if allowed | ||
| 16611 | (completing-read "Value: " allowed nil 'req-match) | ||
| 16612 | (completing-read | ||
| 16613 | (concat "Value" (if (and cur (string-match "\\S-" cur)) | ||
| 16614 | (concat "[" cur "]") "") | ||
| 16615 | ": ") | ||
| 16616 | existing nil nil "" nil cur)))) | ||
| 16617 | (list prop (if (equal val "") cur val)))) | ||
| 16618 | (unless (equal (org-entry-get nil property) value) | ||
| 16619 | (org-entry-put nil property value))) | ||
| 16620 | |||
| 16621 | (defun org-delete-property (property) | ||
| 16622 | "In the current entry, delete PROPERTY." | ||
| 16623 | (interactive | ||
| 16624 | (let* ((prop (completing-read | ||
| 16625 | "Property: " (org-entry-properties nil 'standard)))) | ||
| 16626 | (list prop))) | ||
| 16627 | (message "Property %s %s" property | ||
| 16628 | (if (org-entry-delete nil property) | ||
| 16629 | "deleted" | ||
| 16630 | "was not present in the entry"))) | ||
| 16631 | |||
| 16632 | (defun org-delete-property-globally (property) | ||
| 16633 | "Remove PROPERTY globally, from all entries." | ||
| 16634 | (interactive | ||
| 16635 | (let* ((prop (completing-read | ||
| 16636 | "Globally remove property: " | ||
| 16637 | (mapcar 'list (org-buffer-property-keys))))) | ||
| 16638 | (list prop))) | ||
| 16639 | (save-excursion | ||
| 16640 | (save-restriction | ||
| 16641 | (widen) | ||
| 16642 | (goto-char (point-min)) | ||
| 16643 | (let ((cnt 0)) | ||
| 16644 | (while (re-search-forward | ||
| 16645 | (concat "^[ \t]*:" (regexp-quote property) ":.*\n?") | ||
| 16646 | nil t) | ||
| 16647 | (setq cnt (1+ cnt)) | ||
| 16648 | (replace-match "")) | ||
| 16649 | (message "Property \"%s\" removed from %d entries" property cnt))))) | ||
| 16650 | |||
| 16651 | (defvar org-columns-current-fmt-compiled) ; defined below | ||
| 16652 | |||
| 16653 | (defun org-compute-property-at-point () | ||
| 16654 | "Compute the property at point. | ||
| 16655 | This looks for an enclosing column format, extracts the operator and | ||
| 16656 | then applies it to the proerty in the column format's scope." | ||
| 16657 | (interactive) | ||
| 16658 | (unless (org-at-property-p) | ||
| 16659 | (error "Not at a property")) | ||
| 16660 | (let ((prop (org-match-string-no-properties 2))) | ||
| 16661 | (org-columns-get-format-and-top-level) | ||
| 16662 | (unless (nth 3 (assoc prop org-columns-current-fmt-compiled)) | ||
| 16663 | (error "No operator defined for property %s" prop)) | ||
| 16664 | (org-columns-compute prop))) | ||
| 16665 | |||
| 16666 | (defun org-property-get-allowed-values (pom property &optional table) | ||
| 16667 | "Get allowed values for the property PROPERTY. | ||
| 16668 | When TABLE is non-nil, return an alist that can directly be used for | ||
| 16669 | completion." | ||
| 16670 | (let (vals) | ||
| 16671 | (cond | ||
| 16672 | ((equal property "TODO") | ||
| 16673 | (setq vals (org-with-point-at pom | ||
| 16674 | (append org-todo-keywords-1 '(""))))) | ||
| 16675 | ((equal property "PRIORITY") | ||
| 16676 | (let ((n org-lowest-priority)) | ||
| 16677 | (while (>= n org-highest-priority) | ||
| 16678 | (push (char-to-string n) vals) | ||
| 16679 | (setq n (1- n))))) | ||
| 16680 | ((member property org-special-properties)) | ||
| 16681 | (t | ||
| 16682 | (setq vals (org-entry-get pom (concat property "_ALL") 'inherit)) | ||
| 16683 | |||
| 16684 | (when (and vals (string-match "\\S-" vals)) | ||
| 16685 | (setq vals (car (read-from-string (concat "(" vals ")")))) | ||
| 16686 | (setq vals (mapcar (lambda (x) | ||
| 16687 | (cond ((stringp x) x) | ||
| 16688 | ((numberp x) (number-to-string x)) | ||
| 16689 | ((symbolp x) (symbol-name x)) | ||
| 16690 | (t "???"))) | ||
| 16691 | vals))))) | ||
| 16692 | (if table (mapcar 'list vals) vals))) | ||
| 16693 | |||
| 16694 | (defun org-property-previous-allowed-value (&optional previous) | ||
| 16695 | "Switch to the next allowed value for this property." | ||
| 16696 | (interactive) | ||
| 16697 | (org-property-next-allowed-value t)) | ||
| 16698 | |||
| 16699 | (defun org-property-next-allowed-value (&optional previous) | ||
| 16700 | "Switch to the next allowed value for this property." | ||
| 16701 | (interactive) | ||
| 16702 | (unless (org-at-property-p) | ||
| 16703 | (error "Not at a property")) | ||
| 16704 | (let* ((key (match-string 2)) | ||
| 16705 | (value (match-string 3)) | ||
| 16706 | (allowed (or (org-property-get-allowed-values (point) key) | ||
| 16707 | (and (member value '("[ ]" "[-]" "[X]")) | ||
| 16708 | '("[ ]" "[X]")))) | ||
| 16709 | nval) | ||
| 16710 | (unless allowed | ||
| 16711 | (error "Allowed values for this property have not been defined")) | ||
| 16712 | (if previous (setq allowed (reverse allowed))) | ||
| 16713 | (if (member value allowed) | ||
| 16714 | (setq nval (car (cdr (member value allowed))))) | ||
| 16715 | (setq nval (or nval (car allowed))) | ||
| 16716 | (if (equal nval value) | ||
| 16717 | (error "Only one allowed value for this property")) | ||
| 16718 | (org-at-property-p) | ||
| 16719 | (replace-match (concat " :" key ": " nval) t t) | ||
| 16720 | (org-indent-line-function) | ||
| 16721 | (beginning-of-line 1) | ||
| 16722 | (skip-chars-forward " \t"))) | ||
| 16723 | |||
| 16724 | (defun org-find-entry-with-id (ident) | ||
| 16725 | "Locate the entry that contains the ID property with exact value IDENT. | ||
| 16726 | IDENT can be a string, a symbol or a number, this function will search for | ||
| 16727 | the string representation of it. | ||
| 16728 | Return the position where this entry starts, or nil if there is no such entry." | ||
| 16729 | (let ((id (cond | ||
| 16730 | ((stringp ident) ident) | ||
| 16731 | ((symbol-name ident) (symbol-name ident)) | ||
| 16732 | ((numberp ident) (number-to-string ident)) | ||
| 16733 | (t (error "IDENT %s must be a string, symbol or number" ident)))) | ||
| 16734 | (case-fold-search nil)) | ||
| 16735 | (save-excursion | ||
| 16736 | (save-restriction | ||
| 16737 | (widen) | ||
| 16738 | (goto-char (point-min)) | ||
| 16739 | (when (re-search-forward | ||
| 16740 | (concat "^[ \t]*:ID:[ \t]+" (regexp-quote id) "[ \t]*$") | ||
| 16741 | nil t) | ||
| 16742 | (org-back-to-heading) | ||
| 16743 | (point)))))) | ||
| 16744 | |||
| 16745 | ;;; Column View | ||
| 16746 | |||
| 16747 | (defvar org-columns-overlays nil | ||
| 16748 | "Holds the list of current column overlays.") | ||
| 16749 | |||
| 16750 | (defvar org-columns-current-fmt nil | ||
| 16751 | "Local variable, holds the currently active column format.") | ||
| 16752 | (defvar org-columns-current-fmt-compiled nil | ||
| 16753 | "Local variable, holds the currently active column format. | ||
| 16754 | This is the compiled version of the format.") | ||
| 16755 | (defvar org-columns-current-widths nil | ||
| 16756 | "Loval variable, holds the currently widths of fields.") | ||
| 16757 | (defvar org-columns-current-maxwidths nil | ||
| 16758 | "Loval variable, holds the currently active maximum column widths.") | ||
| 16759 | (defvar org-columns-begin-marker (make-marker) | ||
| 16760 | "Points to the position where last a column creation command was called.") | ||
| 16761 | (defvar org-columns-top-level-marker (make-marker) | ||
| 16762 | "Points to the position where current columns region starts.") | ||
| 16763 | |||
| 16764 | (defvar org-columns-map (make-sparse-keymap) | ||
| 16765 | "The keymap valid in column display.") | ||
| 16766 | |||
| 16767 | (defun org-columns-content () | ||
| 16768 | "Switch to contents view while in columns view." | ||
| 16769 | (interactive) | ||
| 16770 | (org-overview) | ||
| 16771 | (org-content)) | ||
| 16772 | |||
| 16773 | (org-defkey org-columns-map "c" 'org-columns-content) | ||
| 16774 | (org-defkey org-columns-map "o" 'org-overview) | ||
| 16775 | (org-defkey org-columns-map "e" 'org-columns-edit-value) | ||
| 16776 | (org-defkey org-columns-map "\C-c\C-t" 'org-columns-todo) | ||
| 16777 | (org-defkey org-columns-map "\C-c\C-c" 'org-columns-set-tags-or-toggle) | ||
| 16778 | (org-defkey org-columns-map "\C-c\C-o" 'org-columns-open-link) | ||
| 16779 | (org-defkey org-columns-map "v" 'org-columns-show-value) | ||
| 16780 | (org-defkey org-columns-map "q" 'org-columns-quit) | ||
| 16781 | (org-defkey org-columns-map "r" 'org-columns-redo) | ||
| 16782 | (org-defkey org-columns-map "g" 'org-columns-redo) | ||
| 16783 | (org-defkey org-columns-map [left] 'backward-char) | ||
| 16784 | (org-defkey org-columns-map "\M-b" 'backward-char) | ||
| 16785 | (org-defkey org-columns-map "a" 'org-columns-edit-allowed) | ||
| 16786 | (org-defkey org-columns-map "s" 'org-columns-edit-attributes) | ||
| 16787 | (org-defkey org-columns-map "\M-f" (lambda () (interactive) (goto-char (1+ (point))))) | ||
| 16788 | (org-defkey org-columns-map [right] (lambda () (interactive) (goto-char (1+ (point))))) | ||
| 16789 | (org-defkey org-columns-map [(shift right)] 'org-columns-next-allowed-value) | ||
| 16790 | (org-defkey org-columns-map "n" 'org-columns-next-allowed-value) | ||
| 16791 | (org-defkey org-columns-map [(shift left)] 'org-columns-previous-allowed-value) | ||
| 16792 | (org-defkey org-columns-map "p" 'org-columns-previous-allowed-value) | ||
| 16793 | (org-defkey org-columns-map "<" 'org-columns-narrow) | ||
| 16794 | (org-defkey org-columns-map ">" 'org-columns-widen) | ||
| 16795 | (org-defkey org-columns-map [(meta right)] 'org-columns-move-right) | ||
| 16796 | (org-defkey org-columns-map [(meta left)] 'org-columns-move-left) | ||
| 16797 | (org-defkey org-columns-map [(shift meta right)] 'org-columns-new) | ||
| 16798 | (org-defkey org-columns-map [(shift meta left)] 'org-columns-delete) | ||
| 16799 | |||
| 16800 | (easy-menu-define org-columns-menu org-columns-map "Org Column Menu" | ||
| 16801 | '("Column" | ||
| 16802 | ["Edit property" org-columns-edit-value t] | ||
| 16803 | ["Next allowed value" org-columns-next-allowed-value t] | ||
| 16804 | ["Previous allowed value" org-columns-previous-allowed-value t] | ||
| 16805 | ["Show full value" org-columns-show-value t] | ||
| 16806 | ["Edit allowed values" org-columns-edit-allowed t] | ||
| 16807 | "--" | ||
| 16808 | ["Edit column attributes" org-columns-edit-attributes t] | ||
| 16809 | ["Increase column width" org-columns-widen t] | ||
| 16810 | ["Decrease column width" org-columns-narrow t] | ||
| 16811 | "--" | ||
| 16812 | ["Move column right" org-columns-move-right t] | ||
| 16813 | ["Move column left" org-columns-move-left t] | ||
| 16814 | ["Add column" org-columns-new t] | ||
| 16815 | ["Delete column" org-columns-delete t] | ||
| 16816 | "--" | ||
| 16817 | ["CONTENTS" org-columns-content t] | ||
| 16818 | ["OVERVIEW" org-overview t] | ||
| 16819 | ["Refresh columns display" org-columns-redo t] | ||
| 16820 | "--" | ||
| 16821 | ["Open link" org-columns-open-link t] | ||
| 16822 | "--" | ||
| 16823 | ["Quit" org-columns-quit t])) | ||
| 16824 | |||
| 16825 | (defun org-columns-new-overlay (beg end &optional string face) | ||
| 16826 | "Create a new column overlay and add it to the list." | ||
| 16827 | (let ((ov (org-make-overlay beg end))) | ||
| 16828 | (org-overlay-put ov 'face (or face 'secondary-selection)) | ||
| 16829 | (org-overlay-display ov string face) | ||
| 16830 | (push ov org-columns-overlays) | ||
| 16831 | ov)) | ||
| 16832 | |||
| 16833 | (defun org-columns-display-here (&optional props) | ||
| 16834 | "Overlay the current line with column display." | ||
| 16835 | (interactive) | ||
| 16836 | (let* ((fmt org-columns-current-fmt-compiled) | ||
| 16837 | (beg (point-at-bol)) | ||
| 16838 | (level-face (save-excursion | ||
| 16839 | (beginning-of-line 1) | ||
| 16840 | (and (looking-at "\\(\\**\\)\\(\\* \\)") | ||
| 16841 | (org-get-level-face 2)))) | ||
| 16842 | (color (list :foreground | ||
| 16843 | (face-attribute (or level-face 'default) :foreground))) | ||
| 16844 | props pom property ass width f string ov column val modval) | ||
| 16845 | ;; Check if the entry is in another buffer. | ||
| 16846 | (unless props | ||
| 16847 | (if (eq major-mode 'org-agenda-mode) | ||
| 16848 | (setq pom (or (get-text-property (point) 'org-hd-marker) | ||
| 16849 | (get-text-property (point) 'org-marker)) | ||
| 16850 | props (if pom (org-entry-properties pom) nil)) | ||
| 16851 | (setq props (org-entry-properties nil)))) | ||
| 16852 | ;; Walk the format | ||
| 16853 | (while (setq column (pop fmt)) | ||
| 16854 | (setq property (car column) | ||
| 16855 | ass (if (equal property "ITEM") | ||
| 16856 | (cons "ITEM" | ||
| 16857 | (save-match-data | ||
| 16858 | (org-no-properties | ||
| 16859 | (org-remove-tabs | ||
| 16860 | (buffer-substring-no-properties | ||
| 16861 | (point-at-bol) (point-at-eol)))))) | ||
| 16862 | (assoc property props)) | ||
| 16863 | width (or (cdr (assoc property org-columns-current-maxwidths)) | ||
| 16864 | (nth 2 column) | ||
| 16865 | (length property)) | ||
| 16866 | f (format "%%-%d.%ds | " width width) | ||
| 16867 | val (or (cdr ass) "") | ||
| 16868 | modval (if (equal property "ITEM") | ||
| 16869 | (org-columns-cleanup-item val org-columns-current-fmt-compiled)) | ||
| 16870 | string (format f (or modval val))) | ||
| 16871 | ;; Create the overlay | ||
| 16872 | (org-unmodified | ||
| 16873 | (setq ov (org-columns-new-overlay | ||
| 16874 | beg (setq beg (1+ beg)) string | ||
| 16875 | (list color 'org-column))) | ||
| 16876 | ;;; (list (get-text-property (point-at-bol) 'face) 'org-column))) | ||
| 16877 | (org-overlay-put ov 'keymap org-columns-map) | ||
| 16878 | (org-overlay-put ov 'org-columns-key property) | ||
| 16879 | (org-overlay-put ov 'org-columns-value (cdr ass)) | ||
| 16880 | (org-overlay-put ov 'org-columns-value-modified modval) | ||
| 16881 | (org-overlay-put ov 'org-columns-pom pom) | ||
| 16882 | (org-overlay-put ov 'org-columns-format f)) | ||
| 16883 | (if (or (not (char-after beg)) | ||
| 16884 | (equal (char-after beg) ?\n)) | ||
| 16885 | (let ((inhibit-read-only t)) | ||
| 16886 | (save-excursion | ||
| 16887 | (goto-char beg) | ||
| 16888 | (org-unmodified (insert " ")))))) ;; FIXME: add props and remove later? | ||
| 16889 | ;; Make the rest of the line disappear. | ||
| 16890 | (org-unmodified | ||
| 16891 | (setq ov (org-columns-new-overlay beg (point-at-eol))) | ||
| 16892 | (org-overlay-put ov 'invisible t) | ||
| 16893 | (org-overlay-put ov 'keymap org-columns-map) | ||
| 16894 | (org-overlay-put ov 'intangible t) | ||
| 16895 | (push ov org-columns-overlays) | ||
| 16896 | (setq ov (org-make-overlay (1- (point-at-eol)) (1+ (point-at-eol)))) | ||
| 16897 | (org-overlay-put ov 'keymap org-columns-map) | ||
| 16898 | (push ov org-columns-overlays) | ||
| 16899 | (let ((inhibit-read-only t)) | ||
| 16900 | (put-text-property (max (point-min) (1- (point-at-bol))) | ||
| 16901 | (min (point-max) (1+ (point-at-eol))) | ||
| 16902 | 'read-only "Type `e' to edit property"))))) | ||
| 16903 | |||
| 16904 | (defvar org-previous-header-line-format nil | ||
| 16905 | "The header line format before column view was turned on.") | ||
| 16906 | (defvar org-columns-inhibit-recalculation nil | ||
| 16907 | "Inhibit recomputing of columns on column view startup.") | ||
| 16908 | |||
| 16909 | |||
| 16910 | (defvar header-line-format) | ||
| 16911 | (defun org-columns-display-here-title () | ||
| 16912 | "Overlay the newline before the current line with the table title." | ||
| 16913 | (interactive) | ||
| 16914 | (let ((fmt org-columns-current-fmt-compiled) | ||
| 16915 | string (title "") | ||
| 16916 | property width f column str widths) | ||
| 16917 | (while (setq column (pop fmt)) | ||
| 16918 | (setq property (car column) | ||
| 16919 | str (or (nth 1 column) property) | ||
| 16920 | width (or (cdr (assoc property org-columns-current-maxwidths)) | ||
| 16921 | (nth 2 column) | ||
| 16922 | (length str)) | ||
| 16923 | widths (push width widths) | ||
| 16924 | f (format "%%-%d.%ds | " width width) | ||
| 16925 | string (format f str) | ||
| 16926 | title (concat title string))) | ||
| 16927 | (setq title (concat | ||
| 16928 | (org-add-props " " nil 'display '(space :align-to 0)) | ||
| 16929 | (org-add-props title nil 'face '(:weight bold :underline t)))) | ||
| 16930 | (org-set-local 'org-previous-header-line-format header-line-format) | ||
| 16931 | (org-set-local 'org-columns-current-widths (nreverse widths)) | ||
| 16932 | (setq header-line-format title))) | ||
| 16933 | |||
| 16934 | (defun org-columns-remove-overlays () | ||
| 16935 | "Remove all currently active column overlays." | ||
| 16936 | (interactive) | ||
| 16937 | (when (marker-buffer org-columns-begin-marker) | ||
| 16938 | (with-current-buffer (marker-buffer org-columns-begin-marker) | ||
| 16939 | (when (local-variable-p 'org-previous-header-line-format) | ||
| 16940 | (setq header-line-format org-previous-header-line-format) | ||
| 16941 | (kill-local-variable 'org-previous-header-line-format)) | ||
| 16942 | (move-marker org-columns-begin-marker nil) | ||
| 16943 | (move-marker org-columns-top-level-marker nil) | ||
| 16944 | (org-unmodified | ||
| 16945 | (mapc 'org-delete-overlay org-columns-overlays) | ||
| 16946 | (setq org-columns-overlays nil) | ||
| 16947 | (let ((inhibit-read-only t)) | ||
| 16948 | (remove-text-properties (point-min) (point-max) '(read-only t))))))) | ||
| 16949 | |||
| 16950 | (defun org-columns-cleanup-item (item fmt) | ||
| 16951 | "Remove from ITEM what is a column in the format FMT." | ||
| 16952 | (if (not org-complex-heading-regexp) | ||
| 16953 | item | ||
| 16954 | (when (string-match org-complex-heading-regexp item) | ||
| 16955 | (concat | ||
| 16956 | (org-add-props (concat (match-string 1 item) " ") nil | ||
| 16957 | 'org-whitespace (* 2 (1- (org-reduced-level (- (match-end 1) (match-beginning 1)))))) | ||
| 16958 | (and (match-end 2) (not (assoc "TODO" fmt)) (concat " " (match-string 2 item))) | ||
| 16959 | (and (match-end 3) (not (assoc "PRIORITY" fmt)) (concat " " (match-string 3 item))) | ||
| 16960 | " " (match-string 4 item) | ||
| 16961 | (and (match-end 5) (not (assoc "TAGS" fmt)) (concat " " (match-string 5 item))))))) | ||
| 16962 | |||
| 16963 | (defun org-columns-show-value () | ||
| 16964 | "Show the full value of the property." | ||
| 16965 | (interactive) | ||
| 16966 | (let ((value (get-char-property (point) 'org-columns-value))) | ||
| 16967 | (message "Value is: %s" (or value "")))) | ||
| 16968 | |||
| 16969 | (defun org-columns-quit () | ||
| 16970 | "Remove the column overlays and in this way exit column editing." | ||
| 16971 | (interactive) | ||
| 16972 | (org-unmodified | ||
| 16973 | (org-columns-remove-overlays) | ||
| 16974 | (let ((inhibit-read-only t)) | ||
| 16975 | (remove-text-properties (point-min) (point-max) '(read-only t)))) | ||
| 16976 | (when (eq major-mode 'org-agenda-mode) | ||
| 16977 | (message | ||
| 16978 | "Modification not yet reflected in Agenda buffer, use `r' to refresh"))) | ||
| 16979 | |||
| 16980 | (defun org-columns-check-computed () | ||
| 16981 | "Check if this column value is computed. | ||
| 16982 | If yes, throw an error indicating that changing it does not make sense." | ||
| 16983 | (let ((val (get-char-property (point) 'org-columns-value))) | ||
| 16984 | (when (and (stringp val) | ||
| 16985 | (get-char-property 0 'org-computed val)) | ||
| 16986 | (error "This value is computed from the entry's children")))) | ||
| 16987 | |||
| 16988 | (defun org-columns-todo (&optional arg) | ||
| 16989 | "Change the TODO state during column view." | ||
| 16990 | (interactive "P") | ||
| 16991 | (org-columns-edit-value "TODO")) | ||
| 16992 | |||
| 16993 | (defun org-columns-set-tags-or-toggle (&optional arg) | ||
| 16994 | "Toggle checkbox at point, or set tags for current headline." | ||
| 16995 | (interactive "P") | ||
| 16996 | (if (string-match "\\`\\[[ xX-]\\]\\'" | ||
| 16997 | (get-char-property (point) 'org-columns-value)) | ||
| 16998 | (org-columns-next-allowed-value) | ||
| 16999 | (org-columns-edit-value "TAGS"))) | ||
| 17000 | |||
| 17001 | (defun org-columns-edit-value (&optional key) | ||
| 17002 | "Edit the value of the property at point in column view. | ||
| 17003 | Where possible, use the standard interface for changing this line." | ||
| 17004 | (interactive) | ||
| 17005 | (org-columns-check-computed) | ||
| 17006 | (let* ((external-key key) | ||
| 17007 | (col (current-column)) | ||
| 17008 | (key (or key (get-char-property (point) 'org-columns-key))) | ||
| 17009 | (value (get-char-property (point) 'org-columns-value)) | ||
| 17010 | (bol (point-at-bol)) (eol (point-at-eol)) | ||
| 17011 | (pom (or (get-text-property bol 'org-hd-marker) | ||
| 17012 | (point))) ; keep despite of compiler waring | ||
| 17013 | (line-overlays | ||
| 17014 | (delq nil (mapcar (lambda (x) | ||
| 17015 | (and (eq (overlay-buffer x) (current-buffer)) | ||
| 17016 | (>= (overlay-start x) bol) | ||
| 17017 | (<= (overlay-start x) eol) | ||
| 17018 | x)) | ||
| 17019 | org-columns-overlays))) | ||
| 17020 | nval eval allowed) | ||
| 17021 | (cond | ||
| 17022 | ((equal key "CLOCKSUM") | ||
| 17023 | (error "This special column cannot be edited")) | ||
| 17024 | ((equal key "ITEM") | ||
| 17025 | (setq eval '(org-with-point-at pom | ||
| 17026 | (org-edit-headline)))) | ||
| 17027 | ((equal key "TODO") | ||
| 17028 | (setq eval '(org-with-point-at pom | ||
| 17029 | (let ((current-prefix-arg | ||
| 17030 | (if external-key current-prefix-arg '(4)))) | ||
| 17031 | (call-interactively 'org-todo))))) | ||
| 17032 | ((equal key "PRIORITY") | ||
| 17033 | (setq eval '(org-with-point-at pom | ||
| 17034 | (call-interactively 'org-priority)))) | ||
| 17035 | ((equal key "TAGS") | ||
| 17036 | (setq eval '(org-with-point-at pom | ||
| 17037 | (let ((org-fast-tag-selection-single-key | ||
| 17038 | (if (eq org-fast-tag-selection-single-key 'expert) | ||
| 17039 | t org-fast-tag-selection-single-key))) | ||
| 17040 | (call-interactively 'org-set-tags))))) | ||
| 17041 | ((equal key "DEADLINE") | ||
| 17042 | (setq eval '(org-with-point-at pom | ||
| 17043 | (call-interactively 'org-deadline)))) | ||
| 17044 | ((equal key "SCHEDULED") | ||
| 17045 | (setq eval '(org-with-point-at pom | ||
| 17046 | (call-interactively 'org-schedule)))) | ||
| 17047 | (t | ||
| 17048 | (setq allowed (org-property-get-allowed-values pom key 'table)) | ||
| 17049 | (if allowed | ||
| 17050 | (setq nval (completing-read "Value: " allowed nil t)) | ||
| 17051 | (setq nval (read-string "Edit: " value))) | ||
| 17052 | (setq nval (org-trim nval)) | ||
| 17053 | (when (not (equal nval value)) | ||
| 17054 | (setq eval '(org-entry-put pom key nval))))) | ||
| 17055 | (when eval | ||
| 17056 | (let ((inhibit-read-only t)) | ||
| 17057 | (remove-text-properties (max (point-min) (1- bol)) eol '(read-only t)) | ||
| 17058 | (unwind-protect | ||
| 17059 | (progn | ||
| 17060 | (setq org-columns-overlays | ||
| 17061 | (org-delete-all line-overlays org-columns-overlays)) | ||
| 17062 | (mapc 'org-delete-overlay line-overlays) | ||
| 17063 | (org-columns-eval eval)) | ||
| 17064 | (org-columns-display-here)))) | ||
| 17065 | (move-to-column col) | ||
| 17066 | (if (and (org-mode-p) | ||
| 17067 | (nth 3 (assoc key org-columns-current-fmt-compiled))) | ||
| 17068 | (org-columns-update key)))) | ||
| 17069 | |||
| 17070 | (defun org-edit-headline () ; FIXME: this is not columns specific | ||
| 17071 | "Edit the current headline, the part without TODO keyword, TAGS." | ||
| 17072 | (org-back-to-heading) | ||
| 17073 | (when (looking-at org-todo-line-regexp) | ||
| 17074 | (let ((pre (buffer-substring (match-beginning 0) (match-beginning 3))) | ||
| 17075 | (txt (match-string 3)) | ||
| 17076 | (post "") | ||
| 17077 | txt2) | ||
| 17078 | (if (string-match (org-re "[ \t]+:[[:alnum:]:_@]+:[ \t]*$") txt) | ||
| 17079 | (setq post (match-string 0 txt) | ||
| 17080 | txt (substring txt 0 (match-beginning 0)))) | ||
| 17081 | (setq txt2 (read-string "Edit: " txt)) | ||
| 17082 | (when (not (equal txt txt2)) | ||
| 17083 | (beginning-of-line 1) | ||
| 17084 | (insert pre txt2 post) | ||
| 17085 | (delete-region (point) (point-at-eol)) | ||
| 17086 | (org-set-tags nil t))))) | ||
| 17087 | |||
| 17088 | (defun org-columns-edit-allowed () | ||
| 17089 | "Edit the list of allowed values for the current property." | ||
| 17090 | (interactive) | ||
| 17091 | (let* ((key (get-char-property (point) 'org-columns-key)) | ||
| 17092 | (key1 (concat key "_ALL")) | ||
| 17093 | (allowed (org-entry-get (point) key1 t)) | ||
| 17094 | nval) | ||
| 17095 | ;; FIXME: Cover editing TODO, TAGS etc in-buffer settings.???? | ||
| 17096 | (setq nval (read-string "Allowed: " allowed)) | ||
| 17097 | (org-entry-put | ||
| 17098 | (cond ((marker-position org-entry-property-inherited-from) | ||
| 17099 | org-entry-property-inherited-from) | ||
| 17100 | ((marker-position org-columns-top-level-marker) | ||
| 17101 | org-columns-top-level-marker)) | ||
| 17102 | key1 nval))) | ||
| 17103 | |||
| 17104 | (defmacro org-no-warnings (&rest body) | ||
| 17105 | (cons (if (fboundp 'with-no-warnings) 'with-no-warnings 'progn) body)) | ||
| 17106 | |||
| 17107 | (defun org-columns-eval (form) | ||
| 17108 | (let (hidep) | ||
| 17109 | (save-excursion | ||
| 17110 | (beginning-of-line 1) | ||
| 17111 | ;; `next-line' is needed here, because it skips invisible line. | ||
| 17112 | (condition-case nil (org-no-warnings (next-line 1)) (error nil)) | ||
| 17113 | (setq hidep (org-on-heading-p 1))) | ||
| 17114 | (eval form) | ||
| 17115 | (and hidep (hide-entry)))) | ||
| 17116 | |||
| 17117 | (defun org-columns-previous-allowed-value () | ||
| 17118 | "Switch to the previous allowed value for this column." | ||
| 17119 | (interactive) | ||
| 17120 | (org-columns-next-allowed-value t)) | ||
| 17121 | |||
| 17122 | (defun org-columns-next-allowed-value (&optional previous) | ||
| 17123 | "Switch to the next allowed value for this column." | ||
| 17124 | (interactive) | ||
| 17125 | (org-columns-check-computed) | ||
| 17126 | (let* ((col (current-column)) | ||
| 17127 | (key (get-char-property (point) 'org-columns-key)) | ||
| 17128 | (value (get-char-property (point) 'org-columns-value)) | ||
| 17129 | (bol (point-at-bol)) (eol (point-at-eol)) | ||
| 17130 | (pom (or (get-text-property bol 'org-hd-marker) | ||
| 17131 | (point))) ; keep despite of compiler waring | ||
| 17132 | (line-overlays | ||
| 17133 | (delq nil (mapcar (lambda (x) | ||
| 17134 | (and (eq (overlay-buffer x) (current-buffer)) | ||
| 17135 | (>= (overlay-start x) bol) | ||
| 17136 | (<= (overlay-start x) eol) | ||
| 17137 | x)) | ||
| 17138 | org-columns-overlays))) | ||
| 17139 | (allowed (or (org-property-get-allowed-values pom key) | ||
| 17140 | (and (memq | ||
| 17141 | (nth 4 (assoc key org-columns-current-fmt-compiled)) | ||
| 17142 | '(checkbox checkbox-n-of-m checkbox-percent)) | ||
| 17143 | '("[ ]" "[X]")))) | ||
| 17144 | nval) | ||
| 17145 | (when (equal key "ITEM") | ||
| 17146 | (error "Cannot edit item headline from here")) | ||
| 17147 | (unless (or allowed (member key '("SCHEDULED" "DEADLINE"))) | ||
| 17148 | (error "Allowed values for this property have not been defined")) | ||
| 17149 | (if (member key '("SCHEDULED" "DEADLINE")) | ||
| 17150 | (setq nval (if previous 'earlier 'later)) | ||
| 17151 | (if previous (setq allowed (reverse allowed))) | ||
| 17152 | (if (member value allowed) | ||
| 17153 | (setq nval (car (cdr (member value allowed))))) | ||
| 17154 | (setq nval (or nval (car allowed))) | ||
| 17155 | (if (equal nval value) | ||
| 17156 | (error "Only one allowed value for this property"))) | ||
| 17157 | (let ((inhibit-read-only t)) | ||
| 17158 | (remove-text-properties (1- bol) eol '(read-only t)) | ||
| 17159 | (unwind-protect | ||
| 17160 | (progn | ||
| 17161 | (setq org-columns-overlays | ||
| 17162 | (org-delete-all line-overlays org-columns-overlays)) | ||
| 17163 | (mapc 'org-delete-overlay line-overlays) | ||
| 17164 | (org-columns-eval '(org-entry-put pom key nval))) | ||
| 17165 | (org-columns-display-here))) | ||
| 17166 | (move-to-column col) | ||
| 17167 | (if (and (org-mode-p) | ||
| 17168 | (nth 3 (assoc key org-columns-current-fmt-compiled))) | ||
| 17169 | (org-columns-update key)))) | ||
| 17170 | |||
| 17171 | (defun org-verify-version (task) | ||
| 17172 | (cond | ||
| 17173 | ((eq task 'columns) | ||
| 17174 | (if (or (featurep 'xemacs) | ||
| 17175 | (< emacs-major-version 22)) | ||
| 17176 | (error "Emacs 22 is required for the columns feature"))))) | ||
| 17177 | |||
| 17178 | (defun org-columns-open-link (&optional arg) | ||
| 17179 | (interactive "P") | ||
| 17180 | (let ((value (get-char-property (point) 'org-columns-value))) | ||
| 17181 | (org-open-link-from-string value arg))) | ||
| 17182 | |||
| 17183 | (defun org-open-link-from-string (s &optional arg) | ||
| 17184 | "Open a link in the string S, as if it was in Org-mode." | ||
| 17185 | (interactive) | ||
| 17186 | (with-temp-buffer | ||
| 17187 | (let ((org-inhibit-startup t)) | ||
| 17188 | (org-mode) | ||
| 17189 | (insert s) | ||
| 17190 | (goto-char (point-min)) | ||
| 17191 | (org-open-at-point arg)))) | ||
| 17192 | |||
| 17193 | (defun org-columns-get-format-and-top-level () | ||
| 17194 | (let (fmt) | ||
| 17195 | (when (condition-case nil (org-back-to-heading) (error nil)) | ||
| 17196 | (move-marker org-entry-property-inherited-from nil) | ||
| 17197 | (setq fmt (org-entry-get nil "COLUMNS" t))) | ||
| 17198 | (setq fmt (or fmt org-columns-default-format)) | ||
| 17199 | (org-set-local 'org-columns-current-fmt fmt) | ||
| 17200 | (org-columns-compile-format fmt) | ||
| 17201 | (if (marker-position org-entry-property-inherited-from) | ||
| 17202 | (move-marker org-columns-top-level-marker | ||
| 17203 | org-entry-property-inherited-from) | ||
| 17204 | (move-marker org-columns-top-level-marker (point))) | ||
| 17205 | fmt)) | ||
| 17206 | |||
| 17207 | (defun org-columns () | ||
| 17208 | "Turn on column view on an org-mode file." | ||
| 17209 | (interactive) | ||
| 17210 | (org-verify-version 'columns) | ||
| 17211 | (org-columns-remove-overlays) | ||
| 17212 | (move-marker org-columns-begin-marker (point)) | ||
| 17213 | (let (beg end fmt cache maxwidths) | ||
| 17214 | (setq fmt (org-columns-get-format-and-top-level)) | ||
| 17215 | (save-excursion | ||
| 17216 | (goto-char org-columns-top-level-marker) | ||
| 17217 | (setq beg (point)) | ||
| 17218 | (unless org-columns-inhibit-recalculation | ||
| 17219 | (org-columns-compute-all)) | ||
| 17220 | (setq end (or (condition-case nil (org-end-of-subtree t t) (error nil)) | ||
| 17221 | (point-max))) | ||
| 17222 | ;; Get and cache the properties | ||
| 17223 | (goto-char beg) | ||
| 17224 | (when (assoc "CLOCKSUM" org-columns-current-fmt-compiled) | ||
| 17225 | (save-excursion | ||
| 17226 | (save-restriction | ||
| 17227 | (narrow-to-region beg end) | ||
| 17228 | (org-clock-sum)))) | ||
| 17229 | (while (re-search-forward (concat "^" outline-regexp) end t) | ||
| 17230 | (push (cons (org-current-line) (org-entry-properties)) cache)) | ||
| 17231 | (when cache | ||
| 17232 | (setq maxwidths (org-columns-get-autowidth-alist fmt cache)) | ||
| 17233 | (org-set-local 'org-columns-current-maxwidths maxwidths) | ||
| 17234 | (org-columns-display-here-title) | ||
| 17235 | (mapc (lambda (x) | ||
| 17236 | (goto-line (car x)) | ||
| 17237 | (org-columns-display-here (cdr x))) | ||
| 17238 | cache))))) | ||
| 17239 | |||
| 17240 | (defun org-columns-new (&optional prop title width op fmt &rest rest) | ||
| 17241 | "Insert a new column, to the left of the current column." | ||
| 17242 | (interactive) | ||
| 17243 | (let ((editp (and prop (assoc prop org-columns-current-fmt-compiled))) | ||
| 17244 | cell) | ||
| 17245 | (setq prop (completing-read | ||
| 17246 | "Property: " (mapcar 'list (org-buffer-property-keys t nil t)) | ||
| 17247 | nil nil prop)) | ||
| 17248 | (setq title (read-string (concat "Column title [" prop "]: ") (or title prop))) | ||
| 17249 | (setq width (read-string "Column width: " (if width (number-to-string width)))) | ||
| 17250 | (if (string-match "\\S-" width) | ||
| 17251 | (setq width (string-to-number width)) | ||
| 17252 | (setq width nil)) | ||
| 17253 | (setq fmt (completing-read "Summary [none]: " | ||
| 17254 | '(("none") ("add_numbers") ("currency") ("add_times") ("checkbox") ("checkbox-n-of-m") ("checkbox-percent")) | ||
| 17255 | nil t)) | ||
| 17256 | (if (string-match "\\S-" fmt) | ||
| 17257 | (setq fmt (intern fmt)) | ||
| 17258 | (setq fmt nil)) | ||
| 17259 | (if (eq fmt 'none) (setq fmt nil)) | ||
| 17260 | (if editp | ||
| 17261 | (progn | ||
| 17262 | (setcar editp prop) | ||
| 17263 | (setcdr editp (list title width nil fmt))) | ||
| 17264 | (setq cell (nthcdr (1- (current-column)) | ||
| 17265 | org-columns-current-fmt-compiled)) | ||
| 17266 | (setcdr cell (cons (list prop title width nil fmt) | ||
| 17267 | (cdr cell)))) | ||
| 17268 | (org-columns-store-format) | ||
| 17269 | (org-columns-redo))) | ||
| 17270 | |||
| 17271 | (defun org-columns-delete () | ||
| 17272 | "Delete the column at point from columns view." | ||
| 17273 | (interactive) | ||
| 17274 | (let* ((n (current-column)) | ||
| 17275 | (title (nth 1 (nth n org-columns-current-fmt-compiled)))) | ||
| 17276 | (when (y-or-n-p | ||
| 17277 | (format "Are you sure you want to remove column \"%s\"? " title)) | ||
| 17278 | (setq org-columns-current-fmt-compiled | ||
| 17279 | (delq (nth n org-columns-current-fmt-compiled) | ||
| 17280 | org-columns-current-fmt-compiled)) | ||
| 17281 | (org-columns-store-format) | ||
| 17282 | (org-columns-redo) | ||
| 17283 | (if (>= (current-column) (length org-columns-current-fmt-compiled)) | ||
| 17284 | (backward-char 1))))) | ||
| 17285 | |||
| 17286 | (defun org-columns-edit-attributes () | ||
| 17287 | "Edit the attributes of the current column." | ||
| 17288 | (interactive) | ||
| 17289 | (let* ((n (current-column)) | ||
| 17290 | (info (nth n org-columns-current-fmt-compiled))) | ||
| 17291 | (apply 'org-columns-new info))) | ||
| 17292 | |||
| 17293 | (defun org-columns-widen (arg) | ||
| 17294 | "Make the column wider by ARG characters." | ||
| 17295 | (interactive "p") | ||
| 17296 | (let* ((n (current-column)) | ||
| 17297 | (entry (nth n org-columns-current-fmt-compiled)) | ||
| 17298 | (width (or (nth 2 entry) | ||
| 17299 | (cdr (assoc (car entry) org-columns-current-maxwidths))))) | ||
| 17300 | (setq width (max 1 (+ width arg))) | ||
| 17301 | (setcar (nthcdr 2 entry) width) | ||
| 17302 | (org-columns-store-format) | ||
| 17303 | (org-columns-redo))) | ||
| 17304 | |||
| 17305 | (defun org-columns-narrow (arg) | ||
| 17306 | "Make the column nrrower by ARG characters." | ||
| 17307 | (interactive "p") | ||
| 17308 | (org-columns-widen (- arg))) | ||
| 17309 | |||
| 17310 | (defun org-columns-move-right () | ||
| 17311 | "Swap this column with the one to the right." | ||
| 17312 | (interactive) | ||
| 17313 | (let* ((n (current-column)) | ||
| 17314 | (cell (nthcdr n org-columns-current-fmt-compiled)) | ||
| 17315 | e) | ||
| 17316 | (when (>= n (1- (length org-columns-current-fmt-compiled))) | ||
| 17317 | (error "Cannot shift this column further to the right")) | ||
| 17318 | (setq e (car cell)) | ||
| 17319 | (setcar cell (car (cdr cell))) | ||
| 17320 | (setcdr cell (cons e (cdr (cdr cell)))) | ||
| 17321 | (org-columns-store-format) | ||
| 17322 | (org-columns-redo) | ||
| 17323 | (forward-char 1))) | ||
| 17324 | |||
| 17325 | (defun org-columns-move-left () | ||
| 17326 | "Swap this column with the one to the left." | ||
| 17327 | (interactive) | ||
| 17328 | (let* ((n (current-column))) | ||
| 17329 | (when (= n 0) | ||
| 17330 | (error "Cannot shift this column further to the left")) | ||
| 17331 | (backward-char 1) | ||
| 17332 | (org-columns-move-right) | ||
| 17333 | (backward-char 1))) | ||
| 17334 | |||
| 17335 | (defun org-columns-store-format () | ||
| 17336 | "Store the text version of the current columns format in appropriate place. | ||
| 17337 | This is either in the COLUMNS property of the node starting the current column | ||
| 17338 | display, or in the #+COLUMNS line of the current buffer." | ||
| 17339 | (let (fmt (cnt 0)) | ||
| 17340 | (setq fmt (org-columns-uncompile-format org-columns-current-fmt-compiled)) | ||
| 17341 | (org-set-local 'org-columns-current-fmt fmt) | ||
| 17342 | (if (marker-position org-columns-top-level-marker) | ||
| 17343 | (save-excursion | ||
| 17344 | (goto-char org-columns-top-level-marker) | ||
| 17345 | (if (and (org-at-heading-p) | ||
| 17346 | (org-entry-get nil "COLUMNS")) | ||
| 17347 | (org-entry-put nil "COLUMNS" fmt) | ||
| 17348 | (goto-char (point-min)) | ||
| 17349 | ;; Overwrite all #+COLUMNS lines.... | ||
| 17350 | (while (re-search-forward "^#\\+COLUMNS:.*" nil t) | ||
| 17351 | (setq cnt (1+ cnt)) | ||
| 17352 | (replace-match (concat "#+COLUMNS: " fmt) t t)) | ||
| 17353 | (unless (> cnt 0) | ||
| 17354 | (goto-char (point-min)) | ||
| 17355 | (or (org-on-heading-p t) (outline-next-heading)) | ||
| 17356 | (let ((inhibit-read-only t)) | ||
| 17357 | (insert-before-markers "#+COLUMNS: " fmt "\n"))) | ||
| 17358 | (org-set-local 'org-columns-default-format fmt)))))) | ||
| 17359 | |||
| 17360 | (defvar org-overriding-columns-format nil | ||
| 17361 | "When set, overrides any other definition.") | ||
| 17362 | (defvar org-agenda-view-columns-initially nil | ||
| 17363 | "When set, switch to columns view immediately after creating the agenda.") | ||
| 17364 | |||
| 17365 | (defun org-agenda-columns () | ||
| 17366 | "Turn on column view in the agenda." | ||
| 17367 | (interactive) | ||
| 17368 | (org-verify-version 'columns) | ||
| 17369 | (org-columns-remove-overlays) | ||
| 17370 | (move-marker org-columns-begin-marker (point)) | ||
| 17371 | (let (fmt cache maxwidths m) | ||
| 17372 | (cond | ||
| 17373 | ((and (local-variable-p 'org-overriding-columns-format) | ||
| 17374 | org-overriding-columns-format) | ||
| 17375 | (setq fmt org-overriding-columns-format)) | ||
| 17376 | ((setq m (get-text-property (point-at-bol) 'org-hd-marker)) | ||
| 17377 | (setq fmt (org-entry-get m "COLUMNS" t))) | ||
| 17378 | ((and (boundp 'org-columns-current-fmt) | ||
| 17379 | (local-variable-p 'org-columns-current-fmt) | ||
| 17380 | org-columns-current-fmt) | ||
| 17381 | (setq fmt org-columns-current-fmt)) | ||
| 17382 | ((setq m (next-single-property-change (point-min) 'org-hd-marker)) | ||
| 17383 | (setq m (get-text-property m 'org-hd-marker)) | ||
| 17384 | (setq fmt (org-entry-get m "COLUMNS" t)))) | ||
| 17385 | (setq fmt (or fmt org-columns-default-format)) | ||
| 17386 | (org-set-local 'org-columns-current-fmt fmt) | ||
| 17387 | (org-columns-compile-format fmt) | ||
| 17388 | (save-excursion | ||
| 17389 | ;; Get and cache the properties | ||
| 17390 | (goto-char (point-min)) | ||
| 17391 | (while (not (eobp)) | ||
| 17392 | (when (setq m (or (get-text-property (point) 'org-hd-marker) | ||
| 17393 | (get-text-property (point) 'org-marker))) | ||
| 17394 | (push (cons (org-current-line) (org-entry-properties m)) cache)) | ||
| 17395 | (beginning-of-line 2)) | ||
| 17396 | (when cache | ||
| 17397 | (setq maxwidths (org-columns-get-autowidth-alist fmt cache)) | ||
| 17398 | (org-set-local 'org-columns-current-maxwidths maxwidths) | ||
| 17399 | (org-columns-display-here-title) | ||
| 17400 | (mapc (lambda (x) | ||
| 17401 | (goto-line (car x)) | ||
| 17402 | (org-columns-display-here (cdr x))) | ||
| 17403 | cache))))) | ||
| 17404 | |||
| 17405 | (defun org-columns-get-autowidth-alist (s cache) | ||
| 17406 | "Derive the maximum column widths from the format and the cache." | ||
| 17407 | (let ((start 0) rtn) | ||
| 17408 | (while (string-match (org-re "%\\([[:alpha:]][[:alnum:]_-]*\\)") s start) | ||
| 17409 | (push (cons (match-string 1 s) 1) rtn) | ||
| 17410 | (setq start (match-end 0))) | ||
| 17411 | (mapc (lambda (x) | ||
| 17412 | (setcdr x (apply 'max | ||
| 17413 | (mapcar | ||
| 17414 | (lambda (y) | ||
| 17415 | (length (or (cdr (assoc (car x) (cdr y))) " "))) | ||
| 17416 | cache)))) | ||
| 17417 | rtn) | ||
| 17418 | rtn)) | ||
| 17419 | |||
| 17420 | (defun org-columns-compute-all () | ||
| 17421 | "Compute all columns that have operators defined." | ||
| 17422 | (org-unmodified | ||
| 17423 | (remove-text-properties (point-min) (point-max) '(org-summaries t))) | ||
| 17424 | (let ((columns org-columns-current-fmt-compiled) col) | ||
| 17425 | (while (setq col (pop columns)) | ||
| 17426 | (when (nth 3 col) | ||
| 17427 | (save-excursion | ||
| 17428 | (org-columns-compute (car col))))))) | ||
| 17429 | |||
| 17430 | (defun org-columns-update (property) | ||
| 17431 | "Recompute PROPERTY, and update the columns display for it." | ||
| 17432 | (org-columns-compute property) | ||
| 17433 | (let (fmt val pos) | ||
| 17434 | (save-excursion | ||
| 17435 | (mapc (lambda (ov) | ||
| 17436 | (when (equal (org-overlay-get ov 'org-columns-key) property) | ||
| 17437 | (setq pos (org-overlay-start ov)) | ||
| 17438 | (goto-char pos) | ||
| 17439 | (when (setq val (cdr (assoc property | ||
| 17440 | (get-text-property | ||
| 17441 | (point-at-bol) 'org-summaries)))) | ||
| 17442 | (setq fmt (org-overlay-get ov 'org-columns-format)) | ||
| 17443 | (org-overlay-put ov 'org-columns-value val) | ||
| 17444 | (org-overlay-put ov 'display (format fmt val))))) | ||
| 17445 | org-columns-overlays)))) | ||
| 17446 | |||
| 17447 | (defun org-columns-compute (property) | ||
| 17448 | "Sum the values of property PROPERTY hierarchically, for the entire buffer." | ||
| 17449 | (interactive) | ||
| 17450 | (let* ((re (concat "^" outline-regexp)) | ||
| 17451 | (lmax 30) ; Does anyone use deeper levels??? | ||
| 17452 | (lsum (make-vector lmax 0)) | ||
| 17453 | (lflag (make-vector lmax nil)) | ||
| 17454 | (level 0) | ||
| 17455 | (ass (assoc property org-columns-current-fmt-compiled)) | ||
| 17456 | (format (nth 4 ass)) | ||
| 17457 | (printf (nth 5 ass)) | ||
| 17458 | (beg org-columns-top-level-marker) | ||
| 17459 | last-level val valflag flag end sumpos sum-alist sum str str1 useval) | ||
| 17460 | (save-excursion | ||
| 17461 | ;; Find the region to compute | ||
| 17462 | (goto-char beg) | ||
| 17463 | (setq end (condition-case nil (org-end-of-subtree t) (error (point-max)))) | ||
| 17464 | (goto-char end) | ||
| 17465 | ;; Walk the tree from the back and do the computations | ||
| 17466 | (while (re-search-backward re beg t) | ||
| 17467 | (setq sumpos (match-beginning 0) | ||
| 17468 | last-level level | ||
| 17469 | level (org-outline-level) | ||
| 17470 | val (org-entry-get nil property) | ||
| 17471 | valflag (and val (string-match "\\S-" val))) | ||
| 17472 | (cond | ||
| 17473 | ((< level last-level) | ||
| 17474 | ;; put the sum of lower levels here as a property | ||
| 17475 | (setq sum (aref lsum last-level) ; current sum | ||
| 17476 | flag (aref lflag last-level) ; any valid entries from children? | ||
| 17477 | str (org-column-number-to-string sum format printf) | ||
| 17478 | str1 (org-add-props (copy-sequence str) nil 'org-computed t 'face 'bold) | ||
| 17479 | useval (if flag str1 (if valflag val "")) | ||
| 17480 | sum-alist (get-text-property sumpos 'org-summaries)) | ||
| 17481 | (if (assoc property sum-alist) | ||
| 17482 | (setcdr (assoc property sum-alist) useval) | ||
| 17483 | (push (cons property useval) sum-alist) | ||
| 17484 | (org-unmodified | ||
| 17485 | (add-text-properties sumpos (1+ sumpos) | ||
| 17486 | (list 'org-summaries sum-alist)))) | ||
| 17487 | (when val | ||
| 17488 | (org-entry-put nil property (if flag str val))) | ||
| 17489 | ;; add current to current level accumulator | ||
| 17490 | (when (or flag valflag) | ||
| 17491 | (aset lsum level (+ (aref lsum level) | ||
| 17492 | (if flag sum (org-column-string-to-number | ||
| 17493 | (if flag str val) format)))) | ||
| 17494 | (aset lflag level t)) | ||
| 17495 | ;; clear accumulators for deeper levels | ||
| 17496 | (loop for l from (1+ level) to (1- lmax) do | ||
| 17497 | (aset lsum l 0) | ||
| 17498 | (aset lflag l nil))) | ||
| 17499 | ((>= level last-level) | ||
| 17500 | ;; add what we have here to the accumulator for this level | ||
| 17501 | (aset lsum level (+ (aref lsum level) | ||
| 17502 | (org-column-string-to-number (or val "0") format))) | ||
| 17503 | (and valflag (aset lflag level t))) | ||
| 17504 | (t (error "This should not happen"))))))) | ||
| 17505 | |||
| 17506 | (defun org-columns-redo () | ||
| 17507 | "Construct the column display again." | ||
| 17508 | (interactive) | ||
| 17509 | (message "Recomputing columns...") | ||
| 17510 | (save-excursion | ||
| 17511 | (if (marker-position org-columns-begin-marker) | ||
| 17512 | (goto-char org-columns-begin-marker)) | ||
| 17513 | (org-columns-remove-overlays) | ||
| 17514 | (if (org-mode-p) | ||
| 17515 | (call-interactively 'org-columns) | ||
| 17516 | (call-interactively 'org-agenda-columns))) | ||
| 17517 | (message "Recomputing columns...done")) | ||
| 17518 | |||
| 17519 | (defun org-columns-not-in-agenda () | ||
| 17520 | (if (eq major-mode 'org-agenda-mode) | ||
| 17521 | (error "This command is only allowed in Org-mode buffers"))) | ||
| 17522 | |||
| 17523 | |||
| 17524 | (defun org-string-to-number (s) | ||
| 17525 | "Convert string to number, and interpret hh:mm:ss." | ||
| 17526 | (if (not (string-match ":" s)) | ||
| 17527 | (string-to-number s) | ||
| 17528 | (let ((l (nreverse (org-split-string s ":"))) (sum 0.0)) | ||
| 17529 | (while l | ||
| 17530 | (setq sum (+ (string-to-number (pop l)) (/ sum 60)))) | ||
| 17531 | sum))) | ||
| 17532 | |||
| 17533 | (defun org-column-number-to-string (n fmt &optional printf) | ||
| 17534 | "Convert a computed column number to a string value, according to FMT." | ||
| 17535 | (cond | ||
| 17536 | ((eq fmt 'add_times) | ||
| 17537 | (let* ((h (floor n)) (m (floor (+ 0.5 (* 60 (- n h)))))) | ||
| 17538 | (format "%d:%02d" h m))) | ||
| 17539 | ((eq fmt 'checkbox) | ||
| 17540 | (cond ((= n (floor n)) "[X]") | ||
| 17541 | ((> n 1.) "[-]") | ||
| 17542 | (t "[ ]"))) | ||
| 17543 | ((memq fmt '(checkbox-n-of-m checkbox-percent)) | ||
| 17544 | (let* ((n1 (floor n)) (n2 (floor (+ .5 (* 1000000 (- n n1)))))) | ||
| 17545 | (org-nofm-to-completion n1 (+ n2 n1) (eq fmt 'checkbox-percent)))) | ||
| 17546 | (printf (format printf n)) | ||
| 17547 | ((eq fmt 'currency) | ||
| 17548 | (format "%.2f" n)) | ||
| 17549 | (t (number-to-string n)))) | ||
| 17550 | |||
| 17551 | (defun org-nofm-to-completion (n m &optional percent) | ||
| 17552 | (if (not percent) | ||
| 17553 | (format "[%d/%d]" n m) | ||
| 17554 | (format "[%d%%]"(floor (+ 0.5 (* 100. (/ (* 1.0 n) m))))))) | ||
| 17555 | |||
| 17556 | (defun org-column-string-to-number (s fmt) | ||
| 17557 | "Convert a column value to a number that can be used for column computing." | ||
| 17558 | (cond | ||
| 17559 | ((string-match ":" s) | ||
| 17560 | (let ((l (nreverse (org-split-string s ":"))) (sum 0.0)) | ||
| 17561 | (while l | ||
| 17562 | (setq sum (+ (string-to-number (pop l)) (/ sum 60)))) | ||
| 17563 | sum)) | ||
| 17564 | ((memq fmt '(checkbox checkbox-n-of-m checkbox-percent)) | ||
| 17565 | (if (equal s "[X]") 1. 0.000001)) | ||
| 17566 | (t (string-to-number s)))) | ||
| 17567 | |||
| 17568 | (defun org-columns-uncompile-format (cfmt) | ||
| 17569 | "Turn the compiled columns format back into a string representation." | ||
| 17570 | (let ((rtn "") e s prop title op width fmt printf) | ||
| 17571 | (while (setq e (pop cfmt)) | ||
| 17572 | (setq prop (car e) | ||
| 17573 | title (nth 1 e) | ||
| 17574 | width (nth 2 e) | ||
| 17575 | op (nth 3 e) | ||
| 17576 | fmt (nth 4 e) | ||
| 17577 | printf (nth 5 e)) | ||
| 17578 | (cond | ||
| 17579 | ((eq fmt 'add_times) (setq op ":")) | ||
| 17580 | ((eq fmt 'checkbox) (setq op "X")) | ||
| 17581 | ((eq fmt 'checkbox-n-of-m) (setq op "X/")) | ||
| 17582 | ((eq fmt 'checkbox-percent) (setq op "X%")) | ||
| 17583 | ((eq fmt 'add_numbers) (setq op "+")) | ||
| 17584 | ((eq fmt 'currency) (setq op "$"))) | ||
| 17585 | (if (and op printf) (setq op (concat op ";" printf))) | ||
| 17586 | (if (equal title prop) (setq title nil)) | ||
| 17587 | (setq s (concat "%" (if width (number-to-string width)) | ||
| 17588 | prop | ||
| 17589 | (if title (concat "(" title ")")) | ||
| 17590 | (if op (concat "{" op "}")))) | ||
| 17591 | (setq rtn (concat rtn " " s))) | ||
| 17592 | (org-trim rtn))) | ||
| 17593 | |||
| 17594 | (defun org-columns-compile-format (fmt) | ||
| 17595 | "Turn a column format string into an alist of specifications. | ||
| 17596 | The alist has one entry for each column in the format. The elements of | ||
| 17597 | that list are: | ||
| 17598 | property the property | ||
| 17599 | title the title field for the columns | ||
| 17600 | width the column width in characters, can be nil for automatic | ||
| 17601 | operator the operator if any | ||
| 17602 | format the output format for computed results, derived from operator | ||
| 17603 | printf a printf format for computed values" | ||
| 17604 | (let ((start 0) width prop title op f printf) | ||
| 17605 | (setq org-columns-current-fmt-compiled nil) | ||
| 17606 | (while (string-match | ||
| 17607 | (org-re "%\\([0-9]+\\)?\\([[:alnum:]_-]+\\)\\(?:(\\([^)]+\\))\\)?\\(?:{\\([^}]+\\)}\\)?\\s-*") | ||
| 17608 | fmt start) | ||
| 17609 | (setq start (match-end 0) | ||
| 17610 | width (match-string 1 fmt) | ||
| 17611 | prop (match-string 2 fmt) | ||
| 17612 | title (or (match-string 3 fmt) prop) | ||
| 17613 | op (match-string 4 fmt) | ||
| 17614 | f nil | ||
| 17615 | printf nil) | ||
| 17616 | (if width (setq width (string-to-number width))) | ||
| 17617 | (when (and op (string-match ";" op)) | ||
| 17618 | (setq printf (substring op (match-end 0)) | ||
| 17619 | op (substring op 0 (match-beginning 0)))) | ||
| 17620 | (cond | ||
| 17621 | ((equal op "+") (setq f 'add_numbers)) | ||
| 17622 | ((equal op "$") (setq f 'currency)) | ||
| 17623 | ((equal op ":") (setq f 'add_times)) | ||
| 17624 | ((equal op "X") (setq f 'checkbox)) | ||
| 17625 | ((equal op "X/") (setq f 'checkbox-n-of-m)) | ||
| 17626 | ((equal op "X%") (setq f 'checkbox-percent)) | ||
| 17627 | ) | ||
| 17628 | (push (list prop title width op f printf) org-columns-current-fmt-compiled)) | ||
| 17629 | (setq org-columns-current-fmt-compiled | ||
| 17630 | (nreverse org-columns-current-fmt-compiled)))) | ||
| 17631 | |||
| 17632 | |||
| 17633 | ;;; Dynamic block for Column view | ||
| 17634 | |||
| 17635 | (defun org-columns-capture-view (&optional maxlevel skip-empty-rows) | ||
| 17636 | "Get the column view of the current buffer or subtree. | ||
| 17637 | The first optional argument MAXLEVEL sets the level limit. A | ||
| 17638 | second optional argument SKIP-EMPTY-ROWS tells whether to skip | ||
| 17639 | empty rows, an empty row being one where all the column view | ||
| 17640 | specifiers except ITEM are empty. This function returns a list | ||
| 17641 | containing the title row and all other rows. Each row is a list | ||
| 17642 | of fields." | ||
| 17643 | (save-excursion | ||
| 17644 | (let* ((title (mapcar 'cadr org-columns-current-fmt-compiled)) | ||
| 17645 | (n (length title)) row tbl) | ||
| 17646 | (goto-char (point-min)) | ||
| 17647 | (while (and (re-search-forward "^\\(\\*+\\) " nil t) | ||
| 17648 | (or (null maxlevel) | ||
| 17649 | (>= maxlevel | ||
| 17650 | (if org-odd-levels-only | ||
| 17651 | (/ (1+ (length (match-string 1))) 2) | ||
| 17652 | (length (match-string 1)))))) | ||
| 17653 | (when (get-char-property (match-beginning 0) 'org-columns-key) | ||
| 17654 | (setq row nil) | ||
| 17655 | (loop for i from 0 to (1- n) do | ||
| 17656 | (push (or (get-char-property (+ (match-beginning 0) i) 'org-columns-value-modified) | ||
| 17657 | (get-char-property (+ (match-beginning 0) i) 'org-columns-value) | ||
| 17658 | "") | ||
| 17659 | row)) | ||
| 17660 | (setq row (nreverse row)) | ||
| 17661 | (unless (and skip-empty-rows | ||
| 17662 | (eq 1 (length (delete "" (delete-dups row))))) | ||
| 17663 | (push row tbl)))) | ||
| 17664 | (append (list title 'hline) (nreverse tbl))))) | ||
| 17665 | |||
| 17666 | (defun org-dblock-write:columnview (params) | ||
| 17667 | "Write the column view table. | ||
| 17668 | PARAMS is a property list of parameters: | ||
| 17669 | |||
| 17670 | :width enforce same column widths with <N> specifiers. | ||
| 17671 | :id the :ID: property of the entry where the columns view | ||
| 17672 | should be built, as a string. When `local', call locally. | ||
| 17673 | When `global' call column view with the cursor at the beginning | ||
| 17674 | of the buffer (usually this means that the whole buffer switches | ||
| 17675 | to column view). | ||
| 17676 | :hlines When t, insert a hline before each item. When a number, insert | ||
| 17677 | a hline before each level <= that number. | ||
| 17678 | :vlines When t, make each column a colgroup to enforce vertical lines. | ||
| 17679 | :maxlevel When set to a number, don't capture headlines below this level. | ||
| 17680 | :skip-empty-rows | ||
| 17681 | When t, skip rows where all specifiers other than ITEM are empty." | ||
| 17682 | (let ((pos (move-marker (make-marker) (point))) | ||
| 17683 | (hlines (plist-get params :hlines)) | ||
| 17684 | (vlines (plist-get params :vlines)) | ||
| 17685 | (maxlevel (plist-get params :maxlevel)) | ||
| 17686 | (skip-empty-rows (plist-get params :skip-empty-rows)) | ||
| 17687 | tbl id idpos nfields tmp) | ||
| 17688 | (save-excursion | ||
| 17689 | (save-restriction | ||
| 17690 | (when (setq id (plist-get params :id)) | ||
| 17691 | (cond ((not id) nil) | ||
| 17692 | ((eq id 'global) (goto-char (point-min))) | ||
| 17693 | ((eq id 'local) nil) | ||
| 17694 | ((setq idpos (org-find-entry-with-id id)) | ||
| 17695 | (goto-char idpos)) | ||
| 17696 | (t (error "Cannot find entry with :ID: %s" id)))) | ||
| 17697 | (org-columns) | ||
| 17698 | (setq tbl (org-columns-capture-view maxlevel skip-empty-rows)) | ||
| 17699 | (setq nfields (length (car tbl))) | ||
| 17700 | (org-columns-quit))) | ||
| 17701 | (goto-char pos) | ||
| 17702 | (move-marker pos nil) | ||
| 17703 | (when tbl | ||
| 17704 | (when (plist-get params :hlines) | ||
| 17705 | (setq tmp nil) | ||
| 17706 | (while tbl | ||
| 17707 | (if (eq (car tbl) 'hline) | ||
| 17708 | (push (pop tbl) tmp) | ||
| 17709 | (if (string-match "\\` *\\(\\*+\\)" (caar tbl)) | ||
| 17710 | (if (and (not (eq (car tmp) 'hline)) | ||
| 17711 | (or (eq hlines t) | ||
| 17712 | (and (numberp hlines) (<= (- (match-end 1) (match-beginning 1)) hlines)))) | ||
| 17713 | (push 'hline tmp))) | ||
| 17714 | (push (pop tbl) tmp))) | ||
| 17715 | (setq tbl (nreverse tmp))) | ||
| 17716 | (when vlines | ||
| 17717 | (setq tbl (mapcar (lambda (x) | ||
| 17718 | (if (eq 'hline x) x (cons "" x))) | ||
| 17719 | tbl)) | ||
| 17720 | (setq tbl (append tbl (list (cons "/" (make-list nfields "<>")))))) | ||
| 17721 | (setq pos (point)) | ||
| 17722 | (insert (org-listtable-to-string tbl)) | ||
| 17723 | (when (plist-get params :width) | ||
| 17724 | (insert "\n|" (mapconcat (lambda (x) (format "<%d>" (max 3 x))) | ||
| 17725 | org-columns-current-widths "|"))) | ||
| 17726 | (goto-char pos) | ||
| 17727 | (org-table-align)))) | ||
| 17728 | |||
| 17729 | (defun org-listtable-to-string (tbl) | ||
| 17730 | "Convert a listtable TBL to a string that contains the Org-mode table. | ||
| 17731 | The table still need to be alligned. The resulting string has no leading | ||
| 17732 | and tailing newline characters." | ||
| 17733 | (mapconcat | ||
| 17734 | (lambda (x) | ||
| 17735 | (cond | ||
| 17736 | ((listp x) | ||
| 17737 | (concat "|" (mapconcat 'identity x "|") "|")) | ||
| 17738 | ((eq x 'hline) "|-|") | ||
| 17739 | (t (error "Garbage in listtable: %s" x)))) | ||
| 17740 | tbl "\n")) | ||
| 17741 | |||
| 17742 | (defun org-insert-columns-dblock () | ||
| 17743 | "Create a dynamic block capturing a column view table." | ||
| 17744 | (interactive) | ||
| 17745 | (let ((defaults '(:name "columnview" :hlines 1)) | ||
| 17746 | (id (completing-read | ||
| 17747 | "Capture columns (local, global, entry with :ID: property) [local]: " | ||
| 17748 | (append '(("global") ("local")) | ||
| 17749 | (mapcar 'list (org-property-values "ID")))))) | ||
| 17750 | (if (equal id "") (setq id 'local)) | ||
| 17751 | (if (equal id "global") (setq id 'global)) | ||
| 17752 | (setq defaults (append defaults (list :id id))) | ||
| 17753 | (org-create-dblock defaults) | ||
| 17754 | (org-update-dblock))) | ||
| 17755 | |||
| 17756 | ;;;; Timestamps | ||
| 17757 | |||
| 17758 | (defvar org-last-changed-timestamp nil) | ||
| 17759 | (defvar org-time-was-given) ; dynamically scoped parameter | ||
| 17760 | (defvar org-end-time-was-given) ; dynamically scoped parameter | ||
| 17761 | (defvar org-ts-what) ; dynamically scoped parameter | ||
| 17762 | |||
| 17763 | (defun org-time-stamp (arg) | ||
| 17764 | "Prompt for a date/time and insert a time stamp. | ||
| 17765 | If the user specifies a time like HH:MM, or if this command is called | ||
| 17766 | with a prefix argument, the time stamp will contain date and time. | ||
| 17767 | Otherwise, only the date will be included. All parts of a date not | ||
| 17768 | specified by the user will be filled in from the current date/time. | ||
| 17769 | So if you press just return without typing anything, the time stamp | ||
| 17770 | will represent the current date/time. If there is already a timestamp | ||
| 17771 | at the cursor, it will be modified." | ||
| 17772 | (interactive "P") | ||
| 17773 | (let* ((ts nil) | ||
| 17774 | (default-time | ||
| 17775 | ;; Default time is either today, or, when entering a range, | ||
| 17776 | ;; the range start. | ||
| 17777 | (if (or (and (org-at-timestamp-p t) (setq ts (match-string 0))) | ||
| 17778 | (save-excursion | ||
| 17779 | (re-search-backward | ||
| 17780 | (concat org-ts-regexp "--?-?\\=") ; 1-3 minuses | ||
| 17781 | (- (point) 20) t))) | ||
| 17782 | (apply 'encode-time (org-parse-time-string (match-string 1))) | ||
| 17783 | (current-time))) | ||
| 17784 | (default-input (and ts (org-get-compact-tod ts))) | ||
| 17785 | org-time-was-given org-end-time-was-given time) | ||
| 17786 | (cond | ||
| 17787 | ((and (org-at-timestamp-p) | ||
| 17788 | (eq last-command 'org-time-stamp) | ||
| 17789 | (eq this-command 'org-time-stamp)) | ||
| 17790 | (insert "--") | ||
| 17791 | (setq time (let ((this-command this-command)) | ||
| 17792 | (org-read-date arg 'totime nil nil default-time default-input))) | ||
| 17793 | (org-insert-time-stamp time (or org-time-was-given arg))) | ||
| 17794 | ((org-at-timestamp-p) | ||
| 17795 | (setq time (let ((this-command this-command)) | ||
| 17796 | (org-read-date arg 'totime nil nil default-time default-input))) | ||
| 17797 | (when (org-at-timestamp-p) ; just to get the match data | ||
| 17798 | (replace-match "") | ||
| 17799 | (setq org-last-changed-timestamp | ||
| 17800 | (org-insert-time-stamp | ||
| 17801 | time (or org-time-was-given arg) | ||
| 17802 | nil nil nil (list org-end-time-was-given)))) | ||
| 17803 | (message "Timestamp updated")) | ||
| 17804 | (t | ||
| 17805 | (setq time (let ((this-command this-command)) | ||
| 17806 | (org-read-date arg 'totime nil nil default-time default-input))) | ||
| 17807 | (org-insert-time-stamp time (or org-time-was-given arg) | ||
| 17808 | nil nil nil (list org-end-time-was-given)))))) | ||
| 17809 | |||
| 17810 | ;; FIXME: can we use this for something else???? | ||
| 17811 | ;; like computing time differences????? | ||
| 17812 | (defun org-get-compact-tod (s) | ||
| 17813 | (when (string-match "\\(\\([012]?[0-9]\\):\\([0-5][0-9]\\)\\)\\(-\\(\\([012]?[0-9]\\):\\([0-5][0-9]\\)\\)\\)?" s) | ||
| 17814 | (let* ((t1 (match-string 1 s)) | ||
| 17815 | (h1 (string-to-number (match-string 2 s))) | ||
| 17816 | (m1 (string-to-number (match-string 3 s))) | ||
| 17817 | (t2 (and (match-end 4) (match-string 5 s))) | ||
| 17818 | (h2 (and t2 (string-to-number (match-string 6 s)))) | ||
| 17819 | (m2 (and t2 (string-to-number (match-string 7 s)))) | ||
| 17820 | dh dm) | ||
| 17821 | (if (not t2) | ||
| 17822 | t1 | ||
| 17823 | (setq dh (- h2 h1) dm (- m2 m1)) | ||
| 17824 | (if (< dm 0) (setq dm (+ dm 60) dh (1- dh))) | ||
| 17825 | (concat t1 "+" (number-to-string dh) | ||
| 17826 | (if (/= 0 dm) (concat ":" (number-to-string dm)))))))) | ||
| 17827 | |||
| 17828 | (defun org-time-stamp-inactive (&optional arg) | ||
| 17829 | "Insert an inactive time stamp. | ||
| 17830 | An inactive time stamp is enclosed in square brackets instead of angle | ||
| 17831 | brackets. It is inactive in the sense that it does not trigger agenda entries, | ||
| 17832 | does not link to the calendar and cannot be changed with the S-cursor keys. | ||
| 17833 | So these are more for recording a certain time/date." | ||
| 17834 | (interactive "P") | ||
| 17835 | (let (org-time-was-given org-end-time-was-given time) | ||
| 17836 | (setq time (org-read-date arg 'totime)) | ||
| 17837 | (org-insert-time-stamp time (or org-time-was-given arg) 'inactive | ||
| 17838 | nil nil (list org-end-time-was-given)))) | ||
| 17839 | |||
| 17840 | (defvar org-date-ovl (org-make-overlay 1 1)) | ||
| 17841 | (org-overlay-put org-date-ovl 'face 'org-warning) | ||
| 17842 | (org-detach-overlay org-date-ovl) | ||
| 17843 | |||
| 17844 | (defvar org-ans1) ; dynamically scoped parameter | ||
| 17845 | (defvar org-ans2) ; dynamically scoped parameter | ||
| 17846 | |||
| 17847 | (defvar org-plain-time-of-day-regexp) ; defined below | ||
| 17848 | |||
| 17849 | (defvar org-read-date-overlay nil) | ||
| 17850 | (defvar org-dcst nil) ; dynamically scoped | ||
| 17851 | |||
| 17852 | (defun org-read-date (&optional with-time to-time from-string prompt | ||
| 17853 | default-time default-input) | ||
| 17854 | "Read a date, possibly a time, and make things smooth for the user. | ||
| 17855 | The prompt will suggest to enter an ISO date, but you can also enter anything | ||
| 17856 | which will at least partially be understood by `parse-time-string'. | ||
| 17857 | Unrecognized parts of the date will default to the current day, month, year, | ||
| 17858 | hour and minute. If this command is called to replace a timestamp at point, | ||
| 17859 | of to enter the second timestamp of a range, the default time is taken from the | ||
| 17860 | existing stamp. For example, | ||
| 17861 | 3-2-5 --> 2003-02-05 | ||
| 17862 | feb 15 --> currentyear-02-15 | ||
| 17863 | sep 12 9 --> 2009-09-12 | ||
| 17864 | 12:45 --> today 12:45 | ||
| 17865 | 22 sept 0:34 --> currentyear-09-22 0:34 | ||
| 17866 | 12 --> currentyear-currentmonth-12 | ||
| 17867 | Fri --> nearest Friday (today or later) | ||
| 17868 | etc. | ||
| 17869 | |||
| 17870 | Furthermore you can specify a relative date by giving, as the *first* thing | ||
| 17871 | in the input: a plus/minus sign, a number and a letter [dwmy] to indicate | ||
| 17872 | change in days weeks, months, years. | ||
| 17873 | With a single plus or minus, the date is relative to today. With a double | ||
| 17874 | plus or minus, it is relative to the date in DEFAULT-TIME. E.g. | ||
| 17875 | +4d --> four days from today | ||
| 17876 | +4 --> same as above | ||
| 17877 | +2w --> two weeks from today | ||
| 17878 | ++5 --> five days from default date | ||
| 17879 | |||
| 17880 | The function understands only English month and weekday abbreviations, | ||
| 17881 | but this can be configured with the variables `parse-time-months' and | ||
| 17882 | `parse-time-weekdays'. | ||
| 17883 | |||
| 17884 | While prompting, a calendar is popped up - you can also select the | ||
| 17885 | date with the mouse (button 1). The calendar shows a period of three | ||
| 17886 | months. To scroll it to other months, use the keys `>' and `<'. | ||
| 17887 | If you don't like the calendar, turn it off with | ||
| 17888 | \(setq org-read-date-popup-calendar nil) | ||
| 17889 | |||
| 17890 | With optional argument TO-TIME, the date will immediately be converted | ||
| 17891 | to an internal time. | ||
| 17892 | With an optional argument WITH-TIME, the prompt will suggest to also | ||
| 17893 | insert a time. Note that when WITH-TIME is not set, you can still | ||
| 17894 | enter a time, and this function will inform the calling routine about | ||
| 17895 | this change. The calling routine may then choose to change the format | ||
| 17896 | used to insert the time stamp into the buffer to include the time. | ||
| 17897 | With optional argument FROM-STRING, read from this string instead from | ||
| 17898 | the user. PROMPT can overwrite the default prompt. DEFAULT-TIME is | ||
| 17899 | the time/date that is used for everything that is not specified by the | ||
| 17900 | user." | ||
| 17901 | (require 'parse-time) | ||
| 17902 | (let* ((org-time-stamp-rounding-minutes | ||
| 17903 | (if (equal with-time '(16)) '(0 0) org-time-stamp-rounding-minutes)) | ||
| 17904 | (org-dcst org-display-custom-times) | ||
| 17905 | (ct (org-current-time)) | ||
| 17906 | (def (or default-time ct)) | ||
| 17907 | (defdecode (decode-time def)) | ||
| 17908 | (dummy (progn | ||
| 17909 | (when (< (nth 2 defdecode) org-extend-today-until) | ||
| 17910 | (setcar (nthcdr 2 defdecode) -1) | ||
| 17911 | (setcar (nthcdr 1 defdecode) 59) | ||
| 17912 | (setq def (apply 'encode-time defdecode) | ||
| 17913 | defdecode (decode-time def))))) | ||
| 17914 | (calendar-move-hook nil) | ||
| 17915 | (view-diary-entries-initially nil) | ||
| 17916 | (view-calendar-holidays-initially nil) | ||
| 17917 | (timestr (format-time-string | ||
| 17918 | (if with-time "%Y-%m-%d %H:%M" "%Y-%m-%d") def)) | ||
| 17919 | (prompt (concat (if prompt (concat prompt " ") "") | ||
| 17920 | (format "Date+time [%s]: " timestr))) | ||
| 17921 | ans (org-ans0 "") org-ans1 org-ans2 final) | ||
| 17922 | |||
| 17923 | (cond | ||
| 17924 | (from-string (setq ans from-string)) | ||
| 17925 | (org-read-date-popup-calendar | ||
| 17926 | (save-excursion | ||
| 17927 | (save-window-excursion | ||
| 17928 | (calendar) | ||
| 17929 | (calendar-forward-day (- (time-to-days def) | ||
| 17930 | (calendar-absolute-from-gregorian | ||
| 17931 | (calendar-current-date)))) | ||
| 17932 | (org-eval-in-calendar nil t) | ||
| 17933 | (let* ((old-map (current-local-map)) | ||
| 17934 | (map (copy-keymap calendar-mode-map)) | ||
| 17935 | (minibuffer-local-map (copy-keymap minibuffer-local-map))) | ||
| 17936 | (org-defkey map (kbd "RET") 'org-calendar-select) | ||
| 17937 | (org-defkey map (if (featurep 'xemacs) [button1] [mouse-1]) | ||
| 17938 | 'org-calendar-select-mouse) | ||
| 17939 | (org-defkey map (if (featurep 'xemacs) [button2] [mouse-2]) | ||
| 17940 | 'org-calendar-select-mouse) | ||
| 17941 | (org-defkey minibuffer-local-map [(meta shift left)] | ||
| 17942 | (lambda () (interactive) | ||
| 17943 | (org-eval-in-calendar '(calendar-backward-month 1)))) | ||
| 17944 | (org-defkey minibuffer-local-map [(meta shift right)] | ||
| 17945 | (lambda () (interactive) | ||
| 17946 | (org-eval-in-calendar '(calendar-forward-month 1)))) | ||
| 17947 | (org-defkey minibuffer-local-map [(meta shift up)] | ||
| 17948 | (lambda () (interactive) | ||
| 17949 | (org-eval-in-calendar '(calendar-backward-year 1)))) | ||
| 17950 | (org-defkey minibuffer-local-map [(meta shift down)] | ||
| 17951 | (lambda () (interactive) | ||
| 17952 | (org-eval-in-calendar '(calendar-forward-year 1)))) | ||
| 17953 | (org-defkey minibuffer-local-map [(shift up)] | ||
| 17954 | (lambda () (interactive) | ||
| 17955 | (org-eval-in-calendar '(calendar-backward-week 1)))) | ||
| 17956 | (org-defkey minibuffer-local-map [(shift down)] | ||
| 17957 | (lambda () (interactive) | ||
| 17958 | (org-eval-in-calendar '(calendar-forward-week 1)))) | ||
| 17959 | (org-defkey minibuffer-local-map [(shift left)] | ||
| 17960 | (lambda () (interactive) | ||
| 17961 | (org-eval-in-calendar '(calendar-backward-day 1)))) | ||
| 17962 | (org-defkey minibuffer-local-map [(shift right)] | ||
| 17963 | (lambda () (interactive) | ||
| 17964 | (org-eval-in-calendar '(calendar-forward-day 1)))) | ||
| 17965 | (org-defkey minibuffer-local-map ">" | ||
| 17966 | (lambda () (interactive) | ||
| 17967 | (org-eval-in-calendar '(scroll-calendar-left 1)))) | ||
| 17968 | (org-defkey minibuffer-local-map "<" | ||
| 17969 | (lambda () (interactive) | ||
| 17970 | (org-eval-in-calendar '(scroll-calendar-right 1)))) | ||
| 17971 | (unwind-protect | ||
| 17972 | (progn | ||
| 17973 | (use-local-map map) | ||
| 17974 | (add-hook 'post-command-hook 'org-read-date-display) | ||
| 17975 | (setq org-ans0 (read-string prompt default-input nil nil)) | ||
| 17976 | ;; org-ans0: from prompt | ||
| 17977 | ;; org-ans1: from mouse click | ||
| 17978 | ;; org-ans2: from calendar motion | ||
| 17979 | (setq ans (concat org-ans0 " " (or org-ans1 org-ans2)))) | ||
| 17980 | (remove-hook 'post-command-hook 'org-read-date-display) | ||
| 17981 | (use-local-map old-map) | ||
| 17982 | (when org-read-date-overlay | ||
| 17983 | (org-delete-overlay org-read-date-overlay) | ||
| 17984 | (setq org-read-date-overlay nil))))))) | ||
| 17985 | |||
| 17986 | (t ; Naked prompt only | ||
| 17987 | (unwind-protect | ||
| 17988 | (setq ans (read-string prompt default-input nil timestr)) | ||
| 17989 | (when org-read-date-overlay | ||
| 17990 | (org-delete-overlay org-read-date-overlay) | ||
| 17991 | (setq org-read-date-overlay nil))))) | ||
| 17992 | |||
| 17993 | (setq final (org-read-date-analyze ans def defdecode)) | ||
| 17994 | |||
| 17995 | (if to-time | ||
| 17996 | (apply 'encode-time final) | ||
| 17997 | (if (and (boundp 'org-time-was-given) org-time-was-given) | ||
| 17998 | (format "%04d-%02d-%02d %02d:%02d" | ||
| 17999 | (nth 5 final) (nth 4 final) (nth 3 final) | ||
| 18000 | (nth 2 final) (nth 1 final)) | ||
| 18001 | (format "%04d-%02d-%02d" (nth 5 final) (nth 4 final) (nth 3 final)))))) | ||
| 18002 | (defvar def) | ||
| 18003 | (defvar defdecode) | ||
| 18004 | (defvar with-time) | ||
| 18005 | (defun org-read-date-display () | ||
| 18006 | "Display the currrent date prompt interpretation in the minibuffer." | ||
| 18007 | (when org-read-date-display-live | ||
| 18008 | (when org-read-date-overlay | ||
| 18009 | (org-delete-overlay org-read-date-overlay)) | ||
| 18010 | (let ((p (point))) | ||
| 18011 | (end-of-line 1) | ||
| 18012 | (while (not (equal (buffer-substring | ||
| 18013 | (max (point-min) (- (point) 4)) (point)) | ||
| 18014 | " ")) | ||
| 18015 | (insert " ")) | ||
| 18016 | (goto-char p)) | ||
| 18017 | (let* ((ans (concat (buffer-substring (point-at-bol) (point-max)) | ||
| 18018 | " " (or org-ans1 org-ans2))) | ||
| 18019 | (org-end-time-was-given nil) | ||
| 18020 | (f (org-read-date-analyze ans def defdecode)) | ||
| 18021 | (fmts (if org-dcst | ||
| 18022 | org-time-stamp-custom-formats | ||
| 18023 | org-time-stamp-formats)) | ||
| 18024 | (fmt (if (or with-time | ||
| 18025 | (and (boundp 'org-time-was-given) org-time-was-given)) | ||
| 18026 | (cdr fmts) | ||
| 18027 | (car fmts))) | ||
| 18028 | (txt (concat "=> " (format-time-string fmt (apply 'encode-time f))))) | ||
| 18029 | (when (and org-end-time-was-given | ||
| 18030 | (string-match org-plain-time-of-day-regexp txt)) | ||
| 18031 | (setq txt (concat (substring txt 0 (match-end 0)) "-" | ||
| 18032 | org-end-time-was-given | ||
| 18033 | (substring txt (match-end 0))))) | ||
| 18034 | (setq org-read-date-overlay | ||
| 18035 | (make-overlay (1- (point-at-eol)) (point-at-eol))) | ||
| 18036 | (org-overlay-display org-read-date-overlay txt 'secondary-selection)))) | ||
| 18037 | |||
| 18038 | (defun org-read-date-analyze (ans def defdecode) | ||
| 18039 | "Analyze the combined answer of the date prompt." | ||
| 18040 | ;; FIXME: cleanup and comment | ||
| 18041 | (let (delta deltan deltaw deltadef year month day | ||
| 18042 | hour minute second wday pm h2 m2 tl wday1) | ||
| 18043 | |||
| 18044 | (when (setq delta (org-read-date-get-relative ans (current-time) def)) | ||
| 18045 | (setq ans (replace-match "" t t ans) | ||
| 18046 | deltan (car delta) | ||
| 18047 | deltaw (nth 1 delta) | ||
| 18048 | deltadef (nth 2 delta))) | ||
| 18049 | |||
| 18050 | ;; Help matching ISO dates with single digit month ot day, like 2006-8-11. | ||
| 18051 | (when (string-match | ||
| 18052 | "^ *\\(\\([0-9]+\\)-\\)?\\([0-1]?[0-9]\\)-\\([0-3]?[0-9]\\)\\([^-0-9]\\|$\\)" ans) | ||
| 18053 | (setq year (if (match-end 2) | ||
| 18054 | (string-to-number (match-string 2 ans)) | ||
| 18055 | (string-to-number (format-time-string "%Y"))) | ||
| 18056 | month (string-to-number (match-string 3 ans)) | ||
| 18057 | day (string-to-number (match-string 4 ans))) | ||
| 18058 | (if (< year 100) (setq year (+ 2000 year))) | ||
| 18059 | (setq ans (replace-match (format "%04d-%02d-%02d\\5" year month day) | ||
| 18060 | t nil ans))) | ||
| 18061 | ;; Help matching am/pm times, because `parse-time-string' does not do that. | ||
| 18062 | ;; If there is a time with am/pm, and *no* time without it, we convert | ||
| 18063 | ;; so that matching will be successful. | ||
| 18064 | (loop for i from 1 to 2 do ; twice, for end time as well | ||
| 18065 | (when (and (not (string-match "\\(\\`\\|[^+]\\)[012]?[0-9]:[0-9][0-9]\\([ \t\n]\\|$\\)" ans)) | ||
| 18066 | (string-match "\\([012]?[0-9]\\)\\(:\\([0-5][0-9]\\)\\)?\\(am\\|AM\\|pm\\|PM\\)\\>" ans)) | ||
| 18067 | (setq hour (string-to-number (match-string 1 ans)) | ||
| 18068 | minute (if (match-end 3) | ||
| 18069 | (string-to-number (match-string 3 ans)) | ||
| 18070 | 0) | ||
| 18071 | pm (equal ?p | ||
| 18072 | (string-to-char (downcase (match-string 4 ans))))) | ||
| 18073 | (if (and (= hour 12) (not pm)) | ||
| 18074 | (setq hour 0) | ||
| 18075 | (if (and pm (< hour 12)) (setq hour (+ 12 hour)))) | ||
| 18076 | (setq ans (replace-match (format "%02d:%02d" hour minute) | ||
| 18077 | t t ans)))) | ||
| 18078 | |||
| 18079 | ;; Check if a time range is given as a duration | ||
| 18080 | (when (string-match "\\([012]?[0-9]\\):\\([0-6][0-9]\\)\\+\\([012]?[0-9]\\)\\(:\\([0-5][0-9]\\)\\)?" ans) | ||
| 18081 | (setq hour (string-to-number (match-string 1 ans)) | ||
| 18082 | h2 (+ hour (string-to-number (match-string 3 ans))) | ||
| 18083 | minute (string-to-number (match-string 2 ans)) | ||
| 18084 | m2 (+ minute (if (match-end 5) (string-to-number (match-string 5 ans))0))) | ||
| 18085 | (if (>= m2 60) (setq h2 (1+ h2) m2 (- m2 60))) | ||
| 18086 | (setq ans (replace-match (format "%02d:%02d-%02d:%02d" hour minute h2 m2) t t ans))) | ||
| 18087 | |||
| 18088 | ;; Check if there is a time range | ||
| 18089 | (when (boundp 'org-end-time-was-given) | ||
| 18090 | (setq org-time-was-given nil) | ||
| 18091 | (when (and (string-match org-plain-time-of-day-regexp ans) | ||
| 18092 | (match-end 8)) | ||
| 18093 | (setq org-end-time-was-given (match-string 8 ans)) | ||
| 18094 | (setq ans (concat (substring ans 0 (match-beginning 7)) | ||
| 18095 | (substring ans (match-end 7)))))) | ||
| 18096 | |||
| 18097 | (setq tl (parse-time-string ans) | ||
| 18098 | day (or (nth 3 tl) (nth 3 defdecode)) | ||
| 18099 | month (or (nth 4 tl) | ||
| 18100 | (if (and org-read-date-prefer-future | ||
| 18101 | (nth 3 tl) (< (nth 3 tl) (nth 3 defdecode))) | ||
| 18102 | (1+ (nth 4 defdecode)) | ||
| 18103 | (nth 4 defdecode))) | ||
| 18104 | year (or (nth 5 tl) | ||
| 18105 | (if (and org-read-date-prefer-future | ||
| 18106 | (nth 4 tl) (< (nth 4 tl) (nth 4 defdecode))) | ||
| 18107 | (1+ (nth 5 defdecode)) | ||
| 18108 | (nth 5 defdecode))) | ||
| 18109 | hour (or (nth 2 tl) (nth 2 defdecode)) | ||
| 18110 | minute (or (nth 1 tl) (nth 1 defdecode)) | ||
| 18111 | second (or (nth 0 tl) 0) | ||
| 18112 | wday (nth 6 tl)) | ||
| 18113 | (when deltan | ||
| 18114 | (unless deltadef | ||
| 18115 | (let ((now (decode-time (current-time)))) | ||
| 18116 | (setq day (nth 3 now) month (nth 4 now) year (nth 5 now)))) | ||
| 18117 | (cond ((member deltaw '("d" "")) (setq day (+ day deltan))) | ||
| 18118 | ((equal deltaw "w") (setq day (+ day (* 7 deltan)))) | ||
| 18119 | ((equal deltaw "m") (setq month (+ month deltan))) | ||
| 18120 | ((equal deltaw "y") (setq year (+ year deltan))))) | ||
| 18121 | (when (and wday (not (nth 3 tl))) | ||
| 18122 | ;; Weekday was given, but no day, so pick that day in the week | ||
| 18123 | ;; on or after the derived date. | ||
| 18124 | (setq wday1 (nth 6 (decode-time (encode-time 0 0 0 day month year)))) | ||
| 18125 | (unless (equal wday wday1) | ||
| 18126 | (setq day (+ day (% (- wday wday1 -7) 7))))) | ||
| 18127 | (if (and (boundp 'org-time-was-given) | ||
| 18128 | (nth 2 tl)) | ||
| 18129 | (setq org-time-was-given t)) | ||
| 18130 | (if (< year 100) (setq year (+ 2000 year))) | ||
| 18131 | (if (< year 1970) (setq year (nth 5 defdecode))) ; not representable | ||
| 18132 | (list second minute hour day month year))) | ||
| 18133 | |||
| 18134 | (defvar parse-time-weekdays) | ||
| 18135 | |||
| 18136 | (defun org-read-date-get-relative (s today default) | ||
| 18137 | "Check string S for special relative date string. | ||
| 18138 | TODAY and DEFAULT are internal times, for today and for a default. | ||
| 18139 | Return shift list (N what def-flag) | ||
| 18140 | WHAT is \"d\", \"w\", \"m\", or \"y\" for day, week, month, year. | ||
| 18141 | N is the number of WHATs to shift. | ||
| 18142 | DEF-FLAG is t when a double ++ or -- indicates shift relative to | ||
| 18143 | the DEFAULT date rather than TODAY." | ||
| 18144 | (when (string-match | ||
| 18145 | (concat | ||
| 18146 | "\\`[ \t]*\\([-+]\\{1,2\\}\\)" | ||
| 18147 | "\\([0-9]+\\)?" | ||
| 18148 | "\\([dwmy]\\|\\(" (mapconcat 'car parse-time-weekdays "\\|") "\\)\\)?" | ||
| 18149 | "\\([ \t]\\|$\\)") s) | ||
| 18150 | (let* ((dir (if (match-end 1) | ||
| 18151 | (string-to-char (substring (match-string 1 s) -1)) | ||
| 18152 | ?+)) | ||
| 18153 | (rel (and (match-end 1) (= 2 (- (match-end 1) (match-beginning 1))))) | ||
| 18154 | (n (if (match-end 2) (string-to-number (match-string 2 s)) 1)) | ||
| 18155 | (what (if (match-end 3) (match-string 3 s) "d")) | ||
| 18156 | (wday1 (cdr (assoc (downcase what) parse-time-weekdays))) | ||
| 18157 | (date (if rel default today)) | ||
| 18158 | (wday (nth 6 (decode-time date))) | ||
| 18159 | delta) | ||
| 18160 | (if wday1 | ||
| 18161 | (progn | ||
| 18162 | (setq delta (mod (+ 7 (- wday1 wday)) 7)) | ||
| 18163 | (if (= dir ?-) (setq delta (- delta 7))) | ||
| 18164 | (if (> n 1) (setq delta (+ delta (* (1- n) (if (= dir ?-) -7 7))))) | ||
| 18165 | (list delta "d" rel)) | ||
| 18166 | (list (* n (if (= dir ?-) -1 1)) what rel))))) | ||
| 18167 | |||
| 18168 | (defun org-eval-in-calendar (form &optional keepdate) | ||
| 18169 | "Eval FORM in the calendar window and return to current window. | ||
| 18170 | Also, store the cursor date in variable org-ans2." | ||
| 18171 | (let ((sw (selected-window))) | ||
| 18172 | (select-window (get-buffer-window "*Calendar*")) | ||
| 18173 | (eval form) | ||
| 18174 | (when (and (not keepdate) (calendar-cursor-to-date)) | ||
| 18175 | (let* ((date (calendar-cursor-to-date)) | ||
| 18176 | (time (encode-time 0 0 0 (nth 1 date) (nth 0 date) (nth 2 date)))) | ||
| 18177 | (setq org-ans2 (format-time-string "%Y-%m-%d" time)))) | ||
| 18178 | (org-move-overlay org-date-ovl (1- (point)) (1+ (point)) (current-buffer)) | ||
| 18179 | (select-window sw))) | ||
| 18180 | |||
| 18181 | ; ;; Update the prompt to show new default date | ||
| 18182 | ; (save-excursion | ||
| 18183 | ; (goto-char (point-min)) | ||
| 18184 | ; (when (and org-ans2 | ||
| 18185 | ; (re-search-forward "\\[[-0-9]+\\]" nil t) | ||
| 18186 | ; (get-text-property (match-end 0) 'field)) | ||
| 18187 | ; (let ((inhibit-read-only t)) | ||
| 18188 | ; (replace-match (concat "[" org-ans2 "]") t t) | ||
| 18189 | ; (add-text-properties (point-min) (1+ (match-end 0)) | ||
| 18190 | ; (text-properties-at (1+ (point-min))))))))) | ||
| 18191 | |||
| 18192 | (defun org-calendar-select () | ||
| 18193 | "Return to `org-read-date' with the date currently selected. | ||
| 18194 | This is used by `org-read-date' in a temporary keymap for the calendar buffer." | ||
| 18195 | (interactive) | ||
| 18196 | (when (calendar-cursor-to-date) | ||
| 18197 | (let* ((date (calendar-cursor-to-date)) | ||
| 18198 | (time (encode-time 0 0 0 (nth 1 date) (nth 0 date) (nth 2 date)))) | ||
| 18199 | (setq org-ans1 (format-time-string "%Y-%m-%d" time))) | ||
| 18200 | (if (active-minibuffer-window) (exit-minibuffer)))) | ||
| 18201 | |||
| 18202 | (defun org-insert-time-stamp (time &optional with-hm inactive pre post extra) | ||
| 18203 | "Insert a date stamp for the date given by the internal TIME. | ||
| 18204 | WITH-HM means, use the stamp format that includes the time of the day. | ||
| 18205 | INACTIVE means use square brackets instead of angular ones, so that the | ||
| 18206 | stamp will not contribute to the agenda. | ||
| 18207 | PRE and POST are optional strings to be inserted before and after the | ||
| 18208 | stamp. | ||
| 18209 | The command returns the inserted time stamp." | ||
| 18210 | (let ((fmt (funcall (if with-hm 'cdr 'car) org-time-stamp-formats)) | ||
| 18211 | stamp) | ||
| 18212 | (if inactive (setq fmt (concat "[" (substring fmt 1 -1) "]"))) | ||
| 18213 | (insert-before-markers (or pre "")) | ||
| 18214 | (insert-before-markers (setq stamp (format-time-string fmt time))) | ||
| 18215 | (when (listp extra) | ||
| 18216 | (setq extra (car extra)) | ||
| 18217 | (if (and (stringp extra) | ||
| 18218 | (string-match "\\([0-9]+\\):\\([0-9]+\\)" extra)) | ||
| 18219 | (setq extra (format "-%02d:%02d" | ||
| 18220 | (string-to-number (match-string 1 extra)) | ||
| 18221 | (string-to-number (match-string 2 extra)))) | ||
| 18222 | (setq extra nil))) | ||
| 18223 | (when extra | ||
| 18224 | (backward-char 1) | ||
| 18225 | (insert-before-markers extra) | ||
| 18226 | (forward-char 1)) | ||
| 18227 | (insert-before-markers (or post "")) | ||
| 18228 | stamp)) | ||
| 18229 | |||
| 18230 | (defun org-toggle-time-stamp-overlays () | ||
| 18231 | "Toggle the use of custom time stamp formats." | ||
| 18232 | (interactive) | ||
| 18233 | (setq org-display-custom-times (not org-display-custom-times)) | ||
| 18234 | (unless org-display-custom-times | ||
| 18235 | (let ((p (point-min)) (bmp (buffer-modified-p))) | ||
| 18236 | (while (setq p (next-single-property-change p 'display)) | ||
| 18237 | (if (and (get-text-property p 'display) | ||
| 18238 | (eq (get-text-property p 'face) 'org-date)) | ||
| 18239 | (remove-text-properties | ||
| 18240 | p (setq p (next-single-property-change p 'display)) | ||
| 18241 | '(display t)))) | ||
| 18242 | (set-buffer-modified-p bmp))) | ||
| 18243 | (if (featurep 'xemacs) | ||
| 18244 | (remove-text-properties (point-min) (point-max) '(end-glyph t))) | ||
| 18245 | (org-restart-font-lock) | ||
| 18246 | (setq org-table-may-need-update t) | ||
| 18247 | (if org-display-custom-times | ||
| 18248 | (message "Time stamps are overlayed with custom format") | ||
| 18249 | (message "Time stamp overlays removed"))) | ||
| 18250 | |||
| 18251 | (defun org-display-custom-time (beg end) | ||
| 18252 | "Overlay modified time stamp format over timestamp between BED and END." | ||
| 18253 | (let* ((ts (buffer-substring beg end)) | ||
| 18254 | t1 w1 with-hm tf time str w2 (off 0)) | ||
| 18255 | (save-match-data | ||
| 18256 | (setq t1 (org-parse-time-string ts t)) | ||
| 18257 | (if (string-match "\\(-[0-9]+:[0-9]+\\)?\\( [.+]?\\+[0-9]+[dwmy]\\)?\\'" ts) | ||
| 18258 | (setq off (- (match-end 0) (match-beginning 0))))) | ||
| 18259 | (setq end (- end off)) | ||
| 18260 | (setq w1 (- end beg) | ||
| 18261 | with-hm (and (nth 1 t1) (nth 2 t1)) | ||
| 18262 | tf (funcall (if with-hm 'cdr 'car) org-time-stamp-custom-formats) | ||
| 18263 | time (org-fix-decoded-time t1) | ||
| 18264 | str (org-add-props | ||
| 18265 | (format-time-string | ||
| 18266 | (substring tf 1 -1) (apply 'encode-time time)) | ||
| 18267 | nil 'mouse-face 'highlight) | ||
| 18268 | w2 (length str)) | ||
| 18269 | (if (not (= w2 w1)) | ||
| 18270 | (add-text-properties (1+ beg) (+ 2 beg) | ||
| 18271 | (list 'org-dwidth t 'org-dwidth-n (- w1 w2)))) | ||
| 18272 | (if (featurep 'xemacs) | ||
| 18273 | (progn | ||
| 18274 | (put-text-property beg end 'invisible t) | ||
| 18275 | (put-text-property beg end 'end-glyph (make-glyph str))) | ||
| 18276 | (put-text-property beg end 'display str)))) | ||
| 18277 | |||
| 18278 | (defun org-translate-time (string) | ||
| 18279 | "Translate all timestamps in STRING to custom format. | ||
| 18280 | But do this only if the variable `org-display-custom-times' is set." | ||
| 18281 | (when org-display-custom-times | ||
| 18282 | (save-match-data | ||
| 18283 | (let* ((start 0) | ||
| 18284 | (re org-ts-regexp-both) | ||
| 18285 | t1 with-hm inactive tf time str beg end) | ||
| 18286 | (while (setq start (string-match re string start)) | ||
| 18287 | (setq beg (match-beginning 0) | ||
| 18288 | end (match-end 0) | ||
| 18289 | t1 (save-match-data | ||
| 18290 | (org-parse-time-string (substring string beg end) t)) | ||
| 18291 | with-hm (and (nth 1 t1) (nth 2 t1)) | ||
| 18292 | inactive (equal (substring string beg (1+ beg)) "[") | ||
| 18293 | tf (funcall (if with-hm 'cdr 'car) | ||
| 18294 | org-time-stamp-custom-formats) | ||
| 18295 | time (org-fix-decoded-time t1) | ||
| 18296 | str (format-time-string | ||
| 18297 | (concat | ||
| 18298 | (if inactive "[" "<") (substring tf 1 -1) | ||
| 18299 | (if inactive "]" ">")) | ||
| 18300 | (apply 'encode-time time)) | ||
| 18301 | string (replace-match str t t string) | ||
| 18302 | start (+ start (length str))))))) | ||
| 18303 | string) | ||
| 18304 | |||
| 18305 | (defun org-fix-decoded-time (time) | ||
| 18306 | "Set 0 instead of nil for the first 6 elements of time. | ||
| 18307 | Don't touch the rest." | ||
| 18308 | (let ((n 0)) | ||
| 18309 | (mapcar (lambda (x) (if (< (setq n (1+ n)) 7) (or x 0) x)) time))) | ||
| 18310 | |||
| 18311 | (defun org-days-to-time (timestamp-string) | ||
| 18312 | "Difference between TIMESTAMP-STRING and now in days." | ||
| 18313 | (- (time-to-days (org-time-string-to-time timestamp-string)) | ||
| 18314 | (time-to-days (current-time)))) | ||
| 18315 | |||
| 18316 | (defun org-deadline-close (timestamp-string &optional ndays) | ||
| 18317 | "Is the time in TIMESTAMP-STRING close to the current date?" | ||
| 18318 | (setq ndays (or ndays (org-get-wdays timestamp-string))) | ||
| 18319 | (and (< (org-days-to-time timestamp-string) ndays) | ||
| 18320 | (not (org-entry-is-done-p)))) | ||
| 18321 | |||
| 18322 | (defun org-get-wdays (ts) | ||
| 18323 | "Get the deadline lead time appropriate for timestring TS." | ||
| 18324 | (cond | ||
| 18325 | ((<= org-deadline-warning-days 0) | ||
| 18326 | ;; 0 or negative, enforce this value no matter what | ||
| 18327 | (- org-deadline-warning-days)) | ||
| 18328 | ((string-match "-\\([0-9]+\\)\\([dwmy]\\)\\(\\'\\|>\\)" ts) | ||
| 18329 | ;; lead time is specified. | ||
| 18330 | (floor (* (string-to-number (match-string 1 ts)) | ||
| 18331 | (cdr (assoc (match-string 2 ts) | ||
| 18332 | '(("d" . 1) ("w" . 7) | ||
| 18333 | ("m" . 30.4) ("y" . 365.25))))))) | ||
| 18334 | ;; go for the default. | ||
| 18335 | (t org-deadline-warning-days))) | ||
| 18336 | |||
| 18337 | (defun org-calendar-select-mouse (ev) | ||
| 18338 | "Return to `org-read-date' with the date currently selected. | ||
| 18339 | This is used by `org-read-date' in a temporary keymap for the calendar buffer." | ||
| 18340 | (interactive "e") | ||
| 18341 | (mouse-set-point ev) | ||
| 18342 | (when (calendar-cursor-to-date) | ||
| 18343 | (let* ((date (calendar-cursor-to-date)) | ||
| 18344 | (time (encode-time 0 0 0 (nth 1 date) (nth 0 date) (nth 2 date)))) | ||
| 18345 | (setq org-ans1 (format-time-string "%Y-%m-%d" time))) | ||
| 18346 | (if (active-minibuffer-window) (exit-minibuffer)))) | ||
| 18347 | |||
| 18348 | (defun org-check-deadlines (ndays) | ||
| 18349 | "Check if there are any deadlines due or past due. | ||
| 18350 | A deadline is considered due if it happens within `org-deadline-warning-days' | ||
| 18351 | days from today's date. If the deadline appears in an entry marked DONE, | ||
| 18352 | it is not shown. The prefix arg NDAYS can be used to test that many | ||
| 18353 | days. If the prefix is a raw \\[universal-argument] prefix, all deadlines are shown." | ||
| 18354 | (interactive "P") | ||
| 18355 | (let* ((org-warn-days | ||
| 18356 | (cond | ||
| 18357 | ((equal ndays '(4)) 100000) | ||
| 18358 | (ndays (prefix-numeric-value ndays)) | ||
| 18359 | (t (abs org-deadline-warning-days)))) | ||
| 18360 | (case-fold-search nil) | ||
| 18361 | (regexp (concat "\\<" org-deadline-string " *<\\([^>]+\\)>")) | ||
| 18362 | (callback | ||
| 18363 | (lambda () (org-deadline-close (match-string 1) org-warn-days)))) | ||
| 18364 | |||
| 18365 | (message "%d deadlines past-due or due within %d days" | ||
| 18366 | (org-occur regexp nil callback) | ||
| 18367 | org-warn-days))) | ||
| 18368 | |||
| 18369 | (defun org-check-before-date (date) | ||
| 18370 | "Check if there are deadlines or scheduled entries before DATE." | ||
| 18371 | (interactive (list (org-read-date))) | ||
| 18372 | (let ((case-fold-search nil) | ||
| 18373 | (regexp (concat "\\<\\(" org-deadline-string | ||
| 18374 | "\\|" org-scheduled-string | ||
| 18375 | "\\) *<\\([^>]+\\)>")) | ||
| 18376 | (callback | ||
| 18377 | (lambda () (time-less-p | ||
| 18378 | (org-time-string-to-time (match-string 2)) | ||
| 18379 | (org-time-string-to-time date))))) | ||
| 18380 | (message "%d entries before %s" | ||
| 18381 | (org-occur regexp nil callback) date))) | ||
| 18382 | |||
| 18383 | (defun org-evaluate-time-range (&optional to-buffer) | ||
| 18384 | "Evaluate a time range by computing the difference between start and end. | ||
| 18385 | Normally the result is just printed in the echo area, but with prefix arg | ||
| 18386 | TO-BUFFER, the result is inserted just after the date stamp into the buffer. | ||
| 18387 | If the time range is actually in a table, the result is inserted into the | ||
| 18388 | next column. | ||
| 18389 | For time difference computation, a year is assumed to be exactly 365 | ||
| 18390 | days in order to avoid rounding problems." | ||
| 18391 | (interactive "P") | ||
| 18392 | (or | ||
| 18393 | (org-clock-update-time-maybe) | ||
| 18394 | (save-excursion | ||
| 18395 | (unless (org-at-date-range-p t) | ||
| 18396 | (goto-char (point-at-bol)) | ||
| 18397 | (re-search-forward org-tr-regexp-both (point-at-eol) t)) | ||
| 18398 | (if (not (org-at-date-range-p t)) | ||
| 18399 | (error "Not at a time-stamp range, and none found in current line"))) | ||
| 18400 | (let* ((ts1 (match-string 1)) | ||
| 18401 | (ts2 (match-string 2)) | ||
| 18402 | (havetime (or (> (length ts1) 15) (> (length ts2) 15))) | ||
| 18403 | (match-end (match-end 0)) | ||
| 18404 | (time1 (org-time-string-to-time ts1)) | ||
| 18405 | (time2 (org-time-string-to-time ts2)) | ||
| 18406 | (t1 (time-to-seconds time1)) | ||
| 18407 | (t2 (time-to-seconds time2)) | ||
| 18408 | (diff (abs (- t2 t1))) | ||
| 18409 | (negative (< (- t2 t1) 0)) | ||
| 18410 | ;; (ys (floor (* 365 24 60 60))) | ||
| 18411 | (ds (* 24 60 60)) | ||
| 18412 | (hs (* 60 60)) | ||
| 18413 | (fy "%dy %dd %02d:%02d") | ||
| 18414 | (fy1 "%dy %dd") | ||
| 18415 | (fd "%dd %02d:%02d") | ||
| 18416 | (fd1 "%dd") | ||
| 18417 | (fh "%02d:%02d") | ||
| 18418 | y d h m align) | ||
| 18419 | (if havetime | ||
| 18420 | (setq ; y (floor (/ diff ys)) diff (mod diff ys) | ||
| 18421 | y 0 | ||
| 18422 | d (floor (/ diff ds)) diff (mod diff ds) | ||
| 18423 | h (floor (/ diff hs)) diff (mod diff hs) | ||
| 18424 | m (floor (/ diff 60))) | ||
| 18425 | (setq ; y (floor (/ diff ys)) diff (mod diff ys) | ||
| 18426 | y 0 | ||
| 18427 | d (floor (+ (/ diff ds) 0.5)) | ||
| 18428 | h 0 m 0)) | ||
| 18429 | (if (not to-buffer) | ||
| 18430 | (message "%s" (org-make-tdiff-string y d h m)) | ||
| 18431 | (if (org-at-table-p) | ||
| 18432 | (progn | ||
| 18433 | (goto-char match-end) | ||
| 18434 | (setq align t) | ||
| 18435 | (and (looking-at " *|") (goto-char (match-end 0)))) | ||
| 18436 | (goto-char match-end)) | ||
| 18437 | (if (looking-at | ||
| 18438 | "\\( *-? *[0-9]+y\\)?\\( *[0-9]+d\\)? *[0-9][0-9]:[0-9][0-9]") | ||
| 18439 | (replace-match "")) | ||
| 18440 | (if negative (insert " -")) | ||
| 18441 | (if (> y 0) (insert " " (format (if havetime fy fy1) y d h m)) | ||
| 18442 | (if (> d 0) (insert " " (format (if havetime fd fd1) d h m)) | ||
| 18443 | (insert " " (format fh h m)))) | ||
| 18444 | (if align (org-table-align)) | ||
| 18445 | (message "Time difference inserted"))))) | ||
| 18446 | |||
| 18447 | (defun org-make-tdiff-string (y d h m) | ||
| 18448 | (let ((fmt "") | ||
| 18449 | (l nil)) | ||
| 18450 | (if (> y 0) (setq fmt (concat fmt "%d year" (if (> y 1) "s" "") " ") | ||
| 18451 | l (push y l))) | ||
| 18452 | (if (> d 0) (setq fmt (concat fmt "%d day" (if (> d 1) "s" "") " ") | ||
| 18453 | l (push d l))) | ||
| 18454 | (if (> h 0) (setq fmt (concat fmt "%d hour" (if (> h 1) "s" "") " ") | ||
| 18455 | l (push h l))) | ||
| 18456 | (if (> m 0) (setq fmt (concat fmt "%d minute" (if (> m 1) "s" "") " ") | ||
| 18457 | l (push m l))) | ||
| 18458 | (apply 'format fmt (nreverse l)))) | ||
| 18459 | |||
| 18460 | (defun org-time-string-to-time (s) | ||
| 18461 | (apply 'encode-time (org-parse-time-string s))) | ||
| 18462 | |||
| 18463 | (defun org-time-string-to-absolute (s &optional daynr prefer) | ||
| 18464 | "Convert a time stamp to an absolute day number. | ||
| 18465 | If there is a specifyer for a cyclic time stamp, get the closest date to | ||
| 18466 | DAYNR." | ||
| 18467 | (cond | ||
| 18468 | ((and daynr (string-match "\\`%%\\((.*)\\)" s)) | ||
| 18469 | (if (org-diary-sexp-entry (match-string 1 s) "" date) | ||
| 18470 | daynr | ||
| 18471 | (+ daynr 1000))) | ||
| 18472 | ((and daynr (string-match "\\+[0-9]+[dwmy]" s)) | ||
| 18473 | (org-closest-date s (if (and (boundp 'daynr) (integerp daynr)) daynr | ||
| 18474 | (time-to-days (current-time))) (match-string 0 s) | ||
| 18475 | prefer)) | ||
| 18476 | (t (time-to-days (apply 'encode-time (org-parse-time-string s)))))) | ||
| 18477 | |||
| 18478 | (defun org-time-from-absolute (d) | ||
| 18479 | "Return the time corresponding to date D. | ||
| 18480 | D may be an absolute day number, or a calendar-type list (month day year)." | ||
| 18481 | (if (numberp d) (setq d (calendar-gregorian-from-absolute d))) | ||
| 18482 | (encode-time 0 0 0 (nth 1 d) (car d) (nth 2 d))) | ||
| 18483 | |||
| 18484 | (defun org-calendar-holiday () | ||
| 18485 | "List of holidays, for Diary display in Org-mode." | ||
| 18486 | (require 'holidays) | ||
| 18487 | (let ((hl (funcall | ||
| 18488 | (if (fboundp 'calendar-check-holidays) | ||
| 18489 | 'calendar-check-holidays 'check-calendar-holidays) date))) | ||
| 18490 | (if hl (mapconcat 'identity hl "; ")))) | ||
| 18491 | |||
| 18492 | (defun org-diary-sexp-entry (sexp entry date) | ||
| 18493 | "Process a SEXP diary ENTRY for DATE." | ||
| 18494 | (require 'diary-lib) | ||
| 18495 | (let ((result (if calendar-debug-sexp | ||
| 18496 | (let ((stack-trace-on-error t)) | ||
| 18497 | (eval (car (read-from-string sexp)))) | ||
| 18498 | (condition-case nil | ||
| 18499 | (eval (car (read-from-string sexp))) | ||
| 18500 | (error | ||
| 18501 | (beep) | ||
| 18502 | (message "Bad sexp at line %d in %s: %s" | ||
| 18503 | (org-current-line) | ||
| 18504 | (buffer-file-name) sexp) | ||
| 18505 | (sleep-for 2)))))) | ||
| 18506 | (cond ((stringp result) result) | ||
| 18507 | ((and (consp result) | ||
| 18508 | (stringp (cdr result))) (cdr result)) | ||
| 18509 | (result entry) | ||
| 18510 | (t nil)))) | ||
| 18511 | |||
| 18512 | (defun org-diary-to-ical-string (frombuf) | ||
| 18513 | "Get iCalendar entries from diary entries in buffer FROMBUF. | ||
| 18514 | This uses the icalendar.el library." | ||
| 18515 | (let* ((tmpdir (if (featurep 'xemacs) | ||
| 18516 | (temp-directory) | ||
| 18517 | temporary-file-directory)) | ||
| 18518 | (tmpfile (make-temp-name | ||
| 18519 | (expand-file-name "orgics" tmpdir))) | ||
| 18520 | buf rtn b e) | ||
| 18521 | (save-excursion | ||
| 18522 | (set-buffer frombuf) | ||
| 18523 | (icalendar-export-region (point-min) (point-max) tmpfile) | ||
| 18524 | (setq buf (find-buffer-visiting tmpfile)) | ||
| 18525 | (set-buffer buf) | ||
| 18526 | (goto-char (point-min)) | ||
| 18527 | (if (re-search-forward "^BEGIN:VEVENT" nil t) | ||
| 18528 | (setq b (match-beginning 0))) | ||
| 18529 | (goto-char (point-max)) | ||
| 18530 | (if (re-search-backward "^END:VEVENT" nil t) | ||
| 18531 | (setq e (match-end 0))) | ||
| 18532 | (setq rtn (if (and b e) (concat (buffer-substring b e) "\n") ""))) | ||
| 18533 | (kill-buffer buf) | ||
| 18534 | (kill-buffer frombuf) | ||
| 18535 | (delete-file tmpfile) | ||
| 18536 | rtn)) | ||
| 18537 | |||
| 18538 | (defun org-closest-date (start current change prefer) | ||
| 18539 | "Find the date closest to CURRENT that is consistent with START and CHANGE. | ||
| 18540 | When PREFER is `past' return a date that is either CURRENT or past. | ||
| 18541 | When PREFER is `future', return a date that is either CURRENT or future." | ||
| 18542 | ;; Make the proper lists from the dates | ||
| 18543 | (catch 'exit | ||
| 18544 | (let ((a1 '(("d" . day) ("w" . week) ("m" . month) ("y" . year))) | ||
| 18545 | dn dw sday cday n1 n2 | ||
| 18546 | d m y y1 y2 date1 date2 nmonths nm ny m2) | ||
| 18547 | |||
| 18548 | (setq start (org-date-to-gregorian start) | ||
| 18549 | current (org-date-to-gregorian | ||
| 18550 | (if org-agenda-repeating-timestamp-show-all | ||
| 18551 | current | ||
| 18552 | (time-to-days (current-time)))) | ||
| 18553 | sday (calendar-absolute-from-gregorian start) | ||
| 18554 | cday (calendar-absolute-from-gregorian current)) | ||
| 18555 | |||
| 18556 | (if (<= cday sday) (throw 'exit sday)) | ||
| 18557 | |||
| 18558 | (if (string-match "\\(\\+[0-9]+\\)\\([dwmy]\\)" change) | ||
| 18559 | (setq dn (string-to-number (match-string 1 change)) | ||
| 18560 | dw (cdr (assoc (match-string 2 change) a1))) | ||
| 18561 | (error "Invalid change specifyer: %s" change)) | ||
| 18562 | (if (eq dw 'week) (setq dw 'day dn (* 7 dn))) | ||
| 18563 | (cond | ||
| 18564 | ((eq dw 'day) | ||
| 18565 | (setq n1 (+ sday (* dn (floor (/ (- cday sday) dn)))) | ||
| 18566 | n2 (+ n1 dn))) | ||
| 18567 | ((eq dw 'year) | ||
| 18568 | (setq d (nth 1 start) m (car start) y1 (nth 2 start) y2 (nth 2 current)) | ||
| 18569 | (setq y1 (+ (* (floor (/ (- y2 y1) dn)) dn) y1)) | ||
| 18570 | (setq date1 (list m d y1) | ||
| 18571 | n1 (calendar-absolute-from-gregorian date1) | ||
| 18572 | date2 (list m d (+ y1 (* (if (< n1 cday) 1 -1) dn))) | ||
| 18573 | n2 (calendar-absolute-from-gregorian date2))) | ||
| 18574 | ((eq dw 'month) | ||
| 18575 | ;; approx number of month between the tow dates | ||
| 18576 | (setq nmonths (floor (/ (- cday sday) 30.436875))) | ||
| 18577 | ;; How often does dn fit in there? | ||
| 18578 | (setq d (nth 1 start) m (car start) y (nth 2 start) | ||
| 18579 | nm (* dn (max 0 (1- (floor (/ nmonths dn))))) | ||
| 18580 | m (+ m nm) | ||
| 18581 | ny (floor (/ m 12)) | ||
| 18582 | y (+ y ny) | ||
| 18583 | m (- m (* ny 12))) | ||
| 18584 | (while (> m 12) (setq m (- m 12) y (1+ y))) | ||
| 18585 | (setq n1 (calendar-absolute-from-gregorian (list m d y))) | ||
| 18586 | (setq m2 (+ m dn) y2 y) | ||
| 18587 | (if (> m2 12) (setq y2 (1+ y2) m2 (- m2 12))) | ||
| 18588 | (setq n2 (calendar-absolute-from-gregorian (list m2 d y2))) | ||
| 18589 | (while (< n2 cday) | ||
| 18590 | (setq n1 n2 m m2 y y2) | ||
| 18591 | (setq m2 (+ m dn) y2 y) | ||
| 18592 | (if (> m2 12) (setq y2 (1+ y2) m2 (- m2 12))) | ||
| 18593 | (setq n2 (calendar-absolute-from-gregorian (list m2 d y2)))))) | ||
| 18594 | |||
| 18595 | (if org-agenda-repeating-timestamp-show-all | ||
| 18596 | (cond | ||
| 18597 | ((eq prefer 'past) n1) | ||
| 18598 | ((eq prefer 'future) (if (= cday n1) n1 n2)) | ||
| 18599 | (t (if (> (abs (- cday n1)) (abs (- cday n2))) n2 n1))) | ||
| 18600 | (cond | ||
| 18601 | ((eq prefer 'past) n1) | ||
| 18602 | ((eq prefer 'future) (if (= cday n1) n1 n2)) | ||
| 18603 | (t (if (= cday n1) n1 n2))))))) | ||
| 18604 | |||
| 18605 | (defun org-date-to-gregorian (date) | ||
| 18606 | "Turn any specification of DATE into a gregorian date for the calendar." | ||
| 18607 | (cond ((integerp date) (calendar-gregorian-from-absolute date)) | ||
| 18608 | ((and (listp date) (= (length date) 3)) date) | ||
| 18609 | ((stringp date) | ||
| 18610 | (setq date (org-parse-time-string date)) | ||
| 18611 | (list (nth 4 date) (nth 3 date) (nth 5 date))) | ||
| 18612 | ((listp date) | ||
| 18613 | (list (nth 4 date) (nth 3 date) (nth 5 date))))) | ||
| 18614 | |||
| 18615 | (defun org-parse-time-string (s &optional nodefault) | ||
| 18616 | "Parse the standard Org-mode time string. | ||
| 18617 | This should be a lot faster than the normal `parse-time-string'. | ||
| 18618 | If time is not given, defaults to 0:00. However, with optional NODEFAULT, | ||
| 18619 | hour and minute fields will be nil if not given." | ||
| 18620 | (if (string-match org-ts-regexp0 s) | ||
| 18621 | (list 0 | ||
| 18622 | (if (or (match-beginning 8) (not nodefault)) | ||
| 18623 | (string-to-number (or (match-string 8 s) "0"))) | ||
| 18624 | (if (or (match-beginning 7) (not nodefault)) | ||
| 18625 | (string-to-number (or (match-string 7 s) "0"))) | ||
| 18626 | (string-to-number (match-string 4 s)) | ||
| 18627 | (string-to-number (match-string 3 s)) | ||
| 18628 | (string-to-number (match-string 2 s)) | ||
| 18629 | nil nil nil) | ||
| 18630 | (make-list 9 0))) | ||
| 18631 | |||
| 18632 | (defun org-timestamp-up (&optional arg) | ||
| 18633 | "Increase the date item at the cursor by one. | ||
| 18634 | If the cursor is on the year, change the year. If it is on the month or | ||
| 18635 | the day, change that. | ||
| 18636 | With prefix ARG, change by that many units." | ||
| 18637 | (interactive "p") | ||
| 18638 | (org-timestamp-change (prefix-numeric-value arg))) | ||
| 18639 | |||
| 18640 | (defun org-timestamp-down (&optional arg) | ||
| 18641 | "Decrease the date item at the cursor by one. | ||
| 18642 | If the cursor is on the year, change the year. If it is on the month or | ||
| 18643 | the day, change that. | ||
| 18644 | With prefix ARG, change by that many units." | ||
| 18645 | (interactive "p") | ||
| 18646 | (org-timestamp-change (- (prefix-numeric-value arg)))) | ||
| 18647 | |||
| 18648 | (defun org-timestamp-up-day (&optional arg) | ||
| 18649 | "Increase the date in the time stamp by one day. | ||
| 18650 | With prefix ARG, change that many days." | ||
| 18651 | (interactive "p") | ||
| 18652 | (if (and (not (org-at-timestamp-p t)) | ||
| 18653 | (org-on-heading-p)) | ||
| 18654 | (org-todo 'up) | ||
| 18655 | (org-timestamp-change (prefix-numeric-value arg) 'day))) | ||
| 18656 | |||
| 18657 | (defun org-timestamp-down-day (&optional arg) | ||
| 18658 | "Decrease the date in the time stamp by one day. | ||
| 18659 | With prefix ARG, change that many days." | ||
| 18660 | (interactive "p") | ||
| 18661 | (if (and (not (org-at-timestamp-p t)) | ||
| 18662 | (org-on-heading-p)) | ||
| 18663 | (org-todo 'down) | ||
| 18664 | (org-timestamp-change (- (prefix-numeric-value arg)) 'day))) | ||
| 18665 | |||
| 18666 | (defsubst org-pos-in-match-range (pos n) | ||
| 18667 | (and (match-beginning n) | ||
| 18668 | (<= (match-beginning n) pos) | ||
| 18669 | (>= (match-end n) pos))) | ||
| 18670 | |||
| 18671 | (defun org-at-timestamp-p (&optional inactive-ok) | ||
| 18672 | "Determine if the cursor is in or at a timestamp." | ||
| 18673 | (interactive) | ||
| 18674 | (let* ((tsr (if inactive-ok org-ts-regexp3 org-ts-regexp2)) | ||
| 18675 | (pos (point)) | ||
| 18676 | (ans (or (looking-at tsr) | ||
| 18677 | (save-excursion | ||
| 18678 | (skip-chars-backward "^[<\n\r\t") | ||
| 18679 | (if (> (point) (point-min)) (backward-char 1)) | ||
| 18680 | (and (looking-at tsr) | ||
| 18681 | (> (- (match-end 0) pos) -1)))))) | ||
| 18682 | (and ans | ||
| 18683 | (boundp 'org-ts-what) | ||
| 18684 | (setq org-ts-what | ||
| 18685 | (cond | ||
| 18686 | ((= pos (match-beginning 0)) 'bracket) | ||
| 18687 | ((= pos (1- (match-end 0))) 'bracket) | ||
| 18688 | ((org-pos-in-match-range pos 2) 'year) | ||
| 18689 | ((org-pos-in-match-range pos 3) 'month) | ||
| 18690 | ((org-pos-in-match-range pos 7) 'hour) | ||
| 18691 | ((org-pos-in-match-range pos 8) 'minute) | ||
| 18692 | ((or (org-pos-in-match-range pos 4) | ||
| 18693 | (org-pos-in-match-range pos 5)) 'day) | ||
| 18694 | ((and (> pos (or (match-end 8) (match-end 5))) | ||
| 18695 | (< pos (match-end 0))) | ||
| 18696 | (- pos (or (match-end 8) (match-end 5)))) | ||
| 18697 | (t 'day)))) | ||
| 18698 | ans)) | ||
| 18699 | |||
| 18700 | (defun org-toggle-timestamp-type () | ||
| 18701 | "Toggle the type (<active> or [inactive]) of a time stamp." | ||
| 18702 | (interactive) | ||
| 18703 | (when (org-at-timestamp-p t) | ||
| 18704 | (save-excursion | ||
| 18705 | (goto-char (match-beginning 0)) | ||
| 18706 | (insert (if (equal (char-after) ?<) "[" "<")) (delete-char 1) | ||
| 18707 | (goto-char (1- (match-end 0))) | ||
| 18708 | (insert (if (equal (char-after) ?>) "]" ">")) (delete-char 1)) | ||
| 18709 | (message "Timestamp is now %sactive" | ||
| 18710 | (if (equal (char-before) ?>) "in" "")))) | ||
| 18711 | |||
| 18712 | (defun org-timestamp-change (n &optional what) | ||
| 18713 | "Change the date in the time stamp at point. | ||
| 18714 | The date will be changed by N times WHAT. WHAT can be `day', `month', | ||
| 18715 | `year', `minute', `second'. If WHAT is not given, the cursor position | ||
| 18716 | in the timestamp determines what will be changed." | ||
| 18717 | (let ((pos (point)) | ||
| 18718 | with-hm inactive | ||
| 18719 | (dm (max (nth 1 org-time-stamp-rounding-minutes) 1)) | ||
| 18720 | org-ts-what | ||
| 18721 | extra rem | ||
| 18722 | ts time time0) | ||
| 18723 | (if (not (org-at-timestamp-p t)) | ||
| 18724 | (error "Not at a timestamp")) | ||
| 18725 | (if (and (not what) (eq org-ts-what 'bracket)) | ||
| 18726 | (org-toggle-timestamp-type) | ||
| 18727 | (if (and (not what) (not (eq org-ts-what 'day)) | ||
| 18728 | org-display-custom-times | ||
| 18729 | (get-text-property (point) 'display) | ||
| 18730 | (not (get-text-property (1- (point)) 'display))) | ||
| 18731 | (setq org-ts-what 'day)) | ||
| 18732 | (setq org-ts-what (or what org-ts-what) | ||
| 18733 | inactive (= (char-after (match-beginning 0)) ?\[) | ||
| 18734 | ts (match-string 0)) | ||
| 18735 | (replace-match "") | ||
| 18736 | (if (string-match | ||
| 18737 | "\\(\\(-[012][0-9]:[0-5][0-9]\\)?\\( +[.+]?[-+][0-9]+[dwmy]\\)*\\)[]>]" | ||
| 18738 | ts) | ||
| 18739 | (setq extra (match-string 1 ts))) | ||
| 18740 | (if (string-match "^.\\{10\\}.*?[0-9]+:[0-9][0-9]" ts) | ||
| 18741 | (setq with-hm t)) | ||
| 18742 | (setq time0 (org-parse-time-string ts)) | ||
| 18743 | (when (and (eq org-ts-what 'minute) | ||
| 18744 | (eq current-prefix-arg nil)) | ||
| 18745 | (setq n (* dm (org-no-warnings (signum n)))) | ||
| 18746 | (when (not (= 0 (setq rem (% (nth 1 time0) dm)))) | ||
| 18747 | (setcar (cdr time0) (+ (nth 1 time0) | ||
| 18748 | (if (> n 0) (- rem) (- dm rem)))))) | ||
| 18749 | (setq time | ||
| 18750 | (encode-time (or (car time0) 0) | ||
| 18751 | (+ (if (eq org-ts-what 'minute) n 0) (nth 1 time0)) | ||
| 18752 | (+ (if (eq org-ts-what 'hour) n 0) (nth 2 time0)) | ||
| 18753 | (+ (if (eq org-ts-what 'day) n 0) (nth 3 time0)) | ||
| 18754 | (+ (if (eq org-ts-what 'month) n 0) (nth 4 time0)) | ||
| 18755 | (+ (if (eq org-ts-what 'year) n 0) (nth 5 time0)) | ||
| 18756 | (nthcdr 6 time0))) | ||
| 18757 | (when (integerp org-ts-what) | ||
| 18758 | (setq extra (org-modify-ts-extra extra org-ts-what n dm))) | ||
| 18759 | (if (eq what 'calendar) | ||
| 18760 | (let ((cal-date (org-get-date-from-calendar))) | ||
| 18761 | (setcar (nthcdr 4 time0) (nth 0 cal-date)) ; month | ||
| 18762 | (setcar (nthcdr 3 time0) (nth 1 cal-date)) ; day | ||
| 18763 | (setcar (nthcdr 5 time0) (nth 2 cal-date)) ; year | ||
| 18764 | (setcar time0 (or (car time0) 0)) | ||
| 18765 | (setcar (nthcdr 1 time0) (or (nth 1 time0) 0)) | ||
| 18766 | (setcar (nthcdr 2 time0) (or (nth 2 time0) 0)) | ||
| 18767 | (setq time (apply 'encode-time time0)))) | ||
| 18768 | (setq org-last-changed-timestamp | ||
| 18769 | (org-insert-time-stamp time with-hm inactive nil nil extra)) | ||
| 18770 | (org-clock-update-time-maybe) | ||
| 18771 | (goto-char pos) | ||
| 18772 | ;; Try to recenter the calendar window, if any | ||
| 18773 | (if (and org-calendar-follow-timestamp-change | ||
| 18774 | (get-buffer-window "*Calendar*" t) | ||
| 18775 | (memq org-ts-what '(day month year))) | ||
| 18776 | (org-recenter-calendar (time-to-days time)))))) | ||
| 18777 | |||
| 18778 | ;; FIXME: does not yet work for lead times | ||
| 18779 | (defun org-modify-ts-extra (s pos n dm) | ||
| 18780 | "Change the different parts of the lead-time and repeat fields in timestamp." | ||
| 18781 | (let ((idx '(("d" . 0) ("w" . 1) ("m" . 2) ("y" . 3) ("d" . -1) ("y" . 4))) | ||
| 18782 | ng h m new rem) | ||
| 18783 | (when (string-match "\\(-\\([012][0-9]\\):\\([0-5][0-9]\\)\\)?\\( +\\+\\([0-9]+\\)\\([dmwy]\\)\\)?\\( +-\\([0-9]+\\)\\([dmwy]\\)\\)?" s) | ||
| 18784 | (cond | ||
| 18785 | ((or (org-pos-in-match-range pos 2) | ||
| 18786 | (org-pos-in-match-range pos 3)) | ||
| 18787 | (setq m (string-to-number (match-string 3 s)) | ||
| 18788 | h (string-to-number (match-string 2 s))) | ||
| 18789 | (if (org-pos-in-match-range pos 2) | ||
| 18790 | (setq h (+ h n)) | ||
| 18791 | (setq n (* dm (org-no-warnings (signum n)))) | ||
| 18792 | (when (not (= 0 (setq rem (% m dm)))) | ||
| 18793 | (setq m (+ m (if (> n 0) (- rem) (- dm rem))))) | ||
| 18794 | (setq m (+ m n))) | ||
| 18795 | (if (< m 0) (setq m (+ m 60) h (1- h))) | ||
| 18796 | (if (> m 59) (setq m (- m 60) h (1+ h))) | ||
| 18797 | (setq h (min 24 (max 0 h))) | ||
| 18798 | (setq ng 1 new (format "-%02d:%02d" h m))) | ||
| 18799 | ((org-pos-in-match-range pos 6) | ||
| 18800 | (setq ng 6 new (car (rassoc (+ n (cdr (assoc (match-string 6 s) idx))) idx)))) | ||
| 18801 | ((org-pos-in-match-range pos 5) | ||
| 18802 | (setq ng 5 new (format "%d" (max 1 (+ n (string-to-number (match-string 5 s))))))) | ||
| 18803 | |||
| 18804 | ((org-pos-in-match-range pos 9) | ||
| 18805 | (setq ng 9 new (car (rassoc (+ n (cdr (assoc (match-string 9 s) idx))) idx)))) | ||
| 18806 | ((org-pos-in-match-range pos 8) | ||
| 18807 | (setq ng 8 new (format "%d" (max 0 (+ n (string-to-number (match-string 8 s)))))))) | ||
| 18808 | |||
| 18809 | (when ng | ||
| 18810 | (setq s (concat | ||
| 18811 | (substring s 0 (match-beginning ng)) | ||
| 18812 | new | ||
| 18813 | (substring s (match-end ng)))))) | ||
| 18814 | s)) | ||
| 18815 | |||
| 18816 | (defun org-recenter-calendar (date) | ||
| 18817 | "If the calendar is visible, recenter it to DATE." | ||
| 18818 | (let* ((win (selected-window)) | ||
| 18819 | (cwin (get-buffer-window "*Calendar*" t)) | ||
| 18820 | (calendar-move-hook nil)) | ||
| 18821 | (when cwin | ||
| 18822 | (select-window cwin) | ||
| 18823 | (calendar-goto-date (if (listp date) date | ||
| 18824 | (calendar-gregorian-from-absolute date))) | ||
| 18825 | (select-window win)))) | ||
| 18826 | |||
| 18827 | (defun org-goto-calendar (&optional arg) | ||
| 18828 | "Go to the Emacs calendar at the current date. | ||
| 18829 | If there is a time stamp in the current line, go to that date. | ||
| 18830 | A prefix ARG can be used to force the current date." | ||
| 18831 | (interactive "P") | ||
| 18832 | (let ((tsr org-ts-regexp) diff | ||
| 18833 | (calendar-move-hook nil) | ||
| 18834 | (view-calendar-holidays-initially nil) | ||
| 18835 | (view-diary-entries-initially nil)) | ||
| 18836 | (if (or (org-at-timestamp-p) | ||
| 18837 | (save-excursion | ||
| 18838 | (beginning-of-line 1) | ||
| 18839 | (looking-at (concat ".*" tsr)))) | ||
| 18840 | (let ((d1 (time-to-days (current-time))) | ||
| 18841 | (d2 (time-to-days | ||
| 18842 | (org-time-string-to-time (match-string 1))))) | ||
| 18843 | (setq diff (- d2 d1)))) | ||
| 18844 | (calendar) | ||
| 18845 | (calendar-goto-today) | ||
| 18846 | (if (and diff (not arg)) (calendar-forward-day diff)))) | ||
| 18847 | |||
| 18848 | (defun org-get-date-from-calendar () | ||
| 18849 | "Return a list (month day year) of date at point in calendar." | ||
| 18850 | (with-current-buffer "*Calendar*" | ||
| 18851 | (save-match-data | ||
| 18852 | (calendar-cursor-to-date)))) | ||
| 18853 | |||
| 18854 | (defun org-date-from-calendar () | ||
| 18855 | "Insert time stamp corresponding to cursor date in *Calendar* buffer. | ||
| 18856 | If there is already a time stamp at the cursor position, update it." | ||
| 18857 | (interactive) | ||
| 18858 | (if (org-at-timestamp-p t) | ||
| 18859 | (org-timestamp-change 0 'calendar) | ||
| 18860 | (let ((cal-date (org-get-date-from-calendar))) | ||
| 18861 | (org-insert-time-stamp | ||
| 18862 | (encode-time 0 0 0 (nth 1 cal-date) (car cal-date) (nth 2 cal-date)))))) | ||
| 18863 | |||
| 18864 | (defvar appt-time-msg-list) | ||
| 18865 | |||
| 18866 | ;;;###autoload | ||
| 18867 | (defun org-agenda-to-appt (&optional refresh filter) | ||
| 18868 | "Activate appointments found in `org-agenda-files'. | ||
| 18869 | With a \\[universal-argument] prefix, refresh the list of | ||
| 18870 | appointements. | ||
| 18871 | |||
| 18872 | If FILTER is t, interactively prompt the user for a regular | ||
| 18873 | expression, and filter out entries that don't match it. | ||
| 18874 | |||
| 18875 | If FILTER is a string, use this string as a regular expression | ||
| 18876 | for filtering entries out. | ||
| 18877 | |||
| 18878 | FILTER can also be an alist with the car of each cell being | ||
| 18879 | either 'headline or 'category. For example: | ||
| 18880 | |||
| 18881 | '((headline \"IMPORTANT\") | ||
| 18882 | (category \"Work\")) | ||
| 18883 | |||
| 18884 | will only add headlines containing IMPORTANT or headlines | ||
| 18885 | belonging to the \"Work\" category." | ||
| 18886 | (interactive "P") | ||
| 18887 | (require 'calendar) | ||
| 18888 | (if refresh (setq appt-time-msg-list nil)) | ||
| 18889 | (if (eq filter t) | ||
| 18890 | (setq filter (read-from-minibuffer "Regexp filter: "))) | ||
| 18891 | (let* ((cnt 0) ; count added events | ||
| 18892 | (org-agenda-new-buffers nil) | ||
| 18893 | (org-deadline-warning-days 0) | ||
| 18894 | (today (org-date-to-gregorian | ||
| 18895 | (time-to-days (current-time)))) | ||
| 18896 | (files (org-agenda-files)) entries file) | ||
| 18897 | ;; Get all entries which may contain an appt | ||
| 18898 | (while (setq file (pop files)) | ||
| 18899 | (setq entries | ||
| 18900 | (append entries | ||
| 18901 | (org-agenda-get-day-entries | ||
| 18902 | file today :timestamp :scheduled :deadline)))) | ||
| 18903 | (setq entries (delq nil entries)) | ||
| 18904 | ;; Map thru entries and find if we should filter them out | ||
| 18905 | (mapc | ||
| 18906 | (lambda(x) | ||
| 18907 | (let* ((evt (org-trim (get-text-property 1 'txt x))) | ||
| 18908 | (cat (get-text-property 1 'org-category x)) | ||
| 18909 | (tod (get-text-property 1 'time-of-day x)) | ||
| 18910 | (ok (or (null filter) | ||
| 18911 | (and (stringp filter) (string-match filter evt)) | ||
| 18912 | (and (listp filter) | ||
| 18913 | (or (string-match | ||
| 18914 | (cadr (assoc 'category filter)) cat) | ||
| 18915 | (string-match | ||
| 18916 | (cadr (assoc 'headline filter)) evt)))))) | ||
| 18917 | ;; FIXME: Shall we remove text-properties for the appt text? | ||
| 18918 | ;; (setq evt (set-text-properties 0 (length evt) nil evt)) | ||
| 18919 | (when (and ok tod) | ||
| 18920 | (setq tod (number-to-string tod) | ||
| 18921 | tod (when (string-match | ||
| 18922 | "\\([0-9]\\{1,2\\}\\)\\([0-9]\\{2\\}\\)" tod) | ||
| 18923 | (concat (match-string 1 tod) ":" | ||
| 18924 | (match-string 2 tod)))) | ||
| 18925 | (appt-add tod evt) | ||
| 18926 | (setq cnt (1+ cnt))))) entries) | ||
| 18927 | (org-release-buffers org-agenda-new-buffers) | ||
| 18928 | (if (eq cnt 0) | ||
| 18929 | (message "No event to add") | ||
| 18930 | (message "Added %d event%s for today" cnt (if (> cnt 1) "s" ""))))) | ||
| 18931 | |||
| 18932 | ;;; The clock for measuring work time. | ||
| 18933 | |||
| 18934 | (defvar org-mode-line-string "") | ||
| 18935 | (put 'org-mode-line-string 'risky-local-variable t) | ||
| 18936 | |||
| 18937 | (defvar org-mode-line-timer nil) | ||
| 18938 | (defvar org-clock-heading "") | ||
| 18939 | (defvar org-clock-start-time "") | ||
| 18940 | |||
| 18941 | (defun org-update-mode-line () | ||
| 18942 | (let* ((delta (- (time-to-seconds (current-time)) | ||
| 18943 | (time-to-seconds org-clock-start-time))) | ||
| 18944 | (h (floor delta 3600)) | ||
| 18945 | (m (floor (- delta (* 3600 h)) 60))) | ||
| 18946 | (setq org-mode-line-string | ||
| 18947 | (propertize (format "-[%d:%02d (%s)]" h m org-clock-heading) | ||
| 18948 | 'help-echo "Org-mode clock is running")) | ||
| 18949 | (force-mode-line-update))) | ||
| 18950 | |||
| 18951 | (defvar org-clock-marker (make-marker) | ||
| 18952 | "Marker recording the last clock-in.") | ||
| 18953 | (defvar org-clock-mode-line-entry nil | ||
| 18954 | "Information for the modeline about the running clock.") | ||
| 18955 | |||
| 18956 | (defun org-clock-in () | ||
| 18957 | "Start the clock on the current item. | ||
| 18958 | If necessary, clock-out of the currently active clock." | ||
| 18959 | (interactive) | ||
| 18960 | (org-clock-out t) | ||
| 18961 | (let (ts) | ||
| 18962 | (save-excursion | ||
| 18963 | (org-back-to-heading t) | ||
| 18964 | (when (and org-clock-in-switch-to-state | ||
| 18965 | (not (looking-at (concat outline-regexp "[ \t]*" | ||
| 18966 | org-clock-in-switch-to-state | ||
| 18967 | "\\>")))) | ||
| 18968 | (org-todo org-clock-in-switch-to-state)) | ||
| 18969 | (if (and org-clock-heading-function | ||
| 18970 | (functionp org-clock-heading-function)) | ||
| 18971 | (setq org-clock-heading (funcall org-clock-heading-function)) | ||
| 18972 | (if (looking-at org-complex-heading-regexp) | ||
| 18973 | (setq org-clock-heading (match-string 4)) | ||
| 18974 | (setq org-clock-heading "???"))) | ||
| 18975 | (setq org-clock-heading (propertize org-clock-heading 'face nil)) | ||
| 18976 | (org-clock-find-position) | ||
| 18977 | |||
| 18978 | (insert "\n") (backward-char 1) | ||
| 18979 | (indent-relative) | ||
| 18980 | (insert org-clock-string " ") | ||
| 18981 | (setq org-clock-start-time (current-time)) | ||
| 18982 | (setq ts (org-insert-time-stamp (current-time) 'with-hm 'inactive)) | ||
| 18983 | (move-marker org-clock-marker (point) (buffer-base-buffer)) | ||
| 18984 | (or global-mode-string (setq global-mode-string '(""))) | ||
| 18985 | (or (memq 'org-mode-line-string global-mode-string) | ||
| 18986 | (setq global-mode-string | ||
| 18987 | (append global-mode-string '(org-mode-line-string)))) | ||
| 18988 | (org-update-mode-line) | ||
| 18989 | (setq org-mode-line-timer (run-with-timer 60 60 'org-update-mode-line)) | ||
| 18990 | (message "Clock started at %s" ts)))) | ||
| 18991 | |||
| 18992 | (defun org-clock-find-position () | ||
| 18993 | "Find the location where the next clock line should be inserted." | ||
| 18994 | (org-back-to-heading t) | ||
| 18995 | (catch 'exit | ||
| 18996 | (let ((beg (point-at-bol 2)) (end (progn (outline-next-heading) (point))) | ||
| 18997 | (re (concat "^[ \t]*" org-clock-string)) | ||
| 18998 | (cnt 0) | ||
| 18999 | first last) | ||
| 19000 | (goto-char beg) | ||
| 19001 | (when (eobp) (newline) (setq end (max (point) end))) | ||
| 19002 | (when (re-search-forward "^[ \t]*:CLOCK:" end t) | ||
| 19003 | ;; we seem to have a CLOCK drawer, so go there. | ||
| 19004 | (beginning-of-line 2) | ||
| 19005 | (throw 'exit t)) | ||
| 19006 | ;; Lets count the CLOCK lines | ||
| 19007 | (goto-char beg) | ||
| 19008 | (while (re-search-forward re end t) | ||
| 19009 | (setq first (or first (match-beginning 0)) | ||
| 19010 | last (match-beginning 0) | ||
| 19011 | cnt (1+ cnt))) | ||
| 19012 | (when (and (integerp org-clock-into-drawer) | ||
| 19013 | (>= (1+ cnt) org-clock-into-drawer)) | ||
| 19014 | ;; Wrap current entries into a new drawer | ||
| 19015 | (goto-char last) | ||
| 19016 | (beginning-of-line 2) | ||
| 19017 | (if (org-at-item-p) (org-end-of-item)) | ||
| 19018 | (insert ":END:\n") | ||
| 19019 | (beginning-of-line 0) | ||
| 19020 | (org-indent-line-function) | ||
| 19021 | (goto-char first) | ||
| 19022 | (insert ":CLOCK:\n") | ||
| 19023 | (beginning-of-line 0) | ||
| 19024 | (org-indent-line-function) | ||
| 19025 | (org-flag-drawer t) | ||
| 19026 | (beginning-of-line 2) | ||
| 19027 | (throw 'exit nil)) | ||
| 19028 | |||
| 19029 | (goto-char beg) | ||
| 19030 | (while (and (looking-at (concat "[ \t]*" org-keyword-time-regexp)) | ||
| 19031 | (not (equal (match-string 1) org-clock-string))) | ||
| 19032 | ;; Planning info, skip to after it | ||
| 19033 | (beginning-of-line 2) | ||
| 19034 | (or (bolp) (newline))) | ||
| 19035 | (when (eq t org-clock-into-drawer) | ||
| 19036 | (insert ":CLOCK:\n:END:\n") | ||
| 19037 | (beginning-of-line -1) | ||
| 19038 | (org-indent-line-function) | ||
| 19039 | (org-flag-drawer t) | ||
| 19040 | (beginning-of-line 2) | ||
| 19041 | (org-indent-line-function))))) | ||
| 19042 | |||
| 19043 | (defun org-clock-out (&optional fail-quietly) | ||
| 19044 | "Stop the currently running clock. | ||
| 19045 | If there is no running clock, throw an error, unless FAIL-QUIETLY is set." | ||
| 19046 | (interactive) | ||
| 19047 | (catch 'exit | ||
| 19048 | (if (not (marker-buffer org-clock-marker)) | ||
| 19049 | (if fail-quietly (throw 'exit t) (error "No active clock"))) | ||
| 19050 | (let (ts te s h m) | ||
| 19051 | (save-excursion | ||
| 19052 | (set-buffer (marker-buffer org-clock-marker)) | ||
| 19053 | (goto-char org-clock-marker) | ||
| 19054 | (beginning-of-line 1) | ||
| 19055 | (if (and (looking-at (concat "[ \t]*" org-keyword-time-regexp)) | ||
| 19056 | (equal (match-string 1) org-clock-string)) | ||
| 19057 | (setq ts (match-string 2)) | ||
| 19058 | (if fail-quietly (throw 'exit nil) (error "Clock start time is gone"))) | ||
| 19059 | (goto-char (match-end 0)) | ||
| 19060 | (delete-region (point) (point-at-eol)) | ||
| 19061 | (insert "--") | ||
| 19062 | (setq te (org-insert-time-stamp (current-time) 'with-hm 'inactive)) | ||
| 19063 | (setq s (- (time-to-seconds (apply 'encode-time (org-parse-time-string te))) | ||
| 19064 | (time-to-seconds (apply 'encode-time (org-parse-time-string ts)))) | ||
| 19065 | h (floor (/ s 3600)) | ||
| 19066 | s (- s (* 3600 h)) | ||
| 19067 | m (floor (/ s 60)) | ||
| 19068 | s (- s (* 60 s))) | ||
| 19069 | (insert " => " (format "%2d:%02d" h m)) | ||
| 19070 | (move-marker org-clock-marker nil) | ||
| 19071 | (when org-log-note-clock-out | ||
| 19072 | (org-add-log-maybe 'clock-out)) | ||
| 19073 | (when org-mode-line-timer | ||
| 19074 | (cancel-timer org-mode-line-timer) | ||
| 19075 | (setq org-mode-line-timer nil)) | ||
| 19076 | (setq global-mode-string | ||
| 19077 | (delq 'org-mode-line-string global-mode-string)) | ||
| 19078 | (force-mode-line-update) | ||
| 19079 | (message "Clock stopped at %s after HH:MM = %d:%02d" te h m))))) | ||
| 19080 | |||
| 19081 | (defun org-clock-cancel () | ||
| 19082 | "Cancel the running clock be removing the start timestamp." | ||
| 19083 | (interactive) | ||
| 19084 | (if (not (marker-buffer org-clock-marker)) | ||
| 19085 | (error "No active clock")) | ||
| 19086 | (save-excursion | ||
| 19087 | (set-buffer (marker-buffer org-clock-marker)) | ||
| 19088 | (goto-char org-clock-marker) | ||
| 19089 | (delete-region (1- (point-at-bol)) (point-at-eol))) | ||
| 19090 | (setq global-mode-string | ||
| 19091 | (delq 'org-mode-line-string global-mode-string)) | ||
| 19092 | (force-mode-line-update) | ||
| 19093 | (message "Clock canceled")) | ||
| 19094 | |||
| 19095 | (defun org-clock-goto (&optional delete-windows) | ||
| 19096 | "Go to the currently clocked-in entry." | ||
| 19097 | (interactive "P") | ||
| 19098 | (if (not (marker-buffer org-clock-marker)) | ||
| 19099 | (error "No active clock")) | ||
| 19100 | (switch-to-buffer-other-window | ||
| 19101 | (marker-buffer org-clock-marker)) | ||
| 19102 | (if delete-windows (delete-other-windows)) | ||
| 19103 | (goto-char org-clock-marker) | ||
| 19104 | (org-show-entry) | ||
| 19105 | (org-back-to-heading) | ||
| 19106 | (recenter)) | ||
| 19107 | |||
| 19108 | (defvar org-clock-file-total-minutes nil | ||
| 19109 | "Holds the file total time in minutes, after a call to `org-clock-sum'.") | ||
| 19110 | (make-variable-buffer-local 'org-clock-file-total-minutes) | ||
| 19111 | |||
| 19112 | (defun org-clock-sum (&optional tstart tend) | ||
| 19113 | "Sum the times for each subtree. | ||
| 19114 | Puts the resulting times in minutes as a text property on each headline." | ||
| 19115 | (interactive) | ||
| 19116 | (let* ((bmp (buffer-modified-p)) | ||
| 19117 | (re (concat "^\\(\\*+\\)[ \t]\\|^[ \t]*" | ||
| 19118 | org-clock-string | ||
| 19119 | "[ \t]*\\(?:\\(\\[.*?\\]\\)-+\\(\\[.*?\\]\\)\\|=>[ \t]+\\([0-9]+\\):\\([0-9]+\\)\\)")) | ||
| 19120 | (lmax 30) | ||
| 19121 | (ltimes (make-vector lmax 0)) | ||
| 19122 | (t1 0) | ||
| 19123 | (level 0) | ||
| 19124 | ts te dt | ||
| 19125 | time) | ||
| 19126 | (remove-text-properties (point-min) (point-max) '(:org-clock-minutes t)) | ||
| 19127 | (save-excursion | ||
| 19128 | (goto-char (point-max)) | ||
| 19129 | (while (re-search-backward re nil t) | ||
| 19130 | (cond | ||
| 19131 | ((match-end 2) | ||
| 19132 | ;; Two time stamps | ||
| 19133 | (setq ts (match-string 2) | ||
| 19134 | te (match-string 3) | ||
| 19135 | ts (time-to-seconds | ||
| 19136 | (apply 'encode-time (org-parse-time-string ts))) | ||
| 19137 | te (time-to-seconds | ||
| 19138 | (apply 'encode-time (org-parse-time-string te))) | ||
| 19139 | ts (if tstart (max ts tstart) ts) | ||
| 19140 | te (if tend (min te tend) te) | ||
| 19141 | dt (- te ts) | ||
| 19142 | t1 (if (> dt 0) (+ t1 (floor (/ dt 60))) t1))) | ||
| 19143 | ((match-end 4) | ||
| 19144 | ;; A naket time | ||
| 19145 | (setq t1 (+ t1 (string-to-number (match-string 5)) | ||
| 19146 | (* 60 (string-to-number (match-string 4)))))) | ||
| 19147 | (t ;; A headline | ||
| 19148 | (setq level (- (match-end 1) (match-beginning 1))) | ||
| 19149 | (when (or (> t1 0) (> (aref ltimes level) 0)) | ||
| 19150 | (loop for l from 0 to level do | ||
| 19151 | (aset ltimes l (+ (aref ltimes l) t1))) | ||
| 19152 | (setq t1 0 time (aref ltimes level)) | ||
| 19153 | (loop for l from level to (1- lmax) do | ||
| 19154 | (aset ltimes l 0)) | ||
| 19155 | (goto-char (match-beginning 0)) | ||
| 19156 | (put-text-property (point) (point-at-eol) :org-clock-minutes time))))) | ||
| 19157 | (setq org-clock-file-total-minutes (aref ltimes 0))) | ||
| 19158 | (set-buffer-modified-p bmp))) | ||
| 19159 | |||
| 19160 | (defun org-clock-display (&optional total-only) | ||
| 19161 | "Show subtree times in the entire buffer. | ||
| 19162 | If TOTAL-ONLY is non-nil, only show the total time for the entire file | ||
| 19163 | in the echo area." | ||
| 19164 | (interactive) | ||
| 19165 | (org-remove-clock-overlays) | ||
| 19166 | (let (time h m p) | ||
| 19167 | (org-clock-sum) | ||
| 19168 | (unless total-only | ||
| 19169 | (save-excursion | ||
| 19170 | (goto-char (point-min)) | ||
| 19171 | (while (or (and (equal (setq p (point)) (point-min)) | ||
| 19172 | (get-text-property p :org-clock-minutes)) | ||
| 19173 | (setq p (next-single-property-change | ||
| 19174 | (point) :org-clock-minutes))) | ||
| 19175 | (goto-char p) | ||
| 19176 | (when (setq time (get-text-property p :org-clock-minutes)) | ||
| 19177 | (org-put-clock-overlay time (funcall outline-level)))) | ||
| 19178 | (setq h (/ org-clock-file-total-minutes 60) | ||
| 19179 | m (- org-clock-file-total-minutes (* 60 h))) | ||
| 19180 | ;; Arrange to remove the overlays upon next change. | ||
| 19181 | (when org-remove-highlights-with-change | ||
| 19182 | (org-add-hook 'before-change-functions 'org-remove-clock-overlays | ||
| 19183 | nil 'local)))) | ||
| 19184 | (message "Total file time: %d:%02d (%d hours and %d minutes)" h m h m))) | ||
| 19185 | |||
| 19186 | (defvar org-clock-overlays nil) | ||
| 19187 | (make-variable-buffer-local 'org-clock-overlays) | ||
| 19188 | |||
| 19189 | (defun org-put-clock-overlay (time &optional level) | ||
| 19190 | "Put an overlays on the current line, displaying TIME. | ||
| 19191 | If LEVEL is given, prefix time with a corresponding number of stars. | ||
| 19192 | This creates a new overlay and stores it in `org-clock-overlays', so that it | ||
| 19193 | will be easy to remove." | ||
| 19194 | (let* ((c 60) (h (floor (/ time 60))) (m (- time (* 60 h))) | ||
| 19195 | (l (if level (org-get-valid-level level 0) 0)) | ||
| 19196 | (off 0) | ||
| 19197 | ov tx) | ||
| 19198 | (move-to-column c) | ||
| 19199 | (unless (eolp) (skip-chars-backward "^ \t")) | ||
| 19200 | (skip-chars-backward " \t") | ||
| 19201 | (setq ov (org-make-overlay (1- (point)) (point-at-eol)) | ||
| 19202 | tx (concat (buffer-substring (1- (point)) (point)) | ||
| 19203 | (make-string (+ off (max 0 (- c (current-column)))) ?.) | ||
| 19204 | (org-add-props (format "%s %2d:%02d%s" | ||
| 19205 | (make-string l ?*) h m | ||
| 19206 | (make-string (- 16 l) ?\ )) | ||
| 19207 | '(face secondary-selection)) | ||
| 19208 | "")) | ||
| 19209 | (if (not (featurep 'xemacs)) | ||
| 19210 | (org-overlay-put ov 'display tx) | ||
| 19211 | (org-overlay-put ov 'invisible t) | ||
| 19212 | (org-overlay-put ov 'end-glyph (make-glyph tx))) | ||
| 19213 | (push ov org-clock-overlays))) | ||
| 19214 | |||
| 19215 | (defun org-remove-clock-overlays (&optional beg end noremove) | ||
| 19216 | "Remove the occur highlights from the buffer. | ||
| 19217 | BEG and END are ignored. If NOREMOVE is nil, remove this function | ||
| 19218 | from the `before-change-functions' in the current buffer." | ||
| 19219 | (interactive) | ||
| 19220 | (unless org-inhibit-highlight-removal | ||
| 19221 | (mapc 'org-delete-overlay org-clock-overlays) | ||
| 19222 | (setq org-clock-overlays nil) | ||
| 19223 | (unless noremove | ||
| 19224 | (remove-hook 'before-change-functions | ||
| 19225 | 'org-remove-clock-overlays 'local)))) | ||
| 19226 | |||
| 19227 | (defun org-clock-out-if-current () | ||
| 19228 | "Clock out if the current entry contains the running clock. | ||
| 19229 | This is used to stop the clock after a TODO entry is marked DONE, | ||
| 19230 | and is only done if the variable `org-clock-out-when-done' is not nil." | ||
| 19231 | (when (and org-clock-out-when-done | ||
| 19232 | (member state org-done-keywords) | ||
| 19233 | (equal (marker-buffer org-clock-marker) (current-buffer)) | ||
| 19234 | (< (point) org-clock-marker) | ||
| 19235 | (> (save-excursion (outline-next-heading) (point)) | ||
| 19236 | org-clock-marker)) | ||
| 19237 | ;; Clock out, but don't accept a logging message for this. | ||
| 19238 | (let ((org-log-note-clock-out nil)) | ||
| 19239 | (org-clock-out)))) | ||
| 19240 | |||
| 19241 | (add-hook 'org-after-todo-state-change-hook | ||
| 19242 | 'org-clock-out-if-current) | ||
| 19243 | |||
| 19244 | (defun org-check-running-clock () | ||
| 19245 | "Check if the current buffer contains the running clock. | ||
| 19246 | If yes, offer to stop it and to save the buffer with the changes." | ||
| 19247 | (when (and (equal (marker-buffer org-clock-marker) (current-buffer)) | ||
| 19248 | (y-or-n-p (format "Clock-out in buffer %s before killing it? " | ||
| 19249 | (buffer-name)))) | ||
| 19250 | (org-clock-out) | ||
| 19251 | (when (y-or-n-p "Save changed buffer?") | ||
| 19252 | (save-buffer)))) | ||
| 19253 | |||
| 19254 | (defun org-clock-report (&optional arg) | ||
| 19255 | "Create a table containing a report about clocked time. | ||
| 19256 | If the cursor is inside an existing clocktable block, then the table | ||
| 19257 | will be updated. If not, a new clocktable will be inserted. | ||
| 19258 | When called with a prefix argument, move to the first clock table in the | ||
| 19259 | buffer and update it." | ||
| 19260 | (interactive "P") | ||
| 19261 | (org-remove-clock-overlays) | ||
| 19262 | (when arg | ||
| 19263 | (org-find-dblock "clocktable") | ||
| 19264 | (org-show-entry)) | ||
| 19265 | (if (org-in-clocktable-p) | ||
| 19266 | (goto-char (org-in-clocktable-p)) | ||
| 19267 | (org-create-dblock (list :name "clocktable" | ||
| 19268 | :maxlevel 2 :scope 'file))) | ||
| 19269 | (org-update-dblock)) | ||
| 19270 | |||
| 19271 | (defun org-in-clocktable-p () | ||
| 19272 | "Check if the cursor is in a clocktable." | ||
| 19273 | (let ((pos (point)) start) | ||
| 19274 | (save-excursion | ||
| 19275 | (end-of-line 1) | ||
| 19276 | (and (re-search-backward "^#\\+BEGIN:[ \t]+clocktable" nil t) | ||
| 19277 | (setq start (match-beginning 0)) | ||
| 19278 | (re-search-forward "^#\\+END:.*" nil t) | ||
| 19279 | (>= (match-end 0) pos) | ||
| 19280 | start)))) | ||
| 19281 | |||
| 19282 | (defun org-clock-update-time-maybe () | ||
| 19283 | "If this is a CLOCK line, update it and return t. | ||
| 19284 | Otherwise, return nil." | ||
| 19285 | (interactive) | ||
| 19286 | (save-excursion | ||
| 19287 | (beginning-of-line 1) | ||
| 19288 | (skip-chars-forward " \t") | ||
| 19289 | (when (looking-at org-clock-string) | ||
| 19290 | (let ((re (concat "[ \t]*" org-clock-string | ||
| 19291 | " *[[<]\\([^]>]+\\)[]>]-+[[<]\\([^]>]+\\)[]>]" | ||
| 19292 | "\\([ \t]*=>.*\\)?")) | ||
| 19293 | ts te h m s) | ||
| 19294 | (if (not (looking-at re)) | ||
| 19295 | nil | ||
| 19296 | (and (match-end 3) (delete-region (match-beginning 3) (match-end 3))) | ||
| 19297 | (end-of-line 1) | ||
| 19298 | (setq ts (match-string 1) | ||
| 19299 | te (match-string 2)) | ||
| 19300 | (setq s (- (time-to-seconds | ||
| 19301 | (apply 'encode-time (org-parse-time-string te))) | ||
| 19302 | (time-to-seconds | ||
| 19303 | (apply 'encode-time (org-parse-time-string ts)))) | ||
| 19304 | h (floor (/ s 3600)) | ||
| 19305 | s (- s (* 3600 h)) | ||
| 19306 | m (floor (/ s 60)) | ||
| 19307 | s (- s (* 60 s))) | ||
| 19308 | (insert " => " (format "%2d:%02d" h m)) | ||
| 19309 | t))))) | ||
| 19310 | |||
| 19311 | (defun org-clock-special-range (key &optional time as-strings) | ||
| 19312 | "Return two times bordering a special time range. | ||
| 19313 | Key is a symbol specifying the range and can be one of `today', `yesterday', | ||
| 19314 | `thisweek', `lastweek', `thismonth', `lastmonth', `thisyear', `lastyear'. | ||
| 19315 | A week starts Monday 0:00 and ends Sunday 24:00. | ||
| 19316 | The range is determined relative to TIME. TIME defaults to the current time. | ||
| 19317 | The return value is a cons cell with two internal times like the ones | ||
| 19318 | returned by `current time' or `encode-time'. if AS-STRINGS is non-nil, | ||
| 19319 | the returned times will be formatted strings." | ||
| 19320 | (let* ((tm (decode-time (or time (current-time)))) | ||
| 19321 | (s 0) (m (nth 1 tm)) (h (nth 2 tm)) | ||
| 19322 | (d (nth 3 tm)) (month (nth 4 tm)) (y (nth 5 tm)) | ||
| 19323 | (dow (nth 6 tm)) | ||
| 19324 | s1 m1 h1 d1 month1 y1 diff ts te fm) | ||
| 19325 | (cond | ||
| 19326 | ((eq key 'today) | ||
| 19327 | (setq h 0 m 0 h1 24 m1 0)) | ||
| 19328 | ((eq key 'yesterday) | ||
| 19329 | (setq d (1- d) h 0 m 0 h1 24 m1 0)) | ||
| 19330 | ((eq key 'thisweek) | ||
| 19331 | (setq diff (if (= dow 0) 6 (1- dow)) | ||
| 19332 | m 0 h 0 d (- d diff) d1 (+ 7 d))) | ||
| 19333 | ((eq key 'lastweek) | ||
| 19334 | (setq diff (+ 7 (if (= dow 0) 6 (1- dow))) | ||
| 19335 | m 0 h 0 d (- d diff) d1 (+ 7 d))) | ||
| 19336 | ((eq key 'thismonth) | ||
| 19337 | (setq d 1 h 0 m 0 d1 1 month1 (1+ month) h1 0 m1 0)) | ||
| 19338 | ((eq key 'lastmonth) | ||
| 19339 | (setq d 1 h 0 m 0 d1 1 month (1- month) month1 (1+ month) h1 0 m1 0)) | ||
| 19340 | ((eq key 'thisyear) | ||
| 19341 | (setq m 0 h 0 d 1 month 1 y1 (1+ y))) | ||
| 19342 | ((eq key 'lastyear) | ||
| 19343 | (setq m 0 h 0 d 1 month 1 y (1- y) y1 (1+ y))) | ||
| 19344 | (t (error "No such time block %s" key))) | ||
| 19345 | (setq ts (encode-time s m h d month y) | ||
| 19346 | te (encode-time (or s1 s) (or m1 m) (or h1 h) | ||
| 19347 | (or d1 d) (or month1 month) (or y1 y))) | ||
| 19348 | (setq fm (cdr org-time-stamp-formats)) | ||
| 19349 | (if as-strings | ||
| 19350 | (cons (format-time-string fm ts) (format-time-string fm te)) | ||
| 19351 | (cons ts te)))) | ||
| 19352 | |||
| 19353 | (defun org-dblock-write:clocktable (params) | ||
| 19354 | "Write the standard clocktable." | ||
| 19355 | (catch 'exit | ||
| 19356 | (let* ((hlchars '((1 . "*") (2 . "/"))) | ||
| 19357 | (ins (make-marker)) | ||
| 19358 | (total-time nil) | ||
| 19359 | (scope (plist-get params :scope)) | ||
| 19360 | (tostring (plist-get params :tostring)) | ||
| 19361 | (multifile (plist-get params :multifile)) | ||
| 19362 | (header (plist-get params :header)) | ||
| 19363 | (maxlevel (or (plist-get params :maxlevel) 3)) | ||
| 19364 | (step (plist-get params :step)) | ||
| 19365 | (emph (plist-get params :emphasize)) | ||
| 19366 | (ts (plist-get params :tstart)) | ||
| 19367 | (te (plist-get params :tend)) | ||
| 19368 | (block (plist-get params :block)) | ||
| 19369 | (link (plist-get params :link)) | ||
| 19370 | ipos time h m p level hlc hdl | ||
| 19371 | cc beg end pos tbl) | ||
| 19372 | (when step | ||
| 19373 | (org-clocktable-steps params) | ||
| 19374 | (throw 'exit nil)) | ||
| 19375 | (when block | ||
| 19376 | (setq cc (org-clock-special-range block nil t) | ||
| 19377 | ts (car cc) te (cdr cc))) | ||
| 19378 | (if ts (setq ts (time-to-seconds | ||
| 19379 | (apply 'encode-time (org-parse-time-string ts))))) | ||
| 19380 | (if te (setq te (time-to-seconds | ||
| 19381 | (apply 'encode-time (org-parse-time-string te))))) | ||
| 19382 | (move-marker ins (point)) | ||
| 19383 | (setq ipos (point)) | ||
| 19384 | |||
| 19385 | ;; Get the right scope | ||
| 19386 | (setq pos (point)) | ||
| 19387 | (save-restriction | ||
| 19388 | (cond | ||
| 19389 | ((not scope)) | ||
| 19390 | ((eq scope 'file) (widen)) | ||
| 19391 | ((eq scope 'subtree) (org-narrow-to-subtree)) | ||
| 19392 | ((eq scope 'tree) | ||
| 19393 | (while (org-up-heading-safe)) | ||
| 19394 | (org-narrow-to-subtree)) | ||
| 19395 | ((and (symbolp scope) (string-match "^tree\\([0-9]+\\)$" | ||
| 19396 | (symbol-name scope))) | ||
| 19397 | (setq level (string-to-number (match-string 1 (symbol-name scope)))) | ||
| 19398 | (catch 'exit | ||
| 19399 | (while (org-up-heading-safe) | ||
| 19400 | (looking-at outline-regexp) | ||
| 19401 | (if (<= (org-reduced-level (funcall outline-level)) level) | ||
| 19402 | (throw 'exit nil)))) | ||
| 19403 | (org-narrow-to-subtree)) | ||
| 19404 | ((or (listp scope) (eq scope 'agenda)) | ||
| 19405 | (let* ((files (if (listp scope) scope (org-agenda-files))) | ||
| 19406 | (scope 'agenda) | ||
| 19407 | (p1 (copy-sequence params)) | ||
| 19408 | file) | ||
| 19409 | (plist-put p1 :tostring t) | ||
| 19410 | (plist-put p1 :multifile t) | ||
| 19411 | (plist-put p1 :scope 'file) | ||
| 19412 | (org-prepare-agenda-buffers files) | ||
| 19413 | (while (setq file (pop files)) | ||
| 19414 | (with-current-buffer (find-buffer-visiting file) | ||
| 19415 | (push (org-clocktable-add-file | ||
| 19416 | file (org-dblock-write:clocktable p1)) tbl) | ||
| 19417 | (setq total-time (+ (or total-time 0) | ||
| 19418 | org-clock-file-total-minutes))))))) | ||
| 19419 | (goto-char pos) | ||
| 19420 | |||
| 19421 | (unless (eq scope 'agenda) | ||
| 19422 | (org-clock-sum ts te) | ||
| 19423 | (goto-char (point-min)) | ||
| 19424 | (while (setq p (next-single-property-change (point) :org-clock-minutes)) | ||
| 19425 | (goto-char p) | ||
| 19426 | (when (setq time (get-text-property p :org-clock-minutes)) | ||
| 19427 | (save-excursion | ||
| 19428 | (beginning-of-line 1) | ||
| 19429 | (when (and (looking-at (org-re "\\(\\*+\\)[ \t]+\\(.*?\\)\\([ \t]+:[[:alnum:]_@:]+:\\)?[ \t]*$")) | ||
| 19430 | (setq level (org-reduced-level | ||
| 19431 | (- (match-end 1) (match-beginning 1)))) | ||
| 19432 | (<= level maxlevel)) | ||
| 19433 | (setq hlc (if emph (or (cdr (assoc level hlchars)) "") "") | ||
| 19434 | hdl (if (not link) | ||
| 19435 | (match-string 2) | ||
| 19436 | (org-make-link-string | ||
| 19437 | (format "file:%s::%s" | ||
| 19438 | (buffer-file-name) | ||
| 19439 | (save-match-data | ||
| 19440 | (org-make-org-heading-search-string | ||
| 19441 | (match-string 2)))) | ||
| 19442 | (match-string 2))) | ||
| 19443 | h (/ time 60) | ||
| 19444 | m (- time (* 60 h))) | ||
| 19445 | (if (and (not multifile) (= level 1)) (push "|-" tbl)) | ||
| 19446 | (push (concat | ||
| 19447 | "| " (int-to-string level) "|" hlc hdl hlc " |" | ||
| 19448 | (make-string (1- level) ?|) | ||
| 19449 | hlc (format "%d:%02d" h m) hlc | ||
| 19450 | " |") tbl)))))) | ||
| 19451 | (setq tbl (nreverse tbl)) | ||
| 19452 | (if tostring | ||
| 19453 | (if tbl (mapconcat 'identity tbl "\n") nil) | ||
| 19454 | (goto-char ins) | ||
| 19455 | (insert-before-markers | ||
| 19456 | (or header | ||
| 19457 | (concat | ||
| 19458 | "Clock summary at [" | ||
| 19459 | (substring | ||
| 19460 | (format-time-string (cdr org-time-stamp-formats)) | ||
| 19461 | 1 -1) | ||
| 19462 | "]." | ||
| 19463 | (if block | ||
| 19464 | (format " Considered range is /%s/." block) | ||
| 19465 | "") | ||
| 19466 | "\n\n")) | ||
| 19467 | (if (eq scope 'agenda) "|File" "") | ||
| 19468 | "|L|Headline|Time|\n") | ||
| 19469 | (setq total-time (or total-time org-clock-file-total-minutes) | ||
| 19470 | h (/ total-time 60) | ||
| 19471 | m (- total-time (* 60 h))) | ||
| 19472 | (insert-before-markers | ||
| 19473 | "|-\n|" | ||
| 19474 | (if (eq scope 'agenda) "|" "") | ||
| 19475 | "|" | ||
| 19476 | "*Total time*| " | ||
| 19477 | (format "*%d:%02d*" h m) | ||
| 19478 | "|\n|-\n") | ||
| 19479 | (setq tbl (delq nil tbl)) | ||
| 19480 | (if (and (stringp (car tbl)) (> (length (car tbl)) 1) | ||
| 19481 | (equal (substring (car tbl) 0 2) "|-")) | ||
| 19482 | (pop tbl)) | ||
| 19483 | (insert-before-markers (mapconcat | ||
| 19484 | 'identity (delq nil tbl) | ||
| 19485 | (if (eq scope 'agenda) "\n|-\n" "\n"))) | ||
| 19486 | (backward-delete-char 1) | ||
| 19487 | (goto-char ipos) | ||
| 19488 | (skip-chars-forward "^|") | ||
| 19489 | (org-table-align)))))) | ||
| 19490 | |||
| 19491 | (defun org-clocktable-steps (params) | ||
| 19492 | (let* ((p1 (copy-sequence params)) | ||
| 19493 | (ts (plist-get p1 :tstart)) | ||
| 19494 | (te (plist-get p1 :tend)) | ||
| 19495 | (step0 (plist-get p1 :step)) | ||
| 19496 | (step (cdr (assoc step0 '((day . 86400) (week . 604800))))) | ||
| 19497 | (block (plist-get p1 :block)) | ||
| 19498 | cc) | ||
| 19499 | (when block | ||
| 19500 | (setq cc (org-clock-special-range block nil t) | ||
| 19501 | ts (car cc) te (cdr cc))) | ||
| 19502 | (if ts (setq ts (time-to-seconds | ||
| 19503 | (apply 'encode-time (org-parse-time-string ts))))) | ||
| 19504 | (if te (setq te (time-to-seconds | ||
| 19505 | (apply 'encode-time (org-parse-time-string te))))) | ||
| 19506 | (plist-put p1 :header "") | ||
| 19507 | (plist-put p1 :step nil) | ||
| 19508 | (plist-put p1 :block nil) | ||
| 19509 | (while (< ts te) | ||
| 19510 | (or (bolp) (insert "\n")) | ||
| 19511 | (plist-put p1 :tstart (format-time-string | ||
| 19512 | (car org-time-stamp-formats) | ||
| 19513 | (seconds-to-time ts))) | ||
| 19514 | (plist-put p1 :tend (format-time-string | ||
| 19515 | (car org-time-stamp-formats) | ||
| 19516 | (seconds-to-time (setq ts (+ ts step))))) | ||
| 19517 | (insert "\n" (if (eq step0 'day) "Daily report: " "Weekly report starting on: ") | ||
| 19518 | (plist-get p1 :tstart) "\n") | ||
| 19519 | (org-dblock-write:clocktable p1) | ||
| 19520 | (re-search-forward "#\\+END:") | ||
| 19521 | (end-of-line 0)))) | ||
| 19522 | |||
| 19523 | |||
| 19524 | (defun org-clocktable-add-file (file table) | ||
| 19525 | (if table | ||
| 19526 | (let ((lines (org-split-string table "\n")) | ||
| 19527 | (ff (file-name-nondirectory file))) | ||
| 19528 | (mapconcat 'identity | ||
| 19529 | (mapcar (lambda (x) | ||
| 19530 | (if (string-match org-table-dataline-regexp x) | ||
| 19531 | (concat "|" ff x) | ||
| 19532 | x)) | ||
| 19533 | lines) | ||
| 19534 | "\n")))) | ||
| 19535 | |||
| 19536 | ;; FIXME: I don't think anybody uses this, ask David | ||
| 19537 | (defun org-collect-clock-time-entries () | ||
| 19538 | "Return an internal list with clocking information. | ||
| 19539 | This list has one entry for each CLOCK interval. | ||
| 19540 | FIXME: describe the elements." | ||
| 19541 | (interactive) | ||
| 19542 | (let ((re (concat "^[ \t]*" org-clock-string | ||
| 19543 | " *\\[\\(.*?\\)\\]--\\[\\(.*?\\)\\]")) | ||
| 19544 | rtn beg end next cont level title total closedp leafp | ||
| 19545 | clockpos titlepos h m donep) | ||
| 19546 | (save-excursion | ||
| 19547 | (org-clock-sum) | ||
| 19548 | (goto-char (point-min)) | ||
| 19549 | (while (re-search-forward re nil t) | ||
| 19550 | (setq clockpos (match-beginning 0) | ||
| 19551 | beg (match-string 1) end (match-string 2) | ||
| 19552 | cont (match-end 0)) | ||
| 19553 | (setq beg (apply 'encode-time (org-parse-time-string beg)) | ||
| 19554 | end (apply 'encode-time (org-parse-time-string end))) | ||
| 19555 | (org-back-to-heading t) | ||
| 19556 | (setq donep (org-entry-is-done-p)) | ||
| 19557 | (setq titlepos (point) | ||
| 19558 | total (or (get-text-property (1+ (point)) :org-clock-minutes) 0) | ||
| 19559 | h (/ total 60) m (- total (* 60 h)) | ||
| 19560 | total (cons h m)) | ||
| 19561 | (looking-at "\\(\\*+\\) +\\(.*\\)") | ||
| 19562 | (setq level (- (match-end 1) (match-beginning 1)) | ||
| 19563 | title (org-match-string-no-properties 2)) | ||
| 19564 | (save-excursion (outline-next-heading) (setq next (point))) | ||
| 19565 | (setq closedp (re-search-forward org-closed-time-regexp next t)) | ||
| 19566 | (goto-char next) | ||
| 19567 | (setq leafp (and (looking-at "^\\*+ ") | ||
| 19568 | (<= (- (match-end 0) (point)) level))) | ||
| 19569 | (push (list beg end clockpos closedp donep | ||
| 19570 | total title titlepos level leafp) | ||
| 19571 | rtn) | ||
| 19572 | (goto-char cont))) | ||
| 19573 | (nreverse rtn))) | ||
| 19574 | |||
| 19575 | ;;;; Agenda, and Diary Integration | ||
| 19576 | |||
| 19577 | ;;; Define the Org-agenda-mode | ||
| 19578 | |||
| 19579 | (defvar org-agenda-mode-map (make-sparse-keymap) | ||
| 19580 | "Keymap for `org-agenda-mode'.") | ||
| 19581 | |||
| 19582 | (defvar org-agenda-menu) ; defined later in this file. | ||
| 19583 | (defvar org-agenda-follow-mode nil) | ||
| 19584 | (defvar org-agenda-show-log nil) | ||
| 19585 | (defvar org-agenda-redo-command nil) | ||
| 19586 | (defvar org-agenda-query-string nil) | ||
| 19587 | (defvar org-agenda-mode-hook nil) | ||
| 19588 | (defvar org-agenda-type nil) | ||
| 19589 | (defvar org-agenda-force-single-file nil) | ||
| 19590 | |||
| 19591 | (defun org-agenda-mode () | ||
| 19592 | "Mode for time-sorted view on action items in Org-mode files. | ||
| 19593 | |||
| 19594 | The following commands are available: | ||
| 19595 | |||
| 19596 | \\{org-agenda-mode-map}" | ||
| 19597 | (interactive) | ||
| 19598 | (kill-all-local-variables) | ||
| 19599 | (setq org-agenda-undo-list nil | ||
| 19600 | org-agenda-pending-undo-list nil) | ||
| 19601 | (setq major-mode 'org-agenda-mode) | ||
| 19602 | ;; Keep global-font-lock-mode from turning on font-lock-mode | ||
| 19603 | (org-set-local 'font-lock-global-modes (list 'not major-mode)) | ||
| 19604 | (setq mode-name "Org-Agenda") | ||
| 19605 | (use-local-map org-agenda-mode-map) | ||
| 19606 | (easy-menu-add org-agenda-menu) | ||
| 19607 | (if org-startup-truncated (setq truncate-lines t)) | ||
| 19608 | (org-add-hook 'post-command-hook 'org-agenda-post-command-hook nil 'local) | ||
| 19609 | (org-add-hook 'pre-command-hook 'org-unhighlight nil 'local) | ||
| 19610 | ;; Make sure properties are removed when copying text | ||
| 19611 | (when (boundp 'buffer-substring-filters) | ||
| 19612 | (org-set-local 'buffer-substring-filters | ||
| 19613 | (cons (lambda (x) | ||
| 19614 | (set-text-properties 0 (length x) nil x) x) | ||
| 19615 | buffer-substring-filters))) | ||
| 19616 | (unless org-agenda-keep-modes | ||
| 19617 | (setq org-agenda-follow-mode org-agenda-start-with-follow-mode | ||
| 19618 | org-agenda-show-log nil)) | ||
| 19619 | (easy-menu-change | ||
| 19620 | '("Agenda") "Agenda Files" | ||
| 19621 | (append | ||
| 19622 | (list | ||
| 19623 | (vector | ||
| 19624 | (if (get 'org-agenda-files 'org-restrict) | ||
| 19625 | "Restricted to single file" | ||
| 19626 | "Edit File List") | ||
| 19627 | '(org-edit-agenda-file-list) | ||
| 19628 | (not (get 'org-agenda-files 'org-restrict))) | ||
| 19629 | "--") | ||
| 19630 | (mapcar 'org-file-menu-entry (org-agenda-files)))) | ||
| 19631 | (org-agenda-set-mode-name) | ||
| 19632 | (apply | ||
| 19633 | (if (fboundp 'run-mode-hooks) 'run-mode-hooks 'run-hooks) | ||
| 19634 | (list 'org-agenda-mode-hook))) | ||
| 19635 | |||
| 19636 | (substitute-key-definition 'undo 'org-agenda-undo | ||
| 19637 | org-agenda-mode-map global-map) | ||
| 19638 | (org-defkey org-agenda-mode-map "\C-i" 'org-agenda-goto) | ||
| 19639 | (org-defkey org-agenda-mode-map [(tab)] 'org-agenda-goto) | ||
| 19640 | (org-defkey org-agenda-mode-map "\C-m" 'org-agenda-switch-to) | ||
| 19641 | (org-defkey org-agenda-mode-map "\C-k" 'org-agenda-kill) | ||
| 19642 | (org-defkey org-agenda-mode-map "\C-c$" 'org-agenda-archive) | ||
| 19643 | (org-defkey org-agenda-mode-map "\C-c\C-x\C-s" 'org-agenda-archive) | ||
| 19644 | (org-defkey org-agenda-mode-map "$" 'org-agenda-archive) | ||
| 19645 | (org-defkey org-agenda-mode-map "\C-c\C-o" 'org-agenda-open-link) | ||
| 19646 | (org-defkey org-agenda-mode-map " " 'org-agenda-show) | ||
| 19647 | (org-defkey org-agenda-mode-map "\C-c\C-t" 'org-agenda-todo) | ||
| 19648 | (org-defkey org-agenda-mode-map [(control shift right)] 'org-agenda-todo-nextset) | ||
| 19649 | (org-defkey org-agenda-mode-map [(control shift left)] 'org-agenda-todo-previousset) | ||
| 19650 | (org-defkey org-agenda-mode-map "\C-c\C-xb" 'org-agenda-tree-to-indirect-buffer) | ||
| 19651 | (org-defkey org-agenda-mode-map "b" 'org-agenda-tree-to-indirect-buffer) | ||
| 19652 | (org-defkey org-agenda-mode-map "o" 'delete-other-windows) | ||
| 19653 | (org-defkey org-agenda-mode-map "L" 'org-agenda-recenter) | ||
| 19654 | (org-defkey org-agenda-mode-map "t" 'org-agenda-todo) | ||
| 19655 | (org-defkey org-agenda-mode-map "a" 'org-agenda-toggle-archive-tag) | ||
| 19656 | (org-defkey org-agenda-mode-map ":" 'org-agenda-set-tags) | ||
| 19657 | (org-defkey org-agenda-mode-map "." 'org-agenda-goto-today) | ||
| 19658 | (org-defkey org-agenda-mode-map "j" 'org-agenda-goto-date) | ||
| 19659 | (org-defkey org-agenda-mode-map "d" 'org-agenda-day-view) | ||
| 19660 | (org-defkey org-agenda-mode-map "w" 'org-agenda-week-view) | ||
| 19661 | (org-defkey org-agenda-mode-map "m" 'org-agenda-month-view) | ||
| 19662 | (org-defkey org-agenda-mode-map "y" 'org-agenda-year-view) | ||
| 19663 | (org-defkey org-agenda-mode-map [(shift right)] 'org-agenda-date-later) | ||
| 19664 | (org-defkey org-agenda-mode-map [(shift left)] 'org-agenda-date-earlier) | ||
| 19665 | (org-defkey org-agenda-mode-map [?\C-c ?\C-x (right)] 'org-agenda-date-later) | ||
| 19666 | (org-defkey org-agenda-mode-map [?\C-c ?\C-x (left)] 'org-agenda-date-earlier) | ||
| 19667 | |||
| 19668 | (org-defkey org-agenda-mode-map ">" 'org-agenda-date-prompt) | ||
| 19669 | (org-defkey org-agenda-mode-map "\C-c\C-s" 'org-agenda-schedule) | ||
| 19670 | (org-defkey org-agenda-mode-map "\C-c\C-d" 'org-agenda-deadline) | ||
| 19671 | (let ((l '(1 2 3 4 5 6 7 8 9 0))) | ||
| 19672 | (while l (org-defkey org-agenda-mode-map | ||
| 19673 | (int-to-string (pop l)) 'digit-argument))) | ||
| 19674 | |||
| 19675 | (org-defkey org-agenda-mode-map "f" 'org-agenda-follow-mode) | ||
| 19676 | (org-defkey org-agenda-mode-map "l" 'org-agenda-log-mode) | ||
| 19677 | (org-defkey org-agenda-mode-map "D" 'org-agenda-toggle-diary) | ||
| 19678 | (org-defkey org-agenda-mode-map "G" 'org-agenda-toggle-time-grid) | ||
| 19679 | (org-defkey org-agenda-mode-map "r" 'org-agenda-redo) | ||
| 19680 | (org-defkey org-agenda-mode-map "g" 'org-agenda-redo) | ||
| 19681 | (org-defkey org-agenda-mode-map "e" 'org-agenda-execute) | ||
| 19682 | (org-defkey org-agenda-mode-map "q" 'org-agenda-quit) | ||
| 19683 | (org-defkey org-agenda-mode-map "x" 'org-agenda-exit) | ||
| 19684 | (org-defkey org-agenda-mode-map "\C-x\C-w" 'org-write-agenda) | ||
| 19685 | (org-defkey org-agenda-mode-map "s" 'org-save-all-org-buffers) | ||
| 19686 | (org-defkey org-agenda-mode-map "\C-x\C-s" 'org-save-all-org-buffers) | ||
| 19687 | (org-defkey org-agenda-mode-map "P" 'org-agenda-show-priority) | ||
| 19688 | (org-defkey org-agenda-mode-map "T" 'org-agenda-show-tags) | ||
| 19689 | (org-defkey org-agenda-mode-map "n" 'next-line) | ||
| 19690 | (org-defkey org-agenda-mode-map "p" 'previous-line) | ||
| 19691 | (org-defkey org-agenda-mode-map "\C-c\C-n" 'org-agenda-next-date-line) | ||
| 19692 | (org-defkey org-agenda-mode-map "\C-c\C-p" 'org-agenda-previous-date-line) | ||
| 19693 | (org-defkey org-agenda-mode-map "," 'org-agenda-priority) | ||
| 19694 | (org-defkey org-agenda-mode-map "\C-c," 'org-agenda-priority) | ||
| 19695 | (org-defkey org-agenda-mode-map "i" 'org-agenda-diary-entry) | ||
| 19696 | (org-defkey org-agenda-mode-map "c" 'org-agenda-goto-calendar) | ||
| 19697 | (eval-after-load "calendar" | ||
| 19698 | '(org-defkey calendar-mode-map org-calendar-to-agenda-key | ||
| 19699 | 'org-calendar-goto-agenda)) | ||
| 19700 | (org-defkey org-agenda-mode-map "C" 'org-agenda-convert-date) | ||
| 19701 | (org-defkey org-agenda-mode-map "M" 'org-agenda-phases-of-moon) | ||
| 19702 | (org-defkey org-agenda-mode-map "S" 'org-agenda-sunrise-sunset) | ||
| 19703 | (org-defkey org-agenda-mode-map "h" 'org-agenda-holidays) | ||
| 19704 | (org-defkey org-agenda-mode-map "H" 'org-agenda-holidays) | ||
| 19705 | (org-defkey org-agenda-mode-map "\C-c\C-x\C-i" 'org-agenda-clock-in) | ||
| 19706 | (org-defkey org-agenda-mode-map "I" 'org-agenda-clock-in) | ||
| 19707 | (org-defkey org-agenda-mode-map "\C-c\C-x\C-o" 'org-agenda-clock-out) | ||
| 19708 | (org-defkey org-agenda-mode-map "O" 'org-agenda-clock-out) | ||
| 19709 | (org-defkey org-agenda-mode-map "\C-c\C-x\C-x" 'org-agenda-clock-cancel) | ||
| 19710 | (org-defkey org-agenda-mode-map "X" 'org-agenda-clock-cancel) | ||
| 19711 | (org-defkey org-agenda-mode-map "\C-c\C-x\C-j" 'org-clock-goto) | ||
| 19712 | (org-defkey org-agenda-mode-map "J" 'org-clock-goto) | ||
| 19713 | (org-defkey org-agenda-mode-map "+" 'org-agenda-priority-up) | ||
| 19714 | (org-defkey org-agenda-mode-map "-" 'org-agenda-priority-down) | ||
| 19715 | (org-defkey org-agenda-mode-map [(shift up)] 'org-agenda-priority-up) | ||
| 19716 | (org-defkey org-agenda-mode-map [(shift down)] 'org-agenda-priority-down) | ||
| 19717 | (org-defkey org-agenda-mode-map [?\C-c ?\C-x (up)] 'org-agenda-priority-up) | ||
| 19718 | (org-defkey org-agenda-mode-map [?\C-c ?\C-x (down)] 'org-agenda-priority-down) | ||
| 19719 | (org-defkey org-agenda-mode-map [(right)] 'org-agenda-later) | ||
| 19720 | (org-defkey org-agenda-mode-map [(left)] 'org-agenda-earlier) | ||
| 19721 | (org-defkey org-agenda-mode-map "\C-c\C-x\C-c" 'org-agenda-columns) | ||
| 19722 | |||
| 19723 | (org-defkey org-agenda-mode-map "[" 'org-agenda-manipulate-query-add) | ||
| 19724 | (org-defkey org-agenda-mode-map "]" 'org-agenda-manipulate-query-subtract) | ||
| 19725 | (org-defkey org-agenda-mode-map "{" 'org-agenda-manipulate-query-add-re) | ||
| 19726 | (org-defkey org-agenda-mode-map "}" 'org-agenda-manipulate-query-subtract-re) | ||
| 19727 | |||
| 19728 | (defvar org-agenda-keymap (copy-keymap org-agenda-mode-map) | ||
| 19729 | "Local keymap for agenda entries from Org-mode.") | ||
| 19730 | |||
| 19731 | (org-defkey org-agenda-keymap | ||
| 19732 | (if (featurep 'xemacs) [(button2)] [(mouse-2)]) 'org-agenda-goto-mouse) | ||
| 19733 | (org-defkey org-agenda-keymap | ||
| 19734 | (if (featurep 'xemacs) [(button3)] [(mouse-3)]) 'org-agenda-show-mouse) | ||
| 19735 | (when org-agenda-mouse-1-follows-link | ||
| 19736 | (org-defkey org-agenda-keymap [follow-link] 'mouse-face)) | ||
| 19737 | (easy-menu-define org-agenda-menu org-agenda-mode-map "Agenda menu" | ||
| 19738 | '("Agenda" | ||
| 19739 | ("Agenda Files") | ||
| 19740 | "--" | ||
| 19741 | ["Show" org-agenda-show t] | ||
| 19742 | ["Go To (other window)" org-agenda-goto t] | ||
| 19743 | ["Go To (this window)" org-agenda-switch-to t] | ||
| 19744 | ["Follow Mode" org-agenda-follow-mode | ||
| 19745 | :style toggle :selected org-agenda-follow-mode :active t] | ||
| 19746 | ["Tree to indirect frame" org-agenda-tree-to-indirect-buffer t] | ||
| 19747 | "--" | ||
| 19748 | ["Cycle TODO" org-agenda-todo t] | ||
| 19749 | ["Archive subtree" org-agenda-archive t] | ||
| 19750 | ["Delete subtree" org-agenda-kill t] | ||
| 19751 | "--" | ||
| 19752 | ["Goto Today" org-agenda-goto-today (org-agenda-check-type nil 'agenda 'timeline)] | ||
| 19753 | ["Next Dates" org-agenda-later (org-agenda-check-type nil 'agenda)] | ||
| 19754 | ["Previous Dates" org-agenda-earlier (org-agenda-check-type nil 'agenda)] | ||
| 19755 | ["Jump to date" org-agenda-goto-date (org-agenda-check-type nil 'agenda)] | ||
| 19756 | "--" | ||
| 19757 | ("Tags and Properties" | ||
| 19758 | ["Show all Tags" org-agenda-show-tags t] | ||
| 19759 | ["Set Tags current line" org-agenda-set-tags (not (org-region-active-p))] | ||
| 19760 | ["Change tag in region" org-agenda-set-tags (org-region-active-p)] | ||
| 19761 | "--" | ||
| 19762 | ["Column View" org-columns t]) | ||
| 19763 | ("Date/Schedule" | ||
| 19764 | ["Schedule" org-agenda-schedule t] | ||
| 19765 | ["Set Deadline" org-agenda-deadline t] | ||
| 19766 | "--" | ||
| 19767 | ["Change Date +1 day" org-agenda-date-later (org-agenda-check-type nil 'agenda 'timeline)] | ||
| 19768 | ["Change Date -1 day" org-agenda-date-earlier (org-agenda-check-type nil 'agenda 'timeline)] | ||
| 19769 | ["Change Date to ..." org-agenda-date-prompt (org-agenda-check-type nil 'agenda 'timeline)]) | ||
| 19770 | ("Clock" | ||
| 19771 | ["Clock in" org-agenda-clock-in t] | ||
| 19772 | ["Clock out" org-agenda-clock-out t] | ||
| 19773 | ["Clock cancel" org-agenda-clock-cancel t] | ||
| 19774 | ["Goto running clock" org-clock-goto t]) | ||
| 19775 | ("Priority" | ||
| 19776 | ["Set Priority" org-agenda-priority t] | ||
| 19777 | ["Increase Priority" org-agenda-priority-up t] | ||
| 19778 | ["Decrease Priority" org-agenda-priority-down t] | ||
| 19779 | ["Show Priority" org-agenda-show-priority t]) | ||
| 19780 | ("Calendar/Diary" | ||
| 19781 | ["New Diary Entry" org-agenda-diary-entry (org-agenda-check-type nil 'agenda 'timeline)] | ||
| 19782 | ["Goto Calendar" org-agenda-goto-calendar (org-agenda-check-type nil 'agenda 'timeline)] | ||
| 19783 | ["Phases of the Moon" org-agenda-phases-of-moon (org-agenda-check-type nil 'agenda 'timeline)] | ||
| 19784 | ["Sunrise/Sunset" org-agenda-sunrise-sunset (org-agenda-check-type nil 'agenda 'timeline)] | ||
| 19785 | ["Holidays" org-agenda-holidays (org-agenda-check-type nil 'agenda 'timeline)] | ||
| 19786 | ["Convert" org-agenda-convert-date (org-agenda-check-type nil 'agenda 'timeline)] | ||
| 19787 | "--" | ||
| 19788 | ["Create iCalendar file" org-export-icalendar-combine-agenda-files t]) | ||
| 19789 | "--" | ||
| 19790 | ("View" | ||
| 19791 | ["Day View" org-agenda-day-view :active (org-agenda-check-type nil 'agenda) | ||
| 19792 | :style radio :selected (equal org-agenda-ndays 1)] | ||
| 19793 | ["Week View" org-agenda-week-view :active (org-agenda-check-type nil 'agenda) | ||
| 19794 | :style radio :selected (equal org-agenda-ndays 7)] | ||
| 19795 | ["Month View" org-agenda-month-view :active (org-agenda-check-type nil 'agenda) | ||
| 19796 | :style radio :selected (member org-agenda-ndays '(28 29 30 31))] | ||
| 19797 | ["Year View" org-agenda-year-view :active (org-agenda-check-type nil 'agenda) | ||
| 19798 | :style radio :selected (member org-agenda-ndays '(365 366))] | ||
| 19799 | "--" | ||
| 19800 | ["Show Logbook entries" org-agenda-log-mode | ||
| 19801 | :style toggle :selected org-agenda-show-log :active (org-agenda-check-type nil 'agenda 'timeline)] | ||
| 19802 | ["Include Diary" org-agenda-toggle-diary | ||
| 19803 | :style toggle :selected org-agenda-include-diary :active (org-agenda-check-type nil 'agenda)] | ||
| 19804 | ["Use Time Grid" org-agenda-toggle-time-grid | ||
| 19805 | :style toggle :selected org-agenda-use-time-grid :active (org-agenda-check-type nil 'agenda)]) | ||
| 19806 | ["Write view to file" org-write-agenda t] | ||
| 19807 | ["Rebuild buffer" org-agenda-redo t] | ||
| 19808 | ["Save all Org-mode Buffers" org-save-all-org-buffers t] | ||
| 19809 | "--" | ||
| 19810 | ["Undo Remote Editing" org-agenda-undo org-agenda-undo-list] | ||
| 19811 | "--" | ||
| 19812 | ["Quit" org-agenda-quit t] | ||
| 19813 | ["Exit and Release Buffers" org-agenda-exit t] | ||
| 19814 | )) | ||
| 19815 | |||
| 19816 | ;;; Agenda undo | ||
| 19817 | |||
| 19818 | (defvar org-agenda-allow-remote-undo t | ||
| 19819 | "Non-nil means, allow remote undo from the agenda buffer.") | ||
| 19820 | (defvar org-agenda-undo-list nil | ||
| 19821 | "List of undoable operations in the agenda since last refresh.") | ||
| 19822 | (defvar org-agenda-undo-has-started-in nil | ||
| 19823 | "Buffers that have already seen `undo-start' in the current undo sequence.") | ||
| 19824 | (defvar org-agenda-pending-undo-list nil | ||
| 19825 | "In a series of undo commands, this is the list of remaning undo items.") | ||
| 19826 | |||
| 19827 | (defmacro org-if-unprotected (&rest body) | ||
| 19828 | "Execute BODY if there is no `org-protected' text property at point." | ||
| 19829 | (declare (debug t)) | ||
| 19830 | `(unless (get-text-property (point) 'org-protected) | ||
| 19831 | ,@body)) | ||
| 19832 | |||
| 19833 | (defmacro org-with-remote-undo (_buffer &rest _body) | ||
| 19834 | "Execute BODY while recording undo information in two buffers." | ||
| 19835 | (declare (indent 1) (debug t)) | ||
| 19836 | `(let ((_cline (org-current-line)) | ||
| 19837 | (_cmd this-command) | ||
| 19838 | (_buf1 (current-buffer)) | ||
| 19839 | (_buf2 ,_buffer) | ||
| 19840 | (_undo1 buffer-undo-list) | ||
| 19841 | (_undo2 (with-current-buffer ,_buffer buffer-undo-list)) | ||
| 19842 | _c1 _c2) | ||
| 19843 | ,@_body | ||
| 19844 | (when org-agenda-allow-remote-undo | ||
| 19845 | (setq _c1 (org-verify-change-for-undo | ||
| 19846 | _undo1 (with-current-buffer _buf1 buffer-undo-list)) | ||
| 19847 | _c2 (org-verify-change-for-undo | ||
| 19848 | _undo2 (with-current-buffer _buf2 buffer-undo-list))) | ||
| 19849 | (when (or _c1 _c2) | ||
| 19850 | ;; make sure there are undo boundaries | ||
| 19851 | (and _c1 (with-current-buffer _buf1 (undo-boundary))) | ||
| 19852 | (and _c2 (with-current-buffer _buf2 (undo-boundary))) | ||
| 19853 | ;; remember which buffer to undo | ||
| 19854 | (push (list _cmd _cline _buf1 _c1 _buf2 _c2) | ||
| 19855 | org-agenda-undo-list))))) | ||
| 19856 | |||
| 19857 | (defun org-agenda-undo () | ||
| 19858 | "Undo a remote editing step in the agenda. | ||
| 19859 | This undoes changes both in the agenda buffer and in the remote buffer | ||
| 19860 | that have been changed along." | ||
| 19861 | (interactive) | ||
| 19862 | (or org-agenda-allow-remote-undo | ||
| 19863 | (error "Check the variable `org-agenda-allow-remote-undo' to activate remote undo.")) | ||
| 19864 | (if (not (eq this-command last-command)) | ||
| 19865 | (setq org-agenda-undo-has-started-in nil | ||
| 19866 | org-agenda-pending-undo-list org-agenda-undo-list)) | ||
| 19867 | (if (not org-agenda-pending-undo-list) | ||
| 19868 | (error "No further undo information")) | ||
| 19869 | (let* ((entry (pop org-agenda-pending-undo-list)) | ||
| 19870 | buf line cmd rembuf) | ||
| 19871 | (setq cmd (pop entry) line (pop entry)) | ||
| 19872 | (setq rembuf (nth 2 entry)) | ||
| 19873 | (org-with-remote-undo rembuf | ||
| 19874 | (while (bufferp (setq buf (pop entry))) | ||
| 19875 | (if (pop entry) | ||
| 19876 | (with-current-buffer buf | ||
| 19877 | (let ((last-undo-buffer buf) | ||
| 19878 | (inhibit-read-only t)) | ||
| 19879 | (unless (memq buf org-agenda-undo-has-started-in) | ||
| 19880 | (push buf org-agenda-undo-has-started-in) | ||
| 19881 | (make-local-variable 'pending-undo-list) | ||
| 19882 | (undo-start)) | ||
| 19883 | (while (and pending-undo-list | ||
| 19884 | (listp pending-undo-list) | ||
| 19885 | (not (car pending-undo-list))) | ||
| 19886 | (pop pending-undo-list)) | ||
| 19887 | (undo-more 1)))))) | ||
| 19888 | (goto-line line) | ||
| 19889 | (message "`%s' undone (buffer %s)" cmd (buffer-name rembuf)))) | ||
| 19890 | |||
| 19891 | (defun org-verify-change-for-undo (l1 l2) | ||
| 19892 | "Verify that a real change occurred between the undo lists L1 and L2." | ||
| 19893 | (while (and l1 (listp l1) (null (car l1))) (pop l1)) | ||
| 19894 | (while (and l2 (listp l2) (null (car l2))) (pop l2)) | ||
| 19895 | (not (eq l1 l2))) | ||
| 19896 | |||
| 19897 | ;;; Agenda dispatch | ||
| 19898 | |||
| 19899 | (defvar org-agenda-restrict nil) | ||
| 19900 | (defvar org-agenda-restrict-begin (make-marker)) | ||
| 19901 | (defvar org-agenda-restrict-end (make-marker)) | ||
| 19902 | (defvar org-agenda-last-dispatch-buffer nil) | ||
| 19903 | (defvar org-agenda-overriding-restriction nil) | ||
| 19904 | |||
| 19905 | ;;;###autoload | ||
| 19906 | (defun org-agenda (arg &optional keys restriction) | ||
| 19907 | "Dispatch agenda commands to collect entries to the agenda buffer. | ||
| 19908 | Prompts for a command to execute. Any prefix arg will be passed | ||
| 19909 | on to the selected command. The default selections are: | ||
| 19910 | |||
| 19911 | a Call `org-agenda-list' to display the agenda for current day or week. | ||
| 19912 | t Call `org-todo-list' to display the global todo list. | ||
| 19913 | T Call `org-todo-list' to display the global todo list, select only | ||
| 19914 | entries with a specific TODO keyword (the user gets a prompt). | ||
| 19915 | m Call `org-tags-view' to display headlines with tags matching | ||
| 19916 | a condition (the user is prompted for the condition). | ||
| 19917 | M Like `m', but select only TODO entries, no ordinary headlines. | ||
| 19918 | L Create a timeline for the current buffer. | ||
| 19919 | e Export views to associated files. | ||
| 19920 | |||
| 19921 | More commands can be added by configuring the variable | ||
| 19922 | `org-agenda-custom-commands'. In particular, specific tags and TODO keyword | ||
| 19923 | searches can be pre-defined in this way. | ||
| 19924 | |||
| 19925 | If the current buffer is in Org-mode and visiting a file, you can also | ||
| 19926 | first press `<' once to indicate that the agenda should be temporarily | ||
| 19927 | \(until the next use of \\[org-agenda]) restricted to the current file. | ||
| 19928 | Pressing `<' twice means to restrict to the current subtree or region | ||
| 19929 | \(if active)." | ||
| 19930 | (interactive "P") | ||
| 19931 | (catch 'exit | ||
| 19932 | (let* ((prefix-descriptions nil) | ||
| 19933 | (org-agenda-custom-commands-orig org-agenda-custom-commands) | ||
| 19934 | (org-agenda-custom-commands | ||
| 19935 | ;; normalize different versions | ||
| 19936 | (delq nil | ||
| 19937 | (mapcar | ||
| 19938 | (lambda (x) | ||
| 19939 | (cond ((stringp (cdr x)) | ||
| 19940 | (push x prefix-descriptions) | ||
| 19941 | nil) | ||
| 19942 | ((stringp (nth 1 x)) x) | ||
| 19943 | ((not (nth 1 x)) (cons (car x) (cons "" (cddr x)))) | ||
| 19944 | (t (cons (car x) (cons "" (cdr x)))))) | ||
| 19945 | org-agenda-custom-commands))) | ||
| 19946 | (buf (current-buffer)) | ||
| 19947 | (bfn (buffer-file-name (buffer-base-buffer))) | ||
| 19948 | entry key type match lprops ans) | ||
| 19949 | ;; Turn off restriction unless there is an overriding one | ||
| 19950 | (unless org-agenda-overriding-restriction | ||
| 19951 | (put 'org-agenda-files 'org-restrict nil) | ||
| 19952 | (setq org-agenda-restrict nil) | ||
| 19953 | (move-marker org-agenda-restrict-begin nil) | ||
| 19954 | (move-marker org-agenda-restrict-end nil)) | ||
| 19955 | ;; Delete old local properties | ||
| 19956 | (put 'org-agenda-redo-command 'org-lprops nil) | ||
| 19957 | ;; Remember where this call originated | ||
| 19958 | (setq org-agenda-last-dispatch-buffer (current-buffer)) | ||
| 19959 | (unless keys | ||
| 19960 | (setq ans (org-agenda-get-restriction-and-command prefix-descriptions) | ||
| 19961 | keys (car ans) | ||
| 19962 | restriction (cdr ans))) | ||
| 19963 | ;; Estabish the restriction, if any | ||
| 19964 | (when (and (not org-agenda-overriding-restriction) restriction) | ||
| 19965 | (put 'org-agenda-files 'org-restrict (list bfn)) | ||
| 19966 | (cond | ||
| 19967 | ((eq restriction 'region) | ||
| 19968 | (setq org-agenda-restrict t) | ||
| 19969 | (move-marker org-agenda-restrict-begin (region-beginning)) | ||
| 19970 | (move-marker org-agenda-restrict-end (region-end))) | ||
| 19971 | ((eq restriction 'subtree) | ||
| 19972 | (save-excursion | ||
| 19973 | (setq org-agenda-restrict t) | ||
| 19974 | (org-back-to-heading t) | ||
| 19975 | (move-marker org-agenda-restrict-begin (point)) | ||
| 19976 | (move-marker org-agenda-restrict-end | ||
| 19977 | (progn (org-end-of-subtree t))))))) | ||
| 19978 | |||
| 19979 | (require 'calendar) ; FIXME: can we avoid this for some commands? | ||
| 19980 | ;; For example the todo list should not need it (but does...) | ||
| 19981 | (cond | ||
| 19982 | ((setq entry (assoc keys org-agenda-custom-commands)) | ||
| 19983 | (if (or (symbolp (nth 2 entry)) (functionp (nth 2 entry))) | ||
| 19984 | (progn | ||
| 19985 | (setq type (nth 2 entry) match (nth 3 entry) lprops (nth 4 entry)) | ||
| 19986 | (put 'org-agenda-redo-command 'org-lprops lprops) | ||
| 19987 | (cond | ||
| 19988 | ((eq type 'agenda) | ||
| 19989 | (org-let lprops '(org-agenda-list current-prefix-arg))) | ||
| 19990 | ((eq type 'alltodo) | ||
| 19991 | (org-let lprops '(org-todo-list current-prefix-arg))) | ||
| 19992 | ((eq type 'search) | ||
| 19993 | (org-let lprops '(org-search-view current-prefix-arg match))) | ||
| 19994 | ((eq type 'stuck) | ||
| 19995 | (org-let lprops '(org-agenda-list-stuck-projects | ||
| 19996 | current-prefix-arg))) | ||
| 19997 | ((eq type 'tags) | ||
| 19998 | (org-let lprops '(org-tags-view current-prefix-arg match))) | ||
| 19999 | ((eq type 'tags-todo) | ||
| 20000 | (org-let lprops '(org-tags-view '(4) match))) | ||
| 20001 | ((eq type 'todo) | ||
| 20002 | (org-let lprops '(org-todo-list match))) | ||
| 20003 | ((eq type 'tags-tree) | ||
| 20004 | (org-check-for-org-mode) | ||
| 20005 | (org-let lprops '(org-tags-sparse-tree current-prefix-arg match))) | ||
| 20006 | ((eq type 'todo-tree) | ||
| 20007 | (org-check-for-org-mode) | ||
| 20008 | (org-let lprops | ||
| 20009 | '(org-occur (concat "^" outline-regexp "[ \t]*" | ||
| 20010 | (regexp-quote match) "\\>")))) | ||
| 20011 | ((eq type 'occur-tree) | ||
| 20012 | (org-check-for-org-mode) | ||
| 20013 | (org-let lprops '(org-occur match))) | ||
| 20014 | ((functionp type) | ||
| 20015 | (org-let lprops '(funcall type match))) | ||
| 20016 | ((fboundp type) | ||
| 20017 | (org-let lprops '(funcall type match))) | ||
| 20018 | (t (error "Invalid custom agenda command type %s" type)))) | ||
| 20019 | (org-run-agenda-series (nth 1 entry) (cddr entry)))) | ||
| 20020 | ((equal keys "C") | ||
| 20021 | (setq org-agenda-custom-commands org-agenda-custom-commands-orig) | ||
| 20022 | (customize-variable 'org-agenda-custom-commands)) | ||
| 20023 | ((equal keys "a") (call-interactively 'org-agenda-list)) | ||
| 20024 | ((equal keys "s") (call-interactively 'org-search-view)) | ||
| 20025 | ((equal keys "t") (call-interactively 'org-todo-list)) | ||
| 20026 | ((equal keys "T") (org-call-with-arg 'org-todo-list (or arg '(4)))) | ||
| 20027 | ((equal keys "m") (call-interactively 'org-tags-view)) | ||
| 20028 | ((equal keys "M") (org-call-with-arg 'org-tags-view (or arg '(4)))) | ||
| 20029 | ((equal keys "e") (call-interactively 'org-store-agenda-views)) | ||
| 20030 | ((equal keys "L") | ||
| 20031 | (unless (org-mode-p) | ||
| 20032 | (error "This is not an Org-mode file")) | ||
| 20033 | (unless restriction | ||
| 20034 | (put 'org-agenda-files 'org-restrict (list bfn)) | ||
| 20035 | (org-call-with-arg 'org-timeline arg))) | ||
| 20036 | ((equal keys "#") (call-interactively 'org-agenda-list-stuck-projects)) | ||
| 20037 | ((equal keys "/") (call-interactively 'org-occur-in-agenda-files)) | ||
| 20038 | ((equal keys "!") (customize-variable 'org-stuck-projects)) | ||
| 20039 | (t (error "Invalid agenda key")))))) | ||
| 20040 | |||
| 20041 | (defun org-agenda-normalize-custom-commands (cmds) | ||
| 20042 | (delq nil | ||
| 20043 | (mapcar | ||
| 20044 | (lambda (x) | ||
| 20045 | (cond ((stringp (cdr x)) nil) | ||
| 20046 | ((stringp (nth 1 x)) x) | ||
| 20047 | ((not (nth 1 x)) (cons (car x) (cons "" (cddr x)))) | ||
| 20048 | (t (cons (car x) (cons "" (cdr x)))))) | ||
| 20049 | cmds))) | ||
| 20050 | |||
| 20051 | (defun org-agenda-get-restriction-and-command (prefix-descriptions) | ||
| 20052 | "The user interface for selecting an agenda command." | ||
| 20053 | (catch 'exit | ||
| 20054 | (let* ((bfn (buffer-file-name (buffer-base-buffer))) | ||
| 20055 | (restrict-ok (and bfn (org-mode-p))) | ||
| 20056 | (region-p (org-region-active-p)) | ||
| 20057 | (custom org-agenda-custom-commands) | ||
| 20058 | (selstring "") | ||
| 20059 | restriction second-time | ||
| 20060 | c entry key type match prefixes rmheader header-end custom1 desc) | ||
| 20061 | (save-window-excursion | ||
| 20062 | (delete-other-windows) | ||
| 20063 | (org-switch-to-buffer-other-window " *Agenda Commands*") | ||
| 20064 | (erase-buffer) | ||
| 20065 | (insert (eval-when-compile | ||
| 20066 | (let ((header | ||
| 20067 | " | ||
| 20068 | Press key for an agenda command: < Buffer,subtree/region restriction | ||
| 20069 | -------------------------------- > Remove restriction | ||
| 20070 | a Agenda for current week or day e Export agenda views | ||
| 20071 | t List of all TODO entries T Entries with special TODO kwd | ||
| 20072 | m Match a TAGS query M Like m, but only TODO entries | ||
| 20073 | L Timeline for current buffer # List stuck projects (!=configure) | ||
| 20074 | s Search for keywords C Configure custom agenda commands | ||
| 20075 | / Multi-occur | ||
| 20076 | ") | ||
| 20077 | (start 0)) | ||
| 20078 | (while (string-match | ||
| 20079 | "\\(^\\| \\|(\\)\\(\\S-\\)\\( \\|=\\)" | ||
| 20080 | header start) | ||
| 20081 | (setq start (match-end 0)) | ||
| 20082 | (add-text-properties (match-beginning 2) (match-end 2) | ||
| 20083 | '(face bold) header)) | ||
| 20084 | header))) | ||
| 20085 | (setq header-end (move-marker (make-marker) (point))) | ||
| 20086 | (while t | ||
| 20087 | (setq custom1 custom) | ||
| 20088 | (when (eq rmheader t) | ||
| 20089 | (goto-line 1) | ||
| 20090 | (re-search-forward ":" nil t) | ||
| 20091 | (delete-region (match-end 0) (point-at-eol)) | ||
| 20092 | (forward-char 1) | ||
| 20093 | (looking-at "-+") | ||
| 20094 | (delete-region (match-end 0) (point-at-eol)) | ||
| 20095 | (move-marker header-end (match-end 0))) | ||
| 20096 | (goto-char header-end) | ||
| 20097 | (delete-region (point) (point-max)) | ||
| 20098 | (while (setq entry (pop custom1)) | ||
| 20099 | (setq key (car entry) desc (nth 1 entry) | ||
| 20100 | type (nth 2 entry) match (nth 3 entry)) | ||
| 20101 | (if (> (length key) 1) | ||
| 20102 | (add-to-list 'prefixes (string-to-char key)) | ||
| 20103 | (insert | ||
| 20104 | (format | ||
| 20105 | "\n%-4s%-14s: %s" | ||
| 20106 | (org-add-props (copy-sequence key) | ||
| 20107 | '(face bold)) | ||
| 20108 | (cond | ||
| 20109 | ((string-match "\\S-" desc) desc) | ||
| 20110 | ((eq type 'agenda) "Agenda for current week or day") | ||
| 20111 | ((eq type 'alltodo) "List of all TODO entries") | ||
| 20112 | ((eq type 'search) "Word search") | ||
| 20113 | ((eq type 'stuck) "List of stuck projects") | ||
| 20114 | ((eq type 'todo) "TODO keyword") | ||
| 20115 | ((eq type 'tags) "Tags query") | ||
| 20116 | ((eq type 'tags-todo) "Tags (TODO)") | ||
| 20117 | ((eq type 'tags-tree) "Tags tree") | ||
| 20118 | ((eq type 'todo-tree) "TODO kwd tree") | ||
| 20119 | ((eq type 'occur-tree) "Occur tree") | ||
| 20120 | ((functionp type) (if (symbolp type) | ||
| 20121 | (symbol-name type) | ||
| 20122 | "Lambda expression")) | ||
| 20123 | (t "???")) | ||
| 20124 | (cond | ||
| 20125 | ((stringp match) | ||
| 20126 | (org-add-props match nil 'face 'org-warning)) | ||
| 20127 | (match | ||
| 20128 | (format "set of %d commands" (length match))) | ||
| 20129 | (t "")))))) | ||
| 20130 | (when prefixes | ||
| 20131 | (mapc (lambda (x) | ||
| 20132 | (insert | ||
| 20133 | (format "\n%s %s" | ||
| 20134 | (org-add-props (char-to-string x) | ||
| 20135 | nil 'face 'bold) | ||
| 20136 | (or (cdr (assoc (concat selstring (char-to-string x)) | ||
| 20137 | prefix-descriptions)) | ||
| 20138 | "Prefix key")))) | ||
| 20139 | prefixes)) | ||
| 20140 | (goto-char (point-min)) | ||
| 20141 | (when (fboundp 'fit-window-to-buffer) | ||
| 20142 | (if second-time | ||
| 20143 | (if (not (pos-visible-in-window-p (point-max))) | ||
| 20144 | (fit-window-to-buffer)) | ||
| 20145 | (setq second-time t) | ||
| 20146 | (fit-window-to-buffer))) | ||
| 20147 | (message "Press key for agenda command%s:" | ||
| 20148 | (if (or restrict-ok org-agenda-overriding-restriction) | ||
| 20149 | (if org-agenda-overriding-restriction | ||
| 20150 | " (restriction lock active)" | ||
| 20151 | (if restriction | ||
| 20152 | (format " (restricted to %s)" restriction) | ||
| 20153 | " (unrestricted)")) | ||
| 20154 | "")) | ||
| 20155 | (setq c (read-char-exclusive)) | ||
| 20156 | (message "") | ||
| 20157 | (cond | ||
| 20158 | ((assoc (char-to-string c) custom) | ||
| 20159 | (setq selstring (concat selstring (char-to-string c))) | ||
| 20160 | (throw 'exit (cons selstring restriction))) | ||
| 20161 | ((memq c prefixes) | ||
| 20162 | (setq selstring (concat selstring (char-to-string c)) | ||
| 20163 | prefixes nil | ||
| 20164 | rmheader (or rmheader t) | ||
| 20165 | custom (delq nil (mapcar | ||
| 20166 | (lambda (x) | ||
| 20167 | (if (or (= (length (car x)) 1) | ||
| 20168 | (/= (string-to-char (car x)) c)) | ||
| 20169 | nil | ||
| 20170 | (cons (substring (car x) 1) (cdr x)))) | ||
| 20171 | custom)))) | ||
| 20172 | ((and (not restrict-ok) (memq c '(?1 ?0 ?<))) | ||
| 20173 | (message "Restriction is only possible in Org-mode buffers") | ||
| 20174 | (ding) (sit-for 1)) | ||
| 20175 | ((eq c ?1) | ||
| 20176 | (org-agenda-remove-restriction-lock 'noupdate) | ||
| 20177 | (setq restriction 'buffer)) | ||
| 20178 | ((eq c ?0) | ||
| 20179 | (org-agenda-remove-restriction-lock 'noupdate) | ||
| 20180 | (setq restriction (if region-p 'region 'subtree))) | ||
| 20181 | ((eq c ?<) | ||
| 20182 | (org-agenda-remove-restriction-lock 'noupdate) | ||
| 20183 | (setq restriction | ||
| 20184 | (cond | ||
| 20185 | ((eq restriction 'buffer) | ||
| 20186 | (if region-p 'region 'subtree)) | ||
| 20187 | ((memq restriction '(subtree region)) | ||
| 20188 | nil) | ||
| 20189 | (t 'buffer)))) | ||
| 20190 | ((eq c ?>) | ||
| 20191 | (org-agenda-remove-restriction-lock 'noupdate) | ||
| 20192 | (setq restriction nil)) | ||
| 20193 | ((and (equal selstring "") (memq c '(?s ?a ?t ?m ?L ?C ?e ?T ?M ?# ?! ?/))) | ||
| 20194 | (throw 'exit (cons (setq selstring (char-to-string c)) restriction))) | ||
| 20195 | ((and (> (length selstring) 0) (eq c ?\d)) | ||
| 20196 | (delete-window) | ||
| 20197 | (org-agenda-get-restriction-and-command prefix-descriptions)) | ||
| 20198 | |||
| 20199 | ((equal c ?q) (error "Abort")) | ||
| 20200 | (t (error "Invalid key %c" c)))))))) | ||
| 20201 | |||
| 20202 | (defun org-run-agenda-series (name series) | ||
| 20203 | (org-prepare-agenda name) | ||
| 20204 | (let* ((org-agenda-multi t) | ||
| 20205 | (redo (list 'org-run-agenda-series name (list 'quote series))) | ||
| 20206 | (cmds (car series)) | ||
| 20207 | (gprops (nth 1 series)) | ||
| 20208 | match ;; The byte compiler incorrectly complains about this. Keep it! | ||
| 20209 | cmd type lprops) | ||
| 20210 | (while (setq cmd (pop cmds)) | ||
| 20211 | (setq type (car cmd) match (nth 1 cmd) lprops (nth 2 cmd)) | ||
| 20212 | (cond | ||
| 20213 | ((eq type 'agenda) | ||
| 20214 | (org-let2 gprops lprops | ||
| 20215 | '(call-interactively 'org-agenda-list))) | ||
| 20216 | ((eq type 'alltodo) | ||
| 20217 | (org-let2 gprops lprops | ||
| 20218 | '(call-interactively 'org-todo-list))) | ||
| 20219 | ((eq type 'search) | ||
| 20220 | (org-let2 gprops lprops | ||
| 20221 | '(org-search-view current-prefix-arg match))) | ||
| 20222 | ((eq type 'stuck) | ||
| 20223 | (org-let2 gprops lprops | ||
| 20224 | '(call-interactively 'org-agenda-list-stuck-projects))) | ||
| 20225 | ((eq type 'tags) | ||
| 20226 | (org-let2 gprops lprops | ||
| 20227 | '(org-tags-view current-prefix-arg match))) | ||
| 20228 | ((eq type 'tags-todo) | ||
| 20229 | (org-let2 gprops lprops | ||
| 20230 | '(org-tags-view '(4) match))) | ||
| 20231 | ((eq type 'todo) | ||
| 20232 | (org-let2 gprops lprops | ||
| 20233 | '(org-todo-list match))) | ||
| 20234 | ((fboundp type) | ||
| 20235 | (org-let2 gprops lprops | ||
| 20236 | '(funcall type match))) | ||
| 20237 | (t (error "Invalid type in command series")))) | ||
| 20238 | (widen) | ||
| 20239 | (setq org-agenda-redo-command redo) | ||
| 20240 | (goto-char (point-min))) | ||
| 20241 | (org-finalize-agenda)) | ||
| 20242 | |||
| 20243 | ;;;###autoload | ||
| 20244 | (defmacro org-batch-agenda (cmd-key &rest parameters) | ||
| 20245 | "Run an agenda command in batch mode and send the result to STDOUT. | ||
| 20246 | If CMD-KEY is a string of length 1, it is used as a key in | ||
| 20247 | `org-agenda-custom-commands' and triggers this command. If it is a | ||
| 20248 | longer string it is used as a tags/todo match string. | ||
| 20249 | Paramters are alternating variable names and values that will be bound | ||
| 20250 | before running the agenda command." | ||
| 20251 | (let (pars) | ||
| 20252 | (while parameters | ||
| 20253 | (push (list (pop parameters) (if parameters (pop parameters))) pars)) | ||
| 20254 | (if (> (length cmd-key) 2) | ||
| 20255 | (eval (list 'let (nreverse pars) | ||
| 20256 | (list 'org-tags-view nil cmd-key))) | ||
| 20257 | (eval (list 'let (nreverse pars) (list 'org-agenda nil cmd-key)))) | ||
| 20258 | (set-buffer org-agenda-buffer-name) | ||
| 20259 | (princ (org-encode-for-stdout (buffer-string))))) | ||
| 20260 | |||
| 20261 | (defun org-encode-for-stdout (string) | ||
| 20262 | (if (fboundp 'encode-coding-string) | ||
| 20263 | (encode-coding-string string buffer-file-coding-system) | ||
| 20264 | string)) | ||
| 20265 | |||
| 20266 | (defvar org-agenda-info nil) | ||
| 20267 | |||
| 20268 | ;;;###autoload | ||
| 20269 | (defmacro org-batch-agenda-csv (cmd-key &rest parameters) | ||
| 20270 | "Run an agenda command in batch mode and send the result to STDOUT. | ||
| 20271 | If CMD-KEY is a string of length 1, it is used as a key in | ||
| 20272 | `org-agenda-custom-commands' and triggers this command. If it is a | ||
| 20273 | longer string it is used as a tags/todo match string. | ||
| 20274 | Paramters are alternating variable names and values that will be bound | ||
| 20275 | before running the agenda command. | ||
| 20276 | |||
| 20277 | The output gives a line for each selected agenda item. Each | ||
| 20278 | item is a list of comma-separated values, like this: | ||
| 20279 | |||
| 20280 | category,head,type,todo,tags,date,time,extra,priority-l,priority-n | ||
| 20281 | |||
| 20282 | category The category of the item | ||
| 20283 | head The headline, without TODO kwd, TAGS and PRIORITY | ||
| 20284 | type The type of the agenda entry, can be | ||
| 20285 | todo selected in TODO match | ||
| 20286 | tagsmatch selected in tags match | ||
| 20287 | diary imported from diary | ||
| 20288 | deadline a deadline on given date | ||
| 20289 | scheduled scheduled on given date | ||
| 20290 | timestamp entry has timestamp on given date | ||
| 20291 | closed entry was closed on given date | ||
| 20292 | upcoming-deadline warning about deadline | ||
| 20293 | past-scheduled forwarded scheduled item | ||
| 20294 | block entry has date block including g. date | ||
| 20295 | todo The todo keyword, if any | ||
| 20296 | tags All tags including inherited ones, separated by colons | ||
| 20297 | date The relevant date, like 2007-2-14 | ||
| 20298 | time The time, like 15:00-16:50 | ||
| 20299 | extra Sting with extra planning info | ||
| 20300 | priority-l The priority letter if any was given | ||
| 20301 | priority-n The computed numerical priority | ||
| 20302 | agenda-day The day in the agenda where this is listed" | ||
| 20303 | |||
| 20304 | (let (pars) | ||
| 20305 | (while parameters | ||
| 20306 | (push (list (pop parameters) (if parameters (pop parameters))) pars)) | ||
| 20307 | (push (list 'org-agenda-remove-tags t) pars) | ||
| 20308 | (if (> (length cmd-key) 2) | ||
| 20309 | (eval (list 'let (nreverse pars) | ||
| 20310 | (list 'org-tags-view nil cmd-key))) | ||
| 20311 | (eval (list 'let (nreverse pars) (list 'org-agenda nil cmd-key)))) | ||
| 20312 | (set-buffer org-agenda-buffer-name) | ||
| 20313 | (let* ((lines (org-split-string (buffer-string) "\n")) | ||
| 20314 | line) | ||
| 20315 | (while (setq line (pop lines)) | ||
| 20316 | (catch 'next | ||
| 20317 | (if (not (get-text-property 0 'org-category line)) (throw 'next nil)) | ||
| 20318 | (setq org-agenda-info | ||
| 20319 | (org-fix-agenda-info (text-properties-at 0 line))) | ||
| 20320 | (princ | ||
| 20321 | (org-encode-for-stdout | ||
| 20322 | (mapconcat 'org-agenda-export-csv-mapper | ||
| 20323 | '(org-category txt type todo tags date time-of-day extra | ||
| 20324 | priority-letter priority agenda-day) | ||
| 20325 | ","))) | ||
| 20326 | (princ "\n")))))) | ||
| 20327 | |||
| 20328 | (defun org-fix-agenda-info (props) | ||
| 20329 | "Make sure all properties on an agenda item have a canonical form, | ||
| 20330 | so the export commands can easily use it." | ||
| 20331 | (let (tmp re) | ||
| 20332 | (when (setq tmp (plist-get props 'tags)) | ||
| 20333 | (setq props (plist-put props 'tags (mapconcat 'identity tmp ":")))) | ||
| 20334 | (when (setq tmp (plist-get props 'date)) | ||
| 20335 | (if (integerp tmp) (setq tmp (calendar-gregorian-from-absolute tmp))) | ||
| 20336 | (let ((calendar-date-display-form '(year "-" month "-" day))) | ||
| 20337 | '((format "%4d, %9s %2s, %4s" dayname monthname day year)) | ||
| 20338 | |||
| 20339 | (setq tmp (calendar-date-string tmp))) | ||
| 20340 | (setq props (plist-put props 'date tmp))) | ||
| 20341 | (when (setq tmp (plist-get props 'day)) | ||
| 20342 | (if (integerp tmp) (setq tmp (calendar-gregorian-from-absolute tmp))) | ||
| 20343 | (let ((calendar-date-display-form '(year "-" month "-" day))) | ||
| 20344 | (setq tmp (calendar-date-string tmp))) | ||
| 20345 | (setq props (plist-put props 'day tmp)) | ||
| 20346 | (setq props (plist-put props 'agenda-day tmp))) | ||
| 20347 | (when (setq tmp (plist-get props 'txt)) | ||
| 20348 | (when (string-match "\\[#\\([A-Z0-9]\\)\\] ?" tmp) | ||
| 20349 | (plist-put props 'priority-letter (match-string 1 tmp)) | ||
| 20350 | (setq tmp (replace-match "" t t tmp))) | ||
| 20351 | (when (and (setq re (plist-get props 'org-todo-regexp)) | ||
| 20352 | (setq re (concat "\\`\\.*" re " ?")) | ||
| 20353 | (string-match re tmp)) | ||
| 20354 | (plist-put props 'todo (match-string 1 tmp)) | ||
| 20355 | (setq tmp (replace-match "" t t tmp))) | ||
| 20356 | (plist-put props 'txt tmp))) | ||
| 20357 | props) | ||
| 20358 | |||
| 20359 | (defun org-agenda-export-csv-mapper (prop) | ||
| 20360 | (let ((res (plist-get org-agenda-info prop))) | ||
| 20361 | (setq res | ||
| 20362 | (cond | ||
| 20363 | ((not res) "") | ||
| 20364 | ((stringp res) res) | ||
| 20365 | (t (prin1-to-string res)))) | ||
| 20366 | (while (string-match "," res) | ||
| 20367 | (setq res (replace-match ";" t t res))) | ||
| 20368 | (org-trim res))) | ||
| 20369 | |||
| 20370 | |||
| 20371 | ;;;###autoload | ||
| 20372 | (defun org-store-agenda-views (&rest parameters) | ||
| 20373 | (interactive) | ||
| 20374 | (eval (list 'org-batch-store-agenda-views))) | ||
| 20375 | |||
| 20376 | ;; FIXME, why is this a macro????? | ||
| 20377 | ;;;###autoload | ||
| 20378 | (defmacro org-batch-store-agenda-views (&rest parameters) | ||
| 20379 | "Run all custom agenda commands that have a file argument." | ||
| 20380 | (let ((cmds (org-agenda-normalize-custom-commands org-agenda-custom-commands)) | ||
| 20381 | (pop-up-frames nil) | ||
| 20382 | (dir default-directory) | ||
| 20383 | pars cmd thiscmdkey files opts) | ||
| 20384 | (while parameters | ||
| 20385 | (push (list (pop parameters) (if parameters (pop parameters))) pars)) | ||
| 20386 | (setq pars (reverse pars)) | ||
| 20387 | (save-window-excursion | ||
| 20388 | (while cmds | ||
| 20389 | (setq cmd (pop cmds) | ||
| 20390 | thiscmdkey (car cmd) | ||
| 20391 | opts (nth 4 cmd) | ||
| 20392 | files (nth 5 cmd)) | ||
| 20393 | (if (stringp files) (setq files (list files))) | ||
| 20394 | (when files | ||
| 20395 | (eval (list 'let (append org-agenda-exporter-settings opts pars) | ||
| 20396 | (list 'org-agenda nil thiscmdkey))) | ||
| 20397 | (set-buffer org-agenda-buffer-name) | ||
| 20398 | (while files | ||
| 20399 | (eval (list 'let (append org-agenda-exporter-settings opts pars) | ||
| 20400 | (list 'org-write-agenda | ||
| 20401 | (expand-file-name (pop files) dir) t)))) | ||
| 20402 | (and (get-buffer org-agenda-buffer-name) | ||
| 20403 | (kill-buffer org-agenda-buffer-name))))))) | ||
| 20404 | |||
| 20405 | (defun org-write-agenda (file &optional nosettings) | ||
| 20406 | "Write the current buffer (an agenda view) as a file. | ||
| 20407 | Depending on the extension of the file name, plain text (.txt), | ||
| 20408 | HTML (.html or .htm) or Postscript (.ps) is produced. | ||
| 20409 | If the extension is .ics, run icalendar export over all files used | ||
| 20410 | to construct the agenda and limit the export to entries listed in the | ||
| 20411 | agenda now. | ||
| 20412 | If NOSETTINGS is given, do not scope the settings of | ||
| 20413 | `org-agenda-exporter-settings' into the export commands. This is used when | ||
| 20414 | the settings have already been scoped and we do not wish to overrule other, | ||
| 20415 | higher priority settings." | ||
| 20416 | (interactive "FWrite agenda to file: ") | ||
| 20417 | (if (not (file-writable-p file)) | ||
| 20418 | (error "Cannot write agenda to file %s" file)) | ||
| 20419 | (cond | ||
| 20420 | ((string-match "\\.html?\\'" file) (require 'htmlize)) | ||
| 20421 | ((string-match "\\.ps\\'" file) (require 'ps-print))) | ||
| 20422 | (org-let (if nosettings nil org-agenda-exporter-settings) | ||
| 20423 | '(save-excursion | ||
| 20424 | (save-window-excursion | ||
| 20425 | (cond | ||
| 20426 | ((string-match "\\.html?\\'" file) | ||
| 20427 | (set-buffer (htmlize-buffer (current-buffer))) | ||
| 20428 | |||
| 20429 | (when (and org-agenda-export-html-style | ||
| 20430 | (string-match "<style>" org-agenda-export-html-style)) | ||
| 20431 | ;; replace <style> section with org-agenda-export-html-style | ||
| 20432 | (goto-char (point-min)) | ||
| 20433 | (kill-region (- (search-forward "<style") 6) | ||
| 20434 | (search-forward "</style>")) | ||
| 20435 | (insert org-agenda-export-html-style)) | ||
| 20436 | (write-file file) | ||
| 20437 | (kill-buffer (current-buffer)) | ||
| 20438 | (message "HTML written to %s" file)) | ||
| 20439 | ((string-match "\\.ps\\'" file) | ||
| 20440 | (ps-print-buffer-with-faces file) | ||
| 20441 | (message "Postscript written to %s" file)) | ||
| 20442 | ((string-match "\\.ics\\'" file) | ||
| 20443 | (let ((org-agenda-marker-table | ||
| 20444 | (org-create-marker-find-array | ||
| 20445 | (org-agenda-collect-markers))) | ||
| 20446 | (org-icalendar-verify-function 'org-check-agenda-marker-table) | ||
| 20447 | (org-combined-agenda-icalendar-file file)) | ||
| 20448 | (apply 'org-export-icalendar 'combine (org-agenda-files)))) | ||
| 20449 | (t | ||
| 20450 | (let ((bs (buffer-string))) | ||
| 20451 | (find-file file) | ||
| 20452 | (insert bs) | ||
| 20453 | (save-buffer 0) | ||
| 20454 | (kill-buffer (current-buffer)) | ||
| 20455 | (message "Plain text written to %s" file)))))) | ||
| 20456 | (set-buffer org-agenda-buffer-name))) | ||
| 20457 | |||
| 20458 | (defun org-agenda-collect-markers () | ||
| 20459 | "Collect the markers pointing to entries in the agenda buffer." | ||
| 20460 | (let (m markers) | ||
| 20461 | (save-excursion | ||
| 20462 | (goto-char (point-min)) | ||
| 20463 | (while (not (eobp)) | ||
| 20464 | (when (setq m (or (get-text-property (point) 'org-hd-marker) | ||
| 20465 | (get-text-property (point) 'org-marker))) | ||
| 20466 | (push m markers)) | ||
| 20467 | (beginning-of-line 2))) | ||
| 20468 | (nreverse markers))) | ||
| 20469 | |||
| 20470 | (defun org-create-marker-find-array (marker-list) | ||
| 20471 | "Create a alist of files names with all marker positions in that file." | ||
| 20472 | (let (f tbl m a p) | ||
| 20473 | (while (setq m (pop marker-list)) | ||
| 20474 | (setq p (marker-position m) | ||
| 20475 | f (buffer-file-name (or (buffer-base-buffer | ||
| 20476 | (marker-buffer m)) | ||
| 20477 | (marker-buffer m)))) | ||
| 20478 | (if (setq a (assoc f tbl)) | ||
| 20479 | (push (marker-position m) (cdr a)) | ||
| 20480 | (push (list f p) tbl))) | ||
| 20481 | (mapcar (lambda (x) (setcdr x (sort (copy-sequence (cdr x)) '<)) x) | ||
| 20482 | tbl))) | ||
| 20483 | |||
| 20484 | (defvar org-agenda-marker-table nil) ; dyamically scoped parameter | ||
| 20485 | (defun org-check-agenda-marker-table () | ||
| 20486 | "Check of the current entry is on the marker list." | ||
| 20487 | (let ((file (buffer-file-name (or (buffer-base-buffer) (current-buffer)))) | ||
| 20488 | a) | ||
| 20489 | (and (setq a (assoc file org-agenda-marker-table)) | ||
| 20490 | (save-match-data | ||
| 20491 | (save-excursion | ||
| 20492 | (org-back-to-heading t) | ||
| 20493 | (member (point) (cdr a))))))) | ||
| 20494 | |||
| 20495 | (defmacro org-no-read-only (&rest body) | ||
| 20496 | "Inhibit read-only for BODY." | ||
| 20497 | `(let ((inhibit-read-only t)) ,@body)) | ||
| 20498 | |||
| 20499 | (defun org-check-for-org-mode () | ||
| 20500 | "Make sure current buffer is in org-mode. Error if not." | ||
| 20501 | (or (org-mode-p) | ||
| 20502 | (error "Cannot execute org-mode agenda command on buffer in %s." | ||
| 20503 | major-mode))) | ||
| 20504 | |||
| 20505 | (defun org-fit-agenda-window () | ||
| 20506 | "Fit the window to the buffer size." | ||
| 20507 | (and (memq org-agenda-window-setup '(reorganize-frame)) | ||
| 20508 | (fboundp 'fit-window-to-buffer) | ||
| 20509 | (fit-window-to-buffer | ||
| 20510 | nil | ||
| 20511 | (floor (* (frame-height) (cdr org-agenda-window-frame-fractions))) | ||
| 20512 | (floor (* (frame-height) (car org-agenda-window-frame-fractions)))))) | ||
| 20513 | |||
| 20514 | ;;; Agenda file list | ||
| 20515 | |||
| 20516 | (defun org-agenda-files (&optional unrestricted) | ||
| 20517 | "Get the list of agenda files. | ||
| 20518 | Optional UNRESTRICTED means return the full list even if a restriction | ||
| 20519 | is currently in place." | ||
| 20520 | (let ((files | ||
| 20521 | (cond | ||
| 20522 | ((and (not unrestricted) (get 'org-agenda-files 'org-restrict))) | ||
| 20523 | ((stringp org-agenda-files) (org-read-agenda-file-list)) | ||
| 20524 | ((listp org-agenda-files) org-agenda-files) | ||
| 20525 | (t (error "Invalid value of `org-agenda-files'"))))) | ||
| 20526 | (setq files (apply 'append | ||
| 20527 | (mapcar (lambda (f) | ||
| 20528 | (if (file-directory-p f) | ||
| 20529 | (directory-files f t | ||
| 20530 | org-agenda-file-regexp) | ||
| 20531 | (list f))) | ||
| 20532 | files))) | ||
| 20533 | (if org-agenda-skip-unavailable-files | ||
| 20534 | (delq nil | ||
| 20535 | (mapcar (function | ||
| 20536 | (lambda (file) | ||
| 20537 | (and (file-readable-p file) file))) | ||
| 20538 | files)) | ||
| 20539 | files))) ; `org-check-agenda-file' will remove them from the list | ||
| 20540 | |||
| 20541 | (defun org-edit-agenda-file-list () | ||
| 20542 | "Edit the list of agenda files. | ||
| 20543 | Depending on setup, this either uses customize to edit the variable | ||
| 20544 | `org-agenda-files', or it visits the file that is holding the list. In the | ||
| 20545 | latter case, the buffer is set up in a way that saving it automatically kills | ||
| 20546 | the buffer and restores the previous window configuration." | ||
| 20547 | (interactive) | ||
| 20548 | (if (stringp org-agenda-files) | ||
| 20549 | (let ((cw (current-window-configuration))) | ||
| 20550 | (find-file org-agenda-files) | ||
| 20551 | (org-set-local 'org-window-configuration cw) | ||
| 20552 | (org-add-hook 'after-save-hook | ||
| 20553 | (lambda () | ||
| 20554 | (set-window-configuration | ||
| 20555 | (prog1 org-window-configuration | ||
| 20556 | (kill-buffer (current-buffer)))) | ||
| 20557 | (org-install-agenda-files-menu) | ||
| 20558 | (message "New agenda file list installed")) | ||
| 20559 | nil 'local) | ||
| 20560 | (message "%s" (substitute-command-keys | ||
| 20561 | "Edit list and finish with \\[save-buffer]"))) | ||
| 20562 | (customize-variable 'org-agenda-files))) | ||
| 20563 | |||
| 20564 | (defun org-store-new-agenda-file-list (list) | ||
| 20565 | "Set new value for the agenda file list and save it correcly." | ||
| 20566 | (if (stringp org-agenda-files) | ||
| 20567 | (let ((f org-agenda-files) b) | ||
| 20568 | (while (setq b (find-buffer-visiting f)) (kill-buffer b)) | ||
| 20569 | (with-temp-file f | ||
| 20570 | (insert (mapconcat 'identity list "\n") "\n"))) | ||
| 20571 | (let ((org-mode-hook nil) (default-major-mode 'fundamental-mode)) | ||
| 20572 | (setq org-agenda-files list) | ||
| 20573 | (customize-save-variable 'org-agenda-files org-agenda-files)))) | ||
| 20574 | |||
| 20575 | (defun org-read-agenda-file-list () | ||
| 20576 | "Read the list of agenda files from a file." | ||
| 20577 | (when (stringp org-agenda-files) | ||
| 20578 | (with-temp-buffer | ||
| 20579 | (insert-file-contents org-agenda-files) | ||
| 20580 | (org-split-string (buffer-string) "[ \t\r\n]*?[\r\n][ \t\r\n]*")))) | ||
| 20581 | |||
| 20582 | |||
| 20583 | ;;;###autoload | ||
| 20584 | (defun org-cycle-agenda-files () | ||
| 20585 | "Cycle through the files in `org-agenda-files'. | ||
| 20586 | If the current buffer visits an agenda file, find the next one in the list. | ||
| 20587 | If the current buffer does not, find the first agenda file." | ||
| 20588 | (interactive) | ||
| 20589 | (let* ((fs (org-agenda-files t)) | ||
| 20590 | (files (append fs (list (car fs)))) | ||
| 20591 | (tcf (if buffer-file-name (file-truename buffer-file-name))) | ||
| 20592 | file) | ||
| 20593 | (unless files (error "No agenda files")) | ||
| 20594 | (catch 'exit | ||
| 20595 | (while (setq file (pop files)) | ||
| 20596 | (if (equal (file-truename file) tcf) | ||
| 20597 | (when (car files) | ||
| 20598 | (find-file (car files)) | ||
| 20599 | (throw 'exit t)))) | ||
| 20600 | (find-file (car fs))) | ||
| 20601 | (if (buffer-base-buffer) (switch-to-buffer (buffer-base-buffer))))) | ||
| 20602 | |||
| 20603 | (defun org-agenda-file-to-front (&optional to-end) | ||
| 20604 | "Move/add the current file to the top of the agenda file list. | ||
| 20605 | If the file is not present in the list, it is added to the front. If it is | ||
| 20606 | present, it is moved there. With optional argument TO-END, add/move to the | ||
| 20607 | end of the list." | ||
| 20608 | (interactive "P") | ||
| 20609 | (let ((org-agenda-skip-unavailable-files nil) | ||
| 20610 | (file-alist (mapcar (lambda (x) | ||
| 20611 | (cons (file-truename x) x)) | ||
| 20612 | (org-agenda-files t))) | ||
| 20613 | (ctf (file-truename buffer-file-name)) | ||
| 20614 | x had) | ||
| 20615 | (setq x (assoc ctf file-alist) had x) | ||
| 20616 | |||
| 20617 | (if (not x) (setq x (cons ctf (abbreviate-file-name buffer-file-name)))) | ||
| 20618 | (if to-end | ||
| 20619 | (setq file-alist (append (delq x file-alist) (list x))) | ||
| 20620 | (setq file-alist (cons x (delq x file-alist)))) | ||
| 20621 | (org-store-new-agenda-file-list (mapcar 'cdr file-alist)) | ||
| 20622 | (org-install-agenda-files-menu) | ||
| 20623 | (message "File %s to %s of agenda file list" | ||
| 20624 | (if had "moved" "added") (if to-end "end" "front")))) | ||
| 20625 | |||
| 20626 | (defun org-remove-file (&optional file) | ||
| 20627 | "Remove current file from the list of files in variable `org-agenda-files'. | ||
| 20628 | These are the files which are being checked for agenda entries. | ||
| 20629 | Optional argument FILE means, use this file instead of the current." | ||
| 20630 | (interactive) | ||
| 20631 | (let* ((org-agenda-skip-unavailable-files nil) | ||
| 20632 | (file (or file buffer-file-name)) | ||
| 20633 | (true-file (file-truename file)) | ||
| 20634 | (afile (abbreviate-file-name file)) | ||
| 20635 | (files (delq nil (mapcar | ||
| 20636 | (lambda (x) | ||
| 20637 | (if (equal true-file | ||
| 20638 | (file-truename x)) | ||
| 20639 | nil x)) | ||
| 20640 | (org-agenda-files t))))) | ||
| 20641 | (if (not (= (length files) (length (org-agenda-files t)))) | ||
| 20642 | (progn | ||
| 20643 | (org-store-new-agenda-file-list files) | ||
| 20644 | (org-install-agenda-files-menu) | ||
| 20645 | (message "Removed file: %s" afile)) | ||
| 20646 | (message "File was not in list: %s (not removed)" afile)))) | ||
| 20647 | |||
| 20648 | (defun org-file-menu-entry (file) | ||
| 20649 | (vector file (list 'find-file file) t)) | ||
| 20650 | |||
| 20651 | (defun org-check-agenda-file (file) | ||
| 20652 | "Make sure FILE exists. If not, ask user what to do." | ||
| 20653 | (when (not (file-exists-p file)) | ||
| 20654 | (message "non-existent file %s. [R]emove from list or [A]bort?" | ||
| 20655 | (abbreviate-file-name file)) | ||
| 20656 | (let ((r (downcase (read-char-exclusive)))) | ||
| 20657 | (cond | ||
| 20658 | ((equal r ?r) | ||
| 20659 | (org-remove-file file) | ||
| 20660 | (throw 'nextfile t)) | ||
| 20661 | (t (error "Abort")))))) | ||
| 20662 | |||
| 20663 | ;;; Agenda prepare and finalize | ||
| 20664 | |||
| 20665 | (defvar org-agenda-multi nil) ; dynammically scoped | ||
| 20666 | (defvar org-agenda-buffer-name "*Org Agenda*") | ||
| 20667 | (defvar org-pre-agenda-window-conf nil) | ||
| 20668 | (defvar org-agenda-name nil) | ||
| 20669 | (defun org-prepare-agenda (&optional name) | ||
| 20670 | (setq org-todo-keywords-for-agenda nil) | ||
| 20671 | (setq org-done-keywords-for-agenda nil) | ||
| 20672 | (if org-agenda-multi | ||
| 20673 | (progn | ||
| 20674 | (setq buffer-read-only nil) | ||
| 20675 | (goto-char (point-max)) | ||
| 20676 | (unless (or (bobp) org-agenda-compact-blocks) | ||
| 20677 | (insert "\n" (make-string (window-width) ?=) "\n")) | ||
| 20678 | (narrow-to-region (point) (point-max))) | ||
| 20679 | (org-agenda-reset-markers) | ||
| 20680 | (org-prepare-agenda-buffers (org-agenda-files)) | ||
| 20681 | (setq org-todo-keywords-for-agenda | ||
| 20682 | (org-uniquify org-todo-keywords-for-agenda)) | ||
| 20683 | (setq org-done-keywords-for-agenda | ||
| 20684 | (org-uniquify org-done-keywords-for-agenda)) | ||
| 20685 | (let* ((abuf (get-buffer-create org-agenda-buffer-name)) | ||
| 20686 | (awin (get-buffer-window abuf))) | ||
| 20687 | (cond | ||
| 20688 | ((equal (current-buffer) abuf) nil) | ||
| 20689 | (awin (select-window awin)) | ||
| 20690 | ((not (setq org-pre-agenda-window-conf (current-window-configuration)))) | ||
| 20691 | ((equal org-agenda-window-setup 'current-window) | ||
| 20692 | (switch-to-buffer abuf)) | ||
| 20693 | ((equal org-agenda-window-setup 'other-window) | ||
| 20694 | (org-switch-to-buffer-other-window abuf)) | ||
| 20695 | ((equal org-agenda-window-setup 'other-frame) | ||
| 20696 | (switch-to-buffer-other-frame abuf)) | ||
| 20697 | ((equal org-agenda-window-setup 'reorganize-frame) | ||
| 20698 | (delete-other-windows) | ||
| 20699 | (org-switch-to-buffer-other-window abuf)))) | ||
| 20700 | (setq buffer-read-only nil) | ||
| 20701 | (erase-buffer) | ||
| 20702 | (org-agenda-mode) | ||
| 20703 | (and name (not org-agenda-name) | ||
| 20704 | (org-set-local 'org-agenda-name name))) | ||
| 20705 | (setq buffer-read-only nil)) | ||
| 20706 | |||
| 20707 | (defun org-finalize-agenda () | ||
| 20708 | "Finishing touch for the agenda buffer, called just before displaying it." | ||
| 20709 | (unless org-agenda-multi | ||
| 20710 | (save-excursion | ||
| 20711 | (let ((inhibit-read-only t)) | ||
| 20712 | (goto-char (point-min)) | ||
| 20713 | (while (org-activate-bracket-links (point-max)) | ||
| 20714 | (add-text-properties (match-beginning 0) (match-end 0) | ||
| 20715 | '(face org-link))) | ||
| 20716 | (org-agenda-align-tags) | ||
| 20717 | (unless org-agenda-with-colors | ||
| 20718 | (remove-text-properties (point-min) (point-max) '(face nil)))) | ||
| 20719 | (if (and (boundp 'org-overriding-columns-format) | ||
| 20720 | org-overriding-columns-format) | ||
| 20721 | (org-set-local 'org-overriding-columns-format | ||
| 20722 | org-overriding-columns-format)) | ||
| 20723 | (if (and (boundp 'org-agenda-view-columns-initially) | ||
| 20724 | org-agenda-view-columns-initially) | ||
| 20725 | (org-agenda-columns)) | ||
| 20726 | (when org-agenda-fontify-priorities | ||
| 20727 | (org-fontify-priorities)) | ||
| 20728 | (run-hooks 'org-finalize-agenda-hook) | ||
| 20729 | (setq org-agenda-type (get-text-property (point) 'org-agenda-type)) | ||
| 20730 | ))) | ||
| 20731 | |||
| 20732 | (defun org-fontify-priorities () | ||
| 20733 | "Make highest priority lines bold, and lowest italic." | ||
| 20734 | (interactive) | ||
| 20735 | (mapc (lambda (o) (if (eq (org-overlay-get o 'org-type) 'org-priority) | ||
| 20736 | (org-delete-overlay o))) | ||
| 20737 | (org-overlays-in (point-min) (point-max))) | ||
| 20738 | (save-excursion | ||
| 20739 | (let ((inhibit-read-only t) | ||
| 20740 | b e p ov h l) | ||
| 20741 | (goto-char (point-min)) | ||
| 20742 | (while (re-search-forward "\\[#\\(.\\)\\]" nil t) | ||
| 20743 | (setq h (or (get-char-property (point) 'org-highest-priority) | ||
| 20744 | org-highest-priority) | ||
| 20745 | l (or (get-char-property (point) 'org-lowest-priority) | ||
| 20746 | org-lowest-priority) | ||
| 20747 | p (string-to-char (match-string 1)) | ||
| 20748 | b (match-beginning 0) e (point-at-eol) | ||
| 20749 | ov (org-make-overlay b e)) | ||
| 20750 | (org-overlay-put | ||
| 20751 | ov 'face | ||
| 20752 | (cond ((listp org-agenda-fontify-priorities) | ||
| 20753 | (cdr (assoc p org-agenda-fontify-priorities))) | ||
| 20754 | ((equal p l) 'italic) | ||
| 20755 | ((equal p h) 'bold))) | ||
| 20756 | (org-overlay-put ov 'org-type 'org-priority))))) | ||
| 20757 | |||
| 20758 | (defun org-prepare-agenda-buffers (files) | ||
| 20759 | "Create buffers for all agenda files, protect archived trees and comments." | ||
| 20760 | (interactive) | ||
| 20761 | (let ((pa '(:org-archived t)) | ||
| 20762 | (pc '(:org-comment t)) | ||
| 20763 | (pall '(:org-archived t :org-comment t)) | ||
| 20764 | (inhibit-read-only t) | ||
| 20765 | (rea (concat ":" org-archive-tag ":")) | ||
| 20766 | bmp file re) | ||
| 20767 | (save-excursion | ||
| 20768 | (save-restriction | ||
| 20769 | (while (setq file (pop files)) | ||
| 20770 | (if (bufferp file) | ||
| 20771 | (set-buffer file) | ||
| 20772 | (org-check-agenda-file file) | ||
| 20773 | (set-buffer (org-get-agenda-file-buffer file))) | ||
| 20774 | (widen) | ||
| 20775 | (setq bmp (buffer-modified-p)) | ||
| 20776 | (org-refresh-category-properties) | ||
| 20777 | (setq org-todo-keywords-for-agenda | ||
| 20778 | (append org-todo-keywords-for-agenda org-todo-keywords-1)) | ||
| 20779 | (setq org-done-keywords-for-agenda | ||
| 20780 | (append org-done-keywords-for-agenda org-done-keywords)) | ||
| 20781 | (save-excursion | ||
| 20782 | (remove-text-properties (point-min) (point-max) pall) | ||
| 20783 | (when org-agenda-skip-archived-trees | ||
| 20784 | (goto-char (point-min)) | ||
| 20785 | (while (re-search-forward rea nil t) | ||
| 20786 | (if (org-on-heading-p t) | ||
| 20787 | (add-text-properties (point-at-bol) (org-end-of-subtree t) pa)))) | ||
| 20788 | (goto-char (point-min)) | ||
| 20789 | (setq re (concat "^\\*+ +" org-comment-string "\\>")) | ||
| 20790 | (while (re-search-forward re nil t) | ||
| 20791 | (add-text-properties | ||
| 20792 | (match-beginning 0) (org-end-of-subtree t) pc))) | ||
| 20793 | (set-buffer-modified-p bmp)))))) | ||
| 20794 | |||
| 20795 | (defvar org-agenda-skip-function nil | ||
| 20796 | "Function to be called at each match during agenda construction. | ||
| 20797 | If this function returns nil, the current match should not be skipped. | ||
| 20798 | Otherwise, the function must return a position from where the search | ||
| 20799 | should be continued. | ||
| 20800 | This may also be a Lisp form, it will be evaluated. | ||
| 20801 | Never set this variable using `setq' or so, because then it will apply | ||
| 20802 | to all future agenda commands. Instead, bind it with `let' to scope | ||
| 20803 | it dynamically into the agenda-constructing command. A good way to set | ||
| 20804 | it is through options in org-agenda-custom-commands.") | ||
| 20805 | |||
| 20806 | (defun org-agenda-skip () | ||
| 20807 | "Throw to `:skip' in places that should be skipped. | ||
| 20808 | Also moves point to the end of the skipped region, so that search can | ||
| 20809 | continue from there." | ||
| 20810 | (let ((p (point-at-bol)) to fp) | ||
| 20811 | (and org-agenda-skip-archived-trees | ||
| 20812 | (get-text-property p :org-archived) | ||
| 20813 | (org-end-of-subtree t) | ||
| 20814 | (throw :skip t)) | ||
| 20815 | (and (get-text-property p :org-comment) | ||
| 20816 | (org-end-of-subtree t) | ||
| 20817 | (throw :skip t)) | ||
| 20818 | (if (equal (char-after p) ?#) (throw :skip t)) | ||
| 20819 | (when (and (or (setq fp (functionp org-agenda-skip-function)) | ||
| 20820 | (consp org-agenda-skip-function)) | ||
| 20821 | (setq to (save-excursion | ||
| 20822 | (save-match-data | ||
| 20823 | (if fp | ||
| 20824 | (funcall org-agenda-skip-function) | ||
| 20825 | (eval org-agenda-skip-function)))))) | ||
| 20826 | (goto-char to) | ||
| 20827 | (throw :skip t)))) | ||
| 20828 | |||
| 20829 | (defvar org-agenda-markers nil | ||
| 20830 | "List of all currently active markers created by `org-agenda'.") | ||
| 20831 | (defvar org-agenda-last-marker-time (time-to-seconds (current-time)) | ||
| 20832 | "Creation time of the last agenda marker.") | ||
| 20833 | |||
| 20834 | (defun org-agenda-new-marker (&optional pos) | ||
| 20835 | "Return a new agenda marker. | ||
| 20836 | Org-mode keeps a list of these markers and resets them when they are | ||
| 20837 | no longer in use." | ||
| 20838 | (let ((m (copy-marker (or pos (point))))) | ||
| 20839 | (setq org-agenda-last-marker-time (time-to-seconds (current-time))) | ||
| 20840 | (push m org-agenda-markers) | ||
| 20841 | m)) | ||
| 20842 | |||
| 20843 | (defun org-agenda-reset-markers () | ||
| 20844 | "Reset markers created by `org-agenda'." | ||
| 20845 | (while org-agenda-markers | ||
| 20846 | (move-marker (pop org-agenda-markers) nil))) | ||
| 20847 | |||
| 20848 | (defun org-get-agenda-file-buffer (file) | ||
| 20849 | "Get a buffer visiting FILE. If the buffer needs to be created, add | ||
| 20850 | it to the list of buffers which might be released later." | ||
| 20851 | (let ((buf (org-find-base-buffer-visiting file))) | ||
| 20852 | (if buf | ||
| 20853 | buf ; just return it | ||
| 20854 | ;; Make a new buffer and remember it | ||
| 20855 | (setq buf (find-file-noselect file)) | ||
| 20856 | (if buf (push buf org-agenda-new-buffers)) | ||
| 20857 | buf))) | ||
| 20858 | |||
| 20859 | (defun org-release-buffers (blist) | ||
| 20860 | "Release all buffers in list, asking the user for confirmation when needed. | ||
| 20861 | When a buffer is unmodified, it is just killed. When modified, it is saved | ||
| 20862 | \(if the user agrees) and then killed." | ||
| 20863 | (let (buf file) | ||
| 20864 | (while (setq buf (pop blist)) | ||
| 20865 | (setq file (buffer-file-name buf)) | ||
| 20866 | (when (and (buffer-modified-p buf) | ||
| 20867 | file | ||
| 20868 | (y-or-n-p (format "Save file %s? " file))) | ||
| 20869 | (with-current-buffer buf (save-buffer))) | ||
| 20870 | (kill-buffer buf)))) | ||
| 20871 | |||
| 20872 | (defun org-get-category (&optional pos) | ||
| 20873 | "Get the category applying to position POS." | ||
| 20874 | (get-text-property (or pos (point)) 'org-category)) | ||
| 20875 | |||
| 20876 | ;;; Agenda timeline | ||
| 20877 | |||
| 20878 | (defvar org-agenda-only-exact-dates nil) ; dynamically scoped | ||
| 20879 | |||
| 20880 | (defun org-timeline (&optional include-all) | ||
| 20881 | "Show a time-sorted view of the entries in the current org file. | ||
| 20882 | Only entries with a time stamp of today or later will be listed. With | ||
| 20883 | \\[universal-argument] prefix, all unfinished TODO items will also be shown, | ||
| 20884 | under the current date. | ||
| 20885 | If the buffer contains an active region, only check the region for | ||
| 20886 | dates." | ||
| 20887 | (interactive "P") | ||
| 20888 | (require 'calendar) | ||
| 20889 | (org-compile-prefix-format 'timeline) | ||
| 20890 | (org-set-sorting-strategy 'timeline) | ||
| 20891 | (let* ((dopast t) | ||
| 20892 | (dotodo include-all) | ||
| 20893 | (doclosed org-agenda-show-log) | ||
| 20894 | (entry buffer-file-name) | ||
| 20895 | (date (calendar-current-date)) | ||
| 20896 | (beg (if (org-region-active-p) (region-beginning) (point-min))) | ||
| 20897 | (end (if (org-region-active-p) (region-end) (point-max))) | ||
| 20898 | (day-numbers (org-get-all-dates beg end 'no-ranges | ||
| 20899 | t doclosed ; always include today | ||
| 20900 | org-timeline-show-empty-dates)) | ||
| 20901 | (org-deadline-warning-days 0) | ||
| 20902 | (org-agenda-only-exact-dates t) | ||
| 20903 | (today (time-to-days (current-time))) | ||
| 20904 | (past t) | ||
| 20905 | args | ||
| 20906 | s e rtn d emptyp) | ||
| 20907 | (setq org-agenda-redo-command | ||
| 20908 | (list 'progn | ||
| 20909 | (list 'org-switch-to-buffer-other-window (current-buffer)) | ||
| 20910 | (list 'org-timeline (list 'quote include-all)))) | ||
| 20911 | (if (not dopast) | ||
| 20912 | ;; Remove past dates from the list of dates. | ||
| 20913 | (setq day-numbers (delq nil (mapcar (lambda(x) | ||
| 20914 | (if (>= x today) x nil)) | ||
| 20915 | day-numbers)))) | ||
| 20916 | (org-prepare-agenda (concat "Timeline " | ||
| 20917 | (file-name-nondirectory buffer-file-name))) | ||
| 20918 | (if doclosed (push :closed args)) | ||
| 20919 | (push :timestamp args) | ||
| 20920 | (push :deadline args) | ||
| 20921 | (push :scheduled args) | ||
| 20922 | (push :sexp args) | ||
| 20923 | (if dotodo (push :todo args)) | ||
| 20924 | (while (setq d (pop day-numbers)) | ||
| 20925 | (if (and (listp d) (eq (car d) :omitted)) | ||
| 20926 | (progn | ||
| 20927 | (setq s (point)) | ||
| 20928 | (insert (format "\n[... %d empty days omitted]\n\n" (cdr d))) | ||
| 20929 | (put-text-property s (1- (point)) 'face 'org-agenda-structure)) | ||
| 20930 | (if (listp d) (setq d (car d) emptyp t) (setq emptyp nil)) | ||
| 20931 | (if (and (>= d today) | ||
| 20932 | dopast | ||
| 20933 | past) | ||
| 20934 | (progn | ||
| 20935 | (setq past nil) | ||
| 20936 | (insert (make-string 79 ?-) "\n"))) | ||
| 20937 | (setq date (calendar-gregorian-from-absolute d)) | ||
| 20938 | (setq s (point)) | ||
| 20939 | (setq rtn (and (not emptyp) | ||
| 20940 | (apply 'org-agenda-get-day-entries entry | ||
| 20941 | date args))) | ||
| 20942 | (if (or rtn (equal d today) org-timeline-show-empty-dates) | ||
| 20943 | (progn | ||
| 20944 | (insert | ||
| 20945 | (if (stringp org-agenda-format-date) | ||
| 20946 | (format-time-string org-agenda-format-date | ||
| 20947 | (org-time-from-absolute date)) | ||
| 20948 | (funcall org-agenda-format-date date)) | ||
| 20949 | "\n") | ||
| 20950 | (put-text-property s (1- (point)) 'face 'org-agenda-structure) | ||
| 20951 | (put-text-property s (1- (point)) 'org-date-line t) | ||
| 20952 | (if (equal d today) | ||
| 20953 | (put-text-property s (1- (point)) 'org-today t)) | ||
| 20954 | (and rtn (insert (org-finalize-agenda-entries rtn) "\n")) | ||
| 20955 | (put-text-property s (1- (point)) 'day d))))) | ||
| 20956 | (goto-char (point-min)) | ||
| 20957 | (goto-char (or (text-property-any (point-min) (point-max) 'org-today t) | ||
| 20958 | (point-min))) | ||
| 20959 | (add-text-properties (point-min) (point-max) '(org-agenda-type timeline)) | ||
| 20960 | (org-finalize-agenda) | ||
| 20961 | (setq buffer-read-only t))) | ||
| 20962 | |||
| 20963 | (defun org-get-all-dates (beg end &optional no-ranges force-today inactive empty pre-re) | ||
| 20964 | "Return a list of all relevant day numbers from BEG to END buffer positions. | ||
| 20965 | If NO-RANGES is non-nil, include only the start and end dates of a range, | ||
| 20966 | not every single day in the range. If FORCE-TODAY is non-nil, make | ||
| 20967 | sure that TODAY is included in the list. If INACTIVE is non-nil, also | ||
| 20968 | inactive time stamps (those in square brackets) are included. | ||
| 20969 | When EMPTY is non-nil, also include days without any entries." | ||
| 20970 | (let ((re (concat | ||
| 20971 | (if pre-re pre-re "") | ||
| 20972 | (if inactive org-ts-regexp-both org-ts-regexp))) | ||
| 20973 | dates dates1 date day day1 day2 ts1 ts2) | ||
| 20974 | (if force-today | ||
| 20975 | (setq dates (list (time-to-days (current-time))))) | ||
| 20976 | (save-excursion | ||
| 20977 | (goto-char beg) | ||
| 20978 | (while (re-search-forward re end t) | ||
| 20979 | (setq day (time-to-days (org-time-string-to-time | ||
| 20980 | (substring (match-string 1) 0 10)))) | ||
| 20981 | (or (memq day dates) (push day dates))) | ||
| 20982 | (unless no-ranges | ||
| 20983 | (goto-char beg) | ||
| 20984 | (while (re-search-forward org-tr-regexp end t) | ||
| 20985 | (setq ts1 (substring (match-string 1) 0 10) | ||
| 20986 | ts2 (substring (match-string 2) 0 10) | ||
| 20987 | day1 (time-to-days (org-time-string-to-time ts1)) | ||
| 20988 | day2 (time-to-days (org-time-string-to-time ts2))) | ||
| 20989 | (while (< (setq day1 (1+ day1)) day2) | ||
| 20990 | (or (memq day1 dates) (push day1 dates))))) | ||
| 20991 | (setq dates (sort dates '<)) | ||
| 20992 | (when empty | ||
| 20993 | (while (setq day (pop dates)) | ||
| 20994 | (setq day2 (car dates)) | ||
| 20995 | (push day dates1) | ||
| 20996 | (when (and day2 empty) | ||
| 20997 | (if (or (eq empty t) | ||
| 20998 | (and (numberp empty) (<= (- day2 day) empty))) | ||
| 20999 | (while (< (setq day (1+ day)) day2) | ||
| 21000 | (push (list day) dates1)) | ||
| 21001 | (push (cons :omitted (- day2 day)) dates1)))) | ||
| 21002 | (setq dates (nreverse dates1))) | ||
| 21003 | dates))) | ||
| 21004 | |||
| 21005 | ;;; Agenda Daily/Weekly | ||
| 21006 | |||
| 21007 | (defvar org-agenda-overriding-arguments nil) ; dynamically scoped parameter | ||
| 21008 | (defvar org-agenda-start-day nil) ; dynamically scoped parameter | ||
| 21009 | (defvar org-agenda-last-arguments nil | ||
| 21010 | "The arguments of the previous call to org-agenda") | ||
| 21011 | (defvar org-starting-day nil) ; local variable in the agenda buffer | ||
| 21012 | (defvar org-agenda-span nil) ; local variable in the agenda buffer | ||
| 21013 | (defvar org-include-all-loc nil) ; local variable | ||
| 21014 | (defvar org-agenda-remove-date nil) ; dynamically scoped FIXME: not used??? | ||
| 21015 | |||
| 21016 | ;;;###autoload | ||
| 21017 | (defun org-agenda-list (&optional include-all start-day ndays) | ||
| 21018 | "Produce a daily/weekly view from all files in variable `org-agenda-files'. | ||
| 21019 | The view will be for the current day or week, but from the overview buffer | ||
| 21020 | you will be able to go to other days/weeks. | ||
| 21021 | |||
| 21022 | With one \\[universal-argument] prefix argument INCLUDE-ALL, | ||
| 21023 | all unfinished TODO items will also be shown, before the agenda. | ||
| 21024 | This feature is considered obsolete, please use the TODO list or a block | ||
| 21025 | agenda instead. | ||
| 21026 | |||
| 21027 | With a numeric prefix argument in an interactive call, the agenda will | ||
| 21028 | span INCLUDE-ALL days. Lisp programs should instead specify NDAYS to change | ||
| 21029 | the number of days. NDAYS defaults to `org-agenda-ndays'. | ||
| 21030 | |||
| 21031 | START-DAY defaults to TODAY, or to the most recent match for the weekday | ||
| 21032 | given in `org-agenda-start-on-weekday'." | ||
| 21033 | (interactive "P") | ||
| 21034 | (if (and (integerp include-all) (> include-all 0)) | ||
| 21035 | (setq ndays include-all include-all nil)) | ||
| 21036 | (setq ndays (or ndays org-agenda-ndays) | ||
| 21037 | start-day (or start-day org-agenda-start-day)) | ||
| 21038 | (if org-agenda-overriding-arguments | ||
| 21039 | (setq include-all (car org-agenda-overriding-arguments) | ||
| 21040 | start-day (nth 1 org-agenda-overriding-arguments) | ||
| 21041 | ndays (nth 2 org-agenda-overriding-arguments))) | ||
| 21042 | (if (stringp start-day) | ||
| 21043 | ;; Convert to an absolute day number | ||
| 21044 | (setq start-day (time-to-days (org-read-date nil t start-day)))) | ||
| 21045 | (setq org-agenda-last-arguments (list include-all start-day ndays)) | ||
| 21046 | (org-compile-prefix-format 'agenda) | ||
| 21047 | (org-set-sorting-strategy 'agenda) | ||
| 21048 | (require 'calendar) | ||
| 21049 | (let* ((org-agenda-start-on-weekday | ||
| 21050 | (if (or (equal ndays 7) (and (null ndays) (equal 7 org-agenda-ndays))) | ||
| 21051 | org-agenda-start-on-weekday nil)) | ||
| 21052 | (thefiles (org-agenda-files)) | ||
| 21053 | (files thefiles) | ||
| 21054 | (today (time-to-days | ||
| 21055 | (time-subtract (current-time) | ||
| 21056 | (list 0 (* 3600 org-extend-today-until) 0)))) | ||
| 21057 | (sd (or start-day today)) | ||
| 21058 | (start (if (or (null org-agenda-start-on-weekday) | ||
| 21059 | (< org-agenda-ndays 7)) | ||
| 21060 | sd | ||
| 21061 | (let* ((nt (calendar-day-of-week | ||
| 21062 | (calendar-gregorian-from-absolute sd))) | ||
| 21063 | (n1 org-agenda-start-on-weekday) | ||
| 21064 | (d (- nt n1))) | ||
| 21065 | (- sd (+ (if (< d 0) 7 0) d))))) | ||
| 21066 | (day-numbers (list start)) | ||
| 21067 | (day-cnt 0) | ||
| 21068 | (inhibit-redisplay (not debug-on-error)) | ||
| 21069 | s e rtn rtnall file date d start-pos end-pos todayp nd) | ||
| 21070 | (setq org-agenda-redo-command | ||
| 21071 | (list 'org-agenda-list (list 'quote include-all) start-day ndays)) | ||
| 21072 | ;; Make the list of days | ||
| 21073 | (setq ndays (or ndays org-agenda-ndays) | ||
| 21074 | nd ndays) | ||
| 21075 | (while (> ndays 1) | ||
| 21076 | (push (1+ (car day-numbers)) day-numbers) | ||
| 21077 | (setq ndays (1- ndays))) | ||
| 21078 | (setq day-numbers (nreverse day-numbers)) | ||
| 21079 | (org-prepare-agenda "Day/Week") | ||
| 21080 | (org-set-local 'org-starting-day (car day-numbers)) | ||
| 21081 | (org-set-local 'org-include-all-loc include-all) | ||
| 21082 | (org-set-local 'org-agenda-span | ||
| 21083 | (org-agenda-ndays-to-span nd)) | ||
| 21084 | (when (and (or include-all org-agenda-include-all-todo) | ||
| 21085 | (member today day-numbers)) | ||
| 21086 | (setq files thefiles | ||
| 21087 | rtnall nil) | ||
| 21088 | (while (setq file (pop files)) | ||
| 21089 | (catch 'nextfile | ||
| 21090 | (org-check-agenda-file file) | ||
| 21091 | (setq date (calendar-gregorian-from-absolute today) | ||
| 21092 | rtn (org-agenda-get-day-entries | ||
| 21093 | file date :todo)) | ||
| 21094 | (setq rtnall (append rtnall rtn)))) | ||
| 21095 | (when rtnall | ||
| 21096 | (insert "ALL CURRENTLY OPEN TODO ITEMS:\n") | ||
| 21097 | (add-text-properties (point-min) (1- (point)) | ||
| 21098 | (list 'face 'org-agenda-structure)) | ||
| 21099 | (insert (org-finalize-agenda-entries rtnall) "\n"))) | ||
| 21100 | (unless org-agenda-compact-blocks | ||
| 21101 | (setq s (point)) | ||
| 21102 | (insert (capitalize (symbol-name (org-agenda-ndays-to-span nd))) | ||
| 21103 | "-agenda:\n") | ||
| 21104 | (add-text-properties s (1- (point)) (list 'face 'org-agenda-structure | ||
| 21105 | 'org-date-line t))) | ||
| 21106 | (while (setq d (pop day-numbers)) | ||
| 21107 | (setq date (calendar-gregorian-from-absolute d) | ||
| 21108 | s (point)) | ||
| 21109 | (if (or (setq todayp (= d today)) | ||
| 21110 | (and (not start-pos) (= d sd))) | ||
| 21111 | (setq start-pos (point)) | ||
| 21112 | (if (and start-pos (not end-pos)) | ||
| 21113 | (setq end-pos (point)))) | ||
| 21114 | (setq files thefiles | ||
| 21115 | rtnall nil) | ||
| 21116 | (while (setq file (pop files)) | ||
| 21117 | (catch 'nextfile | ||
| 21118 | (org-check-agenda-file file) | ||
| 21119 | (if org-agenda-show-log | ||
| 21120 | (setq rtn (org-agenda-get-day-entries | ||
| 21121 | file date | ||
| 21122 | :deadline :scheduled :timestamp :sexp :closed)) | ||
| 21123 | (setq rtn (org-agenda-get-day-entries | ||
| 21124 | file date | ||
| 21125 | :deadline :scheduled :sexp :timestamp))) | ||
| 21126 | (setq rtnall (append rtnall rtn)))) | ||
| 21127 | (if org-agenda-include-diary | ||
| 21128 | (progn | ||
| 21129 | (require 'diary-lib) | ||
| 21130 | (setq rtn (org-get-entries-from-diary date)) | ||
| 21131 | (setq rtnall (append rtnall rtn)))) | ||
| 21132 | (if (or rtnall org-agenda-show-all-dates) | ||
| 21133 | (progn | ||
| 21134 | (setq day-cnt (1+ day-cnt)) | ||
| 21135 | (insert | ||
| 21136 | (if (stringp org-agenda-format-date) | ||
| 21137 | (format-time-string org-agenda-format-date | ||
| 21138 | (org-time-from-absolute date)) | ||
| 21139 | (funcall org-agenda-format-date date)) | ||
| 21140 | "\n") | ||
| 21141 | (put-text-property s (1- (point)) 'face 'org-agenda-structure) | ||
| 21142 | (put-text-property s (1- (point)) 'org-date-line t) | ||
| 21143 | (put-text-property s (1- (point)) 'org-day-cnt day-cnt) | ||
| 21144 | (if todayp (put-text-property s (1- (point)) 'org-today t)) | ||
| 21145 | (if rtnall (insert | ||
| 21146 | (org-finalize-agenda-entries | ||
| 21147 | (org-agenda-add-time-grid-maybe | ||
| 21148 | rtnall nd todayp)) | ||
| 21149 | "\n")) | ||
| 21150 | (put-text-property s (1- (point)) 'day d) | ||
| 21151 | (put-text-property s (1- (point)) 'org-day-cnt day-cnt)))) | ||
| 21152 | (goto-char (point-min)) | ||
| 21153 | (org-fit-agenda-window) | ||
| 21154 | (unless (and (pos-visible-in-window-p (point-min)) | ||
| 21155 | (pos-visible-in-window-p (point-max))) | ||
| 21156 | (goto-char (1- (point-max))) | ||
| 21157 | (recenter -1) | ||
| 21158 | (if (not (pos-visible-in-window-p (or start-pos 1))) | ||
| 21159 | (progn | ||
| 21160 | (goto-char (or start-pos 1)) | ||
| 21161 | (recenter 1)))) | ||
| 21162 | (goto-char (or start-pos 1)) | ||
| 21163 | (add-text-properties (point-min) (point-max) '(org-agenda-type agenda)) | ||
| 21164 | (org-finalize-agenda) | ||
| 21165 | (setq buffer-read-only t) | ||
| 21166 | (message ""))) | ||
| 21167 | |||
| 21168 | (defun org-agenda-ndays-to-span (n) | ||
| 21169 | (cond ((< n 7) 'day) ((= n 7) 'week) ((< n 32) 'month) (t 'year))) | ||
| 21170 | |||
| 21171 | ;;; Agenda word search | ||
| 21172 | |||
| 21173 | (defvar org-agenda-search-history nil) | ||
| 21174 | |||
| 21175 | ;;;###autoload | ||
| 21176 | (defun org-search-view (&optional arg string) | ||
| 21177 | "Show all entries that contain words or regular expressions. | ||
| 21178 | If the first character of the search string is an asterisks, | ||
| 21179 | search only the headlines. | ||
| 21180 | |||
| 21181 | The search string is broken into \"words\" by splitting at whitespace. | ||
| 21182 | The individual words are then interpreted as a boolean expression with | ||
| 21183 | logical AND. Words prefixed with a minus must not occur in the entry. | ||
| 21184 | Words without a prefix or prefixed with a plus must occur in the entry. | ||
| 21185 | Matching is case-insensitive and the words are enclosed by word delimiters. | ||
| 21186 | |||
| 21187 | Words enclosed by curly braces are interpreted as regular expressions | ||
| 21188 | that must or must not match in the entry. | ||
| 21189 | |||
| 21190 | This command searches the agenda files, and in addition the files listed | ||
| 21191 | in `org-agenda-text-search-extra-files'." | ||
| 21192 | (interactive "P") | ||
| 21193 | (org-compile-prefix-format 'search) | ||
| 21194 | (org-set-sorting-strategy 'search) | ||
| 21195 | (org-prepare-agenda "SEARCH") | ||
| 21196 | (let* ((props (list 'face nil | ||
| 21197 | 'done-face 'org-done | ||
| 21198 | 'org-not-done-regexp org-not-done-regexp | ||
| 21199 | 'org-todo-regexp org-todo-regexp | ||
| 21200 | 'mouse-face 'highlight | ||
| 21201 | 'keymap org-agenda-keymap | ||
| 21202 | 'help-echo (format "mouse-2 or RET jump to location"))) | ||
| 21203 | regexp rtn rtnall files file pos | ||
| 21204 | marker priority category tags c neg re | ||
| 21205 | ee txt beg end words regexps+ regexps- hdl-only buffer beg1 str) | ||
| 21206 | (unless (and (not arg) | ||
| 21207 | (stringp string) | ||
| 21208 | (string-match "\\S-" string)) | ||
| 21209 | (setq string (read-string "[+-]Word/{Regexp} ...: " | ||
| 21210 | (cond | ||
| 21211 | ((integerp arg) (cons string arg)) | ||
| 21212 | (arg string)) | ||
| 21213 | 'org-agenda-search-history))) | ||
| 21214 | (setq org-agenda-redo-command | ||
| 21215 | (list 'org-search-view 'current-prefix-arg string)) | ||
| 21216 | (setq org-agenda-query-string string) | ||
| 21217 | |||
| 21218 | (if (equal (string-to-char string) ?*) | ||
| 21219 | (setq hdl-only t | ||
| 21220 | words (substring string 1)) | ||
| 21221 | (setq words string)) | ||
| 21222 | (setq words (org-split-string words)) | ||
| 21223 | (mapc (lambda (w) | ||
| 21224 | (setq c (string-to-char w)) | ||
| 21225 | (if (equal c ?-) | ||
| 21226 | (setq neg t w (substring w 1)) | ||
| 21227 | (if (equal c ?+) | ||
| 21228 | (setq neg nil w (substring w 1)) | ||
| 21229 | (setq neg nil))) | ||
| 21230 | (if (string-match "\\`{.*}\\'" w) | ||
| 21231 | (setq re (substring w 1 -1)) | ||
| 21232 | (setq re (concat "\\<" (regexp-quote (downcase w)) "\\>"))) | ||
| 21233 | (if neg (push re regexps-) (push re regexps+))) | ||
| 21234 | words) | ||
| 21235 | (setq regexps+ (sort regexps+ (lambda (a b) (> (length a) (length b))))) | ||
| 21236 | (if (not regexps+) | ||
| 21237 | (setq regexp (concat "^" org-outline-regexp)) | ||
| 21238 | (setq regexp (pop regexps+)) | ||
| 21239 | (if hdl-only (setq regexp (concat "^" org-outline-regexp ".*?" | ||
| 21240 | regexp)))) | ||
| 21241 | (setq files (append (org-agenda-files) org-agenda-text-search-extra-files) | ||
| 21242 | rtnall nil) | ||
| 21243 | (while (setq file (pop files)) | ||
| 21244 | (setq ee nil) | ||
| 21245 | (catch 'nextfile | ||
| 21246 | (org-check-agenda-file file) | ||
| 21247 | (setq buffer (if (file-exists-p file) | ||
| 21248 | (org-get-agenda-file-buffer file) | ||
| 21249 | (error "No such file %s" file))) | ||
| 21250 | (if (not buffer) | ||
| 21251 | ;; If file does not exist, make sure an error message is sent | ||
| 21252 | (setq rtn (list (format "ORG-AGENDA-ERROR: No such org-file %s" | ||
| 21253 | file)))) | ||
| 21254 | (with-current-buffer buffer | ||
| 21255 | (unless (org-mode-p) | ||
| 21256 | (error "Agenda file %s is not in `org-mode'" file)) | ||
| 21257 | (let ((case-fold-search t)) | ||
| 21258 | (save-excursion | ||
| 21259 | (save-restriction | ||
| 21260 | (if org-agenda-restrict | ||
| 21261 | (narrow-to-region org-agenda-restrict-begin | ||
| 21262 | org-agenda-restrict-end) | ||
| 21263 | (widen)) | ||
| 21264 | (goto-char (point-min)) | ||
| 21265 | (unless (or (org-on-heading-p) | ||
| 21266 | (outline-next-heading)) | ||
| 21267 | (throw 'nextfile t)) | ||
| 21268 | (goto-char (max (point-min) (1- (point)))) | ||
| 21269 | (while (re-search-forward regexp nil t) | ||
| 21270 | (org-back-to-heading t) | ||
| 21271 | (skip-chars-forward "* ") | ||
| 21272 | (setq beg (point-at-bol) | ||
| 21273 | beg1 (point) | ||
| 21274 | end (progn (outline-next-heading) (point))) | ||
| 21275 | (catch :skip | ||
| 21276 | (goto-char beg) | ||
| 21277 | (org-agenda-skip) | ||
| 21278 | (setq str (buffer-substring-no-properties | ||
| 21279 | (point-at-bol) | ||
| 21280 | (if hdl-only (point-at-eol) end))) | ||
| 21281 | (mapc (lambda (wr) (when (string-match wr str) | ||
| 21282 | (goto-char (1- end)) | ||
| 21283 | (throw :skip t))) | ||
| 21284 | regexps-) | ||
| 21285 | (mapc (lambda (wr) (unless (string-match wr str) | ||
| 21286 | (goto-char (1- end)) | ||
| 21287 | (throw :skip t))) | ||
| 21288 | regexps+) | ||
| 21289 | (goto-char beg) | ||
| 21290 | (setq marker (org-agenda-new-marker (point)) | ||
| 21291 | category (org-get-category) | ||
| 21292 | tags (org-get-tags-at (point)) | ||
| 21293 | txt (org-format-agenda-item | ||
| 21294 | "" | ||
| 21295 | (buffer-substring-no-properties | ||
| 21296 | beg1 (point-at-eol)) | ||
| 21297 | category tags)) | ||
| 21298 | (org-add-props txt props | ||
| 21299 | 'org-marker marker 'org-hd-marker marker | ||
| 21300 | 'priority 1000 'org-category category | ||
| 21301 | 'type "search") | ||
| 21302 | (push txt ee) | ||
| 21303 | (goto-char (1- end))))))))) | ||
| 21304 | (setq rtn (nreverse ee)) | ||
| 21305 | (setq rtnall (append rtnall rtn))) | ||
| 21306 | (if org-agenda-overriding-header | ||
| 21307 | (insert (org-add-props (copy-sequence org-agenda-overriding-header) | ||
| 21308 | nil 'face 'org-agenda-structure) "\n") | ||
| 21309 | (insert "Search words: ") | ||
| 21310 | (add-text-properties (point-min) (1- (point)) | ||
| 21311 | (list 'face 'org-agenda-structure)) | ||
| 21312 | (setq pos (point)) | ||
| 21313 | (insert string "\n") | ||
| 21314 | (add-text-properties pos (1- (point)) (list 'face 'org-warning)) | ||
| 21315 | (setq pos (point)) | ||
| 21316 | (unless org-agenda-multi | ||
| 21317 | (insert "Press `[', `]' to add/sub word, `{', `}' to add/sub regexp, `C-u r' to edit\n") | ||
| 21318 | (add-text-properties pos (1- (point)) | ||
| 21319 | (list 'face 'org-agenda-structure)))) | ||
| 21320 | (when rtnall | ||
| 21321 | (insert (org-finalize-agenda-entries rtnall) "\n")) | ||
| 21322 | (goto-char (point-min)) | ||
| 21323 | (org-fit-agenda-window) | ||
| 21324 | (add-text-properties (point-min) (point-max) '(org-agenda-type search)) | ||
| 21325 | (org-finalize-agenda) | ||
| 21326 | (setq buffer-read-only t))) | ||
| 21327 | |||
| 21328 | ;;; Agenda TODO list | ||
| 21329 | |||
| 21330 | (defvar org-select-this-todo-keyword nil) | ||
| 21331 | (defvar org-last-arg nil) | ||
| 21332 | |||
| 21333 | ;;;###autoload | ||
| 21334 | (defun org-todo-list (arg) | ||
| 21335 | "Show all TODO entries from all agenda file in a single list. | ||
| 21336 | The prefix arg can be used to select a specific TODO keyword and limit | ||
| 21337 | the list to these. When using \\[universal-argument], you will be prompted | ||
| 21338 | for a keyword. A numeric prefix directly selects the Nth keyword in | ||
| 21339 | `org-todo-keywords-1'." | ||
| 21340 | (interactive "P") | ||
| 21341 | (require 'calendar) | ||
| 21342 | (org-compile-prefix-format 'todo) | ||
| 21343 | (org-set-sorting-strategy 'todo) | ||
| 21344 | (org-prepare-agenda "TODO") | ||
| 21345 | (let* ((today (time-to-days (current-time))) | ||
| 21346 | (date (calendar-gregorian-from-absolute today)) | ||
| 21347 | (kwds org-todo-keywords-for-agenda) | ||
| 21348 | (completion-ignore-case t) | ||
| 21349 | (org-select-this-todo-keyword | ||
| 21350 | (if (stringp arg) arg | ||
| 21351 | (and arg (integerp arg) (> arg 0) | ||
| 21352 | (nth (1- arg) kwds)))) | ||
| 21353 | rtn rtnall files file pos) | ||
| 21354 | (when (equal arg '(4)) | ||
| 21355 | (setq org-select-this-todo-keyword | ||
| 21356 | (completing-read "Keyword (or KWD1|K2D2|...): " | ||
| 21357 | (mapcar 'list kwds) nil nil))) | ||
| 21358 | (and (equal 0 arg) (setq org-select-this-todo-keyword nil)) | ||
| 21359 | (org-set-local 'org-last-arg arg) | ||
| 21360 | (setq org-agenda-redo-command | ||
| 21361 | '(org-todo-list (or current-prefix-arg org-last-arg))) | ||
| 21362 | (setq files (org-agenda-files) | ||
| 21363 | rtnall nil) | ||
| 21364 | (while (setq file (pop files)) | ||
| 21365 | (catch 'nextfile | ||
| 21366 | (org-check-agenda-file file) | ||
| 21367 | (setq rtn (org-agenda-get-day-entries file date :todo)) | ||
| 21368 | (setq rtnall (append rtnall rtn)))) | ||
| 21369 | (if org-agenda-overriding-header | ||
| 21370 | (insert (org-add-props (copy-sequence org-agenda-overriding-header) | ||
| 21371 | nil 'face 'org-agenda-structure) "\n") | ||
| 21372 | (insert "Global list of TODO items of type: ") | ||
| 21373 | (add-text-properties (point-min) (1- (point)) | ||
| 21374 | (list 'face 'org-agenda-structure)) | ||
| 21375 | (setq pos (point)) | ||
| 21376 | (insert (or org-select-this-todo-keyword "ALL") "\n") | ||
| 21377 | (add-text-properties pos (1- (point)) (list 'face 'org-warning)) | ||
| 21378 | (setq pos (point)) | ||
| 21379 | (unless org-agenda-multi | ||
| 21380 | (insert "Available with `N r': (0)ALL") | ||
| 21381 | (let ((n 0) s) | ||
| 21382 | (mapc (lambda (x) | ||
| 21383 | (setq s (format "(%d)%s" (setq n (1+ n)) x)) | ||
| 21384 | (if (> (+ (current-column) (string-width s) 1) (frame-width)) | ||
| 21385 | (insert "\n ")) | ||
| 21386 | (insert " " s)) | ||
| 21387 | kwds)) | ||
| 21388 | (insert "\n")) | ||
| 21389 | (add-text-properties pos (1- (point)) (list 'face 'org-agenda-structure))) | ||
| 21390 | (when rtnall | ||
| 21391 | (insert (org-finalize-agenda-entries rtnall) "\n")) | ||
| 21392 | (goto-char (point-min)) | ||
| 21393 | (org-fit-agenda-window) | ||
| 21394 | (add-text-properties (point-min) (point-max) '(org-agenda-type todo)) | ||
| 21395 | (org-finalize-agenda) | ||
| 21396 | (setq buffer-read-only t))) | ||
| 21397 | |||
| 21398 | ;;; Agenda tags match | ||
| 21399 | |||
| 21400 | ;;;###autoload | ||
| 21401 | (defun org-tags-view (&optional todo-only match) | ||
| 21402 | "Show all headlines for all `org-agenda-files' matching a TAGS criterion. | ||
| 21403 | The prefix arg TODO-ONLY limits the search to TODO entries." | ||
| 21404 | (interactive "P") | ||
| 21405 | (org-compile-prefix-format 'tags) | ||
| 21406 | (org-set-sorting-strategy 'tags) | ||
| 21407 | (let* ((org-tags-match-list-sublevels | ||
| 21408 | (if todo-only t org-tags-match-list-sublevels)) | ||
| 21409 | (completion-ignore-case t) | ||
| 21410 | rtn rtnall files file pos matcher | ||
| 21411 | buffer) | ||
| 21412 | (setq matcher (org-make-tags-matcher match) | ||
| 21413 | match (car matcher) matcher (cdr matcher)) | ||
| 21414 | (org-prepare-agenda (concat "TAGS " match)) | ||
| 21415 | (setq org-agenda-query-string match) | ||
| 21416 | (setq org-agenda-redo-command | ||
| 21417 | (list 'org-tags-view (list 'quote todo-only) | ||
| 21418 | (list 'if 'current-prefix-arg nil 'org-agenda-query-string))) | ||
| 21419 | (setq files (org-agenda-files) | ||
| 21420 | rtnall nil) | ||
| 21421 | (while (setq file (pop files)) | ||
| 21422 | (catch 'nextfile | ||
| 21423 | (org-check-agenda-file file) | ||
| 21424 | (setq buffer (if (file-exists-p file) | ||
| 21425 | (org-get-agenda-file-buffer file) | ||
| 21426 | (error "No such file %s" file))) | ||
| 21427 | (if (not buffer) | ||
| 21428 | ;; If file does not exist, merror message to agenda | ||
| 21429 | (setq rtn (list | ||
| 21430 | (format "ORG-AGENDA-ERROR: No such org-file %s" file)) | ||
| 21431 | rtnall (append rtnall rtn)) | ||
| 21432 | (with-current-buffer buffer | ||
| 21433 | (unless (org-mode-p) | ||
| 21434 | (error "Agenda file %s is not in `org-mode'" file)) | ||
| 21435 | (save-excursion | ||
| 21436 | (save-restriction | ||
| 21437 | (if org-agenda-restrict | ||
| 21438 | (narrow-to-region org-agenda-restrict-begin | ||
| 21439 | org-agenda-restrict-end) | ||
| 21440 | (widen)) | ||
| 21441 | (setq rtn (org-scan-tags 'agenda matcher todo-only)) | ||
| 21442 | (setq rtnall (append rtnall rtn)))))))) | ||
| 21443 | (if org-agenda-overriding-header | ||
| 21444 | (insert (org-add-props (copy-sequence org-agenda-overriding-header) | ||
| 21445 | nil 'face 'org-agenda-structure) "\n") | ||
| 21446 | (insert "Headlines with TAGS match: ") | ||
| 21447 | (add-text-properties (point-min) (1- (point)) | ||
| 21448 | (list 'face 'org-agenda-structure)) | ||
| 21449 | (setq pos (point)) | ||
| 21450 | (insert match "\n") | ||
| 21451 | (add-text-properties pos (1- (point)) (list 'face 'org-warning)) | ||
| 21452 | (setq pos (point)) | ||
| 21453 | (unless org-agenda-multi | ||
| 21454 | (insert "Press `C-u r' to search again with new search string\n")) | ||
| 21455 | (add-text-properties pos (1- (point)) (list 'face 'org-agenda-structure))) | ||
| 21456 | (when rtnall | ||
| 21457 | (insert (org-finalize-agenda-entries rtnall) "\n")) | ||
| 21458 | (goto-char (point-min)) | ||
| 21459 | (org-fit-agenda-window) | ||
| 21460 | (add-text-properties (point-min) (point-max) '(org-agenda-type tags)) | ||
| 21461 | (org-finalize-agenda) | ||
| 21462 | (setq buffer-read-only t))) | ||
| 21463 | |||
| 21464 | ;;; Agenda Finding stuck projects | ||
| 21465 | |||
| 21466 | (defvar org-agenda-skip-regexp nil | ||
| 21467 | "Regular expression used in skipping subtrees for the agenda. | ||
| 21468 | This is basically a temporary global variable that can be set and then | ||
| 21469 | used by user-defined selections using `org-agenda-skip-function'.") | ||
| 21470 | |||
| 21471 | (defvar org-agenda-overriding-header nil | ||
| 21472 | "When this is set during todo and tags searches, will replace header.") | ||
| 21473 | |||
| 21474 | (defun org-agenda-skip-subtree-when-regexp-matches () | ||
| 21475 | "Checks if the current subtree contains match for `org-agenda-skip-regexp'. | ||
| 21476 | If yes, it returns the end position of this tree, causing agenda commands | ||
| 21477 | to skip this subtree. This is a function that can be put into | ||
| 21478 | `org-agenda-skip-function' for the duration of a command." | ||
| 21479 | (let ((end (save-excursion (org-end-of-subtree t))) | ||
| 21480 | skip) | ||
| 21481 | (save-excursion | ||
| 21482 | (setq skip (re-search-forward org-agenda-skip-regexp end t))) | ||
| 21483 | (and skip end))) | ||
| 21484 | |||
| 21485 | (defun org-agenda-skip-entry-if (&rest conditions) | ||
| 21486 | "Skip entry if any of CONDITIONS is true. | ||
| 21487 | See `org-agenda-skip-if' for details." | ||
| 21488 | (org-agenda-skip-if nil conditions)) | ||
| 21489 | |||
| 21490 | (defun org-agenda-skip-subtree-if (&rest conditions) | ||
| 21491 | "Skip entry if any of CONDITIONS is true. | ||
| 21492 | See `org-agenda-skip-if' for details." | ||
| 21493 | (org-agenda-skip-if t conditions)) | ||
| 21494 | |||
| 21495 | (defun org-agenda-skip-if (subtree conditions) | ||
| 21496 | "Checks current entity for CONDITIONS. | ||
| 21497 | If SUBTREE is non-nil, the entire subtree is checked. Otherwise, only | ||
| 21498 | the entry, i.e. the text before the next heading is checked. | ||
| 21499 | |||
| 21500 | CONDITIONS is a list of symbols, boolean OR is used to combine the results | ||
| 21501 | from different tests. Valid conditions are: | ||
| 21502 | |||
| 21503 | scheduled Check if there is a scheduled cookie | ||
| 21504 | notscheduled Check if there is no scheduled cookie | ||
| 21505 | deadline Check if there is a deadline | ||
| 21506 | notdeadline Check if there is no deadline | ||
| 21507 | regexp Check if regexp matches | ||
| 21508 | notregexp Check if regexp does not match. | ||
| 21509 | |||
| 21510 | The regexp is taken from the conditions list, it must come right after | ||
| 21511 | the `regexp' or `notregexp' element. | ||
| 21512 | |||
| 21513 | If any of these conditions is met, this function returns the end point of | ||
| 21514 | the entity, causing the search to continue from there. This is a function | ||
| 21515 | that can be put into `org-agenda-skip-function' for the duration of a command." | ||
| 21516 | (let (beg end m) | ||
| 21517 | (org-back-to-heading t) | ||
| 21518 | (setq beg (point) | ||
| 21519 | end (if subtree | ||
| 21520 | (progn (org-end-of-subtree t) (point)) | ||
| 21521 | (progn (outline-next-heading) (1- (point))))) | ||
| 21522 | (goto-char beg) | ||
| 21523 | (and | ||
| 21524 | (or | ||
| 21525 | (and (memq 'scheduled conditions) | ||
| 21526 | (re-search-forward org-scheduled-time-regexp end t)) | ||
| 21527 | (and (memq 'notscheduled conditions) | ||
| 21528 | (not (re-search-forward org-scheduled-time-regexp end t))) | ||
| 21529 | (and (memq 'deadline conditions) | ||
| 21530 | (re-search-forward org-deadline-time-regexp end t)) | ||
| 21531 | (and (memq 'notdeadline conditions) | ||
| 21532 | (not (re-search-forward org-deadline-time-regexp end t))) | ||
| 21533 | (and (setq m (memq 'regexp conditions)) | ||
| 21534 | (stringp (nth 1 m)) | ||
| 21535 | (re-search-forward (nth 1 m) end t)) | ||
| 21536 | (and (setq m (memq 'notregexp conditions)) | ||
| 21537 | (stringp (nth 1 m)) | ||
| 21538 | (not (re-search-forward (nth 1 m) end t)))) | ||
| 21539 | end))) | ||
| 21540 | |||
| 21541 | ;;;###autoload | ||
| 21542 | (defun org-agenda-list-stuck-projects (&rest ignore) | ||
| 21543 | "Create agenda view for projects that are stuck. | ||
| 21544 | Stuck projects are project that have no next actions. For the definitions | ||
| 21545 | of what a project is and how to check if it stuck, customize the variable | ||
| 21546 | `org-stuck-projects'. | ||
| 21547 | MATCH is being ignored." | ||
| 21548 | (interactive) | ||
| 21549 | (let* ((org-agenda-skip-function 'org-agenda-skip-subtree-when-regexp-matches) | ||
| 21550 | ;; FIXME: we could have used org-agenda-skip-if here. | ||
| 21551 | (org-agenda-overriding-header "List of stuck projects: ") | ||
| 21552 | (matcher (nth 0 org-stuck-projects)) | ||
| 21553 | (todo (nth 1 org-stuck-projects)) | ||
| 21554 | (todo-wds (if (member "*" todo) | ||
| 21555 | (progn | ||
| 21556 | (org-prepare-agenda-buffers (org-agenda-files)) | ||
| 21557 | (org-delete-all | ||
| 21558 | org-done-keywords-for-agenda | ||
| 21559 | (copy-sequence org-todo-keywords-for-agenda))) | ||
| 21560 | todo)) | ||
| 21561 | (todo-re (concat "^\\*+[ \t]+\\(" | ||
| 21562 | (mapconcat 'identity todo-wds "\\|") | ||
| 21563 | "\\)\\>")) | ||
| 21564 | (tags (nth 2 org-stuck-projects)) | ||
| 21565 | (tags-re (if (member "*" tags) | ||
| 21566 | (org-re "^\\*+ .*:[[:alnum:]_@]+:[ \t]*$") | ||
| 21567 | (concat "^\\*+ .*:\\(" | ||
| 21568 | (mapconcat 'identity tags "\\|") | ||
| 21569 | (org-re "\\):[[:alnum:]_@:]*[ \t]*$")))) | ||
| 21570 | (gen-re (nth 3 org-stuck-projects)) | ||
| 21571 | (re-list | ||
| 21572 | (delq nil | ||
| 21573 | (list | ||
| 21574 | (if todo todo-re) | ||
| 21575 | (if tags tags-re) | ||
| 21576 | (and gen-re (stringp gen-re) (string-match "\\S-" gen-re) | ||
| 21577 | gen-re))))) | ||
| 21578 | (setq org-agenda-skip-regexp | ||
| 21579 | (if re-list | ||
| 21580 | (mapconcat 'identity re-list "\\|") | ||
| 21581 | (error "No information how to identify unstuck projects"))) | ||
| 21582 | (org-tags-view nil matcher) | ||
| 21583 | (with-current-buffer org-agenda-buffer-name | ||
| 21584 | (setq org-agenda-redo-command | ||
| 21585 | '(org-agenda-list-stuck-projects | ||
| 21586 | (or current-prefix-arg org-last-arg)))))) | ||
| 21587 | |||
| 21588 | ;;; Diary integration | ||
| 21589 | |||
| 21590 | (defvar org-disable-agenda-to-diary nil) ;Dynamically-scoped param. | ||
| 21591 | (defvar list-diary-entries-hook) | ||
| 21592 | |||
| 21593 | (defun org-get-entries-from-diary (date) | ||
| 21594 | "Get the (Emacs Calendar) diary entries for DATE." | ||
| 21595 | (require 'diary-lib) | ||
| 21596 | (let* ((fancy-diary-buffer "*temporary-fancy-diary-buffer*") | ||
| 21597 | (diary-display-hook '(fancy-diary-display)) | ||
| 21598 | (pop-up-frames nil) | ||
| 21599 | (list-diary-entries-hook | ||
| 21600 | (cons 'org-diary-default-entry list-diary-entries-hook)) | ||
| 21601 | (diary-file-name-prefix-function nil) ; turn this feature off | ||
| 21602 | (diary-modify-entry-list-string-function 'org-modify-diary-entry-string) | ||
| 21603 | entries | ||
| 21604 | (org-disable-agenda-to-diary t)) | ||
| 21605 | (save-excursion | ||
| 21606 | (save-window-excursion | ||
| 21607 | (funcall (if (fboundp 'diary-list-entries) | ||
| 21608 | 'diary-list-entries 'list-diary-entries) | ||
| 21609 | date 1))) | ||
| 21610 | (if (not (get-buffer fancy-diary-buffer)) | ||
| 21611 | (setq entries nil) | ||
| 21612 | (with-current-buffer fancy-diary-buffer | ||
| 21613 | (setq buffer-read-only nil) | ||
| 21614 | (if (zerop (buffer-size)) | ||
| 21615 | ;; No entries | ||
| 21616 | (setq entries nil) | ||
| 21617 | ;; Omit the date and other unnecessary stuff | ||
| 21618 | (org-agenda-cleanup-fancy-diary) | ||
| 21619 | ;; Add prefix to each line and extend the text properties | ||
| 21620 | (if (zerop (buffer-size)) | ||
| 21621 | (setq entries nil) | ||
| 21622 | (setq entries (buffer-substring (point-min) (- (point-max) 1))))) | ||
| 21623 | (set-buffer-modified-p nil) | ||
| 21624 | (kill-buffer fancy-diary-buffer))) | ||
| 21625 | (when entries | ||
| 21626 | (setq entries (org-split-string entries "\n")) | ||
| 21627 | (setq entries | ||
| 21628 | (mapcar | ||
| 21629 | (lambda (x) | ||
| 21630 | (setq x (org-format-agenda-item "" x "Diary" nil 'time)) | ||
| 21631 | ;; Extend the text properties to the beginning of the line | ||
| 21632 | (org-add-props x (text-properties-at (1- (length x)) x) | ||
| 21633 | 'type "diary" 'date date)) | ||
| 21634 | entries))))) | ||
| 21635 | |||
| 21636 | (defun org-agenda-cleanup-fancy-diary () | ||
| 21637 | "Remove unwanted stuff in buffer created by `fancy-diary-display'. | ||
| 21638 | This gets rid of the date, the underline under the date, and | ||
| 21639 | the dummy entry installed by `org-mode' to ensure non-empty diary for each | ||
| 21640 | date. It also removes lines that contain only whitespace." | ||
| 21641 | (goto-char (point-min)) | ||
| 21642 | (if (looking-at ".*?:[ \t]*") | ||
| 21643 | (progn | ||
| 21644 | (replace-match "") | ||
| 21645 | (re-search-forward "\n=+$" nil t) | ||
| 21646 | (replace-match "") | ||
| 21647 | (while (re-search-backward "^ +\n?" nil t) (replace-match ""))) | ||
| 21648 | (re-search-forward "\n=+$" nil t) | ||
| 21649 | (delete-region (point-min) (min (point-max) (1+ (match-end 0))))) | ||
| 21650 | (goto-char (point-min)) | ||
| 21651 | (while (re-search-forward "^ +\n" nil t) | ||
| 21652 | (replace-match "")) | ||
| 21653 | (goto-char (point-min)) | ||
| 21654 | (if (re-search-forward "^Org-mode dummy\n?" nil t) | ||
| 21655 | (replace-match ""))) | ||
| 21656 | |||
| 21657 | ;; Make sure entries from the diary have the right text properties. | ||
| 21658 | (eval-after-load "diary-lib" | ||
| 21659 | '(if (boundp 'diary-modify-entry-list-string-function) | ||
| 21660 | ;; We can rely on the hook, nothing to do | ||
| 21661 | nil | ||
| 21662 | ;; Hook not avaiable, must use advice to make this work | ||
| 21663 | (defadvice add-to-diary-list (before org-mark-diary-entry activate) | ||
| 21664 | "Make the position visible." | ||
| 21665 | (if (and org-disable-agenda-to-diary ;; called from org-agenda | ||
| 21666 | (stringp string) | ||
| 21667 | buffer-file-name) | ||
| 21668 | (setq string (org-modify-diary-entry-string string)))))) | ||
| 21669 | |||
| 21670 | (defun org-modify-diary-entry-string (string) | ||
| 21671 | "Add text properties to string, allowing org-mode to act on it." | ||
| 21672 | (org-add-props string nil | ||
| 21673 | 'mouse-face 'highlight | ||
| 21674 | 'keymap org-agenda-keymap | ||
| 21675 | 'help-echo (if buffer-file-name | ||
| 21676 | (format "mouse-2 or RET jump to diary file %s" | ||
| 21677 | (abbreviate-file-name buffer-file-name)) | ||
| 21678 | "") | ||
| 21679 | 'org-agenda-diary-link t | ||
| 21680 | 'org-marker (org-agenda-new-marker (point-at-bol)))) | ||
| 21681 | |||
| 21682 | (defun org-diary-default-entry () | ||
| 21683 | "Add a dummy entry to the diary. | ||
| 21684 | Needed to avoid empty dates which mess up holiday display." | ||
| 21685 | ;; Catch the error if dealing with the new add-to-diary-alist | ||
| 21686 | (when org-disable-agenda-to-diary | ||
| 21687 | (condition-case nil | ||
| 21688 | (add-to-diary-list original-date "Org-mode dummy" "") | ||
| 21689 | (error | ||
| 21690 | (add-to-diary-list original-date "Org-mode dummy" "" nil))))) | ||
| 21691 | |||
| 21692 | ;;;###autoload | ||
| 21693 | (defun org-diary (&rest args) | ||
| 21694 | "Return diary information from org-files. | ||
| 21695 | This function can be used in a \"sexp\" diary entry in the Emacs calendar. | ||
| 21696 | It accesses org files and extracts information from those files to be | ||
| 21697 | listed in the diary. The function accepts arguments specifying what | ||
| 21698 | items should be listed. The following arguments are allowed: | ||
| 21699 | |||
| 21700 | :timestamp List the headlines of items containing a date stamp or | ||
| 21701 | date range matching the selected date. Deadlines will | ||
| 21702 | also be listed, on the expiration day. | ||
| 21703 | |||
| 21704 | :sexp List entries resulting from diary-like sexps. | ||
| 21705 | |||
| 21706 | :deadline List any deadlines past due, or due within | ||
| 21707 | `org-deadline-warning-days'. The listing occurs only | ||
| 21708 | in the diary for *today*, not at any other date. If | ||
| 21709 | an entry is marked DONE, it is no longer listed. | ||
| 21710 | |||
| 21711 | :scheduled List all items which are scheduled for the given date. | ||
| 21712 | The diary for *today* also contains items which were | ||
| 21713 | scheduled earlier and are not yet marked DONE. | ||
| 21714 | |||
| 21715 | :todo List all TODO items from the org-file. This may be a | ||
| 21716 | long list - so this is not turned on by default. | ||
| 21717 | Like deadlines, these entries only show up in the | ||
| 21718 | diary for *today*, not at any other date. | ||
| 21719 | |||
| 21720 | The call in the diary file should look like this: | ||
| 21721 | |||
| 21722 | &%%(org-diary) ~/path/to/some/orgfile.org | ||
| 21723 | |||
| 21724 | Use a separate line for each org file to check. Or, if you omit the file name, | ||
| 21725 | all files listed in `org-agenda-files' will be checked automatically: | ||
| 21726 | |||
| 21727 | &%%(org-diary) | ||
| 21728 | |||
| 21729 | If you don't give any arguments (as in the example above), the default | ||
| 21730 | arguments (:deadline :scheduled :timestamp :sexp) are used. | ||
| 21731 | So the example above may also be written as | ||
| 21732 | |||
| 21733 | &%%(org-diary :deadline :timestamp :sexp :scheduled) | ||
| 21734 | |||
| 21735 | The function expects the lisp variables `entry' and `date' to be provided | ||
| 21736 | by the caller, because this is how the calendar works. Don't use this | ||
| 21737 | function from a program - use `org-agenda-get-day-entries' instead." | ||
| 21738 | (when (> (- (time-to-seconds (current-time)) | ||
| 21739 | org-agenda-last-marker-time) | ||
| 21740 | 5) | ||
| 21741 | (org-agenda-reset-markers)) | ||
| 21742 | (org-compile-prefix-format 'agenda) | ||
| 21743 | (org-set-sorting-strategy 'agenda) | ||
| 21744 | (setq args (or args '(:deadline :scheduled :timestamp :sexp))) | ||
| 21745 | (let* ((files (if (and entry (stringp entry) (string-match "\\S-" entry)) | ||
| 21746 | (list entry) | ||
| 21747 | (org-agenda-files t))) | ||
| 21748 | file rtn results) | ||
| 21749 | (org-prepare-agenda-buffers files) | ||
| 21750 | ;; If this is called during org-agenda, don't return any entries to | ||
| 21751 | ;; the calendar. Org Agenda will list these entries itself. | ||
| 21752 | (if org-disable-agenda-to-diary (setq files nil)) | ||
| 21753 | (while (setq file (pop files)) | ||
| 21754 | (setq rtn (apply 'org-agenda-get-day-entries file date args)) | ||
| 21755 | (setq results (append results rtn))) | ||
| 21756 | (if results | ||
| 21757 | (concat (org-finalize-agenda-entries results) "\n")))) | ||
| 21758 | |||
| 21759 | ;;; Agenda entry finders | ||
| 21760 | |||
| 21761 | (defun org-agenda-get-day-entries (file date &rest args) | ||
| 21762 | "Does the work for `org-diary' and `org-agenda'. | ||
| 21763 | FILE is the path to a file to be checked for entries. DATE is date like | ||
| 21764 | the one returned by `calendar-current-date'. ARGS are symbols indicating | ||
| 21765 | which kind of entries should be extracted. For details about these, see | ||
| 21766 | the documentation of `org-diary'." | ||
| 21767 | (setq args (or args '(:deadline :scheduled :timestamp :sexp))) | ||
| 21768 | (let* ((org-startup-folded nil) | ||
| 21769 | (org-startup-align-all-tables nil) | ||
| 21770 | (buffer (if (file-exists-p file) | ||
| 21771 | (org-get-agenda-file-buffer file) | ||
| 21772 | (error "No such file %s" file))) | ||
| 21773 | arg results rtn) | ||
| 21774 | (if (not buffer) | ||
| 21775 | ;; If file does not exist, make sure an error message ends up in diary | ||
| 21776 | (list (format "ORG-AGENDA-ERROR: No such org-file %s" file)) | ||
| 21777 | (with-current-buffer buffer | ||
| 21778 | (unless (org-mode-p) | ||
| 21779 | (error "Agenda file %s is not in `org-mode'" file)) | ||
| 21780 | (let ((case-fold-search nil)) | ||
| 21781 | (save-excursion | ||
| 21782 | (save-restriction | ||
| 21783 | (if org-agenda-restrict | ||
| 21784 | (narrow-to-region org-agenda-restrict-begin | ||
| 21785 | org-agenda-restrict-end) | ||
| 21786 | (widen)) | ||
| 21787 | ;; The way we repeatedly append to `results' makes it O(n^2) :-( | ||
| 21788 | (while (setq arg (pop args)) | ||
| 21789 | (cond | ||
| 21790 | ((and (eq arg :todo) | ||
| 21791 | (equal date (calendar-current-date))) | ||
| 21792 | (setq rtn (org-agenda-get-todos)) | ||
| 21793 | (setq results (append results rtn))) | ||
| 21794 | ((eq arg :timestamp) | ||
| 21795 | (setq rtn (org-agenda-get-blocks)) | ||
| 21796 | (setq results (append results rtn)) | ||
| 21797 | (setq rtn (org-agenda-get-timestamps)) | ||
| 21798 | (setq results (append results rtn))) | ||
| 21799 | ((eq arg :sexp) | ||
| 21800 | (setq rtn (org-agenda-get-sexps)) | ||
| 21801 | (setq results (append results rtn))) | ||
| 21802 | ((eq arg :scheduled) | ||
| 21803 | (setq rtn (org-agenda-get-scheduled)) | ||
| 21804 | (setq results (append results rtn))) | ||
| 21805 | ((eq arg :closed) | ||
| 21806 | (setq rtn (org-agenda-get-closed)) | ||
| 21807 | (setq results (append results rtn))) | ||
| 21808 | ((eq arg :deadline) | ||
| 21809 | (setq rtn (org-agenda-get-deadlines)) | ||
| 21810 | (setq results (append results rtn)))))))) | ||
| 21811 | results)))) | ||
| 21812 | |||
| 21813 | (defun org-entry-is-todo-p () | ||
| 21814 | (member (org-get-todo-state) org-not-done-keywords)) | ||
| 21815 | |||
| 21816 | (defun org-entry-is-done-p () | ||
| 21817 | (member (org-get-todo-state) org-done-keywords)) | ||
| 21818 | |||
| 21819 | (defun org-get-todo-state () | ||
| 21820 | (save-excursion | ||
| 21821 | (org-back-to-heading t) | ||
| 21822 | (and (looking-at org-todo-line-regexp) | ||
| 21823 | (match-end 2) | ||
| 21824 | (match-string 2)))) | ||
| 21825 | |||
| 21826 | (defun org-at-date-range-p (&optional inactive-ok) | ||
| 21827 | "Is the cursor inside a date range?" | ||
| 21828 | (interactive) | ||
| 21829 | (save-excursion | ||
| 21830 | (catch 'exit | ||
| 21831 | (let ((pos (point))) | ||
| 21832 | (skip-chars-backward "^[<\r\n") | ||
| 21833 | (skip-chars-backward "<[") | ||
| 21834 | (and (looking-at (if inactive-ok org-tr-regexp-both org-tr-regexp)) | ||
| 21835 | (>= (match-end 0) pos) | ||
| 21836 | (throw 'exit t)) | ||
| 21837 | (skip-chars-backward "^<[\r\n") | ||
| 21838 | (skip-chars-backward "<[") | ||
| 21839 | (and (looking-at (if inactive-ok org-tr-regexp-both org-tr-regexp)) | ||
| 21840 | (>= (match-end 0) pos) | ||
| 21841 | (throw 'exit t))) | ||
| 21842 | nil))) | ||
| 21843 | |||
| 21844 | (defun org-agenda-get-todos () | ||
| 21845 | "Return the TODO information for agenda display." | ||
| 21846 | (let* ((props (list 'face nil | ||
| 21847 | 'done-face 'org-done | ||
| 21848 | 'org-not-done-regexp org-not-done-regexp | ||
| 21849 | 'org-todo-regexp org-todo-regexp | ||
| 21850 | 'mouse-face 'highlight | ||
| 21851 | 'keymap org-agenda-keymap | ||
| 21852 | 'help-echo | ||
| 21853 | (format "mouse-2 or RET jump to org file %s" | ||
| 21854 | (abbreviate-file-name buffer-file-name)))) | ||
| 21855 | ;; FIXME: get rid of the \n at some point but watch out | ||
| 21856 | (regexp (concat "^\\*+[ \t]+\\(" | ||
| 21857 | (if org-select-this-todo-keyword | ||
| 21858 | (if (equal org-select-this-todo-keyword "*") | ||
| 21859 | org-todo-regexp | ||
| 21860 | (concat "\\<\\(" | ||
| 21861 | (mapconcat 'identity (org-split-string org-select-this-todo-keyword "|") "\\|") | ||
| 21862 | "\\)\\>")) | ||
| 21863 | org-not-done-regexp) | ||
| 21864 | "[^\n\r]*\\)")) | ||
| 21865 | marker priority category tags | ||
| 21866 | ee txt beg end) | ||
| 21867 | (goto-char (point-min)) | ||
| 21868 | (while (re-search-forward regexp nil t) | ||
| 21869 | (catch :skip | ||
| 21870 | (save-match-data | ||
| 21871 | (beginning-of-line) | ||
| 21872 | (setq beg (point) end (progn (outline-next-heading) (point))) | ||
| 21873 | (when (or (and org-agenda-todo-ignore-with-date (goto-char beg) | ||
| 21874 | (re-search-forward org-ts-regexp end t)) | ||
| 21875 | (and org-agenda-todo-ignore-scheduled (goto-char beg) | ||
| 21876 | (re-search-forward org-scheduled-time-regexp end t)) | ||
| 21877 | (and org-agenda-todo-ignore-deadlines (goto-char beg) | ||
| 21878 | (re-search-forward org-deadline-time-regexp end t) | ||
| 21879 | (org-deadline-close (match-string 1)))) | ||
| 21880 | (goto-char (1+ beg)) | ||
| 21881 | (or org-agenda-todo-list-sublevels (org-end-of-subtree 'invisible)) | ||
| 21882 | (throw :skip nil))) | ||
| 21883 | (goto-char beg) | ||
| 21884 | (org-agenda-skip) | ||
| 21885 | (goto-char (match-beginning 1)) | ||
| 21886 | (setq marker (org-agenda-new-marker (match-beginning 0)) | ||
| 21887 | category (org-get-category) | ||
| 21888 | tags (org-get-tags-at (point)) | ||
| 21889 | txt (org-format-agenda-item "" (match-string 1) category tags) | ||
| 21890 | priority (1+ (org-get-priority txt))) | ||
| 21891 | (org-add-props txt props | ||
| 21892 | 'org-marker marker 'org-hd-marker marker | ||
| 21893 | 'priority priority 'org-category category | ||
| 21894 | 'type "todo") | ||
| 21895 | (push txt ee) | ||
| 21896 | (if org-agenda-todo-list-sublevels | ||
| 21897 | (goto-char (match-end 1)) | ||
| 21898 | (org-end-of-subtree 'invisible)))) | ||
| 21899 | (nreverse ee))) | ||
| 21900 | |||
| 21901 | (defconst org-agenda-no-heading-message | ||
| 21902 | "No heading for this item in buffer or region.") | ||
| 21903 | |||
| 21904 | (defun org-agenda-get-timestamps () | ||
| 21905 | "Return the date stamp information for agenda display." | ||
| 21906 | (let* ((props (list 'face nil | ||
| 21907 | 'org-not-done-regexp org-not-done-regexp | ||
| 21908 | 'org-todo-regexp org-todo-regexp | ||
| 21909 | 'mouse-face 'highlight | ||
| 21910 | 'keymap org-agenda-keymap | ||
| 21911 | 'help-echo | ||
| 21912 | (format "mouse-2 or RET jump to org file %s" | ||
| 21913 | (abbreviate-file-name buffer-file-name)))) | ||
| 21914 | (d1 (calendar-absolute-from-gregorian date)) | ||
| 21915 | (remove-re | ||
| 21916 | (concat | ||
| 21917 | (regexp-quote | ||
| 21918 | (format-time-string | ||
| 21919 | "<%Y-%m-%d" | ||
| 21920 | (encode-time 0 0 0 (nth 1 date) (nth 0 date) (nth 2 date)))) | ||
| 21921 | ".*?>")) | ||
| 21922 | (regexp | ||
| 21923 | (concat | ||
| 21924 | (regexp-quote | ||
| 21925 | (substring | ||
| 21926 | (format-time-string | ||
| 21927 | (car org-time-stamp-formats) | ||
| 21928 | (apply 'encode-time ; DATE bound by calendar | ||
| 21929 | (list 0 0 0 (nth 1 date) (car date) (nth 2 date)))) | ||
| 21930 | 0 11)) | ||
| 21931 | "\\|\\(<[0-9]+-[0-9]+-[0-9]+[^>\n]+?\\+[0-9]+[dwmy]>\\)" | ||
| 21932 | "\\|\\(<%%\\(([^>\n]+)\\)>\\)")) | ||
| 21933 | marker hdmarker deadlinep scheduledp donep tmp priority category | ||
| 21934 | ee txt timestr tags b0 b3 e3 head) | ||
| 21935 | (goto-char (point-min)) | ||
| 21936 | (while (re-search-forward regexp nil t) | ||
| 21937 | (setq b0 (match-beginning 0) | ||
| 21938 | b3 (match-beginning 3) e3 (match-end 3)) | ||
| 21939 | (catch :skip | ||
| 21940 | (and (org-at-date-range-p) (throw :skip nil)) | ||
| 21941 | (org-agenda-skip) | ||
| 21942 | (if (and (match-end 1) | ||
| 21943 | (not (= d1 (org-time-string-to-absolute (match-string 1) d1)))) | ||
| 21944 | (throw :skip nil)) | ||
| 21945 | (if (and e3 | ||
| 21946 | (not (org-diary-sexp-entry (buffer-substring b3 e3) "" date))) | ||
| 21947 | (throw :skip nil)) | ||
| 21948 | (setq marker (org-agenda-new-marker b0) | ||
| 21949 | category (org-get-category b0) | ||
| 21950 | tmp (buffer-substring (max (point-min) | ||
| 21951 | (- b0 org-ds-keyword-length)) | ||
| 21952 | b0) | ||
| 21953 | timestr (if b3 "" (buffer-substring b0 (point-at-eol))) | ||
| 21954 | deadlinep (string-match org-deadline-regexp tmp) | ||
| 21955 | scheduledp (string-match org-scheduled-regexp tmp) | ||
| 21956 | donep (org-entry-is-done-p)) | ||
| 21957 | (if (or scheduledp deadlinep) (throw :skip t)) | ||
| 21958 | (if (string-match ">" timestr) | ||
| 21959 | ;; substring should only run to end of time stamp | ||
| 21960 | (setq timestr (substring timestr 0 (match-end 0)))) | ||
| 21961 | (save-excursion | ||
| 21962 | (if (re-search-backward "^\\*+ " nil t) | ||
| 21963 | (progn | ||
| 21964 | (goto-char (match-beginning 0)) | ||
| 21965 | (setq hdmarker (org-agenda-new-marker) | ||
| 21966 | tags (org-get-tags-at)) | ||
| 21967 | (looking-at "\\*+[ \t]+\\([^\r\n]+\\)") | ||
| 21968 | (setq head (match-string 1)) | ||
| 21969 | (and org-agenda-skip-timestamp-if-done donep (throw :skip t)) | ||
| 21970 | (setq txt (org-format-agenda-item | ||
| 21971 | nil head category tags timestr nil | ||
| 21972 | remove-re))) | ||
| 21973 | (setq txt org-agenda-no-heading-message)) | ||
| 21974 | (setq priority (org-get-priority txt)) | ||
| 21975 | (org-add-props txt props | ||
| 21976 | 'org-marker marker 'org-hd-marker hdmarker) | ||
| 21977 | (org-add-props txt nil 'priority priority | ||
| 21978 | 'org-category category 'date date | ||
| 21979 | 'type "timestamp") | ||
| 21980 | (push txt ee)) | ||
| 21981 | (outline-next-heading))) | ||
| 21982 | (nreverse ee))) | ||
| 21983 | |||
| 21984 | (defun org-agenda-get-sexps () | ||
| 21985 | "Return the sexp information for agenda display." | ||
| 21986 | (require 'diary-lib) | ||
| 21987 | (let* ((props (list 'face nil | ||
| 21988 | 'mouse-face 'highlight | ||
| 21989 | 'keymap org-agenda-keymap | ||
| 21990 | 'help-echo | ||
| 21991 | (format "mouse-2 or RET jump to org file %s" | ||
| 21992 | (abbreviate-file-name buffer-file-name)))) | ||
| 21993 | (regexp "^&?%%(") | ||
| 21994 | marker category ee txt tags entry result beg b sexp sexp-entry) | ||
| 21995 | (goto-char (point-min)) | ||
| 21996 | (while (re-search-forward regexp nil t) | ||
| 21997 | (catch :skip | ||
| 21998 | (org-agenda-skip) | ||
| 21999 | (setq beg (match-beginning 0)) | ||
| 22000 | (goto-char (1- (match-end 0))) | ||
| 22001 | (setq b (point)) | ||
| 22002 | (forward-sexp 1) | ||
| 22003 | (setq sexp (buffer-substring b (point))) | ||
| 22004 | (setq sexp-entry (if (looking-at "[ \t]*\\(\\S-.*\\)") | ||
| 22005 | (org-trim (match-string 1)) | ||
| 22006 | "")) | ||
| 22007 | (setq result (org-diary-sexp-entry sexp sexp-entry date)) | ||
| 22008 | (when result | ||
| 22009 | (setq marker (org-agenda-new-marker beg) | ||
| 22010 | category (org-get-category beg)) | ||
| 22011 | |||
| 22012 | (if (string-match "\\S-" result) | ||
| 22013 | (setq txt result) | ||
| 22014 | (setq txt "SEXP entry returned empty string")) | ||
| 22015 | |||
| 22016 | (setq txt (org-format-agenda-item | ||
| 22017 | "" txt category tags 'time)) | ||
| 22018 | (org-add-props txt props 'org-marker marker) | ||
| 22019 | (org-add-props txt nil | ||
| 22020 | 'org-category category 'date date | ||
| 22021 | 'type "sexp") | ||
| 22022 | (push txt ee)))) | ||
| 22023 | (nreverse ee))) | ||
| 22024 | |||
| 22025 | (defun org-agenda-get-closed () | ||
| 22026 | "Return the logged TODO entries for agenda display." | ||
| 22027 | (let* ((props (list 'mouse-face 'highlight | ||
| 22028 | 'org-not-done-regexp org-not-done-regexp | ||
| 22029 | 'org-todo-regexp org-todo-regexp | ||
| 22030 | 'keymap org-agenda-keymap | ||
| 22031 | 'help-echo | ||
| 22032 | (format "mouse-2 or RET jump to org file %s" | ||
| 22033 | (abbreviate-file-name buffer-file-name)))) | ||
| 22034 | (regexp (concat | ||
| 22035 | "\\<\\(" org-closed-string "\\|" org-clock-string "\\) *\\[" | ||
| 22036 | (regexp-quote | ||
| 22037 | (substring | ||
| 22038 | (format-time-string | ||
| 22039 | (car org-time-stamp-formats) | ||
| 22040 | (apply 'encode-time ; DATE bound by calendar | ||
| 22041 | (list 0 0 0 (nth 1 date) (car date) (nth 2 date)))) | ||
| 22042 | 1 11)))) | ||
| 22043 | marker hdmarker priority category tags closedp | ||
| 22044 | ee txt timestr) | ||
| 22045 | (goto-char (point-min)) | ||
| 22046 | (while (re-search-forward regexp nil t) | ||
| 22047 | (catch :skip | ||
| 22048 | (org-agenda-skip) | ||
| 22049 | (setq marker (org-agenda-new-marker (match-beginning 0)) | ||
| 22050 | closedp (equal (match-string 1) org-closed-string) | ||
| 22051 | category (org-get-category (match-beginning 0)) | ||
| 22052 | timestr (buffer-substring (match-beginning 0) (point-at-eol)) | ||
| 22053 | ;; donep (org-entry-is-done-p) | ||
| 22054 | ) | ||
| 22055 | (if (string-match "\\]" timestr) | ||
| 22056 | ;; substring should only run to end of time stamp | ||
| 22057 | (setq timestr (substring timestr 0 (match-end 0)))) | ||
| 22058 | (save-excursion | ||
| 22059 | (if (re-search-backward "^\\*+ " nil t) | ||
| 22060 | (progn | ||
| 22061 | (goto-char (match-beginning 0)) | ||
| 22062 | (setq hdmarker (org-agenda-new-marker) | ||
| 22063 | tags (org-get-tags-at)) | ||
| 22064 | (looking-at "\\*+[ \t]+\\([^\r\n]+\\)") | ||
| 22065 | (setq txt (org-format-agenda-item | ||
| 22066 | (if closedp "Closed: " "Clocked: ") | ||
| 22067 | (match-string 1) category tags timestr))) | ||
| 22068 | (setq txt org-agenda-no-heading-message)) | ||
| 22069 | (setq priority 100000) | ||
| 22070 | (org-add-props txt props | ||
| 22071 | 'org-marker marker 'org-hd-marker hdmarker 'face 'org-done | ||
| 22072 | 'priority priority 'org-category category | ||
| 22073 | 'type "closed" 'date date | ||
| 22074 | 'undone-face 'org-warning 'done-face 'org-done) | ||
| 22075 | (push txt ee)) | ||
| 22076 | (goto-char (point-at-eol)))) | ||
| 22077 | (nreverse ee))) | ||
| 22078 | |||
| 22079 | (defun org-agenda-get-deadlines () | ||
| 22080 | "Return the deadline information for agenda display." | ||
| 22081 | (let* ((props (list 'mouse-face 'highlight | ||
| 22082 | 'org-not-done-regexp org-not-done-regexp | ||
| 22083 | 'org-todo-regexp org-todo-regexp | ||
| 22084 | 'keymap org-agenda-keymap | ||
| 22085 | 'help-echo | ||
| 22086 | (format "mouse-2 or RET jump to org file %s" | ||
| 22087 | (abbreviate-file-name buffer-file-name)))) | ||
| 22088 | (regexp org-deadline-time-regexp) | ||
| 22089 | (todayp (equal date (calendar-current-date))) ; DATE bound by calendar | ||
| 22090 | (d1 (calendar-absolute-from-gregorian date)) ; DATE bound by calendar | ||
| 22091 | d2 diff dfrac wdays pos pos1 category tags | ||
| 22092 | ee txt head face s upcomingp donep timestr) | ||
| 22093 | (goto-char (point-min)) | ||
| 22094 | (while (re-search-forward regexp nil t) | ||
| 22095 | (catch :skip | ||
| 22096 | (org-agenda-skip) | ||
| 22097 | (setq s (match-string 1) | ||
| 22098 | pos (1- (match-beginning 1)) | ||
| 22099 | d2 (org-time-string-to-absolute (match-string 1) d1 'past) | ||
| 22100 | diff (- d2 d1) | ||
| 22101 | wdays (org-get-wdays s) | ||
| 22102 | dfrac (/ (* 1.0 (- wdays diff)) (max wdays 1)) | ||
| 22103 | upcomingp (and todayp (> diff 0))) | ||
| 22104 | ;; When to show a deadline in the calendar: | ||
| 22105 | ;; If the expiration is within wdays warning time. | ||
| 22106 | ;; Past-due deadlines are only shown on the current date | ||
| 22107 | (if (or (and (<= diff wdays) | ||
| 22108 | (and todayp (not org-agenda-only-exact-dates))) | ||
| 22109 | (= diff 0)) | ||
| 22110 | (save-excursion | ||
| 22111 | (setq category (org-get-category)) | ||
| 22112 | (if (re-search-backward "^\\*+[ \t]+" nil t) | ||
| 22113 | (progn | ||
| 22114 | (goto-char (match-end 0)) | ||
| 22115 | (setq pos1 (match-beginning 0)) | ||
| 22116 | (setq tags (org-get-tags-at pos1)) | ||
| 22117 | (setq head (buffer-substring-no-properties | ||
| 22118 | (point) | ||
| 22119 | (progn (skip-chars-forward "^\r\n") | ||
| 22120 | (point)))) | ||
| 22121 | (setq donep (string-match org-looking-at-done-regexp head)) | ||
| 22122 | (if (string-match " \\([012]?[0-9]:[0-9][0-9]\\)" s) | ||
| 22123 | (setq timestr | ||
| 22124 | (concat (substring s (match-beginning 1)) " ")) | ||
| 22125 | (setq timestr 'time)) | ||
| 22126 | (if (and donep | ||
| 22127 | (or org-agenda-skip-deadline-if-done | ||
| 22128 | (not (= diff 0)))) | ||
| 22129 | (setq txt nil) | ||
| 22130 | (setq txt (org-format-agenda-item | ||
| 22131 | (if (= diff 0) | ||
| 22132 | (car org-agenda-deadline-leaders) | ||
| 22133 | (format (nth 1 org-agenda-deadline-leaders) | ||
| 22134 | diff)) | ||
| 22135 | head category tags timestr)))) | ||
| 22136 | (setq txt org-agenda-no-heading-message)) | ||
| 22137 | (when txt | ||
| 22138 | (setq face (org-agenda-deadline-face dfrac wdays)) | ||
| 22139 | (org-add-props txt props | ||
| 22140 | 'org-marker (org-agenda-new-marker pos) | ||
| 22141 | 'org-hd-marker (org-agenda-new-marker pos1) | ||
| 22142 | 'priority (+ (- diff) | ||
| 22143 | (org-get-priority txt)) | ||
| 22144 | 'org-category category | ||
| 22145 | 'type (if upcomingp "upcoming-deadline" "deadline") | ||
| 22146 | 'date (if upcomingp date d2) | ||
| 22147 | 'face (if donep 'org-done face) | ||
| 22148 | 'undone-face face 'done-face 'org-done) | ||
| 22149 | (push txt ee)))))) | ||
| 22150 | (nreverse ee))) | ||
| 22151 | |||
| 22152 | (defun org-agenda-deadline-face (fraction &optional wdays) | ||
| 22153 | "Return the face to displaying a deadline item. | ||
| 22154 | FRACTION is what fraction of the head-warning time has passed." | ||
| 22155 | (if (equal wdays 0) (setq fraction 1.)) | ||
| 22156 | (let ((faces org-agenda-deadline-faces) f) | ||
| 22157 | (catch 'exit | ||
| 22158 | (while (setq f (pop faces)) | ||
| 22159 | (if (>= fraction (car f)) (throw 'exit (cdr f))))))) | ||
| 22160 | |||
| 22161 | (defun org-agenda-get-scheduled () | ||
| 22162 | "Return the scheduled information for agenda display." | ||
| 22163 | (let* ((props (list 'org-not-done-regexp org-not-done-regexp | ||
| 22164 | 'org-todo-regexp org-todo-regexp | ||
| 22165 | 'done-face 'org-done | ||
| 22166 | 'mouse-face 'highlight | ||
| 22167 | 'keymap org-agenda-keymap | ||
| 22168 | 'help-echo | ||
| 22169 | (format "mouse-2 or RET jump to org file %s" | ||
| 22170 | (abbreviate-file-name buffer-file-name)))) | ||
| 22171 | (regexp org-scheduled-time-regexp) | ||
| 22172 | (todayp (equal date (calendar-current-date))) ; DATE bound by calendar | ||
| 22173 | (d1 (calendar-absolute-from-gregorian date)) ; DATE bound by calendar | ||
| 22174 | d2 diff pos pos1 category tags | ||
| 22175 | ee txt head pastschedp donep face timestr s) | ||
| 22176 | (goto-char (point-min)) | ||
| 22177 | (while (re-search-forward regexp nil t) | ||
| 22178 | (catch :skip | ||
| 22179 | (org-agenda-skip) | ||
| 22180 | (setq s (match-string 1) | ||
| 22181 | pos (1- (match-beginning 1)) | ||
| 22182 | d2 (org-time-string-to-absolute (match-string 1) d1 'past) | ||
| 22183 | ;;; is this right? | ||
| 22184 | ;;; do we need to do this for deadleine too???? | ||
| 22185 | ;;; d2 (org-time-string-to-absolute (match-string 1) (if todayp nil d1)) | ||
| 22186 | diff (- d2 d1)) | ||
| 22187 | (setq pastschedp (and todayp (< diff 0))) | ||
| 22188 | ;; When to show a scheduled item in the calendar: | ||
| 22189 | ;; If it is on or past the date. | ||
| 22190 | (if (or (and (< diff 0) | ||
| 22191 | (and todayp (not org-agenda-only-exact-dates))) | ||
| 22192 | (= diff 0)) | ||
| 22193 | (save-excursion | ||
| 22194 | (setq category (org-get-category)) | ||
| 22195 | (if (re-search-backward "^\\*+[ \t]+" nil t) | ||
| 22196 | (progn | ||
| 22197 | (goto-char (match-end 0)) | ||
| 22198 | (setq pos1 (match-beginning 0)) | ||
| 22199 | (setq tags (org-get-tags-at)) | ||
| 22200 | (setq head (buffer-substring-no-properties | ||
| 22201 | (point) | ||
| 22202 | (progn (skip-chars-forward "^\r\n") (point)))) | ||
| 22203 | (setq donep (string-match org-looking-at-done-regexp head)) | ||
| 22204 | (if (string-match " \\([012]?[0-9]:[0-9][0-9]\\)" s) | ||
| 22205 | (setq timestr | ||
| 22206 | (concat (substring s (match-beginning 1)) " ")) | ||
| 22207 | (setq timestr 'time)) | ||
| 22208 | (if (and donep | ||
| 22209 | (or org-agenda-skip-scheduled-if-done | ||
| 22210 | (not (= diff 0)))) | ||
| 22211 | (setq txt nil) | ||
| 22212 | (setq txt (org-format-agenda-item | ||
| 22213 | (if (= diff 0) | ||
| 22214 | (car org-agenda-scheduled-leaders) | ||
| 22215 | (format (nth 1 org-agenda-scheduled-leaders) | ||
| 22216 | (- 1 diff))) | ||
| 22217 | head category tags timestr)))) | ||
| 22218 | (setq txt org-agenda-no-heading-message)) | ||
| 22219 | (when txt | ||
| 22220 | (setq face (if pastschedp | ||
| 22221 | 'org-scheduled-previously | ||
| 22222 | 'org-scheduled-today)) | ||
| 22223 | (org-add-props txt props | ||
| 22224 | 'undone-face face | ||
| 22225 | 'face (if donep 'org-done face) | ||
| 22226 | 'org-marker (org-agenda-new-marker pos) | ||
| 22227 | 'org-hd-marker (org-agenda-new-marker pos1) | ||
| 22228 | 'type (if pastschedp "past-scheduled" "scheduled") | ||
| 22229 | 'date (if pastschedp d2 date) | ||
| 22230 | 'priority (+ 94 (- 5 diff) (org-get-priority txt)) | ||
| 22231 | 'org-category category) | ||
| 22232 | (push txt ee)))))) | ||
| 22233 | (nreverse ee))) | ||
| 22234 | |||
| 22235 | (defun org-agenda-get-blocks () | ||
| 22236 | "Return the date-range information for agenda display." | ||
| 22237 | (let* ((props (list 'face nil | ||
| 22238 | 'org-not-done-regexp org-not-done-regexp | ||
| 22239 | 'org-todo-regexp org-todo-regexp | ||
| 22240 | 'mouse-face 'highlight | ||
| 22241 | 'keymap org-agenda-keymap | ||
| 22242 | 'help-echo | ||
| 22243 | (format "mouse-2 or RET jump to org file %s" | ||
| 22244 | (abbreviate-file-name buffer-file-name)))) | ||
| 22245 | (regexp org-tr-regexp) | ||
| 22246 | (d0 (calendar-absolute-from-gregorian date)) | ||
| 22247 | marker hdmarker ee txt d1 d2 s1 s2 timestr category tags pos | ||
| 22248 | donep head) | ||
| 22249 | (goto-char (point-min)) | ||
| 22250 | (while (re-search-forward regexp nil t) | ||
| 22251 | (catch :skip | ||
| 22252 | (org-agenda-skip) | ||
| 22253 | (setq pos (point)) | ||
| 22254 | (setq timestr (match-string 0) | ||
| 22255 | s1 (match-string 1) | ||
| 22256 | s2 (match-string 2) | ||
| 22257 | d1 (time-to-days (org-time-string-to-time s1)) | ||
| 22258 | d2 (time-to-days (org-time-string-to-time s2))) | ||
| 22259 | (if (and (> (- d0 d1) -1) (> (- d2 d0) -1)) | ||
| 22260 | ;; Only allow days between the limits, because the normal | ||
| 22261 | ;; date stamps will catch the limits. | ||
| 22262 | (save-excursion | ||
| 22263 | (setq marker (org-agenda-new-marker (point))) | ||
| 22264 | (setq category (org-get-category)) | ||
| 22265 | (if (re-search-backward "^\\*+ " nil t) | ||
| 22266 | (progn | ||
| 22267 | (goto-char (match-beginning 0)) | ||
| 22268 | (setq hdmarker (org-agenda-new-marker (point))) | ||
| 22269 | (setq tags (org-get-tags-at)) | ||
| 22270 | (looking-at "\\*+[ \t]+\\([^\r\n]+\\)") | ||
| 22271 | (setq head (match-string 1)) | ||
| 22272 | (and org-agenda-skip-timestamp-if-done | ||
| 22273 | (org-entry-is-done-p) | ||
| 22274 | (throw :skip t)) | ||
| 22275 | (setq txt (org-format-agenda-item | ||
| 22276 | (format (if (= d1 d2) "" "(%d/%d): ") | ||
| 22277 | (1+ (- d0 d1)) (1+ (- d2 d1))) | ||
| 22278 | head category tags | ||
| 22279 | (if (= d0 d1) timestr)))) | ||
| 22280 | (setq txt org-agenda-no-heading-message)) | ||
| 22281 | (org-add-props txt props | ||
| 22282 | 'org-marker marker 'org-hd-marker hdmarker | ||
| 22283 | 'type "block" 'date date | ||
| 22284 | 'priority (org-get-priority txt) 'org-category category) | ||
| 22285 | (push txt ee))) | ||
| 22286 | (goto-char pos))) | ||
| 22287 | ;; Sort the entries by expiration date. | ||
| 22288 | (nreverse ee))) | ||
| 22289 | |||
| 22290 | ;;; Agenda presentation and sorting | ||
| 22291 | |||
| 22292 | (defconst org-plain-time-of-day-regexp | ||
| 22293 | (concat | ||
| 22294 | "\\(\\<[012]?[0-9]" | ||
| 22295 | "\\(\\(:\\([0-5][0-9]\\([AaPp][Mm]\\)?\\)\\)\\|\\([AaPp][Mm]\\)\\)\\>\\)" | ||
| 22296 | "\\(--?" | ||
| 22297 | "\\(\\<[012]?[0-9]" | ||
| 22298 | "\\(\\(:\\([0-5][0-9]\\([AaPp][Mm]\\)?\\)\\)\\|\\([AaPp][Mm]\\)\\)\\>\\)" | ||
| 22299 | "\\)?") | ||
| 22300 | "Regular expression to match a plain time or time range. | ||
| 22301 | Examples: 11:45 or 8am-13:15 or 2:45-2:45pm. After a match, the following | ||
| 22302 | groups carry important information: | ||
| 22303 | 0 the full match | ||
| 22304 | 1 the first time, range or not | ||
| 22305 | 8 the second time, if it is a range.") | ||
| 22306 | |||
| 22307 | (defconst org-plain-time-extension-regexp | ||
| 22308 | (concat | ||
| 22309 | "\\(\\<[012]?[0-9]" | ||
| 22310 | "\\(\\(:\\([0-5][0-9]\\([AaPp][Mm]\\)?\\)\\)\\|\\([AaPp][Mm]\\)\\)\\>\\)" | ||
| 22311 | "\\+\\([0-9]+\\)\\(:\\([0-5][0-9]\\)\\)?") | ||
| 22312 | "Regular expression to match a time range like 13:30+2:10 = 13:30-15:40. | ||
| 22313 | Examples: 11:45 or 8am-13:15 or 2:45-2:45pm. After a match, the following | ||
| 22314 | groups carry important information: | ||
| 22315 | 0 the full match | ||
| 22316 | 7 hours of duration | ||
| 22317 | 9 minutes of duration") | ||
| 22318 | |||
| 22319 | (defconst org-stamp-time-of-day-regexp | ||
| 22320 | (concat | ||
| 22321 | "<\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\} +\\sw+ +\\)" | ||
| 22322 | "\\([012][0-9]:[0-5][0-9]\\(-\\([012][0-9]:[0-5][0-9]\\)\\)?[^\n\r>]*?\\)>" | ||
| 22323 | "\\(--?" | ||
| 22324 | "<\\1\\([012][0-9]:[0-5][0-9]\\)>\\)?") | ||
| 22325 | "Regular expression to match a timestamp time or time range. | ||
| 22326 | After a match, the following groups carry important information: | ||
| 22327 | 0 the full match | ||
| 22328 | 1 date plus weekday, for backreferencing to make sure both times on same day | ||
| 22329 | 2 the first time, range or not | ||
| 22330 | 4 the second time, if it is a range.") | ||
| 22331 | |||
| 22332 | (defvar org-prefix-has-time nil | ||
| 22333 | "A flag, set by `org-compile-prefix-format'. | ||
| 22334 | The flag is set if the currently compiled format contains a `%t'.") | ||
| 22335 | (defvar org-prefix-has-tag nil | ||
| 22336 | "A flag, set by `org-compile-prefix-format'. | ||
| 22337 | The flag is set if the currently compiled format contains a `%T'.") | ||
| 22338 | |||
| 22339 | (defun org-format-agenda-item (extra txt &optional category tags dotime | ||
| 22340 | noprefix remove-re) | ||
| 22341 | "Format TXT to be inserted into the agenda buffer. | ||
| 22342 | In particular, it adds the prefix and corresponding text properties. EXTRA | ||
| 22343 | must be a string and replaces the `%s' specifier in the prefix format. | ||
| 22344 | CATEGORY (string, symbol or nil) may be used to overrule the default | ||
| 22345 | category taken from local variable or file name. It will replace the `%c' | ||
| 22346 | specifier in the format. DOTIME, when non-nil, indicates that a | ||
| 22347 | time-of-day should be extracted from TXT for sorting of this entry, and for | ||
| 22348 | the `%t' specifier in the format. When DOTIME is a string, this string is | ||
| 22349 | searched for a time before TXT is. NOPREFIX is a flag and indicates that | ||
| 22350 | only the correctly processes TXT should be returned - this is used by | ||
| 22351 | `org-agenda-change-all-lines'. TAGS can be the tags of the headline. | ||
| 22352 | Any match of REMOVE-RE will be removed from TXT." | ||
| 22353 | (save-match-data | ||
| 22354 | ;; Diary entries sometimes have extra whitespace at the beginning | ||
| 22355 | (if (string-match "^ +" txt) (setq txt (replace-match "" nil nil txt))) | ||
| 22356 | (let* ((category (or category | ||
| 22357 | org-category | ||
| 22358 | (if buffer-file-name | ||
| 22359 | (file-name-sans-extension | ||
| 22360 | (file-name-nondirectory buffer-file-name)) | ||
| 22361 | ""))) | ||
| 22362 | (tag (if tags (nth (1- (length tags)) tags) "")) | ||
| 22363 | time ; time and tag are needed for the eval of the prefix format | ||
| 22364 | (ts (if dotime (concat (if (stringp dotime) dotime "") txt))) | ||
| 22365 | (time-of-day (and dotime (org-get-time-of-day ts))) | ||
| 22366 | stamp plain s0 s1 s2 rtn srp) | ||
| 22367 | (when (and dotime time-of-day org-prefix-has-time) | ||
| 22368 | ;; Extract starting and ending time and move them to prefix | ||
| 22369 | (when (or (setq stamp (string-match org-stamp-time-of-day-regexp ts)) | ||
| 22370 | (setq plain (string-match org-plain-time-of-day-regexp ts))) | ||
| 22371 | (setq s0 (match-string 0 ts) | ||
| 22372 | srp (and stamp (match-end 3)) | ||
| 22373 | s1 (match-string (if plain 1 2) ts) | ||
| 22374 | s2 (match-string (if plain 8 (if srp 4 6)) ts)) | ||
| 22375 | |||
| 22376 | ;; If the times are in TXT (not in DOTIMES), and the prefix will list | ||
| 22377 | ;; them, we might want to remove them there to avoid duplication. | ||
| 22378 | ;; The user can turn this off with a variable. | ||
| 22379 | (if (and org-agenda-remove-times-when-in-prefix (or stamp plain) | ||
| 22380 | (string-match (concat (regexp-quote s0) " *") txt) | ||
| 22381 | (not (equal ?\] (string-to-char (substring txt (match-end 0))))) | ||
| 22382 | (if (eq org-agenda-remove-times-when-in-prefix 'beg) | ||
| 22383 | (= (match-beginning 0) 0) | ||
| 22384 | t)) | ||
| 22385 | (setq txt (replace-match "" nil nil txt)))) | ||
| 22386 | ;; Normalize the time(s) to 24 hour | ||
| 22387 | (if s1 (setq s1 (org-get-time-of-day s1 'string t))) | ||
| 22388 | (if s2 (setq s2 (org-get-time-of-day s2 'string t)))) | ||
| 22389 | |||
| 22390 | (when (and s1 (not s2) org-agenda-default-appointment-duration | ||
| 22391 | (string-match "\\([0-9]+\\):\\([0-9]+\\)" s1)) | ||
| 22392 | (let ((m (+ (string-to-number (match-string 2 s1)) | ||
| 22393 | (* 60 (string-to-number (match-string 1 s1))) | ||
| 22394 | org-agenda-default-appointment-duration)) | ||
| 22395 | h) | ||
| 22396 | (setq h (/ m 60) m (- m (* h 60))) | ||
| 22397 | (setq s2 (format "%02d:%02d" h m)))) | ||
| 22398 | |||
| 22399 | (when (string-match (org-re "\\([ \t]+\\)\\(:[[:alnum:]_@:]+:\\)[ \t]*$") | ||
| 22400 | txt) | ||
| 22401 | ;; Tags are in the string | ||
| 22402 | (if (or (eq org-agenda-remove-tags t) | ||
| 22403 | (and org-agenda-remove-tags | ||
| 22404 | org-prefix-has-tag)) | ||
| 22405 | (setq txt (replace-match "" t t txt)) | ||
| 22406 | (setq txt (replace-match | ||
| 22407 | (concat (make-string (max (- 50 (length txt)) 1) ?\ ) | ||
| 22408 | (match-string 2 txt)) | ||
| 22409 | t t txt)))) | ||
| 22410 | |||
| 22411 | (when remove-re | ||
| 22412 | (while (string-match remove-re txt) | ||
| 22413 | (setq txt (replace-match "" t t txt)))) | ||
| 22414 | |||
| 22415 | ;; Create the final string | ||
| 22416 | (if noprefix | ||
| 22417 | (setq rtn txt) | ||
| 22418 | ;; Prepare the variables needed in the eval of the compiled format | ||
| 22419 | (setq time (cond (s2 (concat s1 "-" s2)) | ||
| 22420 | (s1 (concat s1 "......")) | ||
| 22421 | (t "")) | ||
| 22422 | extra (or extra "") | ||
| 22423 | category (if (symbolp category) (symbol-name category) category)) | ||
| 22424 | ;; Evaluate the compiled format | ||
| 22425 | (setq rtn (concat (eval org-prefix-format-compiled) txt))) | ||
| 22426 | |||
| 22427 | ;; And finally add the text properties | ||
| 22428 | (org-add-props rtn nil | ||
| 22429 | 'org-category (downcase category) 'tags tags | ||
| 22430 | 'org-highest-priority org-highest-priority | ||
| 22431 | 'org-lowest-priority org-lowest-priority | ||
| 22432 | 'prefix-length (- (length rtn) (length txt)) | ||
| 22433 | 'time-of-day time-of-day | ||
| 22434 | 'txt txt | ||
| 22435 | 'time time | ||
| 22436 | 'extra extra | ||
| 22437 | 'dotime dotime)))) | ||
| 22438 | |||
| 22439 | (defvar org-agenda-sorting-strategy) ;; because the def is in a let form | ||
| 22440 | (defvar org-agenda-sorting-strategy-selected nil) | ||
| 22441 | |||
| 22442 | (defun org-agenda-add-time-grid-maybe (list ndays todayp) | ||
| 22443 | (catch 'exit | ||
| 22444 | (cond ((not org-agenda-use-time-grid) (throw 'exit list)) | ||
| 22445 | ((and todayp (member 'today (car org-agenda-time-grid)))) | ||
| 22446 | ((and (= ndays 1) (member 'daily (car org-agenda-time-grid)))) | ||
| 22447 | ((member 'weekly (car org-agenda-time-grid))) | ||
| 22448 | (t (throw 'exit list))) | ||
| 22449 | (let* ((have (delq nil (mapcar | ||
| 22450 | (lambda (x) (get-text-property 1 'time-of-day x)) | ||
| 22451 | list))) | ||
| 22452 | (string (nth 1 org-agenda-time-grid)) | ||
| 22453 | (gridtimes (nth 2 org-agenda-time-grid)) | ||
| 22454 | (req (car org-agenda-time-grid)) | ||
| 22455 | (remove (member 'remove-match req)) | ||
| 22456 | new time) | ||
| 22457 | (if (and (member 'require-timed req) (not have)) | ||
| 22458 | ;; don't show empty grid | ||
| 22459 | (throw 'exit list)) | ||
| 22460 | (while (setq time (pop gridtimes)) | ||
| 22461 | (unless (and remove (member time have)) | ||
| 22462 | (setq time (int-to-string time)) | ||
| 22463 | (push (org-format-agenda-item | ||
| 22464 | nil string "" nil | ||
| 22465 | (concat (substring time 0 -2) ":" (substring time -2))) | ||
| 22466 | new) | ||
| 22467 | (put-text-property | ||
| 22468 | 1 (length (car new)) 'face 'org-time-grid (car new)))) | ||
| 22469 | (if (member 'time-up org-agenda-sorting-strategy-selected) | ||
| 22470 | (append new list) | ||
| 22471 | (append list new))))) | ||
| 22472 | |||
| 22473 | (defun org-compile-prefix-format (key) | ||
| 22474 | "Compile the prefix format into a Lisp form that can be evaluated. | ||
| 22475 | The resulting form is returned and stored in the variable | ||
| 22476 | `org-prefix-format-compiled'." | ||
| 22477 | (setq org-prefix-has-time nil org-prefix-has-tag nil) | ||
| 22478 | (let ((s (cond | ||
| 22479 | ((stringp org-agenda-prefix-format) | ||
| 22480 | org-agenda-prefix-format) | ||
| 22481 | ((assq key org-agenda-prefix-format) | ||
| 22482 | (cdr (assq key org-agenda-prefix-format))) | ||
| 22483 | (t " %-12:c%?-12t% s"))) | ||
| 22484 | (start 0) | ||
| 22485 | varform vars var e c f opt) | ||
| 22486 | (while (string-match "%\\(\\?\\)?\\([-+]?[0-9.]*\\)\\([ .;,:!?=|/<>]?\\)\\([cts]\\)" | ||
| 22487 | s start) | ||
| 22488 | (setq var (cdr (assoc (match-string 4 s) | ||
| 22489 | '(("c" . category) ("t" . time) ("s" . extra) | ||
| 22490 | ("T" . tag)))) | ||
| 22491 | c (or (match-string 3 s) "") | ||
| 22492 | opt (match-beginning 1) | ||
| 22493 | start (1+ (match-beginning 0))) | ||
| 22494 | (if (equal var 'time) (setq org-prefix-has-time t)) | ||
| 22495 | (if (equal var 'tag) (setq org-prefix-has-tag t)) | ||
| 22496 | (setq f (concat "%" (match-string 2 s) "s")) | ||
| 22497 | (if opt | ||
| 22498 | (setq varform | ||
| 22499 | `(if (equal "" ,var) | ||
| 22500 | "" | ||
| 22501 | (format ,f (if (equal "" ,var) "" (concat ,var ,c))))) | ||
| 22502 | (setq varform `(format ,f (if (equal ,var "") "" (concat ,var ,c))))) | ||
| 22503 | (setq s (replace-match "%s" t nil s)) | ||
| 22504 | (push varform vars)) | ||
| 22505 | (setq vars (nreverse vars)) | ||
| 22506 | (setq org-prefix-format-compiled `(format ,s ,@vars)))) | ||
| 22507 | |||
| 22508 | (defun org-set-sorting-strategy (key) | ||
| 22509 | (if (symbolp (car org-agenda-sorting-strategy)) | ||
| 22510 | ;; the old format | ||
| 22511 | (setq org-agenda-sorting-strategy-selected org-agenda-sorting-strategy) | ||
| 22512 | (setq org-agenda-sorting-strategy-selected | ||
| 22513 | (or (cdr (assq key org-agenda-sorting-strategy)) | ||
| 22514 | (cdr (assq 'agenda org-agenda-sorting-strategy)) | ||
| 22515 | '(time-up category-keep priority-down))))) | ||
| 22516 | |||
| 22517 | (defun org-get-time-of-day (s &optional string mod24) | ||
| 22518 | "Check string S for a time of day. | ||
| 22519 | If found, return it as a military time number between 0 and 2400. | ||
| 22520 | If not found, return nil. | ||
| 22521 | The optional STRING argument forces conversion into a 5 character wide string | ||
| 22522 | HH:MM." | ||
| 22523 | (save-match-data | ||
| 22524 | (when | ||
| 22525 | (or (string-match "\\<\\([012]?[0-9]\\)\\(:\\([0-5][0-9]\\)\\)\\([AaPp][Mm]\\)?\\> *" s) | ||
| 22526 | (string-match "\\<\\([012]?[0-9]\\)\\(:\\([0-5][0-9]\\)\\)?\\([AaPp][Mm]\\)\\> *" s)) | ||
| 22527 | (let* ((h (string-to-number (match-string 1 s))) | ||
| 22528 | (m (if (match-end 3) (string-to-number (match-string 3 s)) 0)) | ||
| 22529 | (ampm (if (match-end 4) (downcase (match-string 4 s)))) | ||
| 22530 | (am-p (equal ampm "am")) | ||
| 22531 | (h1 (cond ((not ampm) h) | ||
| 22532 | ((= h 12) (if am-p 0 12)) | ||
| 22533 | (t (+ h (if am-p 0 12))))) | ||
| 22534 | (h2 (if (and string mod24 (not (and (= m 0) (= h1 24)))) | ||
| 22535 | (mod h1 24) h1)) | ||
| 22536 | (t0 (+ (* 100 h2) m)) | ||
| 22537 | (t1 (concat (if (>= h1 24) "+" " ") | ||
| 22538 | (if (< t0 100) "0" "") | ||
| 22539 | (if (< t0 10) "0" "") | ||
| 22540 | (int-to-string t0)))) | ||
| 22541 | (if string (concat (substring t1 -4 -2) ":" (substring t1 -2)) t0))))) | ||
| 22542 | |||
| 22543 | (defun org-finalize-agenda-entries (list &optional nosort) | ||
| 22544 | "Sort and concatenate the agenda items." | ||
| 22545 | (setq list (mapcar 'org-agenda-highlight-todo list)) | ||
| 22546 | (if nosort | ||
| 22547 | list | ||
| 22548 | (mapconcat 'identity (sort list 'org-entries-lessp) "\n"))) | ||
| 22549 | |||
| 22550 | (defun org-agenda-highlight-todo (x) | ||
| 22551 | (let (re pl) | ||
| 22552 | (if (eq x 'line) | ||
| 22553 | (save-excursion | ||
| 22554 | (beginning-of-line 1) | ||
| 22555 | (setq re (get-text-property (point) 'org-todo-regexp)) | ||
| 22556 | (goto-char (+ (point) (or (get-text-property (point) 'prefix-length) 0))) | ||
| 22557 | (when (looking-at (concat "[ \t]*\\.*" re " +")) | ||
| 22558 | (add-text-properties (match-beginning 0) (match-end 0) | ||
| 22559 | (list 'face (org-get-todo-face 0))) | ||
| 22560 | (let ((s (buffer-substring (match-beginning 1) (match-end 1)))) | ||
| 22561 | (delete-region (match-beginning 1) (1- (match-end 0))) | ||
| 22562 | (goto-char (match-beginning 1)) | ||
| 22563 | (insert (format org-agenda-todo-keyword-format s))))) | ||
| 22564 | (setq re (concat (get-text-property 0 'org-todo-regexp x)) | ||
| 22565 | pl (get-text-property 0 'prefix-length x)) | ||
| 22566 | (when (and re | ||
| 22567 | (equal (string-match (concat "\\(\\.*\\)" re "\\( +\\)") | ||
| 22568 | x (or pl 0)) pl)) | ||
| 22569 | (add-text-properties | ||
| 22570 | (or (match-end 1) (match-end 0)) (match-end 0) | ||
| 22571 | (list 'face (org-get-todo-face (match-string 2 x))) | ||
| 22572 | x) | ||
| 22573 | (setq x (concat (substring x 0 (match-end 1)) | ||
| 22574 | (format org-agenda-todo-keyword-format | ||
| 22575 | (match-string 2 x)) | ||
| 22576 | " " | ||
| 22577 | (substring x (match-end 3))))) | ||
| 22578 | x))) | ||
| 22579 | |||
| 22580 | (defsubst org-cmp-priority (a b) | ||
| 22581 | "Compare the priorities of string A and B." | ||
| 22582 | (let ((pa (or (get-text-property 1 'priority a) 0)) | ||
| 22583 | (pb (or (get-text-property 1 'priority b) 0))) | ||
| 22584 | (cond ((> pa pb) +1) | ||
| 22585 | ((< pa pb) -1) | ||
| 22586 | (t nil)))) | ||
| 22587 | |||
| 22588 | (defsubst org-cmp-category (a b) | ||
| 22589 | "Compare the string values of categories of strings A and B." | ||
| 22590 | (let ((ca (or (get-text-property 1 'org-category a) "")) | ||
| 22591 | (cb (or (get-text-property 1 'org-category b) ""))) | ||
| 22592 | (cond ((string-lessp ca cb) -1) | ||
| 22593 | ((string-lessp cb ca) +1) | ||
| 22594 | (t nil)))) | ||
| 22595 | |||
| 22596 | (defsubst org-cmp-tag (a b) | ||
| 22597 | "Compare the string values of categories of strings A and B." | ||
| 22598 | (let ((ta (car (last (get-text-property 1 'tags a)))) | ||
| 22599 | (tb (car (last (get-text-property 1 'tags b))))) | ||
| 22600 | (cond ((not ta) +1) | ||
| 22601 | ((not tb) -1) | ||
| 22602 | ((string-lessp ta tb) -1) | ||
| 22603 | ((string-lessp tb ta) +1) | ||
| 22604 | (t nil)))) | ||
| 22605 | |||
| 22606 | (defsubst org-cmp-time (a b) | ||
| 22607 | "Compare the time-of-day values of strings A and B." | ||
| 22608 | (let* ((def (if org-sort-agenda-notime-is-late 9901 -1)) | ||
| 22609 | (ta (or (get-text-property 1 'time-of-day a) def)) | ||
| 22610 | (tb (or (get-text-property 1 'time-of-day b) def))) | ||
| 22611 | (cond ((< ta tb) -1) | ||
| 22612 | ((< tb ta) +1) | ||
| 22613 | (t nil)))) | ||
| 22614 | |||
| 22615 | (defun org-entries-lessp (a b) | ||
| 22616 | "Predicate for sorting agenda entries." | ||
| 22617 | ;; The following variables will be used when the form is evaluated. | ||
| 22618 | ;; So even though the compiler complains, keep them. | ||
| 22619 | (let* ((time-up (org-cmp-time a b)) | ||
| 22620 | (time-down (if time-up (- time-up) nil)) | ||
| 22621 | (priority-up (org-cmp-priority a b)) | ||
| 22622 | (priority-down (if priority-up (- priority-up) nil)) | ||
| 22623 | (category-up (org-cmp-category a b)) | ||
| 22624 | (category-down (if category-up (- category-up) nil)) | ||
| 22625 | (category-keep (if category-up +1 nil)) | ||
| 22626 | (tag-up (org-cmp-tag a b)) | ||
| 22627 | (tag-down (if tag-up (- tag-up) nil))) | ||
| 22628 | (cdr (assoc | ||
| 22629 | (eval (cons 'or org-agenda-sorting-strategy-selected)) | ||
| 22630 | '((-1 . t) (1 . nil) (nil . nil)))))) | ||
| 22631 | |||
| 22632 | ;;; Agenda restriction lock | ||
| 22633 | |||
| 22634 | (defvar org-agenda-restriction-lock-overlay (org-make-overlay 1 1) | ||
| 22635 | "Overlay to mark the headline to which arenda commands are restricted.") | ||
| 22636 | (org-overlay-put org-agenda-restriction-lock-overlay | ||
| 22637 | 'face 'org-agenda-restriction-lock) | ||
| 22638 | (org-overlay-put org-agenda-restriction-lock-overlay | ||
| 22639 | 'help-echo "Agendas are currently limited to this subtree.") | ||
| 22640 | (org-detach-overlay org-agenda-restriction-lock-overlay) | ||
| 22641 | (defvar org-speedbar-restriction-lock-overlay (org-make-overlay 1 1) | ||
| 22642 | "Overlay marking the agenda restriction line in speedbar.") | ||
| 22643 | (org-overlay-put org-speedbar-restriction-lock-overlay | ||
| 22644 | 'face 'org-agenda-restriction-lock) | ||
| 22645 | (org-overlay-put org-speedbar-restriction-lock-overlay | ||
| 22646 | 'help-echo "Agendas are currently limited to this item.") | ||
| 22647 | (org-detach-overlay org-speedbar-restriction-lock-overlay) | ||
| 22648 | |||
| 22649 | (defun org-agenda-set-restriction-lock (&optional type) | ||
| 22650 | "Set restriction lock for agenda, to current subtree or file. | ||
| 22651 | Restriction will be the file if TYPE is `file', or if type is the | ||
| 22652 | universal prefix '(4), or if the cursor is before the first headline | ||
| 22653 | in the file. Otherwise, restriction will be to the current subtree." | ||
| 22654 | (interactive "P") | ||
| 22655 | (and (equal type '(4)) (setq type 'file)) | ||
| 22656 | (setq type (cond | ||
| 22657 | (type type) | ||
| 22658 | ((org-at-heading-p) 'subtree) | ||
| 22659 | ((condition-case nil (org-back-to-heading t) (error nil)) | ||
| 22660 | 'subtree) | ||
| 22661 | (t 'file))) | ||
| 22662 | (if (eq type 'subtree) | ||
| 22663 | (progn | ||
| 22664 | (setq org-agenda-restrict t) | ||
| 22665 | (setq org-agenda-overriding-restriction 'subtree) | ||
| 22666 | (put 'org-agenda-files 'org-restrict | ||
| 22667 | (list (buffer-file-name (buffer-base-buffer)))) | ||
| 22668 | (org-back-to-heading t) | ||
| 22669 | (org-move-overlay org-agenda-restriction-lock-overlay (point) (point-at-eol)) | ||
| 22670 | (move-marker org-agenda-restrict-begin (point)) | ||
| 22671 | (move-marker org-agenda-restrict-end | ||
| 22672 | (save-excursion (org-end-of-subtree t))) | ||
| 22673 | (message "Locking agenda restriction to subtree")) | ||
| 22674 | (put 'org-agenda-files 'org-restrict | ||
| 22675 | (list (buffer-file-name (buffer-base-buffer)))) | ||
| 22676 | (setq org-agenda-restrict nil) | ||
| 22677 | (setq org-agenda-overriding-restriction 'file) | ||
| 22678 | (move-marker org-agenda-restrict-begin nil) | ||
| 22679 | (move-marker org-agenda-restrict-end nil) | ||
| 22680 | (message "Locking agenda restriction to file")) | ||
| 22681 | (setq current-prefix-arg nil) | ||
| 22682 | (org-agenda-maybe-redo)) | ||
| 22683 | |||
| 22684 | (defun org-agenda-remove-restriction-lock (&optional noupdate) | ||
| 22685 | "Remove the agenda restriction lock." | ||
| 22686 | (interactive "P") | ||
| 22687 | (org-detach-overlay org-agenda-restriction-lock-overlay) | ||
| 22688 | (org-detach-overlay org-speedbar-restriction-lock-overlay) | ||
| 22689 | (setq org-agenda-overriding-restriction nil) | ||
| 22690 | (setq org-agenda-restrict nil) | ||
| 22691 | (put 'org-agenda-files 'org-restrict nil) | ||
| 22692 | (move-marker org-agenda-restrict-begin nil) | ||
| 22693 | (move-marker org-agenda-restrict-end nil) | ||
| 22694 | (setq current-prefix-arg nil) | ||
| 22695 | (message "Agenda restriction lock removed") | ||
| 22696 | (or noupdate (org-agenda-maybe-redo))) | ||
| 22697 | |||
| 22698 | (defun org-agenda-maybe-redo () | ||
| 22699 | "If there is any window showing the agenda view, update it." | ||
| 22700 | (let ((w (get-buffer-window org-agenda-buffer-name t)) | ||
| 22701 | (w0 (selected-window))) | ||
| 22702 | (when w | ||
| 22703 | (select-window w) | ||
| 22704 | (org-agenda-redo) | ||
| 22705 | (select-window w0) | ||
| 22706 | (if org-agenda-overriding-restriction | ||
| 22707 | (message "Agenda view shifted to new %s restriction" | ||
| 22708 | org-agenda-overriding-restriction) | ||
| 22709 | (message "Agenda restriction lock removed"))))) | ||
| 22710 | |||
| 22711 | ;;; Agenda commands | ||
| 22712 | |||
| 22713 | (defun org-agenda-check-type (error &rest types) | ||
| 22714 | "Check if agenda buffer is of allowed type. | ||
| 22715 | If ERROR is non-nil, throw an error, otherwise just return nil." | ||
| 22716 | (if (memq org-agenda-type types) | ||
| 22717 | t | ||
| 22718 | (if error | ||
| 22719 | (error "Not allowed in %s-type agenda buffers" org-agenda-type) | ||
| 22720 | nil))) | ||
| 22721 | |||
| 22722 | (defun org-agenda-quit () | ||
| 22723 | "Exit agenda by removing the window or the buffer." | ||
| 22724 | (interactive) | ||
| 22725 | (let ((buf (current-buffer))) | ||
| 22726 | (if (not (one-window-p)) (delete-window)) | ||
| 22727 | (kill-buffer buf) | ||
| 22728 | (org-agenda-reset-markers) | ||
| 22729 | (org-columns-remove-overlays)) | ||
| 22730 | ;; Maybe restore the pre-agenda window configuration. | ||
| 22731 | (and org-agenda-restore-windows-after-quit | ||
| 22732 | (not (eq org-agenda-window-setup 'other-frame)) | ||
| 22733 | org-pre-agenda-window-conf | ||
| 22734 | (set-window-configuration org-pre-agenda-window-conf))) | ||
| 22735 | |||
| 22736 | (defun org-agenda-exit () | ||
| 22737 | "Exit agenda by removing the window or the buffer. | ||
| 22738 | Also kill all Org-mode buffers which have been loaded by `org-agenda'. | ||
| 22739 | Org-mode buffers visited directly by the user will not be touched." | ||
| 22740 | (interactive) | ||
| 22741 | (org-release-buffers org-agenda-new-buffers) | ||
| 22742 | (setq org-agenda-new-buffers nil) | ||
| 22743 | (org-agenda-quit)) | ||
| 22744 | |||
| 22745 | (defun org-agenda-execute (arg) | ||
| 22746 | "Execute another agenda command, keeping same window.\\<global-map> | ||
| 22747 | So this is just a shortcut for `\\[org-agenda]', available in the agenda." | ||
| 22748 | (interactive "P") | ||
| 22749 | (let ((org-agenda-window-setup 'current-window)) | ||
| 22750 | (org-agenda arg))) | ||
| 22751 | |||
| 22752 | (defun org-save-all-org-buffers () | ||
| 22753 | "Save all Org-mode buffers without user confirmation." | ||
| 22754 | (interactive) | ||
| 22755 | (message "Saving all Org-mode buffers...") | ||
| 22756 | (save-some-buffers t 'org-mode-p) | ||
| 22757 | (message "Saving all Org-mode buffers... done")) | ||
| 22758 | |||
| 22759 | (defun org-agenda-redo () | ||
| 22760 | "Rebuild Agenda. | ||
| 22761 | When this is the global TODO list, a prefix argument will be interpreted." | ||
| 22762 | (interactive) | ||
| 22763 | (let* ((org-agenda-keep-modes t) | ||
| 22764 | (line (org-current-line)) | ||
| 22765 | (window-line (- line (org-current-line (window-start)))) | ||
| 22766 | (lprops (get 'org-agenda-redo-command 'org-lprops))) | ||
| 22767 | (message "Rebuilding agenda buffer...") | ||
| 22768 | (org-let lprops '(eval org-agenda-redo-command)) | ||
| 22769 | (setq org-agenda-undo-list nil | ||
| 22770 | org-agenda-pending-undo-list nil) | ||
| 22771 | (message "Rebuilding agenda buffer...done") | ||
| 22772 | (goto-line line) | ||
| 22773 | (recenter window-line))) | ||
| 22774 | |||
| 22775 | (defun org-agenda-manipulate-query-add () | ||
| 22776 | "Manipulate the query by adding a search term with positive selection. | ||
| 22777 | Positive selection means, the term must be matched for selection of an entry." | ||
| 22778 | (interactive) | ||
| 22779 | (org-agenda-manipulate-query ?\[)) | ||
| 22780 | (defun org-agenda-manipulate-query-subtract () | ||
| 22781 | "Manipulate the query by adding a search term with negative selection. | ||
| 22782 | Negative selection means, term must not be matched for selection of an entry." | ||
| 22783 | (interactive) | ||
| 22784 | (org-agenda-manipulate-query ?\])) | ||
| 22785 | (defun org-agenda-manipulate-query-add-re () | ||
| 22786 | "Manipulate the query by adding a search regexp with positive selection. | ||
| 22787 | Positive selection means, the regexp must match for selection of an entry." | ||
| 22788 | (interactive) | ||
| 22789 | (org-agenda-manipulate-query ?\{)) | ||
| 22790 | (defun org-agenda-manipulate-query-subtract-re () | ||
| 22791 | "Manipulate the query by adding a search regexp with negative selection. | ||
| 22792 | Negative selection means, regexp must not match for selection of an entry." | ||
| 22793 | (interactive) | ||
| 22794 | (org-agenda-manipulate-query ?\})) | ||
| 22795 | (defun org-agenda-manipulate-query (char) | ||
| 22796 | (cond | ||
| 22797 | ((eq org-agenda-type 'search) | ||
| 22798 | (org-add-to-string | ||
| 22799 | 'org-agenda-query-string | ||
| 22800 | (cdr (assoc char '((?\[ . " +") (?\] . " -") | ||
| 22801 | (?\{ . " +{}") (?\} . " -{}"))))) | ||
| 22802 | (setq org-agenda-redo-command | ||
| 22803 | (list 'org-search-view | ||
| 22804 | (+ (length org-agenda-query-string) | ||
| 22805 | (if (member char '(?\{ ?\})) 0 1)) | ||
| 22806 | org-agenda-query-string)) | ||
| 22807 | (set-register org-agenda-query-register org-agenda-query-string) | ||
| 22808 | (org-agenda-redo)) | ||
| 22809 | (t (error "Canot manipulate query for %s-type agenda buffers" | ||
| 22810 | org-agenda-type)))) | ||
| 22811 | |||
| 22812 | (defun org-add-to-string (var string) | ||
| 22813 | (set var (concat (symbol-value var) string))) | ||
| 22814 | |||
| 22815 | (defun org-agenda-goto-date (date) | ||
| 22816 | "Jump to DATE in agenda." | ||
| 22817 | (interactive (list (org-read-date))) | ||
| 22818 | (org-agenda-list nil date)) | ||
| 22819 | |||
| 22820 | (defun org-agenda-goto-today () | ||
| 22821 | "Go to today." | ||
| 22822 | (interactive) | ||
| 22823 | (org-agenda-check-type t 'timeline 'agenda) | ||
| 22824 | (let ((tdpos (text-property-any (point-min) (point-max) 'org-today t))) | ||
| 22825 | (cond | ||
| 22826 | (tdpos (goto-char tdpos)) | ||
| 22827 | ((eq org-agenda-type 'agenda) | ||
| 22828 | (let* ((sd (time-to-days | ||
| 22829 | (time-subtract (current-time) | ||
| 22830 | (list 0 (* 3600 org-extend-today-until) 0)))) | ||
| 22831 | (comp (org-agenda-compute-time-span sd org-agenda-span)) | ||
| 22832 | (org-agenda-overriding-arguments org-agenda-last-arguments)) | ||
| 22833 | (setf (nth 1 org-agenda-overriding-arguments) (car comp)) | ||
| 22834 | (setf (nth 2 org-agenda-overriding-arguments) (cdr comp)) | ||
| 22835 | (org-agenda-redo) | ||
| 22836 | (org-agenda-find-same-or-today-or-agenda))) | ||
| 22837 | (t (error "Cannot find today"))))) | ||
| 22838 | |||
| 22839 | (defun org-agenda-find-same-or-today-or-agenda (&optional cnt) | ||
| 22840 | (goto-char | ||
| 22841 | (or (and cnt (text-property-any (point-min) (point-max) 'org-day-cnt cnt)) | ||
| 22842 | (text-property-any (point-min) (point-max) 'org-today t) | ||
| 22843 | (text-property-any (point-min) (point-max) 'org-agenda-type 'agenda) | ||
| 22844 | (point-min)))) | ||
| 22845 | |||
| 22846 | (defun org-agenda-later (arg) | ||
| 22847 | "Go forward in time by thee current span. | ||
| 22848 | With prefix ARG, go forward that many times the current span." | ||
| 22849 | (interactive "p") | ||
| 22850 | (org-agenda-check-type t 'agenda) | ||
| 22851 | (let* ((span org-agenda-span) | ||
| 22852 | (sd org-starting-day) | ||
| 22853 | (greg (calendar-gregorian-from-absolute sd)) | ||
| 22854 | (cnt (get-text-property (point) 'org-day-cnt)) | ||
| 22855 | greg2 nd) | ||
| 22856 | (cond | ||
| 22857 | ((eq span 'day) | ||
| 22858 | (setq sd (+ arg sd) nd 1)) | ||
| 22859 | ((eq span 'week) | ||
| 22860 | (setq sd (+ (* 7 arg) sd) nd 7)) | ||
| 22861 | ((eq span 'month) | ||
| 22862 | (setq greg2 (list (+ (car greg) arg) (nth 1 greg) (nth 2 greg)) | ||
| 22863 | sd (calendar-absolute-from-gregorian greg2)) | ||
| 22864 | (setcar greg2 (1+ (car greg2))) | ||
| 22865 | (setq nd (- (calendar-absolute-from-gregorian greg2) sd))) | ||
| 22866 | ((eq span 'year) | ||
| 22867 | (setq greg2 (list (car greg) (nth 1 greg) (+ arg (nth 2 greg))) | ||
| 22868 | sd (calendar-absolute-from-gregorian greg2)) | ||
| 22869 | (setcar (nthcdr 2 greg2) (1+ (nth 2 greg2))) | ||
| 22870 | (setq nd (- (calendar-absolute-from-gregorian greg2) sd)))) | ||
| 22871 | (let ((org-agenda-overriding-arguments | ||
| 22872 | (list (car org-agenda-last-arguments) sd nd t))) | ||
| 22873 | (org-agenda-redo) | ||
| 22874 | (org-agenda-find-same-or-today-or-agenda cnt)))) | ||
| 22875 | |||
| 22876 | (defun org-agenda-earlier (arg) | ||
| 22877 | "Go backward in time by the current span. | ||
| 22878 | With prefix ARG, go backward that many times the current span." | ||
| 22879 | (interactive "p") | ||
| 22880 | (org-agenda-later (- arg))) | ||
| 22881 | |||
| 22882 | (defun org-agenda-day-view () | ||
| 22883 | "Switch to daily view for agenda." | ||
| 22884 | (interactive) | ||
| 22885 | (setq org-agenda-ndays 1) | ||
| 22886 | (org-agenda-change-time-span 'day)) | ||
| 22887 | (defun org-agenda-week-view () | ||
| 22888 | "Switch to daily view for agenda." | ||
| 22889 | (interactive) | ||
| 22890 | (setq org-agenda-ndays 7) | ||
| 22891 | (org-agenda-change-time-span 'week)) | ||
| 22892 | (defun org-agenda-month-view () | ||
| 22893 | "Switch to daily view for agenda." | ||
| 22894 | (interactive) | ||
| 22895 | (org-agenda-change-time-span 'month)) | ||
| 22896 | (defun org-agenda-year-view () | ||
| 22897 | "Switch to daily view for agenda." | ||
| 22898 | (interactive) | ||
| 22899 | (if (y-or-n-p "Are you sure you want to compute the agenda for an entire year? ") | ||
| 22900 | (org-agenda-change-time-span 'year) | ||
| 22901 | (error "Abort"))) | ||
| 22902 | |||
| 22903 | (defun org-agenda-change-time-span (span) | ||
| 22904 | "Change the agenda view to SPAN. | ||
| 22905 | SPAN may be `day', `week', `month', `year'." | ||
| 22906 | (org-agenda-check-type t 'agenda) | ||
| 22907 | (if (equal org-agenda-span span) | ||
| 22908 | (error "Viewing span is already \"%s\"" span)) | ||
| 22909 | (let* ((sd (or (get-text-property (point) 'day) | ||
| 22910 | org-starting-day)) | ||
| 22911 | (computed (org-agenda-compute-time-span sd span)) | ||
| 22912 | (org-agenda-overriding-arguments | ||
| 22913 | (list (car org-agenda-last-arguments) | ||
| 22914 | (car computed) (cdr computed) t))) | ||
| 22915 | (org-agenda-redo) | ||
| 22916 | (org-agenda-find-same-or-today-or-agenda)) | ||
| 22917 | (org-agenda-set-mode-name) | ||
| 22918 | (message "Switched to %s view" span)) | ||
| 22919 | |||
| 22920 | (defun org-agenda-compute-time-span (sd span) | ||
| 22921 | "Compute starting date and number of days for agenda. | ||
| 22922 | SPAN may be `day', `week', `month', `year'. The return value | ||
| 22923 | is a cons cell with the starting date and the number of days, | ||
| 22924 | so that the date SD will be in that range." | ||
| 22925 | (let* ((greg (calendar-gregorian-from-absolute sd)) | ||
| 22926 | nd) | ||
| 22927 | (cond | ||
| 22928 | ((eq span 'day) | ||
| 22929 | (setq nd 1)) | ||
| 22930 | ((eq span 'week) | ||
| 22931 | (let* ((nt (calendar-day-of-week | ||
| 22932 | (calendar-gregorian-from-absolute sd))) | ||
| 22933 | (d (if org-agenda-start-on-weekday | ||
| 22934 | (- nt org-agenda-start-on-weekday) | ||
| 22935 | 0))) | ||
| 22936 | (setq sd (- sd (+ (if (< d 0) 7 0) d))) | ||
| 22937 | (setq nd 7))) | ||
| 22938 | ((eq span 'month) | ||
| 22939 | (setq sd (calendar-absolute-from-gregorian | ||
| 22940 | (list (car greg) 1 (nth 2 greg))) | ||
| 22941 | nd (- (calendar-absolute-from-gregorian | ||
| 22942 | (list (1+ (car greg)) 1 (nth 2 greg))) | ||
| 22943 | sd))) | ||
| 22944 | ((eq span 'year) | ||
| 22945 | (setq sd (calendar-absolute-from-gregorian | ||
| 22946 | (list 1 1 (nth 2 greg))) | ||
| 22947 | nd (- (calendar-absolute-from-gregorian | ||
| 22948 | (list 1 1 (1+ (nth 2 greg)))) | ||
| 22949 | sd)))) | ||
| 22950 | (cons sd nd))) | ||
| 22951 | |||
| 22952 | ;; FIXME: does not work if user makes date format that starts with a blank | ||
| 22953 | (defun org-agenda-next-date-line (&optional arg) | ||
| 22954 | "Jump to the next line indicating a date in agenda buffer." | ||
| 22955 | (interactive "p") | ||
| 22956 | (org-agenda-check-type t 'agenda 'timeline) | ||
| 22957 | (beginning-of-line 1) | ||
| 22958 | (if (looking-at "^\\S-") (forward-char 1)) | ||
| 22959 | (if (not (re-search-forward "^\\S-" nil t arg)) | ||
| 22960 | (progn | ||
| 22961 | (backward-char 1) | ||
| 22962 | (error "No next date after this line in this buffer"))) | ||
| 22963 | (goto-char (match-beginning 0))) | ||
| 22964 | |||
| 22965 | (defun org-agenda-previous-date-line (&optional arg) | ||
| 22966 | "Jump to the previous line indicating a date in agenda buffer." | ||
| 22967 | (interactive "p") | ||
| 22968 | (org-agenda-check-type t 'agenda 'timeline) | ||
| 22969 | (beginning-of-line 1) | ||
| 22970 | (if (not (re-search-backward "^\\S-" nil t arg)) | ||
| 22971 | (error "No previous date before this line in this buffer"))) | ||
| 22972 | |||
| 22973 | ;; Initialize the highlight | ||
| 22974 | (defvar org-hl (org-make-overlay 1 1)) | ||
| 22975 | (org-overlay-put org-hl 'face 'highlight) | ||
| 22976 | |||
| 22977 | (defun org-highlight (begin end &optional buffer) | ||
| 22978 | "Highlight a region with overlay." | ||
| 22979 | (funcall (if (featurep 'xemacs) 'set-extent-endpoints 'move-overlay) | ||
| 22980 | org-hl begin end (or buffer (current-buffer)))) | ||
| 22981 | |||
| 22982 | (defun org-unhighlight () | ||
| 22983 | "Detach overlay INDEX." | ||
| 22984 | (funcall (if (featurep 'xemacs) 'detach-extent 'delete-overlay) org-hl)) | ||
| 22985 | |||
| 22986 | ;; FIXME this is currently not used. | ||
| 22987 | (defun org-highlight-until-next-command (beg end &optional buffer) | ||
| 22988 | (org-highlight beg end buffer) | ||
| 22989 | (add-hook 'pre-command-hook 'org-unhighlight-once)) | ||
| 22990 | (defun org-unhighlight-once () | ||
| 22991 | (remove-hook 'pre-command-hook 'org-unhighlight-once) | ||
| 22992 | (org-unhighlight)) | ||
| 22993 | |||
| 22994 | (defun org-agenda-follow-mode () | ||
| 22995 | "Toggle follow mode in an agenda buffer." | ||
| 22996 | (interactive) | ||
| 22997 | (setq org-agenda-follow-mode (not org-agenda-follow-mode)) | ||
| 22998 | (org-agenda-set-mode-name) | ||
| 22999 | (message "Follow mode is %s" | ||
| 23000 | (if org-agenda-follow-mode "on" "off"))) | ||
| 23001 | |||
| 23002 | (defun org-agenda-log-mode () | ||
| 23003 | "Toggle log mode in an agenda buffer." | ||
| 23004 | (interactive) | ||
| 23005 | (org-agenda-check-type t 'agenda 'timeline) | ||
| 23006 | (setq org-agenda-show-log (not org-agenda-show-log)) | ||
| 23007 | (org-agenda-set-mode-name) | ||
| 23008 | (org-agenda-redo) | ||
| 23009 | (message "Log mode is %s" | ||
| 23010 | (if org-agenda-show-log "on" "off"))) | ||
| 23011 | |||
| 23012 | (defun org-agenda-toggle-diary () | ||
| 23013 | "Toggle diary inclusion in an agenda buffer." | ||
| 23014 | (interactive) | ||
| 23015 | (org-agenda-check-type t 'agenda) | ||
| 23016 | (setq org-agenda-include-diary (not org-agenda-include-diary)) | ||
| 23017 | (org-agenda-redo) | ||
| 23018 | (org-agenda-set-mode-name) | ||
| 23019 | (message "Diary inclusion turned %s" | ||
| 23020 | (if org-agenda-include-diary "on" "off"))) | ||
| 23021 | |||
| 23022 | (defun org-agenda-toggle-time-grid () | ||
| 23023 | "Toggle time grid in an agenda buffer." | ||
| 23024 | (interactive) | ||
| 23025 | (org-agenda-check-type t 'agenda) | ||
| 23026 | (setq org-agenda-use-time-grid (not org-agenda-use-time-grid)) | ||
| 23027 | (org-agenda-redo) | ||
| 23028 | (org-agenda-set-mode-name) | ||
| 23029 | (message "Time-grid turned %s" | ||
| 23030 | (if org-agenda-use-time-grid "on" "off"))) | ||
| 23031 | |||
| 23032 | (defun org-agenda-set-mode-name () | ||
| 23033 | "Set the mode name to indicate all the small mode settings." | ||
| 23034 | (setq mode-name | ||
| 23035 | (concat "Org-Agenda" | ||
| 23036 | (if (equal org-agenda-ndays 1) " Day" "") | ||
| 23037 | (if (equal org-agenda-ndays 7) " Week" "") | ||
| 23038 | (if org-agenda-follow-mode " Follow" "") | ||
| 23039 | (if org-agenda-include-diary " Diary" "") | ||
| 23040 | (if org-agenda-use-time-grid " Grid" "") | ||
| 23041 | (if org-agenda-show-log " Log" ""))) | ||
| 23042 | (force-mode-line-update)) | ||
| 23043 | |||
| 23044 | (defun org-agenda-post-command-hook () | ||
| 23045 | (and (eolp) (not (bolp)) (backward-char 1)) | ||
| 23046 | (setq org-agenda-type (get-text-property (point) 'org-agenda-type)) | ||
| 23047 | (if (and org-agenda-follow-mode | ||
| 23048 | (get-text-property (point) 'org-marker)) | ||
| 23049 | (org-agenda-show))) | ||
| 23050 | |||
| 23051 | (defun org-agenda-show-priority () | ||
| 23052 | "Show the priority of the current item. | ||
| 23053 | This priority is composed of the main priority given with the [#A] cookies, | ||
| 23054 | and by additional input from the age of a schedules or deadline entry." | ||
| 23055 | (interactive) | ||
| 23056 | (let* ((pri (get-text-property (point-at-bol) 'priority))) | ||
| 23057 | (message "Priority is %d" (if pri pri -1000)))) | ||
| 23058 | |||
| 23059 | (defun org-agenda-show-tags () | ||
| 23060 | "Show the tags applicable to the current item." | ||
| 23061 | (interactive) | ||
| 23062 | (let* ((tags (get-text-property (point-at-bol) 'tags))) | ||
| 23063 | (if tags | ||
| 23064 | (message "Tags are :%s:" | ||
| 23065 | (org-no-properties (mapconcat 'identity tags ":"))) | ||
| 23066 | (message "No tags associated with this line")))) | ||
| 23067 | |||
| 23068 | (defun org-agenda-goto (&optional highlight) | ||
| 23069 | "Go to the Org-mode file which contains the item at point." | ||
| 23070 | (interactive) | ||
| 23071 | (let* ((marker (or (get-text-property (point) 'org-marker) | ||
| 23072 | (org-agenda-error))) | ||
| 23073 | (buffer (marker-buffer marker)) | ||
| 23074 | (pos (marker-position marker))) | ||
| 23075 | (switch-to-buffer-other-window buffer) | ||
| 23076 | (widen) | ||
| 23077 | (goto-char pos) | ||
| 23078 | (when (org-mode-p) | ||
| 23079 | (org-show-context 'agenda) | ||
| 23080 | (save-excursion | ||
| 23081 | (and (outline-next-heading) | ||
| 23082 | (org-flag-heading nil)))) ; show the next heading | ||
| 23083 | (recenter (/ (window-height) 2)) | ||
| 23084 | (run-hooks 'org-agenda-after-show-hook) | ||
| 23085 | (and highlight (org-highlight (point-at-bol) (point-at-eol))))) | ||
| 23086 | |||
| 23087 | (defvar org-agenda-after-show-hook nil | ||
| 23088 | "Normal hook run after an item has been shown from the agenda. | ||
| 23089 | Point is in the buffer where the item originated.") | ||
| 23090 | |||
| 23091 | (defun org-agenda-kill () | ||
| 23092 | "Kill the entry or subtree belonging to the current agenda entry." | ||
| 23093 | (interactive) | ||
| 23094 | (or (eq major-mode 'org-agenda-mode) (error "Not in agenda")) | ||
| 23095 | (let* ((marker (or (get-text-property (point) 'org-marker) | ||
| 23096 | (org-agenda-error))) | ||
| 23097 | (buffer (marker-buffer marker)) | ||
| 23098 | (pos (marker-position marker)) | ||
| 23099 | (type (get-text-property (point) 'type)) | ||
| 23100 | dbeg dend (n 0) conf) | ||
| 23101 | (org-with-remote-undo buffer | ||
| 23102 | (with-current-buffer buffer | ||
| 23103 | (save-excursion | ||
| 23104 | (goto-char pos) | ||
| 23105 | (if (and (org-mode-p) (not (member type '("sexp")))) | ||
| 23106 | (setq dbeg (progn (org-back-to-heading t) (point)) | ||
| 23107 | dend (org-end-of-subtree t t)) | ||
| 23108 | (setq dbeg (point-at-bol) | ||
| 23109 | dend (min (point-max) (1+ (point-at-eol))))) | ||
| 23110 | (goto-char dbeg) | ||
| 23111 | (while (re-search-forward "^[ \t]*\\S-" dend t) (setq n (1+ n))))) | ||
| 23112 | (setq conf (or (eq t org-agenda-confirm-kill) | ||
| 23113 | (and (numberp org-agenda-confirm-kill) | ||
| 23114 | (> n org-agenda-confirm-kill)))) | ||
| 23115 | (and conf | ||
| 23116 | (not (y-or-n-p | ||
| 23117 | (format "Delete entry with %d lines in buffer \"%s\"? " | ||
| 23118 | n (buffer-name buffer)))) | ||
| 23119 | (error "Abort")) | ||
| 23120 | (org-remove-subtree-entries-from-agenda buffer dbeg dend) | ||
| 23121 | (with-current-buffer buffer (delete-region dbeg dend)) | ||
| 23122 | (message "Agenda item and source killed")))) | ||
| 23123 | |||
| 23124 | (defun org-agenda-archive () | ||
| 23125 | "Kill the entry or subtree belonging to the current agenda entry." | ||
| 23126 | (interactive) | ||
| 23127 | (or (eq major-mode 'org-agenda-mode) (error "Not in agenda")) | ||
| 23128 | (let* ((marker (or (get-text-property (point) 'org-marker) | ||
| 23129 | (org-agenda-error))) | ||
| 23130 | (buffer (marker-buffer marker)) | ||
| 23131 | (pos (marker-position marker))) | ||
| 23132 | (org-with-remote-undo buffer | ||
| 23133 | (with-current-buffer buffer | ||
| 23134 | (if (org-mode-p) | ||
| 23135 | (save-excursion | ||
| 23136 | (goto-char pos) | ||
| 23137 | (org-remove-subtree-entries-from-agenda) | ||
| 23138 | (org-back-to-heading t) | ||
| 23139 | (org-archive-subtree)) | ||
| 23140 | (error "Archiving works only in Org-mode files")))))) | ||
| 23141 | |||
| 23142 | (defun org-remove-subtree-entries-from-agenda (&optional buf beg end) | ||
| 23143 | "Remove all lines in the agenda that correspond to a given subtree. | ||
| 23144 | The subtree is the one in buffer BUF, starting at BEG and ending at END. | ||
| 23145 | If this information is not given, the function uses the tree at point." | ||
| 23146 | (let ((buf (or buf (current-buffer))) m p) | ||
| 23147 | (save-excursion | ||
| 23148 | (unless (and beg end) | ||
| 23149 | (org-back-to-heading t) | ||
| 23150 | (setq beg (point)) | ||
| 23151 | (org-end-of-subtree t) | ||
| 23152 | (setq end (point))) | ||
| 23153 | (set-buffer (get-buffer org-agenda-buffer-name)) | ||
| 23154 | (save-excursion | ||
| 23155 | (goto-char (point-max)) | ||
| 23156 | (beginning-of-line 1) | ||
| 23157 | (while (not (bobp)) | ||
| 23158 | (when (and (setq m (get-text-property (point) 'org-marker)) | ||
| 23159 | (equal buf (marker-buffer m)) | ||
| 23160 | (setq p (marker-position m)) | ||
| 23161 | (>= p beg) | ||
| 23162 | (<= p end)) | ||
| 23163 | (let ((inhibit-read-only t)) | ||
| 23164 | (delete-region (point-at-bol) (1+ (point-at-eol))))) | ||
| 23165 | (beginning-of-line 0)))))) | ||
| 23166 | |||
| 23167 | (defun org-agenda-open-link () | ||
| 23168 | "Follow the link in the current line, if any." | ||
| 23169 | (interactive) | ||
| 23170 | (org-agenda-copy-local-variable 'org-link-abbrev-alist-local) | ||
| 23171 | (save-excursion | ||
| 23172 | (save-restriction | ||
| 23173 | (narrow-to-region (point-at-bol) (point-at-eol)) | ||
| 23174 | (org-open-at-point)))) | ||
| 23175 | |||
| 23176 | (defun org-agenda-copy-local-variable (var) | ||
| 23177 | "Get a variable from a referenced buffer and install it here." | ||
| 23178 | (let ((m (get-text-property (point) 'org-marker))) | ||
| 23179 | (when (and m (buffer-live-p (marker-buffer m))) | ||
| 23180 | (org-set-local var (with-current-buffer (marker-buffer m) | ||
| 23181 | (symbol-value var)))))) | ||
| 23182 | |||
| 23183 | (defun org-agenda-switch-to (&optional delete-other-windows) | ||
| 23184 | "Go to the Org-mode file which contains the item at point." | ||
| 23185 | (interactive) | ||
| 23186 | (let* ((marker (or (get-text-property (point) 'org-marker) | ||
| 23187 | (org-agenda-error))) | ||
| 23188 | (buffer (marker-buffer marker)) | ||
| 23189 | (pos (marker-position marker))) | ||
| 23190 | (switch-to-buffer buffer) | ||
| 23191 | (and delete-other-windows (delete-other-windows)) | ||
| 23192 | (widen) | ||
| 23193 | (goto-char pos) | ||
| 23194 | (when (org-mode-p) | ||
| 23195 | (org-show-context 'agenda) | ||
| 23196 | (save-excursion | ||
| 23197 | (and (outline-next-heading) | ||
| 23198 | (org-flag-heading nil)))))) ; show the next heading | ||
| 23199 | |||
| 23200 | (defun org-agenda-goto-mouse (ev) | ||
| 23201 | "Go to the Org-mode file which contains the item at the mouse click." | ||
| 23202 | (interactive "e") | ||
| 23203 | (mouse-set-point ev) | ||
| 23204 | (org-agenda-goto)) | ||
| 23205 | |||
| 23206 | (defun org-agenda-show () | ||
| 23207 | "Display the Org-mode file which contains the item at point." | ||
| 23208 | (interactive) | ||
| 23209 | (let ((win (selected-window))) | ||
| 23210 | (org-agenda-goto t) | ||
| 23211 | (select-window win))) | ||
| 23212 | |||
| 23213 | (defun org-agenda-recenter (arg) | ||
| 23214 | "Display the Org-mode file which contains the item at point and recenter." | ||
| 23215 | (interactive "P") | ||
| 23216 | (let ((win (selected-window))) | ||
| 23217 | (org-agenda-goto t) | ||
| 23218 | (recenter arg) | ||
| 23219 | (select-window win))) | ||
| 23220 | |||
| 23221 | (defun org-agenda-show-mouse (ev) | ||
| 23222 | "Display the Org-mode file which contains the item at the mouse click." | ||
| 23223 | (interactive "e") | ||
| 23224 | (mouse-set-point ev) | ||
| 23225 | (org-agenda-show)) | ||
| 23226 | |||
| 23227 | (defun org-agenda-check-no-diary () | ||
| 23228 | "Check if the entry is a diary link and abort if yes." | ||
| 23229 | (if (get-text-property (point) 'org-agenda-diary-link) | ||
| 23230 | (org-agenda-error))) | ||
| 23231 | |||
| 23232 | (defun org-agenda-error () | ||
| 23233 | (error "Command not allowed in this line")) | ||
| 23234 | |||
| 23235 | (defun org-agenda-tree-to-indirect-buffer () | ||
| 23236 | "Show the subtree corresponding to the current entry in an indirect buffer. | ||
| 23237 | This calls the command `org-tree-to-indirect-buffer' from the original | ||
| 23238 | Org-mode buffer. | ||
| 23239 | With numerical prefix arg ARG, go up to this level and then take that tree. | ||
| 23240 | With a C-u prefix, make a separate frame for this tree (i.e. don't use the | ||
| 23241 | dedicated frame)." | ||
| 23242 | (interactive) | ||
| 23243 | (org-agenda-check-no-diary) | ||
| 23244 | (let* ((marker (or (get-text-property (point) 'org-marker) | ||
| 23245 | (org-agenda-error))) | ||
| 23246 | (buffer (marker-buffer marker)) | ||
| 23247 | (pos (marker-position marker))) | ||
| 23248 | (with-current-buffer buffer | ||
| 23249 | (save-excursion | ||
| 23250 | (goto-char pos) | ||
| 23251 | (call-interactively 'org-tree-to-indirect-buffer))))) | ||
| 23252 | |||
| 23253 | (defvar org-last-heading-marker (make-marker) | ||
| 23254 | "Marker pointing to the headline that last changed its TODO state | ||
| 23255 | by a remote command from the agenda.") | ||
| 23256 | |||
| 23257 | (defun org-agenda-todo-nextset () | ||
| 23258 | "Switch TODO entry to next sequence." | ||
| 23259 | (interactive) | ||
| 23260 | (org-agenda-todo 'nextset)) | ||
| 23261 | |||
| 23262 | (defun org-agenda-todo-previousset () | ||
| 23263 | "Switch TODO entry to previous sequence." | ||
| 23264 | (interactive) | ||
| 23265 | (org-agenda-todo 'previousset)) | ||
| 23266 | |||
| 23267 | (defun org-agenda-todo (&optional arg) | ||
| 23268 | "Cycle TODO state of line at point, also in Org-mode file. | ||
| 23269 | This changes the line at point, all other lines in the agenda referring to | ||
| 23270 | the same tree node, and the headline of the tree node in the Org-mode file." | ||
| 23271 | (interactive "P") | ||
| 23272 | (org-agenda-check-no-diary) | ||
| 23273 | (let* ((col (current-column)) | ||
| 23274 | (marker (or (get-text-property (point) 'org-marker) | ||
| 23275 | (org-agenda-error))) | ||
| 23276 | (buffer (marker-buffer marker)) | ||
| 23277 | (pos (marker-position marker)) | ||
| 23278 | (hdmarker (get-text-property (point) 'org-hd-marker)) | ||
| 23279 | (inhibit-read-only t) | ||
| 23280 | newhead) | ||
| 23281 | (org-with-remote-undo buffer | ||
| 23282 | (with-current-buffer buffer | ||
| 23283 | (widen) | ||
| 23284 | (goto-char pos) | ||
| 23285 | (org-show-context 'agenda) | ||
| 23286 | (save-excursion | ||
| 23287 | (and (outline-next-heading) | ||
| 23288 | (org-flag-heading nil))) ; show the next heading | ||
| 23289 | (org-todo arg) | ||
| 23290 | (and (bolp) (forward-char 1)) | ||
| 23291 | (setq newhead (org-get-heading)) | ||
| 23292 | (save-excursion | ||
| 23293 | (org-back-to-heading) | ||
| 23294 | (move-marker org-last-heading-marker (point)))) | ||
| 23295 | (beginning-of-line 1) | ||
| 23296 | (save-excursion | ||
| 23297 | (org-agenda-change-all-lines newhead hdmarker 'fixface)) | ||
| 23298 | (move-to-column col)))) | ||
| 23299 | |||
| 23300 | (defun org-agenda-change-all-lines (newhead hdmarker &optional fixface) | ||
| 23301 | "Change all lines in the agenda buffer which match HDMARKER. | ||
| 23302 | The new content of the line will be NEWHEAD (as modified by | ||
| 23303 | `org-format-agenda-item'). HDMARKER is checked with | ||
| 23304 | `equal' against all `org-hd-marker' text properties in the file. | ||
| 23305 | If FIXFACE is non-nil, the face of each item is modified acording to | ||
| 23306 | the new TODO state." | ||
| 23307 | (let* ((inhibit-read-only t) | ||
| 23308 | props m pl undone-face done-face finish new dotime cat tags) | ||
| 23309 | (save-excursion | ||
| 23310 | (goto-char (point-max)) | ||
| 23311 | (beginning-of-line 1) | ||
| 23312 | (while (not finish) | ||
| 23313 | (setq finish (bobp)) | ||
| 23314 | (when (and (setq m (get-text-property (point) 'org-hd-marker)) | ||
| 23315 | (equal m hdmarker)) | ||
| 23316 | (setq props (text-properties-at (point)) | ||
| 23317 | dotime (get-text-property (point) 'dotime) | ||
| 23318 | cat (get-text-property (point) 'org-category) | ||
| 23319 | tags (get-text-property (point) 'tags) | ||
| 23320 | new (org-format-agenda-item "x" newhead cat tags dotime 'noprefix) | ||
| 23321 | pl (get-text-property (point) 'prefix-length) | ||
| 23322 | undone-face (get-text-property (point) 'undone-face) | ||
| 23323 | done-face (get-text-property (point) 'done-face)) | ||
| 23324 | (move-to-column pl) | ||
| 23325 | (cond | ||
| 23326 | ((equal new "") | ||
| 23327 | (beginning-of-line 1) | ||
| 23328 | (and (looking-at ".*\n?") (replace-match ""))) | ||
| 23329 | ((looking-at ".*") | ||
| 23330 | (replace-match new t t) | ||
| 23331 | (beginning-of-line 1) | ||
| 23332 | (add-text-properties (point-at-bol) (point-at-eol) props) | ||
| 23333 | (when fixface | ||
| 23334 | (add-text-properties | ||
| 23335 | (point-at-bol) (point-at-eol) | ||
| 23336 | (list 'face | ||
| 23337 | (if org-last-todo-state-is-todo | ||
| 23338 | undone-face done-face)))) | ||
| 23339 | (org-agenda-highlight-todo 'line) | ||
| 23340 | (beginning-of-line 1)) | ||
| 23341 | (t (error "Line update did not work")))) | ||
| 23342 | (beginning-of-line 0))) | ||
| 23343 | (org-finalize-agenda))) | ||
| 23344 | |||
| 23345 | (defun org-agenda-align-tags (&optional line) | ||
| 23346 | "Align all tags in agenda items to `org-agenda-tags-column'." | ||
| 23347 | (let ((inhibit-read-only t) l c) | ||
| 23348 | (save-excursion | ||
| 23349 | (goto-char (if line (point-at-bol) (point-min))) | ||
| 23350 | (while (re-search-forward (org-re "\\([ \t]+\\)\\(:[[:alnum:]_@:]+:\\)[ \t]*$") | ||
| 23351 | (if line (point-at-eol) nil) t) | ||
| 23352 | (add-text-properties | ||
| 23353 | (match-beginning 2) (match-end 2) | ||
| 23354 | (list 'face (delq nil (list 'org-tag (get-text-property | ||
| 23355 | (match-beginning 2) 'face))))) | ||
| 23356 | (setq l (- (match-end 2) (match-beginning 2)) | ||
| 23357 | c (if (< org-agenda-tags-column 0) | ||
| 23358 | (- (abs org-agenda-tags-column) l) | ||
| 23359 | org-agenda-tags-column)) | ||
| 23360 | (delete-region (match-beginning 1) (match-end 1)) | ||
| 23361 | (goto-char (match-beginning 1)) | ||
| 23362 | (insert (org-add-props | ||
| 23363 | (make-string (max 1 (- c (current-column))) ?\ ) | ||
| 23364 | (text-properties-at (point)))))))) | ||
| 23365 | |||
| 23366 | (defun org-agenda-priority-up () | ||
| 23367 | "Increase the priority of line at point, also in Org-mode file." | ||
| 23368 | (interactive) | ||
| 23369 | (org-agenda-priority 'up)) | ||
| 23370 | |||
| 23371 | (defun org-agenda-priority-down () | ||
| 23372 | "Decrease the priority of line at point, also in Org-mode file." | ||
| 23373 | (interactive) | ||
| 23374 | (org-agenda-priority 'down)) | ||
| 23375 | |||
| 23376 | (defun org-agenda-priority (&optional force-direction) | ||
| 23377 | "Set the priority of line at point, also in Org-mode file. | ||
| 23378 | This changes the line at point, all other lines in the agenda referring to | ||
| 23379 | the same tree node, and the headline of the tree node in the Org-mode file." | ||
| 23380 | (interactive) | ||
| 23381 | (org-agenda-check-no-diary) | ||
| 23382 | (let* ((marker (or (get-text-property (point) 'org-marker) | ||
| 23383 | (org-agenda-error))) | ||
| 23384 | (hdmarker (get-text-property (point) 'org-hd-marker)) | ||
| 23385 | (buffer (marker-buffer hdmarker)) | ||
| 23386 | (pos (marker-position hdmarker)) | ||
| 23387 | (inhibit-read-only t) | ||
| 23388 | newhead) | ||
| 23389 | (org-with-remote-undo buffer | ||
| 23390 | (with-current-buffer buffer | ||
| 23391 | (widen) | ||
| 23392 | (goto-char pos) | ||
| 23393 | (org-show-context 'agenda) | ||
| 23394 | (save-excursion | ||
| 23395 | (and (outline-next-heading) | ||
| 23396 | (org-flag-heading nil))) ; show the next heading | ||
| 23397 | (funcall 'org-priority force-direction) | ||
| 23398 | (end-of-line 1) | ||
| 23399 | (setq newhead (org-get-heading))) | ||
| 23400 | (org-agenda-change-all-lines newhead hdmarker) | ||
| 23401 | (beginning-of-line 1)))) | ||
| 23402 | |||
| 23403 | (defun org-get-tags-at (&optional pos) | ||
| 23404 | "Get a list of all headline tags applicable at POS. | ||
| 23405 | POS defaults to point. If tags are inherited, the list contains | ||
| 23406 | the targets in the same sequence as the headlines appear, i.e. | ||
| 23407 | the tags of the current headline come last." | ||
| 23408 | (interactive) | ||
| 23409 | (let (tags lastpos) | ||
| 23410 | (save-excursion | ||
| 23411 | (save-restriction | ||
| 23412 | (widen) | ||
| 23413 | (goto-char (or pos (point))) | ||
| 23414 | (save-match-data | ||
| 23415 | (condition-case nil | ||
| 23416 | (progn | ||
| 23417 | (org-back-to-heading t) | ||
| 23418 | (while (not (equal lastpos (point))) | ||
| 23419 | (setq lastpos (point)) | ||
| 23420 | (if (looking-at (org-re "[^\r\n]+?:\\([[:alnum:]_@:]+\\):[ \t]*$")) | ||
| 23421 | (setq tags (append (org-split-string | ||
| 23422 | (org-match-string-no-properties 1) ":") | ||
| 23423 | tags))) | ||
| 23424 | (or org-use-tag-inheritance (error "")) | ||
| 23425 | (org-up-heading-all 1))) | ||
| 23426 | (error nil)))) | ||
| 23427 | tags))) | ||
| 23428 | |||
| 23429 | ;; FIXME: should fix the tags property of the agenda line. | ||
| 23430 | (defun org-agenda-set-tags () | ||
| 23431 | "Set tags for the current headline." | ||
| 23432 | (interactive) | ||
| 23433 | (org-agenda-check-no-diary) | ||
| 23434 | (if (and (org-region-active-p) (interactive-p)) | ||
| 23435 | (call-interactively 'org-change-tag-in-region) | ||
| 23436 | (org-agenda-show) ;;; FIXME This is a stupid hack and should not be needed | ||
| 23437 | (let* ((hdmarker (or (get-text-property (point) 'org-hd-marker) | ||
| 23438 | (org-agenda-error))) | ||
| 23439 | (buffer (marker-buffer hdmarker)) | ||
| 23440 | (pos (marker-position hdmarker)) | ||
| 23441 | (inhibit-read-only t) | ||
| 23442 | newhead) | ||
| 23443 | (org-with-remote-undo buffer | ||
| 23444 | (with-current-buffer buffer | ||
| 23445 | (widen) | ||
| 23446 | (goto-char pos) | ||
| 23447 | (save-excursion | ||
| 23448 | (org-show-context 'agenda)) | ||
| 23449 | (save-excursion | ||
| 23450 | (and (outline-next-heading) | ||
| 23451 | (org-flag-heading nil))) ; show the next heading | ||
| 23452 | (goto-char pos) | ||
| 23453 | (call-interactively 'org-set-tags) | ||
| 23454 | (end-of-line 1) | ||
| 23455 | (setq newhead (org-get-heading))) | ||
| 23456 | (org-agenda-change-all-lines newhead hdmarker) | ||
| 23457 | (beginning-of-line 1))))) | ||
| 23458 | |||
| 23459 | (defun org-agenda-toggle-archive-tag () | ||
| 23460 | "Toggle the archive tag for the current entry." | ||
| 23461 | (interactive) | ||
| 23462 | (org-agenda-check-no-diary) | ||
| 23463 | (org-agenda-show) ;;; FIXME This is a stupid hack and should not be needed | ||
| 23464 | (let* ((hdmarker (or (get-text-property (point) 'org-hd-marker) | ||
| 23465 | (org-agenda-error))) | ||
| 23466 | (buffer (marker-buffer hdmarker)) | ||
| 23467 | (pos (marker-position hdmarker)) | ||
| 23468 | (inhibit-read-only t) | ||
| 23469 | newhead) | ||
| 23470 | (org-with-remote-undo buffer | ||
| 23471 | (with-current-buffer buffer | ||
| 23472 | (widen) | ||
| 23473 | (goto-char pos) | ||
| 23474 | (org-show-context 'agenda) | ||
| 23475 | (save-excursion | ||
| 23476 | (and (outline-next-heading) | ||
| 23477 | (org-flag-heading nil))) ; show the next heading | ||
| 23478 | (call-interactively 'org-toggle-archive-tag) | ||
| 23479 | (end-of-line 1) | ||
| 23480 | (setq newhead (org-get-heading))) | ||
| 23481 | (org-agenda-change-all-lines newhead hdmarker) | ||
| 23482 | (beginning-of-line 1)))) | ||
| 23483 | |||
| 23484 | (defun org-agenda-date-later (arg &optional what) | ||
| 23485 | "Change the date of this item to one day later." | ||
| 23486 | (interactive "p") | ||
| 23487 | (org-agenda-check-type t 'agenda 'timeline) | ||
| 23488 | (org-agenda-check-no-diary) | ||
| 23489 | (let* ((marker (or (get-text-property (point) 'org-marker) | ||
| 23490 | (org-agenda-error))) | ||
| 23491 | (buffer (marker-buffer marker)) | ||
| 23492 | (pos (marker-position marker))) | ||
| 23493 | (org-with-remote-undo buffer | ||
| 23494 | (with-current-buffer buffer | ||
| 23495 | (widen) | ||
| 23496 | (goto-char pos) | ||
| 23497 | (if (not (org-at-timestamp-p)) | ||
| 23498 | (error "Cannot find time stamp")) | ||
| 23499 | (org-timestamp-change arg (or what 'day))) | ||
| 23500 | (org-agenda-show-new-time marker org-last-changed-timestamp)) | ||
| 23501 | (message "Time stamp changed to %s" org-last-changed-timestamp))) | ||
| 23502 | |||
| 23503 | (defun org-agenda-date-earlier (arg &optional what) | ||
| 23504 | "Change the date of this item to one day earlier." | ||
| 23505 | (interactive "p") | ||
| 23506 | (org-agenda-date-later (- arg) what)) | ||
| 23507 | |||
| 23508 | (defun org-agenda-show-new-time (marker stamp &optional prefix) | ||
| 23509 | "Show new date stamp via text properties." | ||
| 23510 | ;; We use text properties to make this undoable | ||
| 23511 | (let ((inhibit-read-only t)) | ||
| 23512 | (setq stamp (concat " " prefix " => " stamp)) | ||
| 23513 | (save-excursion | ||
| 23514 | (goto-char (point-max)) | ||
| 23515 | (while (not (bobp)) | ||
| 23516 | (when (equal marker (get-text-property (point) 'org-marker)) | ||
| 23517 | (move-to-column (- (window-width) (length stamp)) t) | ||
| 23518 | (if (featurep 'xemacs) | ||
| 23519 | ;; Use `duplicable' property to trigger undo recording | ||
| 23520 | (let ((ex (make-extent nil nil)) | ||
| 23521 | (gl (make-glyph stamp))) | ||
| 23522 | (set-glyph-face gl 'secondary-selection) | ||
| 23523 | (set-extent-properties | ||
| 23524 | ex (list 'invisible t 'end-glyph gl 'duplicable t)) | ||
| 23525 | (insert-extent ex (1- (point)) (point-at-eol))) | ||
| 23526 | (add-text-properties | ||
| 23527 | (1- (point)) (point-at-eol) | ||
| 23528 | (list 'display (org-add-props stamp nil | ||
| 23529 | 'face 'secondary-selection)))) | ||
| 23530 | (beginning-of-line 1)) | ||
| 23531 | (beginning-of-line 0))))) | ||
| 23532 | |||
| 23533 | (defun org-agenda-date-prompt (arg) | ||
| 23534 | "Change the date of this item. Date is prompted for, with default today. | ||
| 23535 | The prefix ARG is passed to the `org-time-stamp' command and can therefore | ||
| 23536 | be used to request time specification in the time stamp." | ||
| 23537 | (interactive "P") | ||
| 23538 | (org-agenda-check-type t 'agenda 'timeline) | ||
| 23539 | (org-agenda-check-no-diary) | ||
| 23540 | (let* ((marker (or (get-text-property (point) 'org-marker) | ||
| 23541 | (org-agenda-error))) | ||
| 23542 | (buffer (marker-buffer marker)) | ||
| 23543 | (pos (marker-position marker))) | ||
| 23544 | (org-with-remote-undo buffer | ||
| 23545 | (with-current-buffer buffer | ||
| 23546 | (widen) | ||
| 23547 | (goto-char pos) | ||
| 23548 | (if (not (org-at-timestamp-p)) | ||
| 23549 | (error "Cannot find time stamp")) | ||
| 23550 | (org-time-stamp arg) | ||
| 23551 | (message "Time stamp changed to %s" org-last-changed-timestamp))))) | ||
| 23552 | |||
| 23553 | (defun org-agenda-schedule (arg) | ||
| 23554 | "Schedule the item at point." | ||
| 23555 | (interactive "P") | ||
| 23556 | (org-agenda-check-type t 'agenda 'timeline 'todo 'tags) | ||
| 23557 | (org-agenda-check-no-diary) | ||
| 23558 | (let* ((marker (or (get-text-property (point) 'org-marker) | ||
| 23559 | (org-agenda-error))) | ||
| 23560 | (type (marker-insertion-type marker)) | ||
| 23561 | (buffer (marker-buffer marker)) | ||
| 23562 | (pos (marker-position marker)) | ||
| 23563 | (org-insert-labeled-timestamps-at-point nil) | ||
| 23564 | ts) | ||
| 23565 | (when type (message "%s" type) (sit-for 3)) | ||
| 23566 | (set-marker-insertion-type marker t) | ||
| 23567 | (org-with-remote-undo buffer | ||
| 23568 | (with-current-buffer buffer | ||
| 23569 | (widen) | ||
| 23570 | (goto-char pos) | ||
| 23571 | (setq ts (org-schedule arg))) | ||
| 23572 | (org-agenda-show-new-time marker ts "S")) | ||
| 23573 | (message "Item scheduled for %s" ts))) | ||
| 23574 | |||
| 23575 | (defun org-agenda-deadline (arg) | ||
| 23576 | "Schedule the item at point." | ||
| 23577 | (interactive "P") | ||
| 23578 | (org-agenda-check-type t 'agenda 'timeline 'todo 'tags) | ||
| 23579 | (org-agenda-check-no-diary) | ||
| 23580 | (let* ((marker (or (get-text-property (point) 'org-marker) | ||
| 23581 | (org-agenda-error))) | ||
| 23582 | (buffer (marker-buffer marker)) | ||
| 23583 | (pos (marker-position marker)) | ||
| 23584 | (org-insert-labeled-timestamps-at-point nil) | ||
| 23585 | ts) | ||
| 23586 | (org-with-remote-undo buffer | ||
| 23587 | (with-current-buffer buffer | ||
| 23588 | (widen) | ||
| 23589 | (goto-char pos) | ||
| 23590 | (setq ts (org-deadline arg))) | ||
| 23591 | (org-agenda-show-new-time marker ts "S")) | ||
| 23592 | (message "Deadline for this item set to %s" ts))) | ||
| 23593 | |||
| 23594 | (defun org-get-heading (&optional no-tags) | ||
| 23595 | "Return the heading of the current entry, without the stars." | ||
| 23596 | (save-excursion | ||
| 23597 | (org-back-to-heading t) | ||
| 23598 | (if (looking-at | ||
| 23599 | (if no-tags | ||
| 23600 | (org-re "\\*+[ \t]+\\([^\n\r]*?\\)\\([ \t]+:[[:alnum:]:_@]+:[ \t]*\\)?$") | ||
| 23601 | "\\*+[ \t]+\\([^\r\n]*\\)")) | ||
| 23602 | (match-string 1) ""))) | ||
| 23603 | |||
| 23604 | (defun org-agenda-clock-in (&optional arg) | ||
| 23605 | "Start the clock on the currently selected item." | ||
| 23606 | (interactive "P") | ||
| 23607 | (org-agenda-check-no-diary) | ||
| 23608 | (let* ((marker (or (get-text-property (point) 'org-marker) | ||
| 23609 | (org-agenda-error))) | ||
| 23610 | (pos (marker-position marker))) | ||
| 23611 | (org-with-remote-undo (marker-buffer marker) | ||
| 23612 | (with-current-buffer (marker-buffer marker) | ||
| 23613 | (widen) | ||
| 23614 | (goto-char pos) | ||
| 23615 | (org-clock-in))))) | ||
| 23616 | |||
| 23617 | (defun org-agenda-clock-out (&optional arg) | ||
| 23618 | "Stop the currently running clock." | ||
| 23619 | (interactive "P") | ||
| 23620 | (unless (marker-buffer org-clock-marker) | ||
| 23621 | (error "No running clock")) | ||
| 23622 | (org-with-remote-undo (marker-buffer org-clock-marker) | ||
| 23623 | (org-clock-out))) | ||
| 23624 | |||
| 23625 | (defun org-agenda-clock-cancel (&optional arg) | ||
| 23626 | "Cancel the currently running clock." | ||
| 23627 | (interactive "P") | ||
| 23628 | (unless (marker-buffer org-clock-marker) | ||
| 23629 | (error "No running clock")) | ||
| 23630 | (org-with-remote-undo (marker-buffer org-clock-marker) | ||
| 23631 | (org-clock-cancel))) | ||
| 23632 | |||
| 23633 | (defun org-agenda-diary-entry () | ||
| 23634 | "Make a diary entry, like the `i' command from the calendar. | ||
| 23635 | All the standard commands work: block, weekly etc." | ||
| 23636 | (interactive) | ||
| 23637 | (org-agenda-check-type t 'agenda 'timeline) | ||
| 23638 | (require 'diary-lib) | ||
| 23639 | (let* ((char (progn | ||
| 23640 | (message "Diary entry: [d]ay [w]eekly [m]onthly [y]early [a]nniversary [b]lock [c]yclic") | ||
| 23641 | (read-char-exclusive))) | ||
| 23642 | (cmd (cdr (assoc char | ||
| 23643 | '((?d . insert-diary-entry) | ||
| 23644 | (?w . insert-weekly-diary-entry) | ||
| 23645 | (?m . insert-monthly-diary-entry) | ||
| 23646 | (?y . insert-yearly-diary-entry) | ||
| 23647 | (?a . insert-anniversary-diary-entry) | ||
| 23648 | (?b . insert-block-diary-entry) | ||
| 23649 | (?c . insert-cyclic-diary-entry))))) | ||
| 23650 | (oldf (symbol-function 'calendar-cursor-to-date)) | ||
| 23651 | ; (buf (get-file-buffer (substitute-in-file-name diary-file))) | ||
| 23652 | (point (point)) | ||
| 23653 | (mark (or (mark t) (point)))) | ||
| 23654 | (unless cmd | ||
| 23655 | (error "No command associated with <%c>" char)) | ||
| 23656 | (unless (and (get-text-property point 'day) | ||
| 23657 | (or (not (equal ?b char)) | ||
| 23658 | (get-text-property mark 'day))) | ||
| 23659 | (error "Don't know which date to use for diary entry")) | ||
| 23660 | ;; We implement this by hacking the `calendar-cursor-to-date' function | ||
| 23661 | ;; and the `calendar-mark-ring' variable. Saves a lot of code. | ||
| 23662 | (let ((calendar-mark-ring | ||
| 23663 | (list (calendar-gregorian-from-absolute | ||
| 23664 | (or (get-text-property mark 'day) | ||
| 23665 | (get-text-property point 'day)))))) | ||
| 23666 | (unwind-protect | ||
| 23667 | (progn | ||
| 23668 | (fset 'calendar-cursor-to-date | ||
| 23669 | (lambda (&optional error) | ||
| 23670 | (calendar-gregorian-from-absolute | ||
| 23671 | (get-text-property point 'day)))) | ||
| 23672 | (call-interactively cmd)) | ||
| 23673 | (fset 'calendar-cursor-to-date oldf))))) | ||
| 23674 | |||
| 23675 | |||
| 23676 | (defun org-agenda-execute-calendar-command (cmd) | ||
| 23677 | "Execute a calendar command from the agenda, with the date associated to | ||
| 23678 | the cursor position." | ||
| 23679 | (org-agenda-check-type t 'agenda 'timeline) | ||
| 23680 | (require 'diary-lib) | ||
| 23681 | (unless (get-text-property (point) 'day) | ||
| 23682 | (error "Don't know which date to use for calendar command")) | ||
| 23683 | (let* ((oldf (symbol-function 'calendar-cursor-to-date)) | ||
| 23684 | (point (point)) | ||
| 23685 | (date (calendar-gregorian-from-absolute | ||
| 23686 | (get-text-property point 'day))) | ||
| 23687 | ;; the following 3 vars are needed in the calendar | ||
| 23688 | (displayed-day (extract-calendar-day date)) | ||
| 23689 | (displayed-month (extract-calendar-month date)) | ||
| 23690 | (displayed-year (extract-calendar-year date))) | ||
| 23691 | (unwind-protect | ||
| 23692 | (progn | ||
| 23693 | (fset 'calendar-cursor-to-date | ||
| 23694 | (lambda (&optional error) | ||
| 23695 | (calendar-gregorian-from-absolute | ||
| 23696 | (get-text-property point 'day)))) | ||
| 23697 | (call-interactively cmd)) | ||
| 23698 | (fset 'calendar-cursor-to-date oldf)))) | ||
| 23699 | |||
| 23700 | (defun org-agenda-phases-of-moon () | ||
| 23701 | "Display the phases of the moon for the 3 months around the cursor date." | ||
| 23702 | (interactive) | ||
| 23703 | (org-agenda-execute-calendar-command 'calendar-phases-of-moon)) | ||
| 23704 | |||
| 23705 | (defun org-agenda-holidays () | ||
| 23706 | "Display the holidays for the 3 months around the cursor date." | ||
| 23707 | (interactive) | ||
| 23708 | (org-agenda-execute-calendar-command 'list-calendar-holidays)) | ||
| 23709 | |||
| 23710 | (defvar calendar-longitude) | ||
| 23711 | (defvar calendar-latitude) | ||
| 23712 | (defvar calendar-location-name) | ||
| 23713 | |||
| 23714 | (defun org-agenda-sunrise-sunset (arg) | ||
| 23715 | "Display sunrise and sunset for the cursor date. | ||
| 23716 | Latitude and longitude can be specified with the variables | ||
| 23717 | `calendar-latitude' and `calendar-longitude'. When called with prefix | ||
| 23718 | argument, latitude and longitude will be prompted for." | ||
| 23719 | (interactive "P") | ||
| 23720 | (require 'solar) | ||
| 23721 | (let ((calendar-longitude (if arg nil calendar-longitude)) | ||
| 23722 | (calendar-latitude (if arg nil calendar-latitude)) | ||
| 23723 | (calendar-location-name | ||
| 23724 | (if arg "the given coordinates" calendar-location-name))) | ||
| 23725 | (org-agenda-execute-calendar-command 'calendar-sunrise-sunset))) | ||
| 23726 | |||
| 23727 | (defun org-agenda-goto-calendar () | ||
| 23728 | "Open the Emacs calendar with the date at the cursor." | ||
| 23729 | (interactive) | ||
| 23730 | (org-agenda-check-type t 'agenda 'timeline) | ||
| 23731 | (let* ((day (or (get-text-property (point) 'day) | ||
| 23732 | (error "Don't know which date to open in calendar"))) | ||
| 23733 | (date (calendar-gregorian-from-absolute day)) | ||
| 23734 | (calendar-move-hook nil) | ||
| 23735 | (view-calendar-holidays-initially nil) | ||
| 23736 | (view-diary-entries-initially nil)) | ||
| 23737 | (calendar) | ||
| 23738 | (calendar-goto-date date))) | ||
| 23739 | |||
| 23740 | (defun org-calendar-goto-agenda () | ||
| 23741 | "Compute the Org-mode agenda for the calendar date displayed at the cursor. | ||
| 23742 | This is a command that has to be installed in `calendar-mode-map'." | ||
| 23743 | (interactive) | ||
| 23744 | (org-agenda-list nil (calendar-absolute-from-gregorian | ||
| 23745 | (calendar-cursor-to-date)) | ||
| 23746 | nil)) | ||
| 23747 | |||
| 23748 | (defun org-agenda-convert-date () | ||
| 23749 | (interactive) | ||
| 23750 | (org-agenda-check-type t 'agenda 'timeline) | ||
| 23751 | (let ((day (get-text-property (point) 'day)) | ||
| 23752 | date s) | ||
| 23753 | (unless day | ||
| 23754 | (error "Don't know which date to convert")) | ||
| 23755 | (setq date (calendar-gregorian-from-absolute day)) | ||
| 23756 | (setq s (concat | ||
| 23757 | "Gregorian: " (calendar-date-string date) "\n" | ||
| 23758 | "ISO: " (calendar-iso-date-string date) "\n" | ||
| 23759 | "Day of Yr: " (calendar-day-of-year-string date) "\n" | ||
| 23760 | "Julian: " (calendar-julian-date-string date) "\n" | ||
| 23761 | "Astron. JD: " (calendar-astro-date-string date) | ||
| 23762 | " (Julian date number at noon UTC)\n" | ||
| 23763 | "Hebrew: " (calendar-hebrew-date-string date) " (until sunset)\n" | ||
| 23764 | "Islamic: " (calendar-islamic-date-string date) " (until sunset)\n" | ||
| 23765 | "French: " (calendar-french-date-string date) "\n" | ||
| 23766 | "Baha'i: " (calendar-bahai-date-string date) " (until sunset)\n" | ||
| 23767 | "Mayan: " (calendar-mayan-date-string date) "\n" | ||
| 23768 | "Coptic: " (calendar-coptic-date-string date) "\n" | ||
| 23769 | "Ethiopic: " (calendar-ethiopic-date-string date) "\n" | ||
| 23770 | "Persian: " (calendar-persian-date-string date) "\n" | ||
| 23771 | "Chinese: " (calendar-chinese-date-string date) "\n")) | ||
| 23772 | (with-output-to-temp-buffer "*Dates*" | ||
| 23773 | (princ s)) | ||
| 23774 | (if (fboundp 'fit-window-to-buffer) | ||
| 23775 | (fit-window-to-buffer (get-buffer-window "*Dates*"))))) | ||
| 23776 | |||
| 23777 | |||
| 23778 | ;;;; Embedded LaTeX | ||
| 23779 | |||
| 23780 | (defvar org-cdlatex-mode-map (make-sparse-keymap) | ||
| 23781 | "Keymap for the minor `org-cdlatex-mode'.") | ||
| 23782 | |||
| 23783 | (org-defkey org-cdlatex-mode-map "_" 'org-cdlatex-underscore-caret) | ||
| 23784 | (org-defkey org-cdlatex-mode-map "^" 'org-cdlatex-underscore-caret) | ||
| 23785 | (org-defkey org-cdlatex-mode-map "`" 'cdlatex-math-symbol) | ||
| 23786 | (org-defkey org-cdlatex-mode-map "'" 'org-cdlatex-math-modify) | ||
| 23787 | (org-defkey org-cdlatex-mode-map "\C-c{" 'cdlatex-environment) | ||
| 23788 | |||
| 23789 | (defvar org-cdlatex-texmathp-advice-is-done nil | ||
| 23790 | "Flag remembering if we have applied the advice to texmathp already.") | ||
| 23791 | |||
| 23792 | (define-minor-mode org-cdlatex-mode | ||
| 23793 | "Toggle the minor `org-cdlatex-mode'. | ||
| 23794 | This mode supports entering LaTeX environment and math in LaTeX fragments | ||
| 23795 | in Org-mode. | ||
| 23796 | \\{org-cdlatex-mode-map}" | ||
| 23797 | nil " OCDL" nil | ||
| 23798 | (when org-cdlatex-mode (require 'cdlatex)) | ||
| 23799 | (unless org-cdlatex-texmathp-advice-is-done | ||
| 23800 | (setq org-cdlatex-texmathp-advice-is-done t) | ||
| 23801 | (defadvice texmathp (around org-math-always-on activate) | ||
| 23802 | "Always return t in org-mode buffers. | ||
| 23803 | This is because we want to insert math symbols without dollars even outside | ||
| 23804 | the LaTeX math segments. If Orgmode thinks that point is actually inside | ||
| 23805 | en embedded LaTeX fragement, let texmathp do its job. | ||
| 23806 | \\[org-cdlatex-mode-map]" | ||
| 23807 | (interactive) | ||
| 23808 | (let (p) | ||
| 23809 | (cond | ||
| 23810 | ((not (org-mode-p)) ad-do-it) | ||
| 23811 | ((eq this-command 'cdlatex-math-symbol) | ||
| 23812 | (setq ad-return-value t | ||
| 23813 | texmathp-why '("cdlatex-math-symbol in org-mode" . 0))) | ||
| 23814 | (t | ||
| 23815 | (let ((p (org-inside-LaTeX-fragment-p))) | ||
| 23816 | (if (and p (member (car p) (plist-get org-format-latex-options :matchers))) | ||
| 23817 | (setq ad-return-value t | ||
| 23818 | texmathp-why '("Org-mode embedded math" . 0)) | ||
| 23819 | (if p ad-do-it))))))))) | ||
| 23820 | |||
| 23821 | (defun turn-on-org-cdlatex () | ||
| 23822 | "Unconditionally turn on `org-cdlatex-mode'." | ||
| 23823 | (org-cdlatex-mode 1)) | ||
| 23824 | |||
| 23825 | (defun org-inside-LaTeX-fragment-p () | ||
| 23826 | "Test if point is inside a LaTeX fragment. | ||
| 23827 | I.e. after a \\begin, \\(, \\[, $, or $$, without the corresponding closing | ||
| 23828 | sequence appearing also before point. | ||
| 23829 | Even though the matchers for math are configurable, this function assumes | ||
| 23830 | that \\begin, \\(, \\[, and $$ are always used. Only the single dollar | ||
| 23831 | delimiters are skipped when they have been removed by customization. | ||
| 23832 | The return value is nil, or a cons cell with the delimiter and | ||
| 23833 | and the position of this delimiter. | ||
| 23834 | |||
| 23835 | This function does a reasonably good job, but can locally be fooled by | ||
| 23836 | for example currency specifications. For example it will assume being in | ||
| 23837 | inline math after \"$22.34\". The LaTeX fragment formatter will only format | ||
| 23838 | fragments that are properly closed, but during editing, we have to live | ||
| 23839 | with the uncertainty caused by missing closing delimiters. This function | ||
| 23840 | looks only before point, not after." | ||
| 23841 | (catch 'exit | ||
| 23842 | (let ((pos (point)) | ||
| 23843 | (dodollar (member "$" (plist-get org-format-latex-options :matchers))) | ||
| 23844 | (lim (progn | ||
| 23845 | (re-search-backward (concat "^\\(" paragraph-start "\\)") nil t) | ||
| 23846 | (point))) | ||
| 23847 | dd-on str (start 0) m re) | ||
| 23848 | (goto-char pos) | ||
| 23849 | (when dodollar | ||
| 23850 | (setq str (concat (buffer-substring lim (point)) "\000 X$.") | ||
| 23851 | re (nth 1 (assoc "$" org-latex-regexps))) | ||
| 23852 | (while (string-match re str start) | ||
| 23853 | (cond | ||
| 23854 | ((= (match-end 0) (length str)) | ||
| 23855 | (throw 'exit (cons "$" (+ lim (match-beginning 0) 1)))) | ||
| 23856 | ((= (match-end 0) (- (length str) 5)) | ||
| 23857 | (throw 'exit nil)) | ||
| 23858 | (t (setq start (match-end 0)))))) | ||
| 23859 | (when (setq m (re-search-backward "\\(\\\\begin{[^}]*}\\|\\\\(\\|\\\\\\[\\)\\|\\(\\\\end{[^}]*}\\|\\\\)\\|\\\\\\]\\)\\|\\(\\$\\$\\)" lim t)) | ||
| 23860 | (goto-char pos) | ||
| 23861 | (and (match-beginning 1) (throw 'exit (cons (match-string 1) m))) | ||
| 23862 | (and (match-beginning 2) (throw 'exit nil)) | ||
| 23863 | ;; count $$ | ||
| 23864 | (while (re-search-backward "\\$\\$" lim t) | ||
| 23865 | (setq dd-on (not dd-on))) | ||
| 23866 | (goto-char pos) | ||
| 23867 | (if dd-on (cons "$$" m)))))) | ||
| 23868 | |||
| 23869 | |||
| 23870 | (defun org-try-cdlatex-tab () | ||
| 23871 | "Check if it makes sense to execute `cdlatex-tab', and do it if yes. | ||
| 23872 | It makes sense to do so if `org-cdlatex-mode' is active and if the cursor is | ||
| 23873 | - inside a LaTeX fragment, or | ||
| 23874 | - after the first word in a line, where an abbreviation expansion could | ||
| 23875 | insert a LaTeX environment." | ||
| 23876 | (when org-cdlatex-mode | ||
| 23877 | (cond | ||
| 23878 | ((save-excursion | ||
| 23879 | (skip-chars-backward "a-zA-Z0-9*") | ||
| 23880 | (skip-chars-backward " \t") | ||
| 23881 | (bolp)) | ||
| 23882 | (cdlatex-tab) t) | ||
| 23883 | ((org-inside-LaTeX-fragment-p) | ||
| 23884 | (cdlatex-tab) t) | ||
| 23885 | (t nil)))) | ||
| 23886 | |||
| 23887 | (defun org-cdlatex-underscore-caret (&optional arg) | ||
| 23888 | "Execute `cdlatex-sub-superscript' in LaTeX fragments. | ||
| 23889 | Revert to the normal definition outside of these fragments." | ||
| 23890 | (interactive "P") | ||
| 23891 | (if (org-inside-LaTeX-fragment-p) | ||
| 23892 | (call-interactively 'cdlatex-sub-superscript) | ||
| 23893 | (let (org-cdlatex-mode) | ||
| 23894 | (call-interactively (key-binding (vector last-input-event)))))) | ||
| 23895 | |||
| 23896 | (defun org-cdlatex-math-modify (&optional arg) | ||
| 23897 | "Execute `cdlatex-math-modify' in LaTeX fragments. | ||
| 23898 | Revert to the normal definition outside of these fragments." | ||
| 23899 | (interactive "P") | ||
| 23900 | (if (org-inside-LaTeX-fragment-p) | ||
| 23901 | (call-interactively 'cdlatex-math-modify) | ||
| 23902 | (let (org-cdlatex-mode) | ||
| 23903 | (call-interactively (key-binding (vector last-input-event)))))) | ||
| 23904 | |||
| 23905 | (defvar org-latex-fragment-image-overlays nil | ||
| 23906 | "List of overlays carrying the images of latex fragments.") | ||
| 23907 | (make-variable-buffer-local 'org-latex-fragment-image-overlays) | ||
| 23908 | |||
| 23909 | (defun org-remove-latex-fragment-image-overlays () | ||
| 23910 | "Remove all overlays with LaTeX fragment images in current buffer." | ||
| 23911 | (mapc 'org-delete-overlay org-latex-fragment-image-overlays) | ||
| 23912 | (setq org-latex-fragment-image-overlays nil)) | ||
| 23913 | |||
| 23914 | (defun org-preview-latex-fragment (&optional subtree) | ||
| 23915 | "Preview the LaTeX fragment at point, or all locally or globally. | ||
| 23916 | If the cursor is in a LaTeX fragment, create the image and overlay | ||
| 23917 | it over the source code. If there is no fragment at point, display | ||
| 23918 | all fragments in the current text, from one headline to the next. With | ||
| 23919 | prefix SUBTREE, display all fragments in the current subtree. With a | ||
| 23920 | double prefix `C-u C-u', or when the cursor is before the first headline, | ||
| 23921 | display all fragments in the buffer. | ||
| 23922 | The images can be removed again with \\[org-ctrl-c-ctrl-c]." | ||
| 23923 | (interactive "P") | ||
| 23924 | (org-remove-latex-fragment-image-overlays) | ||
| 23925 | (save-excursion | ||
| 23926 | (save-restriction | ||
| 23927 | (let (beg end at msg) | ||
| 23928 | (cond | ||
| 23929 | ((or (equal subtree '(16)) | ||
| 23930 | (not (save-excursion | ||
| 23931 | (re-search-backward (concat "^" outline-regexp) nil t)))) | ||
| 23932 | (setq beg (point-min) end (point-max) | ||
| 23933 | msg "Creating images for buffer...%s")) | ||
| 23934 | ((equal subtree '(4)) | ||
| 23935 | (org-back-to-heading) | ||
| 23936 | (setq beg (point) end (org-end-of-subtree t) | ||
| 23937 | msg "Creating images for subtree...%s")) | ||
| 23938 | (t | ||
| 23939 | (if (setq at (org-inside-LaTeX-fragment-p)) | ||
| 23940 | (goto-char (max (point-min) (- (cdr at) 2))) | ||
| 23941 | (org-back-to-heading)) | ||
| 23942 | (setq beg (point) end (progn (outline-next-heading) (point)) | ||
| 23943 | msg (if at "Creating image...%s" | ||
| 23944 | "Creating images for entry...%s")))) | ||
| 23945 | (message msg "") | ||
| 23946 | (narrow-to-region beg end) | ||
| 23947 | (goto-char beg) | ||
| 23948 | (org-format-latex | ||
| 23949 | (concat "ltxpng/" (file-name-sans-extension | ||
| 23950 | (file-name-nondirectory | ||
| 23951 | buffer-file-name))) | ||
| 23952 | default-directory 'overlays msg at 'forbuffer) | ||
| 23953 | (message msg "done. Use `C-c C-c' to remove images."))))) | ||
| 23954 | |||
| 23955 | (defvar org-latex-regexps | ||
| 23956 | '(("begin" "^[ \t]*\\(\\\\begin{\\([a-zA-Z0-9\\*]+\\)[^\000]+?\\\\end{\\2}\\)" 1 t) | ||
| 23957 | ;; ("$" "\\([ (]\\|^\\)\\(\\(\\([$]\\)\\([^ \r\n,.$].*?\\(\n.*?\\)\\{0,5\\}[^ \r\n,.$]\\)\\4\\)\\)\\([ .,?;:'\")]\\|$\\)" 2 nil) | ||
| 23958 | ;; \000 in the following regex is needed for org-inside-LaTeX-fragment-p | ||
| 23959 | ("$" "\\([^$]\\)\\(\\(\\$\\([^ \r\n,;.$][^$\n\r]*?\\(\n[^$\n\r]*?\\)\\{0,2\\}[^ \r\n,.$]\\)\\$\\)\\)\\([ .,?;:'\")\000]\\|$\\)" 2 nil) | ||
| 23960 | ("\\(" "\\\\([^\000]*?\\\\)" 0 nil) | ||
| 23961 | ("\\[" "\\\\\\[[^\000]*?\\\\\\]" 0 t) | ||
| 23962 | ("$$" "\\$\\$[^\000]*?\\$\\$" 0 t)) | ||
| 23963 | "Regular expressions for matching embedded LaTeX.") | ||
| 23964 | |||
| 23965 | (defun org-format-latex (prefix &optional dir overlays msg at forbuffer) | ||
| 23966 | "Replace LaTeX fragments with links to an image, and produce images." | ||
| 23967 | (if (and overlays (fboundp 'clear-image-cache)) (clear-image-cache)) | ||
| 23968 | (let* ((prefixnodir (file-name-nondirectory prefix)) | ||
| 23969 | (absprefix (expand-file-name prefix dir)) | ||
| 23970 | (todir (file-name-directory absprefix)) | ||
| 23971 | (opt org-format-latex-options) | ||
| 23972 | (matchers (plist-get opt :matchers)) | ||
| 23973 | (re-list org-latex-regexps) | ||
| 23974 | (cnt 0) txt link beg end re e checkdir | ||
| 23975 | m n block linkfile movefile ov) | ||
| 23976 | ;; Check if there are old images files with this prefix, and remove them | ||
| 23977 | (when (file-directory-p todir) | ||
| 23978 | (mapc 'delete-file | ||
| 23979 | (directory-files | ||
| 23980 | todir 'full | ||
| 23981 | (concat (regexp-quote prefixnodir) "_[0-9]+\\.png$")))) | ||
| 23982 | ;; Check the different regular expressions | ||
| 23983 | (while (setq e (pop re-list)) | ||
| 23984 | (setq m (car e) re (nth 1 e) n (nth 2 e) | ||
| 23985 | block (if (nth 3 e) "\n\n" "")) | ||
| 23986 | (when (member m matchers) | ||
| 23987 | (goto-char (point-min)) | ||
| 23988 | (while (re-search-forward re nil t) | ||
| 23989 | (when (or (not at) (equal (cdr at) (match-beginning n))) | ||
| 23990 | (setq txt (match-string n) | ||
| 23991 | beg (match-beginning n) end (match-end n) | ||
| 23992 | cnt (1+ cnt) | ||
| 23993 | linkfile (format "%s_%04d.png" prefix cnt) | ||
| 23994 | movefile (format "%s_%04d.png" absprefix cnt) | ||
| 23995 | link (concat block "[[file:" linkfile "]]" block)) | ||
| 23996 | (if msg (message msg cnt)) | ||
| 23997 | (goto-char beg) | ||
| 23998 | (unless checkdir ; make sure the directory exists | ||
| 23999 | (setq checkdir t) | ||
| 24000 | (or (file-directory-p todir) (make-directory todir))) | ||
| 24001 | (org-create-formula-image | ||
| 24002 | txt movefile opt forbuffer) | ||
| 24003 | (if overlays | ||
| 24004 | (progn | ||
| 24005 | (setq ov (org-make-overlay beg end)) | ||
| 24006 | (if (featurep 'xemacs) | ||
| 24007 | (progn | ||
| 24008 | (org-overlay-put ov 'invisible t) | ||
| 24009 | (org-overlay-put | ||
| 24010 | ov 'end-glyph | ||
| 24011 | (make-glyph (vector 'png :file movefile)))) | ||
| 24012 | (org-overlay-put | ||
| 24013 | ov 'display | ||
| 24014 | (list 'image :type 'png :file movefile :ascent 'center))) | ||
| 24015 | (push ov org-latex-fragment-image-overlays) | ||
| 24016 | (goto-char end)) | ||
| 24017 | (delete-region beg end) | ||
| 24018 | (insert link)))))))) | ||
| 24019 | |||
| 24020 | ;; This function borrows from Ganesh Swami's latex2png.el | ||
| 24021 | (defun org-create-formula-image (string tofile options buffer) | ||
| 24022 | (let* ((tmpdir (if (featurep 'xemacs) | ||
| 24023 | (temp-directory) | ||
| 24024 | temporary-file-directory)) | ||
| 24025 | (texfilebase (make-temp-name | ||
| 24026 | (expand-file-name "orgtex" tmpdir))) | ||
| 24027 | (texfile (concat texfilebase ".tex")) | ||
| 24028 | (dvifile (concat texfilebase ".dvi")) | ||
| 24029 | (pngfile (concat texfilebase ".png")) | ||
| 24030 | (fnh (face-attribute 'default :height nil)) | ||
| 24031 | (scale (or (plist-get options (if buffer :scale :html-scale)) 1.0)) | ||
| 24032 | (dpi (number-to-string (* scale (floor (* 0.9 (if buffer fnh 140.)))))) | ||
| 24033 | (fg (or (plist-get options (if buffer :foreground :html-foreground)) | ||
| 24034 | "Black")) | ||
| 24035 | (bg (or (plist-get options (if buffer :background :html-background)) | ||
| 24036 | "Transparent"))) | ||
| 24037 | (if (eq fg 'default) (setq fg (org-dvipng-color :foreground))) | ||
| 24038 | (if (eq bg 'default) (setq bg (org-dvipng-color :background))) | ||
| 24039 | (with-temp-file texfile | ||
| 24040 | (insert org-format-latex-header | ||
| 24041 | "\n\\begin{document}\n" string "\n\\end{document}\n")) | ||
| 24042 | (let ((dir default-directory)) | ||
| 24043 | (condition-case nil | ||
| 24044 | (progn | ||
| 24045 | (cd tmpdir) | ||
| 24046 | (call-process "latex" nil nil nil texfile)) | ||
| 24047 | (error nil)) | ||
| 24048 | (cd dir)) | ||
| 24049 | (if (not (file-exists-p dvifile)) | ||
| 24050 | (progn (message "Failed to create dvi file from %s" texfile) nil) | ||
| 24051 | (call-process "dvipng" nil nil nil | ||
| 24052 | "-E" "-fg" fg "-bg" bg | ||
| 24053 | "-D" dpi | ||
| 24054 | ;;"-x" scale "-y" scale | ||
| 24055 | "-T" "tight" | ||
| 24056 | "-o" pngfile | ||
| 24057 | dvifile) | ||
| 24058 | (if (not (file-exists-p pngfile)) | ||
| 24059 | (progn (message "Failed to create png file from %s" texfile) nil) | ||
| 24060 | ;; Use the requested file name and clean up | ||
| 24061 | (copy-file pngfile tofile 'replace) | ||
| 24062 | (loop for e in '(".dvi" ".tex" ".aux" ".log" ".png") do | ||
| 24063 | (delete-file (concat texfilebase e))) | ||
| 24064 | pngfile)))) | ||
| 24065 | |||
| 24066 | (defun org-dvipng-color (attr) | ||
| 24067 | "Return an rgb color specification for dvipng." | ||
| 24068 | (apply 'format "rgb %s %s %s" | ||
| 24069 | (mapcar 'org-normalize-color | ||
| 24070 | (color-values (face-attribute 'default attr nil))))) | ||
| 24071 | |||
| 24072 | (defun org-normalize-color (value) | ||
| 24073 | "Return string to be used as color value for an RGB component." | ||
| 24074 | (format "%g" (/ value 65535.0))) | ||
| 24075 | |||
| 24076 | ;;;; Exporting | ||
| 24077 | |||
| 24078 | ;;; Variables, constants, and parameter plists | ||
| 24079 | |||
| 24080 | (defconst org-level-max 20) | ||
| 24081 | |||
| 24082 | (defvar org-export-html-preamble nil | ||
| 24083 | "Preamble, to be inserted just after <body>. Set by publishing functions.") | ||
| 24084 | (defvar org-export-html-postamble nil | ||
| 24085 | "Preamble, to be inserted just before </body>. Set by publishing functions.") | ||
| 24086 | (defvar org-export-html-auto-preamble t | ||
| 24087 | "Should default preamble be inserted? Set by publishing functions.") | ||
| 24088 | (defvar org-export-html-auto-postamble t | ||
| 24089 | "Should default postamble be inserted? Set by publishing functions.") | ||
| 24090 | (defvar org-current-export-file nil) ; dynamically scoped parameter | ||
| 24091 | (defvar org-current-export-dir nil) ; dynamically scoped parameter | ||
| 24092 | |||
| 24093 | |||
| 24094 | (defconst org-export-plist-vars | ||
| 24095 | '((:language . org-export-default-language) | ||
| 24096 | (:customtime . org-display-custom-times) | ||
| 24097 | (:headline-levels . org-export-headline-levels) | ||
| 24098 | (:section-numbers . org-export-with-section-numbers) | ||
| 24099 | (:table-of-contents . org-export-with-toc) | ||
| 24100 | (:preserve-breaks . org-export-preserve-breaks) | ||
| 24101 | (:archived-trees . org-export-with-archived-trees) | ||
| 24102 | (:emphasize . org-export-with-emphasize) | ||
| 24103 | (:sub-superscript . org-export-with-sub-superscripts) | ||
| 24104 | (:special-strings . org-export-with-special-strings) | ||
| 24105 | (:footnotes . org-export-with-footnotes) | ||
| 24106 | (:drawers . org-export-with-drawers) | ||
| 24107 | (:tags . org-export-with-tags) | ||
| 24108 | (:TeX-macros . org-export-with-TeX-macros) | ||
| 24109 | (:LaTeX-fragments . org-export-with-LaTeX-fragments) | ||
| 24110 | (:skip-before-1st-heading . org-export-skip-text-before-1st-heading) | ||
| 24111 | (:fixed-width . org-export-with-fixed-width) | ||
| 24112 | (:timestamps . org-export-with-timestamps) | ||
| 24113 | (:author-info . org-export-author-info) | ||
| 24114 | (:time-stamp-file . org-export-time-stamp-file) | ||
| 24115 | (:tables . org-export-with-tables) | ||
| 24116 | (:table-auto-headline . org-export-highlight-first-table-line) | ||
| 24117 | (:style . org-export-html-style) | ||
| 24118 | (:agenda-style . org-agenda-export-html-style) | ||
| 24119 | (:convert-org-links . org-export-html-link-org-files-as-html) | ||
| 24120 | (:inline-images . org-export-html-inline-images) | ||
| 24121 | (:html-extension . org-export-html-extension) | ||
| 24122 | (:html-table-tag . org-export-html-table-tag) | ||
| 24123 | (:expand-quoted-html . org-export-html-expand) | ||
| 24124 | (:timestamp . org-export-html-with-timestamp) | ||
| 24125 | (:publishing-directory . org-export-publishing-directory) | ||
| 24126 | (:preamble . org-export-html-preamble) | ||
| 24127 | (:postamble . org-export-html-postamble) | ||
| 24128 | (:auto-preamble . org-export-html-auto-preamble) | ||
| 24129 | (:auto-postamble . org-export-html-auto-postamble) | ||
| 24130 | (:author . user-full-name) | ||
| 24131 | (:email . user-mail-address))) | ||
| 24132 | |||
| 24133 | (defun org-default-export-plist () | ||
| 24134 | "Return the property list with default settings for the export variables." | ||
| 24135 | (let ((l org-export-plist-vars) rtn e) | ||
| 24136 | (while (setq e (pop l)) | ||
| 24137 | (setq rtn (cons (car e) (cons (symbol-value (cdr e)) rtn)))) | ||
| 24138 | rtn)) | ||
| 24139 | |||
| 24140 | (defun org-infile-export-plist () | ||
| 24141 | "Return the property list with file-local settings for export." | ||
| 24142 | (save-excursion | ||
| 24143 | (save-restriction | ||
| 24144 | (widen) | ||
| 24145 | (goto-char 0) | ||
| 24146 | (let ((re (org-make-options-regexp | ||
| 24147 | '("TITLE" "AUTHOR" "DATE" "EMAIL" "TEXT" "OPTIONS" "LANGUAGE"))) | ||
| 24148 | p key val text options) | ||
| 24149 | (while (re-search-forward re nil t) | ||
| 24150 | (setq key (org-match-string-no-properties 1) | ||
| 24151 | val (org-match-string-no-properties 2)) | ||
| 24152 | (cond | ||
| 24153 | ((string-equal key "TITLE") (setq p (plist-put p :title val))) | ||
| 24154 | ((string-equal key "AUTHOR")(setq p (plist-put p :author val))) | ||
| 24155 | ((string-equal key "EMAIL") (setq p (plist-put p :email val))) | ||
| 24156 | ((string-equal key "DATE") (setq p (plist-put p :date val))) | ||
| 24157 | ((string-equal key "LANGUAGE") (setq p (plist-put p :language val))) | ||
| 24158 | ((string-equal key "TEXT") | ||
| 24159 | (setq text (if text (concat text "\n" val) val))) | ||
| 24160 | ((string-equal key "OPTIONS") (setq options val)))) | ||
| 24161 | (setq p (plist-put p :text text)) | ||
| 24162 | (when options | ||
| 24163 | (let ((op '(("H" . :headline-levels) | ||
| 24164 | ("num" . :section-numbers) | ||
| 24165 | ("toc" . :table-of-contents) | ||
| 24166 | ("\\n" . :preserve-breaks) | ||
| 24167 | ("@" . :expand-quoted-html) | ||
| 24168 | (":" . :fixed-width) | ||
| 24169 | ("|" . :tables) | ||
| 24170 | ("^" . :sub-superscript) | ||
| 24171 | ("-" . :special-strings) | ||
| 24172 | ("f" . :footnotes) | ||
| 24173 | ("d" . :drawers) | ||
| 24174 | ("tags" . :tags) | ||
| 24175 | ("*" . :emphasize) | ||
| 24176 | ("TeX" . :TeX-macros) | ||
| 24177 | ("LaTeX" . :LaTeX-fragments) | ||
| 24178 | ("skip" . :skip-before-1st-heading) | ||
| 24179 | ("author" . :author-info) | ||
| 24180 | ("timestamp" . :time-stamp-file))) | ||
| 24181 | o) | ||
| 24182 | (while (setq o (pop op)) | ||
| 24183 | (if (string-match (concat (regexp-quote (car o)) | ||
| 24184 | ":\\([^ \t\n\r;,.]*\\)") | ||
| 24185 | options) | ||
| 24186 | (setq p (plist-put p (cdr o) | ||
| 24187 | (car (read-from-string | ||
| 24188 | (match-string 1 options))))))))) | ||
| 24189 | p)))) | ||
| 24190 | |||
| 24191 | (defun org-export-directory (type plist) | ||
| 24192 | (let* ((val (plist-get plist :publishing-directory)) | ||
| 24193 | (dir (if (listp val) | ||
| 24194 | (or (cdr (assoc type val)) ".") | ||
| 24195 | val))) | ||
| 24196 | dir)) | ||
| 24197 | |||
| 24198 | (defun org-skip-comments (lines) | ||
| 24199 | "Skip lines starting with \"#\" and subtrees starting with COMMENT." | ||
| 24200 | (let ((re1 (concat "^\\(\\*+\\)[ \t]+" org-comment-string)) | ||
| 24201 | (re2 "^\\(\\*+\\)[ \t\n\r]") | ||
| 24202 | (case-fold-search nil) | ||
| 24203 | rtn line level) | ||
| 24204 | (while (setq line (pop lines)) | ||
| 24205 | (cond | ||
| 24206 | ((and (string-match re1 line) | ||
| 24207 | (setq level (- (match-end 1) (match-beginning 1)))) | ||
| 24208 | ;; Beginning of a COMMENT subtree. Skip it. | ||
| 24209 | (while (and (setq line (pop lines)) | ||
| 24210 | (or (not (string-match re2 line)) | ||
| 24211 | (> (- (match-end 1) (match-beginning 1)) level)))) | ||
| 24212 | (setq lines (cons line lines))) | ||
| 24213 | ((string-match "^#" line) | ||
| 24214 | ;; an ordinary comment line | ||
| 24215 | ) | ||
| 24216 | ((and org-export-table-remove-special-lines | ||
| 24217 | (string-match "^[ \t]*|" line) | ||
| 24218 | (or (string-match "^[ \t]*| *[!_^] *|" line) | ||
| 24219 | (and (string-match "| *<[0-9]+> *|" line) | ||
| 24220 | (not (string-match "| *[^ <|]" line))))) | ||
| 24221 | ;; a special table line that should be removed | ||
| 24222 | ) | ||
| 24223 | (t (setq rtn (cons line rtn))))) | ||
| 24224 | (nreverse rtn))) | ||
| 24225 | |||
| 24226 | (defun org-export (&optional arg) | ||
| 24227 | (interactive) | ||
| 24228 | (let ((help "[t] insert the export option template | ||
| 24229 | \[v] limit export to visible part of outline tree | ||
| 24230 | |||
| 24231 | \[a] export as ASCII | ||
| 24232 | |||
| 24233 | \[h] export as HTML | ||
| 24234 | \[H] export as HTML to temporary buffer | ||
| 24235 | \[R] export region as HTML | ||
| 24236 | \[b] export as HTML and browse immediately | ||
| 24237 | \[x] export as XOXO | ||
| 24238 | |||
| 24239 | \[l] export as LaTeX | ||
| 24240 | \[L] export as LaTeX to temporary buffer | ||
| 24241 | |||
| 24242 | \[i] export current file as iCalendar file | ||
| 24243 | \[I] export all agenda files as iCalendar files | ||
| 24244 | \[c] export agenda files into combined iCalendar file | ||
| 24245 | |||
| 24246 | \[F] publish current file | ||
| 24247 | \[P] publish current project | ||
| 24248 | \[X] publish... (project will be prompted for) | ||
| 24249 | \[A] publish all projects") | ||
| 24250 | (cmds | ||
| 24251 | '((?t . org-insert-export-options-template) | ||
| 24252 | (?v . org-export-visible) | ||
| 24253 | (?a . org-export-as-ascii) | ||
| 24254 | (?h . org-export-as-html) | ||
| 24255 | (?b . org-export-as-html-and-open) | ||
| 24256 | (?H . org-export-as-html-to-buffer) | ||
| 24257 | (?R . org-export-region-as-html) | ||
| 24258 | (?x . org-export-as-xoxo) | ||
| 24259 | (?l . org-export-as-latex) | ||
| 24260 | (?L . org-export-as-latex-to-buffer) | ||
| 24261 | (?i . org-export-icalendar-this-file) | ||
| 24262 | (?I . org-export-icalendar-all-agenda-files) | ||
| 24263 | (?c . org-export-icalendar-combine-agenda-files) | ||
| 24264 | (?F . org-publish-current-file) | ||
| 24265 | (?P . org-publish-current-project) | ||
| 24266 | (?X . org-publish) | ||
| 24267 | (?A . org-publish-all))) | ||
| 24268 | r1 r2 ass) | ||
| 24269 | (save-window-excursion | ||
| 24270 | (delete-other-windows) | ||
| 24271 | (with-output-to-temp-buffer "*Org Export/Publishing Help*" | ||
| 24272 | (princ help)) | ||
| 24273 | (message "Select command: ") | ||
| 24274 | (setq r1 (read-char-exclusive))) | ||
| 24275 | (setq r2 (if (< r1 27) (+ r1 96) r1)) | ||
| 24276 | (if (setq ass (assq r2 cmds)) | ||
| 24277 | (call-interactively (cdr ass)) | ||
| 24278 | (error "No command associated with key %c" r1)))) | ||
| 24279 | |||
| 24280 | (defconst org-html-entities | ||
| 24281 | '(("nbsp") | ||
| 24282 | ("iexcl") | ||
| 24283 | ("cent") | ||
| 24284 | ("pound") | ||
| 24285 | ("curren") | ||
| 24286 | ("yen") | ||
| 24287 | ("brvbar") | ||
| 24288 | ("vert" . "|") | ||
| 24289 | ("sect") | ||
| 24290 | ("uml") | ||
| 24291 | ("copy") | ||
| 24292 | ("ordf") | ||
| 24293 | ("laquo") | ||
| 24294 | ("not") | ||
| 24295 | ("shy") | ||
| 24296 | ("reg") | ||
| 24297 | ("macr") | ||
| 24298 | ("deg") | ||
| 24299 | ("plusmn") | ||
| 24300 | ("sup2") | ||
| 24301 | ("sup3") | ||
| 24302 | ("acute") | ||
| 24303 | ("micro") | ||
| 24304 | ("para") | ||
| 24305 | ("middot") | ||
| 24306 | ("odot"."o") | ||
| 24307 | ("star"."*") | ||
| 24308 | ("cedil") | ||
| 24309 | ("sup1") | ||
| 24310 | ("ordm") | ||
| 24311 | ("raquo") | ||
| 24312 | ("frac14") | ||
| 24313 | ("frac12") | ||
| 24314 | ("frac34") | ||
| 24315 | ("iquest") | ||
| 24316 | ("Agrave") | ||
| 24317 | ("Aacute") | ||
| 24318 | ("Acirc") | ||
| 24319 | ("Atilde") | ||
| 24320 | ("Auml") | ||
| 24321 | ("Aring") ("AA"."Å") | ||
| 24322 | ("AElig") | ||
| 24323 | ("Ccedil") | ||
| 24324 | ("Egrave") | ||
| 24325 | ("Eacute") | ||
| 24326 | ("Ecirc") | ||
| 24327 | ("Euml") | ||
| 24328 | ("Igrave") | ||
| 24329 | ("Iacute") | ||
| 24330 | ("Icirc") | ||
| 24331 | ("Iuml") | ||
| 24332 | ("ETH") | ||
| 24333 | ("Ntilde") | ||
| 24334 | ("Ograve") | ||
| 24335 | ("Oacute") | ||
| 24336 | ("Ocirc") | ||
| 24337 | ("Otilde") | ||
| 24338 | ("Ouml") | ||
| 24339 | ("times") | ||
| 24340 | ("Oslash") | ||
| 24341 | ("Ugrave") | ||
| 24342 | ("Uacute") | ||
| 24343 | ("Ucirc") | ||
| 24344 | ("Uuml") | ||
| 24345 | ("Yacute") | ||
| 24346 | ("THORN") | ||
| 24347 | ("szlig") | ||
| 24348 | ("agrave") | ||
| 24349 | ("aacute") | ||
| 24350 | ("acirc") | ||
| 24351 | ("atilde") | ||
| 24352 | ("auml") | ||
| 24353 | ("aring") | ||
| 24354 | ("aelig") | ||
| 24355 | ("ccedil") | ||
| 24356 | ("egrave") | ||
| 24357 | ("eacute") | ||
| 24358 | ("ecirc") | ||
| 24359 | ("euml") | ||
| 24360 | ("igrave") | ||
| 24361 | ("iacute") | ||
| 24362 | ("icirc") | ||
| 24363 | ("iuml") | ||
| 24364 | ("eth") | ||
| 24365 | ("ntilde") | ||
| 24366 | ("ograve") | ||
| 24367 | ("oacute") | ||
| 24368 | ("ocirc") | ||
| 24369 | ("otilde") | ||
| 24370 | ("ouml") | ||
| 24371 | ("divide") | ||
| 24372 | ("oslash") | ||
| 24373 | ("ugrave") | ||
| 24374 | ("uacute") | ||
| 24375 | ("ucirc") | ||
| 24376 | ("uuml") | ||
| 24377 | ("yacute") | ||
| 24378 | ("thorn") | ||
| 24379 | ("yuml") | ||
| 24380 | ("fnof") | ||
| 24381 | ("Alpha") | ||
| 24382 | ("Beta") | ||
| 24383 | ("Gamma") | ||
| 24384 | ("Delta") | ||
| 24385 | ("Epsilon") | ||
| 24386 | ("Zeta") | ||
| 24387 | ("Eta") | ||
| 24388 | ("Theta") | ||
| 24389 | ("Iota") | ||
| 24390 | ("Kappa") | ||
| 24391 | ("Lambda") | ||
| 24392 | ("Mu") | ||
| 24393 | ("Nu") | ||
| 24394 | ("Xi") | ||
| 24395 | ("Omicron") | ||
| 24396 | ("Pi") | ||
| 24397 | ("Rho") | ||
| 24398 | ("Sigma") | ||
| 24399 | ("Tau") | ||
| 24400 | ("Upsilon") | ||
| 24401 | ("Phi") | ||
| 24402 | ("Chi") | ||
| 24403 | ("Psi") | ||
| 24404 | ("Omega") | ||
| 24405 | ("alpha") | ||
| 24406 | ("beta") | ||
| 24407 | ("gamma") | ||
| 24408 | ("delta") | ||
| 24409 | ("epsilon") | ||
| 24410 | ("varepsilon"."ε") | ||
| 24411 | ("zeta") | ||
| 24412 | ("eta") | ||
| 24413 | ("theta") | ||
| 24414 | ("iota") | ||
| 24415 | ("kappa") | ||
| 24416 | ("lambda") | ||
| 24417 | ("mu") | ||
| 24418 | ("nu") | ||
| 24419 | ("xi") | ||
| 24420 | ("omicron") | ||
| 24421 | ("pi") | ||
| 24422 | ("rho") | ||
| 24423 | ("sigmaf") ("varsigma"."ς") | ||
| 24424 | ("sigma") | ||
| 24425 | ("tau") | ||
| 24426 | ("upsilon") | ||
| 24427 | ("phi") | ||
| 24428 | ("chi") | ||
| 24429 | ("psi") | ||
| 24430 | ("omega") | ||
| 24431 | ("thetasym") ("vartheta"."ϑ") | ||
| 24432 | ("upsih") | ||
| 24433 | ("piv") | ||
| 24434 | ("bull") ("bullet"."•") | ||
| 24435 | ("hellip") ("dots"."…") | ||
| 24436 | ("prime") | ||
| 24437 | ("Prime") | ||
| 24438 | ("oline") | ||
| 24439 | ("frasl") | ||
| 24440 | ("weierp") | ||
| 24441 | ("image") | ||
| 24442 | ("real") | ||
| 24443 | ("trade") | ||
| 24444 | ("alefsym") | ||
| 24445 | ("larr") ("leftarrow"."←") ("gets"."←") | ||
| 24446 | ("uarr") ("uparrow"."↑") | ||
| 24447 | ("rarr") ("to"."→") ("rightarrow"."→") | ||
| 24448 | ("darr")("downarrow"."↓") | ||
| 24449 | ("harr") ("leftrightarrow"."↔") | ||
| 24450 | ("crarr") ("hookleftarrow"."↵") ; has round hook, not quite CR | ||
| 24451 | ("lArr") ("Leftarrow"."⇐") | ||
| 24452 | ("uArr") ("Uparrow"."⇑") | ||
| 24453 | ("rArr") ("Rightarrow"."⇒") | ||
| 24454 | ("dArr") ("Downarrow"."⇓") | ||
| 24455 | ("hArr") ("Leftrightarrow"."⇔") | ||
| 24456 | ("forall") | ||
| 24457 | ("part") ("partial"."∂") | ||
| 24458 | ("exist") ("exists"."∃") | ||
| 24459 | ("empty") ("emptyset"."∅") | ||
| 24460 | ("nabla") | ||
| 24461 | ("isin") ("in"."∈") | ||
| 24462 | ("notin") | ||
| 24463 | ("ni") | ||
| 24464 | ("prod") | ||
| 24465 | ("sum") | ||
| 24466 | ("minus") | ||
| 24467 | ("lowast") ("ast"."∗") | ||
| 24468 | ("radic") | ||
| 24469 | ("prop") ("proptp"."∝") | ||
| 24470 | ("infin") ("infty"."∞") | ||
| 24471 | ("ang") ("angle"."∠") | ||
| 24472 | ("and") ("wedge"."∧") | ||
| 24473 | ("or") ("vee"."∨") | ||
| 24474 | ("cap") | ||
| 24475 | ("cup") | ||
| 24476 | ("int") | ||
| 24477 | ("there4") | ||
| 24478 | ("sim") | ||
| 24479 | ("cong") ("simeq"."≅") | ||
| 24480 | ("asymp")("approx"."≈") | ||
| 24481 | ("ne") ("neq"."≠") | ||
| 24482 | ("equiv") | ||
| 24483 | ("le") | ||
| 24484 | ("ge") | ||
| 24485 | ("sub") ("subset"."⊂") | ||
| 24486 | ("sup") ("supset"."⊃") | ||
| 24487 | ("nsub") | ||
| 24488 | ("sube") | ||
| 24489 | ("supe") | ||
| 24490 | ("oplus") | ||
| 24491 | ("otimes") | ||
| 24492 | ("perp") | ||
| 24493 | ("sdot") ("cdot"."⋅") | ||
| 24494 | ("lceil") | ||
| 24495 | ("rceil") | ||
| 24496 | ("lfloor") | ||
| 24497 | ("rfloor") | ||
| 24498 | ("lang") | ||
| 24499 | ("rang") | ||
| 24500 | ("loz") ("Diamond"."◊") | ||
| 24501 | ("spades") ("spadesuit"."♠") | ||
| 24502 | ("clubs") ("clubsuit"."♣") | ||
| 24503 | ("hearts") ("diamondsuit"."♥") | ||
| 24504 | ("diams") ("diamondsuit"."♦") | ||
| 24505 | ("smile"."☺") ("blacksmile"."☻") ("sad"."☹") | ||
| 24506 | ("quot") | ||
| 24507 | ("amp") | ||
| 24508 | ("lt") | ||
| 24509 | ("gt") | ||
| 24510 | ("OElig") | ||
| 24511 | ("oelig") | ||
| 24512 | ("Scaron") | ||
| 24513 | ("scaron") | ||
| 24514 | ("Yuml") | ||
| 24515 | ("circ") | ||
| 24516 | ("tilde") | ||
| 24517 | ("ensp") | ||
| 24518 | ("emsp") | ||
| 24519 | ("thinsp") | ||
| 24520 | ("zwnj") | ||
| 24521 | ("zwj") | ||
| 24522 | ("lrm") | ||
| 24523 | ("rlm") | ||
| 24524 | ("ndash") | ||
| 24525 | ("mdash") | ||
| 24526 | ("lsquo") | ||
| 24527 | ("rsquo") | ||
| 24528 | ("sbquo") | ||
| 24529 | ("ldquo") | ||
| 24530 | ("rdquo") | ||
| 24531 | ("bdquo") | ||
| 24532 | ("dagger") | ||
| 24533 | ("Dagger") | ||
| 24534 | ("permil") | ||
| 24535 | ("lsaquo") | ||
| 24536 | ("rsaquo") | ||
| 24537 | ("euro") | ||
| 24538 | |||
| 24539 | ("arccos"."arccos") | ||
| 24540 | ("arcsin"."arcsin") | ||
| 24541 | ("arctan"."arctan") | ||
| 24542 | ("arg"."arg") | ||
| 24543 | ("cos"."cos") | ||
| 24544 | ("cosh"."cosh") | ||
| 24545 | ("cot"."cot") | ||
| 24546 | ("coth"."coth") | ||
| 24547 | ("csc"."csc") | ||
| 24548 | ("deg"."deg") | ||
| 24549 | ("det"."det") | ||
| 24550 | ("dim"."dim") | ||
| 24551 | ("exp"."exp") | ||
| 24552 | ("gcd"."gcd") | ||
| 24553 | ("hom"."hom") | ||
| 24554 | ("inf"."inf") | ||
| 24555 | ("ker"."ker") | ||
| 24556 | ("lg"."lg") | ||
| 24557 | ("lim"."lim") | ||
| 24558 | ("liminf"."liminf") | ||
| 24559 | ("limsup"."limsup") | ||
| 24560 | ("ln"."ln") | ||
| 24561 | ("log"."log") | ||
| 24562 | ("max"."max") | ||
| 24563 | ("min"."min") | ||
| 24564 | ("Pr"."Pr") | ||
| 24565 | ("sec"."sec") | ||
| 24566 | ("sin"."sin") | ||
| 24567 | ("sinh"."sinh") | ||
| 24568 | ("sup"."sup") | ||
| 24569 | ("tan"."tan") | ||
| 24570 | ("tanh"."tanh") | ||
| 24571 | ) | ||
| 24572 | "Entities for TeX->HTML translation. | ||
| 24573 | Entries can be like (\"ent\"), in which case \"\\ent\" will be translated to | ||
| 24574 | \"&ent;\". An entry can also be a dotted pair like (\"ent\".\"&other;\"). | ||
| 24575 | In that case, \"\\ent\" will be translated to \"&other;\". | ||
| 24576 | The list contains HTML entities for Latin-1, Greek and other symbols. | ||
| 24577 | It is supplemented by a number of commonly used TeX macros with appropriate | ||
| 24578 | translations. There is currently no way for users to extend this.") | ||
| 24579 | |||
| 24580 | ;;; General functions for all backends | ||
| 24581 | |||
| 24582 | (defun org-cleaned-string-for-export (string &rest parameters) | ||
| 24583 | "Cleanup a buffer STRING so that links can be created safely." | ||
| 24584 | (interactive) | ||
| 24585 | (let* ((re-radio (and org-target-link-regexp | ||
| 24586 | (concat "\\([^<]\\)\\(" org-target-link-regexp "\\)"))) | ||
| 24587 | (re-plain-link (concat "\\([^[<]\\)" org-plain-link-re)) | ||
| 24588 | (re-angle-link (concat "\\([^[]\\)" org-angle-link-re)) | ||
| 24589 | (re-archive (concat ":" org-archive-tag ":")) | ||
| 24590 | (re-quote (concat "^\\*+[ \t]+" org-quote-string "\\>")) | ||
| 24591 | (re-commented (concat "^\\*+[ \t]+" org-comment-string "\\>")) | ||
| 24592 | (htmlp (plist-get parameters :for-html)) | ||
| 24593 | (asciip (plist-get parameters :for-ascii)) | ||
| 24594 | (latexp (plist-get parameters :for-LaTeX)) | ||
| 24595 | (commentsp (plist-get parameters :comments)) | ||
| 24596 | (archived-trees (plist-get parameters :archived-trees)) | ||
| 24597 | (inhibit-read-only t) | ||
| 24598 | (drawers org-drawers) | ||
| 24599 | (exp-drawers (plist-get parameters :drawers)) | ||
| 24600 | (outline-regexp "\\*+ ") | ||
| 24601 | a b xx | ||
| 24602 | rtn p) | ||
| 24603 | (with-current-buffer (get-buffer-create " org-mode-tmp") | ||
| 24604 | (erase-buffer) | ||
| 24605 | (insert string) | ||
| 24606 | ;; Remove license-to-kill stuff | ||
| 24607 | (while (setq p (text-property-any (point-min) (point-max) | ||
| 24608 | :org-license-to-kill t)) | ||
| 24609 | (delete-region p (next-single-property-change p :org-license-to-kill))) | ||
| 24610 | |||
| 24611 | (let ((org-inhibit-startup t)) (org-mode)) | ||
| 24612 | (untabify (point-min) (point-max)) | ||
| 24613 | |||
| 24614 | ;; Get rid of drawers | ||
| 24615 | (unless (eq t exp-drawers) | ||
| 24616 | (goto-char (point-min)) | ||
| 24617 | (let ((re (concat "^[ \t]*:\\(" | ||
| 24618 | (mapconcat | ||
| 24619 | 'identity | ||
| 24620 | (org-delete-all exp-drawers | ||
| 24621 | (copy-sequence drawers)) | ||
| 24622 | "\\|") | ||
| 24623 | "\\):[ \t]*\n\\([^@]*?\n\\)?[ \t]*:END:[ \t]*\n"))) | ||
| 24624 | (while (re-search-forward re nil t) | ||
| 24625 | (replace-match "")))) | ||
| 24626 | |||
| 24627 | ;; Get the correct stuff before the first headline | ||
| 24628 | (when (plist-get parameters :skip-before-1st-heading) | ||
| 24629 | (goto-char (point-min)) | ||
| 24630 | (when (re-search-forward "^\\*+[ \t]" nil t) | ||
| 24631 | (delete-region (point-min) (match-beginning 0)) | ||
| 24632 | (goto-char (point-min)) | ||
| 24633 | (insert "\n"))) | ||
| 24634 | (when (plist-get parameters :add-text) | ||
| 24635 | (goto-char (point-min)) | ||
| 24636 | (insert (plist-get parameters :add-text) "\n")) | ||
| 24637 | |||
| 24638 | ;; Get rid of archived trees | ||
| 24639 | (when (not (eq archived-trees t)) | ||
| 24640 | (goto-char (point-min)) | ||
| 24641 | (while (re-search-forward re-archive nil t) | ||
| 24642 | (if (not (org-on-heading-p t)) | ||
| 24643 | (org-end-of-subtree t) | ||
| 24644 | (beginning-of-line 1) | ||
| 24645 | (setq a (if archived-trees | ||
| 24646 | (1+ (point-at-eol)) (point)) | ||
| 24647 | b (org-end-of-subtree t)) | ||
| 24648 | (if (> b a) (delete-region a b))))) | ||
| 24649 | |||
| 24650 | ;; Find targets in comments and move them out of comments, | ||
| 24651 | ;; but mark them as targets that should be invisible | ||
| 24652 | (goto-char (point-min)) | ||
| 24653 | (while (re-search-forward "^#.*?\\(<<<?[^>\r\n]+>>>?\\).*" nil t) | ||
| 24654 | (replace-match "\\1(INVISIBLE)")) | ||
| 24655 | |||
| 24656 | ;; Protect backend specific stuff, throw away the others. | ||
| 24657 | (let ((formatters | ||
| 24658 | `((,htmlp "HTML" "BEGIN_HTML" "END_HTML") | ||
| 24659 | (,asciip "ASCII" "BEGIN_ASCII" "END_ASCII") | ||
| 24660 | (,latexp "LaTeX" "BEGIN_LaTeX" "END_LaTeX"))) | ||
| 24661 | fmt) | ||
| 24662 | (goto-char (point-min)) | ||
| 24663 | (while (re-search-forward "^#\\+BEGIN_EXAMPLE[ \t]*\n" nil t) | ||
| 24664 | (goto-char (match-end 0)) | ||
| 24665 | (while (not (looking-at "#\\+END_EXAMPLE")) | ||
| 24666 | (insert ": ") | ||
| 24667 | (beginning-of-line 2))) | ||
| 24668 | (goto-char (point-min)) | ||
| 24669 | (while (re-search-forward "^[ \t]*:.*\\(\n[ \t]*:.*\\)*" nil t) | ||
| 24670 | (add-text-properties (match-beginning 0) (match-end 0) | ||
| 24671 | '(org-protected t))) | ||
| 24672 | (while formatters | ||
| 24673 | (setq fmt (pop formatters)) | ||
| 24674 | (when (car fmt) | ||
| 24675 | (goto-char (point-min)) | ||
| 24676 | (while (re-search-forward (concat "^#\\+" (cadr fmt) | ||
| 24677 | ":[ \t]*\\(.*\\)") nil t) | ||
| 24678 | (replace-match "\\1" t) | ||
| 24679 | (add-text-properties | ||
| 24680 | (point-at-bol) (min (1+ (point-at-eol)) (point-max)) | ||
| 24681 | '(org-protected t)))) | ||
| 24682 | (goto-char (point-min)) | ||
| 24683 | (while (re-search-forward | ||
| 24684 | (concat "^#\\+" | ||
| 24685 | (caddr fmt) "\\>.*\\(\\(\n.*\\)*?\n\\)#\\+" | ||
| 24686 | (cadddr fmt) "\\>.*\n?") nil t) | ||
| 24687 | (if (car fmt) | ||
| 24688 | (add-text-properties (match-beginning 1) (1+ (match-end 1)) | ||
| 24689 | '(org-protected t)) | ||
| 24690 | (delete-region (match-beginning 0) (match-end 0)))))) | ||
| 24691 | |||
| 24692 | ;; Protect quoted subtrees | ||
| 24693 | (goto-char (point-min)) | ||
| 24694 | (while (re-search-forward re-quote nil t) | ||
| 24695 | (goto-char (match-beginning 0)) | ||
| 24696 | (end-of-line 1) | ||
| 24697 | (add-text-properties (point) (org-end-of-subtree t) | ||
| 24698 | '(org-protected t))) | ||
| 24699 | |||
| 24700 | ;; Protect verbatim elements | ||
| 24701 | (goto-char (point-min)) | ||
| 24702 | (while (re-search-forward org-verbatim-re nil t) | ||
| 24703 | (add-text-properties (match-beginning 4) (match-end 4) | ||
| 24704 | '(org-protected t)) | ||
| 24705 | (goto-char (1+ (match-end 4)))) | ||
| 24706 | |||
| 24707 | ;; Remove subtrees that are commented | ||
| 24708 | (goto-char (point-min)) | ||
| 24709 | (while (re-search-forward re-commented nil t) | ||
| 24710 | (goto-char (match-beginning 0)) | ||
| 24711 | (delete-region (point) (org-end-of-subtree t))) | ||
| 24712 | |||
| 24713 | ;; Remove special table lines | ||
| 24714 | (when org-export-table-remove-special-lines | ||
| 24715 | (goto-char (point-min)) | ||
| 24716 | (while (re-search-forward "^[ \t]*|" nil t) | ||
| 24717 | (beginning-of-line 1) | ||
| 24718 | (if (or (looking-at "[ \t]*| *[!_^] *|") | ||
| 24719 | (and (looking-at ".*?| *<[0-9]+> *|") | ||
| 24720 | (not (looking-at ".*?| *[^ <|]")))) | ||
| 24721 | (delete-region (max (point-min) (1- (point-at-bol))) | ||
| 24722 | (point-at-eol)) | ||
| 24723 | (end-of-line 1)))) | ||
| 24724 | |||
| 24725 | ;; Specific LaTeX stuff | ||
| 24726 | (when latexp | ||
| 24727 | (require 'org-export-latex nil) | ||
| 24728 | (org-export-latex-cleaned-string)) | ||
| 24729 | |||
| 24730 | (when asciip | ||
| 24731 | (org-export-ascii-clean-string)) | ||
| 24732 | |||
| 24733 | ;; Specific HTML stuff | ||
| 24734 | (when htmlp | ||
| 24735 | ;; Convert LaTeX fragments to images | ||
| 24736 | (when (plist-get parameters :LaTeX-fragments) | ||
| 24737 | (org-format-latex | ||
| 24738 | (concat "ltxpng/" (file-name-sans-extension | ||
| 24739 | (file-name-nondirectory | ||
| 24740 | org-current-export-file))) | ||
| 24741 | org-current-export-dir nil "Creating LaTeX image %s")) | ||
| 24742 | (message "Exporting...")) | ||
| 24743 | |||
| 24744 | ;; Remove or replace comments | ||
| 24745 | (goto-char (point-min)) | ||
| 24746 | (while (re-search-forward "^#\\(.*\n?\\)" nil t) | ||
| 24747 | (if commentsp | ||
| 24748 | (progn (add-text-properties | ||
| 24749 | (match-beginning 0) (match-end 0) '(org-protected t)) | ||
| 24750 | (replace-match (format commentsp (match-string 1)) t t)) | ||
| 24751 | (replace-match ""))) | ||
| 24752 | |||
| 24753 | ;; Find matches for radio targets and turn them into internal links | ||
| 24754 | (goto-char (point-min)) | ||
| 24755 | (when re-radio | ||
| 24756 | (while (re-search-forward re-radio nil t) | ||
| 24757 | (org-if-unprotected | ||
| 24758 | (replace-match "\\1[[\\2]]")))) | ||
| 24759 | |||
| 24760 | ;; Find all links that contain a newline and put them into a single line | ||
| 24761 | (goto-char (point-min)) | ||
| 24762 | (while (re-search-forward "\\(\\(\\[\\|\\]\\)\\[[^]]*?\\)[ \t]*\n[ \t]*\\([^]]*\\]\\(\\[\\|\\]\\)\\)" nil t) | ||
| 24763 | (org-if-unprotected | ||
| 24764 | (replace-match "\\1 \\3") | ||
| 24765 | (goto-char (match-beginning 0)))) | ||
| 24766 | |||
| 24767 | |||
| 24768 | ;; Normalize links: Convert angle and plain links into bracket links | ||
| 24769 | ;; Expand link abbreviations | ||
| 24770 | (goto-char (point-min)) | ||
| 24771 | (while (re-search-forward re-plain-link nil t) | ||
| 24772 | (goto-char (1- (match-end 0))) | ||
| 24773 | (org-if-unprotected | ||
| 24774 | (let* ((s (concat (match-string 1) "[[" (match-string 2) | ||
| 24775 | ":" (match-string 3) "]]"))) | ||
| 24776 | ;; added 'org-link face to links | ||
| 24777 | (put-text-property 0 (length s) 'face 'org-link s) | ||
| 24778 | (replace-match s t t)))) | ||
| 24779 | (goto-char (point-min)) | ||
| 24780 | (while (re-search-forward re-angle-link nil t) | ||
| 24781 | (goto-char (1- (match-end 0))) | ||
| 24782 | (org-if-unprotected | ||
| 24783 | (let* ((s (concat (match-string 1) "[[" (match-string 2) | ||
| 24784 | ":" (match-string 3) "]]"))) | ||
| 24785 | (put-text-property 0 (length s) 'face 'org-link s) | ||
| 24786 | (replace-match s t t)))) | ||
| 24787 | (goto-char (point-min)) | ||
| 24788 | (while (re-search-forward org-bracket-link-regexp nil t) | ||
| 24789 | (org-if-unprotected | ||
| 24790 | (let* ((s (concat "[[" (setq xx (save-match-data | ||
| 24791 | (org-link-expand-abbrev (match-string 1)))) | ||
| 24792 | "]" | ||
| 24793 | (if (match-end 3) | ||
| 24794 | (match-string 2) | ||
| 24795 | (concat "[" xx "]")) | ||
| 24796 | "]"))) | ||
| 24797 | (put-text-property 0 (length s) 'face 'org-link s) | ||
| 24798 | (replace-match s t t)))) | ||
| 24799 | |||
| 24800 | ;; Find multiline emphasis and put them into single line | ||
| 24801 | (when (plist-get parameters :emph-multiline) | ||
| 24802 | (goto-char (point-min)) | ||
| 24803 | (while (re-search-forward org-emph-re nil t) | ||
| 24804 | (if (not (= (char-after (match-beginning 3)) | ||
| 24805 | (char-after (match-beginning 4)))) | ||
| 24806 | (org-if-unprotected | ||
| 24807 | (subst-char-in-region (match-beginning 0) (match-end 0) | ||
| 24808 | ?\n ?\ t) | ||
| 24809 | (goto-char (1- (match-end 0)))) | ||
| 24810 | (goto-char (1+ (match-beginning 0)))))) | ||
| 24811 | |||
| 24812 | (setq rtn (buffer-string))) | ||
| 24813 | (kill-buffer " org-mode-tmp") | ||
| 24814 | rtn)) | ||
| 24815 | |||
| 24816 | (defun org-export-grab-title-from-buffer () | ||
| 24817 | "Get a title for the current document, from looking at the buffer." | ||
| 24818 | (let ((inhibit-read-only t)) | ||
| 24819 | (save-excursion | ||
| 24820 | (goto-char (point-min)) | ||
| 24821 | (let ((end (save-excursion (outline-next-heading) (point)))) | ||
| 24822 | (when (re-search-forward "^[ \t]*[^|# \t\r\n].*\n" end t) | ||
| 24823 | ;; Mark the line so that it will not be exported as normal text. | ||
| 24824 | (org-unmodified | ||
| 24825 | (add-text-properties (match-beginning 0) (match-end 0) | ||
| 24826 | (list :org-license-to-kill t))) | ||
| 24827 | ;; Return the title string | ||
| 24828 | (org-trim (match-string 0))))))) | ||
| 24829 | |||
| 24830 | (defun org-export-get-title-from-subtree () | ||
| 24831 | "Return subtree title and exclude it from export." | ||
| 24832 | (let (title (m (mark))) | ||
| 24833 | (save-excursion | ||
| 24834 | (goto-char (region-beginning)) | ||
| 24835 | (when (and (org-at-heading-p) | ||
| 24836 | (>= (org-end-of-subtree t t) (region-end))) | ||
| 24837 | ;; This is a subtree, we take the title from the first heading | ||
| 24838 | (goto-char (region-beginning)) | ||
| 24839 | (looking-at org-todo-line-regexp) | ||
| 24840 | (setq title (match-string 3)) | ||
| 24841 | (org-unmodified | ||
| 24842 | (add-text-properties (point) (1+ (point-at-eol)) | ||
| 24843 | (list :org-license-to-kill t))))) | ||
| 24844 | title)) | ||
| 24845 | |||
| 24846 | (defun org-solidify-link-text (s &optional alist) | ||
| 24847 | "Take link text and make a safe target out of it." | ||
| 24848 | (save-match-data | ||
| 24849 | (let* ((rtn | ||
| 24850 | (mapconcat | ||
| 24851 | 'identity | ||
| 24852 | (org-split-string s "[ \t\r\n]+") "--")) | ||
| 24853 | (a (assoc rtn alist))) | ||
| 24854 | (or (cdr a) rtn)))) | ||
| 24855 | |||
| 24856 | (defun org-get-min-level (lines) | ||
| 24857 | "Get the minimum level in LINES." | ||
| 24858 | (let ((re "^\\(\\*+\\) ") l min) | ||
| 24859 | (catch 'exit | ||
| 24860 | (while (setq l (pop lines)) | ||
| 24861 | (if (string-match re l) | ||
| 24862 | (throw 'exit (org-tr-level (length (match-string 1 l)))))) | ||
| 24863 | 1))) | ||
| 24864 | |||
| 24865 | ;; Variable holding the vector with section numbers | ||
| 24866 | (defvar org-section-numbers (make-vector org-level-max 0)) | ||
| 24867 | |||
| 24868 | (defun org-init-section-numbers () | ||
| 24869 | "Initialize the vector for the section numbers." | ||
| 24870 | (let* ((level -1) | ||
| 24871 | (numbers (nreverse (org-split-string "" "\\."))) | ||
| 24872 | (depth (1- (length org-section-numbers))) | ||
| 24873 | (i depth) number-string) | ||
| 24874 | (while (>= i 0) | ||
| 24875 | (if (> i level) | ||
| 24876 | (aset org-section-numbers i 0) | ||
| 24877 | (setq number-string (or (car numbers) "0")) | ||
| 24878 | (if (string-match "\\`[A-Z]\\'" number-string) | ||
| 24879 | (aset org-section-numbers i | ||
| 24880 | (- (string-to-char number-string) ?A -1)) | ||
| 24881 | (aset org-section-numbers i (string-to-number number-string))) | ||
| 24882 | (pop numbers)) | ||
| 24883 | (setq i (1- i))))) | ||
| 24884 | |||
| 24885 | (defun org-section-number (&optional level) | ||
| 24886 | "Return a string with the current section number. | ||
| 24887 | When LEVEL is non-nil, increase section numbers on that level." | ||
| 24888 | (let* ((depth (1- (length org-section-numbers))) idx n (string "")) | ||
| 24889 | (when level | ||
| 24890 | (when (> level -1) | ||
| 24891 | (aset org-section-numbers | ||
| 24892 | level (1+ (aref org-section-numbers level)))) | ||
| 24893 | (setq idx (1+ level)) | ||
| 24894 | (while (<= idx depth) | ||
| 24895 | (if (not (= idx 1)) | ||
| 24896 | (aset org-section-numbers idx 0)) | ||
| 24897 | (setq idx (1+ idx)))) | ||
| 24898 | (setq idx 0) | ||
| 24899 | (while (<= idx depth) | ||
| 24900 | (setq n (aref org-section-numbers idx)) | ||
| 24901 | (setq string (concat string (if (not (string= string "")) "." "") | ||
| 24902 | (int-to-string n))) | ||
| 24903 | (setq idx (1+ idx))) | ||
| 24904 | (save-match-data | ||
| 24905 | (if (string-match "\\`\\([@0]\\.\\)+" string) | ||
| 24906 | (setq string (replace-match "" t nil string))) | ||
| 24907 | (if (string-match "\\(\\.0\\)+\\'" string) | ||
| 24908 | (setq string (replace-match "" t nil string)))) | ||
| 24909 | string)) | ||
| 24910 | |||
| 24911 | ;;; ASCII export | ||
| 24912 | |||
| 24913 | (defvar org-last-level nil) ; dynamically scoped variable | ||
| 24914 | (defvar org-min-level nil) ; dynamically scoped variable | ||
| 24915 | (defvar org-levels-open nil) ; dynamically scoped parameter | ||
| 24916 | (defvar org-ascii-current-indentation nil) ; For communication | ||
| 24917 | |||
| 24918 | (defun org-export-as-ascii (arg) | ||
| 24919 | "Export the outline as a pretty ASCII file. | ||
| 24920 | If there is an active region, export only the region. | ||
| 24921 | The prefix ARG specifies how many levels of the outline should become | ||
| 24922 | underlined headlines. The default is 3." | ||
| 24923 | (interactive "P") | ||
| 24924 | (setq-default org-todo-line-regexp org-todo-line-regexp) | ||
| 24925 | (let* ((opt-plist (org-combine-plists (org-default-export-plist) | ||
| 24926 | (org-infile-export-plist))) | ||
| 24927 | (region-p (org-region-active-p)) | ||
| 24928 | (subtree-p | ||
| 24929 | (when region-p | ||
| 24930 | (save-excursion | ||
| 24931 | (goto-char (region-beginning)) | ||
| 24932 | (and (org-at-heading-p) | ||
| 24933 | (>= (org-end-of-subtree t t) (region-end)))))) | ||
| 24934 | (custom-times org-display-custom-times) | ||
| 24935 | (org-ascii-current-indentation '(0 . 0)) | ||
| 24936 | (level 0) line txt | ||
| 24937 | (umax nil) | ||
| 24938 | (umax-toc nil) | ||
| 24939 | (case-fold-search nil) | ||
| 24940 | (filename (concat (file-name-as-directory | ||
| 24941 | (org-export-directory :ascii opt-plist)) | ||
| 24942 | (file-name-sans-extension | ||
| 24943 | (or (and subtree-p | ||
| 24944 | (org-entry-get (region-beginning) | ||
| 24945 | "EXPORT_FILE_NAME" t)) | ||
| 24946 | (file-name-nondirectory buffer-file-name))) | ||
| 24947 | ".txt")) | ||
| 24948 | (filename (if (equal (file-truename filename) | ||
| 24949 | (file-truename buffer-file-name)) | ||
| 24950 | (concat filename ".txt") | ||
| 24951 | filename)) | ||
| 24952 | (buffer (find-file-noselect filename)) | ||
| 24953 | (org-levels-open (make-vector org-level-max nil)) | ||
| 24954 | (odd org-odd-levels-only) | ||
| 24955 | (date (plist-get opt-plist :date)) | ||
| 24956 | (author (plist-get opt-plist :author)) | ||
| 24957 | (title (or (and subtree-p (org-export-get-title-from-subtree)) | ||
| 24958 | (plist-get opt-plist :title) | ||
| 24959 | (and (not | ||
| 24960 | (plist-get opt-plist :skip-before-1st-heading)) | ||
| 24961 | (org-export-grab-title-from-buffer)) | ||
| 24962 | (file-name-sans-extension | ||
| 24963 | (file-name-nondirectory buffer-file-name)))) | ||
| 24964 | (email (plist-get opt-plist :email)) | ||
| 24965 | (language (plist-get opt-plist :language)) | ||
| 24966 | (quote-re0 (concat "^[ \t]*" org-quote-string "\\>")) | ||
| 24967 | ; (quote-re (concat "^\\(\\*+\\)\\([ \t]*" org-quote-string "\\>\\)")) | ||
| 24968 | (todo nil) | ||
| 24969 | (lang-words nil) | ||
| 24970 | (region | ||
| 24971 | (buffer-substring | ||
| 24972 | (if (org-region-active-p) (region-beginning) (point-min)) | ||
| 24973 | (if (org-region-active-p) (region-end) (point-max)))) | ||
| 24974 | (lines (org-split-string | ||
| 24975 | (org-cleaned-string-for-export | ||
| 24976 | region | ||
| 24977 | :for-ascii t | ||
| 24978 | :skip-before-1st-heading | ||
| 24979 | (plist-get opt-plist :skip-before-1st-heading) | ||
| 24980 | :drawers (plist-get opt-plist :drawers) | ||
| 24981 | :verbatim-multiline t | ||
| 24982 | :archived-trees | ||
| 24983 | (plist-get opt-plist :archived-trees) | ||
| 24984 | :add-text (plist-get opt-plist :text)) | ||
| 24985 | "\n")) | ||
| 24986 | thetoc have-headings first-heading-pos | ||
| 24987 | table-open table-buffer) | ||
| 24988 | |||
| 24989 | (let ((inhibit-read-only t)) | ||
| 24990 | (org-unmodified | ||
| 24991 | (remove-text-properties (point-min) (point-max) | ||
| 24992 | '(:org-license-to-kill t)))) | ||
| 24993 | |||
| 24994 | (setq org-min-level (org-get-min-level lines)) | ||
| 24995 | (setq org-last-level org-min-level) | ||
| 24996 | (org-init-section-numbers) | ||
| 24997 | |||
| 24998 | (find-file-noselect filename) | ||
| 24999 | |||
| 25000 | (setq lang-words (or (assoc language org-export-language-setup) | ||
| 25001 | (assoc "en" org-export-language-setup))) | ||
| 25002 | (switch-to-buffer-other-window buffer) | ||
| 25003 | (erase-buffer) | ||
| 25004 | (fundamental-mode) | ||
| 25005 | ;; create local variables for all options, to make sure all called | ||
| 25006 | ;; functions get the correct information | ||
| 25007 | (mapc (lambda (x) | ||
| 25008 | (set (make-local-variable (cdr x)) | ||
| 25009 | (plist-get opt-plist (car x)))) | ||
| 25010 | org-export-plist-vars) | ||
| 25011 | (org-set-local 'org-odd-levels-only odd) | ||
| 25012 | (setq umax (if arg (prefix-numeric-value arg) | ||
| 25013 | org-export-headline-levels)) | ||
| 25014 | (setq umax-toc (if (integerp org-export-with-toc) | ||
| 25015 | (min org-export-with-toc umax) | ||
| 25016 | umax)) | ||
| 25017 | |||
| 25018 | ;; File header | ||
| 25019 | (if title (org-insert-centered title ?=)) | ||
| 25020 | (insert "\n") | ||
| 25021 | (if (and (or author email) | ||
| 25022 | org-export-author-info) | ||
| 25023 | (insert (concat (nth 1 lang-words) ": " (or author "") | ||
| 25024 | (if email (concat " <" email ">") "") | ||
| 25025 | "\n"))) | ||
| 25026 | |||
| 25027 | (cond | ||
| 25028 | ((and date (string-match "%" date)) | ||
| 25029 | (setq date (format-time-string date (current-time)))) | ||
| 25030 | (date) | ||
| 25031 | (t (setq date (format-time-string "%Y/%m/%d %X" (current-time))))) | ||
| 25032 | |||
| 25033 | (if (and date org-export-time-stamp-file) | ||
| 25034 | (insert (concat (nth 2 lang-words) ": " date"\n"))) | ||
| 25035 | |||
| 25036 | (insert "\n\n") | ||
| 25037 | |||
| 25038 | (if org-export-with-toc | ||
| 25039 | (progn | ||
| 25040 | (push (concat (nth 3 lang-words) "\n") thetoc) | ||
| 25041 | (push (concat (make-string (length (nth 3 lang-words)) ?=) "\n") thetoc) | ||
| 25042 | (mapc '(lambda (line) | ||
| 25043 | (if (string-match org-todo-line-regexp | ||
| 25044 | line) | ||
| 25045 | ;; This is a headline | ||
| 25046 | (progn | ||
| 25047 | (setq have-headings t) | ||
| 25048 | (setq level (- (match-end 1) (match-beginning 1)) | ||
| 25049 | level (org-tr-level level) | ||
| 25050 | txt (match-string 3 line) | ||
| 25051 | todo | ||
| 25052 | (or (and org-export-mark-todo-in-toc | ||
| 25053 | (match-beginning 2) | ||
| 25054 | (not (member (match-string 2 line) | ||
| 25055 | org-done-keywords))) | ||
| 25056 | ; TODO, not DONE | ||
| 25057 | (and org-export-mark-todo-in-toc | ||
| 25058 | (= level umax-toc) | ||
| 25059 | (org-search-todo-below | ||
| 25060 | line lines level)))) | ||
| 25061 | (setq txt (org-html-expand-for-ascii txt)) | ||
| 25062 | |||
| 25063 | (while (string-match org-bracket-link-regexp txt) | ||
| 25064 | (setq txt | ||
| 25065 | (replace-match | ||
| 25066 | (match-string (if (match-end 2) 3 1) txt) | ||
| 25067 | t t txt))) | ||
| 25068 | |||
| 25069 | (if (and (memq org-export-with-tags '(not-in-toc nil)) | ||
| 25070 | (string-match | ||
| 25071 | (org-re "[ \t]+:[[:alnum:]_@:]+:[ \t]*$") | ||
| 25072 | txt)) | ||
| 25073 | (setq txt (replace-match "" t t txt))) | ||
| 25074 | (if (string-match quote-re0 txt) | ||
| 25075 | (setq txt (replace-match "" t t txt))) | ||
| 25076 | |||
| 25077 | (if org-export-with-section-numbers | ||
| 25078 | (setq txt (concat (org-section-number level) | ||
| 25079 | " " txt))) | ||
| 25080 | (if (<= level umax-toc) | ||
| 25081 | (progn | ||
| 25082 | (push | ||
| 25083 | (concat | ||
| 25084 | (make-string | ||
| 25085 | (* (max 0 (- level org-min-level)) 4) ?\ ) | ||
| 25086 | (format (if todo "%s (*)\n" "%s\n") txt)) | ||
| 25087 | thetoc) | ||
| 25088 | (setq org-last-level level)) | ||
| 25089 | )))) | ||
| 25090 | lines) | ||
| 25091 | (setq thetoc (if have-headings (nreverse thetoc) nil)))) | ||
| 25092 | |||
| 25093 | (org-init-section-numbers) | ||
| 25094 | (while (setq line (pop lines)) | ||
| 25095 | ;; Remove the quoted HTML tags. | ||
| 25096 | (setq line (org-html-expand-for-ascii line)) | ||
| 25097 | ;; Remove targets | ||
| 25098 | (while (string-match "<<<?[^<>]*>>>?[ \t]*\n?" line) | ||
| 25099 | (setq line (replace-match "" t t line))) | ||
| 25100 | ;; Replace internal links | ||
| 25101 | (while (string-match org-bracket-link-regexp line) | ||
| 25102 | (setq line (replace-match | ||
| 25103 | (if (match-end 3) "[\\3]" "[\\1]") | ||
| 25104 | t nil line))) | ||
| 25105 | (when custom-times | ||
| 25106 | (setq line (org-translate-time line))) | ||
| 25107 | (cond | ||
| 25108 | ((string-match "^\\(\\*+\\)[ \t]+\\(.*\\)" line) | ||
| 25109 | ;; a Headline | ||
| 25110 | (setq first-heading-pos (or first-heading-pos (point))) | ||
| 25111 | (setq level (org-tr-level (- (match-end 1) (match-beginning 1))) | ||
| 25112 | txt (match-string 2 line)) | ||
| 25113 | (org-ascii-level-start level txt umax lines)) | ||
| 25114 | |||
| 25115 | ((and org-export-with-tables | ||
| 25116 | (string-match "^\\([ \t]*\\)\\(|\\|\\+-+\\+\\)" line)) | ||
| 25117 | (if (not table-open) | ||
| 25118 | ;; New table starts | ||
| 25119 | (setq table-open t table-buffer nil)) | ||
| 25120 | ;; Accumulate lines | ||
| 25121 | (setq table-buffer (cons line table-buffer)) | ||
| 25122 | (when (or (not lines) | ||
| 25123 | (not (string-match "^\\([ \t]*\\)\\(|\\|\\+-+\\+\\)" | ||
| 25124 | (car lines)))) | ||
| 25125 | (setq table-open nil | ||
| 25126 | table-buffer (nreverse table-buffer)) | ||
| 25127 | (insert (mapconcat | ||
| 25128 | (lambda (x) | ||
| 25129 | (org-fix-indentation x org-ascii-current-indentation)) | ||
| 25130 | (org-format-table-ascii table-buffer) | ||
| 25131 | "\n") "\n"))) | ||
| 25132 | (t | ||
| 25133 | (setq line (org-fix-indentation line org-ascii-current-indentation)) | ||
| 25134 | (if (and org-export-with-fixed-width | ||
| 25135 | (string-match "^\\([ \t]*\\)\\(:\\)" line)) | ||
| 25136 | (setq line (replace-match "\\1" nil nil line))) | ||
| 25137 | (insert line "\n")))) | ||
| 25138 | |||
| 25139 | (normal-mode) | ||
| 25140 | |||
| 25141 | ;; insert the table of contents | ||
| 25142 | (when thetoc | ||
| 25143 | (goto-char (point-min)) | ||
| 25144 | (if (re-search-forward "^[ \t]*\\[TABLE-OF-CONTENTS\\][ \t]*$" nil t) | ||
| 25145 | (progn | ||
| 25146 | (goto-char (match-beginning 0)) | ||
| 25147 | (replace-match "")) | ||
| 25148 | (goto-char first-heading-pos)) | ||
| 25149 | (mapc 'insert thetoc) | ||
| 25150 | (or (looking-at "[ \t]*\n[ \t]*\n") | ||
| 25151 | (insert "\n\n"))) | ||
| 25152 | |||
| 25153 | ;; Convert whitespace place holders | ||
| 25154 | (goto-char (point-min)) | ||
| 25155 | (let (beg end) | ||
| 25156 | (while (setq beg (next-single-property-change (point) 'org-whitespace)) | ||
| 25157 | (setq end (next-single-property-change beg 'org-whitespace)) | ||
| 25158 | (goto-char beg) | ||
| 25159 | (delete-region beg end) | ||
| 25160 | (insert (make-string (- end beg) ?\ )))) | ||
| 25161 | |||
| 25162 | (save-buffer) | ||
| 25163 | ;; remove display and invisible chars | ||
| 25164 | (let (beg end) | ||
| 25165 | (goto-char (point-min)) | ||
| 25166 | (while (setq beg (next-single-property-change (point) 'display)) | ||
| 25167 | (setq end (next-single-property-change beg 'display)) | ||
| 25168 | (delete-region beg end) | ||
| 25169 | (goto-char beg) | ||
| 25170 | (insert "=>")) | ||
| 25171 | (goto-char (point-min)) | ||
| 25172 | (while (setq beg (next-single-property-change (point) 'org-cwidth)) | ||
| 25173 | (setq end (next-single-property-change beg 'org-cwidth)) | ||
| 25174 | (delete-region beg end) | ||
| 25175 | (goto-char beg))) | ||
| 25176 | (goto-char (point-min)))) | ||
| 25177 | |||
| 25178 | (defun org-export-ascii-clean-string () | ||
| 25179 | "Do extra work for ASCII export" | ||
| 25180 | (goto-char (point-min)) | ||
| 25181 | (while (re-search-forward org-verbatim-re nil t) | ||
| 25182 | (goto-char (match-end 2)) | ||
| 25183 | (backward-delete-char 1) (insert "'") | ||
| 25184 | (goto-char (match-beginning 2)) | ||
| 25185 | (delete-char 1) (insert "`") | ||
| 25186 | (goto-char (match-end 2)))) | ||
| 25187 | |||
| 25188 | (defun org-search-todo-below (line lines level) | ||
| 25189 | "Search the subtree below LINE for any TODO entries." | ||
| 25190 | (let ((rest (cdr (memq line lines))) | ||
| 25191 | (re org-todo-line-regexp) | ||
| 25192 | line lv todo) | ||
| 25193 | (catch 'exit | ||
| 25194 | (while (setq line (pop rest)) | ||
| 25195 | (if (string-match re line) | ||
| 25196 | (progn | ||
| 25197 | (setq lv (- (match-end 1) (match-beginning 1)) | ||
| 25198 | todo (and (match-beginning 2) | ||
| 25199 | (not (member (match-string 2 line) | ||
| 25200 | org-done-keywords)))) | ||
| 25201 | ; TODO, not DONE | ||
| 25202 | (if (<= lv level) (throw 'exit nil)) | ||
| 25203 | (if todo (throw 'exit t)))))))) | ||
| 25204 | |||
| 25205 | (defun org-html-expand-for-ascii (line) | ||
| 25206 | "Handle quoted HTML for ASCII export." | ||
| 25207 | (if org-export-html-expand | ||
| 25208 | (while (string-match "@<[^<>\n]*>" line) | ||
| 25209 | ;; We just remove the tags for now. | ||
| 25210 | (setq line (replace-match "" nil nil line)))) | ||
| 25211 | line) | ||
| 25212 | |||
| 25213 | (defun org-insert-centered (s &optional underline) | ||
| 25214 | "Insert the string S centered and underline it with character UNDERLINE." | ||
| 25215 | (let ((ind (max (/ (- 80 (string-width s)) 2) 0))) | ||
| 25216 | (insert (make-string ind ?\ ) s "\n") | ||
| 25217 | (if underline | ||
| 25218 | (insert (make-string ind ?\ ) | ||
| 25219 | (make-string (string-width s) underline) | ||
| 25220 | "\n")))) | ||
| 25221 | |||
| 25222 | (defun org-ascii-level-start (level title umax &optional lines) | ||
| 25223 | "Insert a new level in ASCII export." | ||
| 25224 | (let (char (n (- level umax 1)) (ind 0)) | ||
| 25225 | (if (> level umax) | ||
| 25226 | (progn | ||
| 25227 | (insert (make-string (* 2 n) ?\ ) | ||
| 25228 | (char-to-string (nth (% n (length org-export-ascii-bullets)) | ||
| 25229 | org-export-ascii-bullets)) | ||
| 25230 | " " title "\n") | ||
| 25231 | ;; find the indentation of the next non-empty line | ||
| 25232 | (catch 'stop | ||
| 25233 | (while lines | ||
| 25234 | (if (string-match "^\\* " (car lines)) (throw 'stop nil)) | ||
| 25235 | (if (string-match "^\\([ \t]*\\)\\S-" (car lines)) | ||
| 25236 | (throw 'stop (setq ind (org-get-indentation (car lines))))) | ||
| 25237 | (pop lines))) | ||
| 25238 | (setq org-ascii-current-indentation (cons (* 2 (1+ n)) ind))) | ||
| 25239 | (if (or (not (equal (char-before) ?\n)) | ||
| 25240 | (not (equal (char-before (1- (point))) ?\n))) | ||
| 25241 | (insert "\n")) | ||
| 25242 | (setq char (nth (- umax level) (reverse org-export-ascii-underline))) | ||
| 25243 | (unless org-export-with-tags | ||
| 25244 | (if (string-match (org-re "[ \t]+\\(:[[:alnum:]_@:]+:\\)[ \t]*$") title) | ||
| 25245 | (setq title (replace-match "" t t title)))) | ||
| 25246 | (if org-export-with-section-numbers | ||
| 25247 | (setq title (concat (org-section-number level) " " title))) | ||
| 25248 | (insert title "\n" (make-string (string-width title) char) "\n") | ||
| 25249 | (setq org-ascii-current-indentation '(0 . 0))))) | ||
| 25250 | |||
| 25251 | (defun org-export-visible (type arg) | ||
| 25252 | "Create a copy of the visible part of the current buffer, and export it. | ||
| 25253 | The copy is created in a temporary buffer and removed after use. | ||
| 25254 | TYPE is the final key (as a string) that also select the export command in | ||
| 25255 | the `C-c C-e' export dispatcher. | ||
| 25256 | As a special case, if the you type SPC at the prompt, the temporary | ||
| 25257 | org-mode file will not be removed but presented to you so that you can | ||
| 25258 | continue to use it. The prefix arg ARG is passed through to the exporting | ||
| 25259 | command." | ||
| 25260 | (interactive | ||
| 25261 | (list (progn | ||
| 25262 | (message "Export visible: [a]SCII [h]tml [b]rowse HTML [H/R]uffer with HTML [x]OXO [ ]keep buffer") | ||
| 25263 | (read-char-exclusive)) | ||
| 25264 | current-prefix-arg)) | ||
| 25265 | (if (not (member type '(?a ?\C-a ?b ?\C-b ?h ?x ?\ ))) | ||
| 25266 | (error "Invalid export key")) | ||
| 25267 | (let* ((binding (cdr (assoc type | ||
| 25268 | '((?a . org-export-as-ascii) | ||
| 25269 | (?\C-a . org-export-as-ascii) | ||
| 25270 | (?b . org-export-as-html-and-open) | ||
| 25271 | (?\C-b . org-export-as-html-and-open) | ||
| 25272 | (?h . org-export-as-html) | ||
| 25273 | (?H . org-export-as-html-to-buffer) | ||
| 25274 | (?R . org-export-region-as-html) | ||
| 25275 | (?x . org-export-as-xoxo))))) | ||
| 25276 | (keepp (equal type ?\ )) | ||
| 25277 | (file buffer-file-name) | ||
| 25278 | (buffer (get-buffer-create "*Org Export Visible*")) | ||
| 25279 | s e) | ||
| 25280 | ;; Need to hack the drawers here. | ||
| 25281 | (save-excursion | ||
| 25282 | (goto-char (point-min)) | ||
| 25283 | (while (re-search-forward org-drawer-regexp nil t) | ||
| 25284 | (goto-char (match-beginning 1)) | ||
| 25285 | (or (org-invisible-p) (org-flag-drawer nil)))) | ||
| 25286 | (with-current-buffer buffer (erase-buffer)) | ||
| 25287 | (save-excursion | ||
| 25288 | (setq s (goto-char (point-min))) | ||
| 25289 | (while (not (= (point) (point-max))) | ||
| 25290 | (goto-char (org-find-invisible)) | ||
| 25291 | (append-to-buffer buffer s (point)) | ||
| 25292 | (setq s (goto-char (org-find-visible)))) | ||
| 25293 | (org-cycle-hide-drawers 'all) | ||
| 25294 | (goto-char (point-min)) | ||
| 25295 | (unless keepp | ||
| 25296 | ;; Copy all comment lines to the end, to make sure #+ settings are | ||
| 25297 | ;; still available for the second export step. Kind of a hack, but | ||
| 25298 | ;; does do the trick. | ||
| 25299 | (if (looking-at "#[^\r\n]*") | ||
| 25300 | (append-to-buffer buffer (match-beginning 0) (1+ (match-end 0)))) | ||
| 25301 | (while (re-search-forward "[\n\r]#[^\n\r]*" nil t) | ||
| 25302 | (append-to-buffer buffer (1+ (match-beginning 0)) | ||
| 25303 | (min (point-max) (1+ (match-end 0)))))) | ||
| 25304 | (set-buffer buffer) | ||
| 25305 | (let ((buffer-file-name file) | ||
| 25306 | (org-inhibit-startup t)) | ||
| 25307 | (org-mode) | ||
| 25308 | (show-all) | ||
| 25309 | (unless keepp (funcall binding arg)))) | ||
| 25310 | (if (not keepp) | ||
| 25311 | (kill-buffer buffer) | ||
| 25312 | (switch-to-buffer-other-window buffer) | ||
| 25313 | (goto-char (point-min))))) | ||
| 25314 | |||
| 25315 | (defun org-find-visible () | ||
| 25316 | (let ((s (point))) | ||
| 25317 | (while (and (not (= (point-max) (setq s (next-overlay-change s)))) | ||
| 25318 | (get-char-property s 'invisible))) | ||
| 25319 | s)) | ||
| 25320 | (defun org-find-invisible () | ||
| 25321 | (let ((s (point))) | ||
| 25322 | (while (and (not (= (point-max) (setq s (next-overlay-change s)))) | ||
| 25323 | (not (get-char-property s 'invisible)))) | ||
| 25324 | s)) | ||
| 25325 | |||
| 25326 | ;;; HTML export | ||
| 25327 | |||
| 25328 | (defun org-get-current-options () | ||
| 25329 | "Return a string with current options as keyword options. | ||
| 25330 | Does include HTML export options as well as TODO and CATEGORY stuff." | ||
| 25331 | (format | ||
| 25332 | "#+TITLE: %s | ||
| 25333 | #+AUTHOR: %s | ||
| 25334 | #+EMAIL: %s | ||
| 25335 | #+LANGUAGE: %s | ||
| 25336 | #+TEXT: Some descriptive text to be emitted. Several lines OK. | ||
| 25337 | #+OPTIONS: H:%d num:%s toc:%s \\n:%s @:%s ::%s |:%s ^:%s -:%s f:%s *:%s TeX:%s LaTeX:%s skip:%s d:%s tags:%s | ||
| 25338 | #+CATEGORY: %s | ||
| 25339 | #+SEQ_TODO: %s | ||
| 25340 | #+TYP_TODO: %s | ||
| 25341 | #+PRIORITIES: %c %c %c | ||
| 25342 | #+DRAWERS: %s | ||
| 25343 | #+STARTUP: %s %s %s %s %s | ||
| 25344 | #+TAGS: %s | ||
| 25345 | #+ARCHIVE: %s | ||
| 25346 | #+LINK: %s | ||
| 25347 | " | ||
| 25348 | (buffer-name) (user-full-name) user-mail-address org-export-default-language | ||
| 25349 | org-export-headline-levels | ||
| 25350 | org-export-with-section-numbers | ||
| 25351 | org-export-with-toc | ||
| 25352 | org-export-preserve-breaks | ||
| 25353 | org-export-html-expand | ||
| 25354 | org-export-with-fixed-width | ||
| 25355 | org-export-with-tables | ||
| 25356 | org-export-with-sub-superscripts | ||
| 25357 | org-export-with-special-strings | ||
| 25358 | org-export-with-footnotes | ||
| 25359 | org-export-with-emphasize | ||
| 25360 | org-export-with-TeX-macros | ||
| 25361 | org-export-with-LaTeX-fragments | ||
| 25362 | org-export-skip-text-before-1st-heading | ||
| 25363 | org-export-with-drawers | ||
| 25364 | org-export-with-tags | ||
| 25365 | (file-name-nondirectory buffer-file-name) | ||
| 25366 | "TODO FEEDBACK VERIFY DONE" | ||
| 25367 | "Me Jason Marie DONE" | ||
| 25368 | org-highest-priority org-lowest-priority org-default-priority | ||
| 25369 | (mapconcat 'identity org-drawers " ") | ||
| 25370 | (cdr (assoc org-startup-folded | ||
| 25371 | '((nil . "showall") (t . "overview") (content . "content")))) | ||
| 25372 | (if org-odd-levels-only "odd" "oddeven") | ||
| 25373 | (if org-hide-leading-stars "hidestars" "showstars") | ||
| 25374 | (if org-startup-align-all-tables "align" "noalign") | ||
| 25375 | (cond ((eq org-log-done t) "logdone") | ||
| 25376 | ((equal org-log-done 'note) "lognotedone") | ||
| 25377 | ((not org-log-done) "nologdone")) | ||
| 25378 | (or (mapconcat (lambda (x) | ||
| 25379 | (cond | ||
| 25380 | ((equal '(:startgroup) x) "{") | ||
| 25381 | ((equal '(:endgroup) x) "}") | ||
| 25382 | ((cdr x) (format "%s(%c)" (car x) (cdr x))) | ||
| 25383 | (t (car x)))) | ||
| 25384 | (or org-tag-alist (org-get-buffer-tags)) " ") "") | ||
| 25385 | org-archive-location | ||
| 25386 | "org file:~/org/%s.org" | ||
| 25387 | )) | ||
| 25388 | |||
| 25389 | (defun org-insert-export-options-template () | ||
| 25390 | "Insert into the buffer a template with information for exporting." | ||
| 25391 | (interactive) | ||
| 25392 | (if (not (bolp)) (newline)) | ||
| 25393 | (let ((s (org-get-current-options))) | ||
| 25394 | (and (string-match "#\\+CATEGORY" s) | ||
| 25395 | (setq s (substring s 0 (match-beginning 0)))) | ||
| 25396 | (insert s))) | ||
| 25397 | |||
| 25398 | (defun org-toggle-fixed-width-section (arg) | ||
| 25399 | "Toggle the fixed-width export. | ||
| 25400 | If there is no active region, the QUOTE keyword at the current headline is | ||
| 25401 | inserted or removed. When present, it causes the text between this headline | ||
| 25402 | and the next to be exported as fixed-width text, and unmodified. | ||
| 25403 | If there is an active region, this command adds or removes a colon as the | ||
| 25404 | first character of this line. If the first character of a line is a colon, | ||
| 25405 | this line is also exported in fixed-width font." | ||
| 25406 | (interactive "P") | ||
| 25407 | (let* ((cc 0) | ||
| 25408 | (regionp (org-region-active-p)) | ||
| 25409 | (beg (if regionp (region-beginning) (point))) | ||
| 25410 | (end (if regionp (region-end))) | ||
| 25411 | (nlines (or arg (if (and beg end) (count-lines beg end) 1))) | ||
| 25412 | (case-fold-search nil) | ||
| 25413 | (re "[ \t]*\\(:\\)") | ||
| 25414 | off) | ||
| 25415 | (if regionp | ||
| 25416 | (save-excursion | ||
| 25417 | (goto-char beg) | ||
| 25418 | (setq cc (current-column)) | ||
| 25419 | (beginning-of-line 1) | ||
| 25420 | (setq off (looking-at re)) | ||
| 25421 | (while (> nlines 0) | ||
| 25422 | (setq nlines (1- nlines)) | ||
| 25423 | (beginning-of-line 1) | ||
| 25424 | (cond | ||
| 25425 | (arg | ||
| 25426 | (move-to-column cc t) | ||
| 25427 | (insert ":\n") | ||
| 25428 | (forward-line -1)) | ||
| 25429 | ((and off (looking-at re)) | ||
| 25430 | (replace-match "" t t nil 1)) | ||
| 25431 | ((not off) (move-to-column cc t) (insert ":"))) | ||
| 25432 | (forward-line 1))) | ||
| 25433 | (save-excursion | ||
| 25434 | (org-back-to-heading) | ||
| 25435 | (if (looking-at (concat outline-regexp | ||
| 25436 | "\\( *\\<" org-quote-string "\\>[ \t]*\\)")) | ||
| 25437 | (replace-match "" t t nil 1) | ||
| 25438 | (if (looking-at outline-regexp) | ||
| 25439 | (progn | ||
| 25440 | (goto-char (match-end 0)) | ||
| 25441 | (insert org-quote-string " ")))))))) | ||
| 25442 | |||
| 25443 | (defun org-export-as-html-and-open (arg) | ||
| 25444 | "Export the outline as HTML and immediately open it with a browser. | ||
| 25445 | If there is an active region, export only the region. | ||
| 25446 | The prefix ARG specifies how many levels of the outline should become | ||
| 25447 | headlines. The default is 3. Lower levels will become bulleted lists." | ||
| 25448 | (interactive "P") | ||
| 25449 | (org-export-as-html arg 'hidden) | ||
| 25450 | (org-open-file buffer-file-name)) | ||
| 25451 | |||
| 25452 | (defun org-export-as-html-batch () | ||
| 25453 | "Call `org-export-as-html', may be used in batch processing as | ||
| 25454 | emacs --batch | ||
| 25455 | --load=$HOME/lib/emacs/org.el | ||
| 25456 | --eval \"(setq org-export-headline-levels 2)\" | ||
| 25457 | --visit=MyFile --funcall org-export-as-html-batch" | ||
| 25458 | (org-export-as-html org-export-headline-levels 'hidden)) | ||
| 25459 | |||
| 25460 | (defun org-export-as-html-to-buffer (arg) | ||
| 25461 | "Call `org-exort-as-html` with output to a temporary buffer. | ||
| 25462 | No file is created. The prefix ARG is passed through to `org-export-as-html'." | ||
| 25463 | (interactive "P") | ||
| 25464 | (org-export-as-html arg nil nil "*Org HTML Export*") | ||
| 25465 | (switch-to-buffer-other-window "*Org HTML Export*")) | ||
| 25466 | |||
| 25467 | (defun org-replace-region-by-html (beg end) | ||
| 25468 | "Assume the current region has org-mode syntax, and convert it to HTML. | ||
| 25469 | This can be used in any buffer. For example, you could write an | ||
| 25470 | itemized list in org-mode syntax in an HTML buffer and then use this | ||
| 25471 | command to convert it." | ||
| 25472 | (interactive "r") | ||
| 25473 | (let (reg html buf pop-up-frames) | ||
| 25474 | (save-window-excursion | ||
| 25475 | (if (org-mode-p) | ||
| 25476 | (setq html (org-export-region-as-html | ||
| 25477 | beg end t 'string)) | ||
| 25478 | (setq reg (buffer-substring beg end) | ||
| 25479 | buf (get-buffer-create "*Org tmp*")) | ||
| 25480 | (with-current-buffer buf | ||
| 25481 | (erase-buffer) | ||
| 25482 | (insert reg) | ||
| 25483 | (org-mode) | ||
| 25484 | (setq html (org-export-region-as-html | ||
| 25485 | (point-min) (point-max) t 'string))) | ||
| 25486 | (kill-buffer buf))) | ||
| 25487 | (delete-region beg end) | ||
| 25488 | (insert html))) | ||
| 25489 | |||
| 25490 | (defun org-export-region-as-html (beg end &optional body-only buffer) | ||
| 25491 | "Convert region from BEG to END in org-mode buffer to HTML. | ||
| 25492 | If prefix arg BODY-ONLY is set, omit file header, footer, and table of | ||
| 25493 | contents, and only produce the region of converted text, useful for | ||
| 25494 | cut-and-paste operations. | ||
| 25495 | If BUFFER is a buffer or a string, use/create that buffer as a target | ||
| 25496 | of the converted HTML. If BUFFER is the symbol `string', return the | ||
| 25497 | produced HTML as a string and leave not buffer behind. For example, | ||
| 25498 | a Lisp program could call this function in the following way: | ||
| 25499 | |||
| 25500 | (setq html (org-export-region-as-html beg end t 'string)) | ||
| 25501 | |||
| 25502 | When called interactively, the output buffer is selected, and shown | ||
| 25503 | in a window. A non-interactive call will only retunr the buffer." | ||
| 25504 | (interactive "r\nP") | ||
| 25505 | (when (interactive-p) | ||
| 25506 | (setq buffer "*Org HTML Export*")) | ||
| 25507 | (let ((transient-mark-mode t) (zmacs-regions t) | ||
| 25508 | rtn) | ||
| 25509 | (goto-char end) | ||
| 25510 | (set-mark (point)) ;; to activate the region | ||
| 25511 | (goto-char beg) | ||
| 25512 | (setq rtn (org-export-as-html | ||
| 25513 | nil nil nil | ||
| 25514 | buffer body-only)) | ||
| 25515 | (if (fboundp 'deactivate-mark) (deactivate-mark)) | ||
| 25516 | (if (and (interactive-p) (bufferp rtn)) | ||
| 25517 | (switch-to-buffer-other-window rtn) | ||
| 25518 | rtn))) | ||
| 25519 | |||
| 25520 | (defvar html-table-tag nil) ; dynamically scoped into this. | ||
| 25521 | (defun org-export-as-html (arg &optional hidden ext-plist | ||
| 25522 | to-buffer body-only pub-dir) | ||
| 25523 | "Export the outline as a pretty HTML file. | ||
| 25524 | If there is an active region, export only the region. The prefix | ||
| 25525 | ARG specifies how many levels of the outline should become | ||
| 25526 | headlines. The default is 3. Lower levels will become bulleted | ||
| 25527 | lists. When HIDDEN is non-nil, don't display the HTML buffer. | ||
| 25528 | EXT-PLIST is a property list with external parameters overriding | ||
| 25529 | org-mode's default settings, but still inferior to file-local | ||
| 25530 | settings. When TO-BUFFER is non-nil, create a buffer with that | ||
| 25531 | name and export to that buffer. If TO-BUFFER is the symbol | ||
| 25532 | `string', don't leave any buffer behind but just return the | ||
| 25533 | resulting HTML as a string. When BODY-ONLY is set, don't produce | ||
| 25534 | the file header and footer, simply return the content of | ||
| 25535 | <body>...</body>, without even the body tags themselves. When | ||
| 25536 | PUB-DIR is set, use this as the publishing directory." | ||
| 25537 | (interactive "P") | ||
| 25538 | |||
| 25539 | ;; Make sure we have a file name when we need it. | ||
| 25540 | (when (and (not (or to-buffer body-only)) | ||
| 25541 | (not buffer-file-name)) | ||
| 25542 | (if (buffer-base-buffer) | ||
| 25543 | (org-set-local 'buffer-file-name | ||
| 25544 | (with-current-buffer (buffer-base-buffer) | ||
| 25545 | buffer-file-name)) | ||
| 25546 | (error "Need a file name to be able to export."))) | ||
| 25547 | |||
| 25548 | (message "Exporting...") | ||
| 25549 | (setq-default org-todo-line-regexp org-todo-line-regexp) | ||
| 25550 | (setq-default org-deadline-line-regexp org-deadline-line-regexp) | ||
| 25551 | (setq-default org-done-keywords org-done-keywords) | ||
| 25552 | (setq-default org-maybe-keyword-time-regexp org-maybe-keyword-time-regexp) | ||
| 25553 | (let* ((opt-plist (org-combine-plists (org-default-export-plist) | ||
| 25554 | ext-plist | ||
| 25555 | (org-infile-export-plist))) | ||
| 25556 | |||
| 25557 | (style (plist-get opt-plist :style)) | ||
| 25558 | (html-extension (plist-get opt-plist :html-extension)) | ||
| 25559 | (link-validate (plist-get opt-plist :link-validation-function)) | ||
| 25560 | valid thetoc have-headings first-heading-pos | ||
| 25561 | (odd org-odd-levels-only) | ||
| 25562 | (region-p (org-region-active-p)) | ||
| 25563 | (subtree-p | ||
| 25564 | (when region-p | ||
| 25565 | (save-excursion | ||
| 25566 | (goto-char (region-beginning)) | ||
| 25567 | (and (org-at-heading-p) | ||
| 25568 | (>= (org-end-of-subtree t t) (region-end)))))) | ||
| 25569 | ;; The following two are dynamically scoped into other | ||
| 25570 | ;; routines below. | ||
| 25571 | (org-current-export-dir | ||
| 25572 | (or pub-dir (org-export-directory :html opt-plist))) | ||
| 25573 | (org-current-export-file buffer-file-name) | ||
| 25574 | (level 0) (line "") (origline "") txt todo | ||
| 25575 | (umax nil) | ||
| 25576 | (umax-toc nil) | ||
| 25577 | (filename (if to-buffer nil | ||
| 25578 | (expand-file-name | ||
| 25579 | (concat | ||
| 25580 | (file-name-sans-extension | ||
| 25581 | (or (and subtree-p | ||
| 25582 | (org-entry-get (region-beginning) | ||
| 25583 | "EXPORT_FILE_NAME" t)) | ||
| 25584 | (file-name-nondirectory buffer-file-name))) | ||
| 25585 | "." html-extension) | ||
| 25586 | (file-name-as-directory | ||
| 25587 | (or pub-dir (org-export-directory :html opt-plist)))))) | ||
| 25588 | (current-dir (if buffer-file-name | ||
| 25589 | (file-name-directory buffer-file-name) | ||
| 25590 | default-directory)) | ||
| 25591 | (buffer (if to-buffer | ||
| 25592 | (cond | ||
| 25593 | ((eq to-buffer 'string) (get-buffer-create "*Org HTML Export*")) | ||
| 25594 | (t (get-buffer-create to-buffer))) | ||
| 25595 | (find-file-noselect filename))) | ||
| 25596 | (org-levels-open (make-vector org-level-max nil)) | ||
| 25597 | (date (plist-get opt-plist :date)) | ||
| 25598 | (author (plist-get opt-plist :author)) | ||
| 25599 | (title (or (and subtree-p (org-export-get-title-from-subtree)) | ||
| 25600 | (plist-get opt-plist :title) | ||
| 25601 | (and (not | ||
| 25602 | (plist-get opt-plist :skip-before-1st-heading)) | ||
| 25603 | (org-export-grab-title-from-buffer)) | ||
| 25604 | (and buffer-file-name | ||
| 25605 | (file-name-sans-extension | ||
| 25606 | (file-name-nondirectory buffer-file-name))) | ||
| 25607 | "UNTITLED")) | ||
| 25608 | (html-table-tag (plist-get opt-plist :html-table-tag)) | ||
| 25609 | (quote-re0 (concat "^[ \t]*" org-quote-string "\\>")) | ||
| 25610 | (quote-re (concat "^\\(\\*+\\)\\([ \t]+" org-quote-string "\\>\\)")) | ||
| 25611 | (inquote nil) | ||
| 25612 | (infixed nil) | ||
| 25613 | (in-local-list nil) | ||
| 25614 | (local-list-num nil) | ||
| 25615 | (local-list-indent nil) | ||
| 25616 | (llt org-plain-list-ordered-item-terminator) | ||
| 25617 | (email (plist-get opt-plist :email)) | ||
| 25618 | (language (plist-get opt-plist :language)) | ||
| 25619 | (lang-words nil) | ||
| 25620 | (target-alist nil) tg | ||
| 25621 | (head-count 0) cnt | ||
| 25622 | (start 0) | ||
| 25623 | (coding-system (and (boundp 'buffer-file-coding-system) | ||
| 25624 | buffer-file-coding-system)) | ||
| 25625 | (coding-system-for-write (or org-export-html-coding-system | ||
| 25626 | coding-system)) | ||
| 25627 | (save-buffer-coding-system (or org-export-html-coding-system | ||
| 25628 | coding-system)) | ||
| 25629 | (charset (and coding-system-for-write | ||
| 25630 | (fboundp 'coding-system-get) | ||
| 25631 | (coding-system-get coding-system-for-write | ||
| 25632 | 'mime-charset))) | ||
| 25633 | (region | ||
| 25634 | (buffer-substring | ||
| 25635 | (if region-p (region-beginning) (point-min)) | ||
| 25636 | (if region-p (region-end) (point-max)))) | ||
| 25637 | (lines | ||
| 25638 | (org-split-string | ||
| 25639 | (org-cleaned-string-for-export | ||
| 25640 | region | ||
| 25641 | :emph-multiline t | ||
| 25642 | :for-html t | ||
| 25643 | :skip-before-1st-heading | ||
| 25644 | (plist-get opt-plist :skip-before-1st-heading) | ||
| 25645 | :drawers (plist-get opt-plist :drawers) | ||
| 25646 | :archived-trees | ||
| 25647 | (plist-get opt-plist :archived-trees) | ||
| 25648 | :add-text | ||
| 25649 | (plist-get opt-plist :text) | ||
| 25650 | :LaTeX-fragments | ||
| 25651 | (plist-get opt-plist :LaTeX-fragments)) | ||
| 25652 | "[\r\n]")) | ||
| 25653 | table-open type | ||
| 25654 | table-buffer table-orig-buffer | ||
| 25655 | ind start-is-num starter didclose | ||
| 25656 | rpl path desc descp desc1 desc2 link | ||
| 25657 | ) | ||
| 25658 | |||
| 25659 | (let ((inhibit-read-only t)) | ||
| 25660 | (org-unmodified | ||
| 25661 | (remove-text-properties (point-min) (point-max) | ||
| 25662 | '(:org-license-to-kill t)))) | ||
| 25663 | |||
| 25664 | (message "Exporting...") | ||
| 25665 | |||
| 25666 | (setq org-min-level (org-get-min-level lines)) | ||
| 25667 | (setq org-last-level org-min-level) | ||
| 25668 | (org-init-section-numbers) | ||
| 25669 | |||
| 25670 | (cond | ||
| 25671 | ((and date (string-match "%" date)) | ||
| 25672 | (setq date (format-time-string date (current-time)))) | ||
| 25673 | (date) | ||
| 25674 | (t (setq date (format-time-string "%Y/%m/%d %X" (current-time))))) | ||
| 25675 | |||
| 25676 | ;; Get the language-dependent settings | ||
| 25677 | (setq lang-words (or (assoc language org-export-language-setup) | ||
| 25678 | (assoc "en" org-export-language-setup))) | ||
| 25679 | |||
| 25680 | ;; Switch to the output buffer | ||
| 25681 | (set-buffer buffer) | ||
| 25682 | (let ((inhibit-read-only t)) (erase-buffer)) | ||
| 25683 | (fundamental-mode) | ||
| 25684 | |||
| 25685 | (and (fboundp 'set-buffer-file-coding-system) | ||
| 25686 | (set-buffer-file-coding-system coding-system-for-write)) | ||
| 25687 | |||
| 25688 | (let ((case-fold-search nil) | ||
| 25689 | (org-odd-levels-only odd)) | ||
| 25690 | ;; create local variables for all options, to make sure all called | ||
| 25691 | ;; functions get the correct information | ||
| 25692 | (mapc (lambda (x) | ||
| 25693 | (set (make-local-variable (cdr x)) | ||
| 25694 | (plist-get opt-plist (car x)))) | ||
| 25695 | org-export-plist-vars) | ||
| 25696 | (setq umax (if arg (prefix-numeric-value arg) | ||
| 25697 | org-export-headline-levels)) | ||
| 25698 | (setq umax-toc (if (integerp org-export-with-toc) | ||
| 25699 | (min org-export-with-toc umax) | ||
| 25700 | umax)) | ||
| 25701 | (unless body-only | ||
| 25702 | ;; File header | ||
| 25703 | (insert (format | ||
| 25704 | "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" | ||
| 25705 | \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"> | ||
| 25706 | <html xmlns=\"http://www.w3.org/1999/xhtml\" | ||
| 25707 | lang=\"%s\" xml:lang=\"%s\"> | ||
| 25708 | <head> | ||
| 25709 | <title>%s</title> | ||
| 25710 | <meta http-equiv=\"Content-Type\" content=\"text/html;charset=%s\"/> | ||
| 25711 | <meta name=\"generator\" content=\"Org-mode\"/> | ||
| 25712 | <meta name=\"generated\" content=\"%s\"/> | ||
| 25713 | <meta name=\"author\" content=\"%s\"/> | ||
| 25714 | %s | ||
| 25715 | </head><body> | ||
| 25716 | " | ||
| 25717 | language language (org-html-expand title) | ||
| 25718 | (or charset "iso-8859-1") date author style)) | ||
| 25719 | |||
| 25720 | (insert (or (plist-get opt-plist :preamble) "")) | ||
| 25721 | |||
| 25722 | (when (plist-get opt-plist :auto-preamble) | ||
| 25723 | (if title (insert (format org-export-html-title-format | ||
| 25724 | (org-html-expand title)))))) | ||
| 25725 | |||
| 25726 | (if (and org-export-with-toc (not body-only)) | ||
| 25727 | (progn | ||
| 25728 | (push (format "<h%d>%s</h%d>\n" | ||
| 25729 | org-export-html-toplevel-hlevel | ||
| 25730 | (nth 3 lang-words) | ||
| 25731 | org-export-html-toplevel-hlevel) | ||
| 25732 | thetoc) | ||
| 25733 | (push "<ul>\n<li>" thetoc) | ||
| 25734 | (setq lines | ||
| 25735 | (mapcar '(lambda (line) | ||
| 25736 | (if (string-match org-todo-line-regexp line) | ||
| 25737 | ;; This is a headline | ||
| 25738 | (progn | ||
| 25739 | (setq have-headings t) | ||
| 25740 | (setq level (- (match-end 1) (match-beginning 1)) | ||
| 25741 | level (org-tr-level level) | ||
| 25742 | txt (save-match-data | ||
| 25743 | (org-html-expand | ||
| 25744 | (org-export-cleanup-toc-line | ||
| 25745 | (match-string 3 line)))) | ||
| 25746 | todo | ||
| 25747 | (or (and org-export-mark-todo-in-toc | ||
| 25748 | (match-beginning 2) | ||
| 25749 | (not (member (match-string 2 line) | ||
| 25750 | org-done-keywords))) | ||
| 25751 | ; TODO, not DONE | ||
| 25752 | (and org-export-mark-todo-in-toc | ||
| 25753 | (= level umax-toc) | ||
| 25754 | (org-search-todo-below | ||
| 25755 | line lines level)))) | ||
| 25756 | (if (string-match | ||
| 25757 | (org-re "[ \t]+:\\([[:alnum:]_@:]+\\):[ \t]*$") txt) | ||
| 25758 | (setq txt (replace-match " <span class=\"tag\"> \\1</span>" t nil txt))) | ||
| 25759 | (if (string-match quote-re0 txt) | ||
| 25760 | (setq txt (replace-match "" t t txt))) | ||
| 25761 | (if org-export-with-section-numbers | ||
| 25762 | (setq txt (concat (org-section-number level) | ||
| 25763 | " " txt))) | ||
| 25764 | (if (<= level (max umax umax-toc)) | ||
| 25765 | (setq head-count (+ head-count 1))) | ||
| 25766 | (if (<= level umax-toc) | ||
| 25767 | (progn | ||
| 25768 | (if (> level org-last-level) | ||
| 25769 | (progn | ||
| 25770 | (setq cnt (- level org-last-level)) | ||
| 25771 | (while (>= (setq cnt (1- cnt)) 0) | ||
| 25772 | (push "\n<ul>\n<li>" thetoc)) | ||
| 25773 | (push "\n" thetoc))) | ||
| 25774 | (if (< level org-last-level) | ||
| 25775 | (progn | ||
| 25776 | (setq cnt (- org-last-level level)) | ||
| 25777 | (while (>= (setq cnt (1- cnt)) 0) | ||
| 25778 | (push "</li>\n</ul>" thetoc)) | ||
| 25779 | (push "\n" thetoc))) | ||
| 25780 | ;; Check for targets | ||
| 25781 | (while (string-match org-target-regexp line) | ||
| 25782 | (setq tg (match-string 1 line) | ||
| 25783 | line (replace-match | ||
| 25784 | (concat "@<span class=\"target\">" tg "@</span> ") | ||
| 25785 | t t line)) | ||
| 25786 | (push (cons (org-solidify-link-text tg) | ||
| 25787 | (format "sec-%d" head-count)) | ||
| 25788 | target-alist)) | ||
| 25789 | (while (string-match "<\\(<\\)+\\|>\\(>\\)+" txt) | ||
| 25790 | (setq txt (replace-match "" t t txt))) | ||
| 25791 | (push | ||
| 25792 | (format | ||
| 25793 | (if todo | ||
| 25794 | "</li>\n<li><a href=\"#sec-%d\"><span class=\"todo\">%s</span></a>" | ||
| 25795 | "</li>\n<li><a href=\"#sec-%d\">%s</a>") | ||
| 25796 | head-count txt) thetoc) | ||
| 25797 | |||
| 25798 | (setq org-last-level level)) | ||
| 25799 | ))) | ||
| 25800 | line) | ||
| 25801 | lines)) | ||
| 25802 | (while (> org-last-level (1- org-min-level)) | ||
| 25803 | (setq org-last-level (1- org-last-level)) | ||
| 25804 | (push "</li>\n</ul>\n" thetoc)) | ||
| 25805 | (setq thetoc (if have-headings (nreverse thetoc) nil)))) | ||
| 25806 | |||
| 25807 | (setq head-count 0) | ||
| 25808 | (org-init-section-numbers) | ||
| 25809 | |||
| 25810 | (while (setq line (pop lines) origline line) | ||
| 25811 | (catch 'nextline | ||
| 25812 | |||
| 25813 | ;; end of quote section? | ||
| 25814 | (when (and inquote (string-match "^\\*+ " line)) | ||
| 25815 | (insert "</pre>\n") | ||
| 25816 | (setq inquote nil)) | ||
| 25817 | ;; inside a quote section? | ||
| 25818 | (when inquote | ||
| 25819 | (insert (org-html-protect line) "\n") | ||
| 25820 | (throw 'nextline nil)) | ||
| 25821 | |||
| 25822 | ;; verbatim lines | ||
| 25823 | (when (and org-export-with-fixed-width | ||
| 25824 | (string-match "^[ \t]*:\\(.*\\)" line)) | ||
| 25825 | (when (not infixed) | ||
| 25826 | (setq infixed t) | ||
| 25827 | (insert "<pre>\n")) | ||
| 25828 | (insert (org-html-protect (match-string 1 line)) "\n") | ||
| 25829 | (when (and lines | ||
| 25830 | (not (string-match "^[ \t]*\\(:.*\\)" | ||
| 25831 | (car lines)))) | ||
| 25832 | (setq infixed nil) | ||
| 25833 | (insert "</pre>\n")) | ||
| 25834 | (throw 'nextline nil)) | ||
| 25835 | |||
| 25836 | ;; Protected HTML | ||
| 25837 | (when (get-text-property 0 'org-protected line) | ||
| 25838 | (let (par) | ||
| 25839 | (when (re-search-backward | ||
| 25840 | "\\(<p>\\)\\([ \t\r\n]*\\)\\=" (- (point) 100) t) | ||
| 25841 | (setq par (match-string 1)) | ||
| 25842 | (replace-match "\\2\n")) | ||
| 25843 | (insert line "\n") | ||
| 25844 | (while (and lines | ||
| 25845 | (or (= (length (car lines)) 0) | ||
| 25846 | (get-text-property 0 'org-protected (car lines)))) | ||
| 25847 | (insert (pop lines) "\n")) | ||
| 25848 | (and par (insert "<p>\n"))) | ||
| 25849 | (throw 'nextline nil)) | ||
| 25850 | |||
| 25851 | ;; Horizontal line | ||
| 25852 | (when (string-match "^[ \t]*-\\{5,\\}[ \t]*$" line) | ||
| 25853 | (insert "\n<hr/>\n") | ||
| 25854 | (throw 'nextline nil)) | ||
| 25855 | |||
| 25856 | ;; make targets to anchors | ||
| 25857 | (while (string-match "<<<?\\([^<>]*\\)>>>?\\((INVISIBLE)\\)?[ \t]*\n?" line) | ||
| 25858 | (cond | ||
| 25859 | ((match-end 2) | ||
| 25860 | (setq line (replace-match | ||
| 25861 | (concat "@<a name=\"" | ||
| 25862 | (org-solidify-link-text (match-string 1 line)) | ||
| 25863 | "\">\\nbsp@</a>") | ||
| 25864 | t t line))) | ||
| 25865 | ((and org-export-with-toc (equal (string-to-char line) ?*)) | ||
| 25866 | (setq line (replace-match | ||
| 25867 | (concat "@<span class=\"target\">" (match-string 1 line) "@</span> ") | ||
| 25868 | ; (concat "@<i>" (match-string 1 line) "@</i> ") | ||
| 25869 | t t line))) | ||
| 25870 | (t | ||
| 25871 | (setq line (replace-match | ||
| 25872 | (concat "@<a name=\"" | ||
| 25873 | (org-solidify-link-text (match-string 1 line)) | ||
| 25874 | "\" class=\"target\">" (match-string 1 line) "@</a> ") | ||
| 25875 | t t line))))) | ||
| 25876 | |||
| 25877 | (setq line (org-html-handle-time-stamps line)) | ||
| 25878 | |||
| 25879 | ;; replace "&" by "&", "<" and ">" by "<" and ">" | ||
| 25880 | ;; handle @<..> HTML tags (replace "@>..<" by "<..>") | ||
| 25881 | ;; Also handle sub_superscripts and checkboxes | ||
| 25882 | (or (string-match org-table-hline-regexp line) | ||
| 25883 | (setq line (org-html-expand line))) | ||
| 25884 | |||
| 25885 | ;; Format the links | ||
| 25886 | (setq start 0) | ||
| 25887 | (while (string-match org-bracket-link-analytic-regexp line start) | ||
| 25888 | (setq start (match-beginning 0)) | ||
| 25889 | (setq type (if (match-end 2) (match-string 2 line) "internal")) | ||
| 25890 | (setq path (match-string 3 line)) | ||
| 25891 | (setq desc1 (if (match-end 5) (match-string 5 line)) | ||
| 25892 | desc2 (if (match-end 2) (concat type ":" path) path) | ||
| 25893 | descp (and desc1 (not (equal desc1 desc2))) | ||
| 25894 | desc (or desc1 desc2)) | ||
| 25895 | ;; Make an image out of the description if that is so wanted | ||
| 25896 | (when (and descp (org-file-image-p desc)) | ||
| 25897 | (save-match-data | ||
| 25898 | (if (string-match "^file:" desc) | ||
| 25899 | (setq desc (substring desc (match-end 0))))) | ||
| 25900 | (setq desc (concat "<img src=\"" desc "\"/>"))) | ||
| 25901 | ;; FIXME: do we need to unescape here somewhere? | ||
| 25902 | (cond | ||
| 25903 | ((equal type "internal") | ||
| 25904 | (setq rpl | ||
| 25905 | (concat | ||
| 25906 | "<a href=\"#" | ||
| 25907 | (org-solidify-link-text | ||
| 25908 | (save-match-data (org-link-unescape path)) target-alist) | ||
| 25909 | "\">" desc "</a>"))) | ||
| 25910 | ((member type '("http" "https")) | ||
| 25911 | ;; standard URL, just check if we need to inline an image | ||
| 25912 | (if (and (or (eq t org-export-html-inline-images) | ||
| 25913 | (and org-export-html-inline-images (not descp))) | ||
| 25914 | (org-file-image-p path)) | ||
| 25915 | (setq rpl (concat "<img src=\"" type ":" path "\"/>")) | ||
| 25916 | (setq link (concat type ":" path)) | ||
| 25917 | (setq rpl (concat "<a href=\"" link "\">" desc "</a>")))) | ||
| 25918 | ((member type '("ftp" "mailto" "news")) | ||
| 25919 | ;; standard URL | ||
| 25920 | (setq link (concat type ":" path)) | ||
| 25921 | (setq rpl (concat "<a href=\"" link "\">" desc "</a>"))) | ||
| 25922 | ((string= type "file") | ||
| 25923 | ;; FILE link | ||
| 25924 | (let* ((filename path) | ||
| 25925 | (abs-p (file-name-absolute-p filename)) | ||
| 25926 | thefile file-is-image-p search) | ||
| 25927 | (save-match-data | ||
| 25928 | (if (string-match "::\\(.*\\)" filename) | ||
| 25929 | (setq search (match-string 1 filename) | ||
| 25930 | filename (replace-match "" t nil filename))) | ||
| 25931 | (setq valid | ||
| 25932 | (if (functionp link-validate) | ||
| 25933 | (funcall link-validate filename current-dir) | ||
| 25934 | t)) | ||
| 25935 | (setq file-is-image-p (org-file-image-p filename)) | ||
| 25936 | (setq thefile (if abs-p (expand-file-name filename) filename)) | ||
| 25937 | (when (and org-export-html-link-org-files-as-html | ||
| 25938 | (string-match "\\.org$" thefile)) | ||
| 25939 | (setq thefile (concat (substring thefile 0 | ||
| 25940 | (match-beginning 0)) | ||
| 25941 | "." html-extension)) | ||
| 25942 | (if (and search | ||
| 25943 | ;; make sure this is can be used as target search | ||
| 25944 | (not (string-match "^[0-9]*$" search)) | ||
| 25945 | (not (string-match "^\\*" search)) | ||
| 25946 | (not (string-match "^/.*/$" search))) | ||
| 25947 | (setq thefile (concat thefile "#" | ||
| 25948 | (org-solidify-link-text | ||
| 25949 | (org-link-unescape search))))) | ||
| 25950 | (when (string-match "^file:" desc) | ||
| 25951 | (setq desc (replace-match "" t t desc)) | ||
| 25952 | (if (string-match "\\.org$" desc) | ||
| 25953 | (setq desc (replace-match "" t t desc)))))) | ||
| 25954 | (setq rpl (if (and file-is-image-p | ||
| 25955 | (or (eq t org-export-html-inline-images) | ||
| 25956 | (and org-export-html-inline-images | ||
| 25957 | (not descp)))) | ||
| 25958 | (concat "<img src=\"" thefile "\"/>") | ||
| 25959 | (concat "<a href=\"" thefile "\">" desc "</a>"))) | ||
| 25960 | (if (not valid) (setq rpl desc)))) | ||
| 25961 | ((member type '("bbdb" "vm" "wl" "mhe" "rmail" "gnus" "shell" "info" "elisp")) | ||
| 25962 | (setq rpl (concat "<i><" type ":" | ||
| 25963 | (save-match-data (org-link-unescape path)) | ||
| 25964 | "></i>")))) | ||
| 25965 | (setq line (replace-match rpl t t line) | ||
| 25966 | start (+ start (length rpl)))) | ||
| 25967 | |||
| 25968 | ;; TODO items | ||
| 25969 | (if (and (string-match org-todo-line-regexp line) | ||
| 25970 | (match-beginning 2)) | ||
| 25971 | |||
| 25972 | (setq line | ||
| 25973 | (concat (substring line 0 (match-beginning 2)) | ||
| 25974 | "<span class=\"" | ||
| 25975 | (if (member (match-string 2 line) | ||
| 25976 | org-done-keywords) | ||
| 25977 | "done" "todo") | ||
| 25978 | "\">" (match-string 2 line) | ||
| 25979 | "</span>" (substring line (match-end 2))))) | ||
| 25980 | |||
| 25981 | ;; Does this contain a reference to a footnote? | ||
| 25982 | (when org-export-with-footnotes | ||
| 25983 | (setq start 0) | ||
| 25984 | (while (string-match "\\([^* \t].*?\\)\\[\\([0-9]+\\)\\]" line start) | ||
| 25985 | (if (get-text-property (match-beginning 2) 'org-protected line) | ||
| 25986 | (setq start (match-end 2)) | ||
| 25987 | (let ((n (match-string 2 line))) | ||
| 25988 | (setq line | ||
| 25989 | (replace-match | ||
| 25990 | (format | ||
| 25991 | "%s<sup><a class=\"footref\" name=\"fnr.%s\" href=\"#fn.%s\">%s</a></sup>" | ||
| 25992 | (match-string 1 line) n n n) | ||
| 25993 | t t line)))))) | ||
| 25994 | |||
| 25995 | (cond | ||
| 25996 | ((string-match "^\\(\\*+\\)[ \t]+\\(.*\\)" line) | ||
| 25997 | ;; This is a headline | ||
| 25998 | (setq level (org-tr-level (- (match-end 1) (match-beginning 1))) | ||
| 25999 | txt (match-string 2 line)) | ||
| 26000 | (if (string-match quote-re0 txt) | ||
| 26001 | (setq txt (replace-match "" t t txt))) | ||
| 26002 | (if (<= level (max umax umax-toc)) | ||
| 26003 | (setq head-count (+ head-count 1))) | ||
| 26004 | (when in-local-list | ||
| 26005 | ;; Close any local lists before inserting a new header line | ||
| 26006 | (while local-list-num | ||
| 26007 | (org-close-li) | ||
| 26008 | (insert (if (car local-list-num) "</ol>\n" "</ul>")) | ||
| 26009 | (pop local-list-num)) | ||
| 26010 | (setq local-list-indent nil | ||
| 26011 | in-local-list nil)) | ||
| 26012 | (setq first-heading-pos (or first-heading-pos (point))) | ||
| 26013 | (org-html-level-start level txt umax | ||
| 26014 | (and org-export-with-toc (<= level umax)) | ||
| 26015 | head-count) | ||
| 26016 | ;; QUOTES | ||
| 26017 | (when (string-match quote-re line) | ||
| 26018 | (insert "<pre>") | ||
| 26019 | (setq inquote t))) | ||
| 26020 | |||
| 26021 | ((and org-export-with-tables | ||
| 26022 | (string-match "^\\([ \t]*\\)\\(|\\|\\+-+\\+\\)" line)) | ||
| 26023 | (if (not table-open) | ||
| 26024 | ;; New table starts | ||
| 26025 | (setq table-open t table-buffer nil table-orig-buffer nil)) | ||
| 26026 | ;; Accumulate lines | ||
| 26027 | (setq table-buffer (cons line table-buffer) | ||
| 26028 | table-orig-buffer (cons origline table-orig-buffer)) | ||
| 26029 | (when (or (not lines) | ||
| 26030 | (not (string-match "^\\([ \t]*\\)\\(|\\|\\+-+\\+\\)" | ||
| 26031 | (car lines)))) | ||
| 26032 | (setq table-open nil | ||
| 26033 | table-buffer (nreverse table-buffer) | ||
| 26034 | table-orig-buffer (nreverse table-orig-buffer)) | ||
| 26035 | (org-close-par-maybe) | ||
| 26036 | (insert (org-format-table-html table-buffer table-orig-buffer)))) | ||
| 26037 | (t | ||
| 26038 | ;; Normal lines | ||
| 26039 | (when (string-match | ||
| 26040 | (cond | ||
| 26041 | ((eq llt t) "^\\([ \t]*\\)\\(\\([-+*] \\)\\|\\([0-9]+[.)]\\) \\)?\\( *[^ \t\n\r]\\|[ \t]*$\\)") | ||
| 26042 | ((= llt ?.) "^\\([ \t]*\\)\\(\\([-+*] \\)\\|\\([0-9]+\\.\\) \\)?\\( *[^ \t\n\r]\\|[ \t]*$\\)") | ||
| 26043 | ((= llt ?\)) "^\\([ \t]*\\)\\(\\([-+*] \\)\\|\\([0-9]+)\\) \\)?\\( *[^ \t\n\r]\\|[ \t]*$\\)") | ||
| 26044 | (t (error "Invalid value of `org-plain-list-ordered-item-terminator'"))) | ||
| 26045 | line) | ||
| 26046 | (setq ind (org-get-string-indentation line) | ||
| 26047 | start-is-num (match-beginning 4) | ||
| 26048 | starter (if (match-beginning 2) | ||
| 26049 | (substring (match-string 2 line) 0 -1)) | ||
| 26050 | line (substring line (match-beginning 5))) | ||
| 26051 | (unless (string-match "[^ \t]" line) | ||
| 26052 | ;; empty line. Pretend indentation is large. | ||
| 26053 | (setq ind (if org-empty-line-terminates-plain-lists | ||
| 26054 | 0 | ||
| 26055 | (1+ (or (car local-list-indent) 1))))) | ||
| 26056 | (setq didclose nil) | ||
| 26057 | (while (and in-local-list | ||
| 26058 | (or (and (= ind (car local-list-indent)) | ||
| 26059 | (not starter)) | ||
| 26060 | (< ind (car local-list-indent)))) | ||
| 26061 | (setq didclose t) | ||
| 26062 | (org-close-li) | ||
| 26063 | (insert (if (car local-list-num) "</ol>\n" "</ul>")) | ||
| 26064 | (pop local-list-num) (pop local-list-indent) | ||
| 26065 | (setq in-local-list local-list-indent)) | ||
| 26066 | (cond | ||
| 26067 | ((and starter | ||
| 26068 | (or (not in-local-list) | ||
| 26069 | (> ind (car local-list-indent)))) | ||
| 26070 | ;; Start new (level of) list | ||
| 26071 | (org-close-par-maybe) | ||
| 26072 | (insert (if start-is-num "<ol>\n<li>\n" "<ul>\n<li>\n")) | ||
| 26073 | (push start-is-num local-list-num) | ||
| 26074 | (push ind local-list-indent) | ||
| 26075 | (setq in-local-list t)) | ||
| 26076 | (starter | ||
| 26077 | ;; continue current list | ||
| 26078 | (org-close-li) | ||
| 26079 | (insert "<li>\n")) | ||
| 26080 | (didclose | ||
| 26081 | ;; we did close a list, normal text follows: need <p> | ||
| 26082 | (org-open-par))) | ||
| 26083 | (if (string-match "^[ \t]*\\[\\([X ]\\)\\]" line) | ||
| 26084 | (setq line | ||
| 26085 | (replace-match | ||
| 26086 | (if (equal (match-string 1 line) "X") | ||
| 26087 | "<b>[X]</b>" | ||
| 26088 | "<b>[<span style=\"visibility:hidden;\">X</span>]</b>") | ||
| 26089 | t t line)))) | ||
| 26090 | |||
| 26091 | ;; Empty lines start a new paragraph. If hand-formatted lists | ||
| 26092 | ;; are not fully interpreted, lines starting with "-", "+", "*" | ||
| 26093 | ;; also start a new paragraph. | ||
| 26094 | (if (string-match "^ [-+*]-\\|^[ \t]*$" line) (org-open-par)) | ||
| 26095 | |||
| 26096 | ;; Is this the start of a footnote? | ||
| 26097 | (when org-export-with-footnotes | ||
| 26098 | (when (string-match "^[ \t]*\\[\\([0-9]+\\)\\]" line) | ||
| 26099 | (org-close-par-maybe) | ||
| 26100 | (let ((n (match-string 1 line))) | ||
| 26101 | (setq line (replace-match | ||
| 26102 | (format "<p class=\"footnote\"><sup><a class=\"footnum\" name=\"fn.%s\" href=\"#fnr.%s\">%s</a></sup>" n n n) t t line))))) | ||
| 26103 | |||
| 26104 | ;; Check if the line break needs to be conserved | ||
| 26105 | (cond | ||
| 26106 | ((string-match "\\\\\\\\[ \t]*$" line) | ||
| 26107 | (setq line (replace-match "<br/>" t t line))) | ||
| 26108 | (org-export-preserve-breaks | ||
| 26109 | (setq line (concat line "<br/>")))) | ||
| 26110 | |||
| 26111 | (insert line "\n"))))) | ||
| 26112 | |||
| 26113 | ;; Properly close all local lists and other lists | ||
| 26114 | (when inquote (insert "</pre>\n")) | ||
| 26115 | (when in-local-list | ||
| 26116 | ;; Close any local lists before inserting a new header line | ||
| 26117 | (while local-list-num | ||
| 26118 | (org-close-li) | ||
| 26119 | (insert (if (car local-list-num) "</ol>\n" "</ul>\n")) | ||
| 26120 | (pop local-list-num)) | ||
| 26121 | (setq local-list-indent nil | ||
| 26122 | in-local-list nil)) | ||
| 26123 | (org-html-level-start 1 nil umax | ||
| 26124 | (and org-export-with-toc (<= level umax)) | ||
| 26125 | head-count) | ||
| 26126 | |||
| 26127 | (unless body-only | ||
| 26128 | (when (plist-get opt-plist :auto-postamble) | ||
| 26129 | (insert "<div id=\"postamble\">") | ||
| 26130 | (when (and org-export-author-info author) | ||
| 26131 | (insert "<p class=\"author\"> " | ||
| 26132 | (nth 1 lang-words) ": " author "\n") | ||
| 26133 | (when email | ||
| 26134 | (if (listp (split-string email ",+ *")) | ||
| 26135 | (mapc (lambda(e) | ||
| 26136 | (insert "<a href=\"mailto:" e "\"><" | ||
| 26137 | e "></a>\n")) | ||
| 26138 | (split-string email ",+ *")) | ||
| 26139 | (insert "<a href=\"mailto:" email "\"><" | ||
| 26140 | email "></a>\n"))) | ||
| 26141 | (insert "</p>\n")) | ||
| 26142 | (when (and date org-export-time-stamp-file) | ||
| 26143 | (insert "<p class=\"date\"> " | ||
| 26144 | (nth 2 lang-words) ": " | ||
| 26145 | date "</p>\n")) | ||
| 26146 | (insert "</div>")) | ||
| 26147 | |||
| 26148 | (if org-export-html-with-timestamp | ||
| 26149 | (insert org-export-html-html-helper-timestamp)) | ||
| 26150 | (insert (or (plist-get opt-plist :postamble) "")) | ||
| 26151 | (insert "</body>\n</html>\n")) | ||
| 26152 | |||
| 26153 | (normal-mode) | ||
| 26154 | (if (eq major-mode default-major-mode) (html-mode)) | ||
| 26155 | |||
| 26156 | ;; insert the table of contents | ||
| 26157 | (goto-char (point-min)) | ||
| 26158 | (when thetoc | ||
| 26159 | (if (or (re-search-forward | ||
| 26160 | "<p>\\s-*\\[TABLE-OF-CONTENTS\\]\\s-*</p>" nil t) | ||
| 26161 | (re-search-forward | ||
| 26162 | "\\[TABLE-OF-CONTENTS\\]" nil t)) | ||
| 26163 | (progn | ||
| 26164 | (goto-char (match-beginning 0)) | ||
| 26165 | (replace-match "")) | ||
| 26166 | (goto-char first-heading-pos) | ||
| 26167 | (when (looking-at "\\s-*</p>") | ||
| 26168 | (goto-char (match-end 0)) | ||
| 26169 | (insert "\n"))) | ||
| 26170 | (insert "<div id=\"table-of-contents\">\n") | ||
| 26171 | (mapc 'insert thetoc) | ||
| 26172 | (insert "</div>\n")) | ||
| 26173 | ;; remove empty paragraphs and lists | ||
| 26174 | (goto-char (point-min)) | ||
| 26175 | (while (re-search-forward "<p>[ \r\n\t]*</p>" nil t) | ||
| 26176 | (replace-match "")) | ||
| 26177 | (goto-char (point-min)) | ||
| 26178 | (while (re-search-forward "<li>[ \r\n\t]*</li>\n?" nil t) | ||
| 26179 | (replace-match "")) | ||
| 26180 | (goto-char (point-min)) | ||
| 26181 | (while (re-search-forward "</ul>\\s-*<ul>\n?" nil t) | ||
| 26182 | (replace-match "")) | ||
| 26183 | ;; Convert whitespace place holders | ||
| 26184 | (goto-char (point-min)) | ||
| 26185 | (let (beg end n) | ||
| 26186 | (while (setq beg (next-single-property-change (point) 'org-whitespace)) | ||
| 26187 | (setq n (get-text-property beg 'org-whitespace) | ||
| 26188 | end (next-single-property-change beg 'org-whitespace)) | ||
| 26189 | (goto-char beg) | ||
| 26190 | (delete-region beg end) | ||
| 26191 | (insert (format "<span style=\"visibility:hidden;\">%s</span>" | ||
| 26192 | (make-string n ?x))))) | ||
| 26193 | (or to-buffer (save-buffer)) | ||
| 26194 | (goto-char (point-min)) | ||
| 26195 | (message "Exporting... done") | ||
| 26196 | (if (eq to-buffer 'string) | ||
| 26197 | (prog1 (buffer-substring (point-min) (point-max)) | ||
| 26198 | (kill-buffer (current-buffer))) | ||
| 26199 | (current-buffer))))) | ||
| 26200 | |||
| 26201 | (defvar org-table-colgroup-info nil) | ||
| 26202 | (defun org-format-table-ascii (lines) | ||
| 26203 | "Format a table for ascii export." | ||
| 26204 | (if (stringp lines) | ||
| 26205 | (setq lines (org-split-string lines "\n"))) | ||
| 26206 | (if (not (string-match "^[ \t]*|" (car lines))) | ||
| 26207 | ;; Table made by table.el - test for spanning | ||
| 26208 | lines | ||
| 26209 | |||
| 26210 | ;; A normal org table | ||
| 26211 | ;; Get rid of hlines at beginning and end | ||
| 26212 | (if (string-match "^[ \t]*|-" (car lines)) (setq lines (cdr lines))) | ||
| 26213 | (setq lines (nreverse lines)) | ||
| 26214 | (if (string-match "^[ \t]*|-" (car lines)) (setq lines (cdr lines))) | ||
| 26215 | (setq lines (nreverse lines)) | ||
| 26216 | (when org-export-table-remove-special-lines | ||
| 26217 | ;; Check if the table has a marking column. If yes remove the | ||
| 26218 | ;; column and the special lines | ||
| 26219 | (setq lines (org-table-clean-before-export lines))) | ||
| 26220 | ;; Get rid of the vertical lines except for grouping | ||
| 26221 | (let ((vl (org-colgroup-info-to-vline-list org-table-colgroup-info)) | ||
| 26222 | rtn line vl1 start) | ||
| 26223 | (while (setq line (pop lines)) | ||
| 26224 | (if (string-match org-table-hline-regexp line) | ||
| 26225 | (and (string-match "|\\(.*\\)|" line) | ||
| 26226 | (setq line (replace-match " \\1" t nil line))) | ||
| 26227 | (setq start 0 vl1 vl) | ||
| 26228 | (while (string-match "|" line start) | ||
| 26229 | (setq start (match-end 0)) | ||
| 26230 | (or (pop vl1) (setq line (replace-match " " t t line))))) | ||
| 26231 | (push line rtn)) | ||
| 26232 | (nreverse rtn)))) | ||
| 26233 | |||
| 26234 | (defun org-colgroup-info-to-vline-list (info) | ||
| 26235 | (let (vl new last) | ||
| 26236 | (while info | ||
| 26237 | (setq last new new (pop info)) | ||
| 26238 | (if (or (memq last '(:end :startend)) | ||
| 26239 | (memq new '(:start :startend))) | ||
| 26240 | (push t vl) | ||
| 26241 | (push nil vl))) | ||
| 26242 | (setq vl (nreverse vl)) | ||
| 26243 | (and vl (setcar vl nil)) | ||
| 26244 | vl)) | ||
| 26245 | |||
| 26246 | (defun org-format-table-html (lines olines) | ||
| 26247 | "Find out which HTML converter to use and return the HTML code." | ||
| 26248 | (if (stringp lines) | ||
| 26249 | (setq lines (org-split-string lines "\n"))) | ||
| 26250 | (if (string-match "^[ \t]*|" (car lines)) | ||
| 26251 | ;; A normal org table | ||
| 26252 | (org-format-org-table-html lines) | ||
| 26253 | ;; Table made by table.el - test for spanning | ||
| 26254 | (let* ((hlines (delq nil (mapcar | ||
| 26255 | (lambda (x) | ||
| 26256 | (if (string-match "^[ \t]*\\+-" x) x | ||
| 26257 | nil)) | ||
| 26258 | lines))) | ||
| 26259 | (first (car hlines)) | ||
| 26260 | (ll (and (string-match "\\S-+" first) | ||
| 26261 | (match-string 0 first))) | ||
| 26262 | (re (concat "^[ \t]*" (regexp-quote ll))) | ||
| 26263 | (spanning (delq nil (mapcar (lambda (x) (not (string-match re x))) | ||
| 26264 | hlines)))) | ||
| 26265 | (if (and (not spanning) | ||
| 26266 | (not org-export-prefer-native-exporter-for-tables)) | ||
| 26267 | ;; We can use my own converter with HTML conversions | ||
| 26268 | (org-format-table-table-html lines) | ||
| 26269 | ;; Need to use the code generator in table.el, with the original text. | ||
| 26270 | (org-format-table-table-html-using-table-generate-source olines))))) | ||
| 26271 | |||
| 26272 | (defun org-format-org-table-html (lines &optional splice) | ||
| 26273 | "Format a table into HTML." | ||
| 26274 | ;; Get rid of hlines at beginning and end | ||
| 26275 | (if (string-match "^[ \t]*|-" (car lines)) (setq lines (cdr lines))) | ||
| 26276 | (setq lines (nreverse lines)) | ||
| 26277 | (if (string-match "^[ \t]*|-" (car lines)) (setq lines (cdr lines))) | ||
| 26278 | (setq lines (nreverse lines)) | ||
| 26279 | (when org-export-table-remove-special-lines | ||
| 26280 | ;; Check if the table has a marking column. If yes remove the | ||
| 26281 | ;; column and the special lines | ||
| 26282 | (setq lines (org-table-clean-before-export lines))) | ||
| 26283 | |||
| 26284 | (let ((head (and org-export-highlight-first-table-line | ||
| 26285 | (delq nil (mapcar | ||
| 26286 | (lambda (x) (string-match "^[ \t]*|-" x)) | ||
| 26287 | (cdr lines))))) | ||
| 26288 | (nlines 0) fnum i | ||
| 26289 | tbopen line fields html gr colgropen) | ||
| 26290 | (if splice (setq head nil)) | ||
| 26291 | (unless splice (push (if head "<thead>" "<tbody>") html)) | ||
| 26292 | (setq tbopen t) | ||
| 26293 | (while (setq line (pop lines)) | ||
| 26294 | (catch 'next-line | ||
| 26295 | (if (string-match "^[ \t]*|-" line) | ||
| 26296 | (progn | ||
| 26297 | (unless splice | ||
| 26298 | (push (if head "</thead>" "</tbody>") html) | ||
| 26299 | (if lines (push "<tbody>" html) (setq tbopen nil))) | ||
| 26300 | (setq head nil) ;; head ends here, first time around | ||
| 26301 | ;; ignore this line | ||
| 26302 | (throw 'next-line t))) | ||
| 26303 | ;; Break the line into fields | ||
| 26304 | (setq fields (org-split-string line "[ \t]*|[ \t]*")) | ||
| 26305 | (unless fnum (setq fnum (make-vector (length fields) 0))) | ||
| 26306 | (setq nlines (1+ nlines) i -1) | ||
| 26307 | (push (concat "<tr>" | ||
| 26308 | (mapconcat | ||
| 26309 | (lambda (x) | ||
| 26310 | (setq i (1+ i)) | ||
| 26311 | (if (and (< i nlines) | ||
| 26312 | (string-match org-table-number-regexp x)) | ||
| 26313 | (incf (aref fnum i))) | ||
| 26314 | (if head | ||
| 26315 | (concat (car org-export-table-header-tags) x | ||
| 26316 | (cdr org-export-table-header-tags)) | ||
| 26317 | (concat (car org-export-table-data-tags) x | ||
| 26318 | (cdr org-export-table-data-tags)))) | ||
| 26319 | fields "") | ||
| 26320 | "</tr>") | ||
| 26321 | html))) | ||
| 26322 | (unless splice (if tbopen (push "</tbody>" html))) | ||
| 26323 | (unless splice (push "</table>\n" html)) | ||
| 26324 | (setq html (nreverse html)) | ||
| 26325 | (unless splice | ||
| 26326 | ;; Put in col tags with the alignment (unfortuntely often ignored...) | ||
| 26327 | (push (mapconcat | ||
| 26328 | (lambda (x) | ||
| 26329 | (setq gr (pop org-table-colgroup-info)) | ||
| 26330 | (format "%s<col align=\"%s\"></col>%s" | ||
| 26331 | (if (memq gr '(:start :startend)) | ||
| 26332 | (prog1 | ||
| 26333 | (if colgropen "</colgroup>\n<colgroup>" "<colgroup>") | ||
| 26334 | (setq colgropen t)) | ||
| 26335 | "") | ||
| 26336 | (if (> (/ (float x) nlines) org-table-number-fraction) | ||
| 26337 | "right" "left") | ||
| 26338 | (if (memq gr '(:end :startend)) | ||
| 26339 | (progn (setq colgropen nil) "</colgroup>") | ||
| 26340 | ""))) | ||
| 26341 | fnum "") | ||
| 26342 | html) | ||
| 26343 | (if colgropen (setq html (cons (car html) (cons "</colgroup>" (cdr html))))) | ||
| 26344 | (push html-table-tag html)) | ||
| 26345 | (concat (mapconcat 'identity html "\n") "\n"))) | ||
| 26346 | |||
| 26347 | (defun org-table-clean-before-export (lines) | ||
| 26348 | "Check if the table has a marking column. | ||
| 26349 | If yes remove the column and the special lines." | ||
| 26350 | (setq org-table-colgroup-info nil) | ||
| 26351 | (if (memq nil | ||
| 26352 | (mapcar | ||
| 26353 | (lambda (x) (or (string-match "^[ \t]*|-" x) | ||
| 26354 | (string-match "^[ \t]*| *\\([#!$*_^ /]\\) *|" x))) | ||
| 26355 | lines)) | ||
| 26356 | (progn | ||
| 26357 | (setq org-table-clean-did-remove-column nil) | ||
| 26358 | (delq nil | ||
| 26359 | (mapcar | ||
| 26360 | (lambda (x) | ||
| 26361 | (cond | ||
| 26362 | ((string-match "^[ \t]*| */ *|" x) | ||
| 26363 | (setq org-table-colgroup-info | ||
| 26364 | (mapcar (lambda (x) | ||
| 26365 | (cond ((member x '("<" "<")) :start) | ||
| 26366 | ((member x '(">" ">")) :end) | ||
| 26367 | ((member x '("<>" "<>")) :startend) | ||
| 26368 | (t nil))) | ||
| 26369 | (org-split-string x "[ \t]*|[ \t]*"))) | ||
| 26370 | nil) | ||
| 26371 | (t x))) | ||
| 26372 | lines))) | ||
| 26373 | (setq org-table-clean-did-remove-column t) | ||
| 26374 | (delq nil | ||
| 26375 | (mapcar | ||
| 26376 | (lambda (x) | ||
| 26377 | (cond | ||
| 26378 | ((string-match "^[ \t]*| */ *|" x) | ||
| 26379 | (setq org-table-colgroup-info | ||
| 26380 | (mapcar (lambda (x) | ||
| 26381 | (cond ((member x '("<" "<")) :start) | ||
| 26382 | ((member x '(">" ">")) :end) | ||
| 26383 | ((member x '("<>" "<>")) :startend) | ||
| 26384 | (t nil))) | ||
| 26385 | (cdr (org-split-string x "[ \t]*|[ \t]*")))) | ||
| 26386 | nil) | ||
| 26387 | ((string-match "^[ \t]*| *[!_^/] *|" x) | ||
| 26388 | nil) ; ignore this line | ||
| 26389 | ((or (string-match "^\\([ \t]*\\)|-+\\+" x) | ||
| 26390 | (string-match "^\\([ \t]*\\)|[^|]*|" x)) | ||
| 26391 | ;; remove the first column | ||
| 26392 | (replace-match "\\1|" t nil x)))) | ||
| 26393 | lines)))) | ||
| 26394 | |||
| 26395 | (defun org-format-table-table-html (lines) | ||
| 26396 | "Format a table generated by table.el into HTML. | ||
| 26397 | This conversion does *not* use `table-generate-source' from table.el. | ||
| 26398 | This has the advantage that Org-mode's HTML conversions can be used. | ||
| 26399 | But it has the disadvantage, that no cell- or row-spanning is allowed." | ||
| 26400 | (let (line field-buffer | ||
| 26401 | (head org-export-highlight-first-table-line) | ||
| 26402 | fields html empty) | ||
| 26403 | (setq html (concat html-table-tag "\n")) | ||
| 26404 | (while (setq line (pop lines)) | ||
| 26405 | (setq empty " ") | ||
| 26406 | (catch 'next-line | ||
| 26407 | (if (string-match "^[ \t]*\\+-" line) | ||
| 26408 | (progn | ||
| 26409 | (if field-buffer | ||
| 26410 | (progn | ||
| 26411 | (setq | ||
| 26412 | html | ||
| 26413 | (concat | ||
| 26414 | html | ||
| 26415 | "<tr>" | ||
| 26416 | (mapconcat | ||
| 26417 | (lambda (x) | ||
| 26418 | (if (equal x "") (setq x empty)) | ||
| 26419 | (if head | ||
| 26420 | (concat (car org-export-table-header-tags) x | ||
| 26421 | (cdr org-export-table-header-tags)) | ||
| 26422 | (concat (car org-export-table-data-tags) x | ||
| 26423 | (cdr org-export-table-data-tags)))) | ||
| 26424 | field-buffer "\n") | ||
| 26425 | "</tr>\n")) | ||
| 26426 | (setq head nil) | ||
| 26427 | (setq field-buffer nil))) | ||
| 26428 | ;; Ignore this line | ||
| 26429 | (throw 'next-line t))) | ||
| 26430 | ;; Break the line into fields and store the fields | ||
| 26431 | (setq fields (org-split-string line "[ \t]*|[ \t]*")) | ||
| 26432 | (if field-buffer | ||
| 26433 | (setq field-buffer (mapcar | ||
| 26434 | (lambda (x) | ||
| 26435 | (concat x "<br/>" (pop fields))) | ||
| 26436 | field-buffer)) | ||
| 26437 | (setq field-buffer fields)))) | ||
| 26438 | (setq html (concat html "</table>\n")) | ||
| 26439 | html)) | ||
| 26440 | |||
| 26441 | (defun org-format-table-table-html-using-table-generate-source (lines) | ||
| 26442 | "Format a table into html, using `table-generate-source' from table.el. | ||
| 26443 | This has the advantage that cell- or row-spanning is allowed. | ||
| 26444 | But it has the disadvantage, that Org-mode's HTML conversions cannot be used." | ||
| 26445 | (require 'table) | ||
| 26446 | (with-current-buffer (get-buffer-create " org-tmp1 ") | ||
| 26447 | (erase-buffer) | ||
| 26448 | (insert (mapconcat 'identity lines "\n")) | ||
| 26449 | (goto-char (point-min)) | ||
| 26450 | (if (not (re-search-forward "|[^+]" nil t)) | ||
| 26451 | (error "Error processing table")) | ||
| 26452 | (table-recognize-table) | ||
| 26453 | (with-current-buffer (get-buffer-create " org-tmp2 ") (erase-buffer)) | ||
| 26454 | (table-generate-source 'html " org-tmp2 ") | ||
| 26455 | (set-buffer " org-tmp2 ") | ||
| 26456 | (buffer-substring (point-min) (point-max)))) | ||
| 26457 | |||
| 26458 | (defun org-html-handle-time-stamps (s) | ||
| 26459 | "Format time stamps in string S, or remove them." | ||
| 26460 | (catch 'exit | ||
| 26461 | (let (r b) | ||
| 26462 | (while (string-match org-maybe-keyword-time-regexp s) | ||
| 26463 | (if (and (match-end 1) (equal (match-string 1 s) org-clock-string)) | ||
| 26464 | ;; never export CLOCK | ||
| 26465 | (throw 'exit "")) | ||
| 26466 | (or b (setq b (substring s 0 (match-beginning 0)))) | ||
| 26467 | (if (not org-export-with-timestamps) | ||
| 26468 | (setq r (concat r (substring s 0 (match-beginning 0))) | ||
| 26469 | s (substring s (match-end 0))) | ||
| 26470 | (setq r (concat | ||
| 26471 | r (substring s 0 (match-beginning 0)) | ||
| 26472 | (if (match-end 1) | ||
| 26473 | (format "@<span class=\"timestamp-kwd\">%s @</span>" | ||
| 26474 | (match-string 1 s))) | ||
| 26475 | (format " @<span class=\"timestamp\">%s@</span>" | ||
| 26476 | (substring | ||
| 26477 | (org-translate-time (match-string 3 s)) 1 -1))) | ||
| 26478 | s (substring s (match-end 0))))) | ||
| 26479 | ;; Line break if line started and ended with time stamp stuff | ||
| 26480 | (if (not r) | ||
| 26481 | s | ||
| 26482 | (setq r (concat r s)) | ||
| 26483 | (unless (string-match "\\S-" (concat b s)) | ||
| 26484 | (setq r (concat r "@<br/>"))) | ||
| 26485 | r)))) | ||
| 26486 | |||
| 26487 | (defun org-html-protect (s) | ||
| 26488 | ;; convert & to &, < to < and > to > | ||
| 26489 | (let ((start 0)) | ||
| 26490 | (while (string-match "&" s start) | ||
| 26491 | (setq s (replace-match "&" t t s) | ||
| 26492 | start (1+ (match-beginning 0)))) | ||
| 26493 | (while (string-match "<" s) | ||
| 26494 | (setq s (replace-match "<" t t s))) | ||
| 26495 | (while (string-match ">" s) | ||
| 26496 | (setq s (replace-match ">" t t s)))) | ||
| 26497 | s) | ||
| 26498 | |||
| 26499 | (defun org-export-cleanup-toc-line (s) | ||
| 26500 | "Remove tags and time staps from lines going into the toc." | ||
| 26501 | (when (memq org-export-with-tags '(not-in-toc nil)) | ||
| 26502 | (if (string-match (org-re " +:[[:alnum:]_@:]+: *$") s) | ||
| 26503 | (setq s (replace-match "" t t s)))) | ||
| 26504 | (when org-export-remove-timestamps-from-toc | ||
| 26505 | (while (string-match org-maybe-keyword-time-regexp s) | ||
| 26506 | (setq s (replace-match "" t t s)))) | ||
| 26507 | (while (string-match org-bracket-link-regexp s) | ||
| 26508 | (setq s (replace-match (match-string (if (match-end 3) 3 1) s) | ||
| 26509 | t t s))) | ||
| 26510 | s) | ||
| 26511 | |||
| 26512 | (defun org-html-expand (string) | ||
| 26513 | "Prepare STRING for HTML export. Applies all active conversions. | ||
| 26514 | If there are links in the string, don't modify these." | ||
| 26515 | (let* ((re (concat org-bracket-link-regexp "\\|" | ||
| 26516 | (org-re "[ \t]+\\(:[[:alnum:]_@:]+:\\)[ \t]*$"))) | ||
| 26517 | m s l res) | ||
| 26518 | (while (setq m (string-match re string)) | ||
| 26519 | (setq s (substring string 0 m) | ||
| 26520 | l (match-string 0 string) | ||
| 26521 | string (substring string (match-end 0))) | ||
| 26522 | (push (org-html-do-expand s) res) | ||
| 26523 | (push l res)) | ||
| 26524 | (push (org-html-do-expand string) res) | ||
| 26525 | (apply 'concat (nreverse res)))) | ||
| 26526 | |||
| 26527 | (defun org-html-do-expand (s) | ||
| 26528 | "Apply all active conversions to translate special ASCII to HTML." | ||
| 26529 | (setq s (org-html-protect s)) | ||
| 26530 | (if org-export-html-expand | ||
| 26531 | (let ((start 0)) | ||
| 26532 | (while (string-match "@<\\([^&]*\\)>" s) | ||
| 26533 | (setq s (replace-match "<\\1>" t nil s))))) | ||
| 26534 | (if org-export-with-emphasize | ||
| 26535 | (setq s (org-export-html-convert-emphasize s))) | ||
| 26536 | (if org-export-with-special-strings | ||
| 26537 | (setq s (org-export-html-convert-special-strings s))) | ||
| 26538 | (if org-export-with-sub-superscripts | ||
| 26539 | (setq s (org-export-html-convert-sub-super s))) | ||
| 26540 | (if org-export-with-TeX-macros | ||
| 26541 | (let ((start 0) wd ass) | ||
| 26542 | (while (setq start (string-match "\\\\\\([a-zA-Z]+\\)" s start)) | ||
| 26543 | (if (get-text-property (match-beginning 0) 'org-protected s) | ||
| 26544 | (setq start (match-end 0)) | ||
| 26545 | (setq wd (match-string 1 s)) | ||
| 26546 | (if (setq ass (assoc wd org-html-entities)) | ||
| 26547 | (setq s (replace-match (or (cdr ass) | ||
| 26548 | (concat "&" (car ass) ";")) | ||
| 26549 | t t s)) | ||
| 26550 | (setq start (+ start (length wd)))))))) | ||
| 26551 | s) | ||
| 26552 | |||
| 26553 | (defun org-create-multibrace-regexp (left right n) | ||
| 26554 | "Create a regular expression which will match a balanced sexp. | ||
| 26555 | Opening delimiter is LEFT, and closing delimiter is RIGHT, both given | ||
| 26556 | as single character strings. | ||
| 26557 | The regexp returned will match the entire expression including the | ||
| 26558 | delimiters. It will also define a single group which contains the | ||
| 26559 | match except for the outermost delimiters. The maximum depth of | ||
| 26560 | stacked delimiters is N. Escaping delimiters is not possible." | ||
| 26561 | (let* ((nothing (concat "[^" "\\" left "\\" right "]*?")) | ||
| 26562 | (or "\\|") | ||
| 26563 | (re nothing) | ||
| 26564 | (next (concat "\\(?:" nothing left nothing right "\\)+" nothing))) | ||
| 26565 | (while (> n 1) | ||
| 26566 | (setq n (1- n) | ||
| 26567 | re (concat re or next) | ||
| 26568 | next (concat "\\(?:" nothing left next right "\\)+" nothing))) | ||
| 26569 | (concat left "\\(" re "\\)" right))) | ||
| 26570 | |||
| 26571 | (defvar org-match-substring-regexp | ||
| 26572 | (concat | ||
| 26573 | "\\([^\\]\\)\\([_^]\\)\\(" | ||
| 26574 | "\\(" (org-create-multibrace-regexp "{" "}" org-match-sexp-depth) "\\)" | ||
| 26575 | "\\|" | ||
| 26576 | "\\(" (org-create-multibrace-regexp "(" ")" org-match-sexp-depth) "\\)" | ||
| 26577 | "\\|" | ||
| 26578 | "\\(\\(?:\\*\\|[-+]?[^-+*!@#$%^_ \t\r\n,:\"?<>~;./{}=()]+\\)\\)\\)") | ||
| 26579 | "The regular expression matching a sub- or superscript.") | ||
| 26580 | |||
| 26581 | (defvar org-match-substring-with-braces-regexp | ||
| 26582 | (concat | ||
| 26583 | "\\([^\\]\\)\\([_^]\\)\\(" | ||
| 26584 | "\\(" (org-create-multibrace-regexp "{" "}" org-match-sexp-depth) "\\)" | ||
| 26585 | "\\)") | ||
| 26586 | "The regular expression matching a sub- or superscript, forcing braces.") | ||
| 26587 | |||
| 26588 | (defconst org-export-html-special-string-regexps | ||
| 26589 | '(("\\\\-" . "­") | ||
| 26590 | ("---\\([^-]\\)" . "—\\1") | ||
| 26591 | ("--\\([^-]\\)" . "–\\1") | ||
| 26592 | ("\\.\\.\\." . "…")) | ||
| 26593 | "Regular expressions for special string conversion.") | ||
| 26594 | |||
| 26595 | (defun org-export-html-convert-special-strings (string) | ||
| 26596 | "Convert special characters in STRING to HTML." | ||
| 26597 | (let ((all org-export-html-special-string-regexps) | ||
| 26598 | e a re rpl start) | ||
| 26599 | (while (setq a (pop all)) | ||
| 26600 | (setq re (car a) rpl (cdr a) start 0) | ||
| 26601 | (while (string-match re string start) | ||
| 26602 | (if (get-text-property (match-beginning 0) 'org-protected string) | ||
| 26603 | (setq start (match-end 0)) | ||
| 26604 | (setq string (replace-match rpl t nil string))))) | ||
| 26605 | string)) | ||
| 26606 | |||
| 26607 | (defun org-export-html-convert-sub-super (string) | ||
| 26608 | "Convert sub- and superscripts in STRING to HTML." | ||
| 26609 | (let (key c (s 0) (requireb (eq org-export-with-sub-superscripts '{}))) | ||
| 26610 | (while (string-match org-match-substring-regexp string s) | ||
| 26611 | (cond | ||
| 26612 | ((and requireb (match-end 8)) (setq s (match-end 2))) | ||
| 26613 | ((get-text-property (match-beginning 2) 'org-protected string) | ||
| 26614 | (setq s (match-end 2))) | ||
| 26615 | (t | ||
| 26616 | (setq s (match-end 1) | ||
| 26617 | key (if (string= (match-string 2 string) "_") "sub" "sup") | ||
| 26618 | c (or (match-string 8 string) | ||
| 26619 | (match-string 6 string) | ||
| 26620 | (match-string 5 string)) | ||
| 26621 | string (replace-match | ||
| 26622 | (concat (match-string 1 string) | ||
| 26623 | "<" key ">" c "</" key ">") | ||
| 26624 | t t string))))) | ||
| 26625 | (while (string-match "\\\\\\([_^]\\)" string) | ||
| 26626 | (setq string (replace-match (match-string 1 string) t t string))) | ||
| 26627 | string)) | ||
| 26628 | |||
| 26629 | (defun org-export-html-convert-emphasize (string) | ||
| 26630 | "Apply emphasis." | ||
| 26631 | (let ((s 0) rpl) | ||
| 26632 | (while (string-match org-emph-re string s) | ||
| 26633 | (if (not (equal | ||
| 26634 | (substring string (match-beginning 3) (1+ (match-beginning 3))) | ||
| 26635 | (substring string (match-beginning 4) (1+ (match-beginning 4))))) | ||
| 26636 | (setq s (match-beginning 0) | ||
| 26637 | rpl | ||
| 26638 | (concat | ||
| 26639 | (match-string 1 string) | ||
| 26640 | (nth 2 (assoc (match-string 3 string) org-emphasis-alist)) | ||
| 26641 | (match-string 4 string) | ||
| 26642 | (nth 3 (assoc (match-string 3 string) | ||
| 26643 | org-emphasis-alist)) | ||
| 26644 | (match-string 5 string)) | ||
| 26645 | string (replace-match rpl t t string) | ||
| 26646 | s (+ s (- (length rpl) 2))) | ||
| 26647 | (setq s (1+ s)))) | ||
| 26648 | string)) | ||
| 26649 | |||
| 26650 | (defvar org-par-open nil) | ||
| 26651 | (defun org-open-par () | ||
| 26652 | "Insert <p>, but first close previous paragraph if any." | ||
| 26653 | (org-close-par-maybe) | ||
| 26654 | (insert "\n<p>") | ||
| 26655 | (setq org-par-open t)) | ||
| 26656 | (defun org-close-par-maybe () | ||
| 26657 | "Close paragraph if there is one open." | ||
| 26658 | (when org-par-open | ||
| 26659 | (insert "</p>") | ||
| 26660 | (setq org-par-open nil))) | ||
| 26661 | (defun org-close-li () | ||
| 26662 | "Close <li> if necessary." | ||
| 26663 | (org-close-par-maybe) | ||
| 26664 | (insert "</li>\n")) | ||
| 26665 | |||
| 26666 | (defvar body-only) ; dynamically scoped into this. | ||
| 26667 | (defun org-html-level-start (level title umax with-toc head-count) | ||
| 26668 | "Insert a new level in HTML export. | ||
| 26669 | When TITLE is nil, just close all open levels." | ||
| 26670 | (org-close-par-maybe) | ||
| 26671 | (let ((l org-level-max)) | ||
| 26672 | (while (>= l level) | ||
| 26673 | (if (aref org-levels-open (1- l)) | ||
| 26674 | (progn | ||
| 26675 | (org-html-level-close l umax) | ||
| 26676 | (aset org-levels-open (1- l) nil))) | ||
| 26677 | (setq l (1- l))) | ||
| 26678 | (when title | ||
| 26679 | ;; If title is nil, this means this function is called to close | ||
| 26680 | ;; all levels, so the rest is done only if title is given | ||
| 26681 | (when (string-match (org-re "\\(:[[:alnum:]_@:]+:\\)[ \t]*$") title) | ||
| 26682 | (setq title (replace-match | ||
| 26683 | (if org-export-with-tags | ||
| 26684 | (save-match-data | ||
| 26685 | (concat | ||
| 26686 | " <span class=\"tag\">" | ||
| 26687 | (mapconcat 'identity (org-split-string | ||
| 26688 | (match-string 1 title) ":") | ||
| 26689 | " ") | ||
| 26690 | "</span>")) | ||
| 26691 | "") | ||
| 26692 | t t title))) | ||
| 26693 | (if (> level umax) | ||
| 26694 | (progn | ||
| 26695 | (if (aref org-levels-open (1- level)) | ||
| 26696 | (progn | ||
| 26697 | (org-close-li) | ||
| 26698 | (insert "<li>" title "<br/>\n")) | ||
| 26699 | (aset org-levels-open (1- level) t) | ||
| 26700 | (org-close-par-maybe) | ||
| 26701 | (insert "<ul>\n<li>" title "<br/>\n"))) | ||
| 26702 | (aset org-levels-open (1- level) t) | ||
| 26703 | (if (and org-export-with-section-numbers (not body-only)) | ||
| 26704 | (setq title (concat (org-section-number level) " " title))) | ||
| 26705 | (setq level (+ level org-export-html-toplevel-hlevel -1)) | ||
| 26706 | (if with-toc | ||
| 26707 | (insert (format "\n<div class=\"outline-%d\">\n<h%d id=\"sec-%d\">%s</h%d>\n" | ||
| 26708 | level level head-count title level)) | ||
| 26709 | (insert (format "\n<div class=\"outline-%d\">\n<h%d>%s</h%d>\n" level level title level))) | ||
| 26710 | (org-open-par))))) | ||
| 26711 | |||
| 26712 | (defun org-html-level-close (level max-outline-level) | ||
| 26713 | "Terminate one level in HTML export." | ||
| 26714 | (if (<= level max-outline-level) | ||
| 26715 | (insert "</div>\n") | ||
| 26716 | (org-close-li) | ||
| 26717 | (insert "</ul>\n"))) | ||
| 26718 | |||
| 26719 | ;;; iCalendar export | ||
| 26720 | |||
| 26721 | ;;;###autoload | ||
| 26722 | (defun org-export-icalendar-this-file () | ||
| 26723 | "Export current file as an iCalendar file. | ||
| 26724 | The iCalendar file will be located in the same directory as the Org-mode | ||
| 26725 | file, but with extension `.ics'." | ||
| 26726 | (interactive) | ||
| 26727 | (org-export-icalendar nil buffer-file-name)) | ||
| 26728 | |||
| 26729 | ;;;###autoload | ||
| 26730 | (defun org-export-icalendar-all-agenda-files () | ||
| 26731 | "Export all files in `org-agenda-files' to iCalendar .ics files. | ||
| 26732 | Each iCalendar file will be located in the same directory as the Org-mode | ||
| 26733 | file, but with extension `.ics'." | ||
| 26734 | (interactive) | ||
| 26735 | (apply 'org-export-icalendar nil (org-agenda-files t))) | ||
| 26736 | |||
| 26737 | ;;;###autoload | ||
| 26738 | (defun org-export-icalendar-combine-agenda-files () | ||
| 26739 | "Export all files in `org-agenda-files' to a single combined iCalendar file. | ||
| 26740 | The file is stored under the name `org-combined-agenda-icalendar-file'." | ||
| 26741 | (interactive) | ||
| 26742 | (apply 'org-export-icalendar t (org-agenda-files t))) | ||
| 26743 | |||
| 26744 | (defun org-export-icalendar (combine &rest files) | ||
| 26745 | "Create iCalendar files for all elements of FILES. | ||
| 26746 | If COMBINE is non-nil, combine all calendar entries into a single large | ||
| 26747 | file and store it under the name `org-combined-agenda-icalendar-file'." | ||
| 26748 | (save-excursion | ||
| 26749 | (org-prepare-agenda-buffers files) | ||
| 26750 | (let* ((dir (org-export-directory | ||
| 26751 | :ical (list :publishing-directory | ||
| 26752 | org-export-publishing-directory))) | ||
| 26753 | file ical-file ical-buffer category started org-agenda-new-buffers) | ||
| 26754 | (and (get-buffer "*ical-tmp*") (kill-buffer "*ical-tmp*")) | ||
| 26755 | (when combine | ||
| 26756 | (setq ical-file | ||
| 26757 | (if (file-name-absolute-p org-combined-agenda-icalendar-file) | ||
| 26758 | org-combined-agenda-icalendar-file | ||
| 26759 | (expand-file-name org-combined-agenda-icalendar-file dir)) | ||
| 26760 | ical-buffer (org-get-agenda-file-buffer ical-file)) | ||
| 26761 | (set-buffer ical-buffer) (erase-buffer)) | ||
| 26762 | (while (setq file (pop files)) | ||
| 26763 | (catch 'nextfile | ||
| 26764 | (org-check-agenda-file file) | ||
| 26765 | (set-buffer (org-get-agenda-file-buffer file)) | ||
| 26766 | (unless combine | ||
| 26767 | (setq ical-file (concat (file-name-as-directory dir) | ||
| 26768 | (file-name-sans-extension | ||
| 26769 | (file-name-nondirectory buffer-file-name)) | ||
| 26770 | ".ics")) | ||
| 26771 | (setq ical-buffer (org-get-agenda-file-buffer ical-file)) | ||
| 26772 | (with-current-buffer ical-buffer (erase-buffer))) | ||
| 26773 | (setq category (or org-category | ||
| 26774 | (file-name-sans-extension | ||
| 26775 | (file-name-nondirectory buffer-file-name)))) | ||
| 26776 | (if (symbolp category) (setq category (symbol-name category))) | ||
| 26777 | (let ((standard-output ical-buffer)) | ||
| 26778 | (if combine | ||
| 26779 | (and (not started) (setq started t) | ||
| 26780 | (org-start-icalendar-file org-icalendar-combined-name)) | ||
| 26781 | (org-start-icalendar-file category)) | ||
| 26782 | (org-print-icalendar-entries combine) | ||
| 26783 | (when (or (and combine (not files)) (not combine)) | ||
| 26784 | (org-finish-icalendar-file) | ||
| 26785 | (set-buffer ical-buffer) | ||
| 26786 | (save-buffer) | ||
| 26787 | (run-hooks 'org-after-save-iCalendar-file-hook))))) | ||
| 26788 | (org-release-buffers org-agenda-new-buffers)))) | ||
| 26789 | |||
| 26790 | (defvar org-after-save-iCalendar-file-hook nil | ||
| 26791 | "Hook run after an iCalendar file has been saved. | ||
| 26792 | The iCalendar buffer is still current when this hook is run. | ||
| 26793 | A good way to use this is to tell a desktop calenndar application to re-read | ||
| 26794 | the iCalendar file.") | ||
| 26795 | |||
| 26796 | (defun org-print-icalendar-entries (&optional combine) | ||
| 26797 | "Print iCalendar entries for the current Org-mode file to `standard-output'. | ||
| 26798 | When COMBINE is non nil, add the category to each line." | ||
| 26799 | (let ((re1 (concat org-ts-regexp "\\|<%%([^>\n]+>")) | ||
| 26800 | (re2 (concat "--?-?\\(" org-ts-regexp "\\)")) | ||
| 26801 | (dts (org-ical-ts-to-string | ||
| 26802 | (format-time-string (cdr org-time-stamp-formats) (current-time)) | ||
| 26803 | "DTSTART")) | ||
| 26804 | hd ts ts2 state status (inc t) pos b sexp rrule | ||
| 26805 | scheduledp deadlinep tmp pri category entry location summary desc | ||
| 26806 | (sexp-buffer (get-buffer-create "*ical-tmp*"))) | ||
| 26807 | (org-refresh-category-properties) | ||
| 26808 | (save-excursion | ||
| 26809 | (goto-char (point-min)) | ||
| 26810 | (while (re-search-forward re1 nil t) | ||
| 26811 | (catch :skip | ||
| 26812 | (org-agenda-skip) | ||
| 26813 | (when (boundp 'org-icalendar-verify-function) | ||
| 26814 | (unless (funcall org-icalendar-verify-function) | ||
| 26815 | (outline-next-heading) | ||
| 26816 | (backward-char 1) | ||
| 26817 | (throw :skip nil))) | ||
| 26818 | (setq pos (match-beginning 0) | ||
| 26819 | ts (match-string 0) | ||
| 26820 | inc t | ||
| 26821 | hd (org-get-heading) | ||
| 26822 | summary (org-icalendar-cleanup-string | ||
| 26823 | (org-entry-get nil "SUMMARY")) | ||
| 26824 | desc (org-icalendar-cleanup-string | ||
| 26825 | (or (org-entry-get nil "DESCRIPTION") | ||
| 26826 | (and org-icalendar-include-body (org-get-entry))) | ||
| 26827 | t org-icalendar-include-body) | ||
| 26828 | location (org-icalendar-cleanup-string | ||
| 26829 | (org-entry-get nil "LOCATION")) | ||
| 26830 | category (org-get-category)) | ||
| 26831 | (if (looking-at re2) | ||
| 26832 | (progn | ||
| 26833 | (goto-char (match-end 0)) | ||
| 26834 | (setq ts2 (match-string 1) inc nil)) | ||
| 26835 | (setq tmp (buffer-substring (max (point-min) | ||
| 26836 | (- pos org-ds-keyword-length)) | ||
| 26837 | pos) | ||
| 26838 | ts2 (if (string-match "[0-9]\\{1,2\\}:[0-9][0-9]-\\([0-9]\\{1,2\\}:[0-9][0-9]\\)" ts) | ||
| 26839 | (progn | ||
| 26840 | (setq inc nil) | ||
| 26841 | (replace-match "\\1" t nil ts)) | ||
| 26842 | ts) | ||
| 26843 | deadlinep (string-match org-deadline-regexp tmp) | ||
| 26844 | scheduledp (string-match org-scheduled-regexp tmp) | ||
| 26845 | ;; donep (org-entry-is-done-p) | ||
| 26846 | )) | ||
| 26847 | (if (or (string-match org-tr-regexp hd) | ||
| 26848 | (string-match org-ts-regexp hd)) | ||
| 26849 | (setq hd (replace-match "" t t hd))) | ||
| 26850 | (if (string-match "\\+\\([0-9]+\\)\\([dwmy]\\)>" ts) | ||
| 26851 | (setq rrule | ||
| 26852 | (concat "\nRRULE:FREQ=" | ||
| 26853 | (cdr (assoc | ||
| 26854 | (match-string 2 ts) | ||
| 26855 | '(("d" . "DAILY")("w" . "WEEKLY") | ||
| 26856 | ("m" . "MONTHLY")("y" . "YEARLY")))) | ||
| 26857 | ";INTERVAL=" (match-string 1 ts))) | ||
| 26858 | (setq rrule "")) | ||
| 26859 | (setq summary (or summary hd)) | ||
| 26860 | (if (string-match org-bracket-link-regexp summary) | ||
| 26861 | (setq summary | ||
| 26862 | (replace-match (if (match-end 3) | ||
| 26863 | (match-string 3 summary) | ||
| 26864 | (match-string 1 summary)) | ||
| 26865 | t t summary))) | ||
| 26866 | (if deadlinep (setq summary (concat "DL: " summary))) | ||
| 26867 | (if scheduledp (setq summary (concat "S: " summary))) | ||
| 26868 | (if (string-match "\\`<%%" ts) | ||
| 26869 | (with-current-buffer sexp-buffer | ||
| 26870 | (insert (substring ts 1 -1) " " summary "\n")) | ||
| 26871 | (princ (format "BEGIN:VEVENT | ||
| 26872 | %s | ||
| 26873 | %s%s | ||
| 26874 | SUMMARY:%s%s%s | ||
| 26875 | CATEGORIES:%s | ||
| 26876 | END:VEVENT\n" | ||
| 26877 | (org-ical-ts-to-string ts "DTSTART") | ||
| 26878 | (org-ical-ts-to-string ts2 "DTEND" inc) | ||
| 26879 | rrule summary | ||
| 26880 | (if (and desc (string-match "\\S-" desc)) | ||
| 26881 | (concat "\nDESCRIPTION: " desc) "") | ||
| 26882 | (if (and location (string-match "\\S-" location)) | ||
| 26883 | (concat "\nLOCATION: " location) "") | ||
| 26884 | category))))) | ||
| 26885 | |||
| 26886 | (when (and org-icalendar-include-sexps | ||
| 26887 | (condition-case nil (require 'icalendar) (error nil)) | ||
| 26888 | (fboundp 'icalendar-export-region)) | ||
| 26889 | ;; Get all the literal sexps | ||
| 26890 | (goto-char (point-min)) | ||
| 26891 | (while (re-search-forward "^&?%%(" nil t) | ||
| 26892 | (catch :skip | ||
| 26893 | (org-agenda-skip) | ||
| 26894 | (setq b (match-beginning 0)) | ||
| 26895 | (goto-char (1- (match-end 0))) | ||
| 26896 | (forward-sexp 1) | ||
| 26897 | (end-of-line 1) | ||
| 26898 | (setq sexp (buffer-substring b (point))) | ||
| 26899 | (with-current-buffer sexp-buffer | ||
| 26900 | (insert sexp "\n")) | ||
| 26901 | (princ (org-diary-to-ical-string sexp-buffer))))) | ||
| 26902 | |||
| 26903 | (when org-icalendar-include-todo | ||
| 26904 | (goto-char (point-min)) | ||
| 26905 | (while (re-search-forward org-todo-line-regexp nil t) | ||
| 26906 | (catch :skip | ||
| 26907 | (org-agenda-skip) | ||
| 26908 | (when (boundp 'org-icalendar-verify-function) | ||
| 26909 | (unless (funcall org-icalendar-verify-function) | ||
| 26910 | (outline-next-heading) | ||
| 26911 | (backward-char 1) | ||
| 26912 | (throw :skip nil))) | ||
| 26913 | (setq state (match-string 2)) | ||
| 26914 | (setq status (if (member state org-done-keywords) | ||
| 26915 | "COMPLETED" "NEEDS-ACTION")) | ||
| 26916 | (when (and state | ||
| 26917 | (or (not (member state org-done-keywords)) | ||
| 26918 | (eq org-icalendar-include-todo 'all)) | ||
| 26919 | (not (member org-archive-tag (org-get-tags-at))) | ||
| 26920 | ) | ||
| 26921 | (setq hd (match-string 3) | ||
| 26922 | summary (org-icalendar-cleanup-string | ||
| 26923 | (org-entry-get nil "SUMMARY")) | ||
| 26924 | desc (org-icalendar-cleanup-string | ||
| 26925 | (or (org-entry-get nil "DESCRIPTION") | ||
| 26926 | (and org-icalendar-include-body (org-get-entry))) | ||
| 26927 | t org-icalendar-include-body) | ||
| 26928 | location (org-icalendar-cleanup-string | ||
| 26929 | (org-entry-get nil "LOCATION"))) | ||
| 26930 | (if (string-match org-bracket-link-regexp hd) | ||
| 26931 | (setq hd (replace-match (if (match-end 3) (match-string 3 hd) | ||
| 26932 | (match-string 1 hd)) | ||
| 26933 | t t hd))) | ||
| 26934 | (if (string-match org-priority-regexp hd) | ||
| 26935 | (setq pri (string-to-char (match-string 2 hd)) | ||
| 26936 | hd (concat (substring hd 0 (match-beginning 1)) | ||
| 26937 | (substring hd (match-end 1)))) | ||
| 26938 | (setq pri org-default-priority)) | ||
| 26939 | (setq pri (floor (1+ (* 8. (/ (float (- org-lowest-priority pri)) | ||
| 26940 | (- org-lowest-priority org-highest-priority)))))) | ||
| 26941 | |||
| 26942 | (princ (format "BEGIN:VTODO | ||
| 26943 | %s | ||
| 26944 | SUMMARY:%s%s%s | ||
| 26945 | CATEGORIES:%s | ||
| 26946 | SEQUENCE:1 | ||
| 26947 | PRIORITY:%d | ||
| 26948 | STATUS:%s | ||
| 26949 | END:VTODO\n" | ||
| 26950 | dts | ||
| 26951 | (or summary hd) | ||
| 26952 | (if (and location (string-match "\\S-" location)) | ||
| 26953 | (concat "\nLOCATION: " location) "") | ||
| 26954 | (if (and desc (string-match "\\S-" desc)) | ||
| 26955 | (concat "\nDESCRIPTION: " desc) "") | ||
| 26956 | category pri status))))))))) | ||
| 26957 | |||
| 26958 | (defun org-icalendar-cleanup-string (s &optional is-body maxlength) | ||
| 26959 | "Take out stuff and quote what needs to be quoted. | ||
| 26960 | When IS-BODY is non-nil, assume that this is the body of an item, clean up | ||
| 26961 | whitespace, newlines, drawers, and timestamps, and cut it down to MAXLENGTH | ||
| 26962 | characters." | ||
| 26963 | (if (not s) | ||
| 26964 | nil | ||
| 26965 | (when is-body | ||
| 26966 | (let ((re (concat "\\(" org-drawer-regexp "\\)[^\000]*?:END:.*\n?")) | ||
| 26967 | (re2 (concat "^[ \t]*" org-keyword-time-regexp ".*\n?"))) | ||
| 26968 | (while (string-match re s) (setq s (replace-match "" t t s))) | ||
| 26969 | (while (string-match re2 s) (setq s (replace-match "" t t s))))) | ||
| 26970 | (let ((start 0)) | ||
| 26971 | (while (string-match "\\([,;\\]\\)" s start) | ||
| 26972 | (setq start (+ (match-beginning 0) 2) | ||
| 26973 | s (replace-match "\\\\\\1" nil nil s)))) | ||
| 26974 | (when is-body | ||
| 26975 | (while (string-match "[ \t]*\n[ \t]*" s) | ||
| 26976 | (setq s (replace-match "\\n" t t s)))) | ||
| 26977 | (setq s (org-trim s)) | ||
| 26978 | (if is-body | ||
| 26979 | (if maxlength | ||
| 26980 | (if (and (numberp maxlength) | ||
| 26981 | (> (length s) maxlength)) | ||
| 26982 | (setq s (substring s 0 maxlength))))) | ||
| 26983 | s)) | ||
| 26984 | |||
| 26985 | (defun org-get-entry () | ||
| 26986 | "Clean-up description string." | ||
| 26987 | (save-excursion | ||
| 26988 | (org-back-to-heading t) | ||
| 26989 | (buffer-substring (point-at-bol 2) (org-end-of-subtree t)))) | ||
| 26990 | |||
| 26991 | (defun org-start-icalendar-file (name) | ||
| 26992 | "Start an iCalendar file by inserting the header." | ||
| 26993 | (let ((user user-full-name) | ||
| 26994 | (name (or name "unknown")) | ||
| 26995 | (timezone (cadr (current-time-zone)))) | ||
| 26996 | (princ | ||
| 26997 | (format "BEGIN:VCALENDAR | ||
| 26998 | VERSION:2.0 | ||
| 26999 | X-WR-CALNAME:%s | ||
| 27000 | PRODID:-//%s//Emacs with Org-mode//EN | ||
| 27001 | X-WR-TIMEZONE:%s | ||
| 27002 | CALSCALE:GREGORIAN\n" name user timezone)))) | ||
| 27003 | |||
| 27004 | (defun org-finish-icalendar-file () | ||
| 27005 | "Finish an iCalendar file by inserting the END statement." | ||
| 27006 | (princ "END:VCALENDAR\n")) | ||
| 27007 | |||
| 27008 | (defun org-ical-ts-to-string (s keyword &optional inc) | ||
| 27009 | "Take a time string S and convert it to iCalendar format. | ||
| 27010 | KEYWORD is added in front, to make a complete line like DTSTART.... | ||
| 27011 | When INC is non-nil, increase the hour by two (if time string contains | ||
| 27012 | a time), or the day by one (if it does not contain a time)." | ||
| 27013 | (let ((t1 (org-parse-time-string s 'nodefault)) | ||
| 27014 | t2 fmt have-time time) | ||
| 27015 | (if (and (car t1) (nth 1 t1) (nth 2 t1)) | ||
| 27016 | (setq t2 t1 have-time t) | ||
| 27017 | (setq t2 (org-parse-time-string s))) | ||
| 27018 | (let ((s (car t2)) (mi (nth 1 t2)) (h (nth 2 t2)) | ||
| 27019 | (d (nth 3 t2)) (m (nth 4 t2)) (y (nth 5 t2))) | ||
| 27020 | (when inc | ||
| 27021 | (if have-time | ||
| 27022 | (if org-agenda-default-appointment-duration | ||
| 27023 | (setq mi (+ org-agenda-default-appointment-duration mi)) | ||
| 27024 | (setq h (+ 2 h))) | ||
| 27025 | (setq d (1+ d)))) | ||
| 27026 | (setq time (encode-time s mi h d m y))) | ||
| 27027 | (setq fmt (if have-time ":%Y%m%dT%H%M%S" ";VALUE=DATE:%Y%m%d")) | ||
| 27028 | (concat keyword (format-time-string fmt time)))) | ||
| 27029 | |||
| 27030 | ;;; XOXO export | ||
| 27031 | |||
| 27032 | (defun org-export-as-xoxo-insert-into (buffer &rest output) | ||
| 27033 | (with-current-buffer buffer | ||
| 27034 | (apply 'insert output))) | ||
| 27035 | (put 'org-export-as-xoxo-insert-into 'lisp-indent-function 1) | ||
| 27036 | |||
| 27037 | (defun org-export-as-xoxo (&optional buffer) | ||
| 27038 | "Export the org buffer as XOXO. | ||
| 27039 | The XOXO buffer is named *xoxo-<source buffer name>*" | ||
| 27040 | (interactive (list (current-buffer))) | ||
| 27041 | ;; A quickie abstraction | ||
| 27042 | |||
| 27043 | ;; Output everything as XOXO | ||
| 27044 | (with-current-buffer (get-buffer buffer) | ||
| 27045 | (let* ((pos (point)) | ||
| 27046 | (opt-plist (org-combine-plists (org-default-export-plist) | ||
| 27047 | (org-infile-export-plist))) | ||
| 27048 | (filename (concat (file-name-as-directory | ||
| 27049 | (org-export-directory :xoxo opt-plist)) | ||
| 27050 | (file-name-sans-extension | ||
| 27051 | (file-name-nondirectory buffer-file-name)) | ||
| 27052 | ".html")) | ||
| 27053 | (out (find-file-noselect filename)) | ||
| 27054 | (last-level 1) | ||
| 27055 | (hanging-li nil)) | ||
| 27056 | (goto-char (point-min)) ;; CD: beginning-of-buffer is not allowed. | ||
| 27057 | ;; Check the output buffer is empty. | ||
| 27058 | (with-current-buffer out (erase-buffer)) | ||
| 27059 | ;; Kick off the output | ||
| 27060 | (org-export-as-xoxo-insert-into out "<ol class='xoxo'>\n") | ||
| 27061 | (while (re-search-forward "^\\(\\*+\\)[ \t]+\\(.+\\)" (point-max) 't) | ||
| 27062 | (let* ((hd (match-string-no-properties 1)) | ||
| 27063 | (level (length hd)) | ||
| 27064 | (text (concat | ||
| 27065 | (match-string-no-properties 2) | ||
| 27066 | (save-excursion | ||
| 27067 | (goto-char (match-end 0)) | ||
| 27068 | (let ((str "")) | ||
| 27069 | (catch 'loop | ||
| 27070 | (while 't | ||
| 27071 | (forward-line) | ||
| 27072 | (if (looking-at "^[ \t]\\(.*\\)") | ||
| 27073 | (setq str (concat str (match-string-no-properties 1))) | ||
| 27074 | (throw 'loop str))))))))) | ||
| 27075 | |||
| 27076 | ;; Handle level rendering | ||
| 27077 | (cond | ||
| 27078 | ((> level last-level) | ||
| 27079 | (org-export-as-xoxo-insert-into out "\n<ol>\n")) | ||
| 27080 | |||
| 27081 | ((< level last-level) | ||
| 27082 | (dotimes (- (- last-level level) 1) | ||
| 27083 | (if hanging-li | ||
| 27084 | (org-export-as-xoxo-insert-into out "</li>\n")) | ||
| 27085 | (org-export-as-xoxo-insert-into out "</ol>\n")) | ||
| 27086 | (when hanging-li | ||
| 27087 | (org-export-as-xoxo-insert-into out "</li>\n") | ||
| 27088 | (setq hanging-li nil))) | ||
| 27089 | |||
| 27090 | ((equal level last-level) | ||
| 27091 | (if hanging-li | ||
| 27092 | (org-export-as-xoxo-insert-into out "</li>\n"))) | ||
| 27093 | ) | ||
| 27094 | |||
| 27095 | (setq last-level level) | ||
| 27096 | |||
| 27097 | ;; And output the new li | ||
| 27098 | (setq hanging-li 't) | ||
| 27099 | (if (equal ?+ (elt text 0)) | ||
| 27100 | (org-export-as-xoxo-insert-into out "<li class='" (substring text 1) "'>") | ||
| 27101 | (org-export-as-xoxo-insert-into out "<li>" text)))) | ||
| 27102 | |||
| 27103 | ;; Finally finish off the ol | ||
| 27104 | (dotimes (- last-level 1) | ||
| 27105 | (if hanging-li | ||
| 27106 | (org-export-as-xoxo-insert-into out "</li>\n")) | ||
| 27107 | (org-export-as-xoxo-insert-into out "</ol>\n")) | ||
| 27108 | |||
| 27109 | (goto-char pos) | ||
| 27110 | ;; Finish the buffer off and clean it up. | ||
| 27111 | (switch-to-buffer-other-window out) | ||
| 27112 | (indent-region (point-min) (point-max) nil) | ||
| 27113 | (save-buffer) | ||
| 27114 | (goto-char (point-min)) | ||
| 27115 | ))) | ||
| 27116 | |||
| 27117 | |||
| 27118 | ;;;; Key bindings | ||
| 27119 | |||
| 27120 | ;; Make `C-c C-x' a prefix key | ||
| 27121 | (org-defkey org-mode-map "\C-c\C-x" (make-sparse-keymap)) | ||
| 27122 | |||
| 27123 | ;; TAB key with modifiers | ||
| 27124 | (org-defkey org-mode-map "\C-i" 'org-cycle) | ||
| 27125 | (org-defkey org-mode-map [(tab)] 'org-cycle) | ||
| 27126 | (org-defkey org-mode-map [(control tab)] 'org-force-cycle-archived) | ||
| 27127 | (org-defkey org-mode-map [(meta tab)] 'org-complete) | ||
| 27128 | (org-defkey org-mode-map "\M-\t" 'org-complete) | ||
| 27129 | (org-defkey org-mode-map "\M-\C-i" 'org-complete) | ||
| 27130 | ;; The following line is necessary under Suse GNU/Linux | ||
| 27131 | (unless (featurep 'xemacs) | ||
| 27132 | (org-defkey org-mode-map [S-iso-lefttab] 'org-shifttab)) | ||
| 27133 | (org-defkey org-mode-map [(shift tab)] 'org-shifttab) | ||
| 27134 | (define-key org-mode-map [backtab] 'org-shifttab) | ||
| 27135 | |||
| 27136 | (org-defkey org-mode-map [(shift return)] 'org-table-copy-down) | ||
| 27137 | (org-defkey org-mode-map [(meta shift return)] 'org-insert-todo-heading) | ||
| 27138 | (org-defkey org-mode-map [(meta return)] 'org-meta-return) | ||
| 27139 | |||
| 27140 | ;; Cursor keys with modifiers | ||
| 27141 | (org-defkey org-mode-map [(meta left)] 'org-metaleft) | ||
| 27142 | (org-defkey org-mode-map [(meta right)] 'org-metaright) | ||
| 27143 | (org-defkey org-mode-map [(meta up)] 'org-metaup) | ||
| 27144 | (org-defkey org-mode-map [(meta down)] 'org-metadown) | ||
| 27145 | |||
| 27146 | (org-defkey org-mode-map [(meta shift left)] 'org-shiftmetaleft) | ||
| 27147 | (org-defkey org-mode-map [(meta shift right)] 'org-shiftmetaright) | ||
| 27148 | (org-defkey org-mode-map [(meta shift up)] 'org-shiftmetaup) | ||
| 27149 | (org-defkey org-mode-map [(meta shift down)] 'org-shiftmetadown) | ||
| 27150 | |||
| 27151 | (org-defkey org-mode-map [(shift up)] 'org-shiftup) | ||
| 27152 | (org-defkey org-mode-map [(shift down)] 'org-shiftdown) | ||
| 27153 | (org-defkey org-mode-map [(shift left)] 'org-shiftleft) | ||
| 27154 | (org-defkey org-mode-map [(shift right)] 'org-shiftright) | ||
| 27155 | |||
| 27156 | (org-defkey org-mode-map [(control shift right)] 'org-shiftcontrolright) | ||
| 27157 | (org-defkey org-mode-map [(control shift left)] 'org-shiftcontrolleft) | ||
| 27158 | |||
| 27159 | ;;; Extra keys for tty access. | ||
| 27160 | ;; We only set them when really needed because otherwise the | ||
| 27161 | ;; menus don't show the simple keys | ||
| 27162 | |||
| 27163 | (when (or (featurep 'xemacs) ;; because XEmacs supports multi-device stuff | ||
| 27164 | (not window-system)) | ||
| 27165 | (org-defkey org-mode-map "\C-c\C-xc" 'org-table-copy-down) | ||
| 27166 | (org-defkey org-mode-map "\C-c\C-xM" 'org-insert-todo-heading) | ||
| 27167 | (org-defkey org-mode-map "\C-c\C-xm" 'org-meta-return) | ||
| 27168 | (org-defkey org-mode-map [?\e (return)] 'org-meta-return) | ||
| 27169 | (org-defkey org-mode-map [?\e (left)] 'org-metaleft) | ||
| 27170 | (org-defkey org-mode-map "\C-c\C-xl" 'org-metaleft) | ||
| 27171 | (org-defkey org-mode-map [?\e (right)] 'org-metaright) | ||
| 27172 | (org-defkey org-mode-map "\C-c\C-xr" 'org-metaright) | ||
| 27173 | (org-defkey org-mode-map [?\e (up)] 'org-metaup) | ||
| 27174 | (org-defkey org-mode-map "\C-c\C-xu" 'org-metaup) | ||
| 27175 | (org-defkey org-mode-map [?\e (down)] 'org-metadown) | ||
| 27176 | (org-defkey org-mode-map "\C-c\C-xd" 'org-metadown) | ||
| 27177 | (org-defkey org-mode-map "\C-c\C-xL" 'org-shiftmetaleft) | ||
| 27178 | (org-defkey org-mode-map "\C-c\C-xR" 'org-shiftmetaright) | ||
| 27179 | (org-defkey org-mode-map "\C-c\C-xU" 'org-shiftmetaup) | ||
| 27180 | (org-defkey org-mode-map "\C-c\C-xD" 'org-shiftmetadown) | ||
| 27181 | (org-defkey org-mode-map [?\C-c (up)] 'org-shiftup) | ||
| 27182 | (org-defkey org-mode-map [?\C-c (down)] 'org-shiftdown) | ||
| 27183 | (org-defkey org-mode-map [?\C-c (left)] 'org-shiftleft) | ||
| 27184 | (org-defkey org-mode-map [?\C-c (right)] 'org-shiftright) | ||
| 27185 | (org-defkey org-mode-map [?\C-c ?\C-x (right)] 'org-shiftcontrolright) | ||
| 27186 | (org-defkey org-mode-map [?\C-c ?\C-x (left)] 'org-shiftcontrolleft)) | ||
| 27187 | |||
| 27188 | ;; All the other keys | ||
| 27189 | |||
| 27190 | (org-defkey org-mode-map "\C-c\C-a" 'show-all) ; in case allout messed up. | ||
| 27191 | (org-defkey org-mode-map "\C-c\C-r" 'org-reveal) | ||
| 27192 | (org-defkey org-mode-map "\C-xns" 'org-narrow-to-subtree) | ||
| 27193 | (org-defkey org-mode-map "\C-c$" 'org-archive-subtree) | ||
| 27194 | (org-defkey org-mode-map "\C-c\C-x\C-s" 'org-advertized-archive-subtree) | ||
| 27195 | (org-defkey org-mode-map "\C-c\C-x\C-a" 'org-toggle-archive-tag) | ||
| 27196 | (org-defkey org-mode-map "\C-c\C-xb" 'org-tree-to-indirect-buffer) | ||
| 27197 | (org-defkey org-mode-map "\C-c\C-j" 'org-goto) | ||
| 27198 | (org-defkey org-mode-map "\C-c\C-t" 'org-todo) | ||
| 27199 | (org-defkey org-mode-map "\C-c\C-s" 'org-schedule) | ||
| 27200 | (org-defkey org-mode-map "\C-c\C-d" 'org-deadline) | ||
| 27201 | (org-defkey org-mode-map "\C-c;" 'org-toggle-comment) | ||
| 27202 | (org-defkey org-mode-map "\C-c\C-v" 'org-show-todo-tree) | ||
| 27203 | (org-defkey org-mode-map "\C-c\C-w" 'org-refile) | ||
| 27204 | (org-defkey org-mode-map "\C-c/" 'org-sparse-tree) ; Minor-mode reserved | ||
| 27205 | (org-defkey org-mode-map "\C-c\\" 'org-tags-sparse-tree) ; Minor-mode res. | ||
| 27206 | (org-defkey org-mode-map "\C-c\C-m" 'org-ctrl-c-ret) | ||
| 27207 | (org-defkey org-mode-map "\M-\C-m" 'org-insert-heading) | ||
| 27208 | (org-defkey org-mode-map [(control return)] 'org-insert-heading-after-current) | ||
| 27209 | (org-defkey org-mode-map "\C-c\C-x\C-n" 'org-next-link) | ||
| 27210 | (org-defkey org-mode-map "\C-c\C-x\C-p" 'org-previous-link) | ||
| 27211 | (org-defkey org-mode-map "\C-c\C-l" 'org-insert-link) | ||
| 27212 | (org-defkey org-mode-map "\C-c\C-o" 'org-open-at-point) | ||
| 27213 | (org-defkey org-mode-map "\C-c%" 'org-mark-ring-push) | ||
| 27214 | (org-defkey org-mode-map "\C-c&" 'org-mark-ring-goto) | ||
| 27215 | (org-defkey org-mode-map "\C-c\C-z" 'org-time-stamp) ; Alternative binding | ||
| 27216 | (org-defkey org-mode-map "\C-c." 'org-time-stamp) ; Minor-mode reserved | ||
| 27217 | (org-defkey org-mode-map "\C-c!" 'org-time-stamp-inactive) ; Minor-mode r. | ||
| 27218 | (org-defkey org-mode-map "\C-c," 'org-priority) ; Minor-mode reserved | ||
| 27219 | (org-defkey org-mode-map "\C-c\C-y" 'org-evaluate-time-range) | ||
| 27220 | (org-defkey org-mode-map "\C-c>" 'org-goto-calendar) | ||
| 27221 | (org-defkey org-mode-map "\C-c<" 'org-date-from-calendar) | ||
| 27222 | (org-defkey org-mode-map [(control ?,)] 'org-cycle-agenda-files) | ||
| 27223 | (org-defkey org-mode-map [(control ?\')] 'org-cycle-agenda-files) | ||
| 27224 | (org-defkey org-mode-map "\C-c[" 'org-agenda-file-to-front) | ||
| 27225 | (org-defkey org-mode-map "\C-c]" 'org-remove-file) | ||
| 27226 | (org-defkey org-mode-map "\C-c\C-x<" 'org-agenda-set-restriction-lock) | ||
| 27227 | (org-defkey org-mode-map "\C-c\C-x>" 'org-agenda-remove-restriction-lock) | ||
| 27228 | (org-defkey org-mode-map "\C-c-" 'org-ctrl-c-minus) | ||
| 27229 | (org-defkey org-mode-map "\C-c*" 'org-ctrl-c-star) | ||
| 27230 | (org-defkey org-mode-map "\C-c^" 'org-sort) | ||
| 27231 | (org-defkey org-mode-map "\C-c\C-c" 'org-ctrl-c-ctrl-c) | ||
| 27232 | (org-defkey org-mode-map "\C-c\C-k" 'org-kill-note-or-show-branches) | ||
| 27233 | (org-defkey org-mode-map "\C-c#" 'org-update-checkbox-count) | ||
| 27234 | (org-defkey org-mode-map "\C-m" 'org-return) | ||
| 27235 | (org-defkey org-mode-map "\C-j" 'org-return-indent) | ||
| 27236 | (org-defkey org-mode-map "\C-c?" 'org-table-field-info) | ||
| 27237 | (org-defkey org-mode-map "\C-c " 'org-table-blank-field) | ||
| 27238 | (org-defkey org-mode-map "\C-c+" 'org-table-sum) | ||
| 27239 | (org-defkey org-mode-map "\C-c=" 'org-table-eval-formula) | ||
| 27240 | (org-defkey org-mode-map "\C-c'" 'org-table-edit-formulas) | ||
| 27241 | (org-defkey org-mode-map "\C-c`" 'org-table-edit-field) | ||
| 27242 | (org-defkey org-mode-map "\C-c|" 'org-table-create-or-convert-from-region) | ||
| 27243 | (org-defkey org-mode-map [(control ?#)] 'org-table-rotate-recalc-marks) | ||
| 27244 | (org-defkey org-mode-map "\C-c~" 'org-table-create-with-table.el) | ||
| 27245 | (org-defkey org-mode-map "\C-c\C-q" 'org-table-wrap-region) | ||
| 27246 | (org-defkey org-mode-map "\C-c}" 'org-table-toggle-coordinate-overlays) | ||
| 27247 | (org-defkey org-mode-map "\C-c{" 'org-table-toggle-formula-debugger) | ||
| 27248 | (org-defkey org-mode-map "\C-c\C-e" 'org-export) | ||
| 27249 | (org-defkey org-mode-map "\C-c:" 'org-toggle-fixed-width-section) | ||
| 27250 | (org-defkey org-mode-map "\C-c\C-x\C-f" 'org-emphasize) | ||
| 27251 | |||
| 27252 | (org-defkey org-mode-map "\C-c\C-x\C-k" 'org-cut-special) | ||
| 27253 | (org-defkey org-mode-map "\C-c\C-x\C-w" 'org-cut-special) | ||
| 27254 | (org-defkey org-mode-map "\C-c\C-x\M-w" 'org-copy-special) | ||
| 27255 | (org-defkey org-mode-map "\C-c\C-x\C-y" 'org-paste-special) | ||
| 27256 | |||
| 27257 | (org-defkey org-mode-map "\C-c\C-x\C-t" 'org-toggle-time-stamp-overlays) | ||
| 27258 | (org-defkey org-mode-map "\C-c\C-x\C-i" 'org-clock-in) | ||
| 27259 | (org-defkey org-mode-map "\C-c\C-x\C-o" 'org-clock-out) | ||
| 27260 | (org-defkey org-mode-map "\C-c\C-x\C-j" 'org-clock-goto) | ||
| 27261 | (org-defkey org-mode-map "\C-c\C-x\C-x" 'org-clock-cancel) | ||
| 27262 | (org-defkey org-mode-map "\C-c\C-x\C-d" 'org-clock-display) | ||
| 27263 | (org-defkey org-mode-map "\C-c\C-x\C-r" 'org-clock-report) | ||
| 27264 | (org-defkey org-mode-map "\C-c\C-x\C-u" 'org-dblock-update) | ||
| 27265 | (org-defkey org-mode-map "\C-c\C-x\C-l" 'org-preview-latex-fragment) | ||
| 27266 | (org-defkey org-mode-map "\C-c\C-x\C-b" 'org-toggle-checkbox) | ||
| 27267 | (org-defkey org-mode-map "\C-c\C-xp" 'org-set-property) | ||
| 27268 | (org-defkey org-mode-map "\C-c\C-xr" 'org-insert-columns-dblock) | ||
| 27269 | |||
| 27270 | (define-key org-mode-map "\C-c\C-x\C-c" 'org-columns) | ||
| 27271 | |||
| 27272 | (when (featurep 'xemacs) | ||
| 27273 | (org-defkey org-mode-map 'button3 'popup-mode-menu)) | ||
| 27274 | |||
| 27275 | (defsubst org-table-p () (org-at-table-p)) | ||
| 27276 | |||
| 27277 | (defun org-self-insert-command (N) | ||
| 27278 | "Like `self-insert-command', use overwrite-mode for whitespace in tables. | ||
| 27279 | If the cursor is in a table looking at whitespace, the whitespace is | ||
| 27280 | overwritten, and the table is not marked as requiring realignment." | ||
| 27281 | (interactive "p") | ||
| 27282 | (if (and (org-table-p) | ||
| 27283 | (progn | ||
| 27284 | ;; check if we blank the field, and if that triggers align | ||
| 27285 | (and org-table-auto-blank-field | ||
| 27286 | (member last-command | ||
| 27287 | '(org-cycle org-return org-shifttab org-ctrl-c-ctrl-c)) | ||
| 27288 | (if (or (equal (char-after) ?\ ) (looking-at "[^|\n]* |")) | ||
| 27289 | ;; got extra space, this field does not determine column width | ||
| 27290 | (let (org-table-may-need-update) (org-table-blank-field)) | ||
| 27291 | ;; no extra space, this field may determine column width | ||
| 27292 | (org-table-blank-field))) | ||
| 27293 | t) | ||
| 27294 | (eq N 1) | ||
| 27295 | (looking-at "[^|\n]* |")) | ||
| 27296 | (let (org-table-may-need-update) | ||
| 27297 | (goto-char (1- (match-end 0))) | ||
| 27298 | (delete-backward-char 1) | ||
| 27299 | (goto-char (match-beginning 0)) | ||
| 27300 | (self-insert-command N)) | ||
| 27301 | (setq org-table-may-need-update t) | ||
| 27302 | (self-insert-command N) | ||
| 27303 | (org-fix-tags-on-the-fly))) | ||
| 27304 | |||
| 27305 | (defun org-fix-tags-on-the-fly () | ||
| 27306 | (when (and (equal (char-after (point-at-bol)) ?*) | ||
| 27307 | (org-on-heading-p)) | ||
| 27308 | (org-align-tags-here org-tags-column))) | ||
| 27309 | |||
| 27310 | (defun org-delete-backward-char (N) | ||
| 27311 | "Like `delete-backward-char', insert whitespace at field end in tables. | ||
| 27312 | When deleting backwards, in tables this function will insert whitespace in | ||
| 27313 | front of the next \"|\" separator, to keep the table aligned. The table will | ||
| 27314 | still be marked for re-alignment if the field did fill the entire column, | ||
| 27315 | because, in this case the deletion might narrow the column." | ||
| 27316 | (interactive "p") | ||
| 27317 | (if (and (org-table-p) | ||
| 27318 | (eq N 1) | ||
| 27319 | (string-match "|" (buffer-substring (point-at-bol) (point))) | ||
| 27320 | (looking-at ".*?|")) | ||
| 27321 | (let ((pos (point)) | ||
| 27322 | (noalign (looking-at "[^|\n\r]* |")) | ||
| 27323 | (c org-table-may-need-update)) | ||
| 27324 | (backward-delete-char N) | ||
| 27325 | (skip-chars-forward "^|") | ||
| 27326 | (insert " ") | ||
| 27327 | (goto-char (1- pos)) | ||
| 27328 | ;; noalign: if there were two spaces at the end, this field | ||
| 27329 | ;; does not determine the width of the column. | ||
| 27330 | (if noalign (setq org-table-may-need-update c))) | ||
| 27331 | (backward-delete-char N) | ||
| 27332 | (org-fix-tags-on-the-fly))) | ||
| 27333 | |||
| 27334 | (defun org-delete-char (N) | ||
| 27335 | "Like `delete-char', but insert whitespace at field end in tables. | ||
| 27336 | When deleting characters, in tables this function will insert whitespace in | ||
| 27337 | front of the next \"|\" separator, to keep the table aligned. The table will | ||
| 27338 | still be marked for re-alignment if the field did fill the entire column, | ||
| 27339 | because, in this case the deletion might narrow the column." | ||
| 27340 | (interactive "p") | ||
| 27341 | (if (and (org-table-p) | ||
| 27342 | (not (bolp)) | ||
| 27343 | (not (= (char-after) ?|)) | ||
| 27344 | (eq N 1)) | ||
| 27345 | (if (looking-at ".*?|") | ||
| 27346 | (let ((pos (point)) | ||
| 27347 | (noalign (looking-at "[^|\n\r]* |")) | ||
| 27348 | (c org-table-may-need-update)) | ||
| 27349 | (replace-match (concat | ||
| 27350 | (substring (match-string 0) 1 -1) | ||
| 27351 | " |")) | ||
| 27352 | (goto-char pos) | ||
| 27353 | ;; noalign: if there were two spaces at the end, this field | ||
| 27354 | ;; does not determine the width of the column. | ||
| 27355 | (if noalign (setq org-table-may-need-update c))) | ||
| 27356 | (delete-char N)) | ||
| 27357 | (delete-char N) | ||
| 27358 | (org-fix-tags-on-the-fly))) | ||
| 27359 | |||
| 27360 | ;; Make `delete-selection-mode' work with org-mode and orgtbl-mode | ||
| 27361 | (put 'org-self-insert-command 'delete-selection t) | ||
| 27362 | (put 'orgtbl-self-insert-command 'delete-selection t) | ||
| 27363 | (put 'org-delete-char 'delete-selection 'supersede) | ||
| 27364 | (put 'org-delete-backward-char 'delete-selection 'supersede) | ||
| 27365 | |||
| 27366 | ;; Make `flyspell-mode' delay after some commands | ||
| 27367 | (put 'org-self-insert-command 'flyspell-delayed t) | ||
| 27368 | (put 'orgtbl-self-insert-command 'flyspell-delayed t) | ||
| 27369 | (put 'org-delete-char 'flyspell-delayed t) | ||
| 27370 | (put 'org-delete-backward-char 'flyspell-delayed t) | ||
| 27371 | |||
| 27372 | ;; Make pabbrev-mode expand after org-mode commands | ||
| 27373 | (put 'org-self-insert-command 'pabbrev-expand-after-command t) | ||
| 27374 | (put 'orgybl-self-insert-command 'pabbrev-expand-after-command t) | ||
| 27375 | |||
| 27376 | ;; How to do this: Measure non-white length of current string | ||
| 27377 | ;; If equal to column width, we should realign. | ||
| 27378 | |||
| 27379 | (defun org-remap (map &rest commands) | ||
| 27380 | "In MAP, remap the functions given in COMMANDS. | ||
| 27381 | COMMANDS is a list of alternating OLDDEF NEWDEF command names." | ||
| 27382 | (let (new old) | ||
| 27383 | (while commands | ||
| 27384 | (setq old (pop commands) new (pop commands)) | ||
| 27385 | (if (fboundp 'command-remapping) | ||
| 27386 | (org-defkey map (vector 'remap old) new) | ||
| 27387 | (substitute-key-definition old new map global-map))))) | ||
| 27388 | |||
| 27389 | (when (eq org-enable-table-editor 'optimized) | ||
| 27390 | ;; If the user wants maximum table support, we need to hijack | ||
| 27391 | ;; some standard editing functions | ||
| 27392 | (org-remap org-mode-map | ||
| 27393 | 'self-insert-command 'org-self-insert-command | ||
| 27394 | 'delete-char 'org-delete-char | ||
| 27395 | 'delete-backward-char 'org-delete-backward-char) | ||
| 27396 | (org-defkey org-mode-map "|" 'org-force-self-insert)) | ||
| 27397 | |||
| 27398 | (defun org-shiftcursor-error () | ||
| 27399 | "Throw an error because Shift-Cursor command was applied in wrong context." | ||
| 27400 | (error "This command is active in special context like tables, headlines or timestamps")) | ||
| 27401 | |||
| 27402 | (defun org-shifttab (&optional arg) | ||
| 27403 | "Global visibility cycling or move to previous table field. | ||
| 27404 | Calls `org-cycle' with argument t, or `org-table-previous-field', depending | ||
| 27405 | on context. | ||
| 27406 | See the individual commands for more information." | ||
| 27407 | (interactive "P") | ||
| 27408 | (cond | ||
| 27409 | ((org-at-table-p) (call-interactively 'org-table-previous-field)) | ||
| 27410 | (arg (message "Content view to level: ") | ||
| 27411 | (org-content (prefix-numeric-value arg)) | ||
| 27412 | (setq org-cycle-global-status 'overview)) | ||
| 27413 | (t (call-interactively 'org-global-cycle)))) | ||
| 27414 | |||
| 27415 | (defun org-shiftmetaleft () | ||
| 27416 | "Promote subtree or delete table column. | ||
| 27417 | Calls `org-promote-subtree', `org-outdent-item', | ||
| 27418 | or `org-table-delete-column', depending on context. | ||
| 27419 | See the individual commands for more information." | ||
| 27420 | (interactive) | ||
| 27421 | (cond | ||
| 27422 | ((org-at-table-p) (call-interactively 'org-table-delete-column)) | ||
| 27423 | ((org-on-heading-p) (call-interactively 'org-promote-subtree)) | ||
| 27424 | ((org-at-item-p) (call-interactively 'org-outdent-item)) | ||
| 27425 | (t (org-shiftcursor-error)))) | ||
| 27426 | |||
| 27427 | (defun org-shiftmetaright () | ||
| 27428 | "Demote subtree or insert table column. | ||
| 27429 | Calls `org-demote-subtree', `org-indent-item', | ||
| 27430 | or `org-table-insert-column', depending on context. | ||
| 27431 | See the individual commands for more information." | ||
| 27432 | (interactive) | ||
| 27433 | (cond | ||
| 27434 | ((org-at-table-p) (call-interactively 'org-table-insert-column)) | ||
| 27435 | ((org-on-heading-p) (call-interactively 'org-demote-subtree)) | ||
| 27436 | ((org-at-item-p) (call-interactively 'org-indent-item)) | ||
| 27437 | (t (org-shiftcursor-error)))) | ||
| 27438 | |||
| 27439 | (defun org-shiftmetaup (&optional arg) | ||
| 27440 | "Move subtree up or kill table row. | ||
| 27441 | Calls `org-move-subtree-up' or `org-table-kill-row' or | ||
| 27442 | `org-move-item-up' depending on context. See the individual commands | ||
| 27443 | for more information." | ||
| 27444 | (interactive "P") | ||
| 27445 | (cond | ||
| 27446 | ((org-at-table-p) (call-interactively 'org-table-kill-row)) | ||
| 27447 | ((org-on-heading-p) (call-interactively 'org-move-subtree-up)) | ||
| 27448 | ((org-at-item-p) (call-interactively 'org-move-item-up)) | ||
| 27449 | (t (org-shiftcursor-error)))) | ||
| 27450 | (defun org-shiftmetadown (&optional arg) | ||
| 27451 | "Move subtree down or insert table row. | ||
| 27452 | Calls `org-move-subtree-down' or `org-table-insert-row' or | ||
| 27453 | `org-move-item-down', depending on context. See the individual | ||
| 27454 | commands for more information." | ||
| 27455 | (interactive "P") | ||
| 27456 | (cond | ||
| 27457 | ((org-at-table-p) (call-interactively 'org-table-insert-row)) | ||
| 27458 | ((org-on-heading-p) (call-interactively 'org-move-subtree-down)) | ||
| 27459 | ((org-at-item-p) (call-interactively 'org-move-item-down)) | ||
| 27460 | (t (org-shiftcursor-error)))) | ||
| 27461 | |||
| 27462 | (defun org-metaleft (&optional arg) | ||
| 27463 | "Promote heading or move table column to left. | ||
| 27464 | Calls `org-do-promote' or `org-table-move-column', depending on context. | ||
| 27465 | With no specific context, calls the Emacs default `backward-word'. | ||
| 27466 | See the individual commands for more information." | ||
| 27467 | (interactive "P") | ||
| 27468 | (cond | ||
| 27469 | ((org-at-table-p) (org-call-with-arg 'org-table-move-column 'left)) | ||
| 27470 | ((or (org-on-heading-p) (org-region-active-p)) | ||
| 27471 | (call-interactively 'org-do-promote)) | ||
| 27472 | ((org-at-item-p) (call-interactively 'org-outdent-item)) | ||
| 27473 | (t (call-interactively 'backward-word)))) | ||
| 27474 | |||
| 27475 | (defun org-metaright (&optional arg) | ||
| 27476 | "Demote subtree or move table column to right. | ||
| 27477 | Calls `org-do-demote' or `org-table-move-column', depending on context. | ||
| 27478 | With no specific context, calls the Emacs default `forward-word'. | ||
| 27479 | See the individual commands for more information." | ||
| 27480 | (interactive "P") | ||
| 27481 | (cond | ||
| 27482 | ((org-at-table-p) (call-interactively 'org-table-move-column)) | ||
| 27483 | ((or (org-on-heading-p) (org-region-active-p)) | ||
| 27484 | (call-interactively 'org-do-demote)) | ||
| 27485 | ((org-at-item-p) (call-interactively 'org-indent-item)) | ||
| 27486 | (t (call-interactively 'forward-word)))) | ||
| 27487 | |||
| 27488 | (defun org-metaup (&optional arg) | ||
| 27489 | "Move subtree up or move table row up. | ||
| 27490 | Calls `org-move-subtree-up' or `org-table-move-row' or | ||
| 27491 | `org-move-item-up', depending on context. See the individual commands | ||
| 27492 | for more information." | ||
| 27493 | (interactive "P") | ||
| 27494 | (cond | ||
| 27495 | ((org-at-table-p) (org-call-with-arg 'org-table-move-row 'up)) | ||
| 27496 | ((org-on-heading-p) (call-interactively 'org-move-subtree-up)) | ||
| 27497 | ((org-at-item-p) (call-interactively 'org-move-item-up)) | ||
| 27498 | (t (transpose-lines 1) (beginning-of-line -1)))) | ||
| 27499 | |||
| 27500 | (defun org-metadown (&optional arg) | ||
| 27501 | "Move subtree down or move table row down. | ||
| 27502 | Calls `org-move-subtree-down' or `org-table-move-row' or | ||
| 27503 | `org-move-item-down', depending on context. See the individual | ||
| 27504 | commands for more information." | ||
| 27505 | (interactive "P") | ||
| 27506 | (cond | ||
| 27507 | ((org-at-table-p) (call-interactively 'org-table-move-row)) | ||
| 27508 | ((org-on-heading-p) (call-interactively 'org-move-subtree-down)) | ||
| 27509 | ((org-at-item-p) (call-interactively 'org-move-item-down)) | ||
| 27510 | (t (beginning-of-line 2) (transpose-lines 1) (beginning-of-line 0)))) | ||
| 27511 | |||
| 27512 | (defun org-shiftup (&optional arg) | ||
| 27513 | "Increase item in timestamp or increase priority of current headline. | ||
| 27514 | Calls `org-timestamp-up' or `org-priority-up', or `org-previous-item', | ||
| 27515 | depending on context. See the individual commands for more information." | ||
| 27516 | (interactive "P") | ||
| 27517 | (cond | ||
| 27518 | ((org-at-timestamp-p t) | ||
| 27519 | (call-interactively (if org-edit-timestamp-down-means-later | ||
| 27520 | 'org-timestamp-down 'org-timestamp-up))) | ||
| 27521 | ((org-on-heading-p) (call-interactively 'org-priority-up)) | ||
| 27522 | ((org-at-item-p) (call-interactively 'org-previous-item)) | ||
| 27523 | (t (call-interactively 'org-beginning-of-item) (beginning-of-line 1)))) | ||
| 27524 | |||
| 27525 | (defun org-shiftdown (&optional arg) | ||
| 27526 | "Decrease item in timestamp or decrease priority of current headline. | ||
| 27527 | Calls `org-timestamp-down' or `org-priority-down', or `org-next-item' | ||
| 27528 | depending on context. See the individual commands for more information." | ||
| 27529 | (interactive "P") | ||
| 27530 | (cond | ||
| 27531 | ((org-at-timestamp-p t) | ||
| 27532 | (call-interactively (if org-edit-timestamp-down-means-later | ||
| 27533 | 'org-timestamp-up 'org-timestamp-down))) | ||
| 27534 | ((org-on-heading-p) (call-interactively 'org-priority-down)) | ||
| 27535 | (t (call-interactively 'org-next-item)))) | ||
| 27536 | |||
| 27537 | (defun org-shiftright () | ||
| 27538 | "Next TODO keyword or timestamp one day later, depending on context." | ||
| 27539 | (interactive) | ||
| 27540 | (cond | ||
| 27541 | ((org-at-timestamp-p t) (call-interactively 'org-timestamp-up-day)) | ||
| 27542 | ((org-on-heading-p) (org-call-with-arg 'org-todo 'right)) | ||
| 27543 | ((org-at-item-p) (org-call-with-arg 'org-cycle-list-bullet nil)) | ||
| 27544 | ((org-at-property-p) (call-interactively 'org-property-next-allowed-value)) | ||
| 27545 | (t (org-shiftcursor-error)))) | ||
| 27546 | |||
| 27547 | (defun org-shiftleft () | ||
| 27548 | "Previous TODO keyword or timestamp one day earlier, depending on context." | ||
| 27549 | (interactive) | ||
| 27550 | (cond | ||
| 27551 | ((org-at-timestamp-p t) (call-interactively 'org-timestamp-down-day)) | ||
| 27552 | ((org-on-heading-p) (org-call-with-arg 'org-todo 'left)) | ||
| 27553 | ((org-at-item-p) (org-call-with-arg 'org-cycle-list-bullet 'previous)) | ||
| 27554 | ((org-at-property-p) | ||
| 27555 | (call-interactively 'org-property-previous-allowed-value)) | ||
| 27556 | (t (org-shiftcursor-error)))) | ||
| 27557 | |||
| 27558 | (defun org-shiftcontrolright () | ||
| 27559 | "Switch to next TODO set." | ||
| 27560 | (interactive) | ||
| 27561 | (cond | ||
| 27562 | ((org-on-heading-p) (org-call-with-arg 'org-todo 'nextset)) | ||
| 27563 | (t (org-shiftcursor-error)))) | ||
| 27564 | |||
| 27565 | (defun org-shiftcontrolleft () | ||
| 27566 | "Switch to previous TODO set." | ||
| 27567 | (interactive) | ||
| 27568 | (cond | ||
| 27569 | ((org-on-heading-p) (org-call-with-arg 'org-todo 'previousset)) | ||
| 27570 | (t (org-shiftcursor-error)))) | ||
| 27571 | |||
| 27572 | (defun org-ctrl-c-ret () | ||
| 27573 | "Call `org-table-hline-and-move' or `org-insert-heading' dep. on context." | ||
| 27574 | (interactive) | ||
| 27575 | (cond | ||
| 27576 | ((org-at-table-p) (call-interactively 'org-table-hline-and-move)) | ||
| 27577 | (t (call-interactively 'org-insert-heading)))) | ||
| 27578 | |||
| 27579 | (defun org-copy-special () | ||
| 27580 | "Copy region in table or copy current subtree. | ||
| 27581 | Calls `org-table-copy' or `org-copy-subtree', depending on context. | ||
| 27582 | See the individual commands for more information." | ||
| 27583 | (interactive) | ||
| 27584 | (call-interactively | ||
| 27585 | (if (org-at-table-p) 'org-table-copy-region 'org-copy-subtree))) | ||
| 27586 | |||
| 27587 | (defun org-cut-special () | ||
| 27588 | "Cut region in table or cut current subtree. | ||
| 27589 | Calls `org-table-copy' or `org-cut-subtree', depending on context. | ||
| 27590 | See the individual commands for more information." | ||
| 27591 | (interactive) | ||
| 27592 | (call-interactively | ||
| 27593 | (if (org-at-table-p) 'org-table-cut-region 'org-cut-subtree))) | ||
| 27594 | |||
| 27595 | (defun org-paste-special (arg) | ||
| 27596 | "Paste rectangular region into table, or past subtree relative to level. | ||
| 27597 | Calls `org-table-paste-rectangle' or `org-paste-subtree', depending on context. | ||
| 27598 | See the individual commands for more information." | ||
| 27599 | (interactive "P") | ||
| 27600 | (if (org-at-table-p) | ||
| 27601 | (org-table-paste-rectangle) | ||
| 27602 | (org-paste-subtree arg))) | ||
| 27603 | |||
| 27604 | (defun org-ctrl-c-ctrl-c (&optional arg) | ||
| 27605 | "Set tags in headline, or update according to changed information at point. | ||
| 27606 | |||
| 27607 | This command does many different things, depending on context: | ||
| 27608 | |||
| 27609 | - If the cursor is in a headline, prompt for tags and insert them | ||
| 27610 | into the current line, aligned to `org-tags-column'. When called | ||
| 27611 | with prefix arg, realign all tags in the current buffer. | ||
| 27612 | |||
| 27613 | - If the cursor is in one of the special #+KEYWORD lines, this | ||
| 27614 | triggers scanning the buffer for these lines and updating the | ||
| 27615 | information. | ||
| 27616 | |||
| 27617 | - If the cursor is inside a table, realign the table. This command | ||
| 27618 | works even if the automatic table editor has been turned off. | ||
| 27619 | |||
| 27620 | - If the cursor is on a #+TBLFM line, re-apply the formulas to | ||
| 27621 | the entire table. | ||
| 27622 | |||
| 27623 | - If the cursor is a the beginning of a dynamic block, update it. | ||
| 27624 | |||
| 27625 | - If the cursor is inside a table created by the table.el package, | ||
| 27626 | activate that table. | ||
| 27627 | |||
| 27628 | - If the current buffer is a remember buffer, close note and file it. | ||
| 27629 | with a prefix argument, file it without further interaction to the default | ||
| 27630 | location. | ||
| 27631 | |||
| 27632 | - If the cursor is on a <<<target>>>, update radio targets and corresponding | ||
| 27633 | links in this buffer. | ||
| 27634 | |||
| 27635 | - If the cursor is on a numbered item in a plain list, renumber the | ||
| 27636 | ordered list. | ||
| 27637 | |||
| 27638 | - If the cursor is on a checkbox, toggle it." | ||
| 27639 | (interactive "P") | ||
| 27640 | (let ((org-enable-table-editor t)) | ||
| 27641 | (cond | ||
| 27642 | ((or org-clock-overlays | ||
| 27643 | org-occur-highlights | ||
| 27644 | org-latex-fragment-image-overlays) | ||
| 27645 | (org-remove-clock-overlays) | ||
| 27646 | (org-remove-occur-highlights) | ||
| 27647 | (org-remove-latex-fragment-image-overlays) | ||
| 27648 | (message "Temporary highlights/overlays removed from current buffer")) | ||
| 27649 | ((and (local-variable-p 'org-finish-function (current-buffer)) | ||
| 27650 | (fboundp org-finish-function)) | ||
| 27651 | (funcall org-finish-function)) | ||
| 27652 | ((org-at-property-p) | ||
| 27653 | (call-interactively 'org-property-action)) | ||
| 27654 | ((org-on-target-p) (call-interactively 'org-update-radio-target-regexp)) | ||
| 27655 | ((org-on-heading-p) (call-interactively 'org-set-tags)) | ||
| 27656 | ((org-at-table.el-p) | ||
| 27657 | (require 'table) | ||
| 27658 | (beginning-of-line 1) | ||
| 27659 | (re-search-forward "|" (save-excursion (end-of-line 2) (point))) | ||
| 27660 | (call-interactively 'table-recognize-table)) | ||
| 27661 | ((org-at-table-p) | ||
| 27662 | (org-table-maybe-eval-formula) | ||
| 27663 | (if arg | ||
| 27664 | (call-interactively 'org-table-recalculate) | ||
| 27665 | (org-table-maybe-recalculate-line)) | ||
| 27666 | (call-interactively 'org-table-align)) | ||
| 27667 | ((org-at-item-checkbox-p) | ||
| 27668 | (call-interactively 'org-toggle-checkbox)) | ||
| 27669 | ((org-at-item-p) | ||
| 27670 | (call-interactively 'org-maybe-renumber-ordered-list)) | ||
| 27671 | ((save-excursion (beginning-of-line 1) (looking-at "#\\+BEGIN:")) | ||
| 27672 | ;; Dynamic block | ||
| 27673 | (beginning-of-line 1) | ||
| 27674 | (org-update-dblock)) | ||
| 27675 | ((save-excursion (beginning-of-line 1) (looking-at "#\\+\\([A-Z]+\\)")) | ||
| 27676 | (cond | ||
| 27677 | ((equal (match-string 1) "TBLFM") | ||
| 27678 | ;; Recalculate the table before this line | ||
| 27679 | (save-excursion | ||
| 27680 | (beginning-of-line 1) | ||
| 27681 | (skip-chars-backward " \r\n\t") | ||
| 27682 | (if (org-at-table-p) | ||
| 27683 | (org-call-with-arg 'org-table-recalculate t)))) | ||
| 27684 | (t | ||
| 27685 | (call-interactively 'org-mode-restart)))) | ||
| 27686 | (t (error "C-c C-c can do nothing useful at this location."))))) | ||
| 27687 | |||
| 27688 | (defun org-mode-restart () | ||
| 27689 | "Restart Org-mode, to scan again for special lines. | ||
| 27690 | Also updates the keyword regular expressions." | ||
| 27691 | (interactive) | ||
| 27692 | (let ((org-inhibit-startup t)) (org-mode)) | ||
| 27693 | (message "Org-mode restarted to refresh keyword and special line setup")) | ||
| 27694 | |||
| 27695 | (defun org-kill-note-or-show-branches () | ||
| 27696 | "If this is a Note buffer, abort storing the note. Else call `show-branches'." | ||
| 27697 | (interactive) | ||
| 27698 | (if (not org-finish-function) | ||
| 27699 | (call-interactively 'show-branches) | ||
| 27700 | (let ((org-note-abort t)) | ||
| 27701 | (funcall org-finish-function)))) | ||
| 27702 | |||
| 27703 | (defun org-return (&optional indent) | ||
| 27704 | "Goto next table row or insert a newline. | ||
| 27705 | Calls `org-table-next-row' or `newline', depending on context. | ||
| 27706 | See the individual commands for more information." | ||
| 27707 | (interactive) | ||
| 27708 | (cond | ||
| 27709 | ((bobp) (if indent (newline-and-indent) (newline))) | ||
| 27710 | ((and (org-at-heading-p) | ||
| 27711 | (looking-at | ||
| 27712 | (org-re "\\([ \t]+\\(:[[:alnum:]_@:]+:\\)\\)[ \t]*$"))) | ||
| 27713 | (org-show-entry) | ||
| 27714 | (end-of-line 1) | ||
| 27715 | (newline)) | ||
| 27716 | ((org-at-table-p) | ||
| 27717 | (org-table-justify-field-maybe) | ||
| 27718 | (call-interactively 'org-table-next-row)) | ||
| 27719 | (t (if indent (newline-and-indent) (newline))))) | ||
| 27720 | |||
| 27721 | (defun org-return-indent () | ||
| 27722 | "Goto next table row or insert a newline and indent. | ||
| 27723 | Calls `org-table-next-row' or `newline-and-indent', depending on | ||
| 27724 | context. See the individual commands for more information." | ||
| 27725 | (interactive) | ||
| 27726 | (org-return t)) | ||
| 27727 | |||
| 27728 | (defun org-ctrl-c-star () | ||
| 27729 | "Compute table, or change heading status of lines. | ||
| 27730 | Calls `org-table-recalculate' or `org-toggle-region-headlines', | ||
| 27731 | depending on context. This will also turn a plain list item or a normal | ||
| 27732 | line into a subheading." | ||
| 27733 | (interactive) | ||
| 27734 | (cond | ||
| 27735 | ((org-at-table-p) | ||
| 27736 | (call-interactively 'org-table-recalculate)) | ||
| 27737 | ((org-region-active-p) | ||
| 27738 | ;; Convert all lines in region to list items | ||
| 27739 | (call-interactively 'org-toggle-region-headings)) | ||
| 27740 | ((org-on-heading-p) | ||
| 27741 | (org-toggle-region-headings (point-at-bol) | ||
| 27742 | (min (1+ (point-at-eol)) (point-max)))) | ||
| 27743 | ((org-at-item-p) | ||
| 27744 | ;; Convert to heading | ||
| 27745 | (let ((level (save-match-data | ||
| 27746 | (save-excursion | ||
| 27747 | (condition-case nil | ||
| 27748 | (progn | ||
| 27749 | (org-back-to-heading t) | ||
| 27750 | (funcall outline-level)) | ||
| 27751 | (error 0)))))) | ||
| 27752 | (replace-match | ||
| 27753 | (concat (make-string (org-get-valid-level level 1) ?*) " ") t t))) | ||
| 27754 | (t (org-toggle-region-headings (point-at-bol) | ||
| 27755 | (min (1+ (point-at-eol)) (point-max)))))) | ||
| 27756 | |||
| 27757 | (defun org-ctrl-c-minus () | ||
| 27758 | "Insert separator line in table or modify bullet status of line. | ||
| 27759 | Also turns a plain line or a region of lines into list items. | ||
| 27760 | Calls `org-table-insert-hline', `org-toggle-region-items', or | ||
| 27761 | `org-cycle-list-bullet', depending on context." | ||
| 27762 | (interactive) | ||
| 27763 | (cond | ||
| 27764 | ((org-at-table-p) | ||
| 27765 | (call-interactively 'org-table-insert-hline)) | ||
| 27766 | ((org-on-heading-p) | ||
| 27767 | ;; Convert to item | ||
| 27768 | (save-excursion | ||
| 27769 | (beginning-of-line 1) | ||
| 27770 | (if (looking-at "\\*+ ") | ||
| 27771 | (replace-match (concat (make-string (- (match-end 0) (point) 1) ?\ ) "- "))))) | ||
| 27772 | ((org-region-active-p) | ||
| 27773 | ;; Convert all lines in region to list items | ||
| 27774 | (call-interactively 'org-toggle-region-items)) | ||
| 27775 | ((org-in-item-p) | ||
| 27776 | (call-interactively 'org-cycle-list-bullet)) | ||
| 27777 | (t (org-toggle-region-items (point-at-bol) | ||
| 27778 | (min (1+ (point-at-eol)) (point-max)))))) | ||
| 27779 | |||
| 27780 | (defun org-toggle-region-items (beg end) | ||
| 27781 | "Convert all lines in region to list items. | ||
| 27782 | If the first line is already an item, convert all list items in the region | ||
| 27783 | to normal lines." | ||
| 27784 | (interactive "r") | ||
| 27785 | (let (l2 l) | ||
| 27786 | (save-excursion | ||
| 27787 | (goto-char end) | ||
| 27788 | (setq l2 (org-current-line)) | ||
| 27789 | (goto-char beg) | ||
| 27790 | (beginning-of-line 1) | ||
| 27791 | (setq l (1- (org-current-line))) | ||
| 27792 | (if (org-at-item-p) | ||
| 27793 | ;; We already have items, de-itemize | ||
| 27794 | (while (< (setq l (1+ l)) l2) | ||
| 27795 | (when (org-at-item-p) | ||
| 27796 | (goto-char (match-beginning 2)) | ||
| 27797 | (delete-region (match-beginning 2) (match-end 2)) | ||
| 27798 | (and (looking-at "[ \t]+") (replace-match ""))) | ||
| 27799 | (beginning-of-line 2)) | ||
| 27800 | (while (< (setq l (1+ l)) l2) | ||
| 27801 | (unless (org-at-item-p) | ||
| 27802 | (if (looking-at "\\([ \t]*\\)\\(\\S-\\)") | ||
| 27803 | (replace-match "\\1- \\2"))) | ||
| 27804 | (beginning-of-line 2)))))) | ||
| 27805 | |||
| 27806 | (defun org-toggle-region-headings (beg end) | ||
| 27807 | "Convert all lines in region to list items. | ||
| 27808 | If the first line is already an item, convert all list items in the region | ||
| 27809 | to normal lines." | ||
| 27810 | (interactive "r") | ||
| 27811 | (let (l2 l) | ||
| 27812 | (save-excursion | ||
| 27813 | (goto-char end) | ||
| 27814 | (setq l2 (org-current-line)) | ||
| 27815 | (goto-char beg) | ||
| 27816 | (beginning-of-line 1) | ||
| 27817 | (setq l (1- (org-current-line))) | ||
| 27818 | (if (org-on-heading-p) | ||
| 27819 | ;; We already have headlines, de-star them | ||
| 27820 | (while (< (setq l (1+ l)) l2) | ||
| 27821 | (when (org-on-heading-p t) | ||
| 27822 | (and (looking-at outline-regexp) (replace-match ""))) | ||
| 27823 | (beginning-of-line 2)) | ||
| 27824 | (let* ((stars (save-excursion | ||
| 27825 | (re-search-backward org-complex-heading-regexp nil t) | ||
| 27826 | (or (match-string 1) "*"))) | ||
| 27827 | (add-stars (if org-odd-levels-only "**" "*")) | ||
| 27828 | (rpl (concat stars add-stars " \\2"))) | ||
| 27829 | (while (< (setq l (1+ l)) l2) | ||
| 27830 | (unless (org-on-heading-p) | ||
| 27831 | (if (looking-at "\\([ \t]*\\)\\(\\S-\\)") | ||
| 27832 | (replace-match rpl))) | ||
| 27833 | (beginning-of-line 2))))))) | ||
| 27834 | |||
| 27835 | (defun org-meta-return (&optional arg) | ||
| 27836 | "Insert a new heading or wrap a region in a table. | ||
| 27837 | Calls `org-insert-heading' or `org-table-wrap-region', depending on context. | ||
| 27838 | See the individual commands for more information." | ||
| 27839 | (interactive "P") | ||
| 27840 | (cond | ||
| 27841 | ((org-at-table-p) | ||
| 27842 | (call-interactively 'org-table-wrap-region)) | ||
| 27843 | (t (call-interactively 'org-insert-heading)))) | ||
| 27844 | |||
| 27845 | ;;; Menu entries | ||
| 27846 | |||
| 27847 | ;; Define the Org-mode menus | ||
| 27848 | (easy-menu-define org-tbl-menu org-mode-map "Tbl menu" | ||
| 27849 | '("Tbl" | ||
| 27850 | ["Align" org-ctrl-c-ctrl-c (org-at-table-p)] | ||
| 27851 | ["Next Field" org-cycle (org-at-table-p)] | ||
| 27852 | ["Previous Field" org-shifttab (org-at-table-p)] | ||
| 27853 | ["Next Row" org-return (org-at-table-p)] | ||
| 27854 | "--" | ||
| 27855 | ["Blank Field" org-table-blank-field (org-at-table-p)] | ||
| 27856 | ["Edit Field" org-table-edit-field (org-at-table-p)] | ||
| 27857 | ["Copy Field from Above" org-table-copy-down (org-at-table-p)] | ||
| 27858 | "--" | ||
| 27859 | ("Column" | ||
| 27860 | ["Move Column Left" org-metaleft (org-at-table-p)] | ||
| 27861 | ["Move Column Right" org-metaright (org-at-table-p)] | ||
| 27862 | ["Delete Column" org-shiftmetaleft (org-at-table-p)] | ||
| 27863 | ["Insert Column" org-shiftmetaright (org-at-table-p)]) | ||
| 27864 | ("Row" | ||
| 27865 | ["Move Row Up" org-metaup (org-at-table-p)] | ||
| 27866 | ["Move Row Down" org-metadown (org-at-table-p)] | ||
| 27867 | ["Delete Row" org-shiftmetaup (org-at-table-p)] | ||
| 27868 | ["Insert Row" org-shiftmetadown (org-at-table-p)] | ||
| 27869 | ["Sort lines in region" org-table-sort-lines (org-at-table-p)] | ||
| 27870 | "--" | ||
| 27871 | ["Insert Hline" org-ctrl-c-minus (org-at-table-p)]) | ||
| 27872 | ("Rectangle" | ||
| 27873 | ["Copy Rectangle" org-copy-special (org-at-table-p)] | ||
| 27874 | ["Cut Rectangle" org-cut-special (org-at-table-p)] | ||
| 27875 | ["Paste Rectangle" org-paste-special (org-at-table-p)] | ||
| 27876 | ["Fill Rectangle" org-table-wrap-region (org-at-table-p)]) | ||
| 27877 | "--" | ||
| 27878 | ("Calculate" | ||
| 27879 | ["Set Column Formula" org-table-eval-formula (org-at-table-p)] | ||
| 27880 | ["Set Field Formula" (org-table-eval-formula '(4)) :active (org-at-table-p) :keys "C-u C-c ="] | ||
| 27881 | ["Edit Formulas" org-table-edit-formulas (org-at-table-p)] | ||
| 27882 | "--" | ||
| 27883 | ["Recalculate line" org-table-recalculate (org-at-table-p)] | ||
| 27884 | ["Recalculate all" (lambda () (interactive) (org-table-recalculate '(4))) :active (org-at-table-p) :keys "C-u C-c *"] | ||
| 27885 | ["Iterate all" (lambda () (interactive) (org-table-recalculate '(16))) :active (org-at-table-p) :keys "C-u C-u C-c *"] | ||
| 27886 | "--" | ||
| 27887 | ["Toggle Recalculate Mark" org-table-rotate-recalc-marks (org-at-table-p)] | ||
| 27888 | "--" | ||
| 27889 | ["Sum Column/Rectangle" org-table-sum | ||
| 27890 | (or (org-at-table-p) (org-region-active-p))] | ||
| 27891 | ["Which Column?" org-table-current-column (org-at-table-p)]) | ||
| 27892 | ["Debug Formulas" | ||
| 27893 | org-table-toggle-formula-debugger | ||
| 27894 | :style toggle :selected org-table-formula-debug] | ||
| 27895 | ["Show Col/Row Numbers" | ||
| 27896 | org-table-toggle-coordinate-overlays | ||
| 27897 | :style toggle :selected org-table-overlay-coordinates] | ||
| 27898 | "--" | ||
| 27899 | ["Create" org-table-create (and (not (org-at-table-p)) | ||
| 27900 | org-enable-table-editor)] | ||
| 27901 | ["Convert Region" org-table-convert-region (not (org-at-table-p 'any))] | ||
| 27902 | ["Import from File" org-table-import (not (org-at-table-p))] | ||
| 27903 | ["Export to File" org-table-export (org-at-table-p)] | ||
| 27904 | "--" | ||
| 27905 | ["Create/Convert from/to table.el" org-table-create-with-table.el t])) | ||
| 27906 | |||
| 27907 | (easy-menu-define org-org-menu org-mode-map "Org menu" | ||
| 27908 | '("Org" | ||
| 27909 | ("Show/Hide" | ||
| 27910 | ["Cycle Visibility" org-cycle (or (bobp) (outline-on-heading-p))] | ||
| 27911 | ["Cycle Global Visibility" org-shifttab (not (org-at-table-p))] | ||
| 27912 | ["Sparse Tree" org-occur t] | ||
| 27913 | ["Reveal Context" org-reveal t] | ||
| 27914 | ["Show All" show-all t] | ||
| 27915 | "--" | ||
| 27916 | ["Subtree to indirect buffer" org-tree-to-indirect-buffer t]) | ||
| 27917 | "--" | ||
| 27918 | ["New Heading" org-insert-heading t] | ||
| 27919 | ("Navigate Headings" | ||
| 27920 | ["Up" outline-up-heading t] | ||
| 27921 | ["Next" outline-next-visible-heading t] | ||
| 27922 | ["Previous" outline-previous-visible-heading t] | ||
| 27923 | ["Next Same Level" outline-forward-same-level t] | ||
| 27924 | ["Previous Same Level" outline-backward-same-level t] | ||
| 27925 | "--" | ||
| 27926 | ["Jump" org-goto t]) | ||
| 27927 | ("Edit Structure" | ||
| 27928 | ["Move Subtree Up" org-shiftmetaup (not (org-at-table-p))] | ||
| 27929 | ["Move Subtree Down" org-shiftmetadown (not (org-at-table-p))] | ||
| 27930 | "--" | ||
| 27931 | ["Copy Subtree" org-copy-special (not (org-at-table-p))] | ||
| 27932 | ["Cut Subtree" org-cut-special (not (org-at-table-p))] | ||
| 27933 | ["Paste Subtree" org-paste-special (not (org-at-table-p))] | ||
| 27934 | "--" | ||
| 27935 | ["Promote Heading" org-metaleft (not (org-at-table-p))] | ||
| 27936 | ["Promote Subtree" org-shiftmetaleft (not (org-at-table-p))] | ||
| 27937 | ["Demote Heading" org-metaright (not (org-at-table-p))] | ||
| 27938 | ["Demote Subtree" org-shiftmetaright (not (org-at-table-p))] | ||
| 27939 | "--" | ||
| 27940 | ["Sort Region/Children" org-sort (not (org-at-table-p))] | ||
| 27941 | "--" | ||
| 27942 | ["Convert to odd levels" org-convert-to-odd-levels t] | ||
| 27943 | ["Convert to odd/even levels" org-convert-to-oddeven-levels t]) | ||
| 27944 | ("Editing" | ||
| 27945 | ["Emphasis..." org-emphasize t]) | ||
| 27946 | ("Archive" | ||
| 27947 | ["Toggle ARCHIVE tag" org-toggle-archive-tag t] | ||
| 27948 | ; ["Check and Tag Children" (org-toggle-archive-tag (4)) | ||
| 27949 | ; :active t :keys "C-u C-c C-x C-a"] | ||
| 27950 | ["Sparse trees open ARCHIVE trees" | ||
| 27951 | (setq org-sparse-tree-open-archived-trees | ||
| 27952 | (not org-sparse-tree-open-archived-trees)) | ||
| 27953 | :style toggle :selected org-sparse-tree-open-archived-trees] | ||
| 27954 | ["Cycling opens ARCHIVE trees" | ||
| 27955 | (setq org-cycle-open-archived-trees (not org-cycle-open-archived-trees)) | ||
| 27956 | :style toggle :selected org-cycle-open-archived-trees] | ||
| 27957 | ["Agenda includes ARCHIVE trees" | ||
| 27958 | (setq org-agenda-skip-archived-trees (not org-agenda-skip-archived-trees)) | ||
| 27959 | :style toggle :selected (not org-agenda-skip-archived-trees)] | ||
| 27960 | "--" | ||
| 27961 | ["Move Subtree to Archive" org-advertized-archive-subtree t] | ||
| 27962 | ; ["Check and Move Children" (org-archive-subtree '(4)) | ||
| 27963 | ; :active t :keys "C-u C-c C-x C-s"] | ||
| 27964 | ) | ||
| 27965 | "--" | ||
| 27966 | ("TODO Lists" | ||
| 27967 | ["TODO/DONE/-" org-todo t] | ||
| 27968 | ("Select keyword" | ||
| 27969 | ["Next keyword" org-shiftright (org-on-heading-p)] | ||
| 27970 | ["Previous keyword" org-shiftleft (org-on-heading-p)] | ||
| 27971 | ["Complete Keyword" org-complete (assq :todo-keyword (org-context))] | ||
| 27972 | ["Next keyword set" org-shiftcontrolright (and (> (length org-todo-sets) 1) (org-on-heading-p))] | ||
| 27973 | ["Previous keyword set" org-shiftcontrolright (and (> (length org-todo-sets) 1) (org-on-heading-p))]) | ||
| 27974 | ["Show TODO Tree" org-show-todo-tree t] | ||
| 27975 | ["Global TODO list" org-todo-list t] | ||
| 27976 | "--" | ||
| 27977 | ["Set Priority" org-priority t] | ||
| 27978 | ["Priority Up" org-shiftup t] | ||
| 27979 | ["Priority Down" org-shiftdown t]) | ||
| 27980 | ("TAGS and Properties" | ||
| 27981 | ["Set Tags" 'org-ctrl-c-ctrl-c (org-at-heading-p)] | ||
| 27982 | ["Change tag in region" 'org-change-tag-in-region (org-region-active-p)] | ||
| 27983 | "--" | ||
| 27984 | ["Set property" 'org-set-property t] | ||
| 27985 | ["Column view of properties" org-columns t] | ||
| 27986 | ["Insert Column View DBlock" org-insert-columns-dblock t]) | ||
| 27987 | ("Dates and Scheduling" | ||
| 27988 | ["Timestamp" org-time-stamp t] | ||
| 27989 | ["Timestamp (inactive)" org-time-stamp-inactive t] | ||
| 27990 | ("Change Date" | ||
| 27991 | ["1 Day Later" org-shiftright t] | ||
| 27992 | ["1 Day Earlier" org-shiftleft t] | ||
| 27993 | ["1 ... Later" org-shiftup t] | ||
| 27994 | ["1 ... Earlier" org-shiftdown t]) | ||
| 27995 | ["Compute Time Range" org-evaluate-time-range t] | ||
| 27996 | ["Schedule Item" org-schedule t] | ||
| 27997 | ["Deadline" org-deadline t] | ||
| 27998 | "--" | ||
| 27999 | ["Custom time format" org-toggle-time-stamp-overlays | ||
| 28000 | :style radio :selected org-display-custom-times] | ||
| 28001 | "--" | ||
| 28002 | ["Goto Calendar" org-goto-calendar t] | ||
| 28003 | ["Date from Calendar" org-date-from-calendar t]) | ||
| 28004 | ("Logging work" | ||
| 28005 | ["Clock in" org-clock-in t] | ||
| 28006 | ["Clock out" org-clock-out t] | ||
| 28007 | ["Clock cancel" org-clock-cancel t] | ||
| 28008 | ["Goto running clock" org-clock-goto t] | ||
| 28009 | ["Display times" org-clock-display t] | ||
| 28010 | ["Create clock table" org-clock-report t] | ||
| 28011 | "--" | ||
| 28012 | ["Record DONE time" | ||
| 28013 | (progn (setq org-log-done (not org-log-done)) | ||
| 28014 | (message "Switching to %s will %s record a timestamp" | ||
| 28015 | (car org-done-keywords) | ||
| 28016 | (if org-log-done "automatically" "not"))) | ||
| 28017 | :style toggle :selected org-log-done]) | ||
| 28018 | "--" | ||
| 28019 | ["Agenda Command..." org-agenda t] | ||
| 28020 | ["Set Restriction Lock" org-agenda-set-restriction-lock t] | ||
| 28021 | ("File List for Agenda") | ||
| 28022 | ("Special views current file" | ||
| 28023 | ["TODO Tree" org-show-todo-tree t] | ||
| 28024 | ["Check Deadlines" org-check-deadlines t] | ||
| 28025 | ["Timeline" org-timeline t] | ||
| 28026 | ["Tags Tree" org-tags-sparse-tree t]) | ||
| 28027 | "--" | ||
| 28028 | ("Hyperlinks" | ||
| 28029 | ["Store Link (Global)" org-store-link t] | ||
| 28030 | ["Insert Link" org-insert-link t] | ||
| 28031 | ["Follow Link" org-open-at-point t] | ||
| 28032 | "--" | ||
| 28033 | ["Next link" org-next-link t] | ||
| 28034 | ["Previous link" org-previous-link t] | ||
| 28035 | "--" | ||
| 28036 | ["Descriptive Links" | ||
| 28037 | (progn (org-add-to-invisibility-spec '(org-link)) (org-restart-font-lock)) | ||
| 28038 | :style radio :selected (member '(org-link) buffer-invisibility-spec)] | ||
| 28039 | ["Literal Links" | ||
| 28040 | (progn | ||
| 28041 | (org-remove-from-invisibility-spec '(org-link)) (org-restart-font-lock)) | ||
| 28042 | :style radio :selected (not (member '(org-link) buffer-invisibility-spec))]) | ||
| 28043 | "--" | ||
| 28044 | ["Export/Publish..." org-export t] | ||
| 28045 | ("LaTeX" | ||
| 28046 | ["Org CDLaTeX mode" org-cdlatex-mode :style toggle | ||
| 28047 | :selected org-cdlatex-mode] | ||
| 28048 | ["Insert Environment" cdlatex-environment (fboundp 'cdlatex-environment)] | ||
| 28049 | ["Insert math symbol" cdlatex-math-symbol (fboundp 'cdlatex-math-symbol)] | ||
| 28050 | ["Modify math symbol" org-cdlatex-math-modify | ||
| 28051 | (org-inside-LaTeX-fragment-p)] | ||
| 28052 | ["Export LaTeX fragments as images" | ||
| 28053 | (setq org-export-with-LaTeX-fragments (not org-export-with-LaTeX-fragments)) | ||
| 28054 | :style toggle :selected org-export-with-LaTeX-fragments]) | ||
| 28055 | "--" | ||
| 28056 | ("Documentation" | ||
| 28057 | ["Show Version" org-version t] | ||
| 28058 | ["Info Documentation" org-info t]) | ||
| 28059 | ("Customize" | ||
| 28060 | ["Browse Org Group" org-customize t] | ||
| 28061 | "--" | ||
| 28062 | ["Expand This Menu" org-create-customize-menu | ||
| 28063 | (fboundp 'customize-menu-create)]) | ||
| 28064 | "--" | ||
| 28065 | ["Refresh setup" org-mode-restart t] | ||
| 28066 | )) | ||
| 28067 | |||
| 28068 | (defun org-info (&optional node) | ||
| 28069 | "Read documentation for Org-mode in the info system. | ||
| 28070 | With optional NODE, go directly to that node." | ||
| 28071 | (interactive) | ||
| 28072 | (info (format "(org)%s" (or node "")))) | ||
| 28073 | |||
| 28074 | (defun org-install-agenda-files-menu () | ||
| 28075 | (let ((bl (buffer-list))) | ||
| 28076 | (save-excursion | ||
| 28077 | (while bl | ||
| 28078 | (set-buffer (pop bl)) | ||
| 28079 | (if (org-mode-p) (setq bl nil))) | ||
| 28080 | (when (org-mode-p) | ||
| 28081 | (easy-menu-change | ||
| 28082 | '("Org") "File List for Agenda" | ||
| 28083 | (append | ||
| 28084 | (list | ||
| 28085 | ["Edit File List" (org-edit-agenda-file-list) t] | ||
| 28086 | ["Add/Move Current File to Front of List" org-agenda-file-to-front t] | ||
| 28087 | ["Remove Current File from List" org-remove-file t] | ||
| 28088 | ["Cycle through agenda files" org-cycle-agenda-files t] | ||
| 28089 | ["Occur in all agenda files" org-occur-in-agenda-files t] | ||
| 28090 | "--") | ||
| 28091 | (mapcar 'org-file-menu-entry (org-agenda-files t)))))))) | ||
| 28092 | |||
| 28093 | ;;;; Documentation | ||
| 28094 | |||
| 28095 | (defun org-customize () | ||
| 28096 | "Call the customize function with org as argument." | ||
| 28097 | (interactive) | ||
| 28098 | (customize-browse 'org)) | ||
| 28099 | |||
| 28100 | (defun org-create-customize-menu () | ||
| 28101 | "Create a full customization menu for Org-mode, insert it into the menu." | ||
| 28102 | (interactive) | ||
| 28103 | (if (fboundp 'customize-menu-create) | ||
| 28104 | (progn | ||
| 28105 | (easy-menu-change | ||
| 28106 | '("Org") "Customize" | ||
| 28107 | `(["Browse Org group" org-customize t] | ||
| 28108 | "--" | ||
| 28109 | ,(customize-menu-create 'org) | ||
| 28110 | ["Set" Custom-set t] | ||
| 28111 | ["Save" Custom-save t] | ||
| 28112 | ["Reset to Current" Custom-reset-current t] | ||
| 28113 | ["Reset to Saved" Custom-reset-saved t] | ||
| 28114 | ["Reset to Standard Settings" Custom-reset-standard t])) | ||
| 28115 | (message "\"Org\"-menu now contains full customization menu")) | ||
| 28116 | (error "Cannot expand menu (outdated version of cus-edit.el)"))) | ||
| 28117 | |||
| 28118 | ;;;; Miscellaneous stuff | ||
| 28119 | |||
| 28120 | |||
| 28121 | ;;; Generally useful functions | ||
| 28122 | |||
| 28123 | (defun org-context () | ||
| 28124 | "Return a list of contexts of the current cursor position. | ||
| 28125 | If several contexts apply, all are returned. | ||
| 28126 | Each context entry is a list with a symbol naming the context, and | ||
| 28127 | two positions indicating start and end of the context. Possible | ||
| 28128 | contexts are: | ||
| 28129 | |||
| 28130 | :headline anywhere in a headline | ||
| 28131 | :headline-stars on the leading stars in a headline | ||
| 28132 | :todo-keyword on a TODO keyword (including DONE) in a headline | ||
| 28133 | :tags on the TAGS in a headline | ||
| 28134 | :priority on the priority cookie in a headline | ||
| 28135 | :item on the first line of a plain list item | ||
| 28136 | :item-bullet on the bullet/number of a plain list item | ||
| 28137 | :checkbox on the checkbox in a plain list item | ||
| 28138 | :table in an org-mode table | ||
| 28139 | :table-special on a special filed in a table | ||
| 28140 | :table-table in a table.el table | ||
| 28141 | :link on a hyperlink | ||
| 28142 | :keyword on a keyword: SCHEDULED, DEADLINE, CLOSE,COMMENT, QUOTE. | ||
| 28143 | :target on a <<target>> | ||
| 28144 | :radio-target on a <<<radio-target>>> | ||
| 28145 | :latex-fragment on a LaTeX fragment | ||
| 28146 | :latex-preview on a LaTeX fragment with overlayed preview image | ||
| 28147 | |||
| 28148 | This function expects the position to be visible because it uses font-lock | ||
| 28149 | faces as a help to recognize the following contexts: :table-special, :link, | ||
| 28150 | and :keyword." | ||
| 28151 | (let* ((f (get-text-property (point) 'face)) | ||
| 28152 | (faces (if (listp f) f (list f))) | ||
| 28153 | (p (point)) clist o) | ||
| 28154 | ;; First the large context | ||
| 28155 | (cond | ||
| 28156 | ((org-on-heading-p t) | ||
| 28157 | (push (list :headline (point-at-bol) (point-at-eol)) clist) | ||
| 28158 | (when (progn | ||
| 28159 | (beginning-of-line 1) | ||
| 28160 | (looking-at org-todo-line-tags-regexp)) | ||
| 28161 | (push (org-point-in-group p 1 :headline-stars) clist) | ||
| 28162 | (push (org-point-in-group p 2 :todo-keyword) clist) | ||
| 28163 | (push (org-point-in-group p 4 :tags) clist)) | ||
| 28164 | (goto-char p) | ||
| 28165 | (skip-chars-backward "^[\n\r \t") (or (eobp) (backward-char 1)) | ||
| 28166 | (if (looking-at "\\[#[A-Z0-9]\\]") | ||
| 28167 | (push (org-point-in-group p 0 :priority) clist))) | ||
| 28168 | |||
| 28169 | ((org-at-item-p) | ||
| 28170 | (push (org-point-in-group p 2 :item-bullet) clist) | ||
| 28171 | (push (list :item (point-at-bol) | ||
| 28172 | (save-excursion (org-end-of-item) (point))) | ||
| 28173 | clist) | ||
| 28174 | (and (org-at-item-checkbox-p) | ||
| 28175 | (push (org-point-in-group p 0 :checkbox) clist))) | ||
| 28176 | |||
| 28177 | ((org-at-table-p) | ||
| 28178 | (push (list :table (org-table-begin) (org-table-end)) clist) | ||
| 28179 | (if (memq 'org-formula faces) | ||
| 28180 | (push (list :table-special | ||
| 28181 | (previous-single-property-change p 'face) | ||
| 28182 | (next-single-property-change p 'face)) clist))) | ||
| 28183 | ((org-at-table-p 'any) | ||
| 28184 | (push (list :table-table) clist))) | ||
| 28185 | (goto-char p) | ||
| 28186 | |||
| 28187 | ;; Now the small context | ||
| 28188 | (cond | ||
| 28189 | ((org-at-timestamp-p) | ||
| 28190 | (push (org-point-in-group p 0 :timestamp) clist)) | ||
| 28191 | ((memq 'org-link faces) | ||
| 28192 | (push (list :link | ||
| 28193 | (previous-single-property-change p 'face) | ||
| 28194 | (next-single-property-change p 'face)) clist)) | ||
| 28195 | ((memq 'org-special-keyword faces) | ||
| 28196 | (push (list :keyword | ||
| 28197 | (previous-single-property-change p 'face) | ||
| 28198 | (next-single-property-change p 'face)) clist)) | ||
| 28199 | ((org-on-target-p) | ||
| 28200 | (push (org-point-in-group p 0 :target) clist) | ||
| 28201 | (goto-char (1- (match-beginning 0))) | ||
| 28202 | (if (looking-at org-radio-target-regexp) | ||
| 28203 | (push (org-point-in-group p 0 :radio-target) clist)) | ||
| 28204 | (goto-char p)) | ||
| 28205 | ((setq o (car (delq nil | ||
| 28206 | (mapcar | ||
| 28207 | (lambda (x) | ||
| 28208 | (if (memq x org-latex-fragment-image-overlays) x)) | ||
| 28209 | (org-overlays-at (point)))))) | ||
| 28210 | (push (list :latex-fragment | ||
| 28211 | (org-overlay-start o) (org-overlay-end o)) clist) | ||
| 28212 | (push (list :latex-preview | ||
| 28213 | (org-overlay-start o) (org-overlay-end o)) clist)) | ||
| 28214 | ((org-inside-LaTeX-fragment-p) | ||
| 28215 | ;; FIXME: positions wrong. | ||
| 28216 | (push (list :latex-fragment (point) (point)) clist))) | ||
| 28217 | |||
| 28218 | (setq clist (nreverse (delq nil clist))) | ||
| 28219 | clist)) | ||
| 28220 | |||
| 28221 | ;; FIXME: Compare with at-regexp-p Do we need both? | ||
| 28222 | (defun org-in-regexp (re &optional nlines visually) | ||
| 28223 | "Check if point is inside a match of regexp. | ||
| 28224 | Normally only the current line is checked, but you can include NLINES extra | ||
| 28225 | lines both before and after point into the search. | ||
| 28226 | If VISUALLY is set, require that the cursor is not after the match but | ||
| 28227 | really on, so that the block visually is on the match." | ||
| 28228 | (catch 'exit | ||
| 28229 | (let ((pos (point)) | ||
| 28230 | (eol (point-at-eol (+ 1 (or nlines 0)))) | ||
| 28231 | (inc (if visually 1 0))) | ||
| 28232 | (save-excursion | ||
| 28233 | (beginning-of-line (- 1 (or nlines 0))) | ||
| 28234 | (while (re-search-forward re eol t) | ||
| 28235 | (if (and (<= (match-beginning 0) pos) | ||
| 28236 | (>= (+ inc (match-end 0)) pos)) | ||
| 28237 | (throw 'exit (cons (match-beginning 0) (match-end 0))))))))) | ||
| 28238 | |||
| 28239 | (defun org-at-regexp-p (regexp) | ||
| 28240 | "Is point inside a match of REGEXP in the current line?" | ||
| 28241 | (catch 'exit | ||
| 28242 | (save-excursion | ||
| 28243 | (let ((pos (point)) (end (point-at-eol))) | ||
| 28244 | (beginning-of-line 1) | ||
| 28245 | (while (re-search-forward regexp end t) | ||
| 28246 | (if (and (<= (match-beginning 0) pos) | ||
| 28247 | (>= (match-end 0) pos)) | ||
| 28248 | (throw 'exit t))) | ||
| 28249 | nil)))) | ||
| 28250 | |||
| 28251 | (defun org-occur-in-agenda-files (regexp &optional nlines) | ||
| 28252 | "Call `multi-occur' with buffers for all agenda files." | ||
| 28253 | (interactive "sOrg-files matching: \np") | ||
| 28254 | (let* ((files (org-agenda-files)) | ||
| 28255 | (tnames (mapcar 'file-truename files)) | ||
| 28256 | (extra org-agenda-text-search-extra-files) | ||
| 28257 | f) | ||
| 28258 | (while (setq f (pop extra)) | ||
| 28259 | (unless (member (file-truename f) tnames) | ||
| 28260 | (add-to-list 'files f 'append) | ||
| 28261 | (add-to-list 'tnames (file-truename f) 'append))) | ||
| 28262 | (multi-occur | ||
| 28263 | (mapcar (lambda (x) (or (get-file-buffer x) (find-file-noselect x))) files) | ||
| 28264 | regexp))) | ||
| 28265 | |||
| 28266 | (if (boundp 'occur-mode-find-occurrence-hook) | ||
| 28267 | ;; Emacs 23 | ||
| 28268 | (add-hook 'occur-mode-find-occurrence-hook | ||
| 28269 | (lambda () | ||
| 28270 | (when (org-mode-p) | ||
| 28271 | (org-reveal)))) | ||
| 28272 | ;; Emacs 22 | ||
| 28273 | (defadvice occur-mode-goto-occurrence | ||
| 28274 | (after org-occur-reveal activate) | ||
| 28275 | (and (org-mode-p) (org-reveal))) | ||
| 28276 | (defadvice occur-mode-goto-occurrence-other-window | ||
| 28277 | (after org-occur-reveal activate) | ||
| 28278 | (and (org-mode-p) (org-reveal))) | ||
| 28279 | (defadvice occur-mode-display-occurrence | ||
| 28280 | (after org-occur-reveal activate) | ||
| 28281 | (when (org-mode-p) | ||
| 28282 | (let ((pos (occur-mode-find-occurrence))) | ||
| 28283 | (with-current-buffer (marker-buffer pos) | ||
| 28284 | (save-excursion | ||
| 28285 | (goto-char pos) | ||
| 28286 | (org-reveal))))))) | ||
| 28287 | |||
| 28288 | (defun org-uniquify (list) | ||
| 28289 | "Remove duplicate elements from LIST." | ||
| 28290 | (let (res) | ||
| 28291 | (mapc (lambda (x) (add-to-list 'res x 'append)) list) | ||
| 28292 | res)) | ||
| 28293 | |||
| 28294 | (defun org-delete-all (elts list) | ||
| 28295 | "Remove all elements in ELTS from LIST." | ||
| 28296 | (while elts | ||
| 28297 | (setq list (delete (pop elts) list))) | ||
| 28298 | list) | ||
| 28299 | |||
| 28300 | (defun org-back-over-empty-lines () | ||
| 28301 | "Move backwards over witespace, to the beginning of the first empty line. | ||
| 28302 | Returns the number of empty lines passed." | ||
| 28303 | (let ((pos (point))) | ||
| 28304 | (skip-chars-backward " \t\n\r") | ||
| 28305 | (beginning-of-line 2) | ||
| 28306 | (goto-char (min (point) pos)) | ||
| 28307 | (count-lines (point) pos))) | ||
| 28308 | |||
| 28309 | (defun org-skip-whitespace () | ||
| 28310 | (skip-chars-forward " \t\n\r")) | ||
| 28311 | |||
| 28312 | (defun org-point-in-group (point group &optional context) | ||
| 28313 | "Check if POINT is in match-group GROUP. | ||
| 28314 | If CONTEXT is non-nil, return a list with CONTEXT and the boundaries of the | ||
| 28315 | match. If the match group does ot exist or point is not inside it, | ||
| 28316 | return nil." | ||
| 28317 | (and (match-beginning group) | ||
| 28318 | (>= point (match-beginning group)) | ||
| 28319 | (<= point (match-end group)) | ||
| 28320 | (if context | ||
| 28321 | (list context (match-beginning group) (match-end group)) | ||
| 28322 | t))) | ||
| 28323 | |||
| 28324 | (defun org-switch-to-buffer-other-window (&rest args) | ||
| 28325 | "Switch to buffer in a second window on the current frame. | ||
| 28326 | In particular, do not allow pop-up frames." | ||
| 28327 | (let (pop-up-frames special-display-buffer-names special-display-regexps | ||
| 28328 | special-display-function) | ||
| 28329 | (apply 'switch-to-buffer-other-window args))) | ||
| 28330 | |||
| 28331 | (defun org-combine-plists (&rest plists) | ||
| 28332 | "Create a single property list from all plists in PLISTS. | ||
| 28333 | The process starts by copying the first list, and then setting properties | ||
| 28334 | from the other lists. Settings in the last list are the most significant | ||
| 28335 | ones and overrule settings in the other lists." | ||
| 28336 | (let ((rtn (copy-sequence (pop plists))) | ||
| 28337 | p v ls) | ||
| 28338 | (while plists | ||
| 28339 | (setq ls (pop plists)) | ||
| 28340 | (while ls | ||
| 28341 | (setq p (pop ls) v (pop ls)) | ||
| 28342 | (setq rtn (plist-put rtn p v)))) | ||
| 28343 | rtn)) | ||
| 28344 | |||
| 28345 | (defun org-move-line-down (arg) | ||
| 28346 | "Move the current line down. With prefix argument, move it past ARG lines." | ||
| 28347 | (interactive "p") | ||
| 28348 | (let ((col (current-column)) | ||
| 28349 | beg end pos) | ||
| 28350 | (beginning-of-line 1) (setq beg (point)) | ||
| 28351 | (beginning-of-line 2) (setq end (point)) | ||
| 28352 | (beginning-of-line (+ 1 arg)) | ||
| 28353 | (setq pos (move-marker (make-marker) (point))) | ||
| 28354 | (insert (delete-and-extract-region beg end)) | ||
| 28355 | (goto-char pos) | ||
| 28356 | (move-to-column col))) | ||
| 28357 | |||
| 28358 | (defun org-move-line-up (arg) | ||
| 28359 | "Move the current line up. With prefix argument, move it past ARG lines." | ||
| 28360 | (interactive "p") | ||
| 28361 | (let ((col (current-column)) | ||
| 28362 | beg end pos) | ||
| 28363 | (beginning-of-line 1) (setq beg (point)) | ||
| 28364 | (beginning-of-line 2) (setq end (point)) | ||
| 28365 | (beginning-of-line (- arg)) | ||
| 28366 | (setq pos (move-marker (make-marker) (point))) | ||
| 28367 | (insert (delete-and-extract-region beg end)) | ||
| 28368 | (goto-char pos) | ||
| 28369 | (move-to-column col))) | ||
| 28370 | |||
| 28371 | (defun org-replace-escapes (string table) | ||
| 28372 | "Replace %-escapes in STRING with values in TABLE. | ||
| 28373 | TABLE is an association list with keys like \"%a\" and string values. | ||
| 28374 | The sequences in STRING may contain normal field width and padding information, | ||
| 28375 | for example \"%-5s\". Replacements happen in the sequence given by TABLE, | ||
| 28376 | so values can contain further %-escapes if they are define later in TABLE." | ||
| 28377 | (let ((case-fold-search nil) | ||
| 28378 | e re rpl) | ||
| 28379 | (while (setq e (pop table)) | ||
| 28380 | (setq re (concat "%-?[0-9.]*" (substring (car e) 1))) | ||
| 28381 | (while (string-match re string) | ||
| 28382 | (setq rpl (format (concat (substring (match-string 0 string) 0 -1) "s") | ||
| 28383 | (cdr e))) | ||
| 28384 | (setq string (replace-match rpl t t string)))) | ||
| 28385 | string)) | ||
| 28386 | |||
| 28387 | |||
| 28388 | (defun org-sublist (list start end) | ||
| 28389 | "Return a section of LIST, from START to END. | ||
| 28390 | Counting starts at 1." | ||
| 28391 | (let (rtn (c start)) | ||
| 28392 | (setq list (nthcdr (1- start) list)) | ||
| 28393 | (while (and list (<= c end)) | ||
| 28394 | (push (pop list) rtn) | ||
| 28395 | (setq c (1+ c))) | ||
| 28396 | (nreverse rtn))) | ||
| 28397 | |||
| 28398 | (defun org-find-base-buffer-visiting (file) | ||
| 28399 | "Like `find-buffer-visiting' but alway return the base buffer and | ||
| 28400 | not an indirect buffer." | ||
| 28401 | (let ((buf (find-buffer-visiting file))) | ||
| 28402 | (if buf | ||
| 28403 | (or (buffer-base-buffer buf) buf) | ||
| 28404 | nil))) | ||
| 28405 | |||
| 28406 | (defun org-image-file-name-regexp () | ||
| 28407 | "Return regexp matching the file names of images." | ||
| 28408 | (if (fboundp 'image-file-name-regexp) | ||
| 28409 | (image-file-name-regexp) | ||
| 28410 | (let ((image-file-name-extensions | ||
| 28411 | '("png" "jpeg" "jpg" "gif" "tiff" "tif" | ||
| 28412 | "xbm" "xpm" "pbm" "pgm" "ppm"))) | ||
| 28413 | (concat "\\." | ||
| 28414 | (regexp-opt (nconc (mapcar 'upcase | ||
| 28415 | image-file-name-extensions) | ||
| 28416 | image-file-name-extensions) | ||
| 28417 | t) | ||
| 28418 | "\\'")))) | ||
| 28419 | |||
| 28420 | (defun org-file-image-p (file) | ||
| 28421 | "Return non-nil if FILE is an image." | ||
| 28422 | (save-match-data | ||
| 28423 | (string-match (org-image-file-name-regexp) file))) | ||
| 28424 | |||
| 28425 | ;;; Paragraph filling stuff. | ||
| 28426 | ;; We want this to be just right, so use the full arsenal. | ||
| 28427 | |||
| 28428 | (defun org-indent-line-function () | ||
| 28429 | "Indent line like previous, but further if previous was headline or item." | ||
| 28430 | (interactive) | ||
| 28431 | (let* ((pos (point)) | ||
| 28432 | (itemp (org-at-item-p)) | ||
| 28433 | column bpos bcol tpos tcol bullet btype bullet-type) | ||
| 28434 | ;; Find the previous relevant line | ||
| 28435 | (beginning-of-line 1) | ||
| 28436 | (cond | ||
| 28437 | ((looking-at "#") (setq column 0)) | ||
| 28438 | ((looking-at "\\*+ ") (setq column 0)) | ||
| 28439 | (t | ||
| 28440 | (beginning-of-line 0) | ||
| 28441 | (while (and (not (bobp)) (looking-at "[ \t]*[\n:#|]")) | ||
| 28442 | (beginning-of-line 0)) | ||
| 28443 | (cond | ||
| 28444 | ((looking-at "\\*+[ \t]+") | ||
| 28445 | (goto-char (match-end 0)) | ||
| 28446 | (setq column (current-column))) | ||
| 28447 | ((org-in-item-p) | ||
| 28448 | (org-beginning-of-item) | ||
| 28449 | ; (looking-at "[ \t]*\\(\\S-+\\)[ \t]*") | ||
| 28450 | (looking-at "[ \t]*\\(\\S-+\\)[ \t]*\\(\\[[- X]\\][ \t]*\\)?") | ||
| 28451 | (setq bpos (match-beginning 1) tpos (match-end 0) | ||
| 28452 | bcol (progn (goto-char bpos) (current-column)) | ||
| 28453 | tcol (progn (goto-char tpos) (current-column)) | ||
| 28454 | bullet (match-string 1) | ||
| 28455 | bullet-type (if (string-match "[0-9]" bullet) "n" bullet)) | ||
| 28456 | (if (not itemp) | ||
| 28457 | (setq column tcol) | ||
| 28458 | (goto-char pos) | ||
| 28459 | (beginning-of-line 1) | ||
| 28460 | (if (looking-at "\\S-") | ||
| 28461 | (progn | ||
| 28462 | (looking-at "[ \t]*\\(\\S-+\\)[ \t]*") | ||
| 28463 | (setq bullet (match-string 1) | ||
| 28464 | btype (if (string-match "[0-9]" bullet) "n" bullet)) | ||
| 28465 | (setq column (if (equal btype bullet-type) bcol tcol))) | ||
| 28466 | (setq column (org-get-indentation))))) | ||
| 28467 | (t (setq column (org-get-indentation)))))) | ||
| 28468 | (goto-char pos) | ||
| 28469 | (if (<= (current-column) (current-indentation)) | ||
| 28470 | (indent-line-to column) | ||
| 28471 | (save-excursion (indent-line-to column))) | ||
| 28472 | (setq column (current-column)) | ||
| 28473 | (beginning-of-line 1) | ||
| 28474 | (if (looking-at | ||
| 28475 | "\\([ \t]+\\)\\(:[-_0-9a-zA-Z]+:\\)[ \t]*\\(\\S-.*\\(\\S-\\|$\\)\\)") | ||
| 28476 | (replace-match (concat "\\1" (format org-property-format | ||
| 28477 | (match-string 2) (match-string 3))) | ||
| 28478 | t nil)) | ||
| 28479 | (move-to-column column))) | ||
| 28480 | |||
| 28481 | (defun org-set-autofill-regexps () | ||
| 28482 | (interactive) | ||
| 28483 | ;; In the paragraph separator we include headlines, because filling | ||
| 28484 | ;; text in a line directly attached to a headline would otherwise | ||
| 28485 | ;; fill the headline as well. | ||
| 28486 | (org-set-local 'comment-start-skip "^#+[ \t]*") | ||
| 28487 | (org-set-local 'paragraph-separate "\f\\|\\*+ \\|[ ]*$\\|[ \t]*[:|]") | ||
| 28488 | ;; The paragraph starter includes hand-formatted lists. | ||
| 28489 | (org-set-local 'paragraph-start | ||
| 28490 | "\f\\|[ ]*$\\|\\*+ \\|\f\\|[ \t]*\\([-+*][ \t]+\\|[0-9]+[.)][ \t]+\\)\\|[ \t]*[:|]") | ||
| 28491 | ;; Inhibit auto-fill for headers, tables and fixed-width lines. | ||
| 28492 | ;; But only if the user has not turned off tables or fixed-width regions | ||
| 28493 | (org-set-local | ||
| 28494 | 'auto-fill-inhibit-regexp | ||
| 28495 | (concat "\\*+ \\|#\\+" | ||
| 28496 | "\\|[ \t]*" org-keyword-time-regexp | ||
| 28497 | (if (or org-enable-table-editor org-enable-fixed-width-editor) | ||
| 28498 | (concat | ||
| 28499 | "\\|[ \t]*[" | ||
| 28500 | (if org-enable-table-editor "|" "") | ||
| 28501 | (if org-enable-fixed-width-editor ":" "") | ||
| 28502 | "]")))) | ||
| 28503 | ;; We use our own fill-paragraph function, to make sure that tables | ||
| 28504 | ;; and fixed-width regions are not wrapped. That function will pass | ||
| 28505 | ;; through to `fill-paragraph' when appropriate. | ||
| 28506 | (org-set-local 'fill-paragraph-function 'org-fill-paragraph) | ||
| 28507 | ; Adaptive filling: To get full control, first make sure that | ||
| 28508 | ;; `adaptive-fill-regexp' never matches. Then install our own matcher. | ||
| 28509 | (org-set-local 'adaptive-fill-regexp "\000") | ||
| 28510 | (org-set-local 'adaptive-fill-function | ||
| 28511 | 'org-adaptive-fill-function) | ||
| 28512 | (org-set-local | ||
| 28513 | 'align-mode-rules-list | ||
| 28514 | '((org-in-buffer-settings | ||
| 28515 | (regexp . "^#\\+[A-Z_]+:\\(\\s-*\\)\\S-+") | ||
| 28516 | (modes . '(org-mode)))))) | ||
| 28517 | |||
| 28518 | (defun org-fill-paragraph (&optional justify) | ||
| 28519 | "Re-align a table, pass through to fill-paragraph if no table." | ||
| 28520 | (let ((table-p (org-at-table-p)) | ||
| 28521 | (table.el-p (org-at-table.el-p))) | ||
| 28522 | (cond ((and (equal (char-after (point-at-bol)) ?*) | ||
| 28523 | (save-excursion (goto-char (point-at-bol)) | ||
| 28524 | (looking-at outline-regexp))) | ||
| 28525 | t) ; skip headlines | ||
| 28526 | (table.el-p t) ; skip table.el tables | ||
| 28527 | (table-p (org-table-align) t) ; align org-mode tables | ||
| 28528 | (t nil)))) ; call paragraph-fill | ||
| 28529 | |||
| 28530 | ;; For reference, this is the default value of adaptive-fill-regexp | ||
| 28531 | ;; "[ \t]*\\([-|#;>*]+[ \t]*\\|(?[0-9]+[.)][ \t]*\\)*" | ||
| 28532 | |||
| 28533 | (defun org-adaptive-fill-function () | ||
| 28534 | "Return a fill prefix for org-mode files. | ||
| 28535 | In particular, this makes sure hanging paragraphs for hand-formatted lists | ||
| 28536 | work correctly." | ||
| 28537 | (cond ((looking-at "#[ \t]+") | ||
| 28538 | (match-string 0)) | ||
| 28539 | ((looking-at "[ \t]*\\([-*+] \\|[0-9]+[.)] \\)?") | ||
| 28540 | (save-excursion | ||
| 28541 | (goto-char (match-end 0)) | ||
| 28542 | (make-string (current-column) ?\ ))) | ||
| 28543 | (t nil))) | ||
| 28544 | |||
| 28545 | ;;;; Functions extending outline functionality | ||
| 28546 | |||
| 28547 | |||
| 28548 | (defun org-beginning-of-line (&optional arg) | ||
| 28549 | "Go to the beginning of the current line. If that is invisible, continue | ||
| 28550 | to a visible line beginning. This makes the function of C-a more intuitive. | ||
| 28551 | If this is a headline, and `org-special-ctrl-a/e' is set, ignore tags on the | ||
| 28552 | first attempt, and only move to after the tags when the cursor is already | ||
| 28553 | beyond the end of the headline." | ||
| 28554 | (interactive "P") | ||
| 28555 | (let ((pos (point))) | ||
| 28556 | (beginning-of-line 1) | ||
| 28557 | (if (bobp) | ||
| 28558 | nil | ||
| 28559 | (backward-char 1) | ||
| 28560 | (if (org-invisible-p) | ||
| 28561 | (while (and (not (bobp)) (org-invisible-p)) | ||
| 28562 | (backward-char 1) | ||
| 28563 | (beginning-of-line 1)) | ||
| 28564 | (forward-char 1))) | ||
| 28565 | (when org-special-ctrl-a/e | ||
| 28566 | (cond | ||
| 28567 | ((and (looking-at org-todo-line-regexp) | ||
| 28568 | (= (char-after (match-end 1)) ?\ )) | ||
| 28569 | (goto-char | ||
| 28570 | (if (eq org-special-ctrl-a/e t) | ||
| 28571 | (cond ((> pos (match-beginning 3)) (match-beginning 3)) | ||
| 28572 | ((= pos (point)) (match-beginning 3)) | ||
| 28573 | (t (point))) | ||
| 28574 | (cond ((> pos (point)) (point)) | ||
| 28575 | ((not (eq last-command this-command)) (point)) | ||
| 28576 | (t (match-beginning 3)))))) | ||
| 28577 | ((org-at-item-p) | ||
| 28578 | (goto-char | ||
| 28579 | (if (eq org-special-ctrl-a/e t) | ||
| 28580 | (cond ((> pos (match-end 4)) (match-end 4)) | ||
| 28581 | ((= pos (point)) (match-end 4)) | ||
| 28582 | (t (point))) | ||
| 28583 | (cond ((> pos (point)) (point)) | ||
| 28584 | ((not (eq last-command this-command)) (point)) | ||
| 28585 | (t (match-end 4)))))))))) | ||
| 28586 | |||
| 28587 | (defun org-end-of-line (&optional arg) | ||
| 28588 | "Go to the end of the line. | ||
| 28589 | If this is a headline, and `org-special-ctrl-a/e' is set, ignore tags on the | ||
| 28590 | first attempt, and only move to after the tags when the cursor is already | ||
| 28591 | beyond the end of the headline." | ||
| 28592 | (interactive "P") | ||
| 28593 | (if (or (not org-special-ctrl-a/e) | ||
| 28594 | (not (org-on-heading-p))) | ||
| 28595 | (end-of-line arg) | ||
| 28596 | (let ((pos (point))) | ||
| 28597 | (beginning-of-line 1) | ||
| 28598 | (if (looking-at (org-re ".*?\\([ \t]*\\)\\(:[[:alnum:]_@:]+:\\)[ \t]*$")) | ||
| 28599 | (if (eq org-special-ctrl-a/e t) | ||
| 28600 | (if (or (< pos (match-beginning 1)) | ||
| 28601 | (= pos (match-end 0))) | ||
| 28602 | (goto-char (match-beginning 1)) | ||
| 28603 | (goto-char (match-end 0))) | ||
| 28604 | (if (or (< pos (match-end 0)) (not (eq this-command last-command))) | ||
| 28605 | (goto-char (match-end 0)) | ||
| 28606 | (goto-char (match-beginning 1)))) | ||
| 28607 | (end-of-line arg))))) | ||
| 28608 | |||
| 28609 | (define-key org-mode-map "\C-a" 'org-beginning-of-line) | ||
| 28610 | (define-key org-mode-map "\C-e" 'org-end-of-line) | ||
| 28611 | |||
| 28612 | (defun org-kill-line (&optional arg) | ||
| 28613 | "Kill line, to tags or end of line." | ||
| 28614 | (interactive "P") | ||
| 28615 | (cond | ||
| 28616 | ((or (not org-special-ctrl-k) | ||
| 28617 | (bolp) | ||
| 28618 | (not (org-on-heading-p))) | ||
| 28619 | (call-interactively 'kill-line)) | ||
| 28620 | ((looking-at (org-re ".*?\\S-\\([ \t]+\\(:[[:alnum:]_@:]+:\\)\\)[ \t]*$")) | ||
| 28621 | (kill-region (point) (match-beginning 1)) | ||
| 28622 | (org-set-tags nil t)) | ||
| 28623 | (t (kill-region (point) (point-at-eol))))) | ||
| 28624 | |||
| 28625 | (define-key org-mode-map "\C-k" 'org-kill-line) | ||
| 28626 | |||
| 28627 | (defun org-invisible-p () | ||
| 28628 | "Check if point is at a character currently not visible." | ||
| 28629 | ;; Early versions of noutline don't have `outline-invisible-p'. | ||
| 28630 | (if (fboundp 'outline-invisible-p) | ||
| 28631 | (outline-invisible-p) | ||
| 28632 | (get-char-property (point) 'invisible))) | ||
| 28633 | |||
| 28634 | (defun org-invisible-p2 () | ||
| 28635 | "Check if point is at a character currently not visible." | ||
| 28636 | (save-excursion | ||
| 28637 | (if (and (eolp) (not (bobp))) (backward-char 1)) | ||
| 28638 | ;; Early versions of noutline don't have `outline-invisible-p'. | ||
| 28639 | (if (fboundp 'outline-invisible-p) | ||
| 28640 | (outline-invisible-p) | ||
| 28641 | (get-char-property (point) 'invisible)))) | ||
| 28642 | |||
| 28643 | (defalias 'org-back-to-heading 'outline-back-to-heading) | ||
| 28644 | (defalias 'org-on-heading-p 'outline-on-heading-p) | ||
| 28645 | (defalias 'org-at-heading-p 'outline-on-heading-p) | ||
| 28646 | (defun org-at-heading-or-item-p () | ||
| 28647 | (or (org-on-heading-p) (org-at-item-p))) | ||
| 28648 | |||
| 28649 | (defun org-on-target-p () | ||
| 28650 | (or (org-in-regexp org-radio-target-regexp) | ||
| 28651 | (org-in-regexp org-target-regexp))) | ||
| 28652 | |||
| 28653 | (defun org-up-heading-all (arg) | ||
| 28654 | "Move to the heading line of which the present line is a subheading. | ||
| 28655 | This function considers both visible and invisible heading lines. | ||
| 28656 | With argument, move up ARG levels." | ||
| 28657 | (if (fboundp 'outline-up-heading-all) | ||
| 28658 | (outline-up-heading-all arg) ; emacs 21 version of outline.el | ||
| 28659 | (outline-up-heading arg t))) ; emacs 22 version of outline.el | ||
| 28660 | |||
| 28661 | (defun org-up-heading-safe () | ||
| 28662 | "Move to the heading line of which the present line is a subheading. | ||
| 28663 | This version will not throw an error. It will return the level of the | ||
| 28664 | headline found, or nil if no higher level is found." | ||
| 28665 | (let ((pos (point)) start-level level | ||
| 28666 | (re (concat "^" outline-regexp))) | ||
| 28667 | (catch 'exit | ||
| 28668 | (outline-back-to-heading t) | ||
| 28669 | (setq start-level (funcall outline-level)) | ||
| 28670 | (if (equal start-level 1) (throw 'exit nil)) | ||
| 28671 | (while (re-search-backward re nil t) | ||
| 28672 | (setq level (funcall outline-level)) | ||
| 28673 | (if (< level start-level) (throw 'exit level))) | ||
| 28674 | nil))) | ||
| 28675 | |||
| 28676 | (defun org-first-sibling-p () | ||
| 28677 | "Is this heading the first child of its parents?" | ||
| 28678 | (interactive) | ||
| 28679 | (let ((re (concat "^" outline-regexp)) | ||
| 28680 | level l) | ||
| 28681 | (unless (org-at-heading-p t) | ||
| 28682 | (error "Not at a heading")) | ||
| 28683 | (setq level (funcall outline-level)) | ||
| 28684 | (save-excursion | ||
| 28685 | (if (not (re-search-backward re nil t)) | ||
| 28686 | t | ||
| 28687 | (setq l (funcall outline-level)) | ||
| 28688 | (< l level))))) | ||
| 28689 | |||
| 28690 | (defun org-goto-sibling (&optional previous) | ||
| 28691 | "Goto the next sibling, even if it is invisible. | ||
| 28692 | When PREVIOUS is set, go to the previous sibling instead. Returns t | ||
| 28693 | when a sibling was found. When none is found, return nil and don't | ||
| 28694 | move point." | ||
| 28695 | (let ((fun (if previous 're-search-backward 're-search-forward)) | ||
| 28696 | (pos (point)) | ||
| 28697 | (re (concat "^" outline-regexp)) | ||
| 28698 | level l) | ||
| 28699 | (when (condition-case nil (org-back-to-heading t) (error nil)) | ||
| 28700 | (setq level (funcall outline-level)) | ||
| 28701 | (catch 'exit | ||
| 28702 | (or previous (forward-char 1)) | ||
| 28703 | (while (funcall fun re nil t) | ||
| 28704 | (setq l (funcall outline-level)) | ||
| 28705 | (when (< l level) (goto-char pos) (throw 'exit nil)) | ||
| 28706 | (when (= l level) (goto-char (match-beginning 0)) (throw 'exit t))) | ||
| 28707 | (goto-char pos) | ||
| 28708 | nil)))) | ||
| 28709 | |||
| 28710 | (defun org-show-siblings () | ||
| 28711 | "Show all siblings of the current headline." | ||
| 28712 | (save-excursion | ||
| 28713 | (while (org-goto-sibling) (org-flag-heading nil))) | ||
| 28714 | (save-excursion | ||
| 28715 | (while (org-goto-sibling 'previous) | ||
| 28716 | (org-flag-heading nil)))) | ||
| 28717 | |||
| 28718 | (defun org-show-hidden-entry () | ||
| 28719 | "Show an entry where even the heading is hidden." | ||
| 28720 | (save-excursion | ||
| 28721 | (org-show-entry))) | ||
| 28722 | |||
| 28723 | (defun org-flag-heading (flag &optional entry) | ||
| 28724 | "Flag the current heading. FLAG non-nil means make invisible. | ||
| 28725 | When ENTRY is non-nil, show the entire entry." | ||
| 28726 | (save-excursion | ||
| 28727 | (org-back-to-heading t) | ||
| 28728 | ;; Check if we should show the entire entry | ||
| 28729 | (if entry | ||
| 28730 | (progn | ||
| 28731 | (org-show-entry) | ||
| 28732 | (save-excursion | ||
| 28733 | (and (outline-next-heading) | ||
| 28734 | (org-flag-heading nil)))) | ||
| 28735 | (outline-flag-region (max (point-min) (1- (point))) | ||
| 28736 | (save-excursion (outline-end-of-heading) (point)) | ||
| 28737 | flag)))) | ||
| 28738 | |||
| 28739 | (defun org-end-of-subtree (&optional invisible-OK to-heading) | ||
| 28740 | ;; This is an exact copy of the original function, but it uses | ||
| 28741 | ;; `org-back-to-heading', to make it work also in invisible | ||
| 28742 | ;; trees. And is uses an invisible-OK argument. | ||
| 28743 | ;; Under Emacs this is not needed, but the old outline.el needs this fix. | ||
| 28744 | (org-back-to-heading invisible-OK) | ||
| 28745 | (let ((first t) | ||
| 28746 | (level (funcall outline-level))) | ||
| 28747 | (while (and (not (eobp)) | ||
| 28748 | (or first (> (funcall outline-level) level))) | ||
| 28749 | (setq first nil) | ||
| 28750 | (outline-next-heading)) | ||
| 28751 | (unless to-heading | ||
| 28752 | (if (memq (preceding-char) '(?\n ?\^M)) | ||
| 28753 | (progn | ||
| 28754 | ;; Go to end of line before heading | ||
| 28755 | (forward-char -1) | ||
| 28756 | (if (memq (preceding-char) '(?\n ?\^M)) | ||
| 28757 | ;; leave blank line before heading | ||
| 28758 | (forward-char -1)))))) | ||
| 28759 | (point)) | ||
| 28760 | |||
| 28761 | (defun org-show-subtree () | ||
| 28762 | "Show everything after this heading at deeper levels." | ||
| 28763 | (outline-flag-region | ||
| 28764 | (point) | ||
| 28765 | (save-excursion | ||
| 28766 | (outline-end-of-subtree) (outline-next-heading) (point)) | ||
| 28767 | nil)) | ||
| 28768 | |||
| 28769 | (defun org-show-entry () | ||
| 28770 | "Show the body directly following this heading. | ||
| 28771 | Show the heading too, if it is currently invisible." | ||
| 28772 | (interactive) | ||
| 28773 | (save-excursion | ||
| 28774 | (condition-case nil | ||
| 28775 | (progn | ||
| 28776 | (org-back-to-heading t) | ||
| 28777 | (outline-flag-region | ||
| 28778 | (max (point-min) (1- (point))) | ||
| 28779 | (save-excursion | ||
| 28780 | (re-search-forward | ||
| 28781 | (concat "[\r\n]\\(" outline-regexp "\\)") nil 'move) | ||
| 28782 | (or (match-beginning 1) (point-max))) | ||
| 28783 | nil)) | ||
| 28784 | (error nil)))) | ||
| 28785 | |||
| 28786 | (defun org-make-options-regexp (kwds) | ||
| 28787 | "Make a regular expression for keyword lines." | ||
| 28788 | (concat | ||
| 28789 | "^" | ||
| 28790 | "#?[ \t]*\\+\\(" | ||
| 28791 | (mapconcat 'regexp-quote kwds "\\|") | ||
| 28792 | "\\):[ \t]*" | ||
| 28793 | "\\(.+\\)")) | ||
| 28794 | |||
| 28795 | ;; Make isearch reveal the necessary context | ||
| 28796 | (defun org-isearch-end () | ||
| 28797 | "Reveal context after isearch exits." | ||
| 28798 | (when isearch-success ; only if search was successful | ||
| 28799 | (if (featurep 'xemacs) | ||
| 28800 | ;; Under XEmacs, the hook is run in the correct place, | ||
| 28801 | ;; we directly show the context. | ||
| 28802 | (org-show-context 'isearch) | ||
| 28803 | ;; In Emacs the hook runs *before* restoring the overlays. | ||
| 28804 | ;; So we have to use a one-time post-command-hook to do this. | ||
| 28805 | ;; (Emacs 22 has a special variable, see function `org-mode') | ||
| 28806 | (unless (and (boundp 'isearch-mode-end-hook-quit) | ||
| 28807 | isearch-mode-end-hook-quit) | ||
| 28808 | ;; Only when the isearch was not quitted. | ||
| 28809 | (org-add-hook 'post-command-hook 'org-isearch-post-command | ||
| 28810 | 'append 'local))))) | ||
| 28811 | |||
| 28812 | (defun org-isearch-post-command () | ||
| 28813 | "Remove self from hook, and show context." | ||
| 28814 | (remove-hook 'post-command-hook 'org-isearch-post-command 'local) | ||
| 28815 | (org-show-context 'isearch)) | ||
| 28816 | |||
| 28817 | |||
| 28818 | ;;;; Integration with and fixes for other packages | ||
| 28819 | |||
| 28820 | ;;; Imenu support | ||
| 28821 | |||
| 28822 | (defvar org-imenu-markers nil | ||
| 28823 | "All markers currently used by Imenu.") | ||
| 28824 | (make-variable-buffer-local 'org-imenu-markers) | ||
| 28825 | |||
| 28826 | (defun org-imenu-new-marker (&optional pos) | ||
| 28827 | "Return a new marker for use by Imenu, and remember the marker." | ||
| 28828 | (let ((m (make-marker))) | ||
| 28829 | (move-marker m (or pos (point))) | ||
| 28830 | (push m org-imenu-markers) | ||
| 28831 | m)) | ||
| 28832 | |||
| 28833 | (defun org-imenu-get-tree () | ||
| 28834 | "Produce the index for Imenu." | ||
| 28835 | (mapc (lambda (x) (move-marker x nil)) org-imenu-markers) | ||
| 28836 | (setq org-imenu-markers nil) | ||
| 28837 | (let* ((n org-imenu-depth) | ||
| 28838 | (re (concat "^" outline-regexp)) | ||
| 28839 | (subs (make-vector (1+ n) nil)) | ||
| 28840 | (last-level 0) | ||
| 28841 | m tree level head) | ||
| 28842 | (save-excursion | ||
| 28843 | (save-restriction | ||
| 28844 | (widen) | ||
| 28845 | (goto-char (point-max)) | ||
| 28846 | (while (re-search-backward re nil t) | ||
| 28847 | (setq level (org-reduced-level (funcall outline-level))) | ||
| 28848 | (when (<= level n) | ||
| 28849 | (looking-at org-complex-heading-regexp) | ||
| 28850 | (setq head (org-match-string-no-properties 4) | ||
| 28851 | m (org-imenu-new-marker)) | ||
| 28852 | (org-add-props head nil 'org-imenu-marker m 'org-imenu t) | ||
| 28853 | (if (>= level last-level) | ||
| 28854 | (push (cons head m) (aref subs level)) | ||
| 28855 | (push (cons head (aref subs (1+ level))) (aref subs level)) | ||
| 28856 | (loop for i from (1+ level) to n do (aset subs i nil))) | ||
| 28857 | (setq last-level level))))) | ||
| 28858 | (aref subs 1))) | ||
| 28859 | |||
| 28860 | (eval-after-load "imenu" | ||
| 28861 | '(progn | ||
| 28862 | (add-hook 'imenu-after-jump-hook | ||
| 28863 | (lambda () (org-show-context 'org-goto))))) | ||
| 28864 | |||
| 28865 | ;; Speedbar support | ||
| 28866 | |||
| 28867 | (defun org-speedbar-set-agenda-restriction () | ||
| 28868 | "Restrict future agenda commands to the location at point in speedbar. | ||
| 28869 | To get rid of the restriction, use \\[org-agenda-remove-restriction-lock]." | ||
| 28870 | (interactive) | ||
| 28871 | (let (p m tp np dir txt w) | ||
| 28872 | (cond | ||
| 28873 | ((setq p (text-property-any (point-at-bol) (point-at-eol) | ||
| 28874 | 'org-imenu t)) | ||
| 28875 | (setq m (get-text-property p 'org-imenu-marker)) | ||
| 28876 | (save-excursion | ||
| 28877 | (save-restriction | ||
| 28878 | (set-buffer (marker-buffer m)) | ||
| 28879 | (goto-char m) | ||
| 28880 | (org-agenda-set-restriction-lock 'subtree)))) | ||
| 28881 | ((setq p (text-property-any (point-at-bol) (point-at-eol) | ||
| 28882 | 'speedbar-function 'speedbar-find-file)) | ||
| 28883 | (setq tp (previous-single-property-change | ||
| 28884 | (1+ p) 'speedbar-function) | ||
| 28885 | np (next-single-property-change | ||
| 28886 | tp 'speedbar-function) | ||
| 28887 | dir (speedbar-line-directory) | ||
| 28888 | txt (buffer-substring-no-properties (or tp (point-min)) | ||
| 28889 | (or np (point-max)))) | ||
| 28890 | (save-excursion | ||
| 28891 | (save-restriction | ||
| 28892 | (set-buffer (find-file-noselect | ||
| 28893 | (let ((default-directory dir)) | ||
| 28894 | (expand-file-name txt)))) | ||
| 28895 | (unless (org-mode-p) | ||
| 28896 | (error "Cannot restrict to non-Org-mode file")) | ||
| 28897 | (org-agenda-set-restriction-lock 'file)))) | ||
| 28898 | (t (error "Don't know how to restrict Org-mode's agenda"))) | ||
| 28899 | (org-move-overlay org-speedbar-restriction-lock-overlay | ||
| 28900 | (point-at-bol) (point-at-eol)) | ||
| 28901 | (setq current-prefix-arg nil) | ||
| 28902 | (org-agenda-maybe-redo))) | ||
| 28903 | |||
| 28904 | (eval-after-load "speedbar" | ||
| 28905 | '(progn | ||
| 28906 | (speedbar-add-supported-extension ".org") | ||
| 28907 | (define-key speedbar-file-key-map "<" 'org-speedbar-set-agenda-restriction) | ||
| 28908 | (define-key speedbar-file-key-map "\C-c\C-x<" 'org-speedbar-set-agenda-restriction) | ||
| 28909 | (define-key speedbar-file-key-map ">" 'org-agenda-remove-restriction-lock) | ||
| 28910 | (define-key speedbar-file-key-map "\C-c\C-x>" 'org-agenda-remove-restriction-lock) | ||
| 28911 | (add-hook 'speedbar-visiting-tag-hook | ||
| 28912 | (lambda () (org-show-context 'org-goto))))) | ||
| 28913 | |||
| 28914 | |||
| 28915 | ;;; Fixes and Hacks | ||
| 28916 | |||
| 28917 | ;; Make flyspell not check words in links, to not mess up our keymap | ||
| 28918 | (defun org-mode-flyspell-verify () | ||
| 28919 | "Don't let flyspell put overlays at active buttons." | ||
| 28920 | (not (get-text-property (point) 'keymap))) | ||
| 28921 | |||
| 28922 | ;; Make `bookmark-jump' show the jump location if it was hidden. | ||
| 28923 | (eval-after-load "bookmark" | ||
| 28924 | '(if (boundp 'bookmark-after-jump-hook) | ||
| 28925 | ;; We can use the hook | ||
| 28926 | (add-hook 'bookmark-after-jump-hook 'org-bookmark-jump-unhide) | ||
| 28927 | ;; Hook not available, use advice | ||
| 28928 | (defadvice bookmark-jump (after org-make-visible activate) | ||
| 28929 | "Make the position visible." | ||
| 28930 | (org-bookmark-jump-unhide)))) | ||
| 28931 | |||
| 28932 | (defun org-bookmark-jump-unhide () | ||
| 28933 | "Unhide the current position, to show the bookmark location." | ||
| 28934 | (and (org-mode-p) | ||
| 28935 | (or (org-invisible-p) | ||
| 28936 | (save-excursion (goto-char (max (point-min) (1- (point)))) | ||
| 28937 | (org-invisible-p))) | ||
| 28938 | (org-show-context 'bookmark-jump))) | ||
| 28939 | |||
| 28940 | ;; Make session.el ignore our circular variable | ||
| 28941 | (eval-after-load "session" | ||
| 28942 | '(add-to-list 'session-globals-exclude 'org-mark-ring)) | ||
| 28943 | |||
| 28944 | ;;;; Experimental code | ||
| 28945 | |||
| 28946 | (defun org-closed-in-range () | ||
| 28947 | "Sparse tree of items closed in a certain time range. | ||
| 28948 | Still experimental, may disappear in the future." | ||
| 28949 | (interactive) | ||
| 28950 | ;; Get the time interval from the user. | ||
| 28951 | (let* ((time1 (time-to-seconds | ||
| 28952 | (org-read-date nil 'to-time nil "Starting date: "))) | ||
| 28953 | (time2 (time-to-seconds | ||
| 28954 | (org-read-date nil 'to-time nil "End date:"))) | ||
| 28955 | ;; callback function | ||
| 28956 | (callback (lambda () | ||
| 28957 | (let ((time | ||
| 28958 | (time-to-seconds | ||
| 28959 | (apply 'encode-time | ||
| 28960 | (org-parse-time-string | ||
| 28961 | (match-string 1)))))) | ||
| 28962 | ;; check if time in interval | ||
| 28963 | (and (>= time time1) (<= time time2)))))) | ||
| 28964 | ;; make tree, check each match with the callback | ||
| 28965 | (org-occur "CLOSED: +\\[\\(.*?\\)\\]" nil callback))) | ||
| 28966 | |||
| 28967 | |||
| 28968 | ;;;; Finish up | ||
| 28969 | |||
| 28970 | (provide 'org) | ||
| 28971 | |||
| 28972 | (run-hooks 'org-load-hook) | ||
| 28973 | |||
| 28974 | ;; arch-tag: e77da1a7-acc7-4336-b19e-efa25af3f9fd | ||
| 28975 | ;;; org.el ends here | ||
| 28976 | |||