Modify the 'Man Page' script to tag imported pdfs with 'manpage'

I want to have the default script to import man pages add the tag manpage to the resultant pdf file.

I was trying to follow examples of other scripts but have failed miserably :frowning:

Heres’ the original script:

-- Man Page
-- Created by Christian Grunenberg on Sat Apr 16 2005.
-- Copyright (c) 2005-2019. All rights reserved.

-- Edited by Houthakker 2011 Feb 12 to import PDF (rather than text) version of man page
-- (to preserve highlighting of keywords and headers)

tell application id "DNtp"
	try
		repeat
			set page to display name editor "Man page" info "Enter the man page to import:"
			if page is not "" then exit repeat
		end repeat
		
		show progress indicator "Converting man page to PDF ..." steps -1
		set strPDF to "~/" & page & ".pdf"
		set strCmd to "man -t " & (quoted form of page) & " | pstopdf -i -o " & strPDF
		do shell script strCmd
		
		tell application id "com.apple.finder"
			set strTmpPath to (((path to home folder) as text) & page & ".pdf")
			set blnExists to exists strTmpPath
		end tell
		
		if blnExists then
			import strPDF name page to current group
			tell application id "com.apple.finder" to delete file strTmpPath
		else
			error "Page does not exist."
		end if
		hide progress indicator
	on error error_message number error_number
		hide progress indicator
		if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
	end try
end tell

You need to set a variable to the resulting record. Then set the tags of the record.

-- Man Page
-- Created by Christian Grunenberg on Sat Apr 16 2005.
-- Copyright (c) 2005-2019. All rights reserved.

-- Edited by Houthakker 2011 Feb 12 to import PDF (rather than text) version of man page
-- (to preserve highlighting of keywords and headers)

tell application id "DNtp"
	try
		repeat
			set page to display name editor "Man page" info "Enter the man page to import:"
			if page is not "" then exit repeat
		end repeat
		
		show progress indicator "Converting man page to PDF ..." steps -1
		set strPDF to "~/" & page & ".pdf"
		set strCmd to "man -t " & (quoted form of page) & " | pstopdf -i -o " & strPDF
		do shell script strCmd
		
		tell application id "com.apple.finder"
			set strTmpPath to (((path to home folder) as text) & page & ".pdf")
			set blnExists to exists strTmpPath
		end tell
		
		if blnExists then
			set theRecord to import strPDF name page to current group
			set tags of theRecord to {"manpage"}
			tell application id "com.apple.finder" to delete file strTmpPath
		else
			error "Page does not exist."
		end if
		hide progress indicator
	on error error_message number error_number
		hide progress indicator
		if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
	end try
end tell
1 Like

Thanks! I’ve modified the script a bit further; it now adds the page name as a tag.

set tags of theRecord to {"manpage", page}

Link to updated script.

FWIW a variant which imports and tags several man pages at once (and reports on which, if any, could not be found under the given name).

(JavaScript for Automation, so JavaScript in the top left language selector of Script Editor)

JS source behind the disclosure triangle below. Copy all the way down to the end, which looks like:

    // MAIN
    return main();
})();
JavaScript Source :: import and tag man pages (as PDF)
(() => {
    'use strict';

    // Houthakker @2020
    // @complexpoint

    // A variant of 'import and tag man pages', which allows
    // for several pages to be named and imported 
    // to DEVONthink 3 at once.

    // Ver 0.1

    // main :: IO ()
    const main = () => {
        // tag(s) to assign to imported man pages.
        const tagList = ['manpage'];

        return either(
            alert('man pages not all found')
        )(
            alert('man page(s) imported')
        )(
            bindLR(
                bashNamesFromDialogLR(
                    Application('DEVONthink 3')
                )
            )(
                pdfsImportedToAppLR(tagList)
            )
        );
    };


    // ------------------- DEVONTHINK --------------------

    // bashNamesFromDialogLR :: App 
    // -> IO Either String (App, String)
    const bashNamesFromDialogLR = dt3 => {
        try {
            return (
                dt3.activate(),
                Right([
                    dt3,
                    dt3.displayNameEditor('Man pages', {
                        info: 'Names of man pages to import:'
                    })
                ])
            );
        } catch (e) {
            return Left(head(lines(e.message)));
        };
    };


    // importedAndTagged :: App -> (String, FilePath) ->
    // [String] -> IO String
    const importedAndTagged = app =>
        namePaths => tags => namePaths.map(
            namePath => {
                const [page, fp] = Array.from(namePath);
                return (
                    // In DEVONthink 3,
                    app.stepProgressIndicator(
                        `Importing ${page}.pdf ...`
                    ),
                    app.import(fp, {
                        to: app.currentGroup
                    }).tags = tags,
                    app.stepProgressIndicator(
                        `${page}.pdf imported.`
                    ),
                    // and in JS.
                    page
                );
            }
        );


    // pdfPageCreatedLR :: App -> String -> 
    // FilePath -> IO Either String String
    const pdfPageCreatedLR = app =>
        page => {
            const fp = tempFilePath(`${page}.pdf`);
            try {
                return (
                    // In the shell,
                    Object.assign(
                        Application.currentApplication(), {
                            includeStandardAdditions: true
                        }).doShellScript(
                        `man -t '${page}' | ` + (
                            `pstopdf -i -o ${fp}`
                        )
                    ),
                    doesFileExist(fp) ? (
                        // in DEVONthink,
                        app.stepProgressIndicator(
                            `PDF created :: ${page}`
                        ),
                        // and in JS.
                        Right(Tuple(page)(fp))
                    ) : (
                        // In DEVONthink,
                        app.stepProgressIndicator(
                            `No PDF :: ${page}`
                        ),
                        // and in JS.
                        Left(Tuple('PDF was not created.')(page))
                    )
                );
            } catch (e) {
                return Left(
                    Tuple(page)(
                        head(lines(e.message))
                    )
                );
            }
        };

    // pdfsForCommandNamesLR :: App -> 
    //  String -> IO Either String [FilePath]
    const pdfsForCommandNamesLR = app =>
        pageNames => {
            const pages = pageNames.split(/[\W]+/);
            return (
                // in Application,
                app.showProgressIndicator(
                    `Converting ${pages.length} man page(s) to PDF ...`, {
                        steps: -1
                    }
                ),
                // and in JS.
                pages.map(pdfPageCreatedLR(app))
            );
        };


    // pdfsImportedToAppLR :: [String] -> 
    // (App, String) -> IO Either String String
    const pdfsImportedToAppLR = tagList =>
        ([app, pageNames]) => {
            const [missing, found] = Array.from(
                partitionEithers(
                    pdfsForCommandNamesLR(app)(pageNames)
                )
            );
            const
                imported = importedAndTagged(app)(
                    found
                )(tagList);
            return (
                app.hideProgressIndicator(),
                missing.length ? Left(
                    'Not found:\n\n' + bulleted('    ')(
                        missing.map(
                            x => `'${fst(x)}'`
                        ).join('\n')
                    ) + (
                        0 < imported.length ? (
                            '\n\nimported and tagged :: ' + (
                                imported.join(' ')
                            )
                        ) : ''
                    )
                ) : Right(
                    'Imported:\n\n' + (
                        bulleted('')(
                            found.map(fst).join('\n')
                        )
                    )
                )
            );
        };


    // ----------------------- JXA -----------------------

    // alert :: String => String -> IO String
    const alert = title =>
        s => {
            const sa = Object.assign(
                Application('System Events'), {
                    includeStandardAdditions: true
                });
            return (
                sa.activate(),
                sa.displayDialog(s, {
                    withTitle: title,
                    buttons: ['OK'],
                    defaultButton: 'OK',
                    withIcon: sa.pathToResource(
                        'DEVONthink 3.icns', {
                            inBundle: 'Applications/DEVONthink 3.app'
                        })
                }),
                s
            );
        };


    // --------------------- GENERIC ---------------------
    // https: //github.com/RobTrew/prelude-jxa

    // Left :: a -> Either a b
    const Left = x => ({
        type: 'Either',
        Left: x
    });


    // Right :: b -> Either a b
    const Right = x => ({
        type: 'Either',
        Right: x
    });


    // Tuple (,) :: a -> b -> (a, b)
    const Tuple = a =>
        b => ({
            type: 'Tuple',
            '0': a,
            '1': b,
            length: 2
        });


    // bindLR (>>=) :: Either a -> 
    // (a -> Either b) -> Either b
    const bindLR = m =>
        mf => undefined !== m.Left ? (
            m
        ) : mf(m.Right);


    // bulleted :: String -> String -> String
    const bulleted = strTab =>
        s => s.split(/[\r\n]/).map(
            x => '' !== x ? strTab + '- ' + x : x
        ).join('\n');


    // doesFileExist :: FilePath -> IO Bool
    const doesFileExist = fp => {
        const ref = Ref();
        return $.NSFileManager.defaultManager
            .fileExistsAtPathIsDirectory(
                $(fp)
                .stringByStandardizingPath, ref
            ) && 1 !== ref[0];
    };


    // either :: (a -> c) -> (b -> c) -> Either a b -> c
    const either = fl =>
        // Application of the function fl to the
        // contents of any Left value in e, or
        // the application of fr to its Right value.
        fr => e => 'Either' === e.type ? (
            undefined !== e.Left ? (
                fl(e.Left)
            ) : fr(e.Right)
        ) : undefined;


    // fst :: (a, b) -> a
    const fst = tpl =>
        // First member of a pair.
        tpl[0];


    // head :: [a] -> a
    const head = xs =>
        xs.length ? (
            xs[0]
        ) : undefined;


    // last :: [a] -> a
    const last = xs =>
        // The last item of a list.
        0 < xs.length ? (
            xs.slice(-1)[0]
        ) : undefined;


    // lines :: String -> [String]
    const lines = s =>
        // A list of strings derived from a single
        // string delimited by newline and or CR.
        0 < s.length ? (
            s.split(/[\r\n]+/)
        ) : [];


    // partitionEithers :: [Either a b] -> ([a],[b])
    const partitionEithers = xs =>
        xs.reduce(
            (a, x) => undefined !== x.Left ? (
                Tuple(a[0].concat(x.Left))(a[1])
            ) : Tuple(a[0])(a[1].concat(x.Right)),
            Tuple([])([])
        );


    // tempFilePath :: String -> IO FilePath
    const tempFilePath = fileName =>
        // File name template for temporary path.
        ObjC.unwrap($.NSTemporaryDirectory()) + fileName;


    // zip :: [a] -> [b] -> [(a, b)]
    const zip = xs =>
        // The paired members of xs and ys, up to
        // the length of the shorter of the two lists.
        ys => Array.from({
            length: Math.min(xs.length, ys.length)
        }, (_, i) => [xs[i], ys[i]]);

    // MAIN
    return main();
})();
1 Like