Bike 1.7 Preview (90)

Bike 1.7 Preview (90) adds:

  • Added Control-T to transpose characters
  • Added Control-Delete to decomposing unicode scalars
  • Added yank: and yankAndSelect: and kill buffer support
  • Added setMark:, deleteToMark:, selectToMark:, swapWithMark:
  • Improved text correction system to learn from your actions
  • Improved checking panel options and descriptions
  • Improved dash replacements to substitute ... to
  • Fixed unindent to properly handled collapsed rows
  • Fixed crash when clicking in an empty outline

Bike 1.7 Preview (89):

  • Added text corrections and replacements
  • Added support for strikethrough when copy/paste .rtf
  • Added key modifiers for opening links in tabs and windows

Text Corrections and replacements and substitutions

The big feature that I’m working on for this release is Text Corrections and Replacements. When enabled Bike should now perform autocorrections, smart quotes and dashes, and user text replacements as you type.

Generally it should be familiar to what you are used to from many macOS text areas. Bike uses the same underlying API. With that said I don’t love the standard macOS interactions around text corrections and so Bike’s behavior is familiar, but different.

Please try out what I’ve done and let me know the problems. Might be lots of problems with typing in other languages, I’m not really sure how autocorrect is supposed to work there. Let me know what goes wrong! :slight_smile:

Autocorrect runs when you finish a word

Bike autocorrect runs anytime you finish a word while typing text. Previous edits and selections are not considered when determining if autocorrect should run.

This makes autocorrect more predictable. It also means some patterns you may have used to temporarily disable autocorrect will no longer work. For example if you want to avoid an autocorrect in TextEdit you can Left Arrow, then Right Arrow before you finish a word. In Bike that won’t work, since previous selection doesn’t change autocorrect behavior.

Instead of avoiding autocorrects Bike makes them easy to undo. You can undo an autocorrect with a single Delete keystroke, instead of doing the two key Right Arrow, then Left Arrow dance to avoid like in TextEdit.

Autosuggest doesn’t run as you are typing a word

In TextEdit when you are part way through typing a word a popup may show offering a completion for the word. Right now Bike doesn’t do this. That autocomplete feature is useful sometimes, but also makes autocorrect just feel heavy and noisy to me. I think better without. If you don’t know how to spell a word just do you best and in most cases autocorrect should fix after you finish typing the word.

Substitutions run as soon as there is a match

Substitutions (just smart quotes and smart dashes) run immediately as they are typed. For example type -- and it will be replaced by as soon as you type the second -. This is the same behavior as TextEdit.

One difference is that Bike will underline these cases with the blue autocorrect underline. And you can go back and revert these substations the same way you can for autocorrections. You can also Delete to revert the substitution.

Delete to undo an autocorrection

Immediately after an autocorrect is performed you can Delete to undo that autocorrect. This undo/delete option is only available immediately after an autocorrect happens. If you keep typing or move the selection then you will need to use Edit > Undo to undo the autocorrect.

A nice feature of Bike is that when undoing autocorrect only the autocorrection is undone. In TextEdit both the autocorrect and the text that you entered to trigger the autocorrect are undone. Bike doesn’t discard your input text on autocorrect undo.

Always show blue autocorrect underline for the current sentence

Autocorrections can sometimes be wrong and for that reason I think it’s important to clearly indicate when an autocorrection has happened. From what I can tell TextEdit shows an autocorrect indicator (blue dots underline) only right after the autocorrection happens. Bike on the other hand shows autocorrect indicators always for the current sentence. These indicators remain until you edit the autocorrected words or close the outline… autocorrect state is only stored in memory, not saved to file.

Revert autocorrections and get spelling suggestions by moving cursor to end of spelling or correction range

This is pretty much how TextEdit works, but it seems to have many cases (intentional or bugs I’m not sure) where this doesn’t happen. In Bike anytime the text selection is:

  1. Collapsed
  2. At the end of a correction or spelling indicator
  3. And the previous action hasn’t been an edit

Then Bike will show a revert or spelling suggestions popup (assuming there are spelling suggestions to be made)

Checking settings show in single place

Text checking settings are all listed in Bike’s text checking panel Edit > Checking > Show Checking panel. When you first start Bike the settings are read from what you have set for your keyboard input in macOS standard Settings.

If you change a setting in Bike’s panel then:

  1. The new set of settings will be saved as default for new Bike documents
  2. Existing Bike documents will keep the settings they already have (until you close window)
  3. There’s a button at the bottom of the settings panel to revert settings to system defaults

Checking panels check next/previous commands check all set options

For example in TextEdit when you “check next” only spelling and grammar problems are checked. Bike checks all options that you have enabled. So for example if you have smart quotes enabled then check next will also find dumb quotes and suggest you replace them with an educated quote.

I’m not 100% sure on this change. It means you will get more false positives when checking. But it also means that check next/prev will check for everything that you have the text system checking for. I think this approach while maybe more noisy is simpler and more powerful, you can check more things.

Bike doesn’t autocorrect grammar errors as you type

In TextEdit under the right circumstances when you finish a sentence grammar errors might get corrected. Bike doesn’t support this because I think those corrections are too hard to spot since they happen somewhere far back in the sentence that you’ve already typed. In Bike autocorrect should only ever happen to the word you just finished typing.

Grammar errors will just be highlighted in green (if yo have grammar checking on) and you can correct them the same (right click, place caret at end, or with checking next/prev commands) as you would spelling errors that aren’t autocorrected.


To get preview releases through Bike’s software update select: Bike > Preferences > General > Include “preview” releases.

3 Likes

I would like support for the capitalize words automatically feature. That lets the first letter of a new sentence be capitalized.

macosxguru

This should already be working. At least it is working for me in macOS Ventura. To make it work you do need to make sure that this system setting is checked:

System Settings > Keyboard > Text Input > Input Sources > Capitalize words automatically

Edit If that doesn’t do it also make sure that you have “Autocorrect” checked in Bike’s Edit > Checking > Show Checking panel.

This version crashes for me whenever I mouse-click in an empty window.

Colin

1 Like

(+1)

macOS 11.7.1, Bike 1.7 Preview (89)

Performing @selector(handleTouch:) from sender Bike.TouchGestureRecognizer 0x6000010409a0

Expand disclosure triangle to view fuller report
Process:               Bike [28986]
Path:                  /Applications/Bike.app/Contents/MacOS/Bike
Identifier:            com.hogbaysoftware.Bike
Version:               1.7 (89)
Code Type:             X86-64 (Native)
Parent Process:        ??? [1]
Responsible:           Bike [28986]
User ID:               501

Date/Time:             2022-11-17 10:43:45.366 +0000
OS Version:            macOS 11.7.1 (20G918)
Report Version:        12
Anonymous UUID:        E45179DE-1B85-C265-98DA-011B593F8AD9

Sleep/Wake UUID:       796A45E9-4456-4C00-8DB8-12C1DFE13C44

Time Awake Since Boot: 670000 seconds
Time Since Wake:       21000 seconds

System Integrity Protection: enabled

Crashed Thread:        0  Dispatch queue: com.apple.main-thread

Exception Type:        EXC_BAD_INSTRUCTION (SIGILL)
Exception Codes:       0x0000000000000001, 0x0000000000000000
Exception Note:        EXC_CORPSE_NOTIFY

Termination Signal:    Illegal instruction: 4
Termination Reason:    Namespace SIGNAL, Code 0x4
Terminating Process:   exc handler [28986]

Application Specific Information:
Performing @selector(handleTouch:) from sender Bike.TouchGestureRecognizer 0x6000010409a0

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   com.hogbaysoftware.Bike       	0x0000000109cb70e0 0x109a82000 + 2314464
1   com.hogbaysoftware.Bike       	0x0000000109cb6460 0x109a82000 + 2311264
2   com.hogbaysoftware.Bike       	0x0000000109cbbb2f 0x109a82000 + 2333487
3   com.hogbaysoftware.Bike       	0x0000000109cc53b2 0x109a82000 + 2372530
4   com.apple.combine             	0x00007fff2e6f52d6 Subscribers.Sink.receive(_:) + 54
5   com.apple.combine             	0x00007fff2e6f59d0 protocol witness for Subscriber.receive(_:) in conformance Subscribers.Sink<A, B> + 16
6   com.apple.combine             	0x00007fff2e70168b PassthroughSubject.Conduit.offer(_:) + 411
7   com.apple.combine             	0x00007fff2e7028c7 partial apply for closure #1 in PassthroughSubject.send(_:) + 23
8   com.apple.combine             	0x00007fff2e73b364 partial apply for thunk for @callee_guaranteed (@guaranteed ConduitBase<A, B>) -> (@error @owned Error) + 20
9   libswiftCore.dylib            	0x00007fff2c9451b4 Sequence.forEach(_:) + 436
10  com.apple.combine             	0x00007fff2e73ad5d ConduitList.forEach(_:) + 173
11  com.apple.combine             	0x00007fff2e7010a6 PassthroughSubject.send(_:) + 166
12  com.hogbaysoftware.Bike       	0x0000000109bb03c8 0x109a82000 + 1237960
13  com.hogbaysoftware.Bike       	0x0000000109c42758 0x109a82000 + 1836888
14  com.hogbaysoftware.Bike       	0x0000000109c2d1de 0x109a82000 + 1749470
15  com.hogbaysoftware.Bike       	0x0000000109ab2edf 0x109a82000 + 200415
16  com.hogbaysoftware.Bike       	0x0000000109ab311f 0x109a82000 + 200991
17  com.apple.AppKit              	0x00007fff22ff5c0b -[NSApplication(NSResponder) sendAction:to:from:] + 288
18  com.apple.AppKit              	0x00007fff230c044f _NSGestureRecognizerSendActions + 173
19  com.apple.AppKit              	0x00007fff2382e156 -[NSGestureRecognizer _updateGesture] + 1266
20  com.apple.AppKit              	0x00007fff230c028b ___NSGestureRecognizerUpdate_block_invoke + 51
21  com.apple.AppKit              	0x00007fff22f62176 _NSGestureRecognizerRemoveObjectsFromArrayAndApplyBlocks + 305
22  com.apple.AppKit              	0x00007fff22f619f0 _NSGestureRecognizerUpdate + 1384
23  com.apple.AppKit              	0x00007fff22fe7d84 -[NSWindow(NSGestureRecognizer_Routing) _sendEventToGestureRecognizers:requireAcceptsFirstMouse:] + 2922
24  com.apple.AppKit              	0x00007fff22fef768 -[NSWindow(NSEventRouting) _handleMouseDownEvent:isDelayedEvent:] + 4891
25  com.apple.AppKit              	0x00007fff22f5efc8 -[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] + 2594
26  com.apple.AppKit              	0x00007fff22f5e386 -[NSWindow(NSEventRouting) sendEvent:] + 347
27  com.hogbaysoftware.Bike       	0x0000000109aa715b 0x109a82000 + 151899
28  com.hogbaysoftware.Bike       	0x0000000109aa719f 0x109a82000 + 151967
29  com.apple.AppKit              	0x00007fff22f5c794 -[NSApplication(NSEvent) sendEvent:] + 352
30  com.hogbaysoftware.Bike       	0x0000000109ab82c1 0x109a82000 + 221889
31  com.apple.AppKit              	0x00007fff23235531 -[NSApplication _handleEvent:] + 65
32  com.apple.AppKit              	0x00007fff22dc562e -[NSApplication run] + 623
33  com.apple.AppKit              	0x00007fff22d9980c NSApplicationMain + 816
34  com.hogbaysoftware.Bike       	0x0000000109a86dec 0x109a82000 + 19948
35  libdyld.dylib                 	0x00007fff204f0f3d start + 1

1 Like

Thanks, I can reproduce the problem and will get a fix in soon.

In macOS Monterey, it is not working.

I have both the system settings checked and the Show Checking panel checked.

macosxguru

I just tested on Monterey and I got it working there too.

For you are any of the autocorrect, text replacement, text substitution features working? For example will smart dashes work?

I did notice that by default Bike’s settings didn’t match system settings. So you need to go into Bike’s check panel and check all the options that you want. Here’s what my system and Bike preferences look like to get it working on Monterey.

First glance feels great! I love the look and feel and functionality of the blue and red lines. I love that the blue lines disappear after moving on to the next sentence, and I love that if I select some text, a light blue lines reappear. Really well thought out.

1 Like

I just realized that “Dash Replacements” translate ... into a single character , that’s in addition to translating -- into . For efficiency I need to hardcode these values instead of running the checking mechanism everything … does anyone know of any other sequences that “Dash Replacements” replaces?

Same question for smart quotes. Now I am checking only for " and ', does smart quotes smarten up any other sequences?

It was my screwup. I did not have Spelling checked in the Bike’s checking panel. My bad.

It works fine.

macosxguru

Great to hear! I think I can clear things for future by disabling autocorrect checkbox in case when spelling isn’t selected.

I used it all day yesterday and it worked beautifully. I love the refinements of how the different elements work, especially the persistent autocorrect underlines for the whole sentence, the collection of all auto-correct related options in the Checking panel, and how Bike handles default settings. Really nice!

1 Like

Any good sources or links for finding out what those are,
and how we might test them ? :slight_smile:

Ha, not really! Or not exactly as implemented.

The background as I understand it is that before we had selection ranges in graphical text editors we had point and mark in console based text editors. So to do something with a range of text you needed to set the mark, position the point, and then perform the command.

And in same text editors people wanted to undo or move text, and they did that by putting deleted text into the kill ring, and if you wanted to get it back you would use yank commands.

From that history a very specific implementation of these ideas exists in the cocoa’s text system, not well documented. I think the primary reason why you might uses (and why I bothered adding to Bike) is because these are convenient (or at least common) features to use when building custom keybindings.

For example save the XML at the end of this post to this path:

~/Library/Keybindings/DefaultKeyBinding.plist:

Then restart TextEdit and Bike and then:

  1. Select some text
  2. Press and release Control-a
  3. Enter character (

And the selected text will be wrapped in ().

To make it all work it’s important that Bike’s commands have the exact same behavior as TextEdits. So most of the work was trying to understand and copy the not well documented default behavior.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>^a</key>
    <dict>
        <key>(</key>
        <array>
            <string>delete:</string>
            <string>insertText:</string>
            <string>( </string>
            <string>deleteBackward:</string>
            <string>yank:</string>
            <string>insertText:</string>
            <string> </string>
            <string>moveLeft:</string>
            <string>insertText:</string>
            <string>)</string>
            <string>deleteForward:</string>
        </array>
    </dict>
</dict>
</plist>
1 Like

Perhaps, looking at your plist code, ^a ?

(that seems to work here)

The extension I need here seems to be .plist

(rather than .dict)

Given that change of path, and using ^a, it works well …

(In both Bike and TextEdit)

Interesting and impressive …

Oops, yes, fixed now.

The extension I need here seems to be .plist

Odd, for me .dict does seem to be working. Though plist is probably more appropriate. I’ll change that above too.

1 Like

Yeah, I never knew Macs custom keybindings could do multiple commands in a single binding. Also didn’t know they could recognize sequences over time.

I wish I could plug into that system and enable different sets of bindings. For example different sets of bindings when in outline mode. So far I haven’t figured out how to do that, seems like they are read on app startup and not changeable after.

1 Like

This might be of interest to you. KeyBindings - BrettTerpstra.com

macosxguru

2 Likes

Great changes overall – with one major exception. :frowning: I find this behavior to be quite problematic:

Instead of avoiding autocorrects Bike makes them easy to undo. You can undo an autocorrect with a single Delete keystroke, instead of doing the two key Right Arrow, then Left Arrow dance to avoid like in TextEdit.

Since…

Bike autocorrect runs anytime you finish a word while typing text.

…it means that typing the space character after any word will trigger autocorrect. If I hit Delete then, it’s unclear what I actually mean – do I want to cancel autocorrection? Or do I want to remove the space character because I’ve forgotten to place a comma after the last word? Of course, instead of using Delete I could use the Left arrow key to move the cursor, insert the missing comma, then go back with Right arrow key – but that’s not what most people I know would do, myself included. I doubt I can retrain my brain just for one app.

This gets even worse if - as in my case - most of autocorrect results are expected which means that in most cases I really do want to delete the last character and not cancel autocorrecting.

I guess I’d prefer being able to use Cmd-Z – solved better than in TextEdit? only cancel autocorrect (i.e. once Bike autocorrects after I pressed space, I can hit Cmd-Z to cancel autocorrect, then hit Cmd-Z again to undo recent text operations)?