Editorial Workflows

MD2LaTeX

public workflow

Install Workflow...

This workflow contains at least one Python script. Only use it if you trust the person who shared this with you, and if you know exactly what it does.

I understand, install the workflow!

This is a workflow for Editorial, a Markdown and plain text editor for iOS. To download it, you need to view this page on a device that has the app installed.

Description: Based on PDF (LaTeX) script by Peter Hopcroft, this script convert Markdown to LaTeX and ask if you want to:
- share to other device with Command-C app
- save .tex file in Dropbox
- just copi LaTeX in clipboard

Shared by: Tommaso Tani (@ttan_)

Comments: Comment Feed (RSS)

There are no comments yet.

+ Add Comment

Workflow Preview
Using this workflow ?
Source Code
#coding: utf-8
"""
This script is based on Peter Hopcroft "PDF (LaTeX)" workflow. I added differents output and edited LaTeX headers to fit my preferred layout of the document.

The CMD-C App sharing is very useful to transfer LaTeX code to any tex Mac app you normally use. In order to complete the transfer, set the device list in "Choose target device" block.

"""
PDF (LaTeX) - Peter Hopcroft, February 2014

The best way I've found to convert Markdown to PDF. This converts the Markdown file being edited to LaTeX and puts it on the clipboard. Then switch to the iOS app Texpad, paste the LaTeX into an empty .tex file and tap typeset to convert to PDF.

The workflow supports basic Markdown syntax except links, plus you can write LaTeX commands in the Markdown to do tables, equations and anything else. You have precise control over page design. The PDFs look great, because LaTeX knows about all the bits (letters, words ... pages) and optimises spacings. It all happens on the iPad, including images.

You'll need:
    http://tobi.oetiker.ch/lshort/lshort.pdf
    http://ctan.unsw.edu.au/macros/latex/contrib/memoir/memman.pdf
    grit

	
MEMOIR: The LaTeX uses the Memoir class.

LaTeX COMMANDS IN MARKDOWN: The workflow converts Markdown to html, then to LaTeX. To write LaTeX commands in Markdown requires \ { and } characters, and you are supposed to backslash escape them in Markdown. But Python Markdown does not seem to need this. The workflow loads the Tabulary package for writing tables.

CONVERSION:
from		to
#				title: same as ##, but no number
##			numbered chapter heading: starts on new page unless at start of text
###			section heading
####		subsection heading
#####		runin heading
######	same as #####
---			\pfbreak
code span elements: | is the end delimiter for now
code block elements: \end{verbatim} is the end delimiter

ENCODING: The workflow encodes the LaTeX as utf-8 to send to Texpad. But you can only use the less-than-256 characters listed in LaTeX's T1 encoding, see:
    http://www.tex.ac.uk/tex-archive/macros/latex/doc/encguide.pdf
For a character outside this, Texpad gives an 'package inputenc error'.

PICTURES: Before you run the workflow, import your picture files into Texpad (use +). They are imported as .png, about three times the size of .jpg. The workflow turns a Markdown image element into an equivalent LaTeX graphic element. My extensions:
- LaTeX requires a width. You can write a width in the alt text; if you don't the default is \textwidth.
- If you write a caption in the title text, the workflow puts the picture in a figure (floating) envoronment, with the caption under the picture.

For example:
	
![](picture.png) -> \includegraphics[width=\textwidth]{picture.png}

![100mm](picture.png) -> \includegraphics[width=100mm]{picture.png}

![100mm](picture.png 'Caption text here') ->
	
\begin{figure}[!hbtp]
\includegraphics[width=100mm]{picture.png}	
\par{}Caption text here
\end{figure}

The .png in the image file name is optional. Texpad has a bug, and sometimes says it can't find the image file when it is there. Try again.

LIGATURES: Texpad's local typesetter has a bug with some fonts (with utopia): Some ligatures are typeset wrong, eg 'ff' appears as 'f '. To avoid this, the E dictionary in the python script can put a zero-width space between faulty ligature character pairs; see the example for 'ff'. If you find more faulty pairs, add them to the E dictionary.

BEWARE:
- Don't use \ or & in regular text, because LaTeX assumes they are parts of commands.
- Some LaTeX commands conflict with Markdown and won't work. Eg LaTeX speech marks are ` ... ' and `` ... '', but you can't use them because Markdown uses ` to mark span code.
- I haven't tested all the valid combinations of Markdown syntax. Some will probably fail or look bad. For example, you can't nest block quotes.
- The faulty ligature pairs have the zero-width space inserted throughout the Markdown, including picture file names (rename if necessary) and LaTeX commands (I don't know if any are affected).

AND: I gleaned LaTeX from tex.stackoverflow. LaTeX can be sweatier than latex. The workflow has the sin of nonzero parskip nonzero and zero parindent. Texpad has a lot of rough edges.

"""
Convert markdown to LaTeX for Texpad ?
Source Code
#coding: utf-8

# PDF (LaTeX) - Peter Hopcroft, February 2014

import clipboard
import console
import editor
import markdown
import re
import os
import workflow

# constants -------------------------------------

# start of a LaTeX document, defines the page design- \\ is an escaped \
LSTART = """
\\documentclass[a4paper,12pt,openany,oneside]{memoir} 

\\usepackage[T1]{fontenc}
\\usepackage[utf8]{inputenc}
\\usepackage[italian]{babel}
%\\usepackage{utopia}
%\\usepackage{palatino}	% this works
%\\raggedright
\\usepackage{graphicx}
\\usepackage{enumitem}
\\usepackage{tabulary}

%\\usepackage{microtype} % does not help with ligature bug
%\\DisableLigatures[f]{encoding=T1, family=*}

% my global lengths
\\newlength{\\myparskip}
\\setlength{\\myparskip}{1.0ex plus 0.2ex minus 0.2ex}
\\newlength{\\myindent}
\\setlength{\\myindent}{3ex}
\\newlength{\\myskipbig}		% for headings
\\setlength{\\myskipbig}{5ex plus 1.0ex minus 1.0ex}
\\newlength{\\myskipsmall}		% for headings
\\setlength{\\myskipsmall}{1.5ex plus 0.3ex minus 0.3ex}

% page layout
\\pagestyle{plain}
\\setlrmarginsandblock{35mm}{35mm}{*}
\\setulmarginsandblock{25mm}{25mm}{*}
\\setlength{\\footskip}{8mm}
\\checkandfixthelayout

% paragraphs
\\setlength{\\parindent}{20pt}
\\abnormalparskip{\\myparskip}
\\linespread{1.1}

% the headings
\\setsecnumdepth{chapter} % number chapters but not lesser headings

% h1 - same as chapter heading but no number
\\newcommand{\\mytitle}[1]%
    {{\\newpage\\vspace*{-1.2\\topskip}%
     \\Large\\mdseries\\raggedright{#1}%
     \\thispagestyle{empty}%
     \\vspace{\\myskipbig}}} % is a group

% h2 - chapter heading
\\chapterstyle{section}
\\renewcommand*{\\chapterheadstart}{\\vspace*{-1.4\\topskip}} % space before
\\renewcommand*{\\chapnumfont}{\\Large\\mdseries\\raggedright}
\\renewcommand*{\\afterchapternum}{\\hspace{1.0ex}} % space after number
\\renewcommand*{\\chaptitlefont}{\\Large\\mdseries\\raggedright}
\\setlength{\\afterchapskip}{\\myskipbig} % space after

% h3 - section heading
\\setbeforesecskip{-\\myskipbig} % - for no hdr indent
\\setsecheadstyle{\\large\\mdseries\\raggedright}
\\setaftersecskip{\\myskipsmall}

% h4 - subsection heading
\\setbeforesubsecskip{-\\myskipbig} % - for no hdr indent
\\setsubsecheadstyle{\\itshape\\raggedright}
\\setaftersubsecskip{\\myskipsmall}

% h5 & h6 subsubsection heading - runin
\\setbeforesubsubsecskip{-\\myskipbig} % - for no hdr indent
\\setsubsubsecheadstyle{\\itshape\\raggedright}
\\setaftersubsubsecskip{-1.4ex} % for runin heading
    
% lists, using enumitem
\\newenvironment{myul}%   % unordered list
    {\\begin{itemize} [topsep=0pt, partopsep=0pt, itemsep=0pt, %
     parsep=\\parskip, leftmargin=\\myindent, labelindent=1.0pt, %
     labelsep=*, label={\\rule[0.2ex]{0.7ex}{0.7ex}}]}%
    {\\end{itemize} \\vspace{0ex} }

\\newenvironment{myol}%   % ordered list
    {\\begin{enumerate} [topsep=0pt, partopsep=0pt, itemsep=0pt, %
     parsep=\\parskip, leftmargin=\\myindent, labelindent=0.5pt, %
     labelsep=*, label=\\arabic*]}%
    {\\end{enumerate} \\vspace{0ex} }

% miscellaneous
\\newenvironment{myblockquote}%
    {\\leftskip=\\myindent}%
    {}

\\begin{document}
"""

# end of a LaTeX document
LEND = """
\\end{document}
"""

# dictionaries -------------------------------------

# html -> latex equivalents - \\ is an escaped \
D = {'<p>':'\n',
     '</p>': '', 
     '<h1>':'\n\\mytitle{',
     '</h1>':'}',
     '<h2>':'\n\\chapter{',
     '</h2>':'}',
     '<h3>':'\n\\section{',
     '</h3>':'}',
     '<h4>':'\n\\subsection{',
     '</h4>':'}',
     '<h5>':'\n\\subsubsection{',
     '</h5>':'}',
     '<h6>':'\n\\subsubsection{',
     '</h6>':'}',
     '<blockquote>':'\n\\begin{myblockquote}',
     '</blockquote>':'\n\\end{myblockquote}',
     '<ul>':'\n\\begin{myul}',
     '</ul>':'\\end{myul}',
     '<ol>':'\n\\begin{myol}',
     '</ol>': '\\end{myol}',
     '<li>':'\\item ',
     '</li>':'',
     '<pre><code>':'\n\\begin{myverbatim}',
     '</code></pre>':'\\end{myverbatim}',
     '<hr />':'\n\\pfbreak',
     '<em>':'\\emph{',
     '</em>':'}',
     '<strong>':'\\textbf{',
     '</strong>':'}',
     '<code>':'\\verb|',
     '</code>':'|',
     }

# html entities -> LaTeX characters or commands
# texpad has a bug with local typesetting: some ligatures, eg 'ff', 
# can typeset wrongly as 'f '; the lines below with \kern insert a 
# zero-size gap between two characters so they typeset properly
E = {'&amp;':'&',
     '&lt;':'<',
     'ff':'f\kern0pt{}f'
     }    

# functions -------------------------------------

# convert one html img element into a latex img element
def latex_img (html_img):
    # extract img file name
    mo = re.search('src="(.*?)"', html_img) # src="anychars"
    if (not mo) or (mo.group(1) == ''):
        f = 'No image file name found' # default
    else:
        f = mo.group(1)

    # extract img width
    mo = re.search('alt="(.*?)"', html_img) # alt="anychars"
    if (not mo) or (mo.group(1) == ''):
        w = '\\textwidth' # default
    else:
        w = mo.group(1)
        
    li = '\\includegraphics[width=' + w + ']{' + f + '}'
    
    # extract title
    mo = re.search('title="(.*?)"', html_img)	# get title="anychars"
    if (mo) and (mo.group(1) != ''):					# put in float
        li = '\n\\begin{figure}[!hbtp]\n' + li + '\n\\par{}' + mo.group(1) + '\n\\end{figure}\n'
    return li
    
# convert all html img elements to latex img elements
def do_imgs (txt): 
    new_txt = ''
    els = txt.split('<img')  # find img elements, start with <img
    for el in els:
        if '/>' in el:
            i_r = el.split('/>', 1)	# split into img element and the rest
            new_txt += latex_img(i_r[0]) + i_r[1]
        else:
            new_txt += el # no img element
    return new_txt
        
# main -------------------------------------
        
console.clear()
txt = editor.get_text()

if '\\' in txt:
    console.alert('Warning:\nThe markdown text\nhas the character:\n\\',
                  'These can only be in LaTeX commands, not in ordinary text',
                  'Continue')
if '&' in txt:
    console.alert('Warning:\nThe markdown text\nhas the character:\n&',
                  'These can only be in LaTeX lists, not in ordinary text',
                  'Continue')
                  
txt = markdown.markdown (txt)			# convert to html, no extensions
for k, v in D.iteritems():				# convert most html to LaTeX
    txt = txt.replace(k, v)
txt = do_imgs(txt)								# convert html imgs to latex imgs

if '<a' in txt and '</a>' in txt:	# check for unsupported html
    console.alert('Warning:\nThere is a markdown link',
                  'This workflow does not suport links in LaTeX', 
                  'Continue')
elif '<' in txt or '>' in txt:
   console.alert('Warning:\nThe LaTeX file has < or > brackets',
                 "This could be HTML that hasn't been converted to laTeX",
                 'Continue')

for k, v in E.iteritems():				# convert minor things to LaTeX
    txt = txt.replace(k, v)

txt = LSTART + txt + LEND					# add preamble and postamble
clipboard.set(txt.encode('utf_8', 'replace'))

# -------------------------------------
Choose destination ?
Title
Converted to LaTex!
Message
Choose destination:
Button 1
Clipoard to Mac
Output Value
clipboard
Button 2
File .tex in Dropbox
Output Value
dropbox
Button 3
Save in Clipboard
Output Value
stop
Show Cancel Button
ON
Redirecting to CMD-C ?
Run the block if
Input
  • is Equal to
  • is Not Equal to
  • Contains
  • Doesn't Contain
  • Matches Regular Expression
clipboard
Choose target device ?
Title
Choose device:
List (Lines)
Marcaurelio Nerone
Multiple Selection
OFF
Show in Popover
OFF
Open URL ?
Open in
  • In-App Browser
  • Default App / Safari
URL
command-c://x-callback-url/copy?deviceName=Input&x-success=editorial://
Tab
  • Last-used Tab
  • New Tab
  • Tab with ID:
Unique identifier
Wait until Loaded
ON
Reveal Browser Automatically
ON
…End If
Saving to dropbox ?
Run the block if
Input
  • is Equal to
  • is Not Equal to
  • Contains
  • Doesn't Contain
  • Matches Regular Expression
dropbox
Choose file name ?
Title
Scegli il nome del file
Initial Text
File Name.tex
  • Single Line
  • Multiple Lines
Keyboard Options:
Saving file ?
File Name
%var:Input
In Dropbox
ON
New Text
Clipboard
If File Does Not Exist
  • Create
  • Stop Workflow
Message: saved ?
HUD Text
File saved!
Duration
  • 1 Second
  • 2 Seconds
  • 3 Seconds
Icon
  • "Success"
  • "Error"
…End If
Just copy in clipboard ?
Run the block if
Input
  • is Equal to
  • is Not Equal to
  • Contains
  • Doesn't Contain
  • Matches Regular Expression
stop
Message: copied ?
HUD Text
LaTeX stored in your Clipboard
Duration
  • 1 Second
  • 2 Seconds
  • 3 Seconds
Icon
  • "Success"
  • "Error"
…End If