Bike: Innovative Rich Text Editing
hogbaysoftware.com
hogbaysoftware.com
Internally the inline formatting will be marked as tags in a rage, exactly like html. Essentially there is a possible cursor position both inside and outside a formatting tag, but both appear as the same visual location on the screen. This is such a lovely way to indicate the difference.
So with this code:
Something <b>bold</b>
There are two cursor positions that are visually the same place: Something |<b>|bold</b>
^ ^
Most editors "jump" over one of those positions to hide the implementation detail from users. This idea exposes it with a little tail on the cursor.That particular bug with slack would be possible to fix with JS. The particular difference about that style is there is a little bit of padding at the start of the style. Bowsers have no understanding of clicking on that padding to select inside the the beginning of the inline style.
How? No matter what I try, the insertion point is always before the bold element, and not inside it.
[sandbox]: https://codesandbox.io/s/gracious-dew-rx3xhz?file=/index.htm...
On my Mac, Firefox 104.0.2 inserts new characters inside the <strong>, so they're bold.
In Chrome, the browser API allows positioning the selection there, but during the input event, the selection ends up normalized to just before the strong tag, so the characters aren't inserted into the <strong> tag.
In Safari, the browser API accepts the arguments to set the selection to the first position inside the strong tag, but normalizes during the API call, and the selection always ends up right before the strong tag.
The variance of contentEditable is a huge impediment to using the API raw. If you want reliable, relatively low-level control of rich text input on the web, use ProseMirror.
(I learned a lot about this stuff while working on Notion's rich-text editor, which is all custom.)
- The default behavior that triple-click to selects a whole paragraph/line will stop at the first contenteditable=false element.
- Android may dismiss the keyboard & selection if the selection ever touches one of your contenteditable=false marker elements.
- Firefox won't let you place the caret in between two contenteditable=false elements, or at the start or end of a contenteditable=true element if the first/last child is contenteditable=false.
Why not use ProseMirror?
Why not use ProseMirror? It doesn't fix this issue, does it? At least in the demos on their website you cannot insert text at the beginning of a styled element. You cannot do it even in a native application (at least on macOS) without a custom handling of the selection.
Do you happen to have any more samples to demonstrate how difficult it is to work with contenteditable APIs?
I think natively if you don’t jump into a tag and you don’t jump out of a tag. So if your cursor is in the tag and you move to the boundary, you stay in it. Similarly if you are outside of it, and move to the boundary you stay outside of it.
So I basically would listen to the the relevant input events, see if I’m at the boundary and the orientation of the cursor (which I save in memory) and if I’m only moving across a boundary (i.e. not to the next character) I call event.preventDefault(), manipulate the range accordingly, and update the orientation state.
I’m not sure how to style the caret it self (other then the color) but I’m sure it can be achieved with some absolute position hacking.
Think of them as having only a none nestable <span> tag with a style attribute.
The innovation is the visual indicator, the cursor tail. The rest is how WordPerfect worked 30 years ago.
It is horrifying to think how much the Microsoft Word approach has hobbled rich text editing for all those years, and continues to do so.
Microsoft Word may never have problems inserting any formatting, but I have; when it comes to paragraph structure, indenting and such, I find it very hard to predict. For example, I'll look at sections of a document with basically the same structure, but in one place the spacing between a table and the paragraph that follows is much larger, and I have no idea why or how to make them the same.
The feature there is named "directional caret"...
When I came up with this feature in Bike I was pretty proud of the idea and it seemed original. Then a few weeks later I came across your post on StackExchange UX... everything already been invented I guess :) I'm curious how you came with idea? Also have you come across other editors that implement it?
For me I new that something bothered me about rich text editing... always seemed more painful then required. I was also aware of the idea of split cursor from Humane Interface book. And also aware of affinity idea from text cursor position in wrapped text editor lines. Bike's typing affinity came from combining those ideas.
Anyway would love to hear any related thoughts or ideas.
While I have the eyeballs I hope you don't mind me asking...
I'm in process of adding autocomplete to Bike. Problem is that I generally find macOS autocomplete painful and unpredictable. I both disable it and have many typos. I'm not talking so much about the suggestions, but about the surrounding UI.
I'm looking for ideas/links for how to make autocomplete better and more predictable. I know Mac apps, I do know much else. What are your favorite autocomplete implementations past or present? If you could have a "fixed" macOS autocompletion what would it look like?
Possible autocomplete-related grammar error? ^_^
I'm not a user of Apple products, but in the Linux world there are code editors that enable the user to define custom completions. I find this to be an excellent productivity feature, not just for coding.
The editor Geany calls them snippets.
For autocorrect I'm talking about corrections that are less predictable such as spelling or grammar errors. They can be very useful because they mean fixes happen without any extra work, and mean you don't see lots of red spelling errors in your document... but it's also a case where computer is doing automatic work that sometimes might be wrong. So needs good way to indicate that correction has happened and easy way to revert.
Doesn't translate directly to macOS but useful reading: https://twitter.com/kocienda/status/1565341723860971520
And just in case you or somebody isn't familiar, read this classic: https://norvig.com/spell-correct.html
I suggest to try and keep it simple.
I've been doing indie Mac software since around 2003. Mostly full time with some consulting mixed in. I've had varying levels of success. Generally business grew into (enough to support me and three others for a few years) until around 2012. Then down down (with very little bumps of success in-between). Since 2012 it's been just me. I make less than I would in a "real" job. Sometimes quite a bit less. Even with Bike's recent success I'm mabye making less than average US programmer.
Some of this is likely due to indie being hard. Much is also due to me being mostly programmer driven, not business driven. I am doing many stupid things business wise. But I also get to work on exactly what I want to work on.
Long ago, I tried to make a better autocomplete feature so people with speech disabilities have fewer buttons to push. Here's what I did - https://ktype.net/wiki/research:articles:progress_20110209 - basically broke down tweets into n-grams (1-4) and then used the 5 most likely next words as suggestions. If I were to do this today, I would still try to get a large volume of text in my target use case (what do most of your users type? Tech project notes? home construction items? grocery lists) and break them down into large lists of 2-3 n-grams. Then ask GPT3 (or equivalent) for 3 possible suggestion for next 1-2 words and save them. Compress and hard-code this list into the app (or alternatively make it download/update from your site infrequently).
If you would like me to explain more, please feel free to reach out!
Bike does have a keyboard shortcut for expand/collapse, but truth is I don't remember what it is without looking. Instead what I do is always exit to "outline mode" with escape key, and then use left/right arrow keys.
Outline mode is inspired by vim, it's a mode where there is no text input, so you can use typing keys for other purposes. Right now it does very little, mostly just expand/collapse and delete. I hope to expand on this in future, but right now I'm more focused on text editing fundamentals.
Thanks for the autocomplete links. I maybe didn't explain well in my question... but I think I'll leave the actual autocomplete logic to macOS. I want to integrate with their autocomplete system so users will have consistent experience that way.
I'm more interested in UI problems of indication that correction has happened and easy undo when corrections go wrong. In this regard I think macOS is pretty poor.
For example on macOS if you type "hello " then after the space it will be corrected to "Hello ". If that's not what you wanted then there aren't really easy options to undo. Of course you can undo... but that will remove the space and then select "hello". Then another few keystrokes to get back to what you wanted. On the other hand in Google docs all you need to do is backspace and it undoes the autocorrect. I like that and will probably copy, but am looking for more autocorrect systems to learn from.
Old behavior: Autocomplete suggests the word I want partway, but by the time I tap it, I've typed additional keys and the suggestion changed. Deleting and trying again would enter the same mistake.
Current behavior: Autocomplete suggests the word I want partway, but by the time I tap it, I've typed additional keys and the suggestion changed. Deleting a few characters causes it to suggest (again) the word I actually wanted. It remembers the next most likely suggestion and I can quickly select it.
This change in behavior was the most significant improvement that I can recall. It went from maddening to somewhat annoying but useful.
Please keep up the good work. Mac nerds who care about high-quality native apps appreciate what you're doing.
Well that's really at the core of my question. Why do you have it disabled? What need to be improved so that you don't disable it.
I think almost everyone would agree that if you type "teh" or other common typos it would nice for computer to automatically correct them. But many people (myself included much of the time) disable autocorrect. I think this is because the UI isn't ideal.
I'm looking for ways to fix that. Maybe it's not fixable, but if you can enumerate specifics on why you disabled autocomplete on macOS I might come up with some solutions. Thanks!
I just turned the feature on for the first time since originally disabling it whenever it was introduced.
After playing with it briefly, it isn't fast enough to offer me any real help. Perhaps if I was hesitating on spelling a challenging word (does it have two of that letter or just one?) it would help me out. But I don't run into those scenarios often enough that it'd be worth the other downsides.
Just now, when I wanted to manually enter typos in the bottom line, it was clunky to dismiss without changing the words. I could mouse over the X or use the arrow keys to change position. Maybe there's another way that isn't intuitive to me? Maybe Esc, but I've already disabled it. Point is, it broke my flow.
I prefer to have the computer point out to me when I spell something incorrectly. It's a method of reinforcing the correct spelling. Then I can hopefully learn not to make the same mistake in the future.
Finally, as I've had it on while typing this post, it autocorrected a typo to the wrong word (amke turned to take; wtf). Had I not noticed, it would make my sentence strange (though most would just assume I was typing on a phone). That's fine on a web forum, but that's not acceptable in professional emails and the like.
It's just not useful to a life-long computer user with a full-sized kbd. However, despite 15 years of thumb typing on phones, the targets are still small enough and my thumbs are still large enough that it's mostly useful.
PS: Because I'm a fan of text-substitution apps (I use aText, but TypeIt4Me is also well-regarded), I already have custom entries for things like hte or thakns).
Good luck conquering this obstacle!
Consider taking a hint from every code editor. As the user types they are presented with a drop-down list of completions and corrections for the current word. This list hovers below the cursor and moves with it. The top item of the list is automatically selected such that hitting the completion key combo (often just the Tab key) replaces the current word with the selected item from the drop-down. The elements of the drop-down are sorted by likelihood of them being what the user meant to type and are navigated with up/down arrow keys. Hitting escape hides the completion drop-down and allows the user to use the up/down keys to move the cursor. At any time the user can press a key-combo to bring up a completion/correction drop-down for the word under the cursor.
I guess you could popup a list of all possible matching "correct" words as you type, but that would likely get old fast for normal writing. You would always see the popup. Generally autocorrect (fixing typos and spellings) happens once you have finished typing a word. At that point the word is checked, and maybe autocorrected.
I think that basic design is good. Finish word, then autocorrect if there's a high quality match. The place where I think problems happen and maybe a better design can help include:
1. Clear indication of what has been autocorrected
2. Easy way to revert autocorrections
3. Don't pop up to much UI during this whole process
I wonder if it’s an intentional easter egg that the keyboard shortcuts in the popover spell out “bischl”… which is more than a little reminiscent of “bicycle”. (Could improve it by replacing “h” for “highlight” with “y” for “yellow”: “bisycl”.)
In their app I think you can only use WYSIWYG, but it's full of insane flaws, like if you open a code span (backticks) and then close it but don't immediately enter some more text then there is literally no way to escape it into normal text again. You have to delete the whole code span and start again.
If anyone from Slack is reading this, fix your shit!
For puzzle two it uses some opaque heuristic to decide where to insert the text, I wouldn't really on it, I'd right click and edit the link.
My solution, when I coded my own word processor, was to use a single, invisible control character, '¶' ¹.
So, for example, bold would be enclosed by '¶b' and '¶B', and a first-level heading would be a line starting with '¶1'.
So, there exist characters in the text that are invisible but you know are there: you can insert the couple and delete it just like any other character.
¹(part of the extended character set - '¶' is easily accessible on some systems as [AltGr]+[R])
Two chars - fixed amount. One control, one command. Just cleaner, simple and functional. It's something you type, and it is hidden, you want it to be short and clear.
«How is that different», more literally: it is markup, like in htMl, but it is a special markup for that other special purpose of direct rich text tagging in word processors, not for hypertext (HTml). I called it differently, but if you so fancy, it is DRTTIWPML.
One feature that I do like about this design is it's pretty generic. For example in the future I could imagine detecting dates and then insert a button after the detected date to interact with calendar. I think the general idea of inserting simple interaction button in text can be quite useful.
Workflowy is what I use. It's cross platform, but a lot clunkier than this.
There are certainly a lot of Windows-only apps that are quite nice.
Further, as a person trying to develop a cross-platform, desktop-only GUI framework and applications, macOS is absolutely the worst offender on nearly everything. From only supporting an outdated OpenGL version to requiring that windows are managed on the main thread. Neither Windows nor Linux have either of these limitations.
For example, “<b><i>text” has three insertion points shown with the pipe character: “|<b>|<i>|text”
I suspect that is how Bike is doing it.
Thanks!
- https://codemirror.net - https://prosemirror.net - https://xi-editor.io
Great to see fresh, innovate apps like this that prioritize fast native experience.
The link editing doesn't seem like an improvement on other rich text interfaces, with no visually obvious way to edit the link destination.
A keyboard shortcut that tells you other keyboard shortcuts isn't at all innovative, but it is handy and more software should have it.
I think this is a great example of where an individual can really innovate on their own, but they do need to have a good mix of experience with developing on a particular platform as well as a good sense for UX.
Working in a larger company, you tend to have each of those tasks (implementing vs designing) split out into multiple roles, making it very difficult to know what's possible to innovate, plus experience levels often differ, so newer designers may not know the limitations on a platform, so may over-design, and developers may not have experience to implement certain things, so they may limit the end result as well.
Still, this looks amazing - thank you for implementing it. Would love to see this formatting UI used in more apps going forward.
What Jesse is doing here for rich text editing is astounding, to me, and is exactly the type of advancement that the popular word processing apps should take note of.
Since the use of an early Palm Pilot [1] I wanted to have a personal wiki. It was a little awkward in that moment comparing to something like a Squeak Wiki [2]. So when the iPhone 1 appeared [3] there was another call.
The first versions of iOS didn't include text selection and copy and paste to generate links to new pages. In this context I did a basic reverse engineer of the UITextView and could advance this towards the "wiki dream" but it would never be accepted in the Apple Store so I abandoned the idea that was basically without a business perspective.
As tptacek [4] said recently: "For several years I just use Apple's Notes.app. It's honestly pretty great; it's frustratingly good..." [5]. I would add: but it will be more great if they add native hyperlinks within the internal notes.
[1] https://en.wikipedia.org/wiki/Palm_(PDA)
[2] https://en.wikipedia.org/wiki/Swiki
[3] https://en.wikipedia.org/wiki/IPhone_(1st_generation)
For the hyperlinks, it seems editing the text and visiting the link is easy. But there isn’t a way to edit the hyperlink itself quickly?
Have you considered using affinity cursor along the up/down for that as well? Eg. Up updates the hyperlink content while default/down updates the link text.
Not sure how it would work out UX wise. Maybe opens up a popover with cursor for the hyperlink.
Correct. For that you need to use Formatting pallet (also in video). I did initially build it so clicking link would open a pallet with option to follow link or edit link (Pages.app) does that. But in the end felt better to make following link fast and add/edit links slower.
Up/Down could work, but I think it would break text editing movement/consistency more than I would want. For example if you were down arrowing to navigate you document and then randomly hit a link it would be frustrating to see link editor instead of keep moving down.
What I would love...
Take a look at Bike's file format, it's just a subset of HTML. Would love to someone to write a web based editor for Bike's file format. Then you could edit Bike files anywhere you want... and also have cool native experience on Mac.
Also note that Bike does read/write .txt and .opml.
I love that Jesse is taking a first principles approach with this and not constraining himself with the standard text editor patterns. He's also pretty active on the support forum and very receptive to feedback.
But all my notes are in Notational Velocity (https://notational.net/) at the moment, because the largest source of friction for me is finding note files. In Notational Velocity I never have to open a file dialog; file dialogs on Mac OS are still shockingly slow, and even if they were fast it would take too long to find the file I want. My hands never leave the keyboard; I just type a few characters and Notational Velocity finds the correct note for me.
Do you have any interest in adding an instant search feature, like Notational Velocity? I'd replace it if I could keep the fast search while being able to outline and edit with Bike's fantastic rich text capability.
Right now Bike is very much a text editor, while notational velocity is more database of text files. At some point I hope to add a "workspace" aspect to Bike where you can open a directory of Bike files, but this is a long way off. For now the focus will just be to improve the text editor aspect of Bike.
menuItem("Format:Bold", 0.2)
type("Efficient")
press("⏎")
This problem was solved in Vi with highlighting and concealing: the formatting characters are hidden and the target formatting is approximated until you move the cursor to edit the formatted bit. I’m sure Emacs has an equivalent.
I am a long time Apple user, but knowing Apple's direction, cannot invest in software made only for macOS.
Obsidian gives me everything I need, and mostly a multiplatform confidence.
Being a meta-shortcut I guess the more complex/options it gets, the worst.
What's the right way to write more than one line per row? Return always just adds a new row. For instance, with Workflowy, you can hit Return+shift to add a note to row which can be as long as you want, and only the first line of it will be shown if not focused.
Currently there is no way to add multiple lines to a row. I "think" I would rather solve this problem by adding multiple row types (maybe heading vrs notes) and then use some sort of filtering. That's still on todo list.
Few years ago, I was writing a tiny note taking app, and the only viable alternative was Trix.
The most popular is Quill, and then there are block style like EditorJS, and those meant to be very extensible like Lexical.
And many more- try searching for "Quill alternatives"
Re the luck factor, part of the appeal of Hacker News is there seems to be a lot of work done to minimize the role of luck. Which generally felt like it worked well for me historical, just not recently.
Not a big deal in any event, but if there's something I should be doing differently, I'd like to do it.
HN is better then any other platform (which is incredible considering how many engineers work on it) at detecting fraud (e.g. "upvote rings"). But I think a ton still comes down to the first few people that see the post.
How would these work with mobile devices ? It doesn't seam compatible.
Also, these are user interaction suggestions. What about the encoding ? There are plenty limitations with Markdown (the pseudo standard) on this aspect.
That's a bummer that it is Mac only, no Linux support, and even Windiws!! WTF?
And ideally it could be opensource)
I hope new tools would emerge, that implement this ideas.
As a long time Mac user, I think a little movement in the other direction is only fair. :-)
For links I just decided to leave out. Seemed blue was enough, and especially since link interaction in Bike only happens through link button. For general formatting I left out because underline formatting seems to be falling out of favor as a standard and when I asked in my forum most users said they didn't need it. Eventually I would like to read/write Markdown from Bike and underline isn't a part of standard Markdown.
Lots of great ideas, especially the format affinity indication/control. Is that just arrow key or arrow with cmd key? If it is only the arrow key, how do you distinguish user intent to actually move the cursor vs change the affinity?
The affinity is just treated as a new character position. When caret moves through that position is doesn't "move", but instead draws tail differently. So it's just normal arrow key with one extra state to move through. That extra state only happens at formatting boundaries, so generally the cost isn't too much.
\s