Action
Renumber lists
(Re)number (selected, or all) Markdown and Taskpaper ordered lists.
HTML display automatically corrects numeric disorder in MD etc lists,
but this action aims to fix disordered numbering in the plain text document too.
Steps
-
script
// GENERIC FUNCTIONS --------------------------------------- // concatMap :: (a -> [b]) -> [a] -> [b] const concatMap = (f, xs) => [].concat.apply([], xs.map(f)); // Typical usage: groupBy(on(eq, f), xs) // groupBy :: (a -> a -> Bool) -> [a] -> [[a]] const groupBy = (f, xs) => { const dct = xs.slice(1) .reduce((a, x) => { const h = a.active.length > 0 ? ( a.active[0] ) : undefined; return h !== undefined && f(h, x) ? { active: a.active.concat([x]), sofar: a.sofar } : { active: [x], sofar: a.sofar.concat([a.active]) }; }, { active: xs.length > 0 ? [xs[0]] : [], sofar: [] }); return dct.sofar.concat(dct.active.length > 0 ? ( [dct.active] ) : []); }; // justifyRight :: Int -> Char -> String -> String const justifyRight = (n, cFiller, strText) => n > strText.length ? ( (cFiller.repeat(n) + strText) .slice(-n) ) : strText; // length :: [a] -> Int const length = xs => xs.length; // lines :: String -> [String] const lines = s => s.split(/[\r\n]/); // map :: (a -> b) -> [a] -> [b] const map = (f, xs) => xs.map(f); //Ordering: (LT|EQ|GT): // GT: 1 (or other positive n) // EQ: 0 // LT: -1 (or other negative n) // minimumBy :: (a -> a -> Ordering) -> [a] -> a const minimumBy = (f, xs) => xs.reduce((a, x) => a === undefined ? x : ( f(x, a) < 0 ? x : a ), undefined); // showLog :: a -> Console String const showLog = (...args) => alert( args.map(JSON.stringify) .join(' -> ') ); // unlines :: [String] -> String const unlines = xs => xs.join('\n'); // APPLYING ANY FUNCTION (of type [String] -> [String]) // TO SELECTED (OR ALL) LINES IN DRAFT // draftOrLinesUpdated :: IO () -> // ([String] -> [String]) -> IO () const draftOrLinesUpdated = f => { const functionName = f.name, // Used for logging. // Selected lines or whole of draft. [intStart, intLength] = editor.getSelectedLineRange(), [intFrom, intChars] = ( editor.getSelectedText() .length > 0 ? ( [intStart, intLength] ) : [0, editor.getText().length] ), // Concatenated result of applying f to the list of lines strUpdated = unlines(f(lines( editor.getTextInRange(intFrom, intChars) ))); return ( // Various channels, for testing and use. editor.setTextInRange(intFrom, intChars, strUpdated), console.log(functionName, strUpdated), strUpdated ); };
-
script
(() => { 'use strict'; return draftOrLinesUpdated( draftLines => { const rgxPrefix = /^\s*\d+\.\s*/, rgxOLText = /^\s*\d+\.\s*(.*)$/, rgxIndent = /^(\s*)\d+\./, // renumbered :: [ {isOL :: Bool, // txt :: String} ] -> [String] renumbered = xs => { const // Longest sequence of digits, intDigits = (xs.length - 1) .toString() .length, // and shortest indent string. indent = minimumBy( length, map( x => rgxIndent.exec(x.txt)[1], xs ) ); return map( (dict, i) => indent + (1 + i).toString() + '. ' + rgxOLText.exec(dict.txt)[1], xs ); }; // The list of line groups is flattened by concatMap // and returned as a list of strings. return concatMap( xs => ((xs.length > 0) && xs[0].isOL) ? ( renumbered(xs) ) : map(x => x.txt, xs), groupBy( // Adjacent lines grouped by whether // they are numbered. (a, b) => a.isOL === b.isOL, map(line => ({ isOL: rgxPrefix.test(line), txt: line }), draftLines ) ) ); } ); })();
Options
-
After Success Default Notification Info Log Level Info
Items available in the Drafts Directory are uploaded by community members. Use appropriate caution reviewing downloaded items before use.