1 of 3 β extended editor selection
The simplest route to a subset of lines is through an extended selection in the editor.
// selectedOrAllLines :: Editor () -> [String]
const selectedOrAllLines = () => {
const e = editor;
return (
e.getSelectedRange()[1] > 0 ? (
e.getTextInRange(
...e.getSelectedLineRange()
)
) : draft.content
).split('\n');
};
In the function above, which returns a list of line strings:
- If the length of the selection is non-zero (
e.getSelectedRange()[1] > 0 ?
) then - the text which we split into lines is that in
editor.getSelectedLineRange()
, otherwise - it is the whole
draft.content
.
2 of 3 β filtering
The second route is to get all the lines, and then filter them.
// lines :: String -> [String]
const lines = s => s.split(/[\r\n]/);
const doneLines = lines(draft.content).filter(x => x.includes('@done'))
3 of 3 β combining mapping and filtering with concatMap
The built-in map lets us define a new list as a transformation of an existing one. (See this post for an example)
We can also write ourselves a concatMap function which lets us combine transformation with some filtering:
// concatMap :: (a -> [b]) -> [a] -> [b]
const concatMap = (f, xs) => [].concat(...xs.map(f));
(where xs is a list (for example of lines, or words), and f is a function on one of these items, returning some value wrapped in [list] brackets)
concatMap maps an existing list to a transformed version (in which each new item is [wrapped] in list brackets), and then applies concat β a function which joins all the items in a list together.
Given a list of lists like:
[["alpha"], [], ["beta"], ["gamma"], [], ["delta"]]
concat would concatenate everything and return:
["alpha", "beta", "gamma", "delta"]
from which any empty []
lists have vanished.
Itβs these vanishing empty lists which allow us to do some filtering with concatMap.
The map part of
concatMap(x => isEven(x) ? [] : [x], [1, 2, 3, 4, 5, 6, 7, 8, 9])
produces:
[[1],[],[3],[],[5],[],[7],[],[9]]
and the subsequent concat reduces this to:
[1,3,5,7,9]
In a Drafts action which generates a new draft for each non-blank line in the extended selection ( or for every non-blank line if the selection is not extended ), we can use concatMap to ignore the blank lines:
http://actions.getdrafts.com/a/1I3
If the length of a line is zero, then the concatMap f function returns []
, (which vanishes under the following concatenation) but,
if the length of a line is non-zero, then the concatMap f function returns a new Draft, wrapped in [brackets], which the concatenation simply removes:
(() => {
'use strict';
// main :: Drafts ()
const main = () => draftsFromLines(
selectedOrAllLines()
);
// selectedOrAllLines :: Editor () -> [String]
const selectedOrAllLines = () => {
const e = editor;
return (
e.getSelectedRange()[1] > 0 ? (
e.getTextInRange(
...e.getSelectedLineRange()
)
) : draft.content
).split('\n');
};
// draftsFromLines :: [Strings] -> [UUID]
const draftsFromLines = xs =>
// Concatenation (of map result) purges empty lists
// ( no new draft created from any blank line )
concatMap(
// Function applied ...
s => s.length > 0 ? [
Object.assign(
Draft.create(), {
content: s
}
)
] : [],
// ... to each item of this list.
xs
)
.reverse() // Inbox order matching line order
.map(x => (x.update(), x.uuid));
// concatMap :: (a -> [b]) -> [a] -> [b]
const concatMap = (f, xs) => [].concat(...xs.map(f));
// MAIN ---
const result = main();
return (
console.log(result),
result
);
})();