Skip to content

Instantly share code, notes, and snippets.

@rbf
Last active March 28, 2024 08:04
Show Gist options
  • Save rbf/6064734 to your computer and use it in GitHub Desktop.
Save rbf/6064734 to your computer and use it in GitHub Desktop.
Script to recursively generate PDF files from markdown files in the current directory and its subfolders using "pandoc".

%process-md % https://gist.github.com/rbf/6064734

Description

process-md is a bash tool to recursively generate files from markdown files in other formats using pandoc, which is assumed installed. By default (i.e. calling command tool with no arguments) it processes all markdown files in the current directory and places the resulting PDF files in a ./target directory.

Note: The program code aims also to be one example of bash scripting, so that I can use it as reference for several code snippets.

You might find more information about process-md and the up-to-date version of this documentation in the URL mentioned in the title of this document.

Installation

This tool has been developed and tested on a Mac running following version of bash:

$ bash --version
GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin12)
Copyright (C) 2007 Free Software Foundation, Inc.

However it might work on other *nix platforms with no or little modifications.

Before you begin

Mac

CentOS

  • Install pandoc

    • Add EPEL yum repo:

      rpm -Uvh http://dl.fedoraproject.org/pub/epel/6/x86_64/\
      epel-release-6-8.noarch.rpm
    • Install pandoc package:

      yum install -y pandoc
  • Install TeXLive, to generate PDF files

    • Packaged installation with yum:

      yum install -y texlive-xetex texlive-latex

      As of this writing, the TeXLive package available for CentOS 6.4 via yum is quite outdated (version 2007) and process-md will not work, since some more recent packages are used. To install a recent version of the TeXLive package, it is recommended to use instead the manual installation described below. This manual installation takes, however, much longer to complete.

    • Manual installation from TeXLive website:

      TEXLIVE_TMP_DIR=$(mktemp --directory --tmpdir texlive_install_XXXXX);
      TEXLIVE_TMP_FILENAME="package-install-tl-unx.tar.gz";
      curl -L http://mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz -o ${TEXLIVE_TMP_DIR}/${TEXLIVE_TMP_FILENAME};
      (cd ${TEXLIVE_TMP_DIR}; tar -xvf ${TEXLIVE_TMP_FILENAME});
      ${TEXLIVE_TMP_DIR}/install-tl*/install-tl;

      This should start the installer. From there you can select the options you want to install. You might choose among several schemes (i.e. different sets of \TeX\ packages). The default is the full scheme, which requires some 3 GB of disk space as of this writing, and might take quite long to install. To proceed with the install of this full scheme press i and enter. To install the medium scheme (the minimal required for the options used in process-md) change the installation with s, enter, b, enter, r, enter and start the installation with i and enter.

      If there is not other \TeX\ installation in your system, you might instruct the previous installer to create the necessary links of the binaries so that they can be directly used. For that, modify the configuration before starting the installation with o, enter, l, enter, r, enter and start the installation with i and enter.

      An alternative is to manually add the needed directories to your system's path, as detailed in the documentation:

      cat << EOF > /etc/profile.d/texlive-paths.sh
      PATH=/usr/local/texlive/2013/bin/i386-linux:$PATH; export PATH;
      MANPATH=/usr/local/texlive/2013/texmf-dist/doc/man:$MANPATH; export MANPATH;
      INFOPATH=/usr/local/texlive/2013/texmf-dist/doc/info:$INFOPATH; export INFOPATH;
      EOF

      In the TeXLive website you will find the full documentation about this installation of TeXLive.

Install process-md

To install an executable copy of the process-md tool in your system, you can make a copy of the last released (i.e. stable) version of the script (currently v2.4 into your /usr/local/bin directory and make it executable.

You can perform the installation described above by hand or executing following command, which will perform all steps automatically:

bash <(curl -sSL https://gist.github.com/rbf/6064734/raw/install)

Usage

The command without any options or parameters will already do a hopefully sensible thing: All .md and .markdown files in the current directory will be converted in PDF in the ./target directory. You can directly to try:

  $ process-md

To learn available options and parameters you can read the help text or the program code itself:

  $ process-md --help

The main usage pattern is the following:

  $ process-md [options] [<path-pattern> [<target-path>]]

Options

-b, --bulk

Allow to process more than 10 files. This is a security to avoid triggering this command by error on a directory with lots of subdirectories like / or ~.

--doc

Generate Word files for each Markdown file. Equivalent to -- output=doc.

--doctor, --verify-installation

Performs a check to verify that the process-md is correctly installed, and that the required tools are also available.

-d, --date-files

Prefix generated files with the current date (i.e. adds %Y%m%d_ at the beginning of the output filename pattern).

--example

Downloads an example Markdown document from https://gist.github.com/rbf/6064734 locally so that you can apply process-md on it to better understand how Markdown works.

-f, --flat

Gather all generated files into the target directory, without replicating the original subfolder structure.

-F, --path-name

Include the original path of the Markdown files in the generated file, to avoid name clashes when gathering all files in the target directory. Implies --flat.

-h, --help

Print this help and exit. Other parameters and options are ignored.

--html

Generate HTML files for each Markdown file. Equivalent to -- output=html.

-l=<factor>, --linespacing=<factor>

Specify the linespacing factor of the PDF output (using the 'setspace' package). The factor must be any number between 0.1 and 9.9. Following synomyns are also accepted:

  • single, for 1
  • light, for 1.2
  • spaced, for 1.5
  • double, for 2

Defaults to single.

--language=<language>[,<language>...]

Specify the languages of the resulting file. It is mainly used for PDF generation, using the babel package. Therefore, valid values are: afrikaans, bahasa, breton, catalan, croatian, czech, danish, dutch, english, USenglish, american, UKenglish, estonian, finnish, french, francais, galician, austrian, german, germanb greek, hebrew, magyar, hungarian, irish, italian, lowersorbian, norsk, nynorsk, polish, portuges, portuguese, brazilian, brazil romanian, russian, scottish, spanish, slovak, slovene, swedish, turkish, uppersorbian, welsh. By default 'english' is used if nothing else is specified.

--links-as-notes

Make footnotes with URL of external links when possible (e.g. PDF, HTML). Note: this will fail if there are links in section titles.

-m, --omit-version

If the original Markdown files are in a git repository, by default the git version (as in git describe --always) is included in the filename and as a subtitle in generated PDF files. This flag overrides this behaviour so that the git version is not shown.

-n, --dry-run

Only list what files would be generated with the given parameters without actually generating any files.

--output=<format>[,<format>...]

Specify which files should be generated for each Markdown file. Valid values are '--ouput=pdf,word,openoffice,html' and some synonyms: 'doc' and 'docx' are synonims of 'word'; 'odt' is synonym of 'openoffice'. By default 'pdf' is generated if nothing else is specified.

-o, --open-target-folder

[Mac OS X only] After successful generation, open the target folder in Finder.

-O, --open-files

[Mac OS X only] After successful generation, open the generated files in the default application. If more than 10 files would open, this will fall back to --open-target-folder to avoid issues with the operating system.

--odt

Generate OpenOffice files for each Markdown file. Equivalent to --output=odt.

-p=<format>, --output-filename-pattern=<format>

Pattern for the basename part of the generated files. The extension will be appended for each type of output file. No spaces might be used in the pattern.

By default the generated files have the same basename than their original Markdown files with the git version of the file as suffix, if their are in a git repository (i.e. by default -p=%f_%v or -p=%f). Following parameters are recognized:

  • %f: Original file basename
  • %v: Git version (as in git describe --always) if any, or blank
  • %n: Counter (Use %0xn for a counter padded with x number of zeros)
  • %a: Short date (Sun)
  • %A: Long date (Sunday)
  • %b: Short Month (Feb)
  • %B: Long Month (February)
  • %d: Day of the month
  • %H: Hour in 24 hour format (00..23)
  • %I: Hour in 12 hour format (01..12) (see %p)
  • %j: Day of the year
  • %m: Month in number format (01..12)
  • %M: Minute (00..59)
  • %p: Locale either AM or PM
  • %S: Second (00..59)
  • %u: Day of the week
  • %V: Week number of year with Monday as first day of week (01..53)
  • %Y: Year (2013)
  • %z: Numeric timezone (+0100)
  • %Z: Timezone abbreviation. (CET)

--pdf

Generate PDF files for each Markdown file. Equivalent to -- output=pdf.

-r, --recursive

By default only Markdown files in the current directory are processed. This flag forces the processing of all Markdown files in the current directory and its subdirectories (up to a max depth of 12 levels).

--uninstall

Delete the script from /usr/local/bin and exit. Other parameters and options are ignored.

--update

Update the script installed in /usr/local/bin and exit. Other parameters and options are ignored.

-v, --version

Print the version of the script and related tools and exit. Other parameters and options are ignored.

Examples

$ process-md All .md and .markdown files in the current directory are converted in PDF in the ./target directory.

$ process-md -r All .md and .markdown files in the current directory and its subdirectories are converted in PDF in the ./target directory, maintaining its original sub-folder structure.

$ process-md api All .md and .markdown files in the current directory containing "api" (case sensitive) in the file name are converted in PDF in the ./target directory.

$ process-md -r ./doc/*a All .md and .markdown files in the "doc/" subdirectory and its subdirectories containing "a" (case sensitive) in the file name or the path are converted in PDF in the ./target directory, maintaining its original sub-folder structure.

$ process-md api pdf-files All .md and .markdown files in the current directory containing "api" (case sensitive) in the file name are converted in PDF in the ./pdf-files.

Help

For more info and other examples read the command help:

  $ process-md --help

Extras

Sublime Text 2 Build System

Adding a build system definition for "Sublime Text 2" to call process-md allows to easily produce PDF documents from the current Markdown file using pdftex via pandoc with the keystroke cmd-B. And well, that's handy.

To install this build definition, you have to copy the file Generate PDF.sublime-build into your settings folder for "Sublime Text 2", which in most cases is:

"~/Library/Application Support/Sublime Text 2/Packages/User/"

You can directly install the build system definition in your "Sublime Text 2" settings with following option:

  $ process-md --install-sublimetext2-build-system

Change log

v2.5 (17nov2013) {-}

  • [new] Add exhaustive documentation about available options in README file (and corresponding generated PDF documentation).
  • [new] Add a --example option to download a Markdown example file.
  • [new] Add --linespacing (aka -l) option. The factor must be any number between 0.1 and 9.9 or a synonym ('single', 'light', 'spaced' or 'double').
  • [bugfix] Check if user has write permission in /usr/local/bin.
  • [change] Fix typos in --help output.

v2.4 (15nov2013) {-}

  • [new] Append '+' to filenames generated on a dirty git repo, to avoid overwriting a file generated on a clean tagged repo.
  • [new] Add colored output when running in a terminal, removing the [INFO], [WARN] and [ERROR] line prefixes. When running through a pipe (into a file, or process-md | grep something) colors are disabled and the line prefixes brought back.
  • [new] Include timing information on results.
  • [new] Include documentation for manual installation of TeXLive for CentOS.
  • [new] Update README with instructions to manually install process-md
  • [new] Add URL reference to up-to-date documentation.
  • [bugfix] Fix dates of releases v2.3 and v2.3.1 in changelog.
  • [bugfix] Output filename format was not taken into account when --path-name option given.

v2.3.1 (11nov2013) {-}

  • [new] Include documentation for required packages for CentOS.
  • [bugfix] Fix order of find command parameter on CentOS.

v2.3 (11nov2013) {-}

  • [change] Update to new URL format used by GitHub for raw files.
  • [bugfix] Fix error on subtitle footnote when original files had one or more underscore chars in the file name.
  • [bugfix] Word 'and' appeared innecessarily under some conditions on the subtitle footnote.

v2.2 (02sep2013) {-}

  • [change] Enhance update functionality.
  • [new] Add install script pointing always to the last released version.
  • [new] Add --date-files (aka -d) option to prefix generated files with the current date.
  • [new] Add --omit-version (aka -m) option to omit the git version from the PDF subtitle and the filename.
  • [new] Add option --install-sublimetext2-build-system.
  • [new] Add --doctor option (aka --verify-installation).
  • [change] Enhance check for pdftex and pandoc.
  • [change] Only check for pdftex if PDF generation required.
  • [change] Rename Generate\ PDF.sublime-build into generate PDF.sublime-build to make README appear at the top of the gist page.

v2.1.1 (14aug2013) {-}

  • [bugfix] Fix command in README to install Sublime Text 2 build system.
  • [change] Update README with enhanced command to verify that install dir /usr/local/bin exists and is writable.
  • [new] Add command in README to create install dir /usr/local/bin and make it writable.

v2.1 (13aug2013) {-}

  • [new] Add Sublime Text 2 build definition and variants.
  • [new] Enhance pandoc options to produce better PDF documents.
  • [new] Add language support with option --language, used for PDFs files via babel package.
  • [new] Add --open-target-folder (-o) and --open-files (-O) options.
  • [new] Add git version description in subtitle for PDF documents (i.e. the last git tag), if the original Markdown file is in a git repository. Warn with a footnote form the subtitle if the repo was dirty on PDF generation.
  • [new] By default, include git version (i.e. the last git tag) of the file in the filename for generated files, if the original Markdown files are in a git repository..
  • [new] Add --html shortcut.
  • [new] Add option --output-filename-pattern (-p) to define a filename pattern for generated files.
  • [change] PDF documents: enhance image max height, and select DIV9 instead of DIVcalc.
  • [change] Make --links-as-notes option not active by default, since it might fail in some cases, e.g. when there are links in section titles, like this current README.md file. :)

v2.0.2 (29jul2013) {-}

  • [bugfix] Fix error on install path.
  • [new] Add -SNAPSHOT versioning.
  • [new] Ignore -SNAPSHOT versions when updating.
  • [new] Check for pdftex existence.
  • [new] Add pdftex to version check.
  • [change] Enhanced command name on help hint when using the CURL'ed version. Now is uses the real curl command.

v2.0.1 (29jul2013) {-}

  • [new] Add links for versions in README change log.
  • [change] Remove old command when updating (instead of renaming it to process-md.bak).
  • [change] Fix small typo on help hint: removed heading / in command name.

v2.0 (29jul2013) {-}

  • [change] Command renamed from generate-pdf to process-md.
  • [new] Support other output formats beyond PDF: docx, html, odt and epub.
  • [change] By default, now only the Markdown files in the current directory are processed. Add the option --recursive to process also the Markdown files in the subdirectories.
  • [change] More informative feedback when finishing.
  • [bugfix] Alert when no Markdown files are found.
  • Other small tweaks and fixes.

v1.3 (27jul2013) {-}

  • [new] Add --dyr-run option.
  • [new] Add --bulk option.
  • [new] Add --flat option.
  • [new] Add --path-name option.
  • [bugfix] Fix generation for files with spaces in path.
  • [new] Add one-letter synonims for common options.
  • [new] Allow chained one-letter options.
  • [change] Enhance help.

v1.2 (24jul2013) {-}

  • [new] Add check for version before updating.

v1.1 (24jul2013) {-}

  • [new] Add option to uninstall.

v1.0 (24jul2013) {-}

  • Initial released version.

v0.1 (23jul2013) {-}

  • Initial commit.

% Markdown meta-example document % (here comes the author name)

Introduction

This document is a self-referencing brief example of the Markdown format understood by the process-md tool. It is not only intended to explain the basics of the Markdown syntax, but also to provide a real example of it. It's intended to be read simultaneously in theMarkdown form (raw example.md file) and in one or several of its generated formats (PDF, HTML, rendering in GitHub...)

Apply process-md to this document

In order to better understand both the process-md tool and the Markdown syntax, we encourage you to download this file and apply process-md to it, and play around with the different formats and options.

Markdown

The process-md tool generates several output formats from source files written following John Gruber's Markdown syntax.

Markdown is designed to be easy to write, and, even more importantly, easy to read:

A Markdown-formatted document should be publishable as-is, as plain text, without looking like it’s been marked up with tags or formatting instructions. – John Gruber

Pandoc's Markdown

For reference, let's precise that, since the process-md tool uses the power of John MacFarlane's pandoc under the hood, we refer in this document always to the pandoc dialect of the Markdown syntax. You can find the complete reference of this Markdown dialect in the pandoc website.

Document header

The first two lines of the Markdown file might define the title and the author of the document. They are optional but, if present, they must appear at the very top of the file (i.e. without any blank line before) and each line must be introduced by a %-symbol.

Title

The title of the document is defined in the first line of the markdown file. It must be preceded by a %-symbol.

Author

The author of the document is defined in the second line of the markdown file (i.e. the title must be already present). It must be preceded by a %-symbol.

Sections

Sections of the document are introduced by a #-symbol and its title. This section title must be preceded and followed by at least one blank line.

Subsections

The number of #-symbols at the beginning of the (sub)section title defines the hierarchy of the section.

### Subsubsection

Only 5 subsection levels are supported.

Subsubsubsection

From the fourth level on, sections are rather handled as paragraphs.

Subsubsubsubsection

Mh... Do you really need this level of section?!

Table of contents

process-md will automatically add a table of contents with all sections up to the third level. The section titles in the tables of contents can be clicked in PDF and HTML output to directly go to the corresponding section.

Whitespace

In general, whitespace doesn't matter. The number of spaces between words is not relevant, as the line-breaks are not relevant. All this text will be in one only well-formatted paragraph.

To explicitly make a new paragraph, you must leave a blank line.

Like this.

And this. But not this: this will not create a new paragraph.

Text formatting

Italics

To emphasize some text using italics, you can surround it with single start (*) or underscore (_) symbols. For example, this text is emphasized in italics.

Bold

To stronger emphasize some text using a bold typeface, you can surround it with double start (**) or underscore (__) symbols. For example, this text is emphasized in bold.

Strikeout

To strikeout a section of text with a horizontal line, begin and end it with ~~. For example, this is deleted text.

^superscript^

Superscripts may be written by surrounding the superscripted text by ^ characters. For example, 2^10^ is 1024.

subscript

Subscripts may be written by surrounding the subscripted text by ~ characters. For example, H2O is a liquid at room temperature.

Links

Markdown allows to define links to an URL (website) or email address, which will be click-able in the resulting PDF or HTML document. For example, in this document we are referring to following sources:

The links can also be hidden behind a label. For example again, in this document we are referring to following sources:

Note: Using process-md, these external links will be written in blue and they will be click-able in PDF and HTML outputs. Adding the option --links-as-notes when using process-md to generate a PDF will make these external URLs be written in a footnote instead, making the destination URL explicitly visible, making it also useful when printing out the document.

Internal links

Links to other sections of the document can be also easily created using as link destination the (sub)section's title in lower case, removing all punctuation and replacing spaces with dashes and preceded by a #-symbol. For example, for the titles "Section" and "What do you think?", the reference would be #section and #what-do-you-think.

For example, we talk above about the Markdown flavor understood by Pandoc and below we show several examples of how to define lists in Markdown.

Note: Using process-md, these internal links will not have any special color, but they will be click-able in PDF and HTML outputs.

Images

Images can be inserted with a syntax similar to the one detailed above for the links, but beginning with an exclamation mark (!) and placed as an independent paragraph. In the second part of the image link (within parenthesis), the image filename must be given. To make things easy, the image file should exist next to the current Markdown file, i.e. in the same directory.

Sample image

In PDF files, images will not always appear where they are introduced. The engine to generate the PDFs (i.e. \LaTeX) will figure out where to place them, so that the document looks better. Small images like the one above might indeed appear inline, but bigger ones might appear in the next page.

Footnotes

Small footnotes can be easily created^[Simply like this.]. If the text of the footnote is very long1, it would not be convenient to write it in-line like the previous example, and it can be written later in the document.

By the way, the superscript footnote numbers are also click-able in the PDF an HTML outputs, to go directly to the corresponding footnote.

Quotes

Markdow uses the same (old) email convention to introduce quotations: lines beginning with a >-sign.

Be yourself; everyone else is already taken.

  • Oscar Wilde

To quote a whole paragraph, you might add only one >-sign at the beginning of the first line.

Twenty years from now you will be more disappointed by the things that you didn't do than by the ones you did do. So throw off the bowlines. Sail away from the safe harbor. Catch the trade winds in your sails. Explore. Dream. Discover. - H. Jackson Brown Jr.

Verbatim

To introduce text in a mono-spaced font and without interpreting all the Markdown formatting introduced here, the corresponding text must be surrounded with back-ticks (`). It is useful for special parts of the text like filenames, command names, URLs.

Verbatim blocks

To introduce a bigger block of text in this way, each line must begin with four spaces. Then, none of the Markdown syntax^[Emphasized text, lists, links, footnotes, etc...] will be interpreted, and will appear as written.

Then, _none_ of the [Markdown](#markdown) syntax^[Emphasized text,
lists, links, footnotes, etc...] will be interpreted, and will
appear as written.

The same effect might be reached opening and closing the verbatim paragraph with 3 back-ticks (`) or tildes (~).

The same effect might be reached opening and closing the verbatim
paragraph with 3 back-ticks (\`) or tildes (`~`).

Code blocks

Verbatim blocks are often used to introduce blocks of programming code. Syntax highlighting for a specific programming language can be enabled giving the name of the language after the opening set of back-ticks.

class Hallo {
  public static void main( String[] args ) {
    System.out.println("Hello world!");
  }
}

Lists

Lists are defined as you would naturally define a list:

  • First item
  • Second item

Following symbols might be used as bullets:

  • Minus sign, i.e. -
  • Plus sign, i.e. +
  • Star sign, i.e. *

Ordered lists

Lists beginning with numbers or letters followed by a point and at least one space define ordered lists:

  1. First item
  2. Second item

a. First item a. Second item

If using capital letters, at least two spaces are required after the point:

A. First item A. Second item

Only the starting item number (or letter) is relevant:

  1. Fifth item
  2. Sixth item

f. f-th item a. g-th item

Parenthesis might be used instead of the point:

  1. First item
  2. Second item

(1) First item (1) Second item

a) First item a) Second item

(a) First item (a) Second item

Capital and lower case roman numerals might be also used:

i. First item i. Second item

I. First item I. Second item

Sublists

A list item might contain oder lists or paragraphs provided they are intended with four spaces:

  1. First item

    • This is the first item of the sublist
    • This is the second item of the sublist
  2. Second item

    Here I can write even a whole paragraph inside this list item. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.

  3. And this is the third item

Example items

When defining a list, the special character @ might be used to define an item as an example.

@. One example, which will be numbered 1. @. Another example, which will be numbered 2.

Items of this type will have a continuous numeration across the whole document, even if they don't appear in the same list.

@. A third example, which will be numbered 3.

A label might also be defined, in order to refer to the example number somewhere else in the document, like in example @example. below.

@example. One example

And the whole thing works also with parenthesis, as illustrated in (@with-parenthesis) example below.

(@with-parenthesis) This is an example with parenthesis.

Tables

Pandoc's Markdown undertands several types of tables. The easiest example is the following:

Right Left Center Default


 12     12        12            12
123     123       123          123
  1     1          1             1

For more details about tables, refer to the pandoc documentation.

Language

By default, process-md will assume the document is written in English. However, other languages might be defined with the --language option, among the following choices: afrikaans, bahasa, breton, catalan, croatian, czech, danish, dutch, english, USenglish, american, UKenglish, estonian, finnish, french, francais, galician, austrian, german, germanb greek, hebrew, magyar, hungarian, irish, italian, lowersorbian, norsk, nynorsk, polish, portuges, portuguese, brazilian, brazil romanian, russian, scottish, spanish, slovak, slovene, swedish, turkish, uppersorbian, welsh.

The language chosen will be used for general formatting matters like the title of the table of contents, the title of the figures, the word separation rules, the date format, etc.

Footnotes

  1. This is a much longer footnote. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.

{
"selector": "text.html.markdown",
"cmd": ["process-md", "--recursive", "--open-files", "--links-as-notes", "/$file_name"],
"path": "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/usr/texbin",
"working_dir": "${project_path}",
"variants": [
{
"cmd": ["process-md", "--recursive", "--open-files", "/$file_name"],
"name": "Generate PDF (disable links as footnotes)"
},
{
"cmd": ["process-md", "--recursive", "--links-as-notes", "--open-files"],
"name": "Generate PDF from all Markdown files in project"
},
{
"cmd": ["process-md", "--recursive", "--open-files"],
"name": "Generate PDF from all Markdown files in project (disable links as footnotes)"
}
]
}
#!/bin/bash
# The MIT License (MIT)
#
# Copyright (c) 2013 https://gist.github.com/rbf
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
GP_INSTALL_VERSION="v2.5"
GP_INSTALL_BLOB_HASH="71b771b21cd90c32ae3b8c75afc83e7e72d7ef0f"
GP_INSTALL_DIR="/usr/local/bin"
GP_INSTALL_TOOL_NAME="process-md"
GP_INSTALL_URL="https://gist.github.com/rbf/6064734/raw/${GP_INSTALL_BLOB_HASH}/${GP_INSTALL_TOOL_NAME}"
if [ ! -d "${GP_INSTALL_DIR}" ]
then
echo "Install directory '${GP_INSTALL_DIR}' does not exist. Creating it..."
ORIG_USER="$(whoami)" && \
sudo mkdir -p ${GP_INSTALL_DIR} && \
sudo chown -R "${ORIG_USER}" ${GP_INSTALL_DIR} && \
echo "Install directory '${GP_INSTALL_DIR}' created successfully!" || \
echo "Oups! Something went wrong when trying to create the install directory '${GP_INSTALL_DIR}'."
fi
if ! touch "${GP_INSTALL_DIR}/${GP_INSTALL_TOOL_NAME}"
then
echo "Try with sudo..."
exit 1
fi
echo "Installing '${GP_INSTALL_TOOL_NAME} ${GP_INSTALL_VERSION}' from '${GP_INSTALL_URL}' to '${GP_INSTALL_DIR}'..."
curl -L ${GP_INSTALL_URL} > "${GP_INSTALL_DIR}/${GP_INSTALL_TOOL_NAME}" && \
chmod +x "${GP_INSTALL_DIR}/${GP_INSTALL_TOOL_NAME}" && \
${GP_INSTALL_TOOL_NAME} --version || \
echo "Oups! Something went wrong when installing ${GP_INSTALL_TOOL_NAME}."
exit
#!/bin/bash
# The MIT License (MIT)
#
# Copyright (c) 2013 https://gist.github.com/rbf
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
### File info:
GP_VERSION="v2.6-SNAPSHOT"
GP_RAW_URL="https://gist.github.com/rbf/6064734/raw"
GP_SOURCE="${GP_RAW_URL}/process-md"
GP_DOC="https://gist.github.com/rbf/6064734"
GP_INSTALL_PATH="/usr/local/bin/"
###
GP_COMMAND_BASENAME=$(basename "${GP_SOURCE}")
GP_COMMAND_NAME="${0#${GP_INSTALL_PATH}}"
GP_CURL_BASE="curl -sSL ${GP_SOURCE}"
GP_CURL_COMMAND_BASE="bash <(${GP_CURL_BASE})"
GP_INSTALL_CURL="curl -sSL https://gist.github.com/rbf/6064734/raw/install"
GP_INSTALL_BASH_CURL="bash <(${GP_INSTALL_CURL})"
GP_INSTALLED_SCRIPT="${GP_INSTALL_PATH}${GP_COMMAND_BASENAME}"
# Flags defaulted to false
GP_DATE_OUTPUT_FILES="false"
millisecs(){
if date --version 2>/dev/null 1>/dev/null
then
# centos
current_millisecs="$(date +"%s%N")"
echo "${current_millisecs%??????}" # remove last 6 digits to go from nanosecs to millisecs
else
# mac
# older version of 'date' without %N for nanoseconds
current_millisecs="$(python -c "import time; import re; print re.sub('\.', '', '%.3f' % time.time())" 2>/dev/null)"
if [ $? == 0 ]
then
echo "${current_millisecs}"
else
# python not available: use seconds precision
current_millisecs="$(date +"%s")"
echo "${current_millisecs}000" # add 3 zeros to go from secs to millisecs
fi
fi
}
formatmilliseconds(){
# Output milliseconds in seconds:
# 443123 => 443.123s
# 3123 => 3.123s
# 30 => 0.030s
printf "%013d" "${1}" | sed -e 's|\([0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]\)\([0-9][0-9][0-9]\).*|\1.\2|' -e 's|^0*\([0-9]*[0-9]\..*\)|\1s|'
}
GP_SCRIPT_START_TIME="$(millisecs)"
# Log functions
if [ -t 1 ]
then
GP_OUTPUT_IN_TERMINAL="true"
else
GP_OUTPUT_IN_TERMINAL="false"
fi
if ${GP_OUTPUT_IN_TERMINAL}
then
LOG_PREFIX_INFO="$(tput sgr0)" # Reset color
LOG_SUFFIX_INFO="$(tput sgr0)" # Reset color
# LOG_PREFIX_WARN="$(tput setaf 4)" # Blue
LOG_PREFIX_WARN="$(tput setaf 3)" # Yellow
LOG_SUFFIX_WARN="$(tput sgr0)" # Reset color
LOG_PREFIX_ERROR="$(tput setaf 1)" # Red
LOG_SUFFIX_ERROR="$(tput sgr0)" # Reset color
else
LOG_PREFIX_INFO="[INFO] "
LOG_SUFFIX_INFO=""
LOG_PREFIX_WARN="[WARN] "
LOG_SUFFIX_WARN=""
LOG_PREFIX_ERROR="[ERROR] "
LOG_SUFFIX_ERROR=""
fi
echo_info(){
echo "${LOG_PREFIX_INFO}${1}${LOG_SUFFIX_INFO}"
}
echo_info_wait(){
echo -n "${LOG_PREFIX_INFO}${1}"
}
echo_log_same_line (){
echo "${1}${LOG_SUFFIX_INFO}"
}
echo_warn(){
echo "${LOG_PREFIX_WARN}${1}${LOG_SUFFIX_WARN}"
}
echo_error(){
# In red and to sdterr
echo "${LOG_PREFIX_ERROR}${1}${LOG_SUFFIX_ERROR}" 1>&2;
}
echo_error_stdout(){
# In red and to sdterr
echo "${LOG_PREFIX_ERROR}${1}${LOG_SUFFIX_ERROR}";
}
echo_error_rewrite_line(){
# In red and to sdterr
echo -e "\r${LOG_PREFIX_ERROR}${1}${LOG_SUFFIX_ERROR}" 1>&2;
}
if [ "$(dirname ${GP_COMMAND_NAME})" == "/dev/fd" ]
then
# We are using the script directly form the CURL'ed version
GP_COMMAND_NAME="${GP_CURL_COMMAND_BASE}"
fi
helphint() {
echo_info "Main usage: ${GP_COMMAND_NAME:-${GP_COMMAND_BASENAME}} [-bfFhnoOrv] [--output=<format>[,<format>...]] [<path-pattern> [<target-path>]]"
echo_info "Type '${GP_COMMAND_NAME:-${GP_COMMAND_BASENAME}} --help' for more info."
echo_info "For more info visit ${GP_DOC}"
}
checkflags(){
GP_CHECKING_FLAGS="true"
for flag in "${@}"
do
if parseflag "${flag}"
then
[ "${flag:0:1}" == "-" ] && GP_FOUND_FLAGS+=("${flag}")
else
GP_INVALID_FLAG_FOUND="true"
echo_error "Invalid option: ${flag%=*}"
fi
[ $GP_PARAM_FOUND ] && [ "${flag:0:1}" == "-" ] && GP_OPTION_FOUND_AFTER_PARAM="true"
done
if [ "${GP_INVALID_FLAG_FOUND}" != "" ] || [ $GP_OPTION_FOUND_AFTER_PARAM ]
then
[ $GP_OPTION_FOUND_AFTER_PARAM ] && echo_error "Options are expected at the begin of the parameter list."
helphint
exit 1
fi
unset GP_CHECKING_FLAGS
}
# Usage: echoarraywithmaxwidth <max line length> <array name> [<item separator>] [<line prefix>]
echoarraywithmaxwidth(){
declare -i ea_line_length
ea_separator="${3:-", "}"
ea_result=""
ea_array=()
for (( i = 0; i < "$(eval echo \"\${#${2}[@]}\")"; i++ )); do
ea_array+=("$(eval echo \"\${${2}[${i}]}\")")
done
for word in "${ea_array[@]}"; do
word="${word}${ea_separator}"
[ $((( ${ea_line_length} + ${#word} ))) -ge ${1} ] && ea_result+="\n${4}" && ea_line_length=0
ea_result+="${word}"
ea_line_length+=${#word}
done
echo -e "${ea_result%${ea_separator}}"
}
# "<format-name>=<extension>"
GP_SUPPORTED_OUTPUT_FORMATS+=("pdf=pdf")
GP_SUPPORTED_OUTPUT_FORMATS+=("doc=docx")
GP_SUPPORTED_OUTPUT_FORMATS+=("word=docx")
GP_SUPPORTED_OUTPUT_FORMATS+=("docx=docx")
GP_SUPPORTED_OUTPUT_FORMATS+=("odt=odt")
GP_SUPPORTED_OUTPUT_FORMATS+=("openoffice=odt")
GP_SUPPORTED_OUTPUT_FORMATS+=("epub=epub")
GP_SUPPORTED_OUTPUT_FORMATS+=("html=html")
outputformatextension(){
for format in "${GP_SUPPORTED_OUTPUT_FORMATS[@]}"
do
if [ "${format%%=*}" == "$(echo ${1} | tr '[A-Z]' '[a-z]')" ]
then
echo "${format##*=}"
fi
done
}
checkoutputformats(){
GP_PDFTEX_REQUIRED=false
for format in ${@}
do
GP_OUTPUT_FORMAT_EXTENTION="$(outputformatextension ${format})"
if [ ! "${GP_OUTPUT_FORMAT_EXTENTION}" ]
then
echo_error "${format} format not supported."
GP_UNSUPPORTED_FORMAT_FOUND="true"
elif [ "${GP_OUTPUT_FORMAT_EXTENTION}" == "pdf" ]
then
GP_PDFTEX_REQUIRED=true
fi
done
[ ${GP_UNSUPPORTED_FORMAT_FOUND} ] && helphint && exit 1
}
# "<synonym>=<factor>"
GP_SUPPORTED_LINESPACING_SYNONYMS+=("single=1")
GP_SUPPORTED_LINESPACING_SYNONYMS+=("light=1.2")
GP_SUPPORTED_LINESPACING_SYNONYMS+=("spaced=1.5")
GP_SUPPORTED_LINESPACING_SYNONYMS+=("double=2")
linespacingfactor(){
# Supported values are from 0.1 to 9.9, or synonyms defined above.
if [ -n "$(echo "${1}" | grep "^\([1-9]\|[1-9]\.[0-9]\|0\.[1-9]\)$")" ]
then
echo "${1}"
return 0
fi
for synonym in "${GP_SUPPORTED_LINESPACING_SYNONYMS[@]}"
do
if [ "${synonym%%=*}" == "$(echo ${1} | tr '[A-Z]' '[a-z]')" ]
then
echo "${synonym##*=}"
return 0
fi
done
return 1
}
printlinespacingsynonyms(){
for synonym in "${GP_SUPPORTED_LINESPACING_SYNONYMS[@]}"
do
echo "${1}- ${synonym%%=*}, for ${synonym##*=}"
done
}
GP_FILENAME_EXAMPLE_DOCUMENT="example.md"
GP_FILENAME_EXAMPLE_IMAGE="sample-image.jpg"
downloadexample(){
read -p " > Do you want to download an example Markdown file and one sample image from ${GP_RAW_URL}? [y/n] " GP_ANSWER
if [ "${GP_ANSWER:0:1}" != "y" ]
then
echo_error "Aborted by user."
return 1
fi
GP_TEMP_DIR_EXAMPLE="$(mktemp -d example_tmp_XXXXXX)"
if [ "$?" != "0" ]
then
echo_error "Error writing to the current directory. Wrong rights?"
return 1
fi
curl -sSL "${GP_RAW_URL}/${GP_FILENAME_EXAMPLE_DOCUMENT}" -o "${GP_TEMP_DIR_EXAMPLE}/${GP_FILENAME_EXAMPLE_DOCUMENT}"
if [ "$?" != "0" ]
then
echo_error "Error downloading the example file."
return 1
fi
curl -sSL "${GP_RAW_URL}/${GP_FILENAME_EXAMPLE_IMAGE}" -o "${GP_TEMP_DIR_EXAMPLE}/${GP_FILENAME_EXAMPLE_IMAGE}"
if [ "$?" != "0" ]
then
echo_error "Error downloading the example image."
return 1
fi
echo_info "Example file downloaded successfully into directory '${GP_TEMP_DIR_EXAMPLE}'."
echo_info "Cd into the example directory:"
echo_info " cd ${GP_TEMP_DIR_EXAMPLE}"
echo_info "And then type following command to generate a PDF file from it in the './target' folder:"
echo_info " ${GP_COMMAND_NAME:-${GP_COMMAND_BASENAME}}"
echo_info "Or type following command to generate both PDF and HTML versions in the folder './example-output-directory' and opening them:"
echo_info " ${GP_COMMAND_NAME:-${GP_COMMAND_BASENAME}} --open-files --output=pdf,html example example-output-directory"
}
parseflag(){
if [ "${1}" == "--help" ] || [ "${1}" == "-h" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
printhelp
exit 0
elif [ "${1}" == "--version" ] || [ "${1}" == "-v" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
printversion
exit 0
elif [ "${1}" == "--install" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
installscript
exit 0
elif [ "${1}" == "--update" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
updatescript
exit
elif [ "${1}" == "--uninstall" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
uninstallscript
exit 0
elif [ "${1}" == "--example" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
downloadexample
exit
elif [ "${1}" == "--doctor" ] || [ "${1}" == "--verify-installation" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
verify_installation
exit
elif [ "${1}" == "--install-sublimetext2-build-system" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
install_sublimetext2_build_system
exit
elif [ "${1}" == "--dry-run" ] || [ "${1}" == "-n" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
GP_DRYRUN="true"
shift
elif [ "${1}" == "--flat" ] || [ "${1}" == "-f" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
GP_FLAT="true"
shift
elif [ "${1}" == "--path-name" ] || [ "${1}" == "-F" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
GP_FLAT="true"
GP_PATH_IN_TARGET_FILENAME="true"
shift
elif [ "${1}" == "--recursive" ] || [ "${1}" == "-r" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
GP_PROCESS_RECURSIVELY="true"
shift
elif [ "${1}" == "--bulk" ] || [ "${1}" == "-b" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
GP_BULK="true"
shift
elif [ "${1}" == "--bulk-force" ] || [ "${1}" == "-B" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
GP_BULK="force"
shift
elif [ "${1}" == "--omit-version" ] || [ "${1}" == "-m" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
GP_INCLUDE_GIT_VERSION="false"
shift
elif [ "${1}" == "--date-files" ] || [ "${1}" == "-d" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
GP_DATE_OUTPUT_FILES="true"
shift
elif [ "${1}" == "--open-target-folder" ] || [ "${1}" == "-o" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
GP_OPEN_TARGET_FOLDER="true"
shift
elif [ "${1}" == "--open-files" ] || [ "${1}" == "-O" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
GP_OPEN_FILES="true"
shift
elif [ "${1}" == "--links-as-notes" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
GP_LINKS_AS_NOTES="true"
shift
elif [ "${1%=*}" == "--output" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
if [ "${1:8:1}" == "=" ] && [ "${1:9}" != "" ]
then
GP_OUTPUT_FORMATS+=($(echo ${1#--output=} | tr ',' ' '))
shift
else
echo_error "--output option needs an argument."
helphint
exit 1
fi
elif [ "${1%=*}" == "--language" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
if [ "${1:10:1}" == "=" ] && [ "${1:11}" != "" ]
then
GP_OUTPUT_LANGUAGES+=($(echo ${1#--language=} | tr ',' ' '))
shift
else
echo_error "--language option needs an argument."
helphint
exit 1
fi
elif [ "${1:0:2}" == "-p" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
if [ "${1:2:1}" == "=" ] && [ "${1:3}" != "" ]
then
GP_OUTPUT_FILE_BASENAME_FORMAT="${1#-p=}"
shift
else
echo_error "-p option needs an argument."
helphint
exit 1
fi
elif [ "${1%=*}" == "--output-filename-format" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
if [ "${1:24:1}" == "=" ] && [ "${1:25}" != "" ]
then
GP_OUTPUT_FILE_BASENAME_FORMAT="${1#--output-filename-format=}"
shift
else
echo_error "--output-filename-format option needs an argument."
helphint
exit 1
fi
elif [ "${1:0:2}" == "-l" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
if [ "${1:2:1}" == "=" ] && [ "${1:3}" != "" ]
then
GP_LINESPACING="$(linespacingfactor ${1#-l=})"
if [ "$?" != "0" ]
then
echo_error "${1#-l=} is not a valid linespacing factor."
helphint
exit 1
fi
shift
else
echo_error "-l option needs an argument."
helphint
exit 1
fi
elif [ "${1%=*}" == "--linespacing" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
if [ "${1:13:1}" == "=" ] && [ "${1:14}" != "" ]
then
GP_LINESPACING="$(linespacingfactor ${1#--linespacing=})"
if [ "$?" != "0" ]
then
echo_error "${1#--linespacing=} is not a valid linespacing factor."
helphint
exit 1
fi
shift
else
echo_error "--linespacing option needs an argument."
helphint
exit 1
fi
elif [ "${1}" == "--pdf" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
GP_OUTPUT_FORMATS+=("pdf")
shift
elif [ "${1}" == "--html" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
GP_OUTPUT_FORMATS+=("html")
shift
elif [ "${1}" == "--doc" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
GP_OUTPUT_FORMATS+=("doc")
shift
elif [ "${1}" == "--odt" ]
then
[ $GP_CHECKING_FLAGS ] && return 0
GP_OUTPUT_FORMATS+=("odt")
shift
elif [ "${1:0:1}" == "-" ]
then
[ $GP_CHECKING_FLAGS ] && return 1
fi
[ $GP_CHECKING_FLAGS ] && GP_PARAM_FOUND="true" # Param as value passed to the script without "--". Only two are expected, and right to the end of the param list.
}
checkgitstatus(){
GP_GIT_REPO_HERE=false
GP_GIT_THINGS_TO_COMMIT=false
GP_GIT_UNTRACKED_FILES=false
git rev-parse --git-dir 1>/dev/null 2>/dev/null
[ $? -eq 0 ] && GP_GIT_REPO_HERE=true
git diff-index --quiet HEAD 1>/dev/null 2>/dev/null
[ $? -ne 0 ] && $GP_GIT_REPO_HERE && GP_GIT_THINGS_TO_COMMIT=true
git ls-files --others --exclude-standard --error-unmatch "./$(git rev-parse --show-cdup 2>/dev/null)" 1>/dev/null 2>/dev/null
[ $? -eq 0 ] && $GP_GIT_REPO_HERE && GP_GIT_UNTRACKED_FILES=true
}
# Following function is only relevant PDF generated from Markdown files within a git repo.
# It tries to generate a sensible subtitle including versioning info and it
# warns in case of a dirty git repo.
# When generating on a clean tagged version of the repo, the subtitle will be the tag name, e.g. v1.2
# If not, it will include the number of commits after the last tag, e.g. v1.2-23-g123dv2x i.e. $(git describe --always)
generatedocumentsubtitle(){
$GP_INCLUDE_GIT_VERSION || return 0
GP_DOCUMENT_SUBTITLE=
checkgitstatus
if $GP_GIT_REPO_HERE
then
GP_DOCUMENT_SUBTITLE="$(git describe --always)"
if $GP_GIT_THINGS_TO_COMMIT || $GP_GIT_UNTRACKED_FILES
then
GP_DOCUMENT_SUBTITLE=" \textcolor{red}{$(git describe --always)}\footnote{"
GP_DOCUMENT_SUBTITLE+="The git repository of the source file '$(basename ${1//_/\\_})' had " # underscore chars are not allowed in this footnote (?)
$GP_GIT_THINGS_TO_COMMIT && GP_DOCUMENT_SUBTITLE+="uncommitted changes"
$GP_GIT_UNTRACKED_FILES && $GP_GIT_THINGS_TO_COMMIT && GP_DOCUMENT_SUBTITLE+=" and "
$GP_GIT_UNTRACKED_FILES && GP_DOCUMENT_SUBTITLE+="untracked files"
GP_DOCUMENT_SUBTITLE+=" when this PDF was generated. This output may not be reproducible.}"
fi
fi
echo "${GP_DOCUMENT_SUBTITLE}"
}
# Append a suffix ('+') to the filenames being generated on a dirty git repo
# to avoid overwriting the file generated on a clean, tagged repo state.
filenamesuffix(){
GP_FILENAME_SUFFIX=
checkgitstatus
if $GP_GIT_REPO_HERE
then
if $GP_GIT_THINGS_TO_COMMIT || $GP_GIT_UNTRACKED_FILES
then
GP_FILENAME_SUFFIX="+"
fi
fi
echo "${GP_FILENAME_SUFFIX}"
}
GP_FILENAME_SUFFIX=$(filenamesuffix)
applyoutputfilebasenamepattern(){
finalfilename="${GP_OUTPUT_FILE_BASENAME_FORMAT}${GP_FILENAME_SUFFIX}.${GP_TARGET_FILE_EXTENSION}"
finalfilename="${finalfilename//"%f"/${GP_CURRENT_FILE_BASENAME}}" # Original files name
finalfilename="${finalfilename//"%v"/$(git describe --always 2>/dev/null || echo "")}" # Git version if any
finalfilename="${finalfilename//"%n"/${GP_OUTPUT_COUNTER}}" # No-padded counter
finalfilename="$(eval "$(echo "echo \"${finalfilename}\"" | \
sed "s|\(\%0[0-9]*\)n|\$(printf '\1d' ${GP_OUTPUT_COUNTER})|g")")" # Padded counter(s)
# sory for that previous line :S Happy to learn it better!
finalfilename="${finalfilename//"%a"/$(date +"%a")}" # Short date, Sun
finalfilename="${finalfilename//"%A"/$(date +"%A")}" # Long date, Sunday
finalfilename="${finalfilename//"%b"/$(date +"%b")}" # Short Month, Feb
finalfilename="${finalfilename//"%B"/$(date +"%B")}" # Long Month, February
finalfilename="${finalfilename//"%d"/$(date +"%d")}" # Day of the month
finalfilename="${finalfilename//"%H"/$(date +"%H")}" # Hour in 24 hour format (00..23)
finalfilename="${finalfilename//"%I"/$(date +"%I")}" # Hour in 12 hour format (01..12) (this can be used with %p to append Am or PM)
finalfilename="${finalfilename//"%j"/$(date +"%j")}" # Day of the year
finalfilename="${finalfilename//"%m"/$(date +"%m")}" # Month in number format (01..12)
finalfilename="${finalfilename//"%M"/$(date +"%M")}" # Minute (00..59)
finalfilename="${finalfilename//"%p"/$(date +"%p")}" # Locale either AM or PM
finalfilename="${finalfilename//"%S"/$(date +"%S")}" # Second
finalfilename="${finalfilename//"%u"/$(date +"%u")}" # Day of the week
finalfilename="${finalfilename//"%V"/$(date +"%V")}" # Week number of year with Monday as first day of week (01..53)
finalfilename="${finalfilename//"%Y"/$(date +"%Y")}" # Year
finalfilename="${finalfilename//"%z"/$(date +"%z")}" # Numeric timezone (e.g., -0400) or %Z with timezone abbreviation.
echo "${finalfilename}"
}
declare -i GP_OUTPUT_COUNTER=0
declinepathpartsforfile(){
(( GP_OUTPUT_COUNTER++ ))
GP_CURRENT_DIR="$(dirname "${1}")"
GP_CURRENT_FILENAME="$(basename "${1}")"
GP_CURRENT_FILE_BASENAME="${GP_CURRENT_FILENAME%.*}"
GP_TARGET_CURRENT_DIR="${GP_TARGET_DIR}"
! [ $GP_FLAT ] && GP_TARGET_CURRENT_DIR="${GP_TARGET_CURRENT_DIR}/${GP_CURRENT_DIR}"
GP_TARGET_CURRENT_FILENAME="$(applyoutputfilebasenamepattern)"
[ $GP_PATH_IN_TARGET_FILENAME ] && GP_TARGET_CURRENT_FILENAME="$(echo "${GP_CURRENT_DIR#.}" | tr '/' '-')-${GP_TARGET_CURRENT_FILENAME}"
GP_TARGET_CURRENT_FILEPATH="${GP_TARGET_CURRENT_DIR}/${GP_TARGET_CURRENT_FILENAME#-}"
# Remove unnecessary (but not wrong) "/./" from path for enhanced prompt in stdout
GP_TARGET_CURRENT_FILEPATH="${GP_TARGET_CURRENT_FILEPATH/\/.\///}"
GP_TARGET_CURRENT_FILEPATH="./${GP_TARGET_CURRENT_FILEPATH#./}"
GP_TARGET_FILEPATHS+=("${GP_TARGET_CURRENT_FILEPATH}")
}
dodryrun(){
GP_OUTPUT_FORMATS_PRETTY_PRINTED=$(echo "${GP_OUTPUT_FILE_EXTENSIONS[@]}" | tr '[:lower:]' '[:upper:]' | sed -e "s/ /, /g" -e "s/\(.*\), /\1 and /")
echo_info "Would generate ${GP_OUTPUT_FORMATS_PRETTY_PRINTED} files from ${GP_MD_FILES_COUNT} Markdown file(s):"
for file in "${GP_MD_FILES[@]}"
do
for GP_TARGET_FILE_EXTENSION in "${GP_OUTPUT_FILE_EXTENSIONS[@]}"
do
declinepathpartsforfile "${file}"
echo_info " ${file} --> ${GP_TARGET_CURRENT_FILEPATH}"
done
done
}
check_pdftex_available(){
if [ "$(which pdftex)" == "" ]
then
echo_error "pdftex not found!"
echo_error "pdftex is required to genereate PDF documents from the Markdown files."
echo_error "For installing info visit: http://johnmacfarlane.net/pandoc/installing.html"
echo_error "In the link above, pandoc recommends installing BasicTeX package at http://www.tug.org/mactex/morepackages.html"
GP_PDFTEX_AVAILABLE=false
fi
}
check_pandoc_available(){
if [ "$(which pandoc)" == "" ]
then
echo_error "pandoc not found!"
echo_error "For installing info visit: http://johnmacfarlane.net/pandoc/installing.html"
GP_PANDOC_AVAILABLE=false
fi
}
are_required_tools_available(){
check_pandoc_available
$GP_PDFTEX_REQUIRED && check_pdftex_available
( ! $GP_PANDOC_AVAILABLE || ! $GP_PDFTEX_AVAILABLE ) && return 1 || return 0
}
printversion(){
print_version_echo_fn="${1:-echo_info}"
"${print_version_echo_fn}" "${GP_COMMAND_NAME} ${GP_VERSION}"
check_pandoc_available
$GP_PANDOC_AVAILABLE && "${print_version_echo_fn}" "$(pandoc --version | head -1)"
check_pdftex_available 2>/dev/null
$GP_PDFTEX_AVAILABLE && "${print_version_echo_fn}" "$(pdftex --version | head -1)"
}
verify_installation(){
[ -z "$(which ${GP_COMMAND_BASENAME})" ] && echo_warn "${GP_COMMAND_BASENAME} not reachable from the PATH, but used from $0" && GP_DOCTOR_ALL_OK=false
are_required_tools_available
[ $? == 0 ] || GP_DOCTOR_ALL_OK=false
$GP_DOCTOR_ALL_OK && echo_info "Your system is ready to process Markdown files." && return 0 || return 1
}
GP_BABEL_LANGUAGES=("afrikaans" "bahasa" "breton" "catalan" "croatian" \
"czech" "danish" "dutch" "english" "USenglish" "american" "UKenglish" \
"british esperanto" "estonian" "finnish" "french" "francais" "galician" \
"austrian" "german" "germanb greek" "hebrew" "magyar" "hungarian" \
"irish" "italian" "lowersorbian" "norsk" "nynorsk" "polish" "portuges" \
"portuguese" "brazilian" "brazil romanian" "russian" "scottish" \
"spanish" "slovak" "slovene" "swedish" "turkish" "uppersorbian" "welsh")
checkbabellanguage(){
for babel_language in "${GP_BABEL_LANGUAGES[@]}"
do
if [ "$(echo ${babel_language} | tr '[A-Z]' '[a-z]')" == "$(echo ${1} | tr '[A-Z]' '[a-z]')" ]
then
echo "${babel_language}"
break
fi
done
}
checkoutputlanguages(){
for language in ${@}
do
if [ ! "$(checkbabellanguage ${language})" ]
then
echo_error "'${language}' language not supported."
echo_error "PDF generation uses 'babel' package, therefore the supported languages are: "
echo_error " $(echoarraywithmaxwidth 100 GP_BABEL_LANGUAGES ", " "[INFO] ")"
GP_UNSUPPORTED_LANGUAGE_FOUND="true"
fi
done
[ ${GP_UNSUPPORTED_LANGUAGE_FOUND} ] && helphint && exit 1
}
GP_ST2_SETTINGS_FOLDER=~/Library/Application\ Support/Sublime\ Text\ 2/Packages/User
GP_TEMP_FOLDER_FOR_ST2_BUILD_SYSTEM_FILE="/tmp"
GP_ST2_BUILD_SYSTEM_BASENAME=Generate\ PDF.sublime-build
install_sublimetext2_build_system(){
verify_installation 1>/dev/null
! $GP_DOCTOR_ALL_OK && echo_error "Please fix your installation before installing the 'Sublime Text 2' build system." && exit 1
if [ -d "${GP_ST2_SETTINGS_FOLDER}" ]
then
GP_INSTALL_ST2_BUILD_FILE_TO_TEMP_DIR=false
else
echo_error "Unable to find 'Sublime Text 2' user settings folder in '${GP_ST2_SETTINGS_FOLDER}'."
if [ -d "${GP_TEMP_FOLDER_FOR_ST2_BUILD_SYSTEM_FILE}" ]
then
GP_INSTALL_ST2_BUILD_FILE_TO_TEMP_DIR=true
else
echo_error "Unable to generate build system file for 'Sublime Text 2' into ${GP_TEMP_FOLDER_FOR_ST2_BUILD_SYSTEM_FILE}."
echo_info "For more info visit ${GP_DOC}"
return 1
fi
fi
if $GP_INSTALL_ST2_BUILD_FILE_TO_TEMP_DIR
then
GP_ST2_BUILD_SYSTEM_FILENAME="${GP_TEMP_FOLDER_FOR_ST2_BUILD_SYSTEM_FILE}/${GP_ST2_BUILD_SYSTEM_BASENAME}"
else
GP_ST2_BUILD_SYSTEM_FILENAME="${GP_ST2_SETTINGS_FOLDER}/${GP_ST2_BUILD_SYSTEM_BASENAME}"
fi
cat << EOF >> "${GP_ST2_BUILD_SYSTEM_FILENAME}"
{
"selector": "text.html.markdown",
"cmd": ["process-md", "--recursive", "--open-files", "--links-as-notes", "/\$file_name"],
"path": "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/usr/texbin",
"working_dir": "\${project_path}",
"variants": [
{
"cmd": ["process-md", "--recursive", "--open-files", "/\$file_name"],
"name": "Generate PDF (disable links as footnotes)"
},
{
"cmd": ["process-md", "--recursive", "--links-as-notes", "--open-files"],
"name": "Generate PDF from all Markdown files in project"
},
{
"cmd": ["process-md", "--recursive", "--open-files"],
"name": "Generate PDF from all Markdown files in project (disable links as footnotes)"
}
]
}
EOF
if [ $? == 0 ] && [ -f "${GP_ST2_BUILD_SYSTEM_FILENAME}" ]
then
if $GP_INSTALL_ST2_BUILD_FILE_TO_TEMP_DIR
then
echo_info "Please manually copy the file '${GP_ST2_BUILD_SYSTEM_FILENAME}' to the appropriate folder."
echo_info "Afterwards, you will find it in the menu 'Tools' > 'Build System' > '$(basename "${GP_ST2_BUILD_SYSTEM_FILENAME}" ".sublime-build")'"
else
echo_info "Build system definition for 'Sublime Text 2' successfully installed to:"
echo_info " ${GP_ST2_BUILD_SYSTEM_FILENAME}"
echo_info "You will find it in the menu 'Tools' > 'Build System' > '$(basename "${GP_ST2_BUILD_SYSTEM_FILENAME}" ".sublime-build")'"
fi
else
echo_error "Installation of build system definition for 'Sublime Text 2' failed!"
echo_info "For more info visit ${GP_DOC}"
fi
}
printhelp(){
less << EOF
Version
=======
$(printversion "echo")
Usage
=====
$ ${GP_COMMAND_BASENAME} [option] [<path-pattern> [<target-path>]]
Options
=======
-b, --bulk
Allow to process more than 10 files. This is a security to avoid
triggering this command by error on a directory with lots of subdirectories
like '/' or '~'.
--doc
Generate Word files for each Markdown file. Equivalent to '--output=doc'.
--doctor, --verify-installation
Performs a check to verify that the 'process-md' is correctly installed,
and that the required tools are also available.
-d, --date-files
Prefix generated files with the current date (i.e. adds "%Y%m%d_" at the beginning
of the output filename pattern).
--example
Downloads an example Markdown document from ${GP_DOC} locally so that you can
apply 'process-md' on it to better understand how Markdown works.
-f, --flat
Gather all generated files into the target directory, without
replicating the original subfolder structure.
-F, --path-name
Include the original path of the Markdown files in the generated
file, to avoid name clashes when gathering all files in the target
directory. Implies '--flat'.
-h, --help
Print this help and exit. Other parameters and options are ignored.
--html
Generate HTML files for each Markdown file. Equivalent to '--output=html'.
-l=<factor>, --linespacing=<factor>
Specify the linespacing factor of the PDF output (using the 'setspace' package).
The factor must be any number between 0.1 and 9.9. Following synomyns are also
accepted:
$(printlinespacingsynonyms " ")
Defaults to '${GP_SUPPORTED_LINESPACING_SYNONYMS[0]%%=*}'.
--language=<language>[,<language>...]
Specify the languages of the resulting file. It is mainly used for PDF
generation, with the 'babel' package. Therefore, valid values are:
$(echoarraywithmaxwidth 70 GP_BABEL_LANGUAGES ", " " ")
By default 'english' is used if nothing else is specified.
--links-as-notes
Make footnotes with URL of external links when possible (e.g. PDF, HTML).
Note: This will fail if there are links in section titles.
-m, --omit-version
If the original Markdown files are in a git repository, by default the git
version (as in "git describe --always") is included in the filename and as a subtitle
in generated PDF files. This flag overrides this behaviour so that the git version is
not shown.
-n, --dry-run
Only list what files would be generated with the given parameters
without actually generating any files.
--output=<format>[,<format>...]
Specify which files should be generated for each Markdown file. Valid
values are '--ouput=pdf,word,openoffice,html' and some synonyms: 'doc'
and 'docx' are synonims of 'word'; 'odt' is synonym of 'openoffice'.
By default 'pdf' is generated if nothing else is specified.
-o, --open-target-folder
[Mac OS X only]
After successful generation, open the target folder in Finder.
-O, --open-files
[Mac OS X only]
After successful generation, open the generated files in the default application.
If more than 10 files would open, this will fall back to '--open-target-folder' to
avoid issues with the operating system.
--odt
Generate OpenOffice files for each Markdown file. Equivalent to '--output=odt'.
-p=<format>, --output-filename-pattern=<format>
Pattern for the basename part of the generated files. The extension will be appended
for each type of output file. No spaces might be used in the pattern.
By default the generated files have the same basename
than their original Markdown files with the git version of the file as suffix, if
their are in a git repository (i.e. by default -p=%f_%v or -p=%f). Following parameters
are recognized:
%f - Original file basename
%v - Git version (as in 'git describe --always') if any, or blank
%n - Counter (Use '%0xn' for a counter padded with 'x' number of zeros)
%a - Short date (Sun)
%A - Long date (Sunday)
%b - Short Month (Feb)
%B - Long Month (February)
%d - Day of the month
%H - Hour in 24 hour format (00..23)
%I - Hour in 12 hour format (01..12) (see '%p')
%j - Day of the year
%m - Month in number format (01..12)
%M - Minute (00..59)
%p - Locale either AM or PM
%S - Second (00..59)
%u - Day of the week
%V - Week number of year with Monday as first day of week (01..53)
%Y - Year (2013)
%z - Numeric timezone (+0100)
%Z - Timezone abbreviation. (CET)
--pdf
Generate PDF files for each Markdown file. Equivalent to '--output=pdf'.
-r, --recursive
By default only Markdown files in the current directory are processed. This
flag forces the processing of all Markdown files in the current directory
and its subdirectories (up to a max depth of 12 levels).
--uninstall
Delete the script from '/usr/local/bin' and exit. Other parameters
and options are ignored.
--update
Update the script installed in '/usr/local/bin' and exit. Other parameters
and options are ignored.
-v, --version
Print the version of the script and related tools and exit. Other parameters
and options are ignored.
Extras
======
--install-sublimetext2-build-system
[Mac OS X only]
Install a build system definition for the text editor 'Sublime Text 2'[^1]
to call 'process-md'. This allows to easily produce PDF documents from the
current Markdown file open in the editor using 'pdftex' via 'pandoc' with
the keystroke 'cmd-B'. And well, that is pretty handy.
[^1]: http://www.sublimetext.com
Examples
========
$ ${GP_COMMAND_BASENAME}
All .md and .markdown files in the current directory
are converted in PDF in the ./target directory.
$ ${GP_COMMAND_BASENAME} -r
All .md and .markdown files in the current directory and its
subdirectories are converted in PDF in the ./target directory,
maintaining its original sub-folder structure.
$ ${GP_COMMAND_BASENAME} --output=word
All .md and .markdown files in the current directory
are converted in docx in the ./target directory.
$ ${GP_COMMAND_BASENAME} api
All .md and .markdown files in the current directory
containing "api" (case sensitive) in the file name are
converted in PDF in the ./target directory.
$ ${GP_COMMAND_BASENAME} -r ./doc/*a
All .md and .markdown files in the "doc/" subdirectory and its
subdirectories containing "a" (case sensitive) in the file name or
the path are converted in PDF in the ./target directory, maintaining
its original sub-folder structure.
$ ${GP_COMMAND_BASENAME} api pdfs
All .md and .markdown files in the current directory
containing "api" (case sensitive) in the file name are
converted in PDF in the ./pdfs directory.
$ ${GP_COMMAND_BASENAME} -r . .
All .md and .markdown files in the current directory
and its subfolders are converted in PDF in the current directory,
maintaining its original sub-folder structure, i.e. next to their .md
counterparts.
For more info visit ${GP_DOC}
EOF
}
updatescript(){
if [ ! -e "${GP_INSTALLED_SCRIPT}" ]
then
echo_error "${GP_INSTALLED_SCRIPT} not found"
echo_error "Run following command to install: ${GP_INSTALL_BASH_CURL}"
exit 1
fi
GP_INSTALLING_VERSION="$(eval "${GP_INSTALL_CURL}" | grep "GP_INSTALL_VERSION=" | head -1 | sed "s/GP_INSTALL_VERSION=\"\(.*\)\"/\1/")"
if [ "${GP_VERSION}" == "${GP_INSTALLING_VERSION}" ]
then
echo_info "Already up-to-date."
exit 0
fi
echo_info "'${GP_COMMAND_NAME} ${GP_VERSION}' is currently installed."
echo_info "There is a newer released version: ${GP_INSTALLING_VERSION}."
read -p " > Do you want to install '${GP_COMMAND_NAME} ${GP_INSTALLING_VERSION}'? [y/n] " GP_ANSWER
if [ "${GP_ANSWER:0:1}" != "y" ]
then
echo_info "Update aborted by user."
exit 0
fi
eval ${GP_INSTALL_BASH_CURL}
}
installscript(){
if [ "${0}" == "${GP_INSTALLED_SCRIPT}" ]
then
echo_info "Already using ${0}."
exit 0
fi
$(are_required_tools_available) || exit 1
if [ -e "${GP_INSTALLED_SCRIPT}" ]
then
echo_info "Currently installed: ${GP_INSTALL_PATH}"
"${GP_INSTALLED_SCRIPT}" --version | head -1
echo_info "You are installing version ${GP_VERSION}."
read -p "Do you want to continue? [y/n] " GP_ANSWER
if [ "${GP_ANSWER:0:1}" == "n" ]
then
exit 0
fi
fi
if [ -e "${GP_INSTALLED_SCRIPT}" ]
then
rm "${GP_INSTALLED_SCRIPT}"
fi
if [ "$(dirname ${0})" == "/dev/fd" ]
then
# We are installing from the piped version, and we have to redownload a new version of the file
# since the current one (often in /dev/fd/63) has already been consumed up to here
eval ${GP_INSTALL_BASH_CURL}
else
cp -v "${0}" "${GP_INSTALLED_SCRIPT}"
fi
if [ $? != 0 ]
then
echo_error "Error installing script to ${GP_INSTALLED_SCRIPT}"
exit 1
fi
chmod +x "${GP_INSTALLED_SCRIPT}"
if [ $? == 0 ]
then
echo_info "Successfully installed to ${GP_INSTALLED_SCRIPT}"
else
echo_error "Error installing script to ${GP_INSTALLED_SCRIPT}"
exit 1
fi
}
uninstallscript(){
if [ ! -e "${GP_INSTALLED_SCRIPT}" ]
then
echo_warn "${GP_INSTALLED_SCRIPT} not found"
exit 0
fi
echo_info "This action will remove ${GP_INSTALLED_SCRIPT}"
read -p "Do you want to continue? [y/n] " GP_ANSWER
if [ "${GP_ANSWER:0:1}" == "n" ]
then
exit 0
fi
rm -v ${GP_INSTALLED_SCRIPT}
if [ $? == 0 ]
then
echo_info "${GP_INSTALLED_SCRIPT} removed successfully"
else
echo_error "Removing ${GP_INSTALLED_SCRIPT} failed"
exit 1
fi
}
# Expand one-letter params
GP_PARAMS="${@}"
while [ "true" ]
do
GP_PARAMS_PARSED=$(echo "params: ${GP_PARAMS}" | sed "s/\( -[a-zA-Z]\)\([a-zA-Z]\)/\1 -\2/g")
if [ "${GP_PARAMS}" == "${GP_PARAMS_PARSED#params: }" ]
then
break
else
GP_PARAMS="${GP_PARAMS_PARSED#params: }"
fi
done
set -- ${GP_PARAMS}
checkflags ${@}
for flag in "${@}"
do
parseflag "${flag}"
done
for flag in "${GP_FOUND_FLAGS[@]}"
do
shift
done
GP_OUTPUT_LANGUAGES="${GP_OUTPUT_LANGUAGES:-english}"
checkoutputlanguages "${GP_OUTPUT_LANGUAGES[@]}"
GP_OUTPUT_FORMATS="${GP_OUTPUT_FORMATS:-pdf}"
checkoutputformats "${GP_OUTPUT_FORMATS[@]}"
$(are_required_tools_available) || exit 1
checkgitstatus
if $GP_GIT_REPO_HERE && $GP_INCLUDE_GIT_VERSION
then
GP_OUTPUT_FILE_BASENAME_FORMAT="${GP_OUTPUT_FILE_BASENAME_FORMAT:-"%f_%v"}"
else
GP_OUTPUT_FILE_BASENAME_FORMAT="${GP_OUTPUT_FILE_BASENAME_FORMAT:-"%f"}"
fi
if $GP_DATE_OUTPUT_FILES
then
GP_OUTPUT_FILE_BASENAME_FORMAT="%Y%m%d_${GP_OUTPUT_FILE_BASENAME_FORMAT}"
fi
# Gather file extensions for output formats and remove duplicates
for format in "${GP_OUTPUT_FORMATS[@]}"
do
GP_OUTPUT_FILE_EXTENSIONS+=($(outputformatextension ${format}))
done
GP_OUTPUT_FILE_EXTENSIONS=($(printf "%s\n" "${GP_OUTPUT_FILE_EXTENSIONS[@]}" | sort -u))
# Gather Markdown files to process
while read -r line
do
GP_MD_FILES+=("${line}")
done <<< "$(find . -maxdepth 1$([ $GP_PROCESS_RECURSIVELY ] && echo "2") -type f -path "*${1}*" \( -iname "*.md" -or -iname "*.markdown" \) -print)"
GP_MD_FILES_COUNT=${#GP_MD_FILES[@]}
GP_MD_FILES_MAX=10
GP_BASE_DIR="$(pwd)"
GP_TARGET_DIR="${2:-target}"
if [ ${#GP_MD_FILES[0]} -eq 0 ]
then
echo_warn "No Markdown file found in the current directory$([ $GP_PROCESS_RECURSIVELY ] && echo " and its subfolders")."
helphint
exit 0
fi
[ "${GP_DRYRUN}" == "true" ] && dodryrun && exit
if [ ${GP_MD_FILES_COUNT} -gt ${GP_MD_FILES_MAX} ]
then
GP_ARGUMENTS="${1} ${2}"
GP_ARGUMENTS="$(echo " ${1} ${2}" | sed 's/ *$//g')"
echo_warn "${GP_MD_FILES_COUNT} Markdown files found! That sounds like a lot..."
echo_info "Use '${GP_COMMAND_NAME} --dry-run${GP_ARGUMENTS}' to see a list of what would be generated."
if [ "${GP_BULK}" == "true" ]
then
echo_info "Use '${GP_COMMAND_NAME} --bulk-force${GP_ARGUMENTS}' to avoid this question and directly proceed with the file generation."
read -p " > Do you want to continue? [y/n] " GP_ANSWER
if [ "${GP_ANSWER:0:1}" != "y" ]
then
exit 0
fi
elif [ "${GP_BULK}" == "" ]
then
echo_info "Use '${GP_COMMAND_NAME} --bulk${GP_ARGUMENTS}' to proceed with the file generation."
exit 0
fi
fi
[ "${GP_LINKS_AS_NOTES}" == "true" ] && GP_LINKS_AS_NOTES_COMMAND="--variable=links-as-notes"
for file in "${GP_MD_FILES[@]}"
do
for GP_TARGET_FILE_EXTENSION in "${GP_OUTPUT_FILE_EXTENSIONS[@]}"
do
echo_info_wait "Processing file: $file "
declinepathpartsforfile "${file}"
mkdir -p "${GP_TARGET_CURRENT_DIR}"
# Since pandoc looks for images relatives to where it is called (https://github.com/jgm/pandoc/issues/917)
# we have to cd into the directory of the given file before pandoc'ing it,
# and we have to pass the full path in the -o parameter.
cd "${GP_CURRENT_DIR}"
# Comments to options used below:
# --variable=documentclass:scrartcl \ => this class allow \subtitle{} used below
# --variable=linkcolor:black \ => the default is magenta
# --variable=links-as-notes \ => only for external links, it doesn't work if links in section titles
# --variable=papersize:"a4paper, DIV=9" \ => Bigger DIV values make thiner borders.
# DIVcalc tends to make too low values of DIV (thing text widths),
# and DIV10 gives problems with TOC (???)
# Other valid options:
# --variable=date:"$(date +"%d %b %Y" || echo "")" \
# --variable=lang:"french" \
pandoc_start="$(millisecs)"
GP_PANDOC_OUTPUT=$(pandoc \
--table-of-contents \
--number-sections \
--smart \
--variable=documentclass:scrartcl \
--variable=papersize:"a4paper, DIV=9" \
--variable=lang:"$(echoarraywithmaxwidth 1000 GP_OUTPUT_LANGUAGES ",")" \
--variable=linkcolor:black \
--variable=header-includes:"\usepackage{setspace} \setstretch{${GP_LINESPACING:-1}}" \
--variable=header-includes:"\subtitle{$(generatedocumentsubtitle "${GP_CURRENT_FILENAME}")}" \
--variable=header-includes:"\ifdefined \includegraphics \renewcommand{\includegraphics}[1]{\Oldincludegraphics[width=0.9\textwidth,height=0.9\textheight,keepaspectratio]{#1}} \fi" \
--variable=date:"\today" \
${GP_LINKS_AS_NOTES_COMMAND} \
-o "${GP_BASE_DIR}/${GP_TARGET_CURRENT_FILEPATH#./}" \
"${GP_CURRENT_FILENAME}" \
2>&1) # capture pandoc stderr output
if [ $? == 0 ]
then
pandoc_duration="$(( $(millisecs) - ${pandoc_start} ))"
echo_log_same_line "---> ${GP_TARGET_CURRENT_FILEPATH} - OK [$(formatmilliseconds ${pandoc_duration})]"
GP_GENERATED_FILES+=("${GP_BASE_DIR}/${GP_TARGET_CURRENT_FILEPATH#./}")
else
pandoc_duration="$(( $(millisecs) - ${pandoc_start} ))"
echo_error_rewrite_line "Processing file: $file -X-> ${GP_TARGET_CURRENT_FILEPATH} - FAILED [$(formatmilliseconds ${pandoc_duration})]"
GP_ERRORS+=("$(echo "${file} - Failed generation of PDF"; \
echo_error_stdout "Expected target file: ${GP_TARGET_CURRENT_FILEPATH}"; \
echo_error_stdout "${GP_PANDOC_OUTPUT}"; \
echo_error_stdout;)")
fi
global_pandoc_duration=$(( ${global_pandoc_duration} + ${pandoc_duration} ))
cd "${GP_BASE_DIR}"
done
done
GP_SCRIPT_FINISH_TIME="$(( $(millisecs) - ${GP_SCRIPT_START_TIME} ))"
if [ ${#GP_GENERATED_FILES[@]} -eq 1 ] && [ ${#GP_GENERATED_FILES[@]} -eq ${#GP_TARGET_FILEPATHS[@]} ]
then
echo_info "One file successfully generated in $(formatmilliseconds ${GP_SCRIPT_FINISH_TIME})."
elif [ ${#GP_GENERATED_FILES[@]} -gt 1 ] && [ ${#GP_GENERATED_FILES[@]} -eq ${#GP_TARGET_FILEPATHS[@]} ]
then
echo_info "${#GP_GENERATED_FILES[@]} files successfully generated in $(formatmilliseconds ${GP_SCRIPT_FINISH_TIME})."
elif [ ${#GP_GENERATED_FILES[@]} -gt 0 ]
then
echo_info "${#GP_GENERATED_FILES[@]} out of ${#GP_TARGET_FILEPATHS[@]} file(s) successfully generated in $(formatmilliseconds ${GP_SCRIPT_FINISH_TIME})."
fi
if [ ${#GP_GENERATED_FILES[@]} -gt 0 ] && [ ${#GP_GENERATED_FILES[@]} -le 10 ]
then
[ "${GP_OPEN_TARGET_FOLDER}" == "true" ] && open "${GP_TARGET_DIR}"
[ "${GP_OPEN_FILES}" == "true" ] && open "${GP_GENERATED_FILES[@]}"
elif [ ${#GP_GENERATED_FILES[@]} -gt 10 ]
then
if [ "${GP_OPEN_TARGET_FOLDER}" == "true" ] || [ "${GP_OPEN_FILES}" == "true" ]
then
open "${GP_TARGET_DIR}"
fi
fi
if [ ${#GP_ERRORS[@]} -eq 0 ]
then
exit 0
fi
echo_error
echo_error "===================================================================="
echo_error "pandoc failed to generate PDF for ${#GP_ERRORS[@]} file(s)"
echo_error "===================================================================="
if [ "${GP_LINKS_AS_NOTES}" == "true" ]
then
echo_error
echo_error "--------------------------------------------------------------------"
echo_error "Option '--links-as-notes' will fail if there are links in section "
echo_error "titles. Try to generate the files again without this option. "
echo_error "--------------------------------------------------------------------"
fi
for i in "${GP_ERRORS[@]}"
do
echo_error
echo_error "--------------------------------------------------------------------"
echo_error "${i}"
echo_error "--------------------------------------------------------------------"
echo_error
done
exit 1
Display the source blob
Display the rendered blob
Raw
  • Add check to avoid parsing the whole computer for markdown files! For example:
    • Add --test mode to list only the files that it would process
    • Warn if more than say 10 files would be processed
    • Limit the depth for recursitivy to default to say 3 directory levels, and maybe a flagg --levels=4 to modify it...
  • Allow a plain structure in the target folder, instead of replicating the original subfolder structure of the markdown files.
  • Make small script to update version and tag commit
  • Add examples of shell scripting in the README referencing lines in the code.
  • Make --update not update for -SNAPSHOT version
  • Make --update-snapshot to force update for -SNAPSHOT version
  • Maybe enhance to install only tagged released versions of the script
@inwardmovement
Copy link

Thats's sounds awesome... Do you know how to make a similar thing on Windows?

@howardjones
Copy link

howardjones commented Dec 17, 2020

I like the idea but...

/home/howie/bin/process-md: line 188: syntax error near unexpected token `newline'
/home/howie/bin/process-md: line 188: `  done'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment