My habit is to work with files which include a YYYY-MM-DD date in the filepath.
The corresponding weekday name may not be clear at a glance
- once the date is no longer close to today, or
- if it falls at some point in the future.
This macro just pastes the weekday name which corresponds to the last (if any) YYYY-MM-DD date found in the file path of the active document.
In other words, if both folder and filename contain a yyyy-mmm-dd date, then we paste the file date.
It should work in many (not all) macOS document-based applications.
Paste weekday name for ISO8601 date in filepath of active document.kmmacros (8.0 KB)
Expand disclosure triangle to view JS Source
(() => {
"use strict";
ObjC.import("AppKit");
// Rob Trew @2022
// Weekday name from *last* ISO8601 date in the filepath
// of the front document.
// E.g. if both folder and file contain a date,
// we take the file date.
// Ver 0.02
const main = () =>
either(
alert("Day name from file path")
)(
// Returned to Keyboard Maestro
weekdayName => weekdayName
)(
dayNameFromFrontWindowFilePathLR()
);
// ------- WEEKDAY FROM FRONT WINDOW FILEPATH --------
// dayNameFromFrontWindowFilePathLR :: IO () ->
// Either String String
const dayNameFromFrontWindowFilePathLR = () =>
// Either a message, or the locale name of the week
// day whose date is found in ISO8601 format in the
// file path of the document in the front window.
bindLR(
filePathFromFrontWindowLR()
)(
compose(
fmapLR(
dte => dte.toLocaleDateString(
$.NSLocale.currentLocale
.localeIdentifier, {
weekday: "long"
}
)
),
dayDateFromStringIncludingISO8601LR
)
);
// dateFromStringWithISO8601LR :: String ->
// Either String Date
const dayDateFromStringIncludingISO8601LR = s => {
// Either a message or a date corresponding to
// the last yyyy-mm-dd string found in s.
const ms = s.match(/\d{4}-\d{2}-\d{2}/ug);
return Boolean(ms) ? (
// Rightmost match
Right(new Date(last(ms)))
) : Left(
`No ISO8601 day date found in filepath:\n\n\t'${s}'`
);
};
// --------------------- 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
);
};
// filePathFromFrontWindowLR ::
// () -> Either String FilePath
const filePathFromFrontWindowLR = () => {
const
appName = ObjC.unwrap(
$.NSWorkspace.sharedWorkspace
.frontmostApplication.localizedName
),
ws = Application("System Events")
.applicationProcesses.byName(appName).windows;
return bindLR(
0 < ws.length ? Right(
ws.at(0).attributes.byName("AXDocument")
.value()
) : Left(
`No document windows open in ${appName}.`
)
)(
docURL => null !== docURL ? (
Right(decodeURIComponent(docURL.slice(7)))
) : Left(
`No saved document active in ${appName}.`
)
);
};
// --------------------- 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);
// compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
const compose = (...fs) =>
// A function defined by the right-to-left
// composition of all the functions in fs.
fs.reduce(
(f, g) => x => f(g(x)),
x => x
);
// 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);
// fmapLR (<$>) :: (b -> c) -> Either a b -> Either a c
const fmapLR = f =>
// Either f mapped into the contents of any Right
// value in e, or e unchanged if is a Left value.
e => "Left" in e ? (
e
) : Right(f(e.Right));
// last :: [a] -> a
const last = xs =>
// The last item of a list.
Boolean(xs.length) ? (
xs.slice(-1)[0]
) : null;
// MAIN ---
return main();
})();