This script implements block travel (go to next empty line) as inspired by this Visual Studio plugin.
tell front document of application "Bike"
set currentId to id of selection row
set candidateRows to rows whose visible = true and (name = "" or id = currentId)
set foundCurrent to false
repeat with each in candidateRows
if id of each = currentId then
set foundCurrent to true
else if foundCurrent then
select at each
return
end if
end repeat
beep
end tell
Note: This script is pretty brute force :). I think it should be fine for intended use as a command, but if there’s a more elegant way to do it in AppleScript let me know.
1 Like
Here, FWIW, is a JavaScript for Automation version,
which can be used for moving DOWN (next blank line)
or moving UP (previous blank line).
(the directional option is set by editing the value of directionDown
at the top of the script to true
or false
)
To test in Script Editor.app
, set the language selector at top left to JavaScript
, and paste in all of the code (scrolling right down to the bottom) behind the disclosure triangle below:
Expand disclosure triangle to view JS Source
(() => {
"use strict";
// BIKE – Select next (or previous) empty line.
// Rob Trew @2022
// Ver 0.02
// JavaScript for Automation
// Test in Script Editor with language selector at
// top left set to JavaScript
// ---------------- DIRECTION OPTION -----------------
// To jump to PREVIOUS blank line,
// edit the value of `directionDown` to false.
const directionDown = true;
// main :: IO ()
// eslint-disable-next-line max-lines-per-function
const main = () => {
const
bike = Application("Bike"),
doc = bike.documents.at(0);
return doc.exists() ? (() => {
const
// IDs paired with names
rows = doc.rows.where({
visible: true
}),
idNames = zip(
rows.id()
)(
rows.name()
),
// Position of selected line
selectedID = doc.selectionRow.id(),
selnIndex = idNames.findIndex(
ab => selectedID === ab[0]
),
// Offset of first blank in remaining or
// preceding lines.
nextIndex = (
directionDown ? (
idNames.slice(1 + selnIndex)
) : (
idNames.slice(0, selnIndex)
.reverse()
)
)
.findIndex(ab => "" === ab[1]);
bike.activate();
// First following blank line selected (if any)
return -1 !== nextIndex ? (
doc.select({
at: rows.at(
directionDown ? (
selnIndex + (1 + nextIndex)
) : selnIndex - (1 + nextIndex)
)
}),
"Selected"
) : (
Object.assign(
Application.currentApplication(), {
includeStandardAdditions: true
}
).beep(),
`No more blank rows visible in ${doc.name()}`
);
})() : "No document open in Bike.";
};
// --------------------- GENERIC ---------------------
// https://github.com/RobTrew/prelude-jxa
// zip :: [a] -> [b] -> [(a, b)]
const zip = xs =>
// The paired members of xs and ys, up to
// the length of the shorter of the two lists.
ys => Array.from({
length: Math.min(xs.length, ys.length)
}, (_, i) => [xs[i], ys[i]]);
// MAIN ---
return main();
})();
If you use Keyboard Maestro, the pair of macros in this zip:
NextOrPreviousBikeEmptyLine.kmmacros.zip (2.6 KB)
initially assign the two directions to ⌥⌘Up Arrow
and ⌥⌘Down Arrow
respectively, but you can readily change to any other pair of keyboard bindings.
2 Likes
Thanks @complexpoint. The one functional difference I notice is I think the JavaScript version is navigating to next empty row, while my version is navigating to next visible
empty row.
2 Likes
Thanks ! I’ll make an edit to ver 0.02 
UPDATE
JS Source and Keyboard Maestro macros updated to Ver 0.02 above, to jump to next or previous visible
row that is empty.
2 Likes