A first draft of a macro for looking up the selected function in Quiver.
I use a set of c. 350 generic functions (in JS, with a parallel set in AS) to compose any scripts that I need.
I already have a KM macro for finding and pasting these functions, but I sometimes also need to move in the opposite direction – to look up and perhaps update the version of a function that I have in a Quiver Notebook.
To test the draft macro below, first update variable values for:
- The path to the Quiver library, and
- the name of the Quiver Notebook to search in.
Note that this macro assumes that the function name is the first word (space-delimited) of the Quiver note's name.
i.e. given Quiver note names like those below, it finds strings like fmap and fmapLR, as well as flatten, flip, and floor:
Find selected function in Quiver.kmmacros (27.5 KB)
Javascript source
(() => {
'use strict';
const main = () => {
const
kme = Application('Keyboard Maestro Engine'),
kmQVar = k => kme.getvariable('quiver' + k),
lrUUID = uuidFromPathBookNameLR(
...['LibPath', 'Book', 'Function'].map(kmQVar)
);
return lrUUID.Left || lrUUID.Right;
};
// GENERIC FUNCTIONS ----------------------------------
// Just :: a -> Just a
const Just = x => ({
type: 'Maybe',
Nothing: false,
Just: x
});
// Left :: a -> Either a b
const Left = x => ({
type: 'Either',
Left: x
});
// Nothing :: () -> Nothing
const Nothing = () => ({
type: 'Maybe',
Nothing: true,
});
// 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;
// bindMay (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
const bindMay = (mb, mf) =>
mb.Nothing ? mb : mf(mb.Just);
// doesFileExist :: FilePath -> IO Bool
const doesFileExist = strPath => {
const ref = Ref();
return $.NSFileManager.defaultManager
.fileExistsAtPathIsDirectory(
$(strPath)
.stringByStandardizingPath, ref
) && ref[0] !== 1;
};
// doesPathExist :: FilePath -> IO Bool
const doesPathExist = strPath =>
$.NSFileManager.defaultManager
.fileExistsAtPath(
$(strPath).stringByStandardizingPath
);
// filePath :: String -> FilePath
const filePath = s =>
ObjC.unwrap(ObjC.wrap(s)
.stringByStandardizingPath);
// findIndex :: (a -> Bool) -> [a] -> Maybe Int
const findIndex = (p, xs) => {
const i = xs.findIndex(p);
return i !== -1 ? (
Just(i)
) : Nothing();
};
// listDirectory :: FilePath -> [FilePath]
const listDirectory = strPath =>
ObjC.unwrap(
$.NSFileManager.defaultManager
.contentsOfDirectoryAtPathError(
ObjC.wrap(strPath)
.stringByStandardizingPath,
null
))
.map(ObjC.unwrap);
// readFile :: FilePath -> IO String
const readFile = strPath => {
let error = $(),
str = ObjC.unwrap(
$.NSString
.stringWithContentsOfFileEncodingError(
$(strPath)
.stringByStandardizingPath,
$.NSUTF8StringEncoding,
error
)
);
return Boolean(error.code) ? (
ObjC.unwrap(error.localizedDescription)
) : str;
};
// showLog :: a -> IO ()
const showLog = (...args) =>
console.log(
args
.map(JSON.stringify)
.join(' -> ')
);
// JXA ------------------------------------------------
// standardAdditions :: () -> Application
const standardAdditions = () =>
Object.assign(Application.currentApplication(), {
includeStandardAdditions: true
});
// MAIN -----------------------------------------------
// uuidFromPathBookNameLR :: String -> String -> String
// -> Either String UUID
const uuidFromPathBookNameLR = (strPath, bookName, fName) => {
const fp = filePath(strPath);
return bindLR(
doesPathExist(fp) ? (
Right(fp)
) : Left(`Quiver library not found at ${fp}`),
fp => {
const
xs = listDirectory(fp),
mbBook = findIndex(
x => {
const fpMeta = `${fp}/${x}/meta.json`;
return doesFileExist(fpMeta) &&
bookName === JSON.parse(
readFile(fpMeta)
).name;
},
xs
);
return bindLR(
mbBook.Nothing ? Left(
`Notebook named '${
bookName
}' not found ...`
) : Right(fp + '/' + xs[mbBook.Just]),
fpBook => {
const
notes = listDirectory(fpBook),
mbNote = findIndex(
noteName => {
const
fpMeta = `${fpBook}/${
noteName
}/meta.json`;
return doesFileExist(fpMeta) &&
fName === JSON.parse(
readFile(fpMeta)
).title.split(' ')[0]
},
notes
);
return mbNote.Nothing ? Left(
`'${fName}' not found in ${bookName}`
) : Right(notes[mbNote.Just].slice(0, -7));
}
);
}
);
};
// MAIN ---
return main();
})()