[Orgmode] Useful utility function: org-sort-multi
I found myself having to sort by multiple criteria, and I was doing it with multiple calls to org-sort-entries-or-items. Then I decided to abstract the repetition into a function. Here it is: (defun org-sort-multi (&rest sort-types) "Sort successively by a list of criteria, in descending order of importance. For example, sort first by TODO status, then by priority, then by date, then alphabetically, case-sensitive. Each criterion is either a character or a cons pair (BOOL . CHAR), where BOOL is whether or not to sort case-sensitively, and CHAR is one of the characters defined in ``org-sort-entries-or-items''. So, the example above could be accomplished with: (org-sort-multi ?o ?p ?t (t . ?a))" (interactive) (mapc #'(lambda (sort-type) (when (characterp sort-type) (setq sort-type (cons nil sort-type))) (org-sort-entries-or-items (car sort-type) (cdr sort-type))) (reverse sort-types))) Note the call to reverse. This makes it so that the first criterion you provide is the dominant criterion. Try it out to see how it works, and let me know if there's a better way to pass the arguments. Just as an example, the particular sorting function I wanted to write now becomes this: (defun org-sort-custom () "Sort children of node by todo status and by priority and by date, so the * TODO [#A] items with latest dates go to the top." (interactive) (org-sort-multi ?o ?p ?T)) ___ Emacs-orgmode mailing list Remember: use `Reply All' to send replies to the list. Emacs-orgmode@gnu.org http://lists.gnu.org/mailman/listinfo/emacs-orgmode
[Orgmode] Re: Useful utility function: org-sort-multi
Benjamin Andresen wrote: if you have the following list * Test Sorting ** TODO Charlie ** WAITING Beta ** TODO Alpha ** STARTED Beta ** STARTED Charlie ** TODO Beta ** STARTED Alpha ** WAITING Charlie ** WAITING Alpha calling org-multi-sort with ?o ?a will sort it like this * Test Sorting ** TODO Alpha ** TODO Beta ** TODO Charlie ** STARTED Alpha ** STARTED Beta ** STARTED Charlie ** WAITING Alpha ** WAITING Beta ** WAITING Charlie but just ?a would completely ignore the TODO, STARTED, WAITING order. Thanks Ryan, pretty useful. br, benny ___ Emacs-orgmode mailing list Remember: use `Reply All' to send replies to the list. Emacs-orgmode@gnu.org http://lists.gnu.org/mailman/listinfo/emacs-orgmode That's right, the function relies on the fact that org's sorting is stable. So the results of earlier sorts are preserved as much as possible in later sorts. Of course, this is really inefficient, but oh well. As another test case, try using (org-sort-multi ?o ?p) on this: * Multi-sort test ** DONE [#B] ** TODO [#C] ** STARTED [#C] ** STARTED [#A] ** DONE [#C] ** TODO [#B] ** TODO [#A] ** STARTED [#B] ** DONE [#A] Anyway, Carsten, if you think this would be useful, feel free to include some variant of this in org-mode itself. You'd probably want to implement it as a one-pass sort in which the set of sorting criteria function as a series of fallbacks for tiebreakers, rather than a series of sorts. Ryan ___ Emacs-orgmode mailing list Remember: use `Reply All' to send replies to the list. Emacs-orgmode@gnu.org http://lists.gnu.org/mailman/listinfo/emacs-orgmode
[Orgmode] Easier customization of TODO keyword colors
Here is some code I came up with some code to make it easier to customize the colors of various TODO keywords. As long as you just want a different color and nothing else, you can customize the variable org-todo-keyword-faces and use just a string color (i.e. a string of the color name) as the face, and then org-get-todo-face will convert the color to a face, inheriting everything else from the standard org-todo face. To demonstrate, I currently have org-todo-keyword-faces set to (("IN PROGRESS" . "dark orange") ("WAITING" . "red4") ("CANCELED" . "saddle brown")) Here's the code, in a form you can put in your .emacs. (eval-after-load 'org-faces '(progn (defcustom org-todo-keyword-faces nil "Faces for specific TODO keywords. This is a list of cons cells, with TODO keywords in the car and faces in the cdr. The face can be a symbol, a color, or a property list of attributes, like (:foreground \"blue\" :weight bold :underline t)." :group 'org-faces :group 'org-todo :type '(repeat (cons (string :tag "Keyword") (choice color (sexp :tag "Face"))) (eval-after-load 'org '(progn (defun org-get-todo-face-from-color (color) "Returns a specification for a face that inherits from org-todo face and has the given color as foreground. Returns nil if color is nil." (when color `(:inherit org-warning :foreground ,color))) (defun org-get-todo-face (kwd) "Get the right face for a TODO keyword KWD. If KWD is a number, get the corresponding match group." (if (numberp kwd) (setq kwd (match-string kwd))) (or (let ((face (cdr (assoc kwd org-todo-keyword-faces (if (stringp face) (org-get-todo-face-from-color face) face)) (and (member kwd org-done-keywords) 'org-done) 'org-todo ___ Emacs-orgmode mailing list Remember: use `Reply All' to send replies to the list. Emacs-orgmode@gnu.org http://lists.gnu.org/mailman/listinfo/emacs-orgmode
Re: [Orgmode] Easier customization of TODO keyword colors
Bastien wrote: Interesting - would you like to add this in org-hacks? http://orgmode.org/worg/org-hacks.php If so, please send me your username on repo.or.cz (if you are not already a Worger...) Thank! I'm not on either, actually. I'm a relative newcomer to org-mode and elisp hacking in general. But I'd love to see it on Worg. ___ Emacs-orgmode mailing list Remember: use `Reply All' to send replies to the list. Emacs-orgmode@gnu.org http://lists.gnu.org/mailman/listinfo/emacs-orgmode
[Orgmode] Setting org-remember-store-without-prompt specifically for certain templates?
Hi, I want to be prompted for a location to file some org-remember templates, but not others. How can I set org-remember-store-without-prompt in a template-specific fashion? I tried putting code in the template with %(sexp) that would set a buffer-local value for this variable, but I can't seem to make it work. -Ryan ___ Emacs-orgmode mailing list Remember: use `Reply All' to send replies to the list. Emacs-orgmode@gnu.org http://lists.gnu.org/mailman/listinfo/emacs-orgmode
Re: [Orgmode] Setting org-remember-store-without-prompt specifically for certain templates?
That's a fine solution for now, but I have one template that I *always* want to be prompted about. (It's an "assignment" template, and I want to refile it under the appropriate class.) For others, I don't want a prompt. I feel there should be a way to implement this and stick it inside a %(sexp) in my template of choice. Darlan Cavalcante Moreira wrote: I just leave org-remember-store-without-prompt as t and use C-c C-c in the remember buffer to put the note in the default location. When I want to specify a different location I use M-1 C-c C-c instead and org asks me where to refile it to. Darlan At Wed, 21 Oct 2009 11:15:23 -0700, "Ryan C. Thompson" wrote: ___ Emacs-orgmode mailing list Remember: use `Reply All' to send replies to the list. Emacs-orgmode@gnu.org http://lists.gnu.org/mailman/listinfo/emacs-orgmode
Re: [Orgmode] Setting org-remember-store-without-prompt specifically for certain templates?
Carsten Dominik wrote: All you need to do is *not* to specify file and headline for this template - then you will be prompted. If I don't specify a file and headline, won't the note just be stored under org-default-notes file and org-remember-default-headline? Or even remember-data-file? ___ Emacs-orgmode mailing list Remember: use `Reply All' to send replies to the list. Emacs-orgmode@gnu.org http://lists.gnu.org/mailman/listinfo/emacs-orgmode
Re: [Orgmode] Setting org-remember-store-without-prompt specifically for certain templates?
My original idea for a per-template solution was to create a function to set buffer-local values of the appropriate variables in the rememebr buffer, and have that function return an empty string, and then put it inside a %(sexp) in the template itself. Should this work? Would buffer-local values take precedence when I press C-c C-c after finishing my note? My first few attempts were unsuccessful, but I'm not sure I got the code right. I suppose I should try manually setting buffer-local values and observing the effects. - Ryan Carsten Dominik wrote: On Oct 24, 2009, at 11:00 PM, Ryan C. Thompson wrote: Hi Ryan, you are completely right, I was mistaken. No, you cannot currently do what you want on a per-template basis. - Carsten ___ Emacs-orgmode mailing list Remember: use `Reply All' to send replies to the list. Emacs-orgmode@gnu.org http://lists.gnu.org/mailman/listinfo/emacs-orgmode
[Orgmode] Bug Report: org-blocker-hook and org-trigger-hook are named incorrectly
I believe it is the emacs convention to distinguish between hooks that take no arguments and hooks that do. Since org-blocker-hook and org-trigger-hook pass an argument to their functions, they should actually be called org-blocker-functions and org-trigger-functions. From the elisp info, 23.1 Hooks: If the hook variable's name does not end with `-hook', that indicates it is probably an "abnormal hook". That means the hook functions are called with arguments, or their return values are used in some way. The hook's documentation says how the functions are called. You can use `add-hook' to add a function to an abnormal hook, but you must write the function to follow the hook's calling convention. By convention, abnormal hook names end in `-functions' or `-hooks'. If the variable's name ends in `-function', then its value is just a single function, not a list of functions. -Ryan ___ Emacs-orgmode mailing list Please use `Reply All' to send replies to the list. Emacs-orgmode@gnu.org http://lists.gnu.org/mailman/listinfo/emacs-orgmode
[Orgmode] Bug Report: TAB on empty headline cycles through the wrong levels
I have discovered a possible bug with the new 6.33 feature of cycling empty headline levels with TAB. IT seems that org will always assume that the initial level of the headline is the "base" level. Pressing TAB once will always go one level deeper than that, to the "child" level, TAB a second time will go one level shallower than the base level, and so on. the problem is that I expect the "base" level to be based on the previous headline's level, not on the initial level of the empty headline itself. The problem would not usually show itself, because if you press meta+RET at the end of a headline, you get a new empty one at the same level as the previous headline. However, if you press meta+RET at the *beginning* of a headline (before the stars), you get a new empty headline at the same level as the *next* headline, which might not be the same level as the previous headline. Here's a simple test case: * Head1 ** Head2 Put the point at the very beginning of the second heading, and press meta+RET, then TAB. You should get this: * Head1 *** [point is here] ** Head2 The following is what I would *expect* to get: * Head1 * [point is here] ** Head2 So basically, the base level for depth cycling should be determined from the previous headline, not the new blank headline. At least, that's what I expected, and I can't think of any reason you would want to put a level-3 headline under a level-1 headline. -Ryan ___ Emacs-orgmode mailing list Please use `Reply All' to send replies to the list. Emacs-orgmode@gnu.org http://lists.gnu.org/mailman/listinfo/emacs-orgmode
[Orgmode] Org-remember: How to unambiguously store notes to level-2 and deeper headlines?
Hi, Is there a way to unambiguously specify non-top-level headers as org-remember targets in templates? My specific use case is that I want to split my "Tasks" entries list into sublists, and I want to store new tasks in Tasks/Unsorted by default. I know I could just specify "Unsorted" as the target, but that seems really easy to break, for example, if I also had Events/Unsorted in the same file. So, is there a good way to specify a level-2 headline as a target in org-remember-templates? -Ryan ___ Emacs-orgmode mailing list Please use `Reply All' to send replies to the list. Emacs-orgmode@gnu.org http://lists.gnu.org/mailman/listinfo/emacs-orgmode
[Orgmode] Org-remember-handler fix for empty remember buffer
Hi, I ran into a problem with org's remember functionality, and found a fix for it. The problem is that if you attempt to either abort or remember an empty buffer (that is, a buffer containing only whitespace and comments), then org-mode hits an error and fails to do either, leaving the buffer annoyingly open. The bug is in the loop that deletes trailing comments and whitespace. If the buffer is empty, then this loop reaches the first line, and attempts to delete a region starting at position zero, which causes the error. Here is the modified function definition that checks for this condition. As a bonus, the function also auto-aborts instead of saving if the buffer is empty. Thank you, Ryan Thompson ;; Fix for empty remember buffer. (defun org-remember-handler () "Store stuff from remember.el into an org file. When the template has specified a file and a headline, the entry is filed there, or in the location defined by `org-default-notes-file' and `org-remember-default-headline'. If no defaults have been defined, or if the current prefix argument is 1 (so you must use `C-1 C-c C-c' to exit remember), an interactive process is used to select the target location. When the prefix is 0 (i.e. when remember is exited with `C-0 C-c C-c'), the entry is filed to the same location as the previous note. When the prefix is 2 (i.e. when remember is exited with `C-2 C-c C-c'), the entry is filed as a subentry of the entry where the clock is currently running. When `C-u' has been used as prefix argument, the note is stored and emacs moves point to the new location of the note, so that editing can be continued there (similar to inserting \"%&\" into the template). Before storing the note, the function ensures that the text has an org-mode-style headline, i.e. a first line that starts with a \"*\". If not, a headline is constructed from the current date and some additional data. If the variable `org-adapt-indentation' is non-nil, the entire text is also indented so that it starts in the same column as the headline \(i.e. after the stars). See also the variable `org-reverse-note-order'." (interactive) (when (and (equal current-prefix-arg 2) (not (marker-buffer org-clock-marker))) (error "No running clock")) (when (org-bound-and-true-p org-jump-to-target-location) (let* ((end (min (point-max) (1+ (point (beg (point))) (if (= end beg) (setq beg (1- beg))) (put-text-property beg end 'org-position-cursor t))) (goto-char (point-min)) (while (looking-at "^[ \t]*\n\\|^##.*\n") (replace-match "")) (goto-char (point-max)) (beginning-of-line 1) (catch 'quit (while (looking-at "[ \t]*$\\|##.*") ;; Abort on empty buffer (if (= (point) (point-min)) (throw 'quit nil) (previous-line))) (delete-region (point) (point-max)) (backward-delete-char 1) (if org-note-abort (throw 'quit nil)) ;; Also abort on an empty (i.e. whitespace-only) buffer ;; (if (not (string-match "[^[:space:]]" (buffer-substring-no-properties (point-min) (point-max (return t)) (let* ((visitp (org-bound-and-true-p org-jump-to-target-location)) (previousp (and (member current-prefix-arg '((16) 0)) org-remember-previous-location)) (clockp (equal current-prefix-arg 2)) (fastp (org-xor (equal current-prefix-arg 1) org-remember-store-without-prompt)) (file (cond (fastp org-default-notes-file) ((and (eq org-remember-interactive-interface 'refile) org-refile-targets) org-default-notes-file) ((not previousp) (org-get-org-file (heading org-remember-default-headline) (visiting (and file (org-find-base-buffer-visiting file))) (org-startup-folded nil) (org-startup-align-all-tables nil) (org-goto-start-pos 1) spos exitcmd level reversed txt) (when (equal current-prefix-arg '(4)) (setq visitp t)) (when previousp (setq file (car org-remember-previous-location) visiting (and file (org-find-base-buffer-visiting file)) heading (cdr org-remember-previous-location) fastp t)) (when clockp (setq file (buffer-file-name (marker-buffer org-clock-marker)) visiting (and file (org-find-base-buffer-visiting file)) heading org-clock-heading-for-remember fastp t)) (setq current-prefix-arg nil) ;; Modify text so that it becomes a nice subtree which can be inserted ;; into an org tree. (goto-char (point-min)) (if (re-search-forward "[ \t\n]+\\'" nil t) ;; remove empty lines at end (replace-match "")) (goto-char (point-min)) (unless (looking-at org-outline-regexp) ;; add a headline (insert (concat "* " (current-time-string) " (" (remember-buffer-desc) ")\n")) (backward-char 1) (when org-adapt-indentation (while (re-search-forward "^" nil t) (insert " " (goto-char (poin
Re: [Orgmode] Org-remember-handler fix for empty remember buffer
Carsten Dominik wrote: Fixed, thanks. - Carsten On Jun 4, 2009, at 7:45 PM, Ryan C. Thompson wrote: If you used the code I sent in my previous email, I discovered a bug in it. It would delete the last nonblank line as well. I have fixed this in my code. I've fixed things by copying the function into my .emacs and then editing it, so generating a diff -u is nontrivial. I'll do it now though. Also, I should mention that I'm not an experienced elisp hacker, so the solution that I came up with might not be the best. If you know a better way to do the same thing, go for it. --- /usr/share/emacs/site-lisp/org-mode/org-remember.el 2009-03-13 10:00:34.0 -0400 +++ org-remember.el 2009-06-08 15:43:04.708905961 -0400 @@ -740,10 +740,14 @@ (replace-match "")) (goto-char (point-max)) (beginning-of-line 1) - (while (looking-at "[ \t]*$\\|##.*") -(delete-region (1- (point)) (point-max)) -(beginning-of-line 1)) (catch 'quit +(while (looking-at "[ \t]*$\\|##.*") + ;; Abort on empty buffer + (if (= (point) (point-min)) + (throw 'quit nil) +(previous-line))) +(end-of-line 1) ; end of last nonblank line +(delete-region (point) (point-max)) (if org-note-abort (throw 'quit nil)) (let* ((visitp (org-bound-and-true-p org-jump-to-target-location)) (previousp (and (member current-prefix-arg '((16) 0)) ___ Emacs-orgmode mailing list Remember: use `Reply All' to send replies to the list. Emacs-orgmode@gnu.org http://lists.gnu.org/mailman/listinfo/emacs-orgmode
[Orgmode] Setting custom frame parameters for org remember frame
I am using org-remember set to open a new frame when used, and the default frame size is much too large. To fix this, I have designed some advice and a custom variable to implement custom parameters for the remember frame: (defcustom remember-frame-alist nil "Additional frame parameters for dedicated remember frame." :type 'alist :group 'remember) (defadvice remember (around remember-frame-parameters activate) "Set some frame parameters for the remember frame." (let ((default-frame-alist (append remember-frame-alist default-frame-alist))) ad-do-it)) I have set remember-frame-alist to ((width . 80) (height . 15)) which gives me a reasonable-sized frame, and provides and easy way to change it later. ___ Emacs-orgmode mailing list Remember: use `Reply All' to send replies to the list. Emacs-orgmode@gnu.org http://lists.gnu.org/mailman/listinfo/emacs-orgmode
[Orgmode] Setting custom frame parameters for org remember frame
I am using org-remember set to open a new frame when used, and the default frame size is much too large. To fix this, I have designed some advice and a custom variable to implement custom parameters for the remember frame: (defcustom remember-frame-alist nil "Additional frame parameters for dedicated remember frame." :type 'alist :group 'remember) (defadvice remember (around remember-frame-parameters activate) "Set some frame parameters for the remember frame." (let ((default-frame-alist (append remember-frame-alist default-frame-alist))) ad-do-it)) I have set remember-frame-alist to ((width . 80) (height . 15)) which gives me a reasonable-sized frame, and provides and easy way to change it later. (I accidentally sent this from the wrong address before. Admins, please delete/ignore the other one.) ___ Emacs-orgmode mailing list Remember: use `Reply All' to send replies to the list. Emacs-orgmode@gnu.org http://lists.gnu.org/mailman/listinfo/emacs-orgmode
[Orgmode] Re: Vertical split in Emacs 23
I believe the function you're looking for is split-window-sensibly. Try M-x describe-function split-window-sensibly. It describes all the relevant variables that control its behavior. If you wish to affect the behavior of only a specific case of splitting windows (for example, the org-todo function) you can use advice to temporarily modify one or more of these variables for the duration of the function call. For example, the following (untested!) code should guarantee a vertical split for org-todo: (defadvice org-todo (around tweak-splitting-behavior activate) "Tweak the sensible window splitting behavior for org-todo." (let ((split-height-threshold 0)) ad-do-it)) ___ Emacs-orgmode mailing list Remember: use `Reply All' to send replies to the list. Emacs-orgmode@gnu.org http://lists.gnu.org/mailman/listinfo/emacs-orgmode
Bug: org-eldoc should require org-refile [9.3.6 (release_9.3.6-442-g97f0f1 @ /home/ryan/.emacs.d/straight/build/org-plus-contrib/)]
Remember to cover the basics, that is, what you expected to happen and what in fact did happen. You don't know how to make a good report? See https://orgmode.org/manual/Feedback.html#Feedback Your bug report will be posted to the Org mailing list. `org-eldoc-get-breadcrumb' in org-eldoc.el calls `org-get-outline-path' which is defined in org-refile.el, but org-eldoc does not load org-refile. This results in void-function errors when the Eldoc idle timer runs in an org buffer, unless you manually load org-refile. To fix this, org-eldoc should load org-refile. Emacs : GNU Emacs 26.3 (build 1, x86_64-pc-linux-gnu, X toolkit, Xaw3d scroll bars) of 2019-09-23, modified by Debian Package: Org mode version 9.3.6 (release_9.3.6-442-g97f0f1 @ /home/ryan/.emacs.d/straight/build/org-plus-contrib/) current state: == (setq org-src-mode-hook '(org-src-babel-configure-edit-buffer org-src-mode-configure-edit-buffer) org-after-todo-state-change-hook '(org-checklist) org-link-shell-confirm-function 'yes-or-no-p org-metadown-hook '(org-babel-pop-to-session-maybe) org-clock-out-hook '(org-clock-remove-empty-clock-drawer) org-html-format-inlinetask-function 'org-html-format-inlinetask-default-function org-odt-format-headline-function 'org-odt-format-headline-default-function org-ascii-format-inlinetask-function 'org-ascii-format-inlinetask-default org-reveal-start-hook '(org-decrypt-entry) org-mode-hook '((lambda nil (org-bullets-mode 1)) #[0 "\301\211\207" [imenu-create-index-function org-imenu-get-tree] 2] #[0 "\300\301\302\303\304$\207" [add-hook change-major-mode-hook org-show-all append local] 5] #[0 "\300\301\302\303\304$\207" [add-hook change-major-mode-hook org-babel-show-result-all append local] 5] org-babel-result-hide-spec org-babel-hide-all-hashes org-eldoc-load) org-odt-format-drawer-function #[514 "\207" [] 3 "\n\n(fn NAME CONTENTS)"] org-archive-hook '(org-attach-archive-delete-maybe) org-confirm-elisp-link-function 'yes-or-no-p org-agenda-before-write-hook '(org-agenda-add-entry-text) org-metaup-hook '(org-babel-load-in-session-maybe) org-bibtex-headline-format-function #[257 "\300\236A\207" [:title] 3 "\n\n(fn ENTRY)"] org-adapt-indentation nil org-latex-format-drawer-function #[514 "\207" [] 3 "\n\n(fn _ CONTENTS)"] org-babel-pre-tangle-hook '(save-buffer) org-tab-first-hook '(org-babel-hide-result-toggle-maybe org-babel-header-arg-expand) org-checklist-export-function 'org-export-as-ascii org-ascii-format-drawer-function #[771 "\207" [] 4 "\n\n(fn NAME CONTENTS WIDTH)"] org-agenda-loop-over-headlines-in-active-region nil org-src-lang-modes '(("arduino" . arduino) ("redis" . redis) ("php" . php) ("C" . c) ("C++" . c++) ("asymptote" . asy) ("bash" . sh) ("beamer" . latex) ("calc" . fundamental) ("cpp" . c++) ("ditaa" . artist) ("dot" . fundamental) ("elisp" . emacs-lisp) ("ocaml" . tuareg) ("screen" . shell-script) ("shell" . sh) ("sqlite" . sql)) org-occur-hook '(org-first-headline-recenter) org-cycle-hook '(org-cycle-hide-archived-subtrees org-cycle-show-empty-lines org-optimize-window-after-visibility-change) org-todo-keywords '((sequence "TODO" "|" "DONE" "CANCELLED")) org-support-shift-select t org-speed-command-hook '(org-speed-command-activate org-babel-speed-command-activate) org-odt-format-inlinetask-function 'org-odt-format-inlinetask-default-function org-html-allow-name-attribute-in-anchors t org-export-async-init-file "/home/ryan/.emacs.d/.temp-org-export-async-init.el" org-export-before-parsing-hook '(org-attach-expand-links org-latex-header-blocks-filter) org-confirm-shell-link-function 'yes-or-no-p org-link-parameters '(("attachment" :follow org-attach-follow :complete org-attach-complete-link) ("id" :follow org-id-open) ("message" :follow org-mac-message-open) ("x-devonthink-item" :follow org-devonthink-item-open) ("mac-evernote" :follow org-mac-evernote-note-open) ("mac-outlook" :follow org-mac-outlook-message-open) ("acrobat" :follow org-mac-acrobat-open) ("skim" :follow org-mac-skim-open) ("addressbook" :follow org-mac-addressbook-item-open) ("x-together-item" :follow org-mac-together-item-open) ("mairix" :follow org-mairix-open :store org-mairix-store-gnus-link) ("eww" :follow org-eww-open :store org-eww-store-link) ("rmail" :follow org-rmail-open :store org-rmail-store-link) ("mhe" :follow org-mhe-open :store org-mhe-store-link) ("irc" :follow org-irc-visit :store org-irc-store-link :export org-irc-export) ("info" :follow org-info-open :export org-info-export :store org-info-store-link) ("gnus" :follow org-gnus-open :store org-gnus-store-link) ("docview" :follow org-docview-open :export org-docview-export :store org-docview-store-link) ("bibtex" :follow org-bibtex-open :store org-bibtex-store-link) ("bbdb" :follow org-bbdb-open :export org-bbdb-export :complete org-bbdb-complete-link :store org-bbdb-store-link) ("w3m" :store org-w3m-store-link) ("roll" :follow
Re: Feature request: Allow export to convert broken links to plain text
On 1/13/19 5:34 PM, Berry, Charles wrote: Looks like your original idea to revise `org-export-data' might be best. IIUC, you need to add the link text to the SIGNAL-DATA in each of the places where `org-export-resolve-*-link' functions call `signal', then modify `org-export-data' to ignore the addition for `mark' and add it back for your new `mark-with-text' option. HTH, Chuck Years later, I became annoyed enough by this to attempt to fix it again. Unfortunately, I looked into changing all the functions that signal org-link-broken, and not all of them can be modified in the way you described, at least not easily. Instead, I came up with a fairly clean alternative solution: define a new link type "maybe" using org-link-set-parameters with an :export function that pulls out the real link transcoder from the backend and calls it, but then implements my desired behavior if that transcoder throws an error. This allows you to prefix any link's path with "maybe:" to have it magically become plain text if it can't be resolved during export. Here's the implementation: (org-link-set-parameters "maybe" :follow (lambda (path prefix) (condition-case err (org-link-open-from-string (format "[[%s]]" path)) (error (message "Failed to open maybe link %S" path ;; This must be a lambda so it is self-contained :export (lambda (path desc backend &optional info) (when (symbolp backend) (setq backend (org-export-get-backend backend))) ;; Generate the non-maybe version of the link, and call the ;; backend's appropriate transcoder on it, but catch any error ;; thrown and just replace the link with its text instead. (let* ((real-link (with-temp-buffer (save-excursion (insert "[[" path "][" desc "]]")) (org-element-link-parser))) (real-link-transcoder (cdr (assoc 'link (org-export-get-all-transcoders backend) (condition-case err (funcall real-link-transcoder real-link desc info) (error (message "Skipping error during maybe link transcoding: %S" err) (or desc path)) Using the above code, the following org file can be successfully exported to HTML, with the broken/invalid links converted to just plain text. * First heading :PROPERTIES: :CUSTOM_ID: heading1 :END: - [[maybe:maybe:maybe:https://google.com][Maybe google]] - [[maybe:#heading1][Link to first heading]] - [[maybe:#heading2][Link to second heading]] - [[maybe:#heading3][Link to third(?) heading]] - [[maybe:blarg:notalink][This is an invalid link]] * Second heading :PROPERTIES: :CUSTOM_ID: heading2 :END: So, this isn't an ideal solution, since it requires me to prefix any potential offending links with "maybe:". But it's good enough for me. Regards, Ryan