Script to convert OO to markdown, tex, and PDF using pandoc

Many thanks to you both! I’ve been trying to figure this out for a long time. Here’s the completed script, now with support for markdown bold and italic tags!

function run() {

// My pandoc template file; you'll need one of these to include necessary LaTeX front- and back-matter e.g. "\begin{document}." (You'll also need to look up where pandoc stores these and put yours there.)

var pandocTemplate = 'dmgarticletemplate';

// Setup

var app = Application.currentApplication();
app.includeStandardAdditions = true;
var OmniOutliner = Application('OmniOutliner');

// Get the current document

var doc = OmniOutliner.documents[0];

// Get the name (stripped of spaces) of the Omni Outliner document. The script may fail if your filename includes certain characters, e.g. parentheses.

var fileName = doc.name().replace(/\s/g, '');

// Create a directory on the desktop to hold our new files

var desktopString = app.pathTo("desktop").toString()
app.doShellScript(`mkdir -p ${desktopString}/LaTeX/`);

// The text of the paper

var paperText = "";

// Loop through rows and append their text to paperText

doc.rows().forEach(function(theRow) {
	if (Object.keys(theRow.style.namedStyles).length > 0) {
		switch(theRow.style.namedStyles[0].name()) {
			case "Heading 1":
				paperText += "# ";
				break;
			case "Heading 2":
				paperText += "## ";
				break;
			case "Heading 3":
				paperText += "### ";
				break;
			case "Blockquote":
				paperText += "> ";
				break;
			case "Ordered List":
				paperText += "1. ";
				break;
			case "Unordered List":
				paperText += "* ";
				break;
		}	
	}
	paperText += rowTextMD(theRow);
	paperText += "\r\r";
});

// Convert the text of the paper to UTF8 encoding so pandoc can read it

paperText = $.NSString.alloc.initWithUTF8String(paperText);

// Write paperText to a new markdown file

var file = `${desktopString}/LaTeX/${fileName}.md`
paperText.writeToFileAtomicallyEncodingError(file, true, $.NSUTF8StringEncoding, null);

// Use pandoc to convert that markdown file to a tex file

shellCommand = `/usr/local/bin/pandoc ${desktopString}/LaTeX/${fileName}.md -f markdown -t latex -o ${desktopString}/LaTeX/${fileName}.tex --template=${pandocTemplate}`;

app.doShellScript(shellCommand);

// Compile our new tex file to PDF using xelatex

shellCommand = `/Library/TeX/texbin/xelatex --output-directory=${desktopString}/LaTeX/ ${desktopString}/LaTeX/${fileName}.tex`;

app.doShellScript(shellCommand);

return true;

}

// From apple's documentation for Javascript for Automation
 
function writeTextToFile(text, file, overwriteExistingContent) {
    try {
 
        // Convert the file to a string
        var fileString = file.toString()
 
        // Open the file for writing
        var openedFile = app.openForAccess(Path(fileString), { writePermission: true })
 
        // Clear the file if content should be overwritten
        if (overwriteExistingContent) {
            app.setEof(openedFile, { to: 0 })
        }
 
        // Write the new content to the file
        app.write(text, { to: openedFile, startingAt: app.getEof(openedFile) })
 
        // Close the file
        app.closeAccess(openedFile)
 
        // Return a boolean indicating that writing was successful
        return true
    }
    catch(error) {
 
        try {
            // Close the file
            app.closeAccess(file)
        }
        catch(error) {
            // Report the error is closing failed
            console.log(`Couldn't close file: ${error}`)
        }
 
        // Return a boolean indicating that writing was successful
        return false
    }
}

// Code below written by draft8, based on code written by SGIII, in turn adapted from AppleScript code written by Rob Trew

const rowTextMD = row => {
        const
            as = row.topic.attributeRuns;
        return enumFromTo(0, as.length - 1)
            .reduce((s, i) => {
                const
                    attrib = as.at(i),
                    fnt = attrib.font(),
                    bld = (fnt.includes('Bold') || fnt.includes('Black')) ? (
                        '**'
                    ) : '',
                    ital = fnt.includes('Italic') ? '*' : '';
                return s + bld + ital + attrib.text() + ital + bld;
            }, '') + '\n';
    };
	
// enumFromTo :: Int -> Int -> [Int]
const enumFromTo = (m, n) =>
	Array.from({
	length: Math.floor(n - m) + 1
    }, (_, i) => m + i);
1 Like