Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/fniessen/orgmk
Streamline your Org document exports to PDF, HTML, DOC, and more with OrgMk. Simplify document compilation and enhance productivity. #orgmode #productivity #automation
https://github.com/fniessen/orgmk
Last synced: about 1 month ago
JSON representation
Streamline your Org document exports to PDF, HTML, DOC, and more with OrgMk. Simplify document compilation and enhance productivity. #orgmode #productivity #automation
- Host: GitHub
- URL: https://github.com/fniessen/orgmk
- Owner: fniessen
- Created: 2014-03-03T12:04:27.000Z (almost 11 years ago)
- Default Branch: master
- Last Pushed: 2024-03-30T13:04:09.000Z (9 months ago)
- Last Synced: 2024-08-02T16:46:29.717Z (4 months ago)
- Language: Emacs Lisp
- Homepage:
- Size: 471 KB
- Stars: 226
- Watchers: 22
- Forks: 27
- Open Issues: 7
-
Metadata Files:
- Readme: README.org
Awesome Lists containing this project
- my-awesome-github-stars - fniessen/orgmk - Streamline your Org document exports to PDF, HTML, DOC, and more with OrgMk. Simplify document compilation and enhance productivity. #orgmode #productivity #automation (Emacs Lisp)
README
#+TITLE: Export Org mode documents to HTML, PDF, etc.
#+AUTHOR: Fabrice Niessen
#+EMAIL: (concat "fniessen" at-sign "pirilampo.org")
#+DESCRIPTION: Orgmk completely automates the export of Org documents.
#+KEYWORDS: org-mode, orgmk, export, automate, emacs, pdf, latex, html
#+LANGUAGE: en
#+OPTIONS: H:4 toc:t num:nil#+PROPERTY: header-args :eval no :noweb yes :comments no
#+SETUPFILE: ~/org/theme-readtheorg.setup#+begin_quote
[!TIP]*** Elevate your Emacs skills in Paris, Utrecht, Leuven or Valencia!
*Unlock the power of Emacs! Join my next exclusive "Emacs Boost" course!*Ready to /supercharge your productivity/ and become an Emacs ninja? Look no
further!*What you'll learn:*
- Master Emacs from the basics to advanced tricks.
- /Boost your editing efficiency/ and streamline your workflow.
- Customize Emacs to fit your unique needs.
- And much more!*Audience:*
Open to anyone interested in Emacs, from beginners to advanced
users.*Why choose my course?*
- Expert instructor with 25 years of Emacs experience.
- /Hands-on exercises/ to reinforce your learning.
- /Networking opportunities/ with like-minded Emacs enthusiasts.
- Personalized attention.Don't miss this opportunity to take your Emacs skills to the next level! \\
Visit https://emacsboost.com/en/ for more information, dates and locations, and
to /reserve your seat/.
#+end_quote* Overview
** Description
Orgmk is a suite of Bash scripts for *automating the conversion of Org mode
documents to different formats* (such as HTML or PDF) from the command line.#+begin_export html
Tweet
#+end_exportThe scripts run on both Unix and Microsoft Windows (with Cygwin).
** Objectives
The first goal is to *be more productive*, by running the export only when the
source Org files are updated.The second goal is to *share some common Emacs and Org configuration inside your*
*team*, separately of what you have in your personal Emacs configuration file.Finally, the third goal is also to *offload compilation into an external batch
Emacs process*, allowing you to go on editing or working while exporting the
documents.** Quotations
"If one has been trying to bulk convert many quickly changing org-documents,
[one] will appreciate the power and flexibility of this tool." \\
-- /z27/"Orgmk is a wonderful tool, and, as far as I know, still unique." \\
-- /Priyadarshan/** Requirements
:PROPERTIES:
:header-args+: :tangle no
:END:*** Emacs 24+
Emacs version 24 (for the ~package~ facility) must be in your =PATH=.
*** Org 8+
Org mode version 8 (or later) is required.
If such a version is not bundled with your Emacs, Org 8 will be automatically
installed -- if you accept it! -- through ELPA.*** LaTeX (PDF)
A working LaTeX installation is required for exporting to PDF. If it is not
yet installed on your system, install [[http://www.tug.org/texlive/][TeX Live]] (for example).* Usage
Org files can have the extension ~.org~ or ~.txt~.
** Standalone scripts
- For "weaving" files (producing the formatted documentation files):
#+begin_src shell
org2html [OPTION] FILE
org2latex [OPTION] FILE
org2pdf [OPTION] FILE
org2beamerpdf [OPTION] FILE
org2odt [OPTION] FILE
org2txt [OPTION] FILE
#+end_src- For "tangling" files:
#+begin_src shell
org-tangle FILE
#+end_src** Makefile wrapper
#+begin_src shell
orgmk [OPTION]
orgmk [OPTION] [html | pdf]
orgmk [OPTION] [FILE]
#+end_srcCurrently, =orgmk= does not tangle Org files.
* Options
** Standalone scripts
- =-h=, =--help= ::
Print usage information and exit.- =-y= ::
Authorize the update of the source file (update of dynamic blocks and
re-computation of tables) without confirmation.Before the conversion, the standalone scripts will try to *update all
dynamic blocks and recompute all tables* in the source Org file, a
*potentially destructive operation* for which the programs require
confirmation: in case the source file gets updated, you will be queried to
overwrite the source file with the updated version of the file -- that's
because the environment variable =UPDATE_SRC= defaults to =query=.To avoid the question, you can also set that variable to =yes= or =no= in a
personal configuration file, =~/.orgmk-rc=.Note that, by design, the command line argument =-y= is passed to every
=org2= script called from =orgmk=, so that =orgmk= doesn't wait for
answers.- =--body-only= ::
Export only body (for HTML and LaTeX).** Makefile wrapper
- =-h=, =--help= ::
Print usage information and exit.- =-r=, =--recursive= ::
Export all Org files *under each directory, recursively*.It just calls =orgmk.mk= with the argument =ALLSUBDIRS=yes=.
By default, =orgmk= exports all Org files (which need it) in the current
directory only.* Files
[[~/.orgmk-rc]]
* Examples
** Update all documents
Regenerate HTML and/or PDF files for Org files that have been modified.
#+begin_src shell
orgmk
#+end_src** Update specific types of documents
Regenerate HTML only for the Org files that have been changed.
#+begin_src shell
orgmk html
#+end_src** Update specific document
Regenerate (or create for the first time) the file ~thesis.pdf~ from the Org file
~thesis.org~ or ~thesis.txt~. *Don't require confirmation for updating the source
file.*#+begin_src shell
orgmk thesis.pdf
#+end_srcRegenerate (or create for the first time) the file ~thesis.pdf~ from the Org file
~thesis.org~. Require confirmation for updating the source file.#+begin_src shell
org2pdf thesis.org
#+end_src* Installation
The installation process consists of creating symbolic links from the standard
*final directories* on your machine to the =orgmk= executables.** Installing from the Git repository
# See one-line for installation at https://github.com/tj/git-extras
1. *Extract* the latest version of =orgmk=.
#+begin_src shell
git clone [email protected]:fniessen/orgmk.git
#+end_src2. Create configuration files which record where =orgmk= has been extracted
on your host machine.#+begin_src shell
make
#+end_src3. By default, the =orgmk= executable and the standalone scripts (=org2html=,
=org2pdf=, etc.) are installed to the ~/usr/local/bin~ so that all users are
able to run them.If you want to *change the destination directory*, create a ~Make.params~ file
with the target directory. For example:#+begin_src makefile
BIN_DIR=~/bin
#+end_srcIf needed, add that directory to your =PATH=.
*Install* =orgmk= (executable and standalone scripts that you run) to the
=BIN_DIR= location by typing:#+begin_src shell
make install
#+end_srcAt this point, everything should be ready for use.
** Makefile for installation
:PROPERTIES:
:header-args+: :shebang "" :tangle Makefile
:END:#+begin_src makefile
### -*- Makefile -*- definition file for Orgmk# To install `orgmk', type `make' and then `make install'.
PWD=$(shell pwd)
BIN_DIR=/usr/local/bin
-include Make.params
ORGMK_ROOT=$(PWD)
ORGMK_EL=$(ORGMK_ROOT)/site-lisp/orgmk.el# WARNING -- ORGMK_EL must contain the correct path to the `orgmk.el' file
# according to the Emacs version used (Windows, Cygwin or Linux path).
EMACS_SYSTEM_TYPE=$(shell emacs -batch --eval "(message \"%s\" system-type)" 2>&1)
ifeq ($(EMACS_SYSTEM_TYPE),windows-nt)
ORGMK_EL:="$(shell cygpath --mixed $(ORGMK_EL))"
endifORGMK_INIT=orgmk-init
ORGMK_SYSTEM_CONFIG=orgmk.conf
ORGMK_UPDATE_CHECK_DIFF=orgmk-update-src-check-diff
ORG2HTML=org2html
ORG2GFM=org2gfm
ORG2MD=org2md
# ORG2REVEAL=org2reveal
ORG2LATEX=org2latex
ORG2PDF=org2pdf
ORG2BEAMERPDF=org2beamerpdf
ORG2ODT=org2odt
ORG2TXT=org2txt
ORGTANGLE=org-tangle
ORGMK_MAKE_SETUP=orgmk-stow-orgmk.mk
ORGMK_MAKE_RUN=orgmk## MAKE
# Ensure `all' is the default target
all: bin/$(ORGMK_SYSTEM_CONFIG) bin/$(ORGMK_MAKE_SETUP) # Create Orgmk system filesbin/$(ORGMK_SYSTEM_CONFIG): # Create file with location of `orgmk.el'
@echo "Generating system-wide configuration file..."
echo "ORGMK_EL=$(ORGMK_EL)" > bin/$(ORGMK_SYSTEM_CONFIG)
@echobin/$(ORGMK_MAKE_SETUP): # Create core file for `orgmk'
@echo "Generating setup file..."
echo "#!/bin/sh" > bin/$(ORGMK_MAKE_SETUP)
echo "ln -f -s $(PWD)/bin/orgmk.mk orgmk.mk" >> bin/$(ORGMK_MAKE_SETUP)
chmod u+x bin/$(ORGMK_MAKE_SETUP)
@echo## MAKE INSTALL
.PHONY: install
install: all # Create symlinks to Orgmk scripts
@echo "Creating symlinks..."
ln -f -s $(PWD)/bin/$(ORGMK_INIT) $(BIN_DIR)/$(ORGMK_INIT)
ln -f -s $(PWD)/bin/$(ORGMK_SYSTEM_CONFIG) $(BIN_DIR)/$(ORGMK_SYSTEM_CONFIG)
ln -f -s $(PWD)/bin/$(ORGMK_UPDATE_CHECK_DIFF) $(BIN_DIR)/$(ORGMK_UPDATE_CHECK_DIFF)
ln -f -s $(PWD)/bin/$(ORG2HTML) $(BIN_DIR)/$(ORG2HTML)
ln -f -s $(PWD)/bin/$(ORG2GFM) $(BIN_DIR)/$(ORG2GFM)
ln -f -s $(PWD)/bin/$(ORG2MD) $(BIN_DIR)/$(ORG2MD)
# ln -f -s $(PWD)/bin/$(ORG2REVEAL) $(BIN_DIR)/$(ORG2REVEAL)
ln -f -s $(PWD)/bin/$(ORG2LATEX) $(BIN_DIR)/$(ORG2LATEX)
ln -f -s $(PWD)/bin/$(ORG2PDF) $(BIN_DIR)/$(ORG2PDF)
ln -f -s $(PWD)/bin/$(ORG2BEAMERPDF) $(BIN_DIR)/$(ORG2BEAMERPDF)
ln -f -s $(PWD)/bin/$(ORG2ODT) $(BIN_DIR)/$(ORG2ODT)
ln -f -s $(PWD)/bin/$(ORG2TXT) $(BIN_DIR)/$(ORG2TXT)
ln -f -s $(PWD)/bin/$(ORGTANGLE) $(BIN_DIR)/$(ORGTANGLE)
ln -f -s $(PWD)/bin/$(ORGMK_MAKE_SETUP) $(BIN_DIR)/$(ORGMK_MAKE_SETUP)
ln -f -s $(PWD)/bin/$(ORGMK_MAKE_RUN) $(BIN_DIR)/$(ORGMK_MAKE_RUN)### Makefile ends here
#+end_src* Standalone scripts
** Orgmk-init
:PROPERTIES:
:header-args+: :shebang "#!/bin/sh\n" :tangle bin/orgmk-init
:END:The =orgmk-init= script contains the common part used to setup Emacs
and Org in order to export to HTML, PDF, etc.*** Functions
#+begin_src shell
Usage ()
{
cat << EOF 1>&2
Usage: $(basename $0) [OPTION] FILE
Convert FILE to another format.-h, --help display this help and exit
-y authorize update of the source file without confirmation
--body-only export only body (for HTML and LaTeX exports)
EOF
exit 1
}
#+end_src#+begin_src shell
die () {
printf "$(basename $0): $@\n" > /dev/stderr
exit 2 # an error occurred
}
#+end_src#+begin_src shell
CleanUp ()
{
# restore backed up target file if it hasn't been produced
if [ ! -z $FILE_TARGET ]; then
if [ -r $FILE_TARGET.orig ]; then
if [ ! -r $FILE_TARGET ]; then
printf "Recovering OLD file $FILE_TARGET...\n"
mv $FILE_TARGET.orig $FILE_TARGET
else
rm $FILE_TARGET.orig
fi
fi
fi# display log file, if present
if [ ! -z $FILE_LOG ]; then
if [ -r $FILE_LOG ]; then
grep -e "^!.*" -A 3 -B 1 $FILE_LOG
fi
fi# remove the temporary copy of the source Org file
if [ ! -z $FILE_SRC_UPDT ]; then
rm -f $FILE_SRC_UPDT
fi
}
#+end_src*** Runtime
#+name: current-time
#+begin_src emacs-lisp :eval yes :results silent :tangle no
(format-time-string "%Y%m%d.%H%M")
#+end_src#+begin_src shell
cat << EOF
This is $(basename $0), version: <>.
EOF
#+end_src#+begin_src shell
# perform housekeeping on program exit or a variety of signals
# (EXIT, HUP, INT, QUIT, TERM)
trap CleanUp 0 1 2 3 15
#+end_src#+begin_src shell
# load the system-wide config file (definition of `ORGMK_EL')
. orgmk.confif [ "$ORGMK_EL" = "" ]; then
printf "ORGMK_EL variable not defined, please check your setup!\n"
exit 2
fi# source the user config file (default for `UPDATE_SRC', etc.)
ORGMK_USER_CONF=$HOME/.orgmk-rc
if [ -r $ORGMK_USER_CONF ]; then
. $ORGMK_USER_CONF
fiexport UPDATE_SRC
# set a default value
export BODY_ONLY="no"while true; do
case "$1" in
-y ) UPDATE_SRC="yes"; shift ;;
--body-only ) BODY_ONLY="yes"; shift ;;
-h | --help ) Usage ;;
,* ) break ;;
esac
done
# now do something with $@
#+end_src#+begin_src shell
if [ $# -ne 1 ]; then
Usage
fiFILE_SRC_ORIG=$1
if [ ! -r "$FILE_SRC_ORIG" ]; then
die "Cannot read file $FILE_SRC_ORIG"
fiFILE_SRC_UPDT="${FILE_SRC_ORIG%.*}.orgmk" # replace extension
# The temporary file only differ by its extension (`.orgmk'), so that the
# exported file will be named ..
#+end_src#+begin_src shell
FILE_LOG="${FILE_SRC_ORIG%.*}.log"
rm -f $FILE_LOG
#+end_srcIf the PDF file isn't produced (for example, because of an /undefined control
sequence/), there is no PDF file anymore; hence, =orgmk= would ignore the source
file in future calls, and the PDF file (now, missing...) would completely
disappear from the user attention.To avoid that, we must make a backup of the target file before the export, and
put it back if there is no target file produced.#+begin_src shell
FILE_TARGET="${FILE_SRC_ORIG%.*}.$TARGET_EXT"# back up previous version of target file
if [ -r $FILE_TARGET ]; then
mv $FILE_TARGET $FILE_TARGET.orig
fi
#+end_srcNote that, like with the ~patch~ command, the original file is saved with the
=.orig= extension.#+begin_src shell
EMACS=emacsWHICH_EMACS=$(which $EMACS)
EMACS_FLAGS="--eval \"(progn (message \\\"Launching $WHICH_EMACS...\\\") (message \\\"Emacs %s (%s)\\\" emacs-version system-type))\""
EMACS_BATCH="emacs --batch -Q $EMACS_FLAGS"
ORG_FLAGS=""
ORGMK="$EMACS_BATCH $ORG_FLAGS --eval \"(message \\\"Loading ${ORGMK_EL}...\\\")\" -l $ORGMK_EL"
ORGMK_UPDATE_FLAGS="-f org-update-all-dblocks -f org-table-iterate-buffer-tables --eval \"(write-file \\\"${FILE_SRC_UPDT##*/}\\\")\"" # base name
#+end_src#+begin_note
*Batch option* \\
Font Lock mode is disabled by default in batch mode. That generates errors with
some Java code blocks. Hence, one workaround, in that case, is to call Emacs
without batch mode (and, then, to add ~-f kill-emacs~, or simply ~--kill~, at the
end of the command line).
#+end_note** org2html
:PROPERTIES:
:header-args+: :shebang "#!/bin/sh\n" :tangle bin/org2html
:END:The =org2html= script converts an Org file to HTML.
#+begin_src shell
TARGET_EXT=html
. orgmk-initcase $BODY_ONLY in
"yes")
eval $ORGMK $FILE_SRC_ORIG $ORGMK_UPDATE_FLAGS -f org-html-export-body-only-to-html \
|| die "Exported file wasn't produced"
;;
"no")
eval $ORGMK $FILE_SRC_ORIG $ORGMK_UPDATE_FLAGS -f org-html-export-to-html \
|| die "Exported file wasn't produced"
esacorgmk-update-src-check-diff "$FILE_SRC_ORIG" "$FILE_SRC_UPDT"
#+end_src** org2latex
:PROPERTIES:
:header-args+: :shebang "#!/bin/sh\n" :tangle bin/org2latex
:END:The =org2latex= script converts an Org file to LaTeX.
#+begin_src shell
TARGET_EXT=tex
. orgmk-initcase $BODY_ONLY in
"yes")
eval $ORGMK $FILE_SRC_ORIG $ORGMK_UPDATE_FLAGS -f org-latex-export-body-only-to-latex \
|| die "Exported file wasn't produced"
;;
"no")
if grep -E "^#\+BEAMER_THEME: " $FILE_SRC_ORIG > /dev/null; then
eval $ORGMK $FILE_SRC_ORIG $ORGMK_UPDATE_FLAGS -f org-beamer-export-to-latex \
|| die "Exported file wasn't produced"
else
eval $ORGMK $FILE_SRC_ORIG $ORGMK_UPDATE_FLAGS -f org-latex-export-to-latex \
|| die "Exported file wasn't produced"
fi
esacorgmk-update-src-check-diff "$FILE_SRC_ORIG" "$FILE_SRC_UPDT"
#+end_src** org2pdf
:PROPERTIES:
:header-args+: :shebang "#!/bin/sh\n" :tangle bin/org2pdf
:END:The =org2pdf= script converts an Org file to PDF.
#+begin_note
It tries to detect whether the target is a standard LaTeX document or a Beamer
presentation by searching for the string =#+BEAMER_THEME:= inside the Org source.
#+end_note#+begin_src shell
TARGET_EXT=pdf
. orgmk-initif grep -E "^#\+BEAMER_THEME: " $FILE_SRC_ORIG > /dev/null; then
eval $ORGMK $FILE_SRC_ORIG $ORGMK_UPDATE_FLAGS -f org-beamer-export-to-latex \
|| die "Exported file wasn't produced"
else
eval $ORGMK $FILE_SRC_ORIG $ORGMK_UPDATE_FLAGS -f org-latex-export-to-latex \
|| die "Exported file wasn't produced"
fi
orgmk-update-src-check-diff "$FILE_SRC_ORIG" "$FILE_SRC_UPDT"
#+end_src** org2beamerpdf
:PROPERTIES:
:header-args+: :shebang "#!/bin/sh\n" :tangle bin/org2beamerpdf
:END:The =org2beamerpdf= script converts an Org file to a Beamer presentation (PDF).
#+begin_src shell
TARGET_EXT=pdf
. orgmk-initeval $ORGMK $FILE_SRC_ORIG $ORGMK_UPDATE_FLAGS -f org-beamer-export-to-pdf \
|| die "Exported file wasn't produced"
orgmk-update-src-check-diff "$FILE_SRC_ORIG" "$FILE_SRC_UPDT"
#+end_src** org2odt
:PROPERTIES:
:header-args+: :shebang "#!/bin/sh\n" :tangle bin/org2odt
:END:The =org2odt= script converts an Org file to ODT.
#+begin_src shell
TARGET_EXT=odt
. orgmk-initeval $ORGMK $FILE_SRC_ORIG $ORGMK_UPDATE_FLAGS -f org-odt-export-to-odt \
|| die "Exported file wasn't produced"
orgmk-update-src-check-diff "$FILE_SRC_ORIG" "$FILE_SRC_UPDT"
#+end_src** org2txt
:PROPERTIES:
:header-args+: :shebang "#!/bin/sh\n" :tangle bin/org2txt
:END:The =org2txt= script converts an Org file to text.
#+begin_src shell
TARGET_EXT=txt
. orgmk-initeval $ORGMK $FILE_SRC_ORIG $ORGMK_UPDATE_FLAGS -f org-ascii-export-to-ascii \
|| die "Exported file wasn't produced"
orgmk-update-src-check-diff "$FILE_SRC_ORIG" "$FILE_SRC_UPDT"
#+end_src** org2gfm
:PROPERTIES:
:header-args+: :shebang "#!/bin/sh\n" :tangle bin/org2gfm
:END:The =org2gfm= script converts an Org file to Github Flavored Markdown.
#+BEGIN_SRC shell
TARGET_EXT=md
. orgmk-initeval $ORGMK $FILE_SRC_ORIG $ORGMK_UPDATE_FLAGS -f org-gfm-export-to-markdown \
|| die "Exported file wasn't produced"
orgmk-update-src-check-diff "$FILE_SRC_ORIG" "$FILE_SRC_UPDT"
#+END_SRC** Orgmk-update-src-check-diff
:PROPERTIES:
:header-args+: :shebang "#!/bin/bash\n" :tangle bin/orgmk-update-src-check-diff
:END:Check whether dynamic blocks and tables have been updated, and (if yes) propose
to overwrite the source Org file.*** Functions
#+begin_src shell
ask () {
while true; do
if [ "${2:-}" = "Y" ]; then
prompt="Y/n"
default=Y
elif [ "${2:-}" = "N" ]; then
prompt="y/N"
default=N
else
prompt="y/n"
default=
fi# ask the question (without the need to press RET)
printf "$1 ($prompt): "
read -n 1 -r REPLY
printf "\n" # just a final linefeed# default?
if [ -z "$REPLY" ]; then
REPLY=$default
fi# check if the reply is valid
case "$REPLY" in
y*|Y*) return 0 ;;
n*|N*) return 1 ;;
esac
done
}
#+end_src*** Runtime
#+begin_src shell
FILE_SRC_ORIG=$1
FILE_SRC_UPDT=$2# set a default value
: ${UPDATE_SRC:="query"}if [ ! -r "$FILE_SRC_UPDT" ]; then
printf "Cannot read file $FILE_SRC_UPDT\n"
else
if diff -q "$FILE_SRC_ORIG" "$FILE_SRC_UPDT" > /dev/null; then
rm "$FILE_SRC_UPDT"
else
if [[ "$UPDATE_SRC" = "query" ]]; then
ask "Update source file?" && UPDATE_SRC="yes" || UPDATE_SRC="no"
fiif [[ "$UPDATE_SRC" = "yes" ]]; then
mv "$FILE_SRC_UPDT" "$FILE_SRC_ORIG"
printf "${C_INFO}Dynamic blocks and tables in \`$FILE_SRC_ORIG' successfully updated${C_RESET}\n"
else
printf "Nothing gets updated...\n"
fi
fi
fi
#+end_srcIn order to avoid "file changed on disk" messages (and be forced to revert
open buffers) when nothing changed, we save the file with another name, and
diff it with the original file. If there is no change, the new file is
dropped.#+begin_note
The time stamps in "Clock summary at ..." will be different, each time dynamic
blocks are updated (if not done during the same minute). In that case, =diff=
will always "succeed".
#+end_note** org-tangle
:PROPERTIES:
:header-args+: :shebang "#!/bin/sh\n" :tangle bin/org-tangle
:END:The =org-tangle= tangles an Org file.
#+begin_src shell
TARGET_EXT=
. orgmk-initeval $ORGMK $FILE_SRC_ORIG $ORGMK_UPDATE_FLAGS -f org-babel-tangle \
|| die "File wasn't tangled"
#+end_src* Orgmk
** Orgmk.mk
:PROPERTIES:
:header-args+: :tangle bin/orgmk.mk
:END:Here is the "ultimate" Makefile to *automate the generation of HTML or PDF*
versions from your Org mode files.It is designed to solve tedious tasks nicely, such as updating:
- [X] table of contents,
- [X] cross-references,
- [ ] index,
- [ ] list of figures,
- [ ] BibTeX references,
- [X] Org dynamic blocks,
- [X] tables with formulas, and
- [ ] extracting (tangle) code blocks.*************** TODO Test whether Orgmk works with symbolic links
Does their modification time change to reflect the latest modification of the
source?
*************** END*** Some system-dependent stuff
#+begin_src makefile
### -*- Makefile -*- definition file for Orgmk
#+end_src**** Default shell
#+begin_src makefile
SHELL = /bin/sh
#+end_src**** Exportation scripts
By default, the =orgmk.mk= will overwrite the Org source file if it has changed
after dblocks update and tables re-computation.#+begin_src makefile
ORG2_FLAGS=-yORG2HTML=org2html $(ORG2_FLAGS)
ORG2PDF=org2pdf $(ORG2_FLAGS)
#+end_src**** Viewing stuff
#+begin_src makefile
VIEW_HTML ?= firefox
VIEW_PDF ?= xpdf
#+end_src**** Color output
#+begin_src makefile :tangle no
ifdef NO_COLOR
tput =
else
tput = $(shell $(TPUT) $1)
endifblack := $(call tput,setaf 0)
red := $(call tput,setaf 1)
green := $(call tput,setaf 2)
yellow := $(call tput,setaf 3)
blue := $(call tput,setaf 4)
magenta := $(call tput,setaf 5)
cyan := $(call tput,setaf 6)
white := $(call tput,setaf 7)
bold := $(call tput,bold)
uline := $(call tput,smul)
reset := $(call tput,sgr0)
#+end_src#+begin_src makefile
C_INFO="\\e[32m"
C_WARNING="\\e[35m"
C_SUCCESS="\\e[1\;32m"
C_FAILURE="\\e[1\;31m"
C_RESET="\\e[0m"
#+end_src*** Basic configuration
**** Org Sources
Discover and process all Org files in the current directory (or in the current
subtree).#+begin_src makefile
ifeq ($(ALLSUBDIRS),yes)
TXT_FILES=$(shell find . -name \*.txt)
ORG_FILES=$(shell find . -name \*.org)
HTML_FILES=$(shell find . -name \*.html)
PDF_FILES=$(shell find . -name \*.pdf)
else
TXT_FILES=$(shell find . -maxdepth 1 -name \*.txt)
ORG_FILES=$(shell find . -maxdepth 1 -name \*.org)
HTML_FILES=$(shell find . -maxdepth 1 -name \*.html)
PDF_FILES=$(shell find . -maxdepth 1 -name \*.pdf)
endifFILES_TO_TANGLE := $(join $(ORG_FILES), $(TXT_FILES))
#+end_src*************** TODO Add Org_DIRS defaulting to .
Use Org_DIRS with foreach (?) in the following lists
*************** END*************** TODO Fix problem of Orgfile with .org/.txt extension
If an Org file exists with the 2 file extensions =.txt= and =.org= (same base
name), then we get messages such as:Makefile:102: warning: overriding recipe for target `plot.html'
Makefile:89: warning: ignoring old recipe for target `plot.html'
*************** END**** HTML Targets
List of HTML files which can be generated:
#+begin_src makefile
HTML_FILES_FROM_ORG = $(patsubst %.org,%.html,$(ORG_FILES))
HTML_FILES_FROM_TXT = $(patsubst %.txt,%.html,$(TXT_FILES))
#+end_srcList of HTML files to be re-generated (if they have an Org counterpart):
#+begin_src makefile
CUR_HTML_FILES := $(HTML_FILES)
#+end_src**** PDF Targets
List of PDF files which can be generated:
#+begin_src makefile
PDF_FILES_FROM_ORG = $(patsubst %.org,%.pdf,$(ORG_FILES))
PDF_FILES_FROM_TXT = $(patsubst %.txt,%.pdf,$(TXT_FILES))
#+end_srcList of PDF files to be re-generated (if they have an Org counterpart):
#+begin_src makefile
CUR_PDF_FILES := $(PDF_FILES)
#+end_src**** Debugging
#+begin_src makefile
# turn command echo'ing back on with VERBOSE=1
ifndef VERBOSE
QUIET := @
endif
#+end_src*Everything* is echo'ed, even =$(shell ...)= invocations:
#+begin_src makefile
# turn on shell debugging with SHELL_DEBUG=1
ifdef SHELL_DEBUG
SHELL += -x
endif
#+end_src**** Commands
Define variables for each command used in targets:
#+begin_src makefile
PRINTF=$(QUIET)printf
EGREP=$(QUIET)grep -E
LS=$(QUIET)ls
#+end_src*** All
#+begin_src makefile
.PHONY: all
all: html pdf # Regenerate all HTML and PDF files
#+end_src*** Help
Get help.
#+begin_src makefile
.PHONY: help
help: # Display callable targets
$(PRINTF) "Usage: orgmk [OPTION]... [TARGET]...\n" > /dev/stderr
$(PRINTF) "\n"
$(PRINTF) "What target do you want?\n" > /dev/stderr
$(EGREP) "^[^ #A-Z]+:" [Mm]akefile \
| sed 's/:[^#]*//' | sed 's/^/\n/g' | sed 's/# /\n\t/g' > /dev/stderr
#+end_src*** HTML
=orgmk html= will regenerate all HTML files which *currently exist* in the
directory, and whose source Org file has changed.#+begin_src makefile
.PHONY: html
html: $(CUR_HTML_FILES) # Regenerate all HTML documents from Org
#+end_srcTo create an HTML file for the *first time*, type =orgmk file.html=. It will
ignore other Org files in the directory.#+begin_src makefile
$(HTML_FILES_FROM_ORG): %.html: %.org # Export an Org document to HTML
<>$(HTML_FILES_FROM_TXT): %.html: %.txt # Export an Org document to HTML
<>
#+end_srcThe recipe to *convert Org to HTML* is:
#+name: recipe-convert-to-html
#+begin_src makefile :tangle no
$(PRINTF) "$(C_INFO)Exporting \`$(CURDIR)/$<' to HTML...$(C_RESET)\n"
$(ORG2HTML) $<
$(LS) -l -t $< $@ | head -n 1 | grep -E "\.html" > /dev/null \
|| { printf "$(C_FAILURE)\`$(CURDIR)/$@' is NOT up to date$(C_RESET)\n"; exit 1; }
$(PRINTF) "$(C_SUCCESS)\`$(CURDIR)/$@' successfully generated$(C_RESET)\n"
#+end_srcWhat about =org-export-as-html-batch= and =org-export-as-html-and-open=?
#+begin_src makefile
view-html: # Generate the HTML files, then show the result
#+end_src=orgmk pdf= will find out which PDF files have to be regenerated, and will
regenerate all of them.#+begin_src makefile
.PHONY: pdf
pdf: $(CUR_PDF_FILES) # Regenerate all PDF documents from Org
#+end_srcType =orgmk file.pdf= to generate only the specified PDF file.
#+begin_src makefile
$(PDF_FILES_FROM_ORG): %.pdf: %.org # Export an Org document to PDF
<>$(PDF_FILES_FROM_TXT): %.pdf: %.txt # Export an Org document to PDF
<>
#+end_src#+begin_note
The drawback of updating the dblocks inside the the recipes for HTML and PDF
means that, if we have a file that's *converted to both file formats*, the
update will be done twice (so, once at least for nothing): once for HTML, then
once again for PDF. Though, this case is quite uncommon.
#+end_noteThe recipe to *convert Org to PDF* is:
#+name: recipe-convert-to-pdf
#+begin_src makefile :tangle no
$(PRINTF) "$(C_INFO)Exporting \`$(CURDIR)/$<' to PDF...$(C_RESET)\n"
$(ORG2PDF) $<
$(LS) -l -t $< $@ | head -n 1 | grep -E "\.pdf" > /dev/null \
|| { printf "$(C_FAILURE)\`$(CURDIR)/$@' is NOT up to date$(C_RESET)\n"; exit 1; }
$(PRINTF) "$(C_SUCCESS)\`$(CURDIR)/$@' successfully generated$(C_RESET)\n"
#+end_src*************** TODO Export as LaTeX?
Maybe the export should be done to TeX, and then call (the minimum number of
times) PDFLaTeX from the =orgmk.mk=? Check out if this is as robust as using Org
to build the PDF... (which goes on, even with some errors occurring)
*************** ENDI've observed cases where =orgmk pdf= was reporting that "Exporting to
PDF...done", but I was left with the previous PDF file. Hence, every call to
=orgmk= tried to redo them...On deleting the PDF, and relaunching =orgmk= on that file, I had an error
during the "Processing LaTeX file".Workaround, to be sure that an old PDF does not stay in the way, remove the
PDF output upon startup of the recipe. The TeX file was well updated. Hence,
no need to delete it at startup...*Problem*: when the PDF file is not generated anymore, it won't be remade with
=orgmk pdf=. We then have to explicitly =orgmk file.pdf=.*** Clean
#+begin_src makefile
.PHONY: clean
clean: # Delete all temporary files created by Org export
#+end_src*** TODO Orgmk init file
Here, we should *make a symlink*, if it does not exist yet. Would then be used
just once...The only thing that's not done yet automatically is: tangling this file!
*** Footer
#+begin_src makefile
### orgmk.mk ends here
#+end_src** Makefile wrapper
:PROPERTIES:
:header-args+: :tangle bin/orgmk :shebang "#!/bin/sh\n"
:END:As you could want to run the batch scripts from a (development) directory
where there is already a ~Makefile~, you must install the ~Makefile~ under a
different name: ~orgmk.mk~.An addition is to create a symbolic link to the ~orgmk.mk~ into the
directory of your Org files just for the duration of the script execution
(on-the-fly install). The links can be safely removed after =make= has been run.#+begin_src shell
Usage ()
{
cat << EOF 1>&2
Usage: $(basename $0) [OPTION] FILE
Export Org source files whenever they are updated.-h, --help display this help and exit
-r, --recursive export all Org files under each directory, recursivelyReport $(basename $0) bugs to [email protected]
EOF
exit 1
}
#+end_src#+begin_src shell
CleanUp ()
{
# remove the Makefile
rm orgmk.mk
}# perform housekeeping on program exit or a variety of signals
# (EXIT, HUP, INT, QUIT, TERM)
trap CleanUp 0 1 2 3 15
#+end_src#+begin_src shell
# install the Makefile where you are
orgmk-stow-orgmk.mkFLAGS=""
while true; do
case "$1" in
-h | --help ) Usage ;;
-r | --recursive) FLAGS="ALLSUBDIRS=yes"; shift ;;
,* ) break ;;
esac
donemake -f orgmk.mk $FLAGS $*
#+end_src* Orgmk configuration file
:PROPERTIES:
:header-args+: :tangle site-lisp/orgmk.el
:END:I use a setup file =orgmk.el= to hold minimal customization.
#+begin_info
In batch mode, [...] Emacs functions that normally print a message in the echo
area will print to either the standard output stream (=stdout=) or the standard
error stream (=stderr=) instead. (To be precise, functions like =prin1=, =princ= and
=print= print to =stdout=, while =message= and =error= print to =stderr=.)
#+end_info** Common
#+begin_src emacs-lisp
;;; orgmk.el --- Emacs configuration file for `orgmk';;; Commentary:
;;; Code:
#+end_src*** Library Search
Remember current directory.
#+begin_src emacs-lisp
;; remember this directory
(defconst orgmk-el-directory
(file-name-directory (or load-file-name (buffer-file-name)))
"Directory path of Orgmk.")
#+end_src*** Feedback
#+begin_src emacs-lisp
;; ;; activate debugging
;; (setq debug-on-error t);; no limit when printing values
(setq eval-expression-print-length nil)
(setq eval-expression-print-level nil)
#+end_src*** Auto Save
#+begin_src emacs-lisp
;; don't make a backup of files
(setq backup-inhibited t)
#+end_src*** Initialization for MS Windows
When running an native Microsoft Windows version of Emacs:
#+begin_src emacs-lisp
;; ;; let Emacs recognize Cygwin paths (e.g. /usr/local/lib)
;; (add-to-list 'load-path "~/Downloads/emacs/site-lisp") ;; <- adjust
;; (when (eq system-type 'windows-nt)
;; (when (try-require 'cygwin-mount)
;; (cygwin-mount-activate)))
#+end_src*** Shell
Fix the shell to use: the *default value of shell-file-name* (that is the
program =/bin/bash=) is not found under Windows Emacs.#+begin_src emacs-lisp
;; shell
(message "Current value of `shell-file-name': %s" shell-file-name)
(unless (equal shell-file-name "bash")
(setq shell-file-name "bash")
(message "... changed to: %s" shell-file-name))
#+end_srcThis is important when launching external tools, such as ~PDFLaTeX~ or ~Latexmk~.
*** Installation of version 8 or later
Ensure that a recent version of Org mode is installed and loaded.
#+begin_src emacs-lisp
(when (locate-library "package")
(require 'package)
(add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/"))
(add-to-list 'package-archives '("melpa" . "http://melpa.milkbox.net/packages/"))
(package-initialize)
(unless package-archive-contents
(package-refresh-contents)))
#+end_src#+begin_src emacs-lisp
(unless (locate-library "ox") ; trick to detect the presence of Org 8
(ding)
(message "The versions 6 and 7 of Org mode are no longer supported")
(message "Time to upgrade, don't you think?")
(when (locate-library "package")
(let ((pkg 'org-plus-contrib))
(if (yes-or-no-p (format "Install package `%s'? " pkg))
(ignore-errors
(package-install pkg))
(setq debug-on-error nil)
(error "Please upgrade to 8 or later")))))
#+end_src#+begin_src emacs-lisp
(when (locate-library "package")
(unless (locate-library "htmlize") ; for syntax highlighting in org2html
(let ((pkg 'htmlize))
(if (yes-or-no-p (format "Install package `%s'? " pkg))
(ignore-errors
(package-install pkg)))))
(unless (locate-library "ox-gfm") ; for exporting to GFM
(let ((pkg 'ox-gfm))
(if (yes-or-no-p (format "Install package `%s`? " pkg))
(ignore-errors
(package-install pkg)))))
;; (unless (locate-library "ox-reveal") ; for exporting to Reveal
;; (let ((pkg 'ox-reveal))
;; (if (yes-or-no-p (format "Install package `%s`? " pkg))
;; (ignore-errors
;; (package-install pkg)))))
)
#+end_src#+begin_src emacs-lisp
;; version info
(let ((org-install-dir (file-name-directory (locate-library "org-loaddefs")))
(org-dir (file-name-directory (locate-library "org")))) ; org.(el|elc)
(message "Org mode version %s (org @ %s)"
(org-version)
(if (string= org-dir org-install-dir)
org-install-dir
(concat "mixed installation! " org-install-dir " and " org-dir))))
#+end_src*** Activation
#+begin_src emacs-lisp
(require 'org)
(require 'org-clock)
(require 'ox)
;; (require 'ox-reveal)(add-to-list 'auto-mode-alist '("\\.txt\\'" . org-mode))
#+end_src*** Language Environment
#+begin_src emacs-lisp
;; make sure that timestamps appear in English
(setq system-time-locale "C") ; [default: nil]
#+end_src*** Clock table
#+begin_src emacs-lisp
;; format string used when creating CLOCKSUM lines and when generating a
;; time duration (avoid showing days)
(setq org-time-clocksum-format
'(:hours "%d" :require-hours t :minutes ":%02d" :require-minutes t));; format string for the total time cells
(setq org-clock-total-time-cell-format "%s");; format string for the file time cells
(setq org-clock-file-time-cell-format "%s")
#+end_src*** Markup
#+begin_src emacs-lisp
;; hide the emphasis marker characters
(setq org-hide-emphasis-markers t) ; impact on table alignment!
#+end_src*** Export options
#+begin_src emacs-lisp
;; don't insert a time stamp into the exported file
(setq org-export-time-stamp-file nil);; activate smart quotes during export (convert " to \og, \fg in French)
(setq org-export-with-smart-quotes t) ; curly quotes in HTML;; interpret "_" and "^" for export when braces are used
(setq org-export-with-sub-superscripts '{});; allow #+BIND to define local variable values for export
(setq org-export-allow-bind-keywords t)
#+end_src*** Org-Babel
#+begin_src emacs-lisp
;; configure Babel to support most languages
(add-to-list 'org-babel-load-languages '(R . t)) ; Requires R and ess-mode.
(add-to-list 'org-babel-load-languages '(awk . t))
(add-to-list 'org-babel-load-languages '(ditaa . t)) ; Sudo aptitude install openjdk-6-jre.
(add-to-list 'org-babel-load-languages '(dot . t))
(add-to-list 'org-babel-load-languages '(java . t))
(add-to-list 'org-babel-load-languages '(perl . t))
(add-to-list 'org-babel-load-languages '(latex . t)) ; Shouldn't you use #+begin/end_latex blocks instead?
(add-to-list 'org-babel-load-languages '(ledger . t)) ; Requires ledger.
(add-to-list 'org-babel-load-languages '(makefile . t))
(add-to-list 'org-babel-load-languages '(org . t))
(if (locate-library "ob-shell") ; ob-sh renamed on 2013-12-13
(add-to-list 'org-babel-load-languages '(shell . t))
(add-to-list 'org-babel-load-languages '(sh . t)))
(add-to-list 'org-babel-load-languages '(sql . t))(org-babel-do-load-languages ; loads org, gnus-sum, etc...
'org-babel-load-languages org-babel-load-languages);; accented characters on graphics
(setq org-babel-R-command
(concat org-babel-R-command " --encoding=UTF-8"));; don't require confirmation before evaluating code blocks
(setq org-confirm-babel-evaluate nil)
#+end_src*** Library of Babel
#+begin_src emacs-lisp
;; load up Babel libraries
(let ((lob-file (concat (file-name-directory (locate-library "org"))
"../doc/library-of-babel.org")))
(when (file-exists-p lob-file)
(org-babel-lob-ingest lob-file)))
#+end_src** HTML export
*************** TODO Understand the hidden xx used for spacing levels in column views
Depending on interactive vs batch export to HTML, we still have the above
difference in the resulting HTML file.
*************** END#+begin_src emacs-lisp
(when (require 'ox-html);; export the CSS selectors only, when formatting code snippets
(setq org-html-htmlize-output-type 'css);; ;; XML encoding
;; (setq org-html-xml-declaration
;; '(("html" . "")));; coding system for HTML export
(setq org-html-coding-system 'utf-8);; ;; format for the HTML postamble
;; (setq org-html-postamble
;; "")\n Copyright © %d %a\n;; don't include the JavaScript snippets in exported HTML files
(setq org-html-head-include-scripts nil);; turn inclusion of the default CSS style off
(setq org-html-head-include-default-style nil)(defun org-html-export-body-only-to-html ()
"Export only code between between \"\" and \"\" tags to a HTML file."
(interactive)
(org-html-export-to-html nil nil nil t)))
#+end_src** PDF LaTeX export
*************** TODO Since [2012-10-26 Fri], the %b now means the real base name (no full part).
*************** END#+begin_src emacs-lisp
(when (require 'ox-latex);; ;; This is disturbing when calling `org2html'.
;; (when (executable-find "latexmk")
;; (message "%s" (shell-command-to-string "latexmk --version")))(setq org-latex-pdf-process
(if (eq system-type 'cygwin) ;; running a Cygwin version of Emacs
;; use Latexmk (if installed with LaTeX)
(if (executable-find "latexmk")
'("latexmk -CF -pdf $(cygpath -m %f) && latexmk -c")
'("pdflatex -interaction=nonstopmode -output-directory=%o $(cygpath -m %f)"
"pdflatex -interaction=nonstopmode -output-directory=%o $(cygpath -m %f)"
"pdflatex -interaction=nonstopmode -output-directory=%o $(cygpath -m %f)"))
(if (executable-find "latexmk")
'("latexmk -CF -pdf %f && latexmk -c")
'("pdflatex -interaction=nonstopmode -output-directory=%o %f"
"pdflatex -interaction=nonstopmode -output-directory=%o %f"
"pdflatex -interaction=nonstopmode -output-directory=%o %f"))))(message "LaTeX command: %S" org-latex-pdf-process)
;; tell org to use `listings' (instead of `verbatim') for source code
(setq org-latex-listings t);; default packages to be inserted in the header
;; include the `listings' package for fontified source code
(add-to-list 'org-latex-packages-alist '("" "listings") t);; include the `xcolor' package for colored source code
(add-to-list 'org-latex-packages-alist '("" "xcolor") t);; include the `babel' package for language-specific hyphenation and
;; typography
(add-to-list 'org-latex-packages-alist '("english" "babel") t);; default position for LaTeX figures
(setq org-latex-default-figure-position "!htbp")(defun org-latex-export-body-only-to-latex ()
"Export only code between \"\begin{document}\" and \"\end{document}\" to a LaTeX file."
(interactive)
(org-latex-export-to-latex nil nil nil t)))
#+end_src** Extra customization files
To allow you to easily add extra settings to the above "standard" ones, you can
create several files in the =lisp= directory. All of them will be loaded at the
end of =orgmk='s initialization.#+begin_src emacs-lisp
;; require all files from `lisp' directory
(dolist (file (directory-files
(concat orgmk-el-directory "../lisp/") t ".+\\.elc?$"))
(load-file file))
#+end_src#+begin_src emacs-lisp
;;; orgmk.el ends here
#+end_src* Sample parameters
** Custom LaTeX classes
:PROPERTIES:
:header-args+: :tangle lisp/org-latex-classes.el
:END:#+begin_src emacs-lisp
;;; org-latex-classes.el --- Sample configuration file for LaTeX;;; Commentary:
;;; Code:
(require 'ox-latex)
(add-to-list 'org-latex-classes
'("koma-article"
"\\documentclass{scrartcl}
[NO-DEFAULT-PACKAGES]
[EXTRA]"
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
("\\subparagraph{%s}" . "\\subparagraph*{%s}")));;; org-latex-classes.el ends here
#+end_src* Contributing
** Issues
Report issues and suggest features and improvements on the [[https://github.com/fniessen/orgmk/issues/new][GitHub issue tracker]].
** Patches
I love contributions! Patches under any form are always welcome!
** Donations
If you like the Orgmk project, you can show your appreciation and help support
future development by making a [[https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=VCVAS6KPDQ4JC&lc=BE&item_number=orgmk¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHosted][donation]] through PayPal.Regardless of the donations, Orgmk will always be free both as in beer and as in
speech.* License
Copyright (C) 2011-2021 Fabrice Niessen
Author: Fabrice Niessen \\
Keywords: org mode export automationThis program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.You should have received a copy of the GNU General Public License along with
this program. If not, see http://www.gnu.org/licenses/.* Standard disclaimer
I am furnishing this item "as is". I do *NOT* provide *ANY WARRANTY* of the item
whatsoever, whether express, implied, or statutory, including, but not limited
to, any warranty of *MERCHANTABILITY* or *FITNESS FOR A PARTICULAR PURPOSE* or any
warranty that the contents of the item will be error-free.In no respect shall I incur any liability for any damages, including, but
limited to, direct, indirect, special, or consequential damages arising out of,
resulting from, or any way connected to the use of the item, whether or not
based upon warranty, contract, tort, or otherwise; whether or not injury was
sustained by persons or property or otherwise; and whether or not loss was
sustained from, or arose out of, the results of, the item, or any services that
may be provided by me.# This is for the sake of Emacs.
# Local Variables:
# before-save-hook: nil
# End:# README.org ends here