diff options
author | Carsten Dominik <carsten.dominik@gmail.com> | 2010-02-25 07:31:29 +0100 |
---|---|---|
committer | Carsten Dominik <carsten.dominik@gmail.com> | 2010-03-28 09:27:33 +0200 |
commit | 4892c8899e5b99d041836749fb2d1458971be55d (patch) | |
tree | 47a3c83e4a9efc5968dd39458078b03e5e07e5c9 | |
parent | 6b8632e2c3b1573f12e8eae2c1d4a15e31ab9ffe (diff) | |
download | org-mode-4892c8899e5b99d041836749fb2d1458971be55d.tar.gz |
Implement index generation during export
This new code will search #+INDEX lines in the buffer. For LaTeX, it
will simple convert these into LaTeX \index{} commands. For other
backends, it will copy thee entries to a new file, with extension
orgx. These files can then later be post-processed to create the index.
-rw-r--r-- | doc/ChangeLog | 5 | ||||
-rw-r--r-- | doc/org.texi | 90 | ||||
-rwxr-xr-x | lisp/ChangeLog | 11 | ||||
-rw-r--r-- | lisp/org-ascii.el | 5 | ||||
-rw-r--r-- | lisp/org-exp.el | 23 | ||||
-rw-r--r-- | lisp/org-latex.el | 5 | ||||
-rw-r--r-- | lisp/org-publish.el | 209 |
7 files changed, 275 insertions, 73 deletions
diff --git a/doc/ChangeLog b/doc/ChangeLog index 7f9a514..b9fb625 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,8 @@ +2010-03-28 Carsten Dominik <carsten.dominik@gmail.com> + + * org.texi (Index entries): New section. + (Generating an index): New section. + 2010-03-27 Carsten Dominik <carsten.dominik@gmail.com> * org.texi (Column width and alignment): Document that <N> now diff --git a/doc/org.texi b/doc/org.texi index 671df0c..bc57b93 100644 --- a/doc/org.texi +++ b/doc/org.texi @@ -304,6 +304,7 @@ Markup for rich export * Images and tables:: Tables and Images will be included * Literal examples:: Source code examples with special formatting * Include files:: Include additional files into a document +* Index entries:: * Macro replacement:: Use macros to create complex output * Embedded LaTeX:: LaTeX can be freely used inside Org documents @@ -385,7 +386,8 @@ Configuration * Publishing action:: Setting the function doing the publishing * Publishing options:: Tweaking HTML export * Publishing links:: Which links keep working after publishing? -* Project page index:: Publishing a list of project files +* Sitemap:: Generating a list of all pages +* Generating an index:: An index that reaches across pages Sample configuration @@ -8199,6 +8201,7 @@ summarizes the markup rules used in an Org-mode buffer. * Images and tables:: Tables and Images will be included * Literal examples:: Source code examples with special formatting * Include files:: Include additional files into a document +* Index entries:: * Macro replacement:: Use macros to create complex output * Embedded LaTeX:: LaTeX can be freely used inside Org documents @end menu @@ -8550,7 +8553,7 @@ label is stored as a link @samp{(label)}, for retrieval with @kbd{C-c C-l}. @end table -@node Include files, Macro replacement, Literal examples, Markup +@node Include files, Index entries, Literal examples, Markup @section Include files @cindex include files, markup rules @@ -8581,8 +8584,25 @@ the selected markup. For example, to include a file as an item, use Visit the include file at point. @end table +@node Index entries, Macro replacement, Include files, Markup +@section Index enries +@cindex index entries, for publishing -@node Macro replacement, Embedded LaTeX, Include files, Markup +You can specify entries that will be used for generating an index during +publishing. This is done by lines starting with @code{#+INDEX}. An entry +the contains an exclamation mark will create a sub item. See @ref{Generating +an index} for more information. + +@example +* Curriculum Vitae +#+INDEX: CV +#+INDEX: Application!CV +@end example + + + + +@node Macro replacement, Embedded LaTeX, Index entries, Markup @section Macro replacement @cindex macro replacement, during export @cindex #+MACRO @@ -10098,7 +10118,8 @@ and many other properties of a project. * Publishing action:: Setting the function doing the publishing * Publishing options:: Tweaking HTML export * Publishing links:: Which links keep working after publishing? -* Project page index:: Publishing a list of project files +* Sitemap:: Generating a list of all pages +* Generating an index:: An index that reaches across pages @end menu @node Project alist, Sources and destinations, Configuration, Configuration @@ -10144,13 +10165,15 @@ publish to a webserver using a file name syntax appropriate for the Emacs @file{tramp} package. Or you can publish to a local directory and use external tools to upload your website (@pxref{Uploading files}). @item @code{:preparation-function} -@tab Function called before starting the publishing process, for example, to -run @code{make} for updating files to be published. The project property -list is scoped into this call as the variable @code{project-plist}. +@tab Function or list of functions to be called before starting the +publishing process, for example, to run @code{make} for updating files to be +published. The project property list is scoped into this call as the +variable @code{project-plist}. @item @code{:completion-function} -@tab Function called after finishing the publishing process, for example, to -change permissions of the resulting files. The project property list is -scoped into this call as the variable @code{project-plist}. +@tab Function or list of functions called after finishing the publishing +process, for example, to change permissions of the resulting files. The +project property list is scoped into this call as the variable +@code{project-plist}. @end multitable @noindent @@ -10337,7 +10360,7 @@ its setting overrides the value of the corresponding user variable (if any) during publishing. Options set within a file (@pxref{Export options}), however, override everything. -@node Publishing links, Project page index, Publishing options, Configuration +@node Publishing links, Sitemap, Publishing options, Configuration @subsection Links between published files @cindex links, publishing @@ -10374,31 +10397,48 @@ description into the HTML file, but no link. One option for this function is @code{org-publish-validate-link} which checks if the given file is part of any project in @code{org-publish-project-alist}. -@node Project page index, , Publishing links, Configuration -@subsection Project page index -@cindex index, of published pages +@node Sitemap, Generating an index, Publishing links, Configuration +@subsection Generating a sitemap +@cindex sitemap, of published pages -The following properties may be used to control publishing of an -index of files or a summary page for a given project. +The following properties may be used to control publishing of +a map of files for a given project. @multitable @columnfractions 0.25 0.75 -@item @code{:auto-index} -@tab When non-nil, publish an index during @code{org-publish-current-project} +@item @code{:auto-sitemap} +@tab When non-nil, publish a sitemap during @code{org-publish-current-project} or @code{org-publish-all}. -@item @code{:index-filename} -@tab Filename for output of index. Defaults to @file{sitemap.org} (which +@item @code{:sitemap-filename} +@tab Filename for output of sitemap. Defaults to @file{sitemap.org} (which becomes @file{sitemap.html}). -@item @code{:index-title} -@tab Title of index page. Defaults to name of file. +@item @code{:sitemap-title} +@tab Title of sitemap page. Defaults to name of file. -@item @code{:index-function} -@tab Plug-in function to use for generation of index. -Defaults to @code{org-publish-org-index}, which generates a plain list +@item @code{:sitemap-function} +@tab Plug-in function to use for generation of the sitemap. +Defaults to @code{org-publish-org-sitemap}, which generates a plain list of links to all files in the project. @end multitable +@node Generating an index, , Sitemap, Configuration +@subsection Generating an index +@cindex index, in a publishing project + +Org-mode can generate an index across the files of a publishing project. + +@multitable @columnfractions 0.25 0.75 +@item @code{:makeindex} +@tab When non-nil, generate in index in the file @file{theindex.org} and +publish it as @file{theindex.html}. +@end multitable + +The file will be create when first publishing a project with the +@code{:makeindex} set. The file only contains a statement @code{#+include: +"theindex.inc"}. You can then built around this include statement by adding +a title, style information etc. + @node Uploading files, Sample configuration, Configuration, Publishing @section Uploading files @cindex rsync diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 848c42c..e492ad3 100755 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,14 @@ +2010-03-28 Carsten Dominik <carsten.dominik@gmail.com> + + * org-publish.el (org-publish-sanitize-plist): New function to + rename "index" properties to "sitemap". Do this renaming + globally. + (org-publish-with-aux-preprocess-maybe): New macro. + (org-publish-org-to-pdf, org-publish-org-to-html): Use the new + macro. + (org-publish-aux-preprocess) + (org-publish-index-generate-theindex.inc): New function. + 2010-03-27 Carsten Dominik <carsten.dominik@gmail.com> * org-table.el (org-table-align): Interpret <N> at fixed width, diff --git a/lisp/org-ascii.el b/lisp/org-ascii.el index 633958c..00840fa 100644 --- a/lisp/org-ascii.el +++ b/lisp/org-ascii.el @@ -189,6 +189,11 @@ publishing directory." (if subtree-p (org-export-add-subtree-options opt-plist rbeg) opt-plist))) + ;; The following two are dynamically scoped into other + ;; routines below. + (org-current-export-dir + (or pub-dir (org-export-directory :html opt-plist))) + (org-current-export-file buffer-file-name) (custom-times org-display-custom-times) (org-ascii-current-indentation '(0 . 0)) (level 0) line txt diff --git a/lisp/org-exp.el b/lisp/org-exp.el index f4e89f4..0add47f 100644 --- a/lisp/org-exp.el +++ b/lisp/org-exp.el @@ -396,6 +396,11 @@ This is run after selection of trees to be exported has happened. This selection includes tags-based selection, as well as removal of commented and archived trees.") +(defvar org-export-preprocess-after-headline-targets-hook nil + "Hook for preprocessing export buffer. +This is run just after the headline targets have been defined and +the target-alist has been set up.") + (defvar org-export-preprocess-before-selecting-backend-code-hook nil "Hook for preprocessing an export buffer. This is run just before backend-specific blocks get selected.") @@ -1296,6 +1301,8 @@ translations. There is currently no way for users to extend this.") "Alist of targets with invisible aliases.") (defvar org-export-preferred-target-alist nil "Alist of section id's with preferred aliases.") +(defvar org-export-id-target-alist nil + "Alist of section id's with preferred aliases.") (defvar org-export-code-refs nil "Alist of code references and line numbers") @@ -1320,9 +1327,10 @@ on this string to produce the exported version." (outline-regexp "\\*+ ") target-alist rtn) - (setq org-export-target-aliases nil) - (setq org-export-preferred-target-alist nil) - (setq org-export-code-refs nil) + (setq org-export-target-aliases nil + org-export-preferred-target-alist nil + org-export-id-target-alist nil + org-export-code-refs nil) (with-current-buffer (get-buffer-create " org-mode-tmp") (erase-buffer) @@ -1379,6 +1387,8 @@ on this string to produce the exported version." ;; Find all headings and compute the targets for them (setq target-alist (org-export-define-heading-targets target-alist)) + (run-hooks 'org-export-preprocess-after-headline-targets-hook) + ;; Find HTML special classes for headlines (org-export-remember-html-container-classes) @@ -1517,7 +1527,12 @@ The new targets are added to TARGET-ALIST, which is also returned." (if (not (assoc last-section-target org-export-preferred-target-alist)) (push (cons last-section-target id) - org-export-preferred-target-alist)))) + org-export-preferred-target-alist))) + (when (equal (match-string 1) "ID") + (if (not (assoc last-section-target + org-export-id-target-alist)) + (push (cons last-section-target (concat "ID-" id)) + org-export-id-target-alist)))) (setq level (org-reduced-level (save-excursion (goto-char (point-at-bol)) (org-outline-level)))) diff --git a/lisp/org-latex.el b/lisp/org-latex.el index 2ba6e31..3f0e3d7 100644 --- a/lisp/org-latex.el +++ b/lisp/org-latex.el @@ -636,6 +636,11 @@ when PUB-DIR is set, use this as the publishing directory." opt-plist))) ;; Make sure the variable contains the updated values. (org-export-latex-options-plist (setq org-export-opt-plist opt-plist)) + ;; The following two are dynamically scoped into other + ;; routines below. + (org-current-export-dir + (or pub-dir (org-export-directory :html opt-plist))) + (org-current-export-file buffer-file-name) (title (or (and subtree-p (org-export-get-title-from-subtree)) (plist-get opt-plist :title) (and (not diff --git a/lisp/org-publish.el b/lisp/org-publish.el index d8c248c..a27cea1 100644 --- a/lisp/org-publish.el +++ b/lisp/org-publish.el @@ -31,7 +31,7 @@ ;; + Publish all one's org-files to HTML or PDF ;; + Upload HTML, images, attachments and other files to a web server ;; + Exclude selected private pages from publishing -;; + Publish a clickable index of pages +;; + Publish a clickable sitemap of pages ;; + Manage local timestamps for publishing only changed files ;; + Accept plugin functions to extend range of publishable content ;; @@ -39,6 +39,16 @@ ;;; Code: + +(defun org-publish-sanitize-plist (plist) + (mapcar (lambda (x) + (or (cdr (assoq x '((:index-filename . :sitemap-filename) + (:index-title . :sitemap-title) + (:index-function . :sitemap-function) + (:index-style . :sitemap-style) + (:auto-index . :auto-sitemap)))) + x)))) + (eval-when-compile (require 'cl)) (require 'org) @@ -112,9 +122,11 @@ project for publishing. For example, you could call GNU Make on a certain makefile, to ensure published files are built up to date. :preparation-function Function to be called before publishing - this project. + this project. This may also be a list + of functions. :completion-function Function to be called after publishing - this project. + this project. This may also be a list + of functions. Some properties control details of the Org publishing process, and are equivalent to the corresponding user variables listed in @@ -144,22 +156,22 @@ learn more about their use and default values. :author `user-full-name' :email `user-mail-address' -The following properties may be used to control publishing of an -index of files or summary page for a given project. +The following properties may be used to control publishing of a +sitemap of files or summary page for a given project. - :auto-index Whether to publish an index during + :auto-sitemap Whether to publish a sitemap during `org-publish-current-project' or `org-publish-all'. - :index-filename Filename for output of index. Defaults + :sitemap-filename Filename for output of sitemap. Defaults to 'sitemap.org' (which becomes 'sitemap.html'). - :index-title Title of index page. Defaults to name of file. - :index-function Plugin function to use for generation of index. - Defaults to `org-publish-org-index', which + :sitemap-title Title of sitemap page. Defaults to name of file. + :sitemap-function Plugin function to use for generation of sitemap. + Defaults to `org-publish-org-sitemap', which generates a plain list of links to all files in the project. - :index-style Can be `list' (index is just an itemized list + :sitemap-style Can be `list' (sitemap is just an itemized list of the titles of the files involved) or `tree' (the directory structure of the source - files is reflected in the index). Defaults to + files is reflected in the sitemap). Defaults to `tree'." :group 'org-publish :type 'alist) @@ -439,20 +451,32 @@ PUB-DIR is the publishing directory." (unless visiting (kill-buffer init-buf)))))) +(defmacro org-publish-with-aux-preprocess-maybe (&rest body) + "Execute BODY with a modified hook to preprocess for index." + `(let ((org-export-preprocess-after-headline-targets-hook + (if (plist-get project-plist :makeindex) + (cons 'org-publish-aux-preprocess + org-export-preprocess-after-headline-targets-hook) + org-export-preprocess-after-headline-targets-hook))) + ,@body)) + (defun org-publish-org-to-latex (plist filename pub-dir) "Publish an org file to LaTeX. See `org-publish-org-to' to the list of arguments." - (org-publish-org-to "latex" plist filename pub-dir)) + (org-publish-with-aux-preprocess-maybe + (org-publish-org-to "latex" plist filename pub-dir))) (defun org-publish-org-to-pdf (plist filename pub-dir) "Publish an org file to PDF (via LaTeX). See `org-publish-org-to' to the list of arguments." - (org-publish-org-to "pdf" plist filename pub-dir)) + (org-publish-with-aux-preprocess-maybe + (org-publish-org-to "pdf" plist filename pub-dir))) (defun org-publish-org-to-html (plist filename pub-dir) "Publish an org file to HTML. See `org-publish-org-to' to the list of arguments." - (org-publish-org-to "html" plist filename pub-dir)) + (org-publish-with-aux-preprocess-maybe + (org-publish-org-to "html" plist filename pub-dir))) (defun org-publish-org-to-org (plist filename pub-dir) "Publish an org file to HTML. @@ -518,31 +542,39 @@ See `org-publish-org-to' to the list of arguments." (defun org-publish-projects (projects) "Publish all files belonging to the PROJECTS alist. -If :auto-index is set, publish the index too." +If :auto-sitemap is set, publish the sitemap too. +If :makeindex is set, also produce a file theindex.org." (mapc (lambda (project) (let* ((project-plist (cdr project)) (exclude-regexp (plist-get project-plist :exclude)) - (index-p (plist-get project-plist :auto-index)) - (index-filename (or (plist-get project-plist :index-filename) - "sitemap.org")) - (index-function (or (plist-get project-plist :index-function) - 'org-publish-org-index)) + (sitemap-p (plist-get project-plist :auto-sitemap)) + (sitemap-filename (or (plist-get project-plist :sitemap-filename) + "sitemap.org")) + (sitemap-function (or (plist-get project-plist :sitemap-function) + 'org-publish-org-sitemap)) (preparation-function (plist-get project-plist :preparation-function)) (completion-function (plist-get project-plist :completion-function)) (files (org-publish-get-base-files project exclude-regexp)) file) - (when preparation-function (funcall preparation-function)) - (if index-p (funcall index-function project index-filename)) + (when preparation-function (run-hooks 'preparation-function)) + (if sitemap-p (funcall sitemap-function project sitemap-filename)) (while (setq file (pop files)) (org-publish-file file project)) - (when completion-function (funcall completion-function)))) + (when (plist-get project-plist :makeindex) + (org-publish-index-generate-theindex.inc + (plist-get project-plist :base-directory)) + (org-publish-file (expand-file-name + "theindex.org" + (plist-get project-plist :base-directory)) + project)) + (when completion-function (run-hooks 'completion-function)))) (org-publish-expand-projects projects))) -(defun org-publish-org-index (project &optional index-filename) - "Create an index of pages in set defined by PROJECT. -Optionally set the filename of the index with INDEX-FILENAME. -Default for INDEX-FILENAME is 'sitemap.org'." +(defun org-publish-org-sitemap (project &optional sitemap-filename) + "Create an sitemap of pages in set defined by PROJECT. +Optionally set the filename of the sitemap with SITEMAP-FILENAME. +Default for SITEMAP-FILENAME is 'sitemap.org'." (let* ((project-plist (cdr project)) (dir (file-name-as-directory (plist-get project-plist :base-directory))) @@ -550,28 +582,28 @@ Default for INDEX-FILENAME is 'sitemap.org'." (indent-str (make-string 2 ?\ )) (exclude-regexp (plist-get project-plist :exclude)) (files (nreverse (org-publish-get-base-files project exclude-regexp))) - (index-filename (concat dir (or index-filename "sitemap.org"))) - (index-title (or (plist-get project-plist :index-title) - (concat "Index for project " (car project)))) - (index-style (or (plist-get project-plist :index-style) + (sitemap-filename (concat dir (or sitemap-filename "sitemap.org"))) + (sitemap-title (or (plist-get project-plist :sitemap-title) + (concat "Sitemap for project " (car project)))) + (sitemap-style (or (plist-get project-plist :sitemap-style) 'tree)) - (visiting (find-buffer-visiting index-filename)) - (ifn (file-name-nondirectory index-filename)) - file index-buffer) - (with-current-buffer (setq index-buffer - (or visiting (find-file index-filename))) + (visiting (find-buffer-visiting sitemap-filename)) + (ifn (file-name-nondirectory sitemap-filename)) + file sitemap-buffer) + (with-current-buffer (setq sitemap-buffer + (or visiting (find-file sitemap-filename))) (erase-buffer) - (insert (concat "#+TITLE: " index-title "\n\n")) + (insert (concat "#+TITLE: " sitemap-title "\n\n")) (while (setq file (pop files)) (let ((fn (file-name-nondirectory file)) (link (file-relative-name file dir)) (oldlocal localdir)) - ;; index shouldn't index itself - (unless (equal (file-truename index-filename) + ;; sitemap shouldn't list itself + (unless (equal (file-truename sitemap-filename) (file-truename file)) - (if (eq index-style 'list) - (message "Generating list-style index for %s" index-title) - (message "Generating tree-style index for %s" index-title) + (if (eq sitemap-style 'list) + (message "Generating list-style sitemap for %s" sitemap-title) + (message "Generating tree-style sitemap for %s" sitemap-title) (setq localdir (concat (file-name-as-directory dir) (file-name-directory link))) (unless (string= localdir oldlocal) @@ -600,7 +632,7 @@ Default for INDEX-FILENAME is 'sitemap.org'." (org-publish-find-title file) "]]\n"))))) (save-buffer)) - (or visiting (kill-buffer index-buffer)))) + (or visiting (kill-buffer sitemap-buffer)))) (defun org-publish-find-title (file) "Find the title of file in project." @@ -656,6 +688,7 @@ directory and force publishing all files." (if force nil org-publish-use-timestamps-flag))) (org-publish-projects org-publish-project-alist)))) + ;;;###autoload (defun org-publish-current-file (&optional force) "Publish the current file. @@ -682,6 +715,94 @@ the project." (error "File %s is not part of any known project" (buffer-file-name))) (org-publish project)))) + +;;; Index generation + +(defun org-publish-aux-preprocess () + "Find index entries and write them to an .orgx file." + (let (entry index) + (goto-char (point-min)) + (while + (and + (re-search-forward "^[ \t]*#\\+index:[ \t]*\\(.*?\\)[ \t]*$" nil t) + (> (match-end 1) (match-beginning 1))) + (setq entry (match-string 1)) + (when (eq backend 'latex) + (replace-match (format "\\index{%s}" entry) t t)) + (save-excursion + (org-back-to-heading t) + (setq target (get-text-property (point) 'target)) + (setq target (or (cdr (assoc target org-export-preferred-target-alist)) + (cdr (assoc target org-export-id-target-alist)) + target)) + (push (cons entry target) index))) + (with-temp-file + (concat (file-name-sans-extension org-current-export-file) ".orgx") + (dolist (entry (nreverse index)) + (insert (format "INDEX: (%s) %s\n" (cdr entry) (car entry))))))) + +(defun org-publish-index-generate-theindex.inc (directory) + "Generate the index from all .orgx files in the current directory and below." + (require 'find-lisp) + (let* ((fulldir (file-name-as-directory + (expand-file-name directory))) + (full-files (find-lisp-find-files directory "\\.orgx\\'")) + (re (concat "\\`" fulldir)) + (files (mapcar (lambda (f) (if (string-match re f) + (substring f (match-end 0)) + f)) + full-files)) + (default-directory directory) + index origfile buf target entry ibuffer + main last-main letter last-letter) + ;; `files' contains the list of relative file names + (dolist (file files) + (setq origfile (substring file 0 -1)) + (setq buf (find-file-noselect file)) + (with-current-buffer buf + (goto-char (point-min)) + (while (re-search-forward "^INDEX: (\\(.*?\\)) \\(.*\\)" nil t) + (setq target (match-string 1) + entry (match-string 2)) + (push (list entry origfile target) index))) + (kill-buffer buf)) + (setq index (sort index (lambda (a b) (string< (downcase (car a)) + (downcase (car b)))))) + (setq ibuffer (find-file-noselect (expand-file-name "theindex.inc" directory))) + (with-current-buffer ibuffer + (erase-buffer) + (insert "* Index\n") + (setq last-letter nil) + (dolist (idx index) + (setq entry (car idx) file (nth 1 idx) target (nth 2 idx)) + (setq letter (upcase (substring entry 0 1))) + (when (not (equal letter last-letter)) + (insert "** " letter "\n") + (setq last-letter letter)) + (if (string-match "!" entry) + (setq main (substring entry 0 (match-beginning 0)) + sub (substring entry (match-end 0))) + (setq main nil sub nil last-main nil)) + (when (and main (not (equal main last-main))) + (insert " - " main "\n") + (setq last-main main)) + (setq link (concat "[[file:" file "::#" target "]" + "[" (or sub entry) "]]")) + (if (and main sub) + (insert " - " link "\n") + (insert " - " link "\n"))) + (save-buffer)) + (kill-buffer ibuffer) + + (let ((index-file (expand-file-name "theindex.org" directory))) + (unless (file-exists-p index-file) + (setq ibuffer (find-file-noselect index-file)) + (with-current-buffer ibuffer + (erase-buffer) + (insert "\n\n#+include: \"theindex.inc\"\n\n") + (save-buffer)) + (kill-buffer ibuffer))))) + (provide 'org-publish) |