From dfde96e6b31da8cb9a25c98434237da4f78272f5 Mon Sep 17 00:00:00 2001 From: Max Nikulin Date: Fri, 20 Oct 2023 23:35:16 +0700 Subject: [PATCH 3/3] ox-ascii.el: Allow to export custom links as notes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * lisp/ox-ascii.el (org-ascii-make-link-formatted): New function whose value may be returned by the :export property of `org-link-parameters' to create links optionally formatted similar to footnotes. (org-ascii--describe-links, org-ascii-link): Handle values returned by `org-ascii-make-link-formatted'. It allows to respect `org-ascii-links-to-notes' for custom link types. * testing/lisp/test-ox-ascii.el (test-ox-ascii/link-custom-protocol-cons): New test for the added feature. * lisp/ol-man.el (org-man-export): * lisp/ol-docview.el (org-docview-export): Allow to export links to man pages and to documents as notes at the end of heading. See the following mailing list thread: Ihor Radchenko to emacs-orgmode… Re: Exporting elisp: and shell: links. Sat, 14 Oct 2023 08:13:35 +0000. https://list.orgmode.org/87wmvp1v0w.fsf@localhost --- lisp/ol-docview.el | 6 ++- lisp/ol-man.el | 6 ++- lisp/ox-ascii.el | 34 ++++++++++++-- testing/lisp/test-ox-ascii.el | 83 +++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 8 deletions(-) diff --git a/lisp/ol-docview.el b/lisp/ol-docview.el index bcb26520b..fd945fe2e 100644 --- a/lisp/ol-docview.el +++ b/lisp/ol-docview.el @@ -51,13 +51,14 @@ (require 'ol) (declare-function doc-view-goto-page "doc-view" (page)) (declare-function image-mode-window-get "image-mode" (prop &optional winprops)) (declare-function org-open-file "org" (path &optional in-emacs line search)) +(declare-function org-ascii-make-link-formatted "ox-ascii" (path desc info)) (org-link-set-parameters "docview" :follow #'org-docview-open :export #'org-docview-export :store #'org-docview-store-link) -(defun org-docview-export (link description backend _info) +(defun org-docview-export (link description backend info) "Export a docview LINK with DESCRIPTION for BACKEND." (let ((path (if (string-match "\\(.+\\)::.+" link) (match-string 1 link) link)) @@ -67,7 +68,8 @@ (defun org-docview-export (link description backend _info) (cond ((eq backend 'html) (format "%s" path desc)) ((eq backend 'latex) (format "\\href{%s}{%s}" path desc)) - ((eq backend 'ascii) (format "[%s] (<%s>)" desc path)) + ((eq backend 'ascii) + (org-ascii-make-link-formatted (format "(<%s>)" path) desc info)) (t path))))) (defun org-docview-open (link _) diff --git a/lisp/ol-man.el b/lisp/ol-man.el index b0701c689..da1cca9ed 100644 --- a/lisp/ol-man.el +++ b/lisp/ol-man.el @@ -33,6 +33,8 @@ (org-assert-version) (require 'ol) +(declare-function org-ascii-make-link-formatted "ox-ascii" (path desc info)) + (org-link-set-parameters "man" :follow #'org-man-open :export #'org-man-export @@ -86,7 +88,7 @@ (defun org-man-get-page-name () (match-string 1 (buffer-name)) (error "Cannot create link to this man page"))) -(defun org-man-export (link description backend) +(defun org-man-export (link description backend info) "Export a man page LINK with DESCRIPTION. BACKEND is the current export backend." (let ((path (format "http://man.he.net/?topic=%s§ion=all" link)) @@ -95,7 +97,7 @@ (defun org-man-export (link description backend) ((eq backend 'html) (format "%s" path desc)) ((eq backend 'latex) (format "\\href{%s}{%s}" path desc)) ((eq backend 'texinfo) (format "@uref{%s,%s}" path desc)) - ((eq backend 'ascii) (format "[%s] (<%s>)" desc path)) + ((eq backend 'ascii) (org-ascii-make-link-formatted (format "<%s>" path) desc info)) ((eq backend 'md) (format "[%s](%s)" desc path)) (t path)))) diff --git a/lisp/ox-ascii.el b/lisp/ox-ascii.el index 10bb1fce7..722b2aa4c 100644 --- a/lisp/ox-ascii.el +++ b/lisp/ox-ascii.el @@ -967,13 +967,26 @@ (defun org-ascii--describe-links (links width info) (org-link-broken nil))))) (setq location (and dest (org-ascii--describe-datum dest info)))))) + ;; Do not add a link already handled by custom export + ;; functions. + ((pcase (org-export-custom-protocol-maybe + link + (and description (org-export-data description info)) + 'ascii + info) + ((pred null)) + ((pred stringp) t) + (`(,(and (or `nil (pred stringp)) path) . + ,(and (or `nil (pred stringp)) desc)) + (setq location (org-string-nw-p path)) + (setq anchor desc) + t) + (_ (error "Link :export returned not cons, or string, or nil: %s" + raw-link)))) ;; Do not add a link that cannot be resolved and doesn't have ;; any description: destination is already visible in the ;; paragraph. ((not description)) - ;; Do not add a link already handled by custom export - ;; functions. - ((org-export-custom-protocol-maybe link anchor 'ascii info) nil) (t (setq location (format "<%s>" raw-link)))) (and location @@ -1601,7 +1614,15 @@ (defun org-ascii-link (link desc info) INFO is a plist holding contextual information." (let ((type (org-element-property :type link))) (cond - ((org-export-custom-protocol-maybe link desc 'ascii info)) + ((pcase (org-export-custom-protocol-maybe link desc 'ascii info) + ((pred null) nil) ; Use fallback. + ((and (pred stringp) str) str) + (`(nil . nil) "") + (`(,(and (or `nil (pred stringp)) custom-path) . + ,(and (or `nil (pred stringp)) custom-desc)) + (org-ascii-link-inline custom-path custom-desc info)) + (_ (error "Link :export returned not cons, or string, or nil: %s" + (org-element-property :raw-link link))))) ((string= type "coderef") (let ((ref (org-element-property :path link))) (format (org-export-get-coderef-format ref desc) @@ -2224,6 +2245,11 @@ (defun org-ascii-publish-to-utf8 (plist filename pub-dir) (org-publish-org-to 'ascii filename ".txt" `(:ascii-charset utf-8 ,@plist) pub-dir)) +(defun org-ascii-make-link-formatted (path descr _info) + "To be used in :export property of `org-link-parameters'. +Returns an opaque type interpreted by `org-ascii-link'." + (cons path descr)) + (provide 'ox-ascii) diff --git a/testing/lisp/test-ox-ascii.el b/testing/lisp/test-ox-ascii.el index 07def1633..5165e867c 100644 --- a/testing/lisp/test-ox-ascii.el +++ b/testing/lisp/test-ox-ascii.el @@ -113,6 +113,89 @@ (ert-deftest test-ox-ascii/link-custom-protocol-string () inline).\n")))) (test-ox-ascii--restore-syntax))) +(ert-deftest test-ox-ascii/link-custom-protocol-cons () + "Test of custom link type optionally exported as a note." + (unwind-protect + (let ((org-link-parameters)) + (org-link-set-parameters + "tstcons" + :export (lambda (path descr _backend info) + (org-ascii-make-link-formatted + (concat "excons-" path) descr info))) + ;; As notes. + (let ((org-ascii-links-to-notes t)) + (should ; With description. + (string-equal + (org-export-string-as + "Link [[tstcons:path-descr][with descr[iption]\u200b]] as note." + 'ascii t) + "Link [with descr[iption]\u200b] as note. +\n +[with descr[iption]\u200b] excons-path-descr\n")) + (should ; No description. + (string-equal + (org-export-string-as + "Link without description (note)." + 'ascii t) + "Link excons-path-no-descr without description (note).\n"))) + ;; Inline. + (let ((org-ascii-links-to-notes nil)) + (should ; With description. + (string-equal + (org-export-string-as + "Inline link [[tstcons:path-descr][with description]]." + 'ascii t) + "Inline link [with description] (excons-path-descr).\n")) + (should ; No description. + (string-equal + (org-export-string-as + "Inline link [[tstcons:path-no-descr]] without description." + 'ascii t) + "Inline link excons-path-no-descr without description.\n"))) + ;; Ugly formatting with duplicated brackets. + ;; Behavior likely should be changed to not add another pair of brackets. + (let ((org-link-parameters)) + (org-link-set-parameters + "brcons" + :export (lambda (path descr _backend info) + (org-ascii-make-link-formatted + (format "(exbr-%s)" path) + (and descr (format "[%s]" descr)) + info))) + (let ((org-ascii-links-to-notes t)) + (should + (string-equal + (org-export-string-as + "Link [[brcons:path-descr][with brackets]] as note." + 'ascii t) + "Link [[with brackets]] as note. +\n +[[with brackets]] (exbr-path-descr)\n"))) + ;; Inline. + (let ((org-ascii-links-to-notes nil)) + (should + (string-equal + (org-export-string-as + "Link [[brcons:path-descr][with brackets]] inline." + 'ascii t) + "Link [[with brackets]] (exbr-path-descr) inline.\n")))) + ;; Error. + (org-link-set-parameters + "tsterr" + :export (lambda (path descr _backend _info) + (list (concat "ex-error! " path) descr "extra arg"))) + (let* ((err (should-error + (org-export-string-as + "Signals [[tsterr:invalid :export][aaa]] error." + 'ascii t) + :type 'error)) + (err-text (cadr err))) + (should-not (unless (and (stringp err-text) + (string-match-p "\\`Link :export returned not.*" + err-text)) + err)))) + (test-ox-ascii--restore-syntax))) + (ert-deftest test-ox-ascii/list () "Test lists." ;; Number counter. -- 2.39.2