From f70daf3c8aee0cc0cc16a65621cc66063ffee192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Delafond?= Date: Mon, 13 Oct 2014 11:01:35 +0200 Subject: Imported Upstream version 8.2.10 --- contrib/lisp/ox-groff.el | 2 +- lisp/ob-lilypond.el | 230 ++++---- lisp/ob-sh.el | 8 +- lisp/org-agenda.el | 12 +- lisp/org-element.el | 206 ++++---- lisp/org-loaddefs.el | 38 +- lisp/org-src.el | 37 +- lisp/org-table.el | 10 +- lisp/org-version.el | 4 +- lisp/org.el | 59 ++- lisp/ox-ascii.el | 24 +- lisp/ox-beamer.el | 2 +- lisp/ox-html.el | 143 +++-- lisp/ox-latex.el | 5 +- lisp/ox-md.el | 141 ++--- lisp/ox-odt.el | 2 +- lisp/ox-publish.el | 6 +- lisp/ox-texinfo.el | 1324 ++++++++++++++++++---------------------------- lisp/ox.el | 37 +- mk/org-fixup.el | 16 +- mk/version.mk | 4 +- 21 files changed, 1013 insertions(+), 1297 deletions(-) diff --git a/contrib/lisp/ox-groff.el b/contrib/lisp/ox-groff.el index 8484def..b3e3ad3 100644 --- a/contrib/lisp/ox-groff.el +++ b/contrib/lisp/ox-groff.el @@ -1268,7 +1268,7 @@ INFO is a plist holding contextual information. See ;; description. ((string= type "radio") (let ((destination (org-export-resolve-radio-link link info))) - (when destination + (if (not destination) desc (format "\\fI [%s] \\fP" (org-export-solidify-link-text (org-element-property :value destination)))))) diff --git a/lisp/ob-lilypond.el b/lisp/ob-lilypond.el index 9b57546..00a951d 100644 --- a/lisp/ob-lilypond.el +++ b/lisp/ob-lilypond.el @@ -39,62 +39,62 @@ (defvar org-babel-default-header-args:lilypond '() "Default header arguments for lilypond code blocks. NOTE: The arguments are determined at lilypond compile time. -See (ly-set-header-args)") +See (org-babel-lilypond-set-header-args)") -(defvar ly-compile-post-tangle t +(defvar org-babel-lilypond-compile-post-tangle t "Following the org-babel-tangle (C-c C-v t) command, -ly-compile-post-tangle determines whether ob-lilypond should +org-babel-lilypond-compile-post-tangle determines whether ob-lilypond should automatically attempt to compile the resultant tangled file. If the value is nil, no automated compilation takes place. Default value is t") -(defvar ly-display-pdf-post-tangle t +(defvar org-babel-lilypond-display-pdf-post-tangle t "Following a successful LilyPond compilation -ly-display-pdf-post-tangle determines whether to automate the +org-babel-lilypond-display-pdf-post-tangle determines whether to automate the drawing / redrawing of the resultant pdf. If the value is nil, the pdf is not automatically redrawn. Default value is t") -(defvar ly-play-midi-post-tangle t +(defvar org-babel-lilypond-play-midi-post-tangle t "Following a successful LilyPond compilation -ly-play-midi-post-tangle determines whether to automate the +org-babel-lilypond-play-midi-post-tangle determines whether to automate the playing of the resultant midi file. If the value is nil, the midi file is not automatically played. Default value is t") -(defvar ly-OSX-ly-path +(defvar org-babel-lilypond-OSX-ly-path "/Applications/lilypond.app/Contents/Resources/bin/lilypond") -(defvar ly-OSX-pdf-path "open") -(defvar ly-OSX-midi-path "open") +(defvar org-babel-lilypond-OSX-pdf-path "open") +(defvar org-babel-lilypond-OSX-midi-path "open") -(defvar ly-nix-ly-path "/usr/bin/lilypond") -(defvar ly-nix-pdf-path "evince") -(defvar ly-nix-midi-path "timidity") +(defvar org-babel-lilypond-nix-ly-path "/usr/bin/lilypond") +(defvar org-babel-lilypond-nix-pdf-path "evince") +(defvar org-babel-lilypond-nix-midi-path "timidity") -(defvar ly-w32-ly-path "lilypond") -(defvar ly-w32-pdf-path "") -(defvar ly-w32-midi-path "") +(defvar org-babel-lilypond-w32-ly-path "lilypond") +(defvar org-babel-lilypond-w32-pdf-path "") +(defvar org-babel-lilypond-w32-midi-path "") -(defvar ly-gen-png nil +(defvar org-babel-lilypond-gen-png nil "Image generation (png) can be turned on by default by setting -LY-GEN-PNG to t") +ORG-BABEL-LILYPOND-GEN-PNG to t") -(defvar ly-gen-svg nil +(defvar org-babel-lilypond-gen-svg nil "Image generation (SVG) can be turned on by default by setting -LY-GEN-SVG to t") +ORG-BABEL-LILYPOND-GEN-SVG to t") -(defvar ly-gen-html nil +(defvar org-babel-lilypond-gen-html nil "HTML generation can be turned on by default by setting -LY-GEN-HTML to t") +ORG-BABEL-LILYPOND-GEN-HTML to t") -(defvar ly-gen-pdf nil +(defvar org-babel-lilypond-gen-pdf nil "PDF generation can be turned on by default by setting -LY-GEN-PDF to t") +ORG-BABEL-LILYPOND-GEN-PDF to t") -(defvar ly-use-eps nil +(defvar org-babel-lilypond-use-eps nil "You can force the compiler to use the EPS backend by setting -LY-USE-EPS to t") +ORG-BABEL-LILYPOND-USE-EPS to t") -(defvar ly-arrange-mode nil - "Arrange mode is turned on by setting LY-ARRANGE-MODE +(defvar org-babel-lilypond-arrange-mode nil + "Arrange mode is turned on by setting ORG-BABEL-LILYPOND-ARRANGE-MODE to t. In Arrange mode the following settings are altered from default... :tangle yes, :noweb yes @@ -123,20 +123,20 @@ Depending on whether we are in arrange mode either: 1. Attempt to execute lilypond block according to header settings (This is the default basic mode) 2. Tangle all lilypond blocks and process the result (arrange mode)" - (ly-set-header-args ly-arrange-mode) - (if ly-arrange-mode - (ly-tangle) - (ly-process-basic body params))) + (org-babel-lilypond-set-header-args org-babel-lilypond-arrange-mode) + (if org-babel-lilypond-arrange-mode + (org-babel-lilypond-tangle) + (org-babel-lilypond-process-basic body params))) -(defun ly-tangle () +(defun org-babel-lilypond-tangle () "ob-lilypond specific tangle, attempts to invoke =ly-execute-tangled-ly= if tangle is successful. Also passes specific arguments to =org-babel-tangle=" (interactive) (if (org-babel-tangle nil "yes" "lilypond") - (ly-execute-tangled-ly) nil)) + (org-babel-lilypond-execute-tangled-ly) nil)) -(defun ly-process-basic (body params) +(defun org-babel-lilypond-process-basic (body params) "Execute a lilypond block in basic mode." (let* ((result-params (cdr (assoc :result-params params))) (out-file (cdr (assoc :file params))) @@ -148,7 +148,7 @@ specific arguments to =org-babel-tangle=" (insert (org-babel-expand-body:generic body params))) (org-babel-eval (concat - (ly-determine-ly-path) + (org-babel-lilypond-determine-ly-path) " -dbackend=eps " "-dno-gs-load-fonts " "-dinclude-eps-fonts " @@ -167,45 +167,45 @@ specific arguments to =org-babel-tangle=" "Return an error because LilyPond exporter does not support sessions." (error "Sorry, LilyPond does not currently support sessions!")) -(defun ly-execute-tangled-ly () +(defun org-babel-lilypond-execute-tangled-ly () "Compile result of block tangle with lilypond. If error in compilation, attempt to mark the error in lilypond org file" - (when ly-compile-post-tangle - (let ((ly-tangled-file (ly-switch-extension + (when org-babel-lilypond-compile-post-tangle + (let ((org-babel-lilypond-tangled-file (org-babel-lilypond-switch-extension (buffer-file-name) ".lilypond")) - (ly-temp-file (ly-switch-extension + (org-babel-lilypond-temp-file (org-babel-lilypond-switch-extension (buffer-file-name) ".ly"))) - (if (file-exists-p ly-tangled-file) + (if (file-exists-p org-babel-lilypond-tangled-file) (progn - (when (file-exists-p ly-temp-file) - (delete-file ly-temp-file)) - (rename-file ly-tangled-file - ly-temp-file)) + (when (file-exists-p org-babel-lilypond-temp-file) + (delete-file org-babel-lilypond-temp-file)) + (rename-file org-babel-lilypond-tangled-file + org-babel-lilypond-temp-file)) (error "Error: Tangle Failed!") t) (switch-to-buffer-other-window "*lilypond*") (erase-buffer) - (ly-compile-lilyfile ly-temp-file) + (org-babel-lilypond-compile-lilyfile org-babel-lilypond-temp-file) (goto-char (point-min)) - (if (not (ly-check-for-compile-error ly-temp-file)) + (if (not (org-babel-lilypond-check-for-compile-error org-babel-lilypond-temp-file)) (progn (other-window -1) - (ly-attempt-to-open-pdf ly-temp-file) - (ly-attempt-to-play-midi ly-temp-file)) + (org-babel-lilypond-attempt-to-open-pdf org-babel-lilypond-temp-file) + (org-babel-lilypond-attempt-to-play-midi org-babel-lilypond-temp-file)) (error "Error in Compilation!")))) nil) -(defun ly-compile-lilyfile (file-name &optional test) +(defun org-babel-lilypond-compile-lilyfile (file-name &optional test) "Compile lilypond file and check for compile errors FILE-NAME is full path to lilypond (.ly) file" (message "Compiling LilyPond...") - (let ((arg-1 (ly-determine-ly-path)) ;program + (let ((arg-1 (org-babel-lilypond-determine-ly-path)) ;program (arg-2 nil) ;infile (arg-3 "*lilypond*") ;buffer (arg-4 t) ;display - (arg-5 (if ly-gen-png "--png" "")) ;&rest... - (arg-6 (if ly-gen-html "--html" "")) - (arg-7 (if ly-gen-pdf "--pdf" "")) - (arg-8 (if ly-use-eps "-dbackend=eps" "")) - (arg-9 (if ly-gen-svg "-dbackend=svg" "")) + (arg-5 (if org-babel-lilypond-gen-png "--png" "")) ;&rest... + (arg-6 (if org-babel-lilypond-gen-html "--html" "")) + (arg-7 (if org-babel-lilypond-gen-pdf "--pdf" "")) + (arg-8 (if org-babel-lilypond-use-eps "-dbackend=eps" "")) + (arg-9 (if org-babel-lilypond-gen-svg "-dbackend=svg" "")) (arg-10 (concat "--output=" (file-name-sans-extension file-name))) (arg-11 file-name)) (if test @@ -215,7 +215,7 @@ FILE-NAME is full path to lilypond (.ly) file" arg-1 arg-2 arg-3 arg-4 arg-5 arg-6 arg-7 arg-8 arg-9 arg-10 arg-11)))) -(defun ly-check-for-compile-error (file-name &optional test) +(defun org-babel-lilypond-check-for-compile-error (file-name &optional test) "Check for compile error. This is performed by parsing the *lilypond* buffer containing the output message from the compilation. @@ -226,24 +226,24 @@ nil as file-name since it is unused in this context" (if (not test) (if (not is-error) nil - (ly-process-compile-error file-name)) + (org-babel-lilypond-process-compile-error file-name)) is-error))) -(defun ly-process-compile-error (file-name) +(defun org-babel-lilypond-process-compile-error (file-name) "Process the compilation error that has occurred. FILE-NAME is full path to lilypond file" - (let ((line-num (ly-parse-line-num))) - (let ((error-lines (ly-parse-error-line file-name line-num))) - (ly-mark-error-line file-name error-lines) + (let ((line-num (org-babel-lilypond-parse-line-num))) + (let ((error-lines (org-babel-lilypond-parse-error-line file-name line-num))) + (org-babel-lilypond-mark-error-line file-name error-lines) (error "Error: Compilation Failed!")))) -(defun ly-mark-error-line (file-name line) +(defun org-babel-lilypond-mark-error-line (file-name line) "Mark the erroneous lines in the lilypond org buffer. FILE-NAME is full path to lilypond file. LINE is the erroneous line" (switch-to-buffer-other-window (concat (file-name-nondirectory - (ly-switch-extension file-name ".org")))) + (org-babel-lilypond-switch-extension file-name ".org")))) (let ((temp (point))) (goto-char (point-min)) (setq case-fold-search nil) @@ -254,7 +254,7 @@ LINE is the erroneous line" (goto-char (- (point) (length line)))) (goto-char temp)))) -(defun ly-parse-line-num (&optional buffer) +(defun org-babel-lilypond-parse-line-num (&optional buffer) "Extract error line number." (when buffer (set-buffer buffer)) @@ -276,12 +276,12 @@ LINE is the erroneous line" nil))) nil))) -(defun ly-parse-error-line (file-name lineNo) +(defun org-babel-lilypond-parse-error-line (file-name lineNo) "Extract the erroneous line from the tangled .ly file FILE-NAME is full path to lilypond file. LINENO is the number of the erroneous line" (with-temp-buffer - (insert-file-contents (ly-switch-extension file-name ".ly") + (insert-file-contents (org-babel-lilypond-switch-extension file-name ".ly") nil nil nil t) (if (> lineNo 0) (progn @@ -290,128 +290,128 @@ LINENO is the number of the erroneous line" (buffer-substring (point) (point-at-eol))) nil))) -(defun ly-attempt-to-open-pdf (file-name &optional test) +(defun org-babel-lilypond-attempt-to-open-pdf (file-name &optional test) "Attempt to display the generated pdf file FILE-NAME is full path to lilypond file If TEST is non-nil, the shell command is returned and is not run" - (when ly-display-pdf-post-tangle - (let ((pdf-file (ly-switch-extension file-name ".pdf"))) + (when org-babel-lilypond-display-pdf-post-tangle + (let ((pdf-file (org-babel-lilypond-switch-extension file-name ".pdf"))) (if (file-exists-p pdf-file) (let ((cmd-string - (concat (ly-determine-pdf-path) " " pdf-file))) + (concat (org-babel-lilypond-determine-pdf-path) " " pdf-file))) (if test cmd-string (start-process "\"Audition pdf\"" "*lilypond*" - (ly-determine-pdf-path) + (org-babel-lilypond-determine-pdf-path) pdf-file))) (message "No pdf file generated so can't display!"))))) -(defun ly-attempt-to-play-midi (file-name &optional test) +(defun org-babel-lilypond-attempt-to-play-midi (file-name &optional test) "Attempt to play the generated MIDI file FILE-NAME is full path to lilypond file If TEST is non-nil, the shell command is returned and is not run" - (when ly-play-midi-post-tangle - (let ((midi-file (ly-switch-extension file-name ".midi"))) + (when org-babel-lilypond-play-midi-post-tangle + (let ((midi-file (org-babel-lilypond-switch-extension file-name ".midi"))) (if (file-exists-p midi-file) (let ((cmd-string - (concat (ly-determine-midi-path) " " midi-file))) + (concat (org-babel-lilypond-determine-midi-path) " " midi-file))) (if test cmd-string (start-process "\"Audition midi\"" "*lilypond*" - (ly-determine-midi-path) + (org-babel-lilypond-determine-midi-path) midi-file))) (message "No midi file generated so can't play!"))))) -(defun ly-determine-ly-path (&optional test) +(defun org-babel-lilypond-determine-ly-path (&optional test) "Return correct path to ly binary depending on OS If TEST is non-nil, it contains a simulation of the OS for test purposes" (let ((sys-type (or test system-type))) (cond ((string= sys-type "darwin") - ly-OSX-ly-path) + org-babel-lilypond-OSX-ly-path) ((string= sys-type "windows-nt") - ly-w32-ly-path) - (t ly-nix-ly-path)))) + org-babel-lilypond-w32-ly-path) + (t org-babel-lilypond-nix-ly-path)))) -(defun ly-determine-pdf-path (&optional test) +(defun org-babel-lilypond-determine-pdf-path (&optional test) "Return correct path to pdf viewer depending on OS If TEST is non-nil, it contains a simulation of the OS for test purposes" (let ((sys-type (or test system-type))) (cond ((string= sys-type "darwin") - ly-OSX-pdf-path) + org-babel-lilypond-OSX-pdf-path) ((string= sys-type "windows-nt") - ly-w32-pdf-path) - (t ly-nix-pdf-path)))) + org-babel-lilypond-w32-pdf-path) + (t org-babel-lilypond-nix-pdf-path)))) -(defun ly-determine-midi-path (&optional test) +(defun org-babel-lilypond-determine-midi-path (&optional test) "Return correct path to midi player depending on OS If TEST is non-nil, it contains a simulation of the OS for test purposes" (let ((sys-type (or test test system-type))) (cond ((string= sys-type "darwin") - ly-OSX-midi-path) + org-babel-lilypond-OSX-midi-path) ((string= sys-type "windows-nt") - ly-w32-midi-path) - (t ly-nix-midi-path)))) + org-babel-lilypond-w32-midi-path) + (t org-babel-lilypond-nix-midi-path)))) -(defun ly-toggle-midi-play () +(defun org-babel-lilypond-toggle-midi-play () "Toggle whether midi will be played following a successful compilation." (interactive) - (setq ly-play-midi-post-tangle - (not ly-play-midi-post-tangle)) + (setq org-babel-lilypond-play-midi-post-tangle + (not org-babel-lilypond-play-midi-post-tangle)) (message (concat "Post-Tangle MIDI play has been " - (if ly-play-midi-post-tangle + (if org-babel-lilypond-play-midi-post-tangle "ENABLED." "DISABLED.")))) -(defun ly-toggle-pdf-display () +(defun org-babel-lilypond-toggle-pdf-display () "Toggle whether pdf will be displayed following a successful compilation." (interactive) - (setq ly-display-pdf-post-tangle - (not ly-display-pdf-post-tangle)) + (setq org-babel-lilypond-display-pdf-post-tangle + (not org-babel-lilypond-display-pdf-post-tangle)) (message (concat "Post-Tangle PDF display has been " - (if ly-display-pdf-post-tangle + (if org-babel-lilypond-display-pdf-post-tangle "ENABLED." "DISABLED.")))) -(defun ly-toggle-png-generation () +(defun org-babel-lilypond-toggle-png-generation () "Toggle whether png image will be generated by compilation." (interactive) - (setq ly-gen-png (not ly-gen-png)) + (setq org-babel-lilypond-gen-png (not org-babel-lilypond-gen-png)) (message (concat "PNG image generation has been " - (if ly-gen-png "ENABLED." "DISABLED.")))) + (if org-babel-lilypond-gen-png "ENABLED." "DISABLED.")))) -(defun ly-toggle-html-generation () +(defun org-babel-lilypond-toggle-html-generation () "Toggle whether html will be generated by compilation." (interactive) - (setq ly-gen-html (not ly-gen-html)) + (setq org-babel-lilypond-gen-html (not org-babel-lilypond-gen-html)) (message (concat "HTML generation has been " - (if ly-gen-html "ENABLED." "DISABLED.")))) + (if org-babel-lilypond-gen-html "ENABLED." "DISABLED.")))) -(defun ly-toggle-pdf-generation () +(defun org-babel-lilypond-toggle-pdf-generation () "Toggle whether pdf will be generated by compilation." (interactive) - (setq ly-gen-pdf (not ly-gen-pdf)) + (setq org-babel-lilypond-gen-pdf (not org-babel-lilypond-gen-pdf)) (message (concat "PDF generation has been " - (if ly-gen-pdf "ENABLED." "DISABLED.")))) + (if org-babel-lilypond-gen-pdf "ENABLED." "DISABLED.")))) -(defun ly-toggle-arrange-mode () +(defun org-babel-lilypond-toggle-arrange-mode () "Toggle whether in Arrange mode or Basic mode." (interactive) - (setq ly-arrange-mode - (not ly-arrange-mode)) + (setq org-babel-lilypond-arrange-mode + (not org-babel-lilypond-arrange-mode)) (message (concat "Arrange mode has been " - (if ly-arrange-mode "ENABLED." "DISABLED.")))) + (if org-babel-lilypond-arrange-mode "ENABLED." "DISABLED.")))) -(defun ly-switch-extension (file-name ext) +(defun org-babel-lilypond-switch-extension (file-name ext) "Utility command to swap current FILE-NAME extension with EXT" (concat (file-name-sans-extension file-name) ext)) -(defun ly-get-header-args (mode) +(defun org-babel-lilypond-get-header-args (mode) "Default arguments to use when evaluating a lilypond source block. These depend upon whether we are in arrange mode i.e. ARRANGE-MODE is t" @@ -425,11 +425,11 @@ mode i.e. ARRANGE-MODE is t" '((:results . "file") (:exports . "results"))))) -(defun ly-set-header-args (mode) +(defun org-babel-lilypond-set-header-args (mode) "Set org-babel-default-header-args:lilypond -dependent on LY-ARRANGE-MODE" +dependent on ORG-BABEL-LILYPOND-ARRANGE-MODE" (setq org-babel-default-header-args:lilypond - (ly-get-header-args mode))) + (org-babel-lilypond-get-header-args mode))) (provide 'ob-lilypond) diff --git a/lisp/ob-sh.el b/lisp/ob-sh.el index 96f275b..856c7a0 100644 --- a/lisp/ob-sh.el +++ b/lisp/ob-sh.el @@ -123,7 +123,13 @@ Emacs-lisp table, otherwise return the results as a string." (when (and session (not (string= session "none"))) (save-window-excursion (or (org-babel-comint-buffer-livep session) - (progn (shell session) (get-buffer (current-buffer))))))) + (progn + (shell session) + ;; Needed for Emacs 23 since the marker is initially + ;; undefined and the filter functions try to use it without + ;; checking. + (set-marker comint-last-output-start (point)) + (get-buffer (current-buffer))))))) (defvar org-babel-sh-eoe-indicator "echo 'org_babel_sh_eoe'" "String to indicate that evaluation has completed.") diff --git a/lisp/org-agenda.el b/lisp/org-agenda.el index 0067165..c11c1c8 100644 --- a/lisp/org-agenda.el +++ b/lisp/org-agenda.el @@ -1472,6 +1472,7 @@ symbols specifying conditions when the grid should be displayed: weekly if the agenda shows an entire week today show grid on current date, independent of daily/weekly display require-timed show grid only if at least one item has a time specification + remove-match skip grid times already present in an entry The second item is a string which will be placed behind the grid time. @@ -3352,7 +3353,7 @@ If AGENDA-BUFFER-NAME, use this as the buffer name for the agenda to write." content))) (find-file file) (erase-buffer) - (mapcar (lambda (s) (org-paste-subtree 1 s)) (reverse content)) + (dolist (s content) (org-paste-subtree 1 s)) (write-file file) (kill-buffer (current-buffer)) (message "Org file written to %s" file))) @@ -5088,8 +5089,7 @@ of what a project is and how to check if it stuck, customize the variable "Get the (Emacs Calendar) diary entries for DATE." (require 'diary-lib) (let* ((diary-fancy-buffer "*temporary-fancy-diary-buffer*") - (diary-display-hook '(fancy-diary-display)) - (diary-display-function 'fancy-diary-display) + (diary-display-function 'diary-fancy-display) (pop-up-frames nil) (diary-list-entries-hook (cons 'org-diary-default-entry diary-list-entries-hook)) @@ -9627,7 +9627,7 @@ This is a command that has to be installed in `calendar-mode-map'." (overlay-put ov 'type 'org-marked-entry-overlay)) (end-of-line 1) (or (ignore-errors - (goto-char (next-single-property-change (point) 'txt))) + (goto-char (next-single-property-change (point) 'org-hd-marker))) (beginning-of-line 2)) (while (and (get-char-property (point) 'invisible) (not (eobp))) (beginning-of-line 2)) @@ -9645,7 +9645,7 @@ This is a command that has to be installed in `calendar-mode-map'." (let ((entries-marked 0) txt-at-point) (save-excursion (goto-char (point-min)) - (goto-char (next-single-property-change (point) 'txt)) + (goto-char (next-single-property-change (point) 'org-hd-marker)) (while (and (re-search-forward regexp nil t) (setq txt-at-point (get-text-property (point) 'txt))) (when (string-match regexp txt-at-point) @@ -9681,7 +9681,7 @@ This is a command that has to be installed in `calendar-mode-map'." (save-excursion (goto-char (point-min)) (while (ignore-errors - (goto-char (next-single-property-change (point) 'txt))) + (goto-char (next-single-property-change (point) 'org-hd-marker))) (org-agenda-bulk-toggle)))) (defun org-agenda-bulk-toggle () diff --git a/lisp/org-element.el b/lisp/org-element.el index bbed67a..eb8ff41 100644 --- a/lisp/org-element.el +++ b/lisp/org-element.el @@ -727,11 +727,11 @@ CONTENTS is the contents of the footnote-definition." Return a list whose CAR is `headline' and CDR is a plist containing `:raw-value', `:title', `:alt-title', `:begin', -`:end', `:pre-blank', `:hiddenp', `:contents-begin' and +`:end', `:pre-blank', `:hiddenp', `:contents-begin', `:contents-end', `:level', `:priority', `:tags', `:todo-keyword',`:todo-type', `:scheduled', `:deadline', -`:closed', `:quotedp', `:archivedp', `:commentedp' and -`:footnote-section-p' keywords. +`:closed', `:quotedp', `:archivedp', `:commentedp', +`:footnote-section-p' and `:post-blank' keywords. The plist also contains any property set in the property drawer, with its name in upper cases and colons added at the @@ -870,38 +870,40 @@ CONTENTS is the contents of the element." (org-element-property :tags headline)) (org-element-property :tags headline)))) (and tag-list - (format ":%s:" (mapconcat 'identity tag-list ":"))))) + (format ":%s:" (mapconcat #'identity tag-list ":"))))) (commentedp (org-element-property :commentedp headline)) (quotedp (org-element-property :quotedp headline)) (pre-blank (or (org-element-property :pre-blank headline) 0)) - (heading (concat (make-string (org-reduced-level level) ?*) - (and todo (concat " " todo)) - (and quotedp (concat " " org-quote-string)) - (and commentedp (concat " " org-comment-string)) - (and priority - (format " [#%s]" (char-to-string priority))) - (cond ((and org-footnote-section - (org-element-property - :footnote-section-p headline)) - (concat " " org-footnote-section)) - (title (concat " " title)))))) - (concat heading - ;; Align tags. - (when tags - (cond - ((zerop org-tags-column) (format " %s" tags)) - ((< org-tags-column 0) - (concat - (make-string - (max (- (+ org-tags-column (length heading) (length tags))) 1) - ? ) - tags)) - (t - (concat - (make-string (max (- org-tags-column (length heading)) 1) ? ) - tags)))) - (make-string (1+ pre-blank) 10) - contents))) + (heading + (concat (make-string (if org-odd-levels-only (1- (* level 2)) level) + ?*) + (and todo (concat " " todo)) + (and quotedp (concat " " org-quote-string)) + (and commentedp (concat " " org-comment-string)) + (and priority (format " [#%s]" (char-to-string priority))) + " " + (if (and org-footnote-section + (org-element-property :footnote-section-p headline)) + org-footnote-section + title)))) + (concat + heading + ;; Align tags. + (when tags + (cond + ((zerop org-tags-column) (format " %s" tags)) + ((< org-tags-column 0) + (concat + (make-string + (max (- (+ org-tags-column (length heading) (length tags))) 1) + ?\s) + tags)) + (t + (concat + (make-string (max (- org-tags-column (length heading)) 1) ?\s) + tags)))) + (make-string (1+ pre-blank) ?\n) + contents))) ;;;; Inlinetask @@ -1310,36 +1312,36 @@ containing `:begin', `:end', `:hiddenp', `:contents-begin', `:contents-end', `:post-blank' and `:post-affiliated' keywords. Assume point is at the beginning of the property drawer." - (save-excursion - (let ((case-fold-search t)) - (if (not (save-excursion - (re-search-forward "^[ \t]*:END:[ \t]*$" limit t))) - ;; Incomplete drawer: parse it as a paragraph. - (org-element-paragraph-parser limit affiliated) - (save-excursion - (let* ((drawer-end-line (match-beginning 0)) - (begin (car affiliated)) - (post-affiliated (point)) - (contents-begin (progn (forward-line) - (and (< (point) drawer-end-line) - (point)))) - (contents-end (and contents-begin drawer-end-line)) - (hidden (org-invisible-p2)) - (pos-before-blank (progn (goto-char drawer-end-line) - (forward-line) - (point))) - (end (progn (skip-chars-forward " \r\t\n" limit) - (if (eobp) (point) (line-beginning-position))))) - (list 'property-drawer - (nconc - (list :begin begin - :end end - :hiddenp hidden - :contents-begin contents-begin - :contents-end contents-end - :post-blank (count-lines pos-before-blank end) - :post-affiliated post-affiliated) - (cdr affiliated))))))))) + (let ((case-fold-search t)) + (if (not (save-excursion (re-search-forward "^[ \t]*:END:[ \t]*$" limit t))) + ;; Incomplete drawer: parse it as a paragraph. + (org-element-paragraph-parser limit affiliated) + (save-excursion + (let* ((drawer-end-line (match-beginning 0)) + (begin (car affiliated)) + (post-affiliated (point)) + (contents-begin + (progn + (forward-line) + (and (re-search-forward org-property-re drawer-end-line t) + (line-beginning-position)))) + (contents-end (and contents-begin drawer-end-line)) + (hidden (org-invisible-p2)) + (pos-before-blank (progn (goto-char drawer-end-line) + (forward-line) + (point))) + (end (progn (skip-chars-forward " \r\t\n" limit) + (if (eobp) (point) (line-beginning-position))))) + (list 'property-drawer + (nconc + (list :begin begin + :end end + :hiddenp hidden + :contents-begin contents-begin + :contents-end contents-end + :post-blank (count-lines pos-before-blank end) + :post-affiliated post-affiliated) + (cdr affiliated)))))))) (defun org-element-property-drawer-interpreter (property-drawer contents) "Interpret PROPERTY-DRAWER element as Org syntax. @@ -2094,28 +2096,28 @@ LIMIT bounds the search. Return a list whose CAR is `node-property' and CDR is a plist containing `:key', `:value', `:begin', `:end' and `:post-blank' keywords." - (save-excursion - (looking-at org-property-re) - (let ((case-fold-search t) - (begin (point)) - (key (org-match-string-no-properties 2)) - (value (org-match-string-no-properties 3)) - (pos-before-blank (progn (forward-line) (point))) - (end (progn (skip-chars-forward " \r\t\n" limit) - (if (eobp) (point) (point-at-bol))))) - (list 'node-property - (list :key key - :value value - :begin begin - :end end - :post-blank (count-lines pos-before-blank end)))))) + (looking-at org-property-re) + (let ((begin (point)) + (key (org-match-string-no-properties 2)) + (value (org-match-string-no-properties 3)) + (end (save-excursion + (end-of-line) + (if (re-search-forward org-property-re limit t) + (line-beginning-position) + limit)))) + (list 'node-property + (list :key key + :value value + :begin begin + :end end + :post-blank 0)))) (defun org-element-node-property-interpreter (node-property contents) "Interpret NODE-PROPERTY element as Org syntax. CONTENTS is nil." (format org-property-format (format ":%s:" (org-element-property :key node-property)) - (org-element-property :value node-property))) + (or (org-element-property :value node-property) ""))) ;;;; Paragraph @@ -2481,7 +2483,7 @@ Assume point is at the beginning of the table." (defun org-element-table-interpreter (table contents) "Interpret TABLE element as Org syntax. -CONTENTS is nil." +CONTENTS is a string, if table's type is `org', or nil." (if (eq (org-element-property :type table) 'table.el) (org-remove-indentation (org-element-property :value table)) (concat (with-temp-buffer (insert contents) @@ -4612,29 +4614,29 @@ indentation is not done with TAB characters." (let* ((min-ind most-positive-fixnum) find-min-ind ; For byte-compiler. (find-min-ind - (function - ;; Return minimal common indentation within BLOB. This is - ;; done by walking recursively BLOB and updating MIN-IND - ;; along the way. FIRST-FLAG is non-nil when the first - ;; string hasn't been seen yet. It is required as this - ;; string is the only one whose indentation doesn't happen - ;; after a newline character. - (lambda (blob first-flag) - (dolist (object (org-element-contents blob)) - (when (and first-flag (stringp object)) - (setq first-flag nil) - (string-match "\\`\\( *\\)" object) - (let ((len (length (match-string 1 object)))) - ;; An indentation of zero means no string will be - ;; modified. Quit the process. - (if (zerop len) (throw 'zero (setq min-ind 0)) - (setq min-ind (min len min-ind))))) - (cond - ((stringp object) - (dolist (line (delq "" (cdr (org-split-string object " *\n")))) - (setq min-ind (min (org-get-indentation line) min-ind)))) - ((memq (org-element-type object) org-element-recursive-objects) - (funcall find-min-ind object first-flag)))))))) + ;; Return minimal common indentation within BLOB. This is + ;; done by walking recursively BLOB and updating MIN-IND + ;; along the way. FIRST-FLAG is non-nil when the first + ;; string hasn't been seen yet. It is required as this + ;; string is the only one whose indentation doesn't happen + ;; after a newline character. + (lambda (blob first-flag) + (dolist (object (org-element-contents blob)) + (when (and first-flag (stringp object)) + (setq first-flag nil) + (string-match "\\` *" object) + (let ((len (match-end 0))) + ;; An indentation of zero means no string will be + ;; modified. Quit the process. + (if (zerop len) (throw 'zero (setq min-ind 0)) + (setq min-ind (min len min-ind))))) + (cond + ((stringp object) + (dolist (line (cdr (org-split-string object " *\n"))) + (unless (string= line "") + (setq min-ind (min (org-get-indentation line) min-ind))))) + ((memq (org-element-type object) org-element-recursive-objects) + (funcall find-min-ind object first-flag))))))) ;; Find minimal indentation in ELEMENT. (catch 'zero (funcall find-min-ind element (not ignore-first))) (if (or (zerop min-ind) (= min-ind most-positive-fixnum)) element diff --git a/lisp/org-loaddefs.el b/lisp/org-loaddefs.el index 4695dad..4f937cc 100644 --- a/lisp/org-loaddefs.el +++ b/lisp/org-loaddefs.el @@ -292,7 +292,7 @@ used to limit the exported source code blocks by language. ;;;;;; org-search-view org-agenda-list org-batch-store-agenda-views ;;;;;; org-store-agenda-views org-batch-agenda-csv org-batch-agenda ;;;;;; org-agenda org-toggle-sticky-agenda) "org-agenda" "org-agenda.el" -;;;;;; (21464 32404)) +;;;;;; (21562 65218)) ;;; Generated autoloads from org-agenda.el (autoload 'org-toggle-sticky-agenda "org-agenda" "\ @@ -644,8 +644,8 @@ Extract anniversaries from BBDB for display in the agenda. ;;;*** ;;;### (autoloads (org-capture-import-remember-templates org-capture -;;;;;; org-capture-string) "org-capture" "org-capture.el" (21464 -;;;;;; 32404)) +;;;;;; org-capture-string) "org-capture" "org-capture.el" (21562 +;;;;;; 3391)) ;;; Generated autoloads from org-capture.el (autoload 'org-capture-string "org-capture" "\ @@ -821,7 +821,7 @@ Otherwise, return nil. ;;;### (autoloads (org-agenda-columns org-insert-columns-dblock org-dblock-write:columnview ;;;;;; org-columns-number-to-string org-columns-compute org-columns ;;;;;; org-columns-get-format-and-top-level org-columns-remove-overlays) -;;;;;; "org-colview" "org-colview.el" (21464 32404)) +;;;;;; "org-colview" "org-colview.el" (21562 3391)) ;;; Generated autoloads from org-colview.el (autoload 'org-columns-remove-overlays "org-colview" "\ @@ -885,7 +885,7 @@ Turn on or update column view in the agenda. ;;;*** ;;;### (autoloads (org-check-version) "org-compat" "org-compat.el" -;;;;;; (21464 32404)) +;;;;;; (21562 3391)) ;;; Generated autoloads from org-compat.el (autoload 'org-check-version "org-compat" "\ @@ -910,7 +910,7 @@ tree can be found. ;;;*** ;;;### (autoloads (org-element-context org-element-at-point org-element-interpret-data) -;;;;;; "org-element" "org-element.el" "54914322a8abcdde97acf3e16c5153bb") +;;;;;; "org-element" "org-element.el" "40b84110bb3b104027a4d7ca4fda8d30") ;;; Generated autoloads from org-element.el (autoload 'org-element-interpret-data "org-element" "\ @@ -1156,7 +1156,7 @@ Dispatch to the appropriate function to store a link to an IRC session. ;;;*** ;;;### (autoloads (org-load-noerror-mustsuffix) "org-macs" "org-macs.el" -;;;;;; (21464 32404)) +;;;;;; (21562 3391)) ;;; Generated autoloads from org-macs.el (autoload 'org-load-noerror-mustsuffix "org-macs" "\ @@ -1219,7 +1219,7 @@ line directly before or after the table. ;;;;;; org-table-begin org-table-align org-table-export org-table-import ;;;;;; org-table-convert-region org-table-create org-table-create-or-convert-from-region ;;;;;; org-table-create-with-table\.el) "org-table" "org-table.el" -;;;;;; "eb0c58570f974a880afb6dbc990b4604") +;;;;;; "9b6e8818ec6951cc97eba4e5d0822cef") ;;; Generated autoloads from org-table.el (autoload 'org-table-create-with-table\.el "org-table" "\ @@ -1891,7 +1891,7 @@ replace any running timer. ;;;*** ;;;### (autoloads (org-git-version org-release) "org-version" "org-version.el" -;;;;;; (21464 43563)) +;;;;;; (21562 65320)) ;;; Generated autoloads from org-version.el (autoload 'org-release "org-version" "\ @@ -1917,7 +1917,7 @@ The location of ODT styles.") ;;;;;; org-run-like-in-org-mode turn-on-orgstruct++ turn-on-orgstruct ;;;;;; orgstruct-mode org-global-cycle org-cycle org-mode org-clock-persistence-insinuate ;;;;;; turn-on-orgtbl org-version org-babel-load-file org-babel-do-load-languages) -;;;;;; "org" "org.el" (21464 32405)) +;;;;;; "org" "org.el" (21562 3391)) ;;; Generated autoloads from org.el (autoload 'org-babel-do-load-languages "org" "\ @@ -2140,7 +2140,7 @@ Call the customize function with org as argument. ;;;### (autoloads (org-ascii-publish-to-utf8 org-ascii-publish-to-latin1 ;;;;;; org-ascii-publish-to-ascii org-ascii-export-to-ascii org-ascii-export-as-ascii) -;;;;;; "ox-ascii" "ox-ascii.el" "b6167fea7127509f3138b6133b279333") +;;;;;; "ox-ascii" "ox-ascii.el" "8bba507846964285c7ecb40e66b6afe3") ;;; Generated autoloads from ox-ascii.el (autoload 'org-ascii-export-as-ascii "ox-ascii" "\ @@ -2243,7 +2243,7 @@ Return output file name. ;;;### (autoloads (org-beamer-publish-to-pdf org-beamer-publish-to-latex ;;;;;; org-beamer-insert-options-template org-beamer-select-environment ;;;;;; org-beamer-export-to-pdf org-beamer-export-to-latex org-beamer-export-as-latex -;;;;;; org-beamer-mode) "ox-beamer" "ox-beamer.el" "0348058cc4cbc1e72026db6215d71d9f") +;;;;;; org-beamer-mode) "ox-beamer" "ox-beamer.el" "6e708817388023e1e1df3de8f27188ce") ;;; Generated autoloads from ox-beamer.el (autoload 'org-beamer-mode "ox-beamer" "\ @@ -2385,7 +2385,7 @@ Return output file name. ;;;### (autoloads (org-html-publish-to-html org-html-export-to-html ;;;;;; org-html-convert-region-to-html org-html-export-as-html org-html-htmlize-generate-css) -;;;;;; "ox-html" "ox-html.el" "d5c9c4a0e85bc0c8d4341a5ae06255a3") +;;;;;; "ox-html" "ox-html.el" "65604b7a2a80c70979b37eb44119d6f9") ;;; Generated autoloads from ox-html.el (put 'org-html-head-include-default-style 'safe-local-variable 'booleanp) @@ -2545,7 +2545,7 @@ The file is stored under the name chosen in ;;;### (autoloads (org-latex-publish-to-pdf org-latex-publish-to-latex ;;;;;; org-latex-export-to-pdf org-latex-export-to-latex org-latex-convert-region-to-latex -;;;;;; org-latex-export-as-latex) "ox-latex" "ox-latex.el" "89b0609c28a8054b8c4bb3c76caaa41e") +;;;;;; org-latex-export-as-latex) "ox-latex" "ox-latex.el" "6277aa86c5275b5aae6c2c2d578a04fb") ;;; Generated autoloads from ox-latex.el (autoload 'org-latex-export-as-latex "ox-latex" "\ @@ -2671,7 +2671,7 @@ Return output file name. ;;;*** ;;;### (autoloads (org-md-export-to-markdown org-md-convert-region-to-md -;;;;;; org-md-export-as-markdown) "ox-md" "ox-md.el" "050e805f316d1908d1309facb5cb7d5b") +;;;;;; org-md-export-as-markdown) "ox-md" "ox-md.el" "02d27e093680dff82b16ebedcda8cba8") ;;; Generated autoloads from ox-md.el (autoload 'org-md-export-as-markdown "ox-md" "\ @@ -2733,7 +2733,7 @@ Return output file's name. ;;;*** ;;;### (autoloads (org-odt-convert org-odt-export-to-odt org-odt-export-as-odf-and-open -;;;;;; org-odt-export-as-odf) "ox-odt" "ox-odt.el" "5c27e9fcb578e9179a9788880e547448") +;;;;;; org-odt-export-as-odf) "ox-odt" "ox-odt.el" "688d009902f7a23ab86bb93a843abdf5") ;;; Generated autoloads from ox-odt.el (put 'org-odt-preferred-output-format 'safe-local-variable 'stringp) @@ -2870,7 +2870,7 @@ Return output file name. ;;;### (autoloads (org-publish-current-project org-publish-current-file ;;;;;; org-publish-all org-publish) "ox-publish" "ox-publish.el" -;;;;;; "4ebb7ea664336aa5b508cba81203f819") +;;;;;; "e9f7e2ede20ea11ead21108abf19db90") ;;; Generated autoloads from ox-publish.el (defalias 'org-publish-project 'org-publish) @@ -2914,7 +2914,7 @@ the project. ;;;*** ;;;### (autoloads (org-texinfo-convert-region-to-texinfo org-texinfo-publish-to-texinfo) -;;;;;; "ox-texinfo" "ox-texinfo.el" "2b693692963e10fb670fdafe4674f894") +;;;;;; "ox-texinfo" "ox-texinfo.el" "ae3f8dd17715c8093138512ae3c347cc") ;;; Generated autoloads from ox-texinfo.el (autoload 'org-texinfo-publish-to-texinfo "ox-texinfo" "\ @@ -2940,7 +2940,7 @@ this command to convert it. ;;;### (autoloads (org-export-dispatch org-export-to-file org-export-to-buffer ;;;;;; org-export-insert-default-template org-export-replace-region-by -;;;;;; org-export-string-as org-export-as) "ox" "ox.el" "94545423f577521d4c74654b04f13148") +;;;;;; org-export-string-as org-export-as) "ox" "ox.el" "abbaf953c164e76b9957d5ea22f805c8") ;;; Generated autoloads from ox.el (autoload 'org-export-as "ox" "\ diff --git a/lisp/org-src.el b/lisp/org-src.el index f870b2c..752fa30 100644 --- a/lisp/org-src.el +++ b/lisp/org-src.el @@ -376,23 +376,21 @@ the display of windows containing the Org buffer and the code buffer." (when (fboundp edit-prep-func) (funcall edit-prep-func full-info))) (or org-edit-src-code-timer + (zerop org-edit-src-auto-save-idle-delay) (setq org-edit-src-code-timer - (unless (zerop org-edit-src-auto-save-idle-delay) - (run-with-idle-timer - org-edit-src-auto-save-idle-delay t - (lambda () - (cond - ((and (string-match "\*Org Src" (buffer-name)) - (buffer-modified-p)) - (org-edit-src-save)) - ((not - (delq nil (mapcar - (lambda (b) - (string-match "\*Org Src" (buffer-name b))) - (buffer-list)))) - (cancel-timer org-edit-src-code-timer) - (setq org-edit-src-code-timer))))))))) - t))) + (run-with-idle-timer + org-edit-src-auto-save-idle-delay t + (lambda () + (cond + ((org-string-match-p "\\`\\*Org Src" (buffer-name)) + (when (buffer-modified-p) (org-edit-src-save))) + ((not (org-some (lambda (b) + (org-string-match-p "\\`\\*Org Src" + (buffer-name b))) + (buffer-list))) + (cancel-timer org-edit-src-code-timer) + (setq org-edit-src-code-timer nil)))))))) + t))) (defun org-edit-src-continue (e) "Continue editing source blocks." ;; Fixme: be more accurate @@ -757,8 +755,8 @@ with \",*\", \",#+\", \",,*\" and \",,#+\"." (delete-region beg (max beg end)) (unless (string-match "\\`[ \t]*\\'" code) (insert code)) - ;; Make sure the overlay stays in place - (when (eq context 'save) (move-overlay ovl beg (point))) + ;; Make sure the overlay stays in place + (when (eq context 'save) (move-overlay ovl beg (point))) (goto-char beg) (if single (just-one-space))) (if (memq t (mapcar (lambda (overlay) @@ -774,9 +772,6 @@ with \",*\", \",#+\", \",,*\" and \",,#+\"." (unless (eq context 'save) (move-marker beg nil) (move-marker end nil))) - (when org-edit-src-code-timer - (cancel-timer org-edit-src-code-timer) - (setq org-edit-src-code-timer nil)) (unless (eq context 'save) (when org-edit-src-saved-temp-window-config (set-window-configuration org-edit-src-saved-temp-window-config) diff --git a/lisp/org-table.el b/lisp/org-table.el index f19c027..30a66c9 100644 --- a/lisp/org-table.el +++ b/lisp/org-table.el @@ -436,11 +436,15 @@ available parameters." "[ \t]*|[ \t]*"))))))) (defvar org-table-clean-did-remove-column nil) ; dynamically scoped -(defun org-table-clean-before-export (lines) +(defun org-table-clean-before-export (lines &optional maybe-quoted) "Check if the table has a marking column. If yes remove the column and the special lines." - (let ((special "^[ \t]*| *[#!$*_^/] *|") - (ignore "^[ \t]*| *[!$_^/] *|")) + (let ((special (if maybe-quoted + "^[ \t]*| *\\\\?[\#!$*_^/ ] *|" + "^[ \t]*| *[\#!$*_^/ ] *|")) + (ignore (if maybe-quoted + "^[ \t]*| *\\\\?[!$_^/] *|" + "^[ \t]*| *[!$_^/] *|"))) (setq org-table-clean-did-remove-column (not (memq nil (mapcar diff --git a/lisp/org-version.el b/lisp/org-version.el index ee0a178..e8c6044 100644 --- a/lisp/org-version.el +++ b/lisp/org-version.el @@ -5,13 +5,13 @@ (defun org-release () "The release version of org-mode. Inserted by installing org-mode or when a release is made." - (let ((org-release "8.2.7c")) + (let ((org-release "8.2.10")) org-release)) ;;;###autoload (defun org-git-version () "The Git version of org-mode. Inserted by installing org-mode or when a release is made." - (let ((org-git-version "8.2.7c-dist")) + (let ((org-git-version "8.2.10-dist")) org-git-version)) ;;;###autoload (defvar org-odt-data-dir "/usr/share/emacs/etc/org" diff --git a/lisp/org.el b/lisp/org.el index 9c18677..2b5603c 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -6152,13 +6152,21 @@ Use `org-reduced-level' to remove the effect of `org-odd-levels'." (defvar org-font-lock-keywords nil) (defsubst org-re-property (property &optional literal allow-null) - "Return a regexp matching a PROPERTY line. - Match group 3 will be set to the value if it exists." - (concat "^\\(?4:[ \t]*\\)\\(?1::\\(?2:" - (if literal property (regexp-quote property)) - "\\):\\)[ \t]+\\(?3:[^ \t\r\n]" - (if allow-null "*") - ".*?\\)\\(?5:[ \t]*\\)$")) + "Return a regexp matching a PROPERTY line. + +When optional argument LITERAL is non-nil, do not quote PROPERTY. +This is useful when PROPERTY is a regexp. When ALLOW-NULL is +non-nil, match properties even without a value. + +Match group 3 is set to the value when it exists. If there is no +value and ALLOW-NULL is non-nil, it is set to the empty string." + (concat + "^\\(?4:[ \t]*\\)" + (format "\\(?1::\\(?2:%s\\):\\)" + (if literal property (regexp-quote property))) + (if allow-null + "\\(?:\\(?3:$\\)\\|[ \t]+\\(?3:.*?\\)\\)\\(?5:[ \t]*\\)$" + "[ \t]+\\(?3:[^ \r\t\n]+.*?\\)\\(?5:[ \t]*\\)$"))) (defconst org-property-re (org-re-property ".*?" 'literal t) @@ -6720,7 +6728,8 @@ in special contexts. (setq org-cycle-global-status 'overview) (run-hook-with-args 'org-cycle-hook 'overview))))) -(defvar org-called-with-limited-levels);Dyn-bound in ̀org-with-limited-levels'. +(defvar org-called-with-limited-levels nil + "Non-nil when `org-with-limited-levels' is currently active.") (defun org-cycle-internal-local () "Do the local cycling action." @@ -7724,13 +7733,12 @@ command." "Make the number of empty lines before current exactly N. So this will delete or add empty lines." (save-excursion - (goto-char (point-at-bol)) - (if (looking-back "\\s-+" nil 'greedy) - (replace-match "")) - (or (bobp) (insert "\n")) - (while (> N 0) - (insert "\n") - (setq N (1- N))))) + (beginning-of-line) + (let ((p (point))) + (skip-chars-backward " \r\t\n") + (unless (bolp) (forward-line)) + (delete-region (point) p)) + (when (> N 0) (insert (make-string N ?\n))))) (defun org-get-heading (&optional no-tags no-todo) "Return the heading of the current entry, without the stars. @@ -9091,14 +9099,16 @@ if `orgstruct-heading-prefix-regexp' is not empty." (if fallback (let* ((orgstruct-mode) (binding - (loop with key = ,key - for rep in - '(nil - ("<\\([^>]*\\)tab>" . "\\1TAB") - ("<\\([^>]*\\)return>" . "\\1RET") - ("<\\([^>]*\\)escape>" . "\\1ESC") - ("<\\([^>]*\\)delete>" . "\\1DEL")) - do + (let ((key ,key)) + (catch 'exit + (dolist + (rep + '(nil + ("<\\([^>]*\\)tab>" . "\\1TAB") + ("<\\([^>]*\\)return>" . "\\1RET") + ("<\\([^>]*\\)escape>" . "\\1ESC") + ("<\\([^>]*\\)delete>" . "\\1DEL")) + nil) (when rep (setq key (read-kbd-macro (let ((case-fold-search)) @@ -9106,7 +9116,8 @@ if `orgstruct-heading-prefix-regexp' is not empty." (car rep) (cdr rep) (key-description key)))))) - thereis (key-binding key)))) + (when (key-binding key) + (throw 'exit (key-binding key)))))))) (if (keymapp binding) (org-set-transient-map binding) (let ((func (or binding diff --git a/lisp/ox-ascii.el b/lisp/ox-ascii.el index 4a6696e..cd2a9af 100644 --- a/lisp/ox-ascii.el +++ b/lisp/ox-ascii.el @@ -423,17 +423,17 @@ equivalent to `left'. For a justification that doesn't also fill string, see `org-ascii--justify-string'. Return nil if S isn't a string." - ;; Don't fill paragraph when break should be preserved. - (cond ((not (stringp s)) nil) - ((plist-get info :preserve-breaks) s) - (t (let ((double-space-p sentence-end-double-space)) - (with-temp-buffer - (let ((fill-column text-width) - (use-hard-newlines t) - (sentence-end-double-space double-space-p)) - (insert s) - (fill-region (point-min) (point-max) justify)) - (buffer-string)))))) + (when (stringp s) + (let ((double-space-p sentence-end-double-space)) + (with-temp-buffer + (let ((fill-column text-width) + (use-hard-newlines t) + (sentence-end-double-space double-space-p)) + (insert (if (plist-get info :preserve-breaks) + (replace-regexp-in-string "\n" hard-newline s) + s)) + (fill-region (point-min) (point-max) justify)) + (buffer-string))))) (defun org-ascii--justify-string (s text-width how) "Justify string S. @@ -463,7 +463,7 @@ Empty lines are not indented." "Return string S with a partial box to its left. INFO is a plist used as a communication channel." (let ((utf8p (eq (plist-get info :ascii-charset) 'utf-8))) - (format (if utf8p "╭────\n%s\n╰────" ",----\n%s\n`----") + (format (if utf8p "┌────\n%s\n└────" ",----\n%s\n`----") (replace-regexp-in-string "^" (if utf8p "│ " "| ") ;; Remove last newline character. diff --git a/lisp/ox-beamer.el b/lisp/ox-beamer.el index 1d487e9..5ab805d 100644 --- a/lisp/ox-beamer.el +++ b/lisp/ox-beamer.el @@ -687,7 +687,7 @@ used as a communication channel." (cond ((equal type "radio") (let ((destination (org-export-resolve-radio-link link info))) - (when destination + (if (not destination) contents (format "\\hyperlink%s{%s}{%s}" (or (org-beamer--element-has-overlay-p link) "") (org-export-solidify-link-text diff --git a/lisp/ox-html.el b/lisp/ox-html.el index 3eaeb0a..23498b2 100644 --- a/lisp/ox-html.el +++ b/lisp/ox-html.el @@ -2275,83 +2275,70 @@ holding contextual information." "Transcode a HEADLINE element from Org to HTML. CONTENTS holds the contents of the headline. INFO is a plist holding contextual information." - ;; Empty contents? - (setq contents (or contents "")) - (let* ((numberedp (org-export-numbered-headline-p headline info)) - (level (org-export-get-relative-level headline info)) - (text (org-export-data (org-element-property :title headline) info)) - (todo (and (plist-get info :with-todo-keywords) - (let ((todo (org-element-property :todo-keyword headline))) - (and todo (org-export-data todo info))))) - (todo-type (and todo (org-element-property :todo-type headline))) - (tags (and (plist-get info :with-tags) - (org-export-get-tags headline info))) - (priority (and (plist-get info :with-priority) - (org-element-property :priority headline))) - (section-number (and (org-export-numbered-headline-p headline info) - (mapconcat 'number-to-string - (org-export-get-headline-number - headline info) "."))) - ;; Create the headline text. - (full-text (org-html-format-headline--wrap headline info))) - (cond - ;; Case 1: This is a footnote section: ignore it. - ((org-element-property :footnote-section-p headline) nil) - ;; Case 2. This is a deep sub-tree: export it as a list item. - ;; Also export as items headlines for which no section - ;; format has been found. - ((org-export-low-level-p headline info) - ;; Build the real contents of the sub-tree. - (let* ((type (if numberedp 'ordered 'unordered)) - (itemized-body (org-html-format-list-item - contents type nil info nil full-text))) - (concat - (and (org-export-first-sibling-p headline info) - (org-html-begin-plain-list type)) - itemized-body - (and (org-export-last-sibling-p headline info) - (org-html-end-plain-list type))))) - ;; Case 3. Standard headline. Export it as a section. - (t - (let* ((section-number (mapconcat 'number-to-string - (org-export-get-headline-number - headline info) "-")) - (ids (remove 'nil - (list (org-element-property :CUSTOM_ID headline) - (concat "sec-" section-number) - (org-element-property :ID headline)))) - (preferred-id (car ids)) - (extra-ids (cdr ids)) - (extra-class (org-element-property :HTML_CONTAINER_CLASS headline)) - (level1 (+ level (1- org-html-toplevel-hlevel))) - (first-content (car (org-element-contents headline)))) - (format "<%s id=\"%s\" class=\"%s\">%s%s\n" - (org-html--container headline info) - (format "outline-container-%s" - (or (org-element-property :CUSTOM_ID headline) - (concat "sec-" section-number))) - (concat (format "outline-%d" level1) (and extra-class " ") - extra-class) - (format "\n%s%s\n" - level1 - preferred-id - (mapconcat - (lambda (x) - (let ((id (org-export-solidify-link-text - (if (org-uuidgen-p x) (concat "ID-" x) - x)))) - (org-html--anchor id))) - extra-ids "") - full-text - level1) - ;; When there is no section, pretend there is an empty - ;; one to get the correct
%s%s\n" + (org-html--container headline info) + (format "outline-container-%s" + (or (org-element-property :CUSTOM_ID headline) + (concat "sec-" section-number))) + (concat (format "outline-%d" level1) (and extra-class " ") + extra-class) + (format "\n%s%s\n" + level1 preferred-id extra-ids full-text level1) + ;; When there is no section, pretend there is an + ;; empty one to get the correct
%s" (org-export-solidify-link-text (org-element-property :value destination)) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 5f171da..2c71f7d 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -1809,7 +1809,7 @@ INFO is a plist holding contextual information. See ;; description. ((string= type "radio") (let ((destination (org-export-resolve-radio-link link info))) - (when destination + (if (not destination) desc (format "\\hyperref[%s]{%s}" (org-export-solidify-link-text (org-element-property :value destination)) @@ -1842,7 +1842,8 @@ INFO is a plist holding contextual information. See 'number-to-string (org-export-get-headline-number destination info) "-")))) - (if (and (plist-get info :section-numbers) (not desc)) + (if (and (not desc) + (org-export-numbered-headline-p destination info)) (format "\\ref{%s}" label) (format "\\hyperref[%s]{%s}" label (or desc diff --git a/lisp/ox-md.el b/lisp/ox-md.el index f1c4db9..99a4ae0 100644 --- a/lisp/ox-md.el +++ b/lisp/ox-md.el @@ -102,21 +102,28 @@ This variable can be set to either `atx' or `setext'." TREE is the parse tree being exported. BACKEND is the export back-end used. INFO is a plist used as a communication channel. -Make sure there's no blank line before a plain list, unless it is -located right after a paragraph. Otherwise, add a blank line -between elements. Blank lines between items are preserved. +Enforce a blank line between elements. There are three +exceptions to this rule: + + 1. Preserve blank lines between sibling items in a plain list, + + 2. Outside of plain lists, preserve blank lines between + a paragraph and a plain list, + + 3. In an item, remove any blank line before the very first + paragraph and the next sub-list. Assume BACKEND is `md'." (org-element-map tree (remq 'item org-element-all-elements) - (lambda (elem) - (org-element-put-property - elem :post-blank - (if (and (eq (org-element-type (org-export-get-next-element elem info)) - 'plain-list) - (not (and (eq (org-element-type elem) 'paragraph) - (org-export-get-previous-element elem info)))) - 0 - 1)))) + (lambda (e) + (cond + ((not (and (eq (org-element-type e) 'paragraph) + (eq (org-element-type (org-export-get-next-element e info)) + 'plain-list))) + (org-element-put-property e :post-blank 1)) + ((not (eq (org-element-type (org-element-property :parent e)) 'item))) + (t (org-element-put-property + e :post-blank (if (org-export-get-previous-element e info) 1 0)))))) ;; Return updated tree. tree) @@ -287,57 +294,65 @@ a communication channel." (concat (file-name-sans-extension raw-path) ".md") raw-path)))) (type (org-element-property :type link))) - (cond ((member type '("custom-id" "id")) - (let ((destination (org-export-resolve-id-link link info))) - (if (stringp destination) ; External file. - (let ((path (funcall link-org-files-as-md destination))) - (if (not contents) (format "<%s>" path) - (format "[%s](%s)" contents path))) - (concat - (and contents (concat contents " ")) - (format "(%s)" - (format (org-export-translate "See section %s" :html info) - (mapconcat 'number-to-string - (org-export-get-headline-number - destination info) - "."))))))) - ((org-export-inline-image-p link org-html-inline-image-rules) - (let ((path (let ((raw-path (org-element-property :path link))) - (if (not (file-name-absolute-p raw-path)) raw-path - (expand-file-name raw-path)))) - (caption (org-export-data - (org-export-get-caption - (org-export-get-parent-element link)) info))) - (format "![img](%s)" - (if (not (org-string-nw-p caption)) path - (format "%s \"%s\"" path caption))))) - ((string= type "coderef") - (let ((ref (org-element-property :path link))) - (format (org-export-get-coderef-format ref contents) - (org-export-resolve-coderef ref info)))) - ((equal type "radio") contents) - ((equal type "fuzzy") - (let ((destination (org-export-resolve-fuzzy-link link info))) - (if (org-string-nw-p contents) contents - (when destination - (let ((number (org-export-get-ordinal destination info))) - (when number - (if (atom number) (number-to-string number) - (mapconcat 'number-to-string number ".")))))))) - (t (let* ((raw-path (org-element-property :path link)) - (path - (cond - ((member type '("http" "https" "ftp")) - (concat type ":" raw-path)) - ((string= type "file") - (let ((path (funcall link-org-files-as-md raw-path))) - (if (not (file-name-absolute-p path)) path - ;; If file path is absolute, prepend it - ;; with "file:" component. - (concat "file:" path)))) - (t raw-path)))) - (if (not contents) (format "<%s>" path) - (format "[%s](%s)" contents path))))))) + (cond + ((member type '("custom-id" "id")) + (let ((destination (org-export-resolve-id-link link info))) + (if (stringp destination) ; External file. + (let ((path (funcall link-org-files-as-md destination))) + (if (not contents) (format "<%s>" path) + (format "[%s](%s)" contents path))) + (concat + (and contents (concat contents " ")) + (format "(%s)" + (format (org-export-translate "See section %s" :html info) + (mapconcat 'number-to-string + (org-export-get-headline-number + destination info) + "."))))))) + ((org-export-inline-image-p link org-html-inline-image-rules) + (let ((path (let ((raw-path (org-element-property :path link))) + (if (not (file-name-absolute-p raw-path)) raw-path + (expand-file-name raw-path)))) + (caption (org-export-data + (org-export-get-caption + (org-export-get-parent-element link)) info))) + (format "![img](%s)" + (if (not (org-string-nw-p caption)) path + (format "%s \"%s\"" path caption))))) + ((string= type "coderef") + (let ((ref (org-element-property :path link))) + (format (org-export-get-coderef-format ref contents) + (org-export-resolve-coderef ref info)))) + ((equal type "radio") contents) + ((equal type "fuzzy") + (let ((destination (org-export-resolve-fuzzy-link link info))) + (if (org-string-nw-p contents) contents + (when destination + (let ((number (org-export-get-ordinal destination info))) + (when number + (if (atom number) (number-to-string number) + (mapconcat 'number-to-string number ".")))))))) + ;; Link type is handled by a special function. + ((let ((protocol (nth 2 (assoc type org-link-protocols)))) + (and (functionp protocol) + (funcall protocol + (org-link-unescape (org-element-property :path link)) + contents + 'md)))) + (t (let* ((raw-path (org-element-property :path link)) + (path + (cond + ((member type '("http" "https" "ftp")) + (concat type ":" raw-path)) + ((string= type "file") + (let ((path (funcall link-org-files-as-md raw-path))) + (if (not (file-name-absolute-p path)) path + ;; If file path is absolute, prepend it + ;; with "file:" component. + (concat "file:" path)))) + (t raw-path)))) + (if (not contents) (format "<%s>" path) + (format "[%s](%s)" contents path))))))) ;;;; Paragraph diff --git a/lisp/ox-odt.el b/lisp/ox-odt.el index 6640e8a..03b3214 100644 --- a/lisp/ox-odt.el +++ b/lisp/ox-odt.el @@ -2733,7 +2733,7 @@ INFO is a plist holding contextual information. See ;; link's description. ((string= type "radio") (let ((destination (org-export-resolve-radio-link link info))) - (when destination + (if (not destination) desc (format "%s" (org-export-solidify-link-text diff --git a/lisp/ox-publish.el b/lisp/ox-publish.el index 1dc790d..efc70d2 100644 --- a/lisp/ox-publish.el +++ b/lisp/ox-publish.el @@ -881,7 +881,7 @@ publishing will be done asynchronously, in another process." ;; project is still a string here. (list (assoc project org-publish-project-alist))))) (if async - (org-export-async-start 'ignore + (org-export-async-start (lambda (results) nil) `(let ((org-publish-use-timestamps-flag (if ',force nil ,org-publish-use-timestamps-flag))) (org-publish-projects ',project-alist))) @@ -899,7 +899,7 @@ optional argument ASYNC, publishing will be done asynchronously, in another process." (interactive "P") (if async - (org-export-async-start 'ignore + (org-export-async-start (lambda (results) nil) `(progn (when ',force (org-publish-remove-all-timestamps)) (let ((org-publish-use-timestamps-flag @@ -921,7 +921,7 @@ asynchronously, in another process." (interactive "P") (let ((file (buffer-file-name (buffer-base-buffer)))) (if async - (org-export-async-start 'ignore + (org-export-async-start (lambda (results) nil) `(let ((org-publish-use-timestamps-flag (if ',force nil ,org-publish-use-timestamps-flag))) (org-publish-file ,file))) diff --git a/lisp/ox-texinfo.el b/lisp/ox-texinfo.el index a961d7a..37841d7 100644 --- a/lisp/ox-texinfo.el +++ b/lisp/ox-texinfo.el @@ -21,38 +21,7 @@ ;;; Commentary: ;; -;; This library implements a Texinfo back-end for Org generic -;; exporter. -;; -;; To test it, run -;; -;; M-: (org-export-to-buffer 'texinfo "*Test Texinfo*") RET -;; -;; in an Org mode buffer then switch to the buffer to see the Texinfo -;; export. See ox.el for more details on how this exporter works. -;; - -;; It introduces nine new buffer keywords: "TEXINFO_CLASS", -;; "TEXINFO_FILENAME", "TEXINFO_HEADER", "TEXINFO_POST_HEADER", -;; "TEXINFO_DIR_CATEGORY", "TEXINFO_DIR_TITLE", "TEXINFO_DIR_DESC" -;; "SUBTITLE" and "SUBAUTHOR". - -;; -;; It introduces 1 new headline property keywords: -;; "TEXINFO_MENU_TITLE" for optional menu titles. -;; -;; To include inline code snippets (for example for generating @kbd{} -;; and @key{} commands), the following export-snippet keys are -;; accepted: -;; -;; texinfo -;; info -;; -;; You can add them for export snippets via any of the below: -;; -;; (add-to-list 'org-export-snippet-translation-alist -;; '("info" . "texinfo")) -;; +;; See Org manual for details. ;;; Code: @@ -70,8 +39,8 @@ (center-block . org-texinfo-center-block) (clock . org-texinfo-clock) (code . org-texinfo-code) - (comment . org-texinfo-comment) - (comment-block . org-texinfo-comment-block) + (comment . (lambda (&rest args) "")) + (comment-block . (lambda (&rest args) "")) (drawer . org-texinfo-drawer) (dynamic-block . org-texinfo-dynamic-block) (entity . org-texinfo-entity) @@ -114,13 +83,14 @@ :export-block "TEXINFO" :filters-alist '((:filter-headline . org-texinfo-filter-section-blank-lines) + (:filter-parse-tree . org-texinfo--normalize-headlines) (:filter-section . org-texinfo-filter-section-blank-lines)) :menu-entry '(?i "Export to Texinfo" ((?t "As TEXI file" org-texinfo-export-to-texinfo) (?i "As INFO file" org-texinfo-export-to-info))) :options-alist - '((:texinfo-filename "TEXINFO_FILENAME" nil org-texinfo-filename t) + '((:texinfo-filename "TEXINFO_FILENAME" nil nil t) (:texinfo-class "TEXINFO_CLASS" nil org-texinfo-default-class t) (:texinfo-header "TEXINFO_HEADER" nil nil newline) (:texinfo-post-header "TEXINFO_POST_HEADER" nil nil newline) @@ -128,7 +98,8 @@ (:subauthor "SUBAUTHOR" nil nil newline) (:texinfo-dircat "TEXINFO_DIR_CATEGORY" nil nil t) (:texinfo-dirtitle "TEXINFO_DIR_TITLE" nil nil t) - (:texinfo-dirdesc "TEXINFO_DIR_DESC" nil nil t))) + (:texinfo-dirdesc "TEXINFO_DIR_DESC" nil nil t) + (:texinfo-printed-title "TEXINFO_PRINTED_TITLE" nil nil t))) @@ -141,12 +112,7 @@ :package-version '(Org . "8.0") :group 'org-export) -;;; Preamble - -(defcustom org-texinfo-filename "" - "Default filename for Texinfo output." - :group 'org-export-texinfo - :type '(string :tag "Export Filename")) +;;;; Preamble (defcustom org-texinfo-coding-system nil "Default document encoding for Texinfo output. @@ -162,19 +128,42 @@ If `nil' it will default to `buffer-file-coding-system'." (defcustom org-texinfo-classes '(("info" - "\\input texinfo @c -*- texinfo -*-" + "@documentencoding AUTO\n@documentlanguage AUTO" ("@chapter %s" . "@unnumbered %s") ("@section %s" . "@unnumberedsec %s") ("@subsection %s" . "@unnumberedsubsec %s") ("@subsubsection %s" . "@unnumberedsubsubsec %s"))) "Alist of Texinfo classes and associated header and structure. -If #+Texinfo_CLASS is set in the buffer, use its value and the +If #+TEXINFO_CLASS is set in the buffer, use its value and the associated information. Here is the structure of each cell: \(class-name header-string - \(numbered-section . unnumbered-section\) - ...\) + \(numbered-section . unnumbered-section) + ...) + + +The header string +----------------- + +The header string is inserted in the header of the generated +document, right after \"@setfilename\" and \"@settitle\" +commands. + +If it contains the special string + + \"@documentencoding AUTO\" + +\"AUTO\" will be replaced with an appropriate coding system. See +`org-texinfo-coding-system' for more information. Likewise, if +the string contains the special string + + \"@documentlanguage AUTO\" + +\"AUTO\" will be replaced with the language defined in the +buffer, through #+LANGUAGE keyword, or globally, with +`org-export-default-language', which see. + The sectioning structure ------------------------ @@ -186,10 +175,12 @@ section string and will be replaced by the title of the section. Instead of a list of sectioning commands, you can also specify a function name. That function will be called with two -parameters, the \(reduced) level of the headline, and a predicate +parameters, the reduced) level of the headline, and a predicate non-nil when the headline should be numbered. It must return a format string in which the section title will be added." :group 'org-export-texinfo + :version "24.4" + :package-version '(Org . "8.2") :type '(repeat (list (string :tag "Texinfo class") (string :tag "Texinfo header") @@ -200,7 +191,7 @@ a format string in which the section title will be added." (string :tag "unnumbered")) (function :tag "Hook computing sectioning")))))) -;;; Headline +;;;; Headline (defcustom org-texinfo-format-headline-function 'ignore "Function to format headline text. @@ -230,22 +221,16 @@ order to reproduce the default set-up: :group 'org-export-texinfo :type 'function) -;;; Node listing (menu) +;;;; Node listing (menu) (defcustom org-texinfo-node-description-column 32 - "Column at which to start the description in the node - listings. - + "Column at which to start the description in the node listings. If a node title is greater than this length, the description will be placed after the end of the title." :group 'org-export-texinfo :type 'integer) -;;; Footnotes -;; -;; Footnotes are inserted directly - -;;; Timestamps +;;;; Timestamps (defcustom org-texinfo-active-timestamp-format "@emph{%s}" "A printf format string to be applied to active timestamps." @@ -262,14 +247,14 @@ be placed after the end of the title." :group 'org-export-texinfo :type 'string) -;;; Links +;;;; Links (defcustom org-texinfo-link-with-unknown-path-format "@indicateurl{%s}" "Format string for links with unknown path type." :group 'org-export-texinfo :type 'string) -;;; Tables +;;;; Tables (defcustom org-texinfo-tables-verbatim nil "When non-nil, tables are exported verbatim." @@ -285,14 +270,14 @@ When nil, no transformation is made." :group 'org-export-texinfo :type '(choice (string :tag "Format string") - (const :tag "No formatting"))) + (const :tag "No formatting" nil))) (defcustom org-texinfo-def-table-markup "@samp" "Default setting for @table environments." :group 'org-export-texinfo :type 'string) -;;; Text markup +;;;; Text markup (defcustom org-texinfo-text-markup-alist '((bold . "@strong{%s}") (code . code) @@ -316,7 +301,7 @@ returned as-is." :type 'alist :options '(bold code italic verbatim comment)) -;;; Drawers +;;;; Drawers (defcustom org-texinfo-format-drawer-function (lambda (name contents) contents) @@ -331,10 +316,10 @@ The function should return the string to be exported. The default function simply returns the value of CONTENTS." :group 'org-export-texinfo :version "24.4" - :package-version '(Org . "8.3") + :package-version '(Org . "8.2") :type 'function) -;;; Inlinetasks +;;;; Inlinetasks (defcustom org-texinfo-format-inlinetask-function 'ignore "Function called to format an inlinetask in Texinfo code. @@ -370,18 +355,13 @@ in order to mimic default behavior: :group 'org-export-texinfo :type 'function) -;;; Src blocks -;; -;; Src Blocks are example blocks, except for LISP - -;;; Compilation +;;;; Compilation -(defcustom org-texinfo-info-process - '("makeinfo %f") +(defcustom org-texinfo-info-process '("makeinfo %f") "Commands to process a Texinfo file to an INFO file. This is list of strings, each of them will be given to the shell as a command. %f in the command will be replaced by the full -file name, %b by the file base name \(i.e without extension) and +file name, %b by the file base name (i.e without extension) and %o by the base directory of the file." :group 'org-export-texinfo :type '(repeat :tag "Shell command sequence" @@ -403,12 +383,13 @@ set `org-texinfo-logfiles-extensions'." :group 'org-export-latex :type 'boolean) - ;;; Constants + (defconst org-texinfo-max-toc-depth 4 - "Maximum depth for creation of detailed menu listings. Beyond - this depth Texinfo will not recognize the nodes and will cause - errors. Left as a constant in case this value ever changes.") + "Maximum depth for creation of detailed menu listings. +Beyond this depth, Texinfo will not recognize the nodes and will +cause errors. Left as a constant in case this value ever +changes.") (defconst org-texinfo-supported-coding-systems '("US-ASCII" "UTF-8" "ISO-8859-15" "ISO-8859-1" "ISO-8859-2" "koi8-r" "koi8-u") @@ -425,6 +406,31 @@ If two strings share the same prefix (e.g. \"ISO-8859-1\" and (let ((blanks (make-string 2 ?\n))) (replace-regexp-in-string "\n\\(?:\n[ \t]*\\)*\\'" blanks headline))) +(defun org-texinfo--normalize-headlines (tree back-end info) + "Normalize headlines in TREE. + +BACK-END is the symbol specifying back-end used for export. INFO +is a plist used as a communication channel. + +Make sure every headline in TREE contains a section, since those +are required to install a menu. Also put exactly one blank line +at the end of each section. + +Return new tree." + (org-element-map tree 'headline + (lambda (hl) + (org-element-put-property hl :post-blank 1) + (let ((contents (org-element-contents hl))) + (when contents + (let ((first (org-element-map contents '(headline section) + #'identity info t))) + (unless (eq (org-element-type first) 'section) + (apply #'org-element-set-contents + hl + (cons `(section (:parent ,hl)) contents))))))) + info) + tree) + (defun org-texinfo--find-verb-separator (s) "Return a character not used in string S. This is used to choose a separator for constructs like \\verb." @@ -433,18 +439,6 @@ This is used to choose a separator for constructs like \\verb." when (not (string-match (regexp-quote (char-to-string c)) s)) return (char-to-string c)))) -(defun org-texinfo--make-option-string (options) - "Return a comma separated string of keywords and values. -OPTIONS is an alist where the key is the options keyword as -a string, and the value a list containing the keyword value, or -nil." - (mapconcat (lambda (pair) - (concat (first pair) - (when (> (length (second pair)) 0) - (concat "=" (second pair))))) - options - ",")) - (defun org-texinfo--text-markup (text markup) "Format TEXT depending on MARKUP text markup. See `org-texinfo-text-markup-alist' for details." @@ -472,207 +466,44 @@ See `org-texinfo-text-markup-alist' for details." ;; Else use format string. (t (format fmt text))))) -(defun org-texinfo--get-node (headline info) - "Return node entry associated to HEADLINE. -INFO is a plist used as a communication channel." - (let ((menu-title (org-export-get-alt-title headline info))) - (org-texinfo--sanitize-menu - (replace-regexp-in-string - "%" "%%" - (if menu-title (org-export-data menu-title info) - (org-texinfo--sanitize-headline - (org-element-property :title headline) info)))))) - -;;; Headline sanitizing - -(defun org-texinfo--sanitize-headline (headline info) - "Remove all formatting from the text of a headline for use in - node and menu listing." - (mapconcat 'identity - (org-texinfo--sanitize-headline-contents headline info) " ")) - -(defun org-texinfo--sanitize-headline-contents (headline info) - "Retrieve the content of the headline. - -Any content that can contain further formatting is checked -recursively, to ensure that nested content is also properly -retrieved." - (loop for contents in headline append - (cond - ;; already a string - ((stringp contents) - (list (replace-regexp-in-string " $" "" contents))) - ;; Is exported as-is (value) - ((org-element-map contents '(verbatim code) - (lambda (value) (org-element-property :value value)) info)) - ;; Has content and recurse into the content - ((org-element-contents contents) - (org-texinfo--sanitize-headline-contents - (org-element-contents contents) info))))) - -;;; Menu sanitizing - -(defun org-texinfo--sanitize-menu (title) - "Remove invalid characters from TITLE for use in menus and -nodes. - -Based on Texinfo specifications, the following must be removed: -@ { } ( ) : . ," - (replace-regexp-in-string "[@{}():,.]" "" title)) - -;;; Content sanitizing +(defun org-texinfo--get-node (blob info) + "Return node or anchor associated to BLOB. +BLOB is an element or object. INFO is a plist used as +a communication channel. The function guarantees the node or +anchor name is unique." + (let ((cache (plist-get info :texinfo-node-cache))) + (or (cdr (assq blob cache)) + (let ((name + (org-texinfo--sanitize-node + (case (org-element-type blob) + (headline + (org-export-data (org-export-get-alt-title blob info) info)) + ((radio-target target) (org-element-property :value blob)) + (otherwise (or (org-element-property :name blob) "")))))) + ;; Ensure NAME is unique. + (while (rassoc name cache) (setq name (concat name "x"))) + (plist-put info :texinfo-node-cache (cons (cons blob name) cache)) + name)))) + +;;;; Menu sanitizing + +(defun org-texinfo--sanitize-node (title) + "Bend string TITLE to node line requirements. +Trim string and collapse multiple whitespace characters as they +are not significant. Also remove the following characters: @ +{ } ( ) : . ," + (replace-regexp-in-string + "[:,.]" "" + (replace-regexp-in-string + "\\`(\\(.*)\\)" "[\\1" + (org-trim (replace-regexp-in-string "[ \t]\\{2,\\}" " " title))))) + +;;;; Content sanitizing (defun org-texinfo--sanitize-content (text) - "Ensure characters are properly escaped when used in headlines or blocks. - -Escape characters are: @ { }" - (replace-regexp-in-string "\\\([@{}]\\\)" "@\\1" text)) - -;;; Menu creation - -(defun org-texinfo--build-menu (tree level info &optional detailed) - "Create the @menu/@end menu information from TREE at headline -level LEVEL. - -TREE contains the parse-tree to work with, either of the entire -document or of a specific parent headline. LEVEL indicates what -level of headlines to look at when generating the menu. INFO is -a plist containing contextual information. - -Detailed determines whether to build a single level of menu, or -recurse into all children as well." - (let ((menu (org-texinfo--generate-menu-list tree level info)) - output text-menu) - (cond - (detailed - ;; Looping is done within the menu generation. - (setq text-menu (org-texinfo--generate-detailed menu level info))) - (t - (setq text-menu (org-texinfo--generate-menu-items menu info)))) - (when text-menu - (setq output (org-texinfo--format-menu text-menu)) - (mapconcat 'identity output "\n")))) - -(defun org-texinfo--generate-detailed (menu level info) - "Generate a detailed listing of all subheadings within MENU starting at LEVEL. - -MENU is the parse-tree to work with. LEVEL is the starting level -for the menu headlines and from which recursion occurs. INFO is -a plist containing contextual information." - (when level - (let ((max-depth (min org-texinfo-max-toc-depth - (plist-get info :headline-levels)))) - (when (> max-depth level) - (loop for headline in menu append - (let* ((title (org-texinfo--menu-headlines headline info)) - ;; Create list of menu entries for the next level - (sublist (org-texinfo--generate-menu-list - headline (1+ level) info)) - ;; Generate the menu items for that level. If - ;; there are none omit that heading completely, - ;; otherwise join the title to it's related entries. - (submenu (if (org-texinfo--generate-menu-items sublist info) - (append (list title) - (org-texinfo--generate-menu-items sublist info)) - 'nil)) - ;; Start the process over the next level down. - (recursion (org-texinfo--generate-detailed sublist (1+ level) info))) - (setq recursion (append submenu recursion)) - recursion)))))) - -(defun org-texinfo--generate-menu-list (tree level info) - "Generate the list of headlines that are within a given level -of the tree for further formatting. - -TREE is the parse-tree containing the headlines. LEVEL is the -headline level to generate a list of. INFO is a plist holding -contextual information." - (org-element-map tree 'headline - (lambda (head) - (and (= (org-export-get-relative-level head info) level) - ;; Do not take note of footnotes or copying headlines. - (not (org-element-property :COPYING head)) - (not (org-element-property :footnote-section-p head)) - ;; Collect headline. - head)) - info)) - -(defun org-texinfo--generate-menu-items (items info) - "Generate a list of headline information from the listing ITEMS. - -ITEMS is a list of the headlines to be converted into entries. -INFO is a plist containing contextual information. - -Returns a list containing the following information from each -headline: length, title, description. This is used to format the -menu using `org-texinfo--format-menu'." - (loop for headline in items collect - (let* ((menu-title (org-texinfo--sanitize-menu - (org-export-data - (org-export-get-alt-title headline info) - info))) - (title (org-texinfo--sanitize-menu - (org-texinfo--sanitize-headline - (org-element-property :title headline) info))) - (descr (org-export-data - (org-element-property :DESCRIPTION headline) - info)) - (menu-entry (if (string= "" menu-title) title menu-title)) - (len (length menu-entry)) - (output (list len menu-entry descr))) - output))) - -(defun org-texinfo--menu-headlines (headline info) - "Retrieve the title from HEADLINE. - -INFO is a plist holding contextual information. - -Return the headline as a list of (length title description) with -length of -1 and nil description. This is used in -`org-texinfo--format-menu' to identify headlines as opposed to -entries." - (let ((title (org-export-data - (org-element-property :title headline) info))) - (list -1 title 'nil))) - -(defun org-texinfo--format-menu (text-menu) - "Format the TEXT-MENU items to be properly printed in the menu. - -Each entry in the menu should be provided as (length title -description). - -Headlines in the detailed menu are given length -1 to ensure they -are never confused with other entries. They also have no -description. - -Other menu items are output as: - Title:: description - -With the spacing between :: and description based on the length -of the longest menu entry." - - (let (output) - (setq output - (mapcar (lambda (name) - (let* ((title (nth 1 name)) - (desc (nth 2 name)) - (length (nth 0 name)) - (column (max - ;;6 is "* " ":: " for inserted text - length - (- - org-texinfo-node-description-column - 6))) - (spacing (- column length) - )) - (if (> length -1) - (concat "* " title ":: " - (make-string spacing ?\s) - (if desc - (concat desc))) - (concat "\n" title "\n")))) - text-menu)) - output)) + "Escape special characters in string TEXT. +Special characters are: @ { }" + (replace-regexp-in-string "[@{}]" "@\\&" text)) ;;; Template @@ -680,145 +511,127 @@ of the longest menu entry." "Return complete document string after Texinfo conversion. CONTENTS is the transcoded contents string. INFO is a plist holding export options." - (let* ((title (org-export-data (plist-get info :title) info)) - (info-filename (or (plist-get info :texinfo-filename) - (file-name-nondirectory - (org-export-output-file-name ".info")))) - (author (org-export-data (plist-get info :author) info)) - (lang (org-export-data (plist-get info :language) info)) - (texinfo-header (plist-get info :texinfo-header)) - (texinfo-post-header (plist-get info :texinfo-post-header)) - (subtitle (plist-get info :subtitle)) - (subauthor (plist-get info :subauthor)) - (class (plist-get info :texinfo-class)) - (header (nth 1 (assoc class org-texinfo-classes))) - (copying - (org-element-map (plist-get info :parse-tree) 'headline - (lambda (hl) (and (org-element-property :COPYING hl) hl)) info t)) - (dircat (plist-get info :texinfo-dircat)) - (dirtitle (plist-get info :texinfo-dirtitle)) - (dirdesc (plist-get info :texinfo-dirdesc)) - ;; Spacing to align description (column 32 - 3 for `* ' and - ;; `.' in text. - (dirspacing (- 29 (length dirtitle))) - (menu (org-texinfo-make-menu info 'main)) - (detail-menu (org-texinfo-make-menu info 'detailed))) + (let ((title (org-export-data (plist-get info :title) info)) + ;; Copying data is the contents of the first headline in + ;; parse tree with a non-nil copying property. + (copying (org-element-map (plist-get info :parse-tree) 'headline + (lambda (hl) + (and (org-not-nil (org-element-property :COPYING hl)) + (org-element-contents hl))) + info t))) (concat - ;; Header - header "\n" + "\\input texinfo @c -*- texinfo -*-\n" "@c %**start of header\n" - ;; Filename and Title - "@setfilename " info-filename "\n" - "@settitle " title "\n" - ;; Coding system. - (format - "@documentencoding %s\n" - (catch 'coding-system - (let ((case-fold-search t) - (name (symbol-name (or org-texinfo-coding-system - buffer-file-coding-system)))) - (dolist (system org-texinfo-supported-coding-systems "UTF-8") - (when (org-string-match-p (regexp-quote system) name) - (throw 'coding-system system)))))) - "\n" - (format "@documentlanguage %s\n" lang) - "\n\n" - "@c Version and Contact Info\n" - "@set AUTHOR " author "\n" - - ;; Additional Header Options set by `#+TEXINFO_HEADER - (if texinfo-header - (concat "\n" - texinfo-header - "\n")) - - "@c %**end of header\n" - "@finalout\n" - "\n\n" - - ;; Additional Header Options set by #+TEXINFO_POST_HEADER - (if texinfo-post-header - (concat "\n" - texinfo-post-header - "\n")) - - ;; Copying - "@copying\n" - ;; Only export the content of the headline, do not need the - ;; initial headline. - (org-export-data (nth 2 copying) info) - "@end copying\n" - "\n\n" - - ;; Info directory information - ;; Only supply if both title and category are provided - (if (and dircat dirtitle) + (let ((file (or (plist-get info :texinfo-filename) + (let ((f (plist-get info :output-file))) + (and f (concat (file-name-sans-extension f) ".info")))))) + (and file (format "@setfilename %s\n" file))) + (format "@settitle %s\n" title) + ;; Insert class-defined header. + (org-element-normalize-string + (let ((header (nth 1 (assoc (plist-get info :texinfo-class) + org-texinfo-classes))) + (coding + (catch 'coding-system + (let ((case-fold-search t) + (name (symbol-name (or org-texinfo-coding-system + buffer-file-coding-system)))) + (dolist (system org-texinfo-supported-coding-systems "UTF-8") + (when (org-string-match-p (regexp-quote system) name) + (throw 'coding-system system)))))) + (language (plist-get info :language)) + (case-fold-search nil)) + ;; Auto coding system. + (replace-regexp-in-string + "^@documentencoding \\(AUTO\\)$" + coding + (replace-regexp-in-string + "^@documentlanguage \\(AUTO\\)$" language header t nil 1) t nil 1))) + ;; Additional header options set by #+TEXINFO_HEADER. + (let ((texinfo-header (plist-get info :texinfo-header))) + (and texinfo-header (org-element-normalize-string texinfo-header))) + "@c %**end of header\n\n" + ;; Additional options set by #+TEXINFO_POST_HEADER. + (let ((texinfo-post-header (plist-get info :texinfo-post-header))) + (and texinfo-post-header + (org-element-normalize-string texinfo-post-header))) + ;; Copying. + (and copying + (format "@copying\n%s@end copying\n\n" + (org-element-normalize-string + (org-export-data copying info)))) + ;; Info directory information. Only supply if both title and + ;; category are provided. + (let ((dircat (plist-get info :texinfo-dircat)) + (dirtitle + (let ((title (plist-get info :texinfo-dirtitle))) + (and title + (string-match "^\\(?:\\* \\)?\\(.*?\\)\\(\\.\\)?$" title) + (format "* %s." (match-string 1 title)))))) + (when (and dircat dirtitle) (concat "@dircategory " dircat "\n" "@direntry\n" - "* " dirtitle "." - (make-string dirspacing ?\s) - dirdesc "\n" - "@end direntry\n")) - "\n\n" - + (let ((dirdesc + (let ((desc (plist-get info :texinfo-dirdesc))) + (cond ((not desc) nil) + ((org-string-match-p "\\.$" desc) desc) + (t (concat desc ".")))))) + (if dirdesc (format "%-23s %s" dirtitle dirdesc) dirtitle)) + "\n" + "@end direntry\n\n"))) ;; Title + "@finalout\n" "@titlepage\n" - "@title " title "\n\n" - (if subtitle - (concat "@subtitle " subtitle "\n")) - "@author " author "\n" - (if subauthor - (concat subauthor "\n")) - "\n" - "@c The following two commands start the copyright page.\n" - "@page\n" - "@vskip 0pt plus 1filll\n" - "@insertcopying\n" + (format "@title %s\n" (or (plist-get info :texinfo-printed-title) title)) + (let ((subtitle (plist-get info :subtitle))) + (and subtitle + (org-element-normalize-string + (replace-regexp-in-string "^" "@subtitle " subtitle)))) + (when (plist-get info :with-author) + (concat + ;; Primary author. + (let ((author (org-string-nw-p + (org-export-data (plist-get info :author) info))) + (email (and (plist-get info :with-email) + (org-string-nw-p + (org-export-data (plist-get info :email) info))))) + (cond ((and author email) + (format "@author %s (@email{%s})\n" author email)) + (author (format "@author %s\n" author)) + (email (format "@author @email{%s}\n" email)))) + ;; Other authors. + (let ((subauthor (plist-get info :subauthor))) + (and subauthor + (org-element-normalize-string + (replace-regexp-in-string "^" "@author " subauthor)))))) + (and copying "@page\n@vskip 0pt plus 1filll\n@insertcopying\n") "@end titlepage\n\n" - "@c Output the table of contents at the beginning.\n" - "@contents\n\n" - + ;; Table of contents. + (and (plist-get info :with-toc) "@contents\n\n") ;; Configure Top Node when not for Tex "@ifnottex\n" "@node Top\n" - "@top " title " Manual\n" - "@insertcopying\n" + (format "@top %s\n" title) + (and copying "@insertcopying\n") "@end ifnottex\n\n" - - ;; Do not output menus if they are empty - (if menu - ;; Menu - (concat "@menu\n" - menu - "\n\n" - ;; Detailed Menu - (if detail-menu - (concat "@detailmenu\n" - " --- The Detailed Node Listing ---\n" - detail-menu - "\n\n" - "@end detailmenu\n")) - "@end menu\n")) - "\n\n" - - ;; Document's body. - contents + ;; Menu. + (org-texinfo-make-menu (plist-get info :parse-tree) info 'master) "\n" + ;; Document's body. + contents "\n" ;; Creator. - (let ((creator-info (plist-get info :with-creator))) - (cond - ((not creator-info) "") - ((eq creator-info 'comment) - (format "@c %s\n" (plist-get info :creator))) - (t (concat (plist-get info :creator) "\n")))) + (case (plist-get info :with-creator) + ((nil) nil) + (comment (format "@c %s\n" (plist-get info :creator))) + (otherwise (concat (plist-get info :creator) "\n"))) ;; Document end. - "\n@bye"))) + "@bye"))) ;;; Transcode Functions -;;; Bold +;;;; Bold (defun org-texinfo-bold (bold contents info) "Transcode BOLD from Org to Texinfo. @@ -826,7 +639,7 @@ CONTENTS is the text with bold markup. INFO is a plist holding contextual information." (org-texinfo--text-markup contents 'bold)) -;;; Center Block +;;;; Center Block (defun org-texinfo-center-block (center-block contents info) "Transcode a CENTER-BLOCK element from Org to Texinfo. @@ -834,7 +647,7 @@ CONTENTS holds the contents of the block. INFO is a plist used as a communication channel." contents) -;;; Clock +;;;; Clock (defun org-texinfo-clock (clock contents info) "Transcode a CLOCK element from Org to Texinfo. @@ -851,7 +664,7 @@ information." (and time (format " (%s)" time))))) "@*")) -;;; Code +;;;; Code (defun org-texinfo-code (code contents info) "Transcode a CODE object from Org to Texinfo. @@ -859,23 +672,7 @@ CONTENTS is nil. INFO is a plist used as a communication channel." (org-texinfo--text-markup (org-element-property :value code) 'code)) -;;; Comment - -(defun org-texinfo-comment (comment contents info) - "Transcode a COMMENT object from Org to Texinfo. -CONTENTS is the text in the comment. INFO is a plist holding -contextual information." - (org-texinfo--text-markup (org-element-property :value comment) 'comment)) - -;;; Comment Block - -(defun org-texinfo-comment-block (comment-block contents info) - "Transcode a COMMENT-BLOCK object from Org to Texinfo. -CONTENTS is the text within the block. INFO is a plist holding -contextual information." - (format "@ignore\n%s@end ignore" (org-element-property :value comment-block))) - -;;; Drawer +;;;; Drawer (defun org-texinfo-drawer (drawer contents info) "Transcode a DRAWER element from Org to Texinfo. @@ -886,15 +683,15 @@ holding contextual information." name contents))) output)) -;;; Dynamic Block +;;;; Dynamic Block (defun org-texinfo-dynamic-block (dynamic-block contents info) "Transcode a DYNAMIC-BLOCK element from Org to Texinfo. CONTENTS holds the contents of the block. INFO is a plist -holding contextual information. See `org-export-data'." +holding contextual information." contents) -;;; Entity +;;;; Entity (defun org-texinfo-entity (entity contents info) "Transcode an ENTITY object from Org to Texinfo. @@ -903,7 +700,7 @@ contextual information." (let ((ent (org-element-property :latex entity))) (if (org-element-property :latex-math-p entity) (format "@math{%s}" ent) ent))) -;;; Example Block +;;;; Example Block (defun org-texinfo-example-block (example-block contents info) "Transcode an EXAMPLE-BLOCK element from Org to Texinfo. @@ -912,7 +709,7 @@ information." (format "@verbatim\n%s@end verbatim" (org-export-format-code-default example-block info))) -;;; Export Block +;;;; Export Block (defun org-texinfo-export-block (export-block contents info) "Transcode a EXPORT-BLOCK element from Org to Texinfo. @@ -920,7 +717,7 @@ CONTENTS is nil. INFO is a plist holding contextual information." (when (string= (org-element-property :type export-block) "TEXINFO") (org-remove-indentation (org-element-property :value export-block)))) -;;; Export Snippet +;;;; Export Snippet (defun org-texinfo-export-snippet (export-snippet contents info) "Transcode a EXPORT-SNIPPET object from Org to Texinfo. @@ -928,7 +725,7 @@ CONTENTS is nil. INFO is a plist holding contextual information." (when (eq (org-export-snippet-backend export-snippet) 'texinfo) (org-element-property :value export-snippet))) -;;; Fixed Width +;;;; Fixed Width (defun org-texinfo-fixed-width (fixed-width contents info) "Transcode a FIXED-WIDTH element from Org to Texinfo. @@ -938,8 +735,7 @@ CONTENTS is nil. INFO is a plist holding contextual information." (org-texinfo--sanitize-content (org-element-property :value fixed-width))))) -;;; Footnote Reference -;; +;;;; Footnote Reference (defun org-texinfo-footnote-reference (footnote contents info) "Create a footnote reference for FOOTNOTE. @@ -950,7 +746,7 @@ plist holding contextual information." (format "@footnote{%s}" (org-trim (org-export-data def info))))) -;;; Headline +;;;; Headline (defun org-texinfo-headline (headline contents info) "Transcode a HEADLINE element from Org to Texinfo. @@ -960,66 +756,29 @@ holding contextual information." (level (org-export-get-relative-level headline info)) (numberedp (org-export-numbered-headline-p headline info)) (class-sectioning (assoc class org-texinfo-classes)) - ;; Find the index type, if any + ;; Find the index type, if any. (index (org-element-property :INDEX headline)) - ;; Check if it is an appendix - (appendix (org-element-property :APPENDIX headline)) - ;; Retrieve headline text - (text (org-texinfo--sanitize-headline - (org-element-property :title headline) info)) ;; Create node info, to insert it before section formatting. - ;; Use custom menu title if present + ;; Use custom menu title if present. (node (format "@node %s\n" (org-texinfo--get-node headline info))) - ;; Menus must be generated with first child, otherwise they - ;; will not nest properly - (menu (let* ((first (org-export-first-sibling-p headline info)) - (parent (org-export-get-parent-headline headline)) - (title (org-texinfo--sanitize-headline - (org-element-property :title parent) info)) - heading listing - (tree (plist-get info :parse-tree))) - (if first - (org-element-map (plist-get info :parse-tree) 'headline - (lambda (ref) - (if (member title (org-element-property :title ref)) - (push ref heading))) - info t)) - (setq listing (org-texinfo--build-menu - (car heading) level info)) - (if listing - (setq listing (replace-regexp-in-string - "%" "%%" listing) - listing (format - "\n@menu\n%s\n@end menu\n\n" listing)) - 'nil))) ;; Section formatting will set two placeholders: one for the ;; title and the other for the contents. (section-fmt - (let ((sec (if (and (symbolp (nth 2 class-sectioning)) - (fboundp (nth 2 class-sectioning))) - (funcall (nth 2 class-sectioning) level numberedp) - (nth (1+ level) class-sectioning)))) - (cond - ;; No section available for that LEVEL. - ((not sec) nil) - ;; Section format directly returned by a function. - ((stringp sec) sec) - ;; (numbered-section . unnumbered-section) - ((not (consp (cdr sec))) + (if (org-not-nil (org-element-property :APPENDIX headline)) + "@appendix %s\n%s" + (let ((sec (if (and (symbolp (nth 2 class-sectioning)) + (fboundp (nth 2 class-sectioning))) + (funcall (nth 2 class-sectioning) level numberedp) + (nth (1+ level) class-sectioning)))) (cond - ;;If an index, always unnumbered - (index - (concat menu node (cdr sec) "\n%s")) - (appendix - (concat menu node (replace-regexp-in-string - "unnumbered" - "appendix" - (cdr sec)) "\n%s")) - ;; Otherwise number as needed. - (t - (concat menu node - (funcall - (if numberedp #'car #'cdr) sec) "\n%s"))))))) + ;; No section available for that LEVEL. + ((not sec) nil) + ;; Section format directly returned by a function. + ((stringp sec) sec) + ;; (numbered-section . unnumbered-section) + ((not (consp (cdr sec))) + (concat (if (or index (not numberedp)) (cdr sec) (car sec)) + "\n%s")))))) (todo (and (plist-get info :with-todo-keywords) (let ((todo (org-element-property :todo-keyword headline))) @@ -1029,100 +788,54 @@ holding contextual information." (org-export-get-tags headline info))) (priority (and (plist-get info :with-priority) (org-element-property :priority headline))) - ;; Create the headline text along with a no-tag version. The - ;; latter is required to remove tags from table of contents. - (full-text (org-texinfo--sanitize-content - (if (not (eq org-texinfo-format-headline-function 'ignore)) - ;; User-defined formatting function. - (funcall org-texinfo-format-headline-function - todo todo-type priority text tags) - ;; Default formatting. - (concat - (when todo - (format "@strong{%s} " todo)) - (when priority (format "@emph{#%s} " priority)) - text - (when tags - (format " :%s:" - (mapconcat 'identity tags ":"))))))) - (full-text-no-tag - (org-texinfo--sanitize-content - (if (not (eq org-texinfo-format-headline-function 'ignore)) - ;; User-defined formatting function. - (funcall org-texinfo-format-headline-function - todo todo-type priority text nil) - ;; Default formatting. - (concat - (when todo (format "@strong{%s} " todo)) - (when priority (format "@emph{#%c} " priority)) - text)))) - (pre-blanks - (make-string (org-element-property :pre-blank headline) 10))) + (text (org-export-data (org-element-property :title headline) info)) + (full-text (if (not (eq org-texinfo-format-headline-function 'ignore)) + ;; User-defined formatting function. + (funcall org-texinfo-format-headline-function + todo todo-type priority text tags) + ;; Default formatting. + (concat + (when todo + (format "@strong{%s} " todo)) + (when priority (format "@emph{#%s} " priority)) + text + (when tags + (format " :%s:" + (mapconcat 'identity tags ":")))))) + (contents (if (org-string-nw-p contents) (concat "\n" contents) ""))) (cond ;; Case 1: This is a footnote section: ignore it. ((org-element-property :footnote-section-p headline) nil) ;; Case 2: This is the `copying' section: ignore it ;; This is used elsewhere. - ((org-element-property :COPYING headline) nil) + ((org-not-nil (org-element-property :COPYING headline)) nil) ;; Case 3: An index. If it matches one of the known indexes, ;; print it as such following the contents, otherwise ;; print the contents and leave the index up to the user. (index - (format - section-fmt full-text - (concat pre-blanks contents "\n" - (if (member index '("cp" "fn" "ky" "pg" "tp" "vr")) - (concat "@printindex " index))))) + (concat node + (format + section-fmt + full-text + (concat contents + (and (member index '("cp" "fn" "ky" "pg" "tp" "vr")) + (concat "\n@printindex " index)))))) ;; Case 4: This is a deep sub-tree: export it as a list item. ;; Also export as items headlines for which no section ;; format has been found. ((or (not section-fmt) (org-export-low-level-p headline info)) ;; Build the real contents of the sub-tree. - (let ((low-level-body - (concat - ;; If the headline is the first sibling, start a list. - (when (org-export-first-sibling-p headline info) - (format "@%s\n" (if numberedp 'enumerate 'itemize))) - ;; Itemize headline - "@item\n" full-text "\n" pre-blanks contents))) - ;; If headline is not the last sibling simply return - ;; LOW-LEVEL-BODY. Otherwise, also close the list, before any - ;; blank line. - (if (not (org-export-last-sibling-p headline info)) low-level-body - (replace-regexp-in-string - "[ \t\n]*\\'" - (format "\n@end %s" (if numberedp 'enumerate 'itemize)) - low-level-body)))) + (concat (and (org-export-first-sibling-p headline info) + (format "@%s\n" (if numberedp 'enumerate 'itemize))) + "@item\n" full-text "\n" + contents + (if (org-export-last-sibling-p headline info) + (format "@end %s" (if numberedp 'enumerate 'itemize)) + "\n"))) ;; Case 5: Standard headline. Export it as a section. - (t - (cond - ((not (and tags (eq (plist-get info :with-tags) 'not-in-toc))) - ;; Regular section. Use specified format string. - (format (replace-regexp-in-string "%]" "%%]" section-fmt) full-text - (concat pre-blanks contents))) - ((string-match "\\`@\\(.*?\\){" section-fmt) - ;; If tags should be removed from table of contents, insert - ;; title without tags as an alternative heading in sectioning - ;; command. - (format (replace-match (concat (match-string 1 section-fmt) "[%s]") - nil nil section-fmt 1) - ;; Replace square brackets with parenthesis since - ;; square brackets are not supported in optional - ;; arguments. - (replace-regexp-in-string - "\\[" "(" - (replace-regexp-in-string - "\\]" ")" - full-text-no-tag)) - full-text - (concat pre-blanks contents))) - (t - ;; Impossible to add an alternative heading. Fallback to - ;; regular sectioning format string. - (format (replace-regexp-in-string "%]" "%%]" section-fmt) full-text - (concat pre-blanks contents)))))))) - -;;; Inline Src Block + (t (concat node (format section-fmt full-text contents)))))) + +;;;; Inline Src Block (defun org-texinfo-inline-src-block (inline-src-block contents info) "Transcode an INLINE-SRC-BLOCK element from Org to Texinfo. @@ -1132,7 +845,7 @@ contextual information." (separator (org-texinfo--find-verb-separator code))) (concat "@verb{" separator code separator "}"))) -;;; Inlinetask +;;;; Inlinetask (defun org-texinfo-inlinetask (inlinetask contents info) "Transcode an INLINETASK element from Org to Texinfo. @@ -1165,7 +878,7 @@ holding contextual information." "\n") full-title contents))))) -;;; Italic +;;;; Italic (defun org-texinfo-italic (italic contents info) "Transcode ITALIC from Org to Texinfo. @@ -1173,18 +886,18 @@ CONTENTS is the text with italic markup. INFO is a plist holding contextual information." (org-texinfo--text-markup contents 'italic)) -;;; Item +;;;; Item (defun org-texinfo-item (item contents info) "Transcode an ITEM element from Org to Texinfo. CONTENTS holds the contents of the item. INFO is a plist holding contextual information." - (let* ((tag (org-element-property :tag item)) - (desc (org-export-data tag info))) - (concat "\n@item " (if tag desc) "\n" - (and contents (org-trim contents)) "\n"))) + (format "@item%s\n%s" + (let ((tag (org-element-property :tag item))) + (if tag (concat " " (org-export-data tag info)) "")) + (or contents ""))) -;;; Keyword +;;;; Keyword (defun org-texinfo-keyword (keyword contents info) "Transcode a KEYWORD element from Org to Texinfo. @@ -1200,14 +913,14 @@ CONTENTS is nil. INFO is a plist holding contextual information." ((string= key "TINDEX") (format "@tindex %s" value)) ((string= key "VINDEX") (format "@vindex %s" value))))) -;;; Line Break +;;;; Line Break (defun org-texinfo-line-break (line-break contents info) "Transcode a LINE-BREAK object from Org to Texinfo. CONTENTS is nil. INFO is a plist holding contextual information." "@*\n") -;;; Link +;;;; Link (defun org-texinfo-link (link desc info) "Transcode a LINK object from Org to Texinfo. @@ -1225,55 +938,69 @@ INFO is a plist holding contextual information. See ((and (string= type "file") (file-name-absolute-p raw-path)) (concat "file:" raw-path)) (t raw-path))) - (email (if (string= type "mailto") - (let ((text (replace-regexp-in-string - "@" "@@" raw-path))) - (concat text (if desc (concat "," desc)))))) protocol) (cond - ;; Links pointing to a headline: Find destination and build - ;; appropriate referencing command. - ((member type '("custom-id" "id")) - (let ((destination (org-export-resolve-id-link link info))) + ((equal type "radio") + (let ((destination (org-export-resolve-radio-link link info))) + (if (not destination) desc + (format "@ref{%s,,%s}" + (org-texinfo--get-node destination info) + desc)))) + ((member type '("custom-id" "id" "fuzzy")) + (let ((destination + (if (equal type "fuzzy") + (org-export-resolve-fuzzy-link link info) + (org-export-resolve-id-link link info)))) (case (org-element-type destination) + ((nil) + (format org-texinfo-link-with-unknown-path-format + (org-texinfo--sanitize-content path))) ;; Id link points to an external file. (plain-text (if desc (format "@uref{file://%s,%s}" destination desc) (format "@uref{file://%s}" destination))) - ;; LINK points to a headline. Use the headline as the NODE target (headline (format "@ref{%s,%s}" (org-texinfo--get-node destination info) - (or desc ""))) + (cond + (desc) + ((org-export-numbered-headline-p destination info) + (org-export-data + (org-element-property :title destination) info)) + (t + (mapconcat + #'number-to-string + (org-export-get-headline-number destination info) "."))))) (otherwise - (let ((path (org-export-solidify-link-text path))) - (if (not desc) (format "@ref{%s}" path) - (format "@ref{%s,,%s}" path desc))))))) - ((member type '("info")) + (let ((topic + (or desc + (if (and (eq (org-element-type destination) 'headline) + (not (org-export-numbered-headline-p + destination info))) + (org-export-data + (org-element-property :title destination) info)) + (let ((n (org-export-get-ordinal destination info))) + (cond + ((not n) nil) + ((integerp n) n) + (t (mapconcat #'number-to-string n "."))))))) + (when topic + (format "@ref{%s,,%s}" + (org-texinfo--get-node destination info) + topic))))))) + ((equal type "info") (let* ((info-path (split-string path "[:#]")) (info-manual (car info-path)) (info-node (or (cadr info-path) "top")) (title (or desc ""))) (format "@ref{%s,%s,,%s,}" info-node title info-manual))) - ((member type '("fuzzy")) - (let ((destination (org-export-resolve-fuzzy-link link info))) - (case (org-element-type destination) - ;; Id link points to an external file. - (plain-text - (if desc (format "@uref{file://%s,%s}" destination desc) - (format "@uref{file://%s}" destination))) - ;; LINK points to a headline. Use the headline as the NODE target - (headline - (format "@ref{%s,%s}" - (org-texinfo--get-node destination info) - (or desc ""))) - (otherwise - (let ((path (org-export-solidify-link-text path))) - (if (not desc) (format "@ref{%s}" path) - (format "@ref{%s,,%s}" path desc))))))) - ;; Special case for email addresses - (email - (format "@email{%s}" email)) + ((string= type "mailto") + (format "@email{%s}" + (concat (org-texinfo--sanitize-content path) + (and desc (concat "," desc))))) + ((let ((protocol (nth 2 (assoc type org-link-protocols)))) + (and (functionp protocol) + (funcall protocol (org-link-unescape path) desc 'texinfo)))) ;; External link with a description part. ((and path desc) (format "@uref{%s,%s}" path desc)) ;; External link without a description part. @@ -1282,27 +1009,97 @@ INFO is a plist holding contextual information. See (t (format org-texinfo-link-with-unknown-path-format desc))))) -;;; Menu - -(defun org-texinfo-make-menu (info level) - "Create the menu for inclusion in the texifo document. - -INFO is the parsed buffer that contains the headlines. LEVEL -determines whether to make the main menu, or the detailed menu. - -This is only used for generating the primary menu. In-Node menus -are generated directly." - (let ((parse (plist-get info :parse-tree))) - (cond - ;; Generate the main menu - ((eq level 'main) (org-texinfo--build-menu parse 1 info)) - ;; Generate the detailed (recursive) menu - ((eq level 'detailed) - ;; Requires recursion - ;;(org-texinfo--build-detailed-menu parse top info) - (org-texinfo--build-menu parse 1 info 'detailed))))) - -;;; Paragraph +;;;; Menu + +(defun org-texinfo-make-menu (scope info &optional master) + "Create the menu for inclusion in the Texinfo document. + +SCOPE is a headline or a full parse tree. INFO is the +communication channel, as a plist. + +When optional argument MASTER is non-nil, generate a master menu, +including detailed node listing." + (let ((menu (org-texinfo--build-menu scope info))) + (when (org-string-nw-p menu) + (org-element-normalize-string + (format + "@menu\n%s@end menu" + (concat menu + (when master + (let ((detailmenu + (org-texinfo--build-menu + scope info + (let ((toc-depth (plist-get info :with-toc))) + (if (wholenump toc-depth) toc-depth + org-texinfo-max-toc-depth))))) + (when (org-string-nw-p detailmenu) + (concat "\n@detailmenu\n" + "--- The Detailed Node Listing ---\n\n" + detailmenu + "@end detailmenu\n")))))))))) + +(defun org-texinfo--build-menu (scope info &optional level) + "Build menu for entries within SCOPE. +SCOPE is a headline or a full parse tree. INFO is a plist +containing contextual information. When optional argument LEVEL +is an integer, build the menu recursively, down to this depth." + (cond + ((not level) + (org-texinfo--format-entries (org-texinfo--menu-entries scope info) info)) + ((zerop level) nil) + (t + (org-element-normalize-string + (mapconcat + (lambda (h) + (let ((entries (org-texinfo--menu-entries h info))) + (when entries + (concat + (format "%s\n\n%s\n" + (org-export-data (org-export-get-alt-title h info) info) + (org-texinfo--format-entries entries info)) + (org-texinfo--build-menu h info (1- level)))))) + (org-texinfo--menu-entries scope info) ""))))) + +(defun org-texinfo--format-entries (entries info) + "Format all direct menu entries in SCOPE, as a string. +SCOPE is either a headline or a full Org document. INFO is +a plist containing contextual information." + (org-element-normalize-string + (mapconcat + (lambda (h) + (let* ((title (org-export-data + (org-export-get-alt-title h info) info)) + (node (org-texinfo--get-node h info)) + (entry (concat "* " title ":" + (if (string= title node) ":" + (concat " " node ". ")))) + (desc (org-element-property :DESCRIPTION h))) + (if (not desc) entry + (format (format "%%-%ds %%s" org-texinfo-node-description-column) + entry desc)))) + entries "\n"))) + +(defun org-texinfo--menu-entries (scope info) + "List direct children in SCOPE needing a menu entry. +SCOPE is a headline or a full parse tree. INFO is a plist +holding contextual information." + (let* ((cache (or (plist-get info :texinfo-entries-cache) + (plist-get (plist-put info :texinfo-entries-cache + (make-hash-table :test #'eq)) + :texinfo-entries-cache))) + (cached-entries (gethash scope cache 'no-cache))) + (if (not (eq cached-entries 'no-cache)) cached-entries + (puthash scope + (org-element-map (org-element-contents scope) 'headline + (lambda (h) + (and (not (org-not-nil (org-element-property :COPYING h))) + (not (org-element-property :footnote-section-p h)) + (not (org-export-low-level-p h info)) + h)) + info nil 'headline) + cache)))) + +;;;; Paragraph (defun org-texinfo-paragraph (paragraph contents info) "Transcode a PARAGRAPH element from Org to Texinfo. @@ -1310,32 +1107,27 @@ CONTENTS is the contents of the paragraph, as a string. INFO is the plist used as a communication channel." contents) -;;; Plain List +;;;; Plain List (defun org-texinfo-plain-list (plain-list contents info) "Transcode a PLAIN-LIST element from Org to Texinfo. CONTENTS is the contents of the list. INFO is a plist holding contextual information." (let* ((attr (org-export-read-attribute :attr_texinfo plain-list)) - (indic (or (plist-get attr :indic) - org-texinfo-def-table-markup)) - (type (org-element-property :type plain-list)) + (indic (or (plist-get attr :indic) org-texinfo-def-table-markup)) (table-type (plist-get attr :table-type)) - ;; Ensure valid texinfo table type. - (table-type (if (member table-type '("ftable" "vtable")) table-type - "table")) + (type (org-element-property :type plain-list)) (list-type (cond ((eq type 'ordered) "enumerate") ((eq type 'unordered) "itemize") - ((eq type 'descriptive) table-type)))) - (format "@%s%s\n@end %s" - (if (eq type 'descriptive) - (concat list-type " " indic) - list-type) + ((member table-type '("ftable" "vtable")) table-type) + (t "table")))) + (format "@%s\n%s@end %s" + (if (eq type 'descriptive) (concat list-type " " indic) list-type) contents list-type))) -;;; Plain Text +;;;; Plain Text (defun org-texinfo-plain-text (text info) "Transcode a TEXT string from Org to Texinfo. @@ -1366,7 +1158,7 @@ contextual information." ;; Return value. output)) -;;; Planning +;;;; Planning (defun org-texinfo-planning (planning contents info) "Transcode a PLANNING element from Org to Texinfo. @@ -1402,7 +1194,7 @@ information." " ") "@*")) -;;; Property Drawer +;;;; Property Drawer (defun org-texinfo-property-drawer (property-drawer contents info) "Transcode a PROPERTY-DRAWER element from Org to Texinfo. @@ -1412,7 +1204,7 @@ information." ;; lines nonetheless. "") -;;; Quote Block +;;;; Quote Block (defun org-texinfo-quote-block (quote-block contents info) "Transcode a QUOTE-BLOCK element from Org to Texinfo. @@ -1424,7 +1216,7 @@ holding contextual information." (format " %s" title))))) (format "%s\n%s@end quotation" start-quote contents))) -;;; Quote Section +;;;; Quote Section (defun org-texinfo-quote-section (quote-section contents info) "Transcode a QUOTE-SECTION element from Org to Texinfo. @@ -1433,7 +1225,7 @@ CONTENTS is nil. INFO is a plist holding contextual information." (org-element-property :value quote-section)))) (when value (format "@verbatim\n%s@end verbatim" value)))) -;;; Radio Target +;;;; Radio Target (defun org-texinfo-radio-target (radio-target text info) "Transcode a RADIO-TARGET object from Org to Texinfo. @@ -1444,15 +1236,17 @@ contextual information." (org-element-property :value radio-target)) text)) -;;; Section +;;;; Section (defun org-texinfo-section (section contents info) "Transcode a SECTION element from Org to Texinfo. CONTENTS holds the contents of the section. INFO is a plist holding contextual information." - contents) + (concat contents + (let ((parent (org-export-get-parent-headline section))) + (and parent (org-texinfo-make-menu parent info))))) -;;; Special Block +;;;; Special Block (defun org-texinfo-special-block (special-block contents info) "Transcode a SPECIAL-BLOCK element from Org to Texinfo. @@ -1460,34 +1254,26 @@ CONTENTS holds the contents of the block. INFO is a plist used as a communication channel." contents) -;;; Src Block +;;;; Src Block (defun org-texinfo-src-block (src-block contents info) "Transcode a SRC-BLOCK element from Org to Texinfo. CONTENTS holds the contents of the item. INFO is a plist holding contextual information." - (let* ((lang (org-element-property :language src-block)) - (lisp-p (string-match-p "lisp" lang)) - (src-contents (org-texinfo--sanitize-content - (org-export-format-code-default src-block info)))) - (cond - ;; Case 1. Lisp Block - (lisp-p - (format "@lisp\n%s@end lisp" - src-contents)) - ;; Case 2. Other blocks - (t - (format "@example\n%s@end example" - src-contents))))) + (let ((lispp (org-string-match-p "lisp" + (org-element-property :language src-block))) + (code (org-texinfo--sanitize-content + (org-export-format-code-default src-block info)))) + (format (if lispp "@lisp\n%s@end lisp" "@example\n%s@end example") code))) -;;; Statistics Cookie +;;;; Statistics Cookie (defun org-texinfo-statistics-cookie (statistics-cookie contents info) "Transcode a STATISTICS-COOKIE object from Org to Texinfo. CONTENTS is nil. INFO is a plist holding contextual information." (org-element-property :value statistics-cookie)) -;;; Subscript +;;;; Subscript (defun org-texinfo-subscript (subscript contents info) "Transcode a SUBSCRIPT object from Org to Texinfo. @@ -1495,7 +1281,7 @@ CONTENTS is the contents of the object. INFO is a plist holding contextual information." (format "@math{_%s}" contents)) -;;; Superscript +;;;; Superscript (defun org-texinfo-superscript (superscript contents info) "Transcode a SUPERSCRIPT object from Org to Texinfo. @@ -1503,96 +1289,47 @@ CONTENTS is the contents of the object. INFO is a plist holding contextual information." (format "@math{^%s}" contents)) -;;; Table -;; -;; `org-texinfo-table' is the entry point for table transcoding. It -;; takes care of tables with a "verbatim" attribute. Otherwise, it -;; delegates the job to either `org-texinfo-table--table.el-table' or -;; `org-texinfo-table--org-table' functions, depending of the type of -;; the table. -;; -;; `org-texinfo-table--align-string' is a subroutine used to build -;; alignment string for Org tables. +;;;; Table (defun org-texinfo-table (table contents info) "Transcode a TABLE element from Org to Texinfo. CONTENTS is the contents of the table. INFO is a plist holding contextual information." - (cond - ;; Case 1: verbatim table. - ((or org-texinfo-tables-verbatim - (let ((attr (mapconcat 'identity - (org-element-property :attr_latex table) - " "))) - (and attr (string-match "\\" attr)))) - (format "@verbatim \n%s\n@end verbatim" - ;; Re-create table, without affiliated keywords. - (org-trim - (org-element-interpret-data - `(table nil ,@(org-element-contents table)))))) - ;; Case 2: table.el table. Convert it using appropriate tools. - ((eq (org-element-property :type table) 'table.el) - (org-texinfo-table--table.el-table table contents info)) - ;; Case 3: Standard table. - (t (org-texinfo-table--org-table table contents info)))) + (if (eq (org-element-property :type table) 'table.el) + (format "@verbatim\n%s@end verbatim" + (org-element-normalize-string + (org-element-property :value table))) + (let* ((col-width (org-export-read-attribute :attr_texinfo table :columns)) + (columns + (if col-width (format "@columnfractions %s" col-width) + (org-texinfo-table-column-widths table info)))) + (format "@multitable %s\n%s@end multitable" + columns + contents)))) (defun org-texinfo-table-column-widths (table info) "Determine the largest table cell in each column to process alignment. - TABLE is the table element to transcode. INFO is a plist used as a communication channel." - (let* ((rows (org-element-map table 'table-row 'identity info)) - (collected (loop for row in rows collect - (org-element-map row 'table-cell 'identity info))) - (number-cells (length (car collected))) - cells counts) - (loop for row in collected do - (push (mapcar (lambda (ref) - (let* ((start (org-element-property :contents-begin ref)) - (end (org-element-property :contents-end ref)) - (length (- end start))) - length)) row) cells)) - (setq cells (org-remove-if 'null cells)) - (push (loop for count from 0 to (- number-cells 1) collect - (loop for item in cells collect - (nth count item))) counts) - (mapconcat (lambda (size) - (make-string size ?a)) (mapcar (lambda (ref) - (apply 'max `(,@ref))) (car counts)) - "} {"))) - -(defun org-texinfo-table--org-table (table contents info) - "Return appropriate Texinfo code for an Org table. - -TABLE is the table type element to transcode. CONTENTS is its -contents, as a string. INFO is a plist used as a communication -channel. - -This function assumes TABLE has `org' as its `:type' attribute." - (let* ((attr (org-export-read-attribute :attr_texinfo table)) - (col-width (plist-get attr :columns)) - (columns (if col-width - (format "@columnfractions %s" - col-width) - (format "{%s}" - (org-texinfo-table-column-widths - table info))))) - ;; Prepare the final format string for the table. - (cond - ;; Longtable. - ;; Others. - (t (concat - (format "@multitable %s\n%s@end multitable" - columns - contents)))))) - -(defun org-texinfo-table--table.el-table (table contents info) - "Returns nothing. - -Rather than return an invalid table, nothing is returned." - 'nil) - -;;; Table Cell + (let ((widths (make-vector (cdr (org-export-table-dimensions table info)) 0))) + (org-element-map table 'table-row + (lambda (row) + (let ((idx 0)) + (org-element-map row 'table-cell + (lambda (cell) + ;; Length of the cell in the original buffer is only an + ;; approximation of the length of the cell in the + ;; output. It can sometimes fail (e.g. it considers + ;; "/a/" being larger than "ab"). + (let ((w (- (org-element-property :contents-end cell) + (org-element-property :contents-begin cell)))) + (aset widths idx (max w (aref widths idx)))) + (incf idx)) + info))) + info) + (format "{%s}" (mapconcat (lambda (w) (make-string w ?a)) widths "} {")))) + +;;;; Table Cell (defun org-texinfo-table-cell (table-cell contents info) "Transcode a TABLE-CELL element from Org to Texinfo. @@ -1609,7 +1346,7 @@ a communication channel." contents) (when (org-export-get-next-element table-cell info) "\n@tab "))) -;;; Table Row +;;;; Table Row (defun org-texinfo-table-row (table-row contents info) "Transcode a TABLE-ROW element from Org to Texinfo. @@ -1618,21 +1355,15 @@ a communication channel." ;; Rules are ignored since table separators are deduced from ;; borders of the current row. (when (eq (org-element-property :type table-row) 'standard) - (let ((rowgroup-tag - (cond - ;; Case 1: Belongs to second or subsequent rowgroup. - ((not (= 1 (org-export-table-row-group table-row info))) - "@item ") - ;; Case 2: Row is from first rowgroup. Table has >=1 rowgroups. - ((org-export-table-has-header-p - (org-export-get-parent-table table-row) info) - "@headitem ") - ;; Case 3: Row is from first and only row group. - (t "@item ")))) - (when (eq (org-element-property :type table-row) 'standard) - (concat rowgroup-tag contents "\n"))))) - -;;; Target + (let ((rowgroup-tag + (if (and (= 1 (org-export-table-row-group table-row info)) + (org-export-table-has-header-p + (org-export-get-parent-table table-row) info)) + "@headitem " + "@item "))) + (concat rowgroup-tag contents "\n")))) + +;;;; Target (defun org-texinfo-target (target contents info) "Transcode a TARGET object from Org to Texinfo. @@ -1641,7 +1372,7 @@ information." (format "@anchor{%s}" (org-export-solidify-link-text (org-element-property :value target)))) -;;; Timestamp +;;;; Timestamp (defun org-texinfo-timestamp (timestamp contents info) "Transcode a TIMESTAMP object from Org to Texinfo. @@ -1656,7 +1387,7 @@ information." (format org-texinfo-inactive-timestamp-format value)) (t (format org-texinfo-diary-timestamp-format value))))) -;;; Verbatim +;;;; Verbatim (defun org-texinfo-verbatim (verbatim contents info) "Transcode a VERBATIM object from Org to Texinfo. @@ -1664,26 +1395,13 @@ CONTENTS is nil. INFO is a plist used as a communication channel." (org-texinfo--text-markup (org-element-property :value verbatim) 'verbatim)) -;;; Verse Block +;;;; Verse Block (defun org-texinfo-verse-block (verse-block contents info) "Transcode a VERSE-BLOCK element from Org to Texinfo. CONTENTS is verse block contents. INFO is a plist holding contextual information." - ;; In a verse environment, add a line break to each newline - ;; character and change each white space at beginning of a line - ;; into a space of 1 em. Also change each blank line with - ;; a vertical space of 1 em. - (progn - (setq contents (replace-regexp-in-string - "^ *\\\\\\\\$" "\\\\vspace*{1em}" - (replace-regexp-in-string - "\\(\\\\\\\\\\)?[ \t]*\n" " \\\\\\\\\n" contents))) - (while (string-match "^[ \t]+" contents) - (let ((new-str (format "\\hspace*{%dem}" - (length (match-string 0 contents))))) - (setq contents (replace-match new-str nil t contents)))) - (format "\\begin{verse}\n%s\\end{verse}" contents))) + (format "@display\n%s@end display" contents)) ;;; Interactive functions @@ -1797,29 +1515,21 @@ Return INFO file name or an error if it couldn't be produced." errors) (message (format "Processing Texinfo file %s..." file)) (save-window-excursion - (cond - ;; A function is provided: Apply it. - ((functionp org-texinfo-info-process) - (funcall org-texinfo-info-process (shell-quote-argument file))) - ;; A list is provided: Replace %b, %f and %o with appropriate - ;; values in each command before applying it. Output is - ;; redirected to "*Org INFO Texinfo Output*" buffer. - ((consp org-texinfo-info-process) - (let ((outbuf (get-buffer-create "*Org INFO Texinfo Output*"))) - (mapc - (lambda (command) - (shell-command - (replace-regexp-in-string - "%b" (shell-quote-argument base-name) - (replace-regexp-in-string - "%f" (shell-quote-argument full-name) - (replace-regexp-in-string - "%o" (shell-quote-argument out-dir) command t t) t t) t t) - outbuf)) - org-texinfo-info-process) - ;; Collect standard errors from output buffer. - (setq errors (org-texinfo-collect-errors outbuf)))) - (t (error "No valid command to process to Info"))) + ;; Replace %b, %f and %o with appropriate values in each command + ;; before applying it. Output is redirected to "*Org INFO + ;; Texinfo Output*" buffer. + (let ((outbuf (get-buffer-create "*Org INFO Texinfo Output*"))) + (dolist (command org-texinfo-info-process) + (shell-command + (replace-regexp-in-string + "%b" (shell-quote-argument base-name) + (replace-regexp-in-string + "%f" (shell-quote-argument full-name) + (replace-regexp-in-string + "%o" (shell-quote-argument out-dir) command t t) t t) t t) + outbuf)) + ;; Collect standard errors from output buffer. + (setq errors (org-texinfo-collect-errors outbuf))) (let ((infofile (concat out-dir base-name ".info"))) ;; Check for process failure. Provide collected errors if ;; possible. diff --git a/lisp/ox.el b/lisp/ox.el index 6d07a2e..1327ae4 100644 --- a/lisp/ox.el +++ b/lisp/ox.el @@ -814,7 +814,7 @@ This variable can be either set to `buffer' or `subtree'." (defcustom org-export-show-temporary-export-buffer t "Non-nil means show buffer after exporting to temp buffer. -When Org exports to a file, the buffer visiting that file is ever +When Org exports to a file, the buffer visiting that file is never shown, but remains buried. However, when exporting to a temporary buffer, that buffer is popped up in a second window. When this variable is nil, the buffer remains buried also in @@ -1333,6 +1333,10 @@ The back-end could then be called with, for example: ;; - category :: option ;; - type :: string ;; +;; + `:output-file' :: Full path to output file, if any. +;; - category :: option +;; - type :: string or nil +;; ;; + `:parse-tree' :: Whole parse tree, available at any time during ;; transcoding. ;; - category :: option @@ -4134,29 +4138,8 @@ objects of the same type." ((funcall predicate el info) (incf counter) nil))) info 'first-match))))) -;;;; For Special Blocks -;; -;; `org-export-raw-special-block-p' check if current special block is -;; an "export block", i.e., a block whose contents should be inserted -;; as-is in the output. This should generally be the first check to -;; do when handling special blocks in the export back-end. - -(defun org-export-raw-special-block-p (element info &optional no-inheritance) - "Non-nil if ELEMENT is an export block relatively to current back-end. -An export block is a special block whose contents should be -included as-is in the final output. Such blocks are defined -through :export-block property in `org-export-define-backend', -which see." - (and (eq (org-element-type element) 'special-block) - (let ((type (org-element-property :type element)) - (b (plist-get info :back-end))) - (if no-inheritance (member type (org-export-backend-blocks b)) - (while (and b (not (member type (org-export-backend-blocks b)))) - (setq b (org-export-get-backend (org-export-backend-parent b)))) - b)))) - -;;;; For Src Blocks +;;;; For Src-Blocks ;; ;; `org-export-get-loc' counts number of code lines accumulated in ;; src-block or example-block elements with a "+n" switch until @@ -5496,8 +5479,9 @@ to `:default' encoding. If it fails, return S." (defmacro org-export-async-start (fun &rest body) "Call function FUN on the results returned by BODY evaluation. -BODY evaluation happens in an asynchronous process, from a buffer -which is an exact copy of the current one. +FUN is an anonymous function of one argument. BODY evaluation +happens in an asynchronous process, from a buffer which is an +exact copy of the current one. Use `org-export-add-to-stack' in FUN in order to register results in the stack. @@ -5674,7 +5658,8 @@ The function returns either a file name returned by POST-PROCESS, or FILE." (declare (indent 2)) (if (not (file-writable-p file)) (error "Output file not writable") - (let ((encoding (or org-export-coding-system buffer-file-coding-system))) + (let ((ext-plist (org-combine-plists `(:output-file ,file) ext-plist)) + (encoding (or org-export-coding-system buffer-file-coding-system))) (if async (org-export-async-start `(lambda (file) diff --git a/mk/org-fixup.el b/mk/org-fixup.el index aa7ff09..e57eb65 100644 --- a/mk/org-fixup.el +++ b/mk/org-fixup.el @@ -58,8 +58,8 @@ the Git work tree)." \f\n;; Local Variables:\n;; version-control: never ;; no-byte-compile: t ;; coding: utf-8\n;; End:\n;;; org-version.el ends here\n") - (toggle-read-only 0) - (write-file "org-version.el"))) + (let ((inhibit-read-only t)) + (write-file "org-version.el")))) (defun org-make-org-loaddefs () "Make the file org-loaddefs.el in the current directory. @@ -77,8 +77,8 @@ work correctly if this file is not up-to-date." (insert "\f\n;; Local Variables:\n;; version-control: never\n") (insert ";; no-byte-compile: t\n;; no-update-autoloads: t\n") (insert ";; coding: utf-8\n;; End:\n;;; org-loaddefs.el ends here\n") - (toggle-read-only 0) - (save-buffer))) + (let ((inhibit-read-only t)) + (save-buffer)))) (defun org-make-autoloads (&optional compile force) "Make the files org-loaddefs.el and org-version.el in the install directory. @@ -140,8 +140,8 @@ oldorg: # do what the old Makefile did by default. (insert "\ # See default.mk for further configuration options. ") - (toggle-read-only 0) - (write-file local)) + (let ((inhibit-read-only t)) + (write-file local))) nil))) (defun org-make-letterformat (a4name lettername) @@ -152,8 +152,8 @@ oldorg: # do what the old Makefile did by default. (goto-char (point-min)) (while (search-forward "\\pdflayout=(0l)" nil t) (replace-match "\\pdflayout=(1l)" nil t)) - (toggle-read-only 0) - (write-file lettername)) + (let ((inhibit-read-only t)) + (write-file lettername))) nil)) ;; redefine version functions diff --git a/mk/version.mk b/mk/version.mk index bb6d0fe..d33d8e4 100644 --- a/mk/version.mk +++ b/mk/version.mk @@ -1,2 +1,2 @@ -ORGVERSION ?= 8.2.7c -GITVERSION ?= 8.2.7c-dist +ORGVERSION ?= 8.2.10 +GITVERSION ?= 8.2.10-dist -- cgit v1.2.3