Commit | Line | Data |
---|---|---|
c8d0cf5c CD |
1 | ;;; org-inlinetask.el --- Tasks independent of outline hierarchy |
2 | ;; Copyright (C) 2009 Free Software Foundation, Inc. | |
3 | ;; | |
4 | ;; Author: Carsten Dominik <carsten at orgmode dot org> | |
5 | ;; Keywords: outlines, hypermedia, calendar, wp | |
6 | ;; Homepage: http://orgmode.org | |
7 | ;; Version: 6.29c | |
8 | ;; | |
9 | ;; This file is not yet 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 | ;; This module implements inline tasks in Org-mode. Inline tasks are | |
30 | ;; tasks that have all the properties of normal outline nodes, including | |
31 | ;; the ability to store meta data like scheduling dates, TODO state, tags | |
32 | ;; and properties. However, these nodes are treated specially by the | |
33 | ;; visibility cycling and export commands. | |
34 | ;; | |
35 | ;; Visibility cycling exempts these nodes from cycling. So whenever their | |
36 | ;; parent is opened, so are these tasks. This will only work with | |
37 | ;; `org-cycle', so if you are also using orther commands to show/hide | |
38 | ;; entries, you will occasionally find these tasks to behave like | |
39 | ;; all other outline nodes, seemingly splitting the text of the parent | |
40 | ;; into children. | |
41 | ;; | |
42 | ;; Export commands do not treat these nodes as part of the sectioning | |
43 | ;; structure, but as a special inline text that is either removed, or | |
44 | ;; formatted in some special way. | |
45 | ;; | |
46 | ;; Special fontification of inline tasks, so that they can be immediately | |
47 | ;; recognized. From the stars of the headline, only the first and the | |
48 | ;; last two will be visible, the others will be hidden using the | |
49 | ;; `org-hide' face. | |
50 | ;; | |
51 | ;; An inline task is identified solely by a minimum outline level, given | |
52 | ;; by the variable `org-inlinetask-min-level', default 15. | |
53 | ;; | |
54 | ;; Inline tasks are normally assumed to contain at most a time planning | |
55 | ;; line (DEADLINE etc) after it, and then any number of drawers, for | |
56 | ;; example LOGBOOK of PROPERTIES. No empty lines are allowed. | |
57 | ;; If you need to have normal text as part of an inline task, you | |
58 | ;; can do so by adding an "END" headline with the same number of stars, | |
59 | ;; for example | |
60 | ;; | |
61 | ;; **************** TODO some small task | |
62 | ;; DEADLINE: <2009-03-30 Mon> | |
63 | ;; :PROPERTIES: | |
64 | ;; :SOMETHING: or other | |
65 | ;; :END: | |
66 | ;; And here is some extra text | |
67 | ;; **************** END | |
68 | ;; | |
69 | ;; Also, if you want to use refiling and archiving for inline tasks, | |
70 | ;; The END line must be present to make things work properly. | |
71 | ;; | |
72 | ;; This package installs one new comand: | |
73 | ;; | |
74 | ;; C-c C-x t Insert a new inline task with END line | |
75 | ||
76 | ||
77 | ;;; Code | |
78 | ||
79 | (require 'org) | |
80 | ||
81 | (defgroup org-inlinetask nil | |
82 | "Options concerning inline tasks in Org mode." | |
83 | :tag "Org Inline Tasks" | |
84 | :group 'org-structure) | |
85 | ||
86 | (defcustom org-inlinetask-min-level 15 | |
87 | "Minimum level a headline must have before it is treated as an inline task. | |
88 | It is strongly recommended that you set `org-cycle-max-level' not at all, | |
89 | or to a number smaller than this one. In fact, when `org-cycle-max-level' is | |
90 | not set, it will be assumed to be one less than the value of smaller than | |
91 | the value of this variable." | |
92 | :group 'org-inlinetask | |
93 | :type 'boolean) | |
94 | ||
95 | (defcustom org-inlinetask-export 'arrow+content | |
96 | "What should be done with inlinetasks upon export? | |
97 | Possible values: | |
98 | ||
99 | nil Remove entirely, headline and \"content\" | |
100 | arrow Insert heading in bold, preceeded by an arrow | |
101 | arrow+content Insert arrow and headline, add content below in an | |
102 | #+begin_example box (ugly, but works for now) | |
103 | ||
104 | The \"content\" of an inline task is the material below the planning | |
105 | line and any drawers, up to a lines wit the same number of stars, | |
106 | but containing only the word END." | |
107 | :group 'org-inlinetask | |
108 | :group 'org-export-general | |
109 | :type '(choice | |
110 | (const :tag "Remove entirely" nil) | |
111 | (const :tag "Headline preceeded by arrow" arrow) | |
112 | (const :tag "Arrow, headline, + content" arrow+content))) | |
113 | ||
114 | (defvar org-odd-levels-only) | |
115 | (defvar org-keyword-time-regexp) | |
116 | (defvar org-drawer-regexp) | |
117 | (defvar org-complex-heading-regexp) | |
118 | (defvar org-property-end-re) | |
119 | ||
120 | (defun org-inlinetask-insert-task () | |
121 | "Insert an inline task." | |
122 | (interactive) | |
123 | (or (bolp) (newline)) | |
124 | (insert (make-string org-inlinetask-min-level ?*) " \n" | |
125 | (make-string org-inlinetask-min-level ?*) " END\n") | |
126 | (end-of-line -1)) | |
127 | (define-key org-mode-map "\C-c\C-xt" 'org-inlinetask-insert-task) | |
128 | ||
129 | (defun org-inlinetask-export-handler () | |
130 | "Handle headlines with level larger or equal to `org-inlinetask-min-level'. | |
131 | Either remove headline and meta data, or do special formatting." | |
132 | (goto-char (point-min)) | |
133 | (let* ((nstars (if org-odd-levels-only | |
134 | (1- (* 2 (or org-inlinetask-min-level 200))) | |
135 | (or org-inlinetask-min-level 200))) | |
136 | (re1 (format "^\\(\\*\\{%d,\\}\\) .*\n" nstars)) | |
137 | (re2 (concat "^[ \t]*" org-keyword-time-regexp)) | |
138 | headline beg end stars content) | |
139 | (while (re-search-forward re1 nil t) | |
140 | (setq headline (match-string 0) | |
141 | stars (match-string 1) | |
142 | content nil) | |
143 | (replace-match "") | |
144 | (while (looking-at re2) | |
145 | (delete-region (point) (1+ (point-at-eol)))) | |
146 | (while (looking-at org-drawer-regexp) | |
147 | (setq beg (point)) | |
148 | (if (re-search-forward org-property-end-re nil t) | |
149 | (delete-region beg (1+ (match-end 0))))) | |
150 | (setq beg (point)) | |
151 | (when (and (re-search-forward "^\\(\\*+\\) " nil t) | |
152 | (= (length (match-string 1)) (length stars)) | |
153 | (progn (goto-char (match-end 0)) | |
154 | (looking-at "END[ \t]*$"))) | |
155 | (setq content (buffer-substring beg (1- (point-at-bol)))) | |
156 | (delete-region beg (1+ (match-end 0)))) | |
157 | (goto-char beg) | |
158 | (when (and org-inlinetask-export | |
159 | (string-match org-complex-heading-regexp headline)) | |
160 | (when (memq org-inlinetask-export '(arrow+content arrow)) | |
161 | (insert "\n\n\\Rightarrow\\Rightarrow\\Rightarrow *" | |
162 | (if (match-end 2) (concat (match-string 2 headline) " ") "") | |
163 | (match-string 4 headline) "*\n")) | |
164 | (when (and content (eq org-inlinetask-export 'arrow+content)) | |
165 | (insert "#+BEGIN_EXAMPLE\n" content "\n#+END_EXAMPLE\n")) | |
166 | (insert "\n"))))) | |
167 | ||
168 | (defun org-inlinetask-fontify (limit) | |
169 | "Fontify the inline tasks." | |
170 | (let* ((nstars (if org-odd-levels-only | |
171 | (1- (* 2 (or org-inlinetask-min-level 200))) | |
172 | (or org-inlinetask-min-level 200))) | |
173 | (re (concat "^\\(\\*\\)\\(\\*\\{" | |
174 | (format "%d" (- nstars 3)) | |
175 | ",\\}\\)\\(\\*\\* .*\\)"))) | |
176 | (while (re-search-forward re limit t) | |
177 | (add-text-properties (match-beginning 1) (match-end 1) | |
178 | '(face org-warning font-lock-fontified t)) | |
179 | (add-text-properties (match-beginning 2) (match-end 2) | |
180 | '(face org-hide font-lock-fontified t)) | |
181 | (add-text-properties (match-beginning 3) (match-end 3) | |
182 | '(face shadow font-lock-fontified t))))) | |
183 | ||
184 | (defun org-inlinetask-remove-END-maybe () | |
185 | "Remove an END line when present." | |
186 | (when (looking-at (format "\\([ \t]*\n\\)*\\*\\{%d,\\}[ \t]+END[ \t]*$" | |
187 | org-inlinetask-min-level)) | |
188 | (replace-match ""))) | |
189 | ||
190 | (eval-after-load "org-exp" | |
191 | '(add-hook 'org-export-preprocess-after-tree-selection-hook | |
192 | 'org-inlinetask-export-handler)) | |
193 | (eval-after-load "org" | |
194 | '(add-hook 'org-font-lock-hook 'org-inlinetask-fontify)) | |
195 | ||
196 | (provide 'org-inlinetask) | |
197 | ||
198 | ;;; org-inlinetask.el ends here | |
199 |