Usability improvements to org-lparse-convert and co (First cut)

* contrib/lisp/org-lparse.el (org-lparse-and-open)
(org-lparse-register-backend, org-lparse-format-table)
(org-lparse-begin, org-lparse-end): Checkdoc related fixes.
(org-lparse-get-converter): Added
(org-lparse-get-other-backends, org-lparse-all-backends):
Re-implemented. Also improved docstring.
(org-lparse): Make use of improvements in the converter
routines. Improve the following: a) gathering of
target-backend and native-backend args during interactive
calls b) error handling.
(org-lparse-convert): Introduced prefix arg for opening of
converted files. Make use of improvements in the converter
routines. Improve error handling.
(org-lparse-convert-processes): New customizable variable.
(org-lparse-convert-process): Make it customizable. Set
default value to nil.
(org-lparse-convert-capabilities): New customizable variable.
(org-lparse-use-flashy-warning): Fix group and improve docstring.

* contrib/lisp/org-odt.el (org-odt-get): Don't set
CONVERT-METHOD and OTHER-BACKENDS options. Fallback to the
global converter settings for now.
(org-export-odt-preferred-output-format): New variable
(org-export-as-odt-and-open, org-export-as-odt): Use the
afore-mentioned variable.

* contrib/lisp/org-xhtml.el (org-xhtml-get): Don't set
CONVERT-METHOD and OTHER-BACKENDS options. Fallback to the
global converter settings for now.
This commit is contained in:
Jambunathan K 2011-08-05 02:01:19 +05:30
parent 049c0776ff
commit 44472fa6cf
3 changed files with 236 additions and 76 deletions

View File

@ -57,7 +57,7 @@
;;;###autoload ;;;###autoload
(defun org-lparse-and-open (target-backend native-backend arg) (defun org-lparse-and-open (target-backend native-backend arg)
"Export the outline to TARGET-BACKEND via NATIVE-BACKEND and open exported file. "Export outline to TARGET-BACKEND via NATIVE-BACKEND and open exported file.
If there is an active region, export only the region. The prefix If there is an active region, export only the region. The prefix
ARG specifies how many levels of the outline should become ARG specifies how many levels of the outline should become
headlines. The default is 3. Lower levels will become bulleted headlines. The default is 3. Lower levels will become bulleted
@ -357,7 +357,7 @@ For the sake of illustration, the html backend implements
ENTITY-CONTROL and ENTITY-FORMAT settings.") ENTITY-CONTROL and ENTITY-FORMAT settings.")
(defun org-lparse-register-backend (backend) (defun org-lparse-register-backend (backend)
"Make BACKEND known to org-lparse library. "Make BACKEND known to `org-lparse' library.
Add BACKEND to `org-lparse-native-backends'." Add BACKEND to `org-lparse-native-backends'."
(when backend (when backend
(setq backend (cond (setq backend (cond
@ -374,17 +374,41 @@ Add BACKEND to `org-lparse-native-backends'."
org-lparse-native-backends)) org-lparse-native-backends))
(message "Unregistered backend %S" backend)) (message "Unregistered backend %S" backend))
(defun org-lparse-get-other-backends (native-backend) (defun org-lparse-get-other-backends (in-fmt)
(org-lparse-backend-get native-backend 'OTHER-BACKENDS)) "Return OUTPUT-FMT-ALIST corresponding to IN-FMT.
See `org-lparse-convert-capabilities' for definition of
OUTPUT-FMT-ALIST."
(when (org-lparse-get-converter in-fmt)
(or (ignore-errors (org-lparse-backend-get in-fmt 'OTHER-BACKENDS) )
(catch 'out-fmts
(dolist (c org-lparse-convert-capabilities)
(when (member in-fmt (nth 1 c))
(throw 'out-fmts (nth 2 c))))))))
(defun org-lparse-get-converter (in-fmt)
"Return converter associated with IN-FMT.
See `org-lparse-convert-capabilities' for further information."
(or (ignore-errors (org-lparse-backend-get in-fmt 'CONVERT-METHOD))
org-lparse-convert-process))
(defun org-lparse-all-backends () (defun org-lparse-all-backends ()
"Return all formats to which `org-lparse' could export to.
The return value is an alist of the form (TARGET-BACKEND
NATIVE-BACKEND-1 NATIVE-BACKEND-2 ...) with the condition that
the org file can be exported to TARGET-BACKEND via any one of
NATIVE-BACKEND-1, NATIVE-BACKEND-2 etc.
For example, an entry of the form \"(\"pdf\" \"odt\" \"xhtml\")\"
would mean that the org file could be exported to \"pdf\" format
by exporting natively either to \"xhtml\" or \"odt\" backends."
(let (all-backends) (let (all-backends)
(flet ((add (other native) (flet ((add (other native)
(let ((val (assoc-string other all-backends t))) (let ((val (assoc-string other all-backends t)))
(if val (setcdr val (nconc (list native) (cdr val))) (if val (setcdr val (nconc (list native) (cdr val)))
(push (cons other (list native)) all-backends))))) (push (cons other (list native)) all-backends)))))
(loop for backend in org-lparse-native-backends (loop for backend in org-lparse-native-backends
do (loop for other in (org-lparse-get-other-backends backend) do (loop for other in
(mapcar #'car (org-lparse-get-other-backends backend))
do (add other backend)))) do (add other backend))))
all-backends)) all-backends))
@ -428,97 +452,203 @@ PUB-DIR specifies the publishing directory."
(let* ((input (if (featurep 'ido) 'ido-completing-read 'completing-read)) (let* ((input (if (featurep 'ido) 'ido-completing-read 'completing-read))
(all-backends (org-lparse-all-backends)) (all-backends (org-lparse-all-backends))
(target-backend (target-backend
(funcall input "Export to: " all-backends nil t nil)) (and all-backends
(funcall input "Export to: " all-backends nil t nil)))
(native-backend (native-backend
(or (let ((choices (if target-backend
;; (and (org-lparse-backend-is-native-p target-backend) (cdr (assoc target-backend all-backends))
;; target-backend) (or org-lparse-native-backends
(funcall input "Use Native backend: " (error "No registered backends")))))
(cdr (assoc target-backend all-backends)) nil t nil)))) (funcall input "Use Native backend: " choices nil t nil))))
(list target-backend native-backend current-prefix-arg))) (list target-backend native-backend current-prefix-arg)))
(let* ((org-lparse-backend (intern native-backend)) (let* ((org-lparse-backend (intern native-backend))
(org-lparse-other-backend (intern target-backend))) (org-lparse-other-backend (and target-backend
(intern target-backend))))
(unless (org-lparse-backend-is-native-p native-backend) (unless (org-lparse-backend-is-native-p native-backend)
(error "Don't know how to export natively to backend %s" native-backend)) (error "Don't know how to export natively to backend %s" native-backend))
(unless (or (not target-backend) (unless (or (not target-backend)
(equal target-backend native-backend) (equal target-backend native-backend)
(member target-backend (org-lparse-get 'OTHER-BACKENDS))) (assoc target-backend (org-lparse-get-other-backends
native-backend)))
(error "Don't know how to export to backend %s %s" target-backend (error "Don't know how to export to backend %s %s" target-backend
(format "via %s" native-backend))) (format "via %s" native-backend)))
(run-hooks 'org-export-first-hook) (run-hooks 'org-export-first-hook)
(org-do-lparse arg hidden ext-plist to-buffer body-only pub-dir))) (org-do-lparse arg hidden ext-plist to-buffer body-only pub-dir)))
(defcustom org-lparse-convert-process (defcustom org-lparse-convert-processes
'("soffice" "-norestore" "-invisible" "-headless" "\"macro:///BasicODConverter.Main.Convert(%I,%f,%O)\"") '(("BasicODConverter"
"Command to covert a Org exported format to other formats. ("soffice" "-norestore" "-invisible" "-headless"
The variable is an list of the form (PROCESS ARG1 ARG2 ARG3 "\"macro:///BasicODConverter.Main.Convert(%I,%f,%O)\""))
...). Format specifiers used in the ARGs are replaced as below. ("unoconv"
("unoconv" "-f" "%f" "-o" "%d" "%i")))
"Specify a list of document converters and their usage.
The converters in this list are offered as choices while
customizing `org-lparse-convert-process'.
This variable is an alist where each element is of the
form (CONVERTER-NAME (CONVERTER-PROGRAM ARG1 ARG2 ...)).
CONVERTER-NAME is name of the converter. CONVERTER-PROGRAM is
the name of the executable. ARG1, ARG2 etc are command line
options that are passed to CONVERTER-PROGRAM. Format specifiers
can be used in the ARGs and they are interpreted as below:
%i input file name in full %i input file name in full
%I input file name as a URL %I input file name as a URL
%f format of the output file %f format of the output file
%o output file name in full %o output file name in full
%O output file name as a URL %O output file name as a URL
%d output dir in full %d output dir in full
%D output dir as a URL" %D output dir as a URL."
:group 'org-lparse) :group 'org-lparse
:type
'(choice
(const :tag "None" nil)
(alist :tag "Converters"
:key-type (string :tag "Converter Name")
:value-type (group (cons (string :tag "Executable")
(repeat (string :tag "Command line args")))))))
(defcustom org-lparse-convert-process nil
"Command to convert from an Org exported format to other formats.
During customization, the list of choices are populated from
`org-lparse-convert-processes'. Refer afore-mentioned variable
for further information."
:group 'org-lparse
:type '(choice :convert-widget
(lambda (w)
(apply 'widget-convert (widget-type w)
(eval (car (widget-get w :args)))))
`((const :tag "None" nil)
,@(mapcar (lambda (c)
`(const :tag ,(car c) ,(cadr c)))
org-lparse-convert-processes))))
(defcustom org-lparse-convert-capabilities
'(("Text"
("odt" "ott" "doc" "rtf")
(("pdf" "pdf") ("odt" "odt") ("xhtml" "html") ("rtf" "rtf")
("ott" "ott") ("doc" "doc") ("ooxml" "xml") ("html" "html")))
("Web"
("html" "xhtml") (("pdf" "pdf") ("odt" "txt") ("html" "html")))
("Spreadsheet"
("ods" "ots" "xls" "csv")
(("pdf" "pdf") ("ots" "ots") ("html" "html") ("csv" "csv")
("ods" "ods") ("xls" "xls") ("xhtml" "xhtml") ("ooxml" "xml")))
("Presentation"
("odp" "otp" "ppt")
(("pdf" "pdf") ("swf" "swf") ("odp" "odp") ("xhtml" "xml")
("otp" "otp") ("ppt" "ppt") ("odg" "odg") ("html" "html"))))
"Specify input and output formats of `org-lparse-convert-process'.
More correctly, specify the set of input and output formats that
the user is actually interested in.
This variable is an alist where each element is of the
form (DOCUMENT-CLASS INPUT-FMT-LIST OUTPUT-FMT-ALIST).
INPUT-FMT-LIST is a list of INPUT-FMTs. OUTPUT-FMT-ALIST is an
alist where each element is of the form (OUTPUT-FMT
OUTPUT-FILE-EXTENSION).
The variable is interpreted as follows:
`org-lparse-convert-process' can take any document that is in
INPUT-FMT-LIST and produce any document that is in the
OUTPUT-FMT-LIST. A document converted to OUTPUT-FMT will have
OUTPUT-FILE-EXTENSION as the file name extension. OUTPUT-FMT
serves dual purposes:
- It is used for populating completion candidates during
`org-lparse' and `org-lparse-convert' commands.
- It is used as the value of \"%f\" specifier in
`org-lparse-convert-process'.
DOCUMENT-CLASS is used to group a set of file formats in
INPUT-FMT-LIST in to a single class.
Note that this variable inherently captures how LibreOffice based
converters work. LibreOffice maps documents of various formats
to classes like Text, Web, Spreadsheet, Presentation etc and
allow document of a given class (irrespective of it's source
format) to be converted to any of the export formats associated
with that class.
See default setting of this variable for an typical
configuration."
:group 'org-lparse
:type
'(choice
(const :tag "None" nil)
(alist :key-type (string :tag "Document Class")
:value-type
(group (repeat :tag "Input formats" (string :tag "Input format"))
(alist :tag "Output formats"
:key-type (string :tag "Output format")
:value-type
(group (string :tag "Output file extension")))))))
(defcustom org-lparse-use-flashy-warning nil (defcustom org-lparse-use-flashy-warning nil
"Use flashy warnings when exporting to ODT." "Control flashing of messages logged with `org-lparse-warn'.
When non-nil, messages are fontified with warning face and the
exporter lingers for a while to catch user's attention."
:type 'boolean :type 'boolean
:group 'org-export) :group 'org-lparse)
(defun org-lparse-convert (&optional in-file fmt) (defun org-lparse-convert (&optional in-file out-fmt prefix-arg)
"Convert file from one format to another using a converter. "Convert IN-FILE to format OUT-FMT using a command line converter.
IN-FILE is the file to be converted. If unspecified, it defaults IN-FILE is the file to be converted. If unspecified, it defaults
to variable `buffer-file-name'. FMT is the desired output format. If the to variable `buffer-file-name'. OUT-FMT is the desired output
backend has registered a CONVERT-METHOD via it's get function format. If the backend has registered a CONVERT-METHOD as part
then that converter is used. Otherwise of it's get function then that converter is used. Otherwise
`org-export-conver-process' is used." `org-lparse-convert-process' is used. If PREFIX-ARG is non-nil
then the newly converted file is opened using `org-open-file'."
(interactive (interactive
(let* ((input (if (featurep 'ido) 'ido-completing-read 'completing-read)) (let* ((input (if (featurep 'ido) 'ido-completing-read 'completing-read))
(in-file (read-file-name "File to be converted: " (in-file (read-file-name "File to be converted: "
nil buffer-file-name t)) nil buffer-file-name t))
(fmt (funcall input "Output format: " (in-fmt (file-name-extension in-file))
(or (ignore-errors (out-fmt-choices (org-lparse-get-other-backends in-fmt))
(org-lparse-get-other-backends (out-fmt
(file-name-extension in-file))) (or (and out-fmt-choices
(org-lparse-all-backends)) (funcall input "Output format: "
nil nil nil))) out-fmt-choices nil nil nil))
(list in-file fmt))) (error
"No known converter or no known output formats for %s files"
in-fmt))))
(list in-file out-fmt current-prefix-arg)))
(require 'browse-url) (require 'browse-url)
(let* ((in-file (expand-file-name (or in-file buffer-file-name))) (let* ((in-file (expand-file-name (or in-file buffer-file-name)))
(fmt (or fmt "doc") ) (dummy (or (file-readable-p in-file)
(out-file (concat (file-name-sans-extension in-file) "." fmt)) (error "Cannot read %s" in-file)))
(in-fmt (file-name-extension in-file))
(out-fmt (or out-fmt (error "Output format unspecified")))
(convert-process (org-lparse-get-converter in-fmt))
(program (car convert-process))
(dummy (and (or program (error "Converter not configured"))
(or (executable-find program)
(error "Cannot find converter %s" program))))
(out-fmt-alist
(or (assoc out-fmt (org-lparse-get-other-backends in-fmt))
(error "Cannot convert from %s to %s format" in-fmt out-fmt)))
(out-file (concat (file-name-sans-extension in-file) "."
(nth 1 out-fmt-alist)))
(out-dir (file-name-directory in-file)) (out-dir (file-name-directory in-file))
(backend (when (boundp 'org-lparse-backend) org-lparse-backend)) (arglist (mapcar (lambda (arg)
(convert-process (format-spec
(or (ignore-errors (org-lparse-backend-get backend 'CONVERT-METHOD)) arg `((?i . ,in-file)
org-lparse-convert-process)) (?I . ,(browse-url-file-url in-file))
program arglist) (?f . ,out-fmt)
(?o . ,out-file)
(setq program (and convert-process (consp convert-process) (?O . ,(browse-url-file-url out-file))
(car convert-process))) (?d . ,out-dir)
(unless (executable-find program) (?D . ,(browse-url-file-url out-dir)))))
(error "Unable to locate the converter %s" program)) (cdr convert-process))))
(when (file-exists-p out-file)
(setq arglist (delete-file out-file))
(mapcar (lambda (arg)
(format-spec arg `((?i . ,in-file)
(?I . ,(browse-url-file-url in-file))
(?f . ,fmt)
(?o . ,out-file)
(?O . ,(browse-url-file-url out-file))
(?d . ,out-dir)
(?D . ,(browse-url-file-url out-dir)))))
(cdr convert-process)))
(ignore-errors (delete-file out-file))
(message "Executing %s %s" program (mapconcat 'identity arglist " ")) (message "Executing %s %s" program (mapconcat 'identity arglist " "))
(apply 'call-process program nil nil nil arglist) (apply 'call-process program nil nil nil arglist)
(cond (cond
((file-exists-p out-file) ((file-exists-p out-file)
(message "Exported to %s using %s" out-file program) (message "Exported to %s using %s" out-file program)
(when prefix-arg
(message "Opening %s..." out-file)
(org-open-file out-file))
out-file out-file
;; (set-buffer (find-file-noselect out-file)) ;; (set-buffer (find-file-noselect out-file))
) )
@ -1134,7 +1264,8 @@ version."
(or (when (and (boundp 'org-lparse-other-backend) (or (when (and (boundp 'org-lparse-other-backend)
org-lparse-other-backend org-lparse-other-backend
(not (equal org-lparse-backend org-lparse-other-backend))) (not (equal org-lparse-backend org-lparse-other-backend)))
(let ((org-lparse-convert-process (org-lparse-get 'CONVERT-METHOD))) (let ((org-lparse-convert-process
(org-lparse-get-converter org-lparse-backend)))
(when org-lparse-convert-process (when org-lparse-convert-process
(org-lparse-convert buffer-file-name (org-lparse-convert buffer-file-name
(symbol-name org-lparse-other-backend))))) (symbol-name org-lparse-other-backend)))))
@ -1145,8 +1276,7 @@ version."
(t (current-buffer)))))) (t (current-buffer))))))
(defun org-lparse-format-table (lines olines) (defun org-lparse-format-table (lines olines)
"Retuns backend-specific code for org-type and table-type "Retuns backend-specific code for org-type and table-type tables."
tables."
(if (stringp lines) (if (stringp lines)
(setq lines (org-split-string lines "\n"))) (setq lines (org-split-string lines "\n")))
(if (string-match "^[ \t]*|" (car lines)) (if (string-match "^[ \t]*|" (car lines))
@ -1623,7 +1753,7 @@ t : Log all invocations of `org-lparse-begin', `org-lparse-end'
(const :tag "Format and Control callbacks" t))) (const :tag "Format and Control callbacks" t)))
(defun org-lparse-begin (entity &rest args) (defun org-lparse-begin (entity &rest args)
"Begin ENTITY in current buffer. ARGS is entity specific. "Begin ENTITY in current buffer. ARGS is entity specific.
ENTITY can be one of PARAGRAPH, LIST, LIST-ITEM etc. ENTITY can be one of PARAGRAPH, LIST, LIST-ITEM etc.
Use (org-lparse-begin 'LIST \"o\") to begin a list in current Use (org-lparse-begin 'LIST \"o\") to begin a list in current
@ -1640,7 +1770,7 @@ information."
(apply f args))) (apply f args)))
(defun org-lparse-end (entity &rest args) (defun org-lparse-end (entity &rest args)
"Close ENTITY in current buffer. ARGS is entity specific. "Close ENTITY in current buffer. ARGS is entity specific.
ENTITY can be one of PARAGRAPH, LIST, LIST-ITEM ENTITY can be one of PARAGRAPH, LIST, LIST-ITEM
etc. etc.

View File

@ -266,6 +266,30 @@ be linked only."
(error "Cannot determine style name for entity %s of type %s" (error "Cannot determine style name for entity %s of type %s"
entity category)))) entity category))))
(defcustom org-export-odt-preferred-output-format nil
"Automatically post-process to this format after exporting to \"odt\".
Interactive commands `org-export-as-odt' and
`org-export-as-odt-and-open' export first to \"odt\" format and
then use an external converter to convert the resulting document
to this format.
The converter used is that specified with CONVERT-METHOD option
in `org-odt-get'. If the above option is unspecified then
`org-lparse-convert-process' is used.
The format specified here should be listed in OTHER-BACKENDS
option of `org-odt-get' or `org-lparse-convert-capabilities' as
appropriate."
:group 'org-odt
:type '(choice :convert-widget
(lambda (w)
(apply 'widget-convert (widget-type w)
(eval (car (widget-get w :args)))))
`((const :tag "None" nil)
,@(mapcar (lambda (c)
`(const :tag ,(car c) ,(car c)))
(org-lparse-get-other-backends "odt")))))
;;;###autoload ;;;###autoload
(defun org-export-as-odt-and-open (arg) (defun org-export-as-odt-and-open (arg)
"Export the outline as ODT and immediately open it with a browser. "Export the outline as ODT and immediately open it with a browser.
@ -273,7 +297,8 @@ If there is an active region, export only the region.
The prefix ARG specifies how many levels of the outline should become The prefix ARG specifies how many levels of the outline should become
headlines. The default is 3. Lower levels will become bulleted lists." headlines. The default is 3. Lower levels will become bulleted lists."
(interactive "P") (interactive "P")
(org-lparse-and-open "odt" "odt" arg)) (org-lparse-and-open
(or org-export-odt-preferred-output-format "odt") "odt" arg))
;;;###autoload ;;;###autoload
(defun org-export-as-odt-batch () (defun org-export-as-odt-batch ()
@ -338,7 +363,8 @@ the file header and footer, simply return the content of
<body>...</body>, without even the body tags themselves. When <body>...</body>, without even the body tags themselves. When
PUB-DIR is set, use this as the publishing directory." PUB-DIR is set, use this as the publishing directory."
(interactive "P") (interactive "P")
(org-lparse "odt" "odt" arg hidden ext-plist to-buffer body-only pub-dir)) (org-lparse (or org-export-odt-preferred-output-format "odt")
"odt" arg hidden ext-plist to-buffer body-only pub-dir))
(defvar org-odt-entity-control-callbacks-alist (defvar org-odt-entity-control-callbacks-alist
`((EXPORT `((EXPORT
@ -1436,11 +1462,8 @@ MAY-INLINE-P allows inlining it as an image."
(INIT-METHOD 'org-odt-init-outfile) (INIT-METHOD 'org-odt-init-outfile)
(FINAL-METHOD 'org-odt-finalize-outfile) (FINAL-METHOD 'org-odt-finalize-outfile)
(SAVE-METHOD 'org-odt-save-as-outfile) (SAVE-METHOD 'org-odt-save-as-outfile)
(OTHER-BACKENDS ;; (OTHER-BACKENDS) ; see note in `org-xhtml-get'
'("bib" "doc" "doc6" "doc95" "html" "xhtml" "latex" "odt" "ott" "pdf" "rtf" ;; (CONVERT-METHOD) ; see note in `org-xhtml-get'
"sdw" "sdw3" "sdw4" "stw " "sxw" "mediawiki" "text" "txt" "uot" "vor"
"vor3" "vor4" "docbook" "ooxml" "ppt" "odp"))
(CONVERT-METHOD org-lparse-convert-process)
(TOPLEVEL-HLEVEL 1) (TOPLEVEL-HLEVEL 1)
(SPECIAL-STRING-REGEXPS org-export-odt-special-string-regexps) (SPECIAL-STRING-REGEXPS org-export-odt-special-string-regexps)
(INLINE-IMAGES 'maybe) (INLINE-IMAGES 'maybe)

View File

@ -1659,10 +1659,17 @@ lang=\"%s\" xml:lang=\"%s\">
(INIT-METHOD nil) (INIT-METHOD nil)
(SAVE-METHOD nil) (SAVE-METHOD nil)
(CLEANUP-METHOD nil) (CLEANUP-METHOD nil)
(OTHER-BACKENDS ;; (OTHER-BACKENDS
'("xhtml" "etext" "html" "html10" "mediawiki" "pdf" "sdw" "sdw3" "sdw4" ;; ;; There is a provision to register a per-backend converter and
"text" "text10" "odt" "vor" "vor4")) ;; ;; output formats. Refer `org-lparse-get-converter' and
(CONVERT-METHOD org-lparse-convert-process) ;; ;; `org-lparse-get-other-backends'.
;; ;; The default behaviour is to use `org-lparse-convert-process'
;; ;; and `org-lparse-convert-capabilities'.
;; )
;; (CONVERT-METHOD
;; ;; See note above
;; )
(EXPORT-DIR (org-export-directory :html opt-plist)) (EXPORT-DIR (org-export-directory :html opt-plist))
(FILE-NAME-EXTENSION (plist-get opt-plist :html-extension)) (FILE-NAME-EXTENSION (plist-get opt-plist :html-extension))
(EXPORT-BUFFER-NAME "*Org HTML Export*") (EXPORT-BUFFER-NAME "*Org HTML Export*")