Commit | Line | Data |
---|---|---|
47ffc456 CD |
1 | ;;; org-attach.el --- Manage file attachments to org-mode tasks |
2 | ||
ba318903 | 3 | ;; Copyright (C) 2008-2014 Free Software Foundation, Inc. |
47ffc456 CD |
4 | |
5 | ;; Author: John Wiegley <johnw@newartisans.com> | |
6 | ;; Keywords: org data task | |
47ffc456 CD |
7 | |
8 | ;; This file is part of GNU Emacs. | |
9 | ;; | |
10 | ;; GNU Emacs is free software: you can redistribute it and/or modify | |
11 | ;; it under the terms of the GNU General Public License as published by | |
12 | ;; the Free Software Foundation, either version 3 of the License, or | |
13 | ;; (at your option) any later version. | |
14 | ||
15 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | ;; GNU General Public License for more details. | |
19 | ||
20 | ;; You should have received a copy of the GNU General Public License | |
21 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. | |
22 | ||
23 | ;;; Commentary: | |
24 | ||
25 | ;; See the Org-mode manual for information on how to use it. | |
26 | ;; | |
27 | ;; Attachments are managed in a special directory called "data", which | |
c8d0cf5c | 28 | ;; lives in the same directory as the org file itself. If this data |
47ffc456 CD |
29 | ;; directory is initialized as a Git repository, then org-attach will |
30 | ;; automatically commit changes when it sees them. | |
31 | ;; | |
32 | ;; Attachment directories are identified using a UUID generated for the | |
33 | ;; task which has the attachments. These are added as property to the | |
34 | ;; task when necessary, and should not be deleted or changed by the | |
35 | ;; user, ever. UUIDs are generated by a mechanism defined in the variable | |
36 | ;; `org-id-method'. | |
37 | ||
38 | ;;; Code: | |
39 | ||
40 | (eval-when-compile | |
41 | (require 'cl)) | |
42 | (require 'org-id) | |
43 | (require 'org) | |
3c8b09ca | 44 | (require 'vc-git) |
271672fa | 45 | |
47ffc456 CD |
46 | (defgroup org-attach nil |
47 | "Options concerning entry attachments in Org-mode." | |
48 | :tag "Org Attach" | |
49 | :group 'org) | |
50 | ||
51 | (defcustom org-attach-directory "data/" | |
52 | "The directory where attachments are stored. | |
53 | If this is a relative path, it will be interpreted relative to the directory | |
54 | where the Org file lives." | |
55 | :group 'org-attach | |
33306645 | 56 | :type 'directory) |
47ffc456 | 57 | |
271672fa BG |
58 | (defcustom org-attach-git-annex-cutoff (* 32 1024) |
59 | "If non-nil, files larger than this will be annexed instead of stored." | |
60 | :group 'org-attach | |
61 | :version "24.4" | |
62 | :package-version '(Org . "8.0") | |
63 | :type '(choice | |
64 | (const :tag "None" nil) | |
65 | (integer :tag "Bytes"))) | |
66 | ||
47ffc456 CD |
67 | (defcustom org-attach-auto-tag "ATTACH" |
68 | "Tag that will be triggered automatically when an entry has an attachment." | |
69 | :group 'org-attach | |
70 | :type '(choice | |
71 | (const :tag "None" nil) | |
72 | (string :tag "Tag"))) | |
73 | ||
74 | (defcustom org-attach-file-list-property "Attachments" | |
75 | "The property used to keep a list of attachment belonging to this entry. | |
0bd48b37 CD |
76 | This is not really needed, so you may set this to nil if you don't want it. |
77 | Also, for entries where children inherit the directory, the list of | |
78 | attachments is not kept in this property." | |
47ffc456 CD |
79 | :group 'org-attach |
80 | :type '(choice | |
81 | (const :tag "None" nil) | |
82 | (string :tag "Tag"))) | |
83 | ||
84 | (defcustom org-attach-method 'cp | |
85 | "The preferred method to attach a file. | |
86 | Allowed values are: | |
87 | ||
88 | mv rename the file to move it into the attachment directory | |
89 | cp copy the file | |
90 | ln create a hard link. Note that this is not supported | |
8223b1d2 BG |
91 | on all systems, and then the result is not defined. |
92 | lns create a symbol link. Note that this is not supported | |
47ffc456 CD |
93 | on all systems, and then the result is not defined." |
94 | :group 'org-attach | |
95 | :type '(choice | |
96 | (const :tag "Copy" cp) | |
97 | (const :tag "Move/Rename" mv) | |
8223b1d2 BG |
98 | (const :tag "Hard Link" ln) |
99 | (const :tag "Symbol Link" lns))) | |
47ffc456 CD |
100 | |
101 | (defcustom org-attach-expert nil | |
102 | "Non-nil means do not show the splash buffer with the attach dispatcher." | |
103 | :group 'org-attach | |
104 | :type 'boolean) | |
105 | ||
0bd48b37 | 106 | (defcustom org-attach-allow-inheritance t |
ed21c5c8 | 107 | "Non-nil means allow attachment directories be inherited." |
0bd48b37 CD |
108 | :group 'org-attach |
109 | :type 'boolean) | |
c8d0cf5c | 110 | |
0bd48b37 CD |
111 | (defvar org-attach-inherited nil |
112 | "Indicates if the last access to the attachment directory was inherited.") | |
113 | ||
3ab2c837 BG |
114 | (defcustom org-attach-store-link-p nil |
115 | "Non-nil means store a link to a file when attaching it." | |
116 | :group 'org-attach | |
372d7b21 | 117 | :version "24.1" |
3ab2c837 BG |
118 | :type '(choice |
119 | (const :tag "Don't store link" nil) | |
120 | (const :tag "Link to origin location" t) | |
153ae947 | 121 | (const :tag "Link to the attach-dir location" attached))) |
3ab2c837 | 122 | |
47ffc456 CD |
123 | ;;;###autoload |
124 | (defun org-attach () | |
125 | "The dispatcher for attachment commands. | |
126 | Shows a list of commands and prompts for another key to execute a command." | |
127 | (interactive) | |
128 | (let (c marker) | |
129 | (when (eq major-mode 'org-agenda-mode) | |
130 | (setq marker (or (get-text-property (point) 'org-hd-marker) | |
131 | (get-text-property (point) 'org-marker))) | |
132 | (unless marker | |
133 | (error "No task in current line"))) | |
134 | (save-excursion | |
135 | (when marker | |
136 | (set-buffer (marker-buffer marker)) | |
137 | (goto-char marker)) | |
138 | (org-back-to-heading t) | |
139 | (save-excursion | |
140 | (save-window-excursion | |
141 | (unless org-attach-expert | |
142 | (with-output-to-temp-buffer "*Org Attach*" | |
143 | (princ "Select an Attachment Command: | |
144 | ||
145 | a Select a file and attach it to the task, using `org-attach-method'. | |
8223b1d2 | 146 | c/m/l/y Attach a file using copy/move/link/symbolic-link method. |
47ffc456 CD |
147 | n Create a new attachment, as an Emacs buffer. |
148 | z Synchronize the current task with its attachment | |
149 | directory, in case you added attachments yourself. | |
150 | ||
151 | o Open current task's attachments. | |
152 | O Like \"o\", but force opening in Emacs. | |
153 | f Open current task's attachment directory. | |
154 | F Like \"f\", but force using dired in Emacs. | |
155 | ||
156 | d Delete one attachment, you will be prompted for a file name. | |
157 | D Delete all of a task's attachments. A safer way is | |
0bd48b37 CD |
158 | to open the directory in dired and delete from there. |
159 | ||
160 | s Set a specific attachment directory for this entry. | |
161 | i Make children of the current entry inherit its attachment directory."))) | |
93b62de8 | 162 | (org-fit-window-to-buffer (get-buffer-window "*Org Attach*")) |
47ffc456 CD |
163 | (message "Select command: [acmlzoOfFdD]") |
164 | (setq c (read-char-exclusive)) | |
165 | (and (get-buffer "*Org Attach*") (kill-buffer "*Org Attach*")))) | |
166 | (cond | |
167 | ((memq c '(?a ?\C-a)) (call-interactively 'org-attach-attach)) | |
168 | ((memq c '(?c ?\C-c)) | |
169 | (let ((org-attach-method 'cp)) (call-interactively 'org-attach-attach))) | |
170 | ((memq c '(?m ?\C-m)) | |
171 | (let ((org-attach-method 'mv)) (call-interactively 'org-attach-attach))) | |
172 | ((memq c '(?l ?\C-l)) | |
173 | (let ((org-attach-method 'ln)) (call-interactively 'org-attach-attach))) | |
8223b1d2 BG |
174 | ((memq c '(?y ?\C-y)) |
175 | (let ((org-attach-method 'lns)) (call-interactively 'org-attach-attach))) | |
47ffc456 CD |
176 | ((memq c '(?n ?\C-n)) (call-interactively 'org-attach-new)) |
177 | ((memq c '(?z ?\C-z)) (call-interactively 'org-attach-sync)) | |
178 | ((memq c '(?o ?\C-o)) (call-interactively 'org-attach-open)) | |
179 | ((eq c ?O) (call-interactively 'org-attach-open-in-emacs)) | |
180 | ((memq c '(?f ?\C-f)) (call-interactively 'org-attach-reveal)) | |
181 | ((memq c '(?F)) (call-interactively 'org-attach-reveal-in-emacs)) | |
182 | ((memq c '(?d ?\C-d)) (call-interactively | |
183 | 'org-attach-delete-one)) | |
184 | ((eq c ?D) (call-interactively 'org-attach-delete-all)) | |
185 | ((eq c ?q) (message "Abort")) | |
0bd48b37 CD |
186 | ((memq c '(?s ?\C-s)) (call-interactively |
187 | 'org-attach-set-directory)) | |
188 | ((memq c '(?i ?\C-i)) (call-interactively | |
189 | 'org-attach-set-inherit)) | |
47ffc456 CD |
190 | (t (error "No such attachment command %c" c)))))) |
191 | ||
192 | (defun org-attach-dir (&optional create-if-not-exists-p) | |
193 | "Return the directory associated with the current entry. | |
0bd48b37 CD |
194 | This first checks for a local property ATTACH_DIR, and then for an inherited |
195 | property ATTACH_DIR_INHERIT. If neither exists, the default mechanism | |
196 | using the entry ID will be invoked to access the unique directory for the | |
197 | current entry. | |
47ffc456 | 198 | If the directory does not exist and CREATE-IF-NOT-EXISTS-P is non-nil, |
0bd48b37 CD |
199 | the directory and (if necessary) the corresponding ID will be created." |
200 | (let (attach-dir uuid inherit) | |
201 | (setq org-attach-inherited (org-entry-get nil "ATTACH_DIR_INHERIT")) | |
202 | (cond | |
203 | ((setq attach-dir (org-entry-get nil "ATTACH_DIR")) | |
204 | (org-attach-check-absolute-path attach-dir)) | |
205 | ((and org-attach-allow-inheritance | |
206 | (setq inherit (org-entry-get nil "ATTACH_DIR_INHERIT" t))) | |
207 | (setq attach-dir | |
208 | (save-excursion | |
209 | (save-restriction | |
210 | (widen) | |
211 | (goto-char org-entry-property-inherited-from) | |
212 | (let (org-attach-allow-inheritance) | |
213 | (org-attach-dir create-if-not-exists-p))))) | |
214 | (org-attach-check-absolute-path attach-dir) | |
215 | (setq org-attach-inherited t)) | |
216 | (t ; use the ID | |
217 | (org-attach-check-absolute-path nil) | |
218 | (setq uuid (org-id-get (point) create-if-not-exists-p)) | |
219 | (when (or uuid create-if-not-exists-p) | |
220 | (unless uuid (error "ID retrieval/creation failed")) | |
221 | (setq attach-dir (expand-file-name | |
222 | (format "%s/%s" | |
223 | (substring uuid 0 2) | |
224 | (substring uuid 2)) | |
225 | (expand-file-name org-attach-directory)))))) | |
226 | (when attach-dir | |
227 | (if (and create-if-not-exists-p | |
228 | (not (file-directory-p attach-dir))) | |
229 | (make-directory attach-dir t)) | |
230 | (and (file-exists-p attach-dir) | |
231 | attach-dir)))) | |
232 | ||
233 | (defun org-attach-check-absolute-path (dir) | |
8bfe682a | 234 | "Check if we have enough information to root the attachment directory. |
0bd48b37 CD |
235 | When DIR is given, check also if it is already absolute. Otherwise, |
236 | assume that it will be relative, and check if `org-attach-directory' is | |
237 | absolute, or if at least the current buffer has a file name. | |
238 | Throw an error if we cannot root the directory." | |
239 | (or (and dir (file-name-absolute-p dir)) | |
240 | (file-name-absolute-p org-attach-directory) | |
241 | (buffer-file-name (buffer-base-buffer)) | |
f924a367 | 242 | (error "Need absolute `org-attach-directory' to attach in buffers without filename"))) |
0bd48b37 CD |
243 | |
244 | (defun org-attach-set-directory () | |
245 | "Set the ATTACH_DIR property of the current entry. | |
246 | The property defines the directory that is used for attachments | |
247 | of the entry." | |
248 | (interactive) | |
249 | (let ((dir (org-entry-get nil "ATTACH_DIR"))) | |
250 | (setq dir (read-directory-name "Attachment directory: " dir)) | |
251 | (org-entry-put nil "ATTACH_DIR" dir))) | |
252 | ||
253 | (defun org-attach-set-inherit () | |
254 | "Set the ATTACH_DIR_INHERIT property of the current entry. | |
255 | The property defines the directory that is used for attachments | |
256 | of the entry and any children that do not explicitly define (by setting | |
257 | the ATTACH_DIR property) their own attachment directory." | |
258 | (interactive) | |
259 | (org-entry-put nil "ATTACH_DIR_INHERIT" "t") | |
260 | (message "Children will inherit attachment directory")) | |
47ffc456 CD |
261 | |
262 | (defun org-attach-commit () | |
263 | "Commit changes to git if `org-attach-directory' is properly initialized. | |
264 | This checks for the existence of a \".git\" directory in that directory." | |
271672fa BG |
265 | (let* ((dir (expand-file-name org-attach-directory)) |
266 | (git-dir (vc-git-root dir)) | |
267 | (changes 0)) | |
3c8b09ca | 268 | (when (and git-dir (executable-find "git")) |
ed21c5c8 CD |
269 | (with-temp-buffer |
270 | (cd dir) | |
271672fa BG |
271 | (let ((have-annex |
272 | (and org-attach-git-annex-cutoff | |
273 | (file-exists-p (expand-file-name "annex" git-dir))))) | |
274 | (dolist (new-or-modified | |
275 | (split-string | |
276 | (shell-command-to-string | |
277 | "git ls-files -zmo --exclude-standard") "\0" t)) | |
278 | (if (and have-annex | |
279 | (>= (nth 7 (file-attributes new-or-modified)) | |
280 | org-attach-git-annex-cutoff)) | |
281 | (call-process "git" nil nil nil "annex" "add" new-or-modified) | |
282 | (call-process "git" nil nil nil "add" new-or-modified)) | |
283 | (incf changes))) | |
284 | (dolist (deleted | |
285 | (split-string | |
286 | (shell-command-to-string "git ls-files -z --deleted") "\0" t)) | |
287 | (call-process "git" nil nil nil "rm" deleted) | |
288 | (incf changes)) | |
289 | (when (> changes 0) | |
290 | (shell-command "git commit -m 'Synchronized attachments'")))))) | |
ff4be292 | 291 | |
47ffc456 CD |
292 | (defun org-attach-tag (&optional off) |
293 | "Turn the autotag on or (if OFF is set) off." | |
294 | (when org-attach-auto-tag | |
295 | (save-excursion | |
296 | (org-back-to-heading t) | |
297 | (org-toggle-tag org-attach-auto-tag (if off 'off 'on))))) | |
298 | ||
299 | (defun org-attach-untag () | |
300 | "Turn the autotag off." | |
301 | (org-attach-tag 'off)) | |
302 | ||
3ab2c837 BG |
303 | (defun org-attach-store-link (file) |
304 | "Add a link to `org-stored-link' when attaching a file. | |
305 | Only do this when `org-attach-store-link-p' is non-nil." | |
306 | (setq org-stored-links | |
307 | (cons (list (org-attach-expand-link file) | |
308 | (file-name-nondirectory file)) | |
309 | org-stored-links))) | |
310 | ||
47ffc456 CD |
311 | (defun org-attach-attach (file &optional visit-dir method) |
312 | "Move/copy/link FILE into the attachment directory of the current task. | |
313 | If VISIT-DIR is non-nil, visit the directory with dired. | |
8223b1d2 BG |
314 | METHOD may be `cp', `mv', `ln', or `lns' default taken from |
315 | `org-attach-method'." | |
47ffc456 CD |
316 | (interactive "fFile to keep as an attachment: \nP") |
317 | (setq method (or method org-attach-method)) | |
318 | (let ((basename (file-name-nondirectory file))) | |
0bd48b37 | 319 | (when (and org-attach-file-list-property (not org-attach-inherited)) |
47ffc456 CD |
320 | (org-entry-add-to-multivalued-property |
321 | (point) org-attach-file-list-property basename)) | |
322 | (let* ((attach-dir (org-attach-dir t)) | |
323 | (fname (expand-file-name basename attach-dir))) | |
324 | (cond | |
325 | ((eq method 'mv) (rename-file file fname)) | |
326 | ((eq method 'cp) (copy-file file fname)) | |
8223b1d2 BG |
327 | ((eq method 'ln) (add-name-to-file file fname)) |
328 | ((eq method 'lns) (make-symbolic-link file fname))) | |
47ffc456 CD |
329 | (org-attach-commit) |
330 | (org-attach-tag) | |
3ab2c837 BG |
331 | (cond ((eq org-attach-store-link-p 'attached) |
332 | (org-attach-store-link fname)) | |
333 | ((eq org-attach-store-link-p t) | |
334 | (org-attach-store-link file))) | |
47ffc456 CD |
335 | (if visit-dir |
336 | (dired attach-dir) | |
337 | (message "File \"%s\" is now a task attachment." basename))))) | |
338 | ||
339 | (defun org-attach-attach-cp () | |
340 | "Attach a file by copying it." | |
341 | (interactive) | |
342 | (let ((org-attach-method 'cp)) (call-interactively 'org-attach-attach))) | |
343 | (defun org-attach-attach-mv () | |
344 | "Attach a file by moving (renaming) it." | |
345 | (interactive) | |
346 | (let ((org-attach-method 'mv)) (call-interactively 'org-attach-attach))) | |
347 | (defun org-attach-attach-ln () | |
348 | "Attach a file by creating a hard link to it. | |
349 | Beware that this does not work on systems that do not support hard links. | |
350 | On some systems, this apparently does copy the file instead." | |
351 | (interactive) | |
352 | (let ((org-attach-method 'ln)) (call-interactively 'org-attach-attach))) | |
8223b1d2 BG |
353 | (defun org-attach-attach-lns () |
354 | "Attach a file by creating a symbolic link to it. | |
355 | ||
356 | Beware that this does not work on systems that do not support symbolic links. | |
357 | On some systems, this apparently does copy the file instead." | |
358 | (interactive) | |
359 | (let ((org-attach-method 'lns)) (call-interactively 'org-attach-attach))) | |
47ffc456 CD |
360 | |
361 | (defun org-attach-new (file) | |
362 | "Create a new attachment FILE for the current task. | |
363 | The attachment is created as an Emacs buffer." | |
364 | (interactive "sCreate attachment named: ") | |
0bd48b37 | 365 | (when (and org-attach-file-list-property (not org-attach-inherited)) |
47ffc456 CD |
366 | (org-entry-add-to-multivalued-property |
367 | (point) org-attach-file-list-property file)) | |
368 | (let ((attach-dir (org-attach-dir t))) | |
369 | (org-attach-tag) | |
370 | (find-file (expand-file-name file attach-dir)) | |
371 | (message "New attachment %s" file))) | |
372 | ||
373 | (defun org-attach-delete-one (&optional file) | |
374 | "Delete a single attachment." | |
375 | (interactive) | |
376 | (let* ((attach-dir (org-attach-dir t)) | |
377 | (files (org-attach-file-list attach-dir)) | |
378 | (file (or file | |
54a0dee5 | 379 | (org-icompleting-read |
47ffc456 CD |
380 | "Delete attachment: " |
381 | (mapcar (lambda (f) | |
382 | (list (file-name-nondirectory f))) | |
383 | files))))) | |
384 | (setq file (expand-file-name file attach-dir)) | |
385 | (unless (file-exists-p file) | |
386 | (error "No such attachment: %s" file)) | |
ed21c5c8 CD |
387 | (delete-file file) |
388 | (org-attach-commit))) | |
47ffc456 CD |
389 | |
390 | (defun org-attach-delete-all (&optional force) | |
391 | "Delete all attachments from the current task. | |
392 | This actually deletes the entire attachment directory. | |
393 | A safer way is to open the directory in dired and delete from there." | |
394 | (interactive "P") | |
0bd48b37 | 395 | (when (and org-attach-file-list-property (not org-attach-inherited)) |
47ffc456 CD |
396 | (org-entry-delete (point) org-attach-file-list-property)) |
397 | (let ((attach-dir (org-attach-dir))) | |
ff4be292 | 398 | (when |
47ffc456 CD |
399 | (and attach-dir |
400 | (or force | |
401 | (y-or-n-p "Are you sure you want to remove all attachments of this entry? "))) | |
402 | (shell-command (format "rm -fr %s" attach-dir)) | |
403 | (message "Attachment directory removed") | |
404 | (org-attach-commit) | |
405 | (org-attach-untag)))) | |
406 | ||
407 | (defun org-attach-sync () | |
408 | "Synchronize the current tasks with its attachments. | |
409 | This can be used after files have been added externally." | |
410 | (interactive) | |
411 | (org-attach-commit) | |
0bd48b37 | 412 | (when (and org-attach-file-list-property (not org-attach-inherited)) |
47ffc456 CD |
413 | (org-entry-delete (point) org-attach-file-list-property)) |
414 | (let ((attach-dir (org-attach-dir))) | |
415 | (when attach-dir | |
416 | (let ((files (org-attach-file-list attach-dir))) | |
417 | (and files (org-attach-tag)) | |
418 | (when org-attach-file-list-property | |
419 | (dolist (file files) | |
420 | (unless (string-match "^\\." file) | |
421 | (org-entry-add-to-multivalued-property | |
422 | (point) org-attach-file-list-property file)))))))) | |
423 | ||
424 | (defun org-attach-file-list (dir) | |
425 | "Return a list of files in the attachment directory. | |
426 | This ignores files starting with a \".\", and files ending in \"~\"." | |
427 | (delq nil | |
428 | (mapcar (lambda (x) (if (string-match "^\\." x) nil x)) | |
429 | (directory-files dir nil "[^~]\\'")))) | |
430 | ||
8bfe682a | 431 | (defun org-attach-reveal (&optional if-exists) |
271672fa BG |
432 | "Show the attachment directory of the current task. |
433 | This will attempt to use an external program to show the directory." | |
8bfe682a CD |
434 | (interactive "P") |
435 | (let ((attach-dir (org-attach-dir (not if-exists)))) | |
436 | (and attach-dir (org-open-file attach-dir)))) | |
47ffc456 CD |
437 | |
438 | (defun org-attach-reveal-in-emacs () | |
271672fa | 439 | "Show the attachment directory of the current task in dired." |
47ffc456 CD |
440 | (interactive) |
441 | (let ((attach-dir (org-attach-dir t))) | |
442 | (dired attach-dir))) | |
443 | ||
444 | (defun org-attach-open (&optional in-emacs) | |
445 | "Open an attachment of the current task. | |
446 | If there are more than one attachment, you will be prompted for the file name. | |
447 | This command will open the file using the settings in `org-file-apps' | |
448 | and in the system-specific variants of this variable. | |
449 | If IN-EMACS is non-nil, force opening in Emacs." | |
450 | (interactive "P") | |
451 | (let* ((attach-dir (org-attach-dir t)) | |
452 | (files (org-attach-file-list attach-dir)) | |
453 | (file (if (= (length files) 1) | |
454 | (car files) | |
54a0dee5 | 455 | (org-icompleting-read "Open attachment: " |
8223b1d2 | 456 | (mapcar 'list files) nil t)))) |
47ffc456 CD |
457 | (org-open-file (expand-file-name file attach-dir) in-emacs))) |
458 | ||
459 | (defun org-attach-open-in-emacs () | |
460 | "Open attachment, force opening in Emacs. | |
461 | See `org-attach-open'." | |
462 | (interactive) | |
463 | (org-attach-open 'in-emacs)) | |
464 | ||
93b62de8 CD |
465 | (defun org-attach-expand (file) |
466 | "Return the full path to the current entry's attachment file FILE. | |
467 | Basically, this adds the path to the attachment directory." | |
468 | (expand-file-name file (org-attach-dir))) | |
469 | ||
470 | (defun org-attach-expand-link (file) | |
471 | "Return a file link pointing to the current entry's attachment file FILE. | |
472 | Basically, this adds the path to the attachment directory, and a \"file:\" | |
473 | prefix." | |
474 | (concat "file:" (org-attach-expand file))) | |
475 | ||
47ffc456 CD |
476 | (provide 'org-attach) |
477 | ||
bdebdb64 BG |
478 | ;; Local variables: |
479 | ;; generated-autoload-file: "org-loaddefs.el" | |
480 | ;; End: | |
481 | ||
47ffc456 | 482 | ;;; org-attach.el ends here |