Action

Search with one of services listed in a draft

Posted by @ComplexPoint, Last update over 5 years ago

Search on-line for :

  1. the selected phrase, or
  2. the text of the line containing the cursor.

Displays:

  • a menu of online search services, and
  • a text field for adjusting or replacing the search term.

The menu items are defined by any Markdown-formatted links in a draft whose UUID
should be specified at the top of the script step.

The idea is to facilitate edits and additions to the list of services, by taking it:

  • out of the script step code,
  • and into a draft.

It would also be possible, by:

  • duplicating the action, and
  • making a copy with a different UUID at the top of the script step

to use more than one such action, each using a different list of services, contained in a different draft.

( Note: the UUID of a draft can be obtained though the information icon at top left > Copy Link to Draft )

Sample of a possible draft contents for use with this action, adapted from the Search Field Mega Action by @jmreeks:

[Amazon](https://amazon.com/s?ie=UTF8&index=blended&keywords=)
[App Store](itms-apps://search.itunes.apple.com/WebObjects/MZSearch.woa/wa/search?media=software&term=)
[DuckDuckGo](https://duckduckgo.com/?q=)
[Google](https://google.com/search?q=)
[Google Images](https://google.com/search?tbm=isch&q=)
[Google Translate](https://translate.google.com/#auto/en/)
[IMDB](https://www.imdb.com/find?q=)
[iTunes](itms:/search?term=)
[Rotten Tomatoes](https://www.rottentomatoes.com/search/?search=)
[Twitter](https://twitter.com/search?q=)
[Wikipedia](https://en.wikipedia.org/wiki/Special:Search?search=)
[Wolfram Alpha](https://www.wolframalpha.com/input/?i=)
[YouTube](https://www.youtube.com/results?search_query=)

Steps

  • script

    (() => {
        'use strict';
    
        /* UUID of a draft containing MD links with
          named search expressions up to the '=' sign.
          e.g.
    
             [DuckDuckGo](https://duckduckgo.com/?q=)
       */
        // SERVICES EITHER FROM MARKDOWN LINKS IN A DRAFT,
        // (specified by its uuid)
        const uuidLinksDraft =
            '9A15F571-0871-4DF7-A1F3-2E5464F197A3';
    
        // OR IF DRAFT NOT FOUND BY THAT UUID, THEN FROM THESE DEFAULTS:
        const fallbackDefaults = `
    [Amazon](https://amazon.com/s?ie=UTF8&index=blended&keywords=)
    [App Store](itms-apps://search.itunes.apple.com/WebObjects/MZSearch.woa/wa/search?media=software&term=)
    [DuckDuckGo](https://duckduckgo.com/?q=)
    [Google](https://google.com/search?q=)
    [Google Images](https://google.com/search?tbm=isch&q=)
    [Google Translate](https://translate.google.com/#auto/en/)
    [IMDB](https://www.imdb.com/find?q=)
    [iTunes](itms:/search?term=)
    [Rotten Tomatoes](https://www.rottentomatoes.com/search/?search=)
    [Twitter](https://twitter.com/search?q=)
    [Wikipedia](https://en.wikipedia.org/wiki/Special:Search?search=)
    [Wolfram Alpha](https://www.wolframalpha.com/input/?i=)
    [YouTube](https://www.youtube.com/results?search_query=)`;
    
        const main = () => {
            const
                d = Draft.find(uuidLinksDraft),
                lrResult = bindLR(
                    bindLR(
                        // LIST OF SERVICES EITHER FROM DRAFT
                        // WITH GIVEN UUID OR FROM DEFAULTS ABOVE
                        Right(
                            d !== undefined ? [
                                'List found in draft:\n' +
                                uuidLinksDraft,
                                d.content
                            ] : [
                                'No draft found by uuid:\n' +
                                uuidLinksDraft +
                                '\n(using default service list)',
                                fallbackDefaults
                            ]
                        ),
                        ([sourceName, strLinks]) => Right([
                            sourceName,
                            new Map(
                                regexMatches(
                                    /\[(.*)\]\((.*)\)/g,
                                    strLinks
                                )
                                .map(x => [x[1], x[2]])
                            )
                        ])
                    ),
                    ([sourceName, serviceMap]) => {
                        const e = editor;
                        return bindLR(
                            textAndMenuChoiceLR(
                                true, 'Search with chosen service',
                                sourceName,
                                'Term:',
    
                                // SELECTION OR CURRENT LINE
                                e.getSelectedText().trim() ||
                                e.getTextInRange(
                                    ...e.getSelectedLineRange()
                                ), [...serviceMap.keys()]
                            ),
                            dct => {
                                const maybeURL = serviceMap
                                    .get(dct.choice);
                                return maybeURL !== undefined ? (
                                    Right(
                                        app.openURL(
                                            maybeURL +
                                            encodeURIComponent(
                                                dct.text
                                            )
                                        )
                                    )
                                ) : Left(
                                    'Service not found: ' +
                                    dct.choice
                                );
                            }
                        );
                    }
                );
            const strLeft = lrResult.Left;
            return strLeft && strLeft.includes('uuid') ? (
                alert(strLeft)
            ) : console.log(lrResult.Left || lrResult.Right)
        };
    
        // A CONFIRMED TEXT, AND AN ITEM CHOSEN FROM A MENU
    
        // textAndMenuChoiceLR :: Bool -> String -> String ->
        //	String -> String -> [String] ->
        //  Either String { text: String, choice :: String }
        const textAndMenuChoiceLR = (
            withCancelButton, title, msg,
            strLabel, strText, items) => {
            const p = items.reduce(
                (a, item) => (a.addButton(item), a),
                Object.assign(
                    Prompt.create(), {
                        title: title,
                        message: msg,
                        isCancellable: withCancelButton
                    }
                )
            );
            return (
                p.addTextField('txt', strLabel, strText),
                items.length > 0 ? (
                    p.show() ? Right({
                        text: p.fieldValues.txt,
                        choice: p.buttonPressed
                    }) : Left('Cancel')
                ) : Left('Empty menu')
            );
        };
    
        // GENERIC FUNCTIONS ---
    
        // Left :: a -> Either a b
        const Left = x => ({
            type: 'Either',
            Left: x
        });
    
        // Right :: b -> Either a b
        const Right = x => ({
            type: 'Either',
            Right: x
        });
    
        // bindLR (>>=) :: Either a -> (a -> Either b) -> Either b
        const bindLR = (m, mf) =>
            m.Right !== undefined ? (
                mf(m.Right)
            ) : m;
    
        // regexMatches :: String -> String -> [[String]]
        const regexMatches = (strRgx, strHay) => {
            const rgx = new RegExp(strRgx, 'g');
            let m = rgx.exec(strHay),
                xs = [];
            while (m)(xs.push(m), m = rgx.exec(strHay));
            return xs;
        };
    
        // MAIN ---
        return main();
    })();
    

Options

  • After Success Default
    Notification Error
    Log Level Info
Items available in the Drafts Directory are uploaded by community members. Use appropriate caution reviewing downloaded items before use.