Selecting a particular project

can anyone help me modify this script to select a particular project whose name is “example”

tell application “OmniFocus”
activate
delay 0.2
tell front window
set selectedTrees to selected trees of content
set selectedTasks to every item of selectedTrees
end tell

tell front document
	repeat with i from 1 to count of selectedTasks
		set theTask to the value of item i of selectedTasks
		set currTags to name of tags of theTask
		
		repeat with x from 1 to count of currTags
			set currTag to item x of currTags
			if currTag = "today" then
				set currTag to (first flattened tag whose name is item x of currTags)
				remove currTag from tags of theTask
			end if
		end repeat
		
		mark complete theTask
		
	end repeat
end tell

end tell

What are you specifically looking for ? Do you want to mark a task as completed within a specific project ?

yes i am trying to mark tasks complete in a particular project with the specific tag like “today”.

yes i am trying to mark tasks complete in a particular project with the specific tag like “today”.

Understood. Will look into it in a few hours.

Thank you so much really appreciate it

Here is a cross-platform (iOS/Mac) OmniJS Plug-In. Does it solve your problem ? If you really need an AppleScript version, I can look into it later.

Save this code into a file with .omnijs extension and save it in your OmniFocus iCloud folder. It should appear automatically in the Automation menu. The script assumes there is a project named ‘Example’ in the database.

Full code:

/*{
    "type": "action",
    "name": "Remove tag from tasks and mark complete in specific project",
    "author": "@unlocked2412",
    "version": "0.10",
    "description": "Remove tag from tasks and mark complete in specific project",
    "mediumLabel": "Remove tag",
    "paletteLabel": "Remove tag",
}*/
// Twitter: @unlocked2412
(() => {
    // ---------------------- PLUGIN -----------------------
    return Object.assign(
        new PlugIn.Action(selection => {
            'use strict';

            // OMNI JS CODE ---------------------------------------
            const omniJSContext = () => {
                // main :: IO ()
                const main = () => {
                    const projName = 'Example'
                    const tagName = 'next'
                    const lrTasks = bindLR(
                        projectLR(projName)
                    )(
                        proj => {
                            const tasks = filter(
                                x => x.taskStatus !== Task.Status.Completed &&
                                elem(tagName)(map(x => x.name)(x.tags))
                            )(proj.flattenedTasks);
                            return 0 === tasks.length ? (
                                Left('No tasks in project: ' + projName)
                            ) : Right(tasks)
                        }
                    )
                    return new Alert(
                        'Complete and remove tag',
                        either(identity)(
                            xs => `Completed ${map(task => {
                        return (
                            task.removeTag(tagFoundOrCreated(tagName)),
                            task.markComplete(),
                            task
                        )
                    })(xs).length} tasks`
                        )(lrTasks)
                    ).show()
                };

                // projectLR :: String -> Either String OFProject
                const projectLR = strName => {
                    const xs = filter(x => strName === x.name)(
                        flattenedProjects
                    );
                    return 0 === xs.length ? (
                        Left(`No projects named '${strName}' in the database.`)
                    ) : Right(xs[0])
                };


                // FUNCTIONS --
                // https://github.com/RobTrew/prelude-jxa
                // JS Prelude --------------------------------------------------
                // Just :: a -> Maybe a
                const Just = x => ({
                    type: 'Maybe',
                    Nothing: false,
                    Just: x
                });

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

                // Nothing :: Maybe a
                const Nothing = () => ({
                    type: 'Maybe',
                    Nothing: true,
                });

                // 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
                    });

                // and :: [Bool] -> Bool
                const and = xs =>
                    // True unless any value in xs is false.
                    [...xs].every(Boolean);

                // append (++) :: [a] -> [a] -> [a]
                const append = xs =>
                    // A list defined by the
                    // concatenation of two others.
                    ys => xs.concat(ys);

                // bind (>>=) :: Monad m => m a -> (a -> m b) -> m b
                const bind = m =>
                    mf => (Array.isArray(m) ? (
                        bindList
                    ) : (() => {
                        const t = m.type;
                        return 'Either' === t ? (
                            bindLR
                        ) : 'Maybe' === t ? (
                            bindMay
                        ) : 'Tuple' === t ? (
                            bindTuple
                        ) : ('function' === typeof m) ? (
                            bindFn
                        ) : undefined;
                    })()(m)(mf));

                // bindFn (>>=) :: (a -> b) -> (b -> a -> c) -> a -> c
                const bindFn = f =>
                    // Binary operator applied over f x and x.
                    bop => x => bop(f(x))(x);

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

                // bindList (>>=) :: [a] -> (a -> [b]) -> [b]
                const bindList = xs =>
                    mf => [...xs].flatMap(mf);

                // bindMay (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
                const bindMay = mb =>
                    // Nothing if mb is Nothing, or the application of the
                    // (a -> Maybe b) function mf to the contents of mb.
                    mf => mb.Nothing ? (
                        mb
                    ) : mf(mb.Just);

                // bindTuple (>>=) :: Monoid a => (a, a) -> (a -> (a, b)) -> (a, b)
                const bindTuple = tpl =>
                    f => {
                        const t2 = f(tpl[1]);
                        return Tuple(mappend(tpl[0])(t2[0]))(
                            t2[1]
                        );
                    };

                // concat :: [[a]] -> [a]
                // concat :: [String] -> String
                const concat = xs => (
                    ys => 0 < ys.length ? (
                        ys.every(Array.isArray) ? (
                            []
                        ) : ''
                    ).concat(...ys) : ys
                )(list(xs));

                // dropAround :: (a -> Bool) -> [a] -> [a]
                // dropAround :: (Char -> Bool) -> String -> String
                const dropAround = p =>
                    xs => dropWhile(p)(
                        dropWhileEnd(p)(xs)
                    );

                // dropWhile :: (a -> Bool) -> [a] -> [a]
                // dropWhile :: (Char -> Bool) -> String -> String
                const dropWhile = p =>
                    xs => {
                        const n = xs.length;
                        return xs.slice(
                            0 < n ? until(
                                i => n === i || !p(xs[i])
                            )(i => 1 + i)(0) : 0
                        );
                    };

                // dropWhileEnd :: (a -> Bool) -> [a] -> [a]
                // dropWhileEnd :: (Char -> Bool) -> String -> [Char]
                const dropWhileEnd = p =>
                    // xs without the longest suffix for which
                    // p returns true for all elements.
                    xs => {
                        let i = xs.length;
                        while (i-- && p(xs[i])) {}
                        return xs.slice(0, i + 1);
                    };

                // 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;

                // elem :: Eq a => a -> [a] -> Bool
                const elem = x =>
                    // True if xs contains an instance of x.
                    xs => {
                        const t = xs.constructor.name;
                        return 'Array' !== t ? (
                            xs['Set' !== t ? 'includes' : 'has'](x)
                        ) : xs.some(eq(x));
                    };

                // enumFromTo :: Int -> Int -> [Int]
                const enumFromTo = m =>
                    n => !isNaN(m) ? (
                        Array.from({
                            length: 1 + n - m
                        }, (_, i) => m + i)
                    ) : enumFromTo_(m)(n);

                // enumFromTo_ :: Enum a => a -> a -> [a]
                const enumFromTo_ = m => n => {
                    const [x, y] = [m, n].map(fromEnum),
                        b = x + (isNaN(m) ? 0 : m - x);
                    return Array.from({
                        length: 1 + (y - x)
                    }, (_, i) => toEnum(m)(b + i));
                };

                // eq (==) :: Eq a => a -> a -> Bool
                const eq = a =>
                    // True when a and b are equivalent in the terms
                    // defined below for their shared data type.
                    b => {
                        const t = typeof a;
                        return t !== typeof b ? (
                            false
                        ) : 'object' !== t ? (
                            'function' !== t ? (
                                a === b
                            ) : a.toString() === b.toString()
                        ) : (() => {
                            const kvs = Object.entries(a);
                            return kvs.length !== Object.keys(b).length ? (
                                false
                            ) : kvs.every(([k, v]) => eq(v)(b[k]));
                        })();
                    };

                // filter :: (a -> Bool) -> [a] -> [a]
                const filter = p =>
                    // The elements of xs which match
                    // the predicate p.
                    xs => [...xs].filter(p);

                // fromEnum :: Enum a => a -> Int
                const fromEnum = x =>
                    typeof x !== 'string' ? (
                        x.constructor === Object ? (
                            x.value
                        ) : parseInt(Number(x))
                    ) : x.codePointAt(0);

                // identity :: a -> a
                const identity = x =>
                    // The identity function.
                    x;

                // join :: Monad m => m (m a) -> m a
                const join = x =>
                    bind(x)(identity);

                // keys :: Dict -> [String]
                const keys = Object.keys;

                // length :: [a] -> Int
                const length = xs =>
                    // Returns Infinity over objects without 
                    // finite length, enabling zip and zipWith
                    // to choose the shorter argument when one 
                    // is non-finite, like a cycle or repeat.
                    'GeneratorFunction' !== (
                        xs.constructor.constructor.name
                    ) ? xs.length : Infinity;

                // list :: StringOrArrayLike b => b -> [a]
                const list = xs =>
                    // xs itself, if it is an Array,
                    // or an Array derived from xs.
                    Array.isArray(xs) ? (
                        xs
                    ) : Array.from(xs || []);

                // map :: (a -> b) -> [a] -> [b]
                const map = f =>
                    // The list obtained by applying f
                    // to each element of xs.
                    // (The image of xs under f).
                    xs => [...xs].map(f);

                // mappend (<>) :: Monoid a => a -> a -> a
                const mappend = a =>
                    // Associative operation 
                    // defined for various monoid types.
                    b => (t => (Boolean(t) ? (
                        'Maybe' === t ? (
                            mappendMaybe
                        ) : mappendTuple
                    ) : Array.isArray(a) ? (
                        append
                    ) : 'function' === typeof a ? (
                        mappendFn
                    ) : mappendOrd)(a)(b))(a.type);

                // mappendFn :: Monoid b => (a -> b) -> (a -> b) -> (a -> b)
                const mappendFn = f =>
                    g => x => mappend(f(x))(
                        g(x)
                    );

                // mappendMaybe (<>) :: Maybe a -> Maybe a -> Maybe a
                const mappendMaybe = a =>
                    b => a.Nothing ? (
                        b
                    ) : b.Nothing ? (
                        a
                    ) : Just(
                        mappend(a.Just)(
                            b.Just
                        )
                    );

                // mappendOrd (<>) :: Ordering -> Ordering -> Ordering
                const mappendOrd = x =>
                    y => 0 !== x ? (
                        x
                    ) : y;

                // mappendTuple (<>) :: (a, b) -> (a, b) -> (a, b)
                const mappendTuple = t => t2 =>
                    Tuple(
                        mappend(t[0])(
                            t1[0]
                        )
                    )(mappend(t[1])(
                        t1[1]
                    ));

                // min :: Ord a => a -> a -> a
                const min = a =>
                    b => b < a ? b : a;

                // replace :: String -> String -> String -> String
                // replace :: Regex -> String -> String -> String
                const replace = needle => strNew => strHaystack =>
                    strHaystack.replace(
                        'string' !== typeof needle ? (
                            needle
                        ) : new RegExp(needle, 'g'),
                        strNew
                    );

                // show :: a -> String
                // show :: a -> Int -> Indented String
                const show = x => {
                    const
                        e = ('function' !== typeof x) ? (
                            x
                        ) : {
                            type: 'Function',
                            f: x
                        };
                    return JSON.stringify(e, (_, v) => {
                        const
                            f = ((null !== v) && (undefined !== v)) ? (() => {
                                const t = v.type;
                                return 'Either' === t ? (
                                    showLR
                                ) : 'Function' === t ? (
                                    dct => 'λ' + dct.f.toString()
                                ) : 'Maybe' === t ? (
                                    showMaybe
                                ) : 'Ordering' === t ? (
                                    showOrdering
                                ) : 'Ratio' === t ? (
                                    showRatio
                                ) : 'string' === typeof t && t.startsWith('Tuple') ? (
                                    showTuple
                                ) : Array.isArray(v) ? (
                                    showList
                                ) : undefined;
                            })() : showUndefined;
                        return Boolean(f) ? (
                            f(v)
                        ) : 'string' !== typeof v ? (
                            v
                        ) : v;
                    });
                };

                // showLR :: Either a b -> String
                const showLR = lr => {
                    const k = undefined !== lr.Left ? (
                        'Left'
                    ) : 'Right';
                    return k + '(' + unQuoted(show(lr[k])) + ')';
                };

                // showList :: [a] -> String
                const showList = xs =>
                    '[' + xs.map(show)
                    .join(', ')
                    .replace(/[\"]/g, '') + ']';

                // showMaybe :: Maybe a -> String
                const showMaybe = mb =>
                    mb.Nothing ? (
                        'Nothing'
                    ) : 'Just(' + unQuoted(show(mb.Just)) + ')';

                // showOrdering :: Ordering -> String
                const showOrdering = e =>
                    0 < e.value ? (
                        'GT'
                    ) : 0 > e.value ? (
                        'LT'
                    ) : 'EQ';

                // showRatio :: Ratio -> String
                const showRatio = r =>
                    'Ratio' !== r.type ? (
                        r.toString()
                    ) : r.n.toString() + (
                        1 !== r.d ? (
                            '/' + r.d.toString()
                        ) : ''
                    );

                // showTuple :: Tuple -> String
                const showTuple = tpl =>
                    '(' + enumFromTo(0)(tpl.length - 1)
                    .map(x => unQuoted(show(tpl[x])))
                    .join(',') + ')';

                // showUndefined :: () -> String
                const showUndefined = () => '(⊥)';

                // toEnum :: a -> Int -> a
                const toEnum = e =>
                    // The first argument is a sample of the type
                    // allowing the function to make the right mapping
                    x => ({
                        'number': Number,
                        'string': String.fromCodePoint,
                        'boolean': Boolean,
                        'object': v => e.min + v
                    } [typeof e])(x);

                // unQuoted :: String -> String
                const unQuoted = s =>
                    dropAround(x => 34 === x.codePointAt(0))(
                        s
                    );

                // until :: (a -> Bool) -> (a -> a) -> a -> a
                const until = p => f => x => {
                    let v = x;
                    while (!p(v)) v = f(v);
                    return v;
                };

                // OmniFocus OmniJS --------------------------------------------
                // removeTag :: Tag Object -> OFItem -> OFItem
                const removeTag = oTag => item => {
                    item.removeTag(oTag)
                    return item
                }

                // tagFoundOrCreated :: Tag Name -> Tag Object
                const tagFoundOrCreated = strTag =>
                    tagNamed(strTag) || new Tag(strTag)

                return main();
            };

            return omniJSContext()

        }), {
            validate: selection => true
        });
})();
2 Likes

Thanks mate really appreciate it! Was hopping for an apple script version to implement it to my existing script. If it is not so much of an ask I would also appreciate an apple script version. However thank a lot mate!!

Sure ! Just a quick thought, to get a reference to a project named ‘Example’ in the database (assuming it exists), I think first flattened project whose name is "Example" would work.

Retrieving the tag reference to a tag named “today”, would be: set oTag to first flattened tag whose name is "today".

In full, retrieving the list of tasks in a specific project containing a tag named ‘today’:

tell application "OmniFocus"
    tell default document
        set oTag to first flattened tag whose name is "today"
        set oProj to first flattened project whose name is "Example"
        return flattened tasks of (first flattened project whose name is "Example") whose tags contains oTag
    end tell
end tell

I could take a closer look in the afternoon, if you need.

I would really much appreciate that because I cant figure it out for the life of me.

I think this should work:

tell application "OmniFocus"
    tell default document
        set oTag to first flattened tag whose name is "today"
        set oTasks to flattened tasks of (first flattened project whose name is "Example") whose tags contains oTag
        repeat with oTask in oTasks
            remove oTag from tags of oTask
            mark complete oTask
            oTask
        end repeat
    end tell
end tell
2 Likes

Thank you so much worked like a charm!!

1 Like

Good! You’re welcome. Glad to help.