Before I reinvent the wheel, are there already actions (or keyboardless tap tricks) for extending a text selection one word to left or right ?
I believe I saw one in the drafts 4 directory… I’d start there!
update:
yes … I just checked the Drafts 4 directory there is an action for moving ‘forward’ and one for ‘backward’
there is also a ‘select word’ key action:
Select Word
one or a combination of both should be a good starting point for you …
Thanks ! That’s helpful.
Here, FWIW, are a pair of buttons combining those two functions into Left and Right additional selections – (In the end, I needed to write the underlying function to update something else)
Extend selection one more word to the left
http://actions.getdrafts.com/a/1Ie
Extend selection one more word to the right
http://actions.getdrafts.com/a/1Id
The source code is shared – they differ only by a Left ⇄ Right option:
(() => {
'use strict';
// main :: IO ()
const main = () =>
expandSelnByWord(true, true);
// GENERIC FUNCTIONS ----------------------------------
// Tuple (,) :: a -> b -> (a, b)
const Tuple = (a, b) => ({
type: 'Tuple',
'0': a,
'1': b,
length: 2
});
// concatMap :: (a -> [b]) -> [a] -> [b]
const concatMap = (f, xs) => [].concat.apply([], xs.map(f));
// splitAt :: Int -> [a] -> ([a],[a])
const splitAt = (n, xs) => Tuple(xs.slice(0, n), xs.slice(n));
// SELECTION EXTENSIONS ------------------------------
// expandSelnByWord :: () -> IO ()
const expandSelnByWord = (blnMultiWord, blnLeft) => {
const
e = editor,
tplSeln = e.getSelectedRange(),
tplLine = e.getSelectedLineRange(),
strLine = e.getTextInRange(...tplLine),
intPosn = tplSeln[0],
xy = splitAt(
intPosn - tplLine[0],
strLine
),
[dl, dr] = concatMap(
x => x !== null ? (
[x[0].length]
) : [0], //
[/\b[\S]*$/.exec(xy[0]), /^[\S]*\b/.exec(xy[1])]
);
return (tplSeln[1] === 0 || dl > 0 && dr > 0) ? (
e.setSelectedRange(intPosn - dl, dl + dr),
'extended'
) : blnMultiWord ? (
additionalWord(
blnLeft, tplSeln, tplLine, strLine
)
) : 'No further';
};
// additionalWord :: Bool -> (Int, Int) -> (Int, Int)
// -> String -> IO ()
const additionalWord = (blnLeft, tplSeln, tplLine, strLine) => {
const
e = editor,
s = blnLeft ? (
strLine.slice(0, tplSeln[0] - tplLine[0])
) : strLine.slice(tplSeln[0] - tplLine[0] + tplSeln[1]),
m = blnLeft ? (
/\b\S+\s*$/.exec(s)
) : /^\s*\S+\b/.exec(s),
d = m ? m[0].length : 1;
return (
e.setSelectedRange(
tplSeln[0] - (blnLeft ? d : 0),
tplSeln[1] + d
),
m ? 'extending' : (() => {
const
tplNew = e.getSelectedRange(),
blnFinished = blnLeft ? (
tplNew[0] < 1
) : tplNew[0] + tplNew[1] >= e.getText().length;
return blnFinished ? (
'Finished'
) : expandSelnByWord(true, blnLeft);
})()
);
};
// MAIN ---
return main();
})();
Thank you! I remembered being the actions I pointed you to but had never seen a meed for them myself… with the selection focus you bring I now see many opportunities to use