shdds
November 22, 2021, 11:45pm
1
Hi Everyone.
I’m coming back to macOS after ~8 years of Windows use, and was trying to set up Taskpaper the way I had it back in OSX days.
I guess the old extensions using AppleScript won’t work anymore, but it seems like there are plenty of new extensions to replace. I can’t seem to find a replacement for this one however - it was a script for creating a folder in Finder with the project name, and subfolders for sub-projects contained within the project in TP. If it was already remade for TP3, could someone point me to a link?
Sorry if it was in an obvious place and I just couldn’t find it. Any pointers about how to better use TP, or what apps to use it with (I used quicksilver back then, but now it seems like people use Alfred more) would also be appreciated.
1 Like
Perhaps something like this JavaScript for Automation script ?
(which could be launched, for example, from Keyboard Maestro in an Execute a JavaScript for Automation action. See also Taskpaper - Using Scripts )
Expand disclosure triangle to view JS Source
(() => {
"use strict";
// Rob Trew @2021
// Ver 0.01
// main :: IO ()
const main = () => {
// Edit to match the root path for your projects:
const projectsRootPath = "~/projects";
const
taskpaper = Application("TaskPaper"),
windows = taskpaper.windows;
return either(
alert("Folder for selected task")
)(
fp => Object.assign(
Application.currentApplication(), {
includeStandardAdditions: true
}
)
.displayNotification(fp, {
withTitle: "Project folder:",
soundName: "glass"
})
)(
bindLR(
0 < windows.length ? (
Right(windows.at(0).document)
) : Left("No documents open in TaskPaper")
)(
document => bindLR(
document.evaluate({
script: `${TP3Context}`
})
)(
folderPathFoundOrCreatedLR(
projectsRootPath
)
)
)
);
};
// folderPathFoundOrCreatedLR :: FilePath ->
// [String] -> IO FilePath
const folderPathFoundOrCreatedLR = rootPath =>
projects => 0 < projects.length ? (
bindLR(
createDirectoryIfMissingLR(true)(
combine(rootPath)(
projects.join("/")
)
)
)(
openedInFinderLR
)
) : Left(
"TaskPaper selection not in a project."
);
// openedInFinderLR :: FilePath -> IO FilePath
const openedInFinderLR = fpFolder => {
const finder = Application("Finder");
return (
finder.open(Path(fpFolder)),
finder.activate(),
Right(fpFolder)
);
};
// ---------------- TASKPAPER CONTEXT ----------------
// TP3Context :: Editor -> IO Either String [String]
const TP3Context = editor => {
const item = editor.selection.startItem;
return Boolean(item) ? {
Right: item.ancestors.concat(item).flatMap(
x => "project" === x.getAttribute(
"data-type"
) ? [
x.bodyContentString
] : []
)
} : {
Left: "Nothing selected in TaskPaper"
};
};
// ----------------------- 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"
}),
s
);
};
// createDirectoryIfMissingLR :: Bool ->
// FilePath -> Either String FilePath
const createDirectoryIfMissingLR = blnParents =>
dirPath => {
const fp = filePath(dirPath);
return doesPathExist(fp) ? (
Right(fp)
) : (() => {
const
e = $(),
blnOK = $.NSFileManager
.defaultManager[
"createDirectoryAtPath" + (
"WithIntermediateDirectories"
) + "AttributesError"
](fp, blnParents, void 0, e);
return blnOK ? (
Right(fp)
) : Left(e.localizedDescription);
})();
};
// doesPathExist :: FilePath -> IO Bool
const doesPathExist = fp =>
$.NSFileManager.defaultManager
.fileExistsAtPath(
$(fp).stringByStandardizingPath
);
// filePath :: String -> FilePath
const filePath = s =>
// The given file path with any tilde expanded
// to the full user directory path.
ObjC.unwrap(ObjC.wrap(s)
.stringByStandardizingPath);
// --------------------- GENERIC ---------------------
// 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.Left ? (
m
) : mf(m.Right);
// combine (</>) :: FilePath -> FilePath -> FilePath
const combine = fp =>
// Two paths combined with a path separator.
// Just the second path if that starts with
// a path separator.
fp1 => Boolean(fp) && Boolean(fp1) ? (
"/" === fp1.slice(0, 1) ? (
fp1
) : "/" === fp.slice(-1) ? (
fp + fp1
) : `${fp}/${fp1}`
) : fp + fp1;
// 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 => e.Left ? (
fl(e.Left)
) : fr(e.Right);
// MAIN ---
return main();
})();
Zipped sample macro for Keyboard Maestro 10:
Project-path folder opened.kmmacros.zip (3.1 KB)
1 Like
shdds
December 1, 2021, 4:20pm
3
Thanks! This works great!
1 Like