Bike 2.0 Selection Demo

I encourage you to read about the original Bike 2.0 Demo for context:

The biggest question raised there concerned Bike 2’s selection model.

The change is (like in 1.0) you can select individual text characters within a row, but (unlike 2.0) when you extend the selection beyond a single row you start selecting at the row level.

How to try the change

The previous 2 demo was mostly concerned with getting something out the door and demonstrating stylesheets. The actual implementation of selection was hard to understand and buggy.

This demo includes a more complete implementation of Bike 2’s selection model. Note that this is still very much a demo, with many missing application parts/features, but selection is now working much more like I expect it to work in final 2.0.

To try it:

  1. Download Bike 2.0 Selection Demo
  2. Launch App
  3. Open existing document
  4. Choose Window > Themes > Basic (or Demo)
    • If you played with previous Bike demo you should remove/rename any existing theme files so that the new ones get copied into place. They include rules for drawing the selection, so it’s important to get the new ones.
  5. Make some selections

Here’s what I see when I select the w in Two.

Screenshot 2024-04-25 at 2.06.26 PM

And this is what I see when I extend that selection (Hold shift and press right arrow two times) into row three.

Screenshot 2024-04-25 at 2.07.33 PM

And now if you continue to hold shift and press left arrow two times, you should go back to seeing the original image with only w selected.


Bike 2’s selection model should be familiar. It’s how most outliners and structured block editors work. With that said I think Bike’s implementation is more refined than what I’ve seen in other editors in two ways:

  1. First text caret movement should still work like in a plain text editor when moving from row to row. Most structured editors don’t do this well.

  2. More important the transition from selecting characters to selecting rows is always reversible.

    So for example if you click in the middle of a row and drag you will start selecting characters. Drag outside the row and you will be selecting rows. Within that same interaction if you drag back into the original row you will go back to selecting characters. This also works when you are extending the selection by holding down Shift. For example start selecting characters by holding shift and tapping right arrow. Eventually the selection will extend beyond the current row and you will be selecting rows… then if you start hitting the left arrow key (instead of right) the selection will eventually go back and start selecting characters again.

That’s a lot of text to say that Bike tries to make it easy to extend and contract the selection in expected ways. This isn’t what most outline/block editors do.


@Gorgonzola I’m thinking about your editing problems when using a block editor:

I wonder if a “Join Rows” command could be useful for this case, and maybe generally useful for outline editing.

  • In the simple case Join Rows will combine selected rows into a single row, but that doesn’t help to much for your case.

  • In the more interesting case, when you have a single row with a text selection, join rows will append the next row to the row you are editing, while maintaining your text selection.

I think this could make the editing example that you shared easier (once internalized) than what you are doing in Bike 1.0. Here are the core edits that I see you doing in 1.0:

  1. Position selection at start of region to cut
  2. Extend selection across newline to end of region to cut
  3. Cut
  4. Reposition cursor and Paste
  5. Reposition cursor and delete newline

With a join command I think you could:

  1. Position selection at start of region to cut
  2. Invoke Join Rows
  3. Extend selection to end of region to cut
  4. Cut
  5. Reposition cursor and Paste

You end up using the same number of commands. But I think the commands in the second case are easier since you are not having to navigate around the newline when you are positioning your cursor.

I’m interested in anyones feedback hear and maybe will add this command for next demo.

1 Like

Already much more fluid, I notice, than the OmniOutliner block model – here a mid-line return key simply splits, and a start-of-line backspace simply joins.

(No need to remember special key-bindings like ^↩ or ^⌫)

@Gorgonzola @complexpoint Here’s some ideas.

First some definitions:

  1. split is when you take an existing row and split it into multiple rows
  2. join is when you take multiple existing rows and combine into a single row

The most common way to split is place caret in row and press return
The most common way to join is place caret at start of a row and press delete

Note that a text caret/selection is required to use these commands in their standard forms.

I wonder if we can make a more powerful versions of split/join for outline mode that would be generally useful and also (I think) address @Gorgonzola’s the editing problem quite well.

What in outline mode:

  1. split breaks each selected row into sentences and trims whitespace. Maybe if there’s only a single sentence it could break into words.
  2. join combines each selected row into a single row, joined by interior spaces

The basic idea is when you want to make an edit to a (or multiple) paragraphs structure you can break text structure out into outline structure. Delete, reorder as necessary with simple outline commands. Then recombine into text. I think this could be quite powerful, but not sure it would get used.


1 Like

Haven’t gotten around to testing yet, but this is how I would expect proper block to work. Will give it a spin.

My initial thoughts/questions are: this hypothetical command edits text outside the strict selection, which kind of feels unorthodox. What happens if you only select a word in the middle of the row and invoke join rows? Would it work in both directions of the outline?

This would be very unique to Bike, I think. Not sure I recall any editor that blows up paragraphs of the box, but I could be wrong. I can see it make sense in research applications, maybe in legal too. Could work for prose, too, and certainly for blogging. It could be one of those things where once you try, you can’t go back :slightly_smiling_face:

It does feel a little weird, but I think there are other outline commands with similar issues such as promote and demote. They work on children and trailing siblings of the selection.

Join would work on following row when in text mode. It wouldn’t matter what text is selected in the row or where that caret is positioned. Join would maintain that selection, delete following row, append following rows text to current row.

When you place caret at start of a row and press delete Bike would implement that by combining two commands. First move selection to end of previous row. Then run join command.

At least that’s what I’m thinking at moment.

Edit Also I’m not sure that Bike needs both of these features. Maybe outline level split/join is enough.

A built-in sentence splitter seems very useful.

(I often find myself doing something like that to prepare a text for argument structure diagramming)

( I would even be in the market for a comma splitter, or even better, a general clause/point-splitter, though the latter would, I think, be language-specific and non-trivial, beyond the reach of these factory-fed LLMs – something for another decade perhaps – after I’m gone :slight_smile: )

To test that assumption, I just asked chatGPT4 to show me a copy of the Gettysburg address reformatted to one clause per line.

In the usual distributionally-computed bluffing style of LLMs it assured me that it could do that, and then showed me a version segmented on full stops, instead.

What followed was:


That is sentence segmentation. I asked you for clause segmentation.
Am I right in thinking that such a request is beyond the scope of an LLM ?


You’re correct; clause segmentation requires a deeper understanding of syntax and semantics, which can be challenging for a language model to perform accurately in all cases. While some clause boundaries may be identifiable based on patterns like subject-verb pairs, coordinating conjunctions, or punctuation marks, identifying all clauses in a complex text like the Gettysburg Address accurately would likely require human-level comprehension and interpretation. So, in this case, providing an accurate clause segmentation may indeed be beyond the current capabilities of a language model.

( Of course even its concession is bluffing – entirely based on distributional profiling of linguistic tokens, and utterly unhinged from anything outside language. These things have no theory at all of what they can or can’t do – just an ability to emit linguistically plausible recompositions from a vector slurry of other people’s IP )

1 Like

My initial comments on selection demo:

Shift + Right/Left: behaves as expected (select until end of row, then select row in outline mode, then add next/previous row to selection). Moving back the same number of steps restores original selection.

Shift + CMD + Right: Selects from caret until end of line (not line break), then selects next line, continues like so until end of row, then selects full row. From there, if I press it another time, it restores text-level selection, from the initially placed caret and until end of row. From there, it just cycles between the two. Not sure if this is intended or if it should continue to the next row in outline mode.

Shift + CMD + Left: This is where it gets kind of inconsistent. Unlike Shift+CMD+Right, this one first selects text from caret and until beginning of current line, and then immediately jumps to select the entire row in outline mode, then cycles text/outline selection. If I first do S+C+R, and then S+C+L, I immediately go into outline mode, which is inconsistent with S+C+L, then S+C+R, which just switches the selection around the caret, which is then again inconsistent with another S+C+L, which sends it into outline mode instead of switching selection around caret in the other direction. This just feels…strange.

Shift + Option + Left/right seems to function like Shift + Left/right, which I think feels natural.

Up / down plus modifiers seem to work as expected. Selecting with mouse also feels as expected.

Apart from the strange part above, I think moving in/out of outline mode feels more or less natural. I would also say that it behaves much better than any other block editing software I own, but I wonder: what is the reference/standard here? Every block editor I’ve used behaves differently with selections.

1 Like

Lots of good catches here, I think I agree with them all and will have them fixed for next release.

I don’t think there is one. In my experience the boundary between text and block editing is weak and inconsistent. For me the standard should be:

  1. In paragraph selection should works like native (TextEdit).
  2. Block level selection works like (1), but snaps to row boundaries
1 Like

I notice these variations in other apps:

Shift + CMD + L/R, followed by same command in opposite direction can:
a) select from caret until end/beginning of line, then expand selection to end/beginning of line in other direction (Apple Notes, iA Writer, Ulysses, Bear, Scrivener, TextEdit, Pages, TaskPaper, LogSeq, Typora, Drafts, Paper, Byword)
b) swing the selection around the caret in other direction (Obsidian, Craft, Legend, Bike 1.0 :smiley: )
c) do a weird combination of both (CotEditor)

Also, I haven’t touched on cmd+A, this now selects the entire outline right off the rip. Some apps select the entire row first (in text selection), and only move to block selection of whole outline after another cmd+A. I’ve grown to like the second option because I can keep the row if I decide to eliminate its text completely.

1 Like

I think this is one place where I do want to diverge from (a) which is macOS standard behavior. To me (b) seems more strait forward and consistent. I think it should be that Bike 2 is currently working like Bike 1 in this regard.

I agree, and have changed this for next release.