// ---------------- PARSER COMBINATORS -----------------
// Rob Trew @2020
// Parser :: String -> [(a, String)] -> Parser a
const Parser = f =>
// A function lifted into a Parser object.
({
type: 'Parser',
parser: f
});
// altP (<|>) :: Parser a -> Parser a -> Parser a
const altP = p =>
// p, or q if p doesn't match.
q => Parser(s => {
const xs = parse(p)(s);
return 0 < xs.length ? (
xs
) : parse(q)(s);
});
// apP <*> :: Parser (a -> b) -> Parser a -> Parser b
const apP = pf =>
// A new parser obtained by the application
// of a Parser-wrapped function,
// to a Parser-wrapped value.
p => Parser(
s => parse(pf)(s).flatMap(
vr => parse(
fmapP(vr[0])(p)
)(vr[1])
)
);
// bindP (>>=) :: Parser a ->
// (a -> Parser b) -> Parser b
const bindP = p =>
// A new parser obtained by the application of
// a function to a Parser-wrapped value.
// The function must enrich its output, lifting it
// into a new Parser.
// Allows for the nesting of parsers.
f => Parser(
s => parse(p)(s).flatMap(
tpl => parse(f(tpl[0]))(tpl[1])
)
);
// char :: Char -> Parser Char
const char = x =>
// A particular single character.
satisfy(c => x == c);
// count :: Int -> Parser a -> Parser [a]
const count = n =>
// A list of n successive instances of p.
p => sequenceP(
replicate(n)(p)
);
// digit :: Parser Char
const digit = () =>
// A single digit.
satisfy(isDigit);
// fmapP :: (a -> b) -> Parser a -> Parser b
const fmapP = f =>
// A new parser derived by the structure-preserving
// application of f to the value in p.
p => Parser(
s => parse(p)(s).flatMap(
first(f)
)
);
// letter :: Parser Char
const letter = () =>
// A single alphabetic character.
satisfy(isAlpha);
// liftA2P :: (a -> b -> c) ->
// Parser a -> Parser b -> Parser c
const liftA2P = op =>
// The binary function op, lifted
// to a function over two parsers.
p => apP(fmapP(op)(p));
// many :: Parser a -> Parser [a]
const many = p => {
// Zero or more instances of p.
// Lifts a parser for a simple type of value
// to a parser for a list of such values.
const some_p = p =>
liftA2P(
x => xs => [x].concat(xs)
)(p)(many(p));
return Parser(
s => parse(
0 < s.length ? (
altP(some_p(p))(pureP([]))
) : pureP([])
)(s)
);
};
// oneOf :: [Char] -> Parser Char
const oneOf = s =>
// One instance of any character found
// the given string.
satisfy(c => s.includes(c));
// parse :: Parser a -> String -> [(a, String)]
const parse = p =>
// The result of parsing s with p.
s => {
// showLog('s', s)
return p.parser([...s]);
};
// pureP :: a -> Parser a
const pureP = x =>
// The value x lifted, unchanged,
// into the Parser monad.
Parser(s => [Tuple(x)(s)]);
// satisfy :: (Char -> Bool) -> Parser Char
const satisfy = test =>
// Any character for which the
// given predicate returns true.
Parser(
s => 0 < s.length ? (
test(s[0]) ? [
Tuple(s[0])(s.slice(1))
] : []
) : []
);
// sequenceP :: [Parser a] -> Parser [a]
const sequenceP = ps =>
// A single parser for a list of values, derived
// from a list of parsers for single values.
Parser(
s => ps.reduce(
(a, q) => a.flatMap(
vr => parse(q)(snd(vr)).flatMap(
first(xs => fst(vr).concat(xs))
)
),
[Tuple([])(s)]
)
);
// some :: Parser a -> Parser [a]
const some = p => {
// One or more instances of p.
// Lifts a parser for a simple type of value
// to a parser for a list of such values.
const many_p = p =>
altP(some(p))(pureP([]));
return Parser(
s => parse(
liftA2P(
x => xs => [x].concat(xs)
)(p)(many_p(p))
)(s)
);
};
// whiteSpace :: Parser String
const whiteSpace = () =>
// Zero or more non-printing characters.
many(oneOf(' \t\n\r'));
This is just an example written in response to the below KM Forum Topic. You will need to use as an example and/or change to meet your workflow automation needs.
MACRO SETUP
Carefully review the Release Notes and the Macro Actions
Make sure you understand what the Macro will do.
You are responsible for running the Macro, not me.
USE AT YOUR OWN RISK
While I have given this a modest amount of testing, and to the best of my knowledge will do no harm, I cannot guarantee it.
If you have any doubts or questions:
Ask first
Turn on the KM Debugger from the KM Status Menu, and step through the macro, making sure you understand what it is doing with each Action.
@JMichaelTX, thank you for the help with this also! Really appreciate it!
Strangely, I couldn't get this macro to work.
I set a hot key trigger, thinking the macro would run similar to the macro provided above by @ComplexPoint, however, nothing seemed to happen and all that pasted was what was previously on the clipboard...
@JMichaelTX and @ComplexPoint , Thank you for your further help and advice. Greatly appreciated! Apologies for the delay in responding, been trying to work out some issues I have been having with the macros and Bear, but finally decided I wasn't getting anywhere fast... so I thought it best to return to the source
@JMichaelTX, I am still experiencing an issue with this macro, in that it doesn't seem to run?
I set a hot trigger.
Make a selection
Fire the hot trigger
Nothing...
I did notice a couple of times an error saying the macro timed-out before completing. But have no clue as to remedy this. Your thoughts would be welcomed.
@ComplexPoint, Thank you so much for your help! The second macro works great! Just a question, is there a way I can amend the script to parse 1-2 digits for the day and paste yyyy-mm-dd mm:ss instead of yyyy-m-d mm:ss?
Again, thank you so much for all your help guys! Really appreciate it!
If it is not running, that means that either the Macro is disabled, or it is in a Macro Group that is either disabled or not active.
Try moving the Macro to a "Global Macro Group" so that it is always active.
Easy. Just set the "Local_Day" variable to itself in a Set Variable to Calculation action and check and provide the format. Should be "00" in this case.