Bike 2.0 (Preview 211-212)

New Bike 2.0 Preview today!

Still not ready for daily use!

I do not expect that it will corrupt files or delete data, but there’s many missing features and visual glitches. The focus of this release is on the extension API. Please give that a close look and let me know how I can make it better.

This release adds two big changes:

  • Outline editor filtering
  • Extension API

Themes note: This release started as work to polish themes and then evolved in horrible and wonderful ways beyond that scope. Theme changes were left in a halfway state.

  1. The Bike (Standard) theme is built in and can’t be modified.
  2. To modify that build in theme you need to copy it from Bike’s app bundle and into Bikes Window > Themes folder.

Outline editor filtering

First choose Window > Themes > Bike (Standard), otherwise you won’t see scaled search results.

Use Command-Shift-F to show filter. Enter plain text or an outline path.

Outline rows are expanded to show matches and collapsed for branches that contain no matches. That default stylesheet also scales the remaining visible rows (that are not matches) smaller.

Like many features of the current Bike preview… I think big picture is coming together, but details aren’t very polished. A few fixes planned:

Todos:

  • Fix/smooth row scaling animations
  • Make it possible to restore original expand/collapse state after filter

Extension API

The extension API, yeah!

This won’t stabilize until some later Bike 2.x release. Right now my goal is to get the API right. Please take a look and let me know what it needs. Later in some 2.x release I’ll make extensions more user friendly to install/manage/update.

Generally I’m learning modern Javascript/Typescript as I go. I feel pretty good about where things are now, but don’t hesitate to let me know if I’m doing things in a non-standard way, where the standard way would be better.

Overview:

  • Extensions written in typescript or javascript
  • APIs protected by opt-in permission system
  • Each extension runs in separate script context… not sure if this is necessary or not. If anyone knows a lot about javascript security I have some questions for you! :slight_smile:

Get started:

  1. Choose menu Bike > Extensions… to open the extensions folder

  2. Open that entire folder in VS Code, you will see two subfolders @Bike and @Startup.

  3. @Bike contains the API definitions along with lots of documentation comments.

  4. @Startup is a special Bike extension that is always loads first. Take a look at @Startup see how the core extension APIs work. Try making changes.

  5. You should get a good autocomplete experience and type checking. When you save, Bike should load those changes immediately.

The API has four big components:

  • Commands: Define your own command and it will show up in the View > Show Commands (Command-P) palette.

  • Keybindings: Define your own keybindings (target the text-mode or block-mode keymap). Keybindings can trigger a named command or an arbitrary callback.

  • Outline Editor: Extensions can access and modify the selection/focus/fold and filter state of outline editors

  • Outline: Extensions can read/write outlines and associated rows… though some of that API is missing right now. See commented out API’s in @Bike folder.

  • Sidebar: Extensions can add sidebar items. My thinking is there will be two kinds of items: Buttons and outline paths. Click buttons to run an action. Click outline path items to set the editor filter. Eventually I expect outline path item to also expand to show matched rows.

Todo:

  • If you look in the @Bike API you’ll see sections of the API commented out. In particular most of the API for editing rows is commented out. I expect to get that uncommented soon.

  • Integrate theme system and extension system APIs. Now they are separate, and for example you can’t use typescript in the theme system. I plan to move all the theme API’s into the extension system.

  • The sidebar item ordering property is ignored right now.

2 Likes

If you are messing with this… just realized that live reload will not work if you are editing the @Startup extension. It should work if you create your own … make sure that your extension folder has .bikeextension file extension.

2 Likes

Cool stuff!

I’m still working on theming, and I still can’t get this to work:

defineRowRule(".parent() = true/run::@view-paragraph-focus", (env, row) => {
    row.text.color = Color.systemRed()
})

Shouldn’t this make parent rows I have focus turn red? :confused: (That’s not what I want – but it’s a start.)

I’m also trying to have a different colour on the arrow if the row is a .heading. How would I do that?

defineRowRule(".parent() = true", (env, row) => {
  let theme = resolveTheme(env);
  row.text.decoration("focus", (focus, layout) => {
    let size = layout.lastLine.height;
    focus.contents.gravity = "center";
    focus.contents.image = symbolImage(
      "arrow.down.forward",
      theme.colors.text.withAlpha(0.2),
      row.text.font,
    );
    focus.x = layout.lastLine.trailing
      .offset(size.scale(0.5))
      .offset(row.text.padding.right);
    focus.y = layout.lastLine.centerY;
    focus.width = size;
    focus.height = size;
    if (env.isTyping && theme.hideControlsWhenTyping) {
      focus.opacity = 0;
    }
  });
1 Like

Hum… I think there’s a bug here, will try to fix today

I’m going to try to be good and fix bug first… then my treat is to check this out. Thanks for sharing :slight_smile:

1 Like

Are you talking about the “Focus in Arrow” in that case I think this is what you want. This should make the arrow for headings with children colored red.

defineRowRule(".@type = heading and parent() = true", (env, row) => {
    row.text.decoration("focus", (focus, layout) => {
        focus.contents.image = symbolImage("arrow.down.forward", Color.systemRed(), row.text.font)
    })
})

Regarding the bug exposed by:

.parent() = true/run::@view-paragraph-focus

I think I need to redesign this a bit. The problem is that the code that inserts view attributes such as view-paragraph-focus is a bit special cased. It is injected for run rules, but you are trying to access those attributes from a row rule and they are not injected there.

I think probably the whole idea of injecting those attributes that way is a bad idea. Instead I think I need to add more functions to query view state, such as the existing selection() and expanded() and collapsed() functions.

So in the future (once I add this fix) I think your path could work something like this:

.parent() = true/run::paragraph-focus()

Does that make sense? It will make those attributes a bit harder to find, since they will not show up in the outline path explorer. But it should also be a bit more efficient and more importantly work for all cases.

1 Like

I’ve just posted 212. It mostly adds extension API’s that I didn’t have time to finish for 211:

  • Added Outline.insertRows, Outline.moveRows, Outline.removeRows
  • Added Outline.query, Outline.scheduleQuery, Outline.streamQuery
  • Added Outline.importRows, Outline.exportRows
  • Fixed console.log to show in Safari insprector and Console.app
  • Fixed Outline Path Explorer to always show frontmost outline view state
  • Fixed live reload of @Startup extension
1 Like

Nice! :raised_hands:t2:

If you think you’ve deserved the treat :stuck_out_tongue:, I’ve updated my theme draft:

Havn.biketheme 0.2.zip (40.2 KB)

I don’t really know Javascript, so it’s probably painful to read! :see_no_evil: It should also be fully usable, if anyone else wants to give it a go. (Feedback appreciated!)

I’ve had one idea, BTW. Just like with theme.hideControlsWhenTyping, I’d like an option like hideHandleWhenNoChildren.

2 Likes

Some outline filtering feedback, based on what I’m seeing in my 1107-node outline.

  • When I search for @task where task row types (or their parents!) have many siblings, current solution gives me more redundant context than I need/want to see. Sometimes I see more non-matches than matches on-screen. Basically, it makes everything look very messy.
    (dummy example below)
  • In cases where context could be helpful, like child rows of matches, that isn’t shown because matches are collapsed. I can always expand, but there currently doesn’t seem to be a way to do that with keyboard only (I know, not final :slight_smile: ).
  • In cases where I only get a couple of matches on a keyword, those matches can appear off-screen multiple times because of filtering logic. Pressing Return to jump to match helps, but it’s really forcing me to look everything one-by-one and not see the big picture. I’m not sure what the benefit of Filter vs. Find is in this case, and this is my main issue with this version of filtering. It’s not removing excess information, just presenting it in a different—sometimes even more confusing—way.
  • Unfortunately, I’m not seeing the scaling visible non-matches on Default theme—maybe there’s something I’m supposed to activate?

Overall, I’m not a big fan of the current iteration, but I’m curious of seeing how scaled non-matches behave.

Ah… that will at least make things look quite different. Make sure to choose Window > Themes > Bike (Standard) to see scaling. That should be at the very top of the themes menu with a divider right below it. Do you see scaling in that case?

This is what I see:

I haven’t fixed bug yet, but thanks for screenshot. Great to see theme work and testing, thanks! Can’t wait to dig in and see how you’ve done things. Also, while it’s fresh in your mind, if you have a moment please list out any difficulties you had that I might be able to smooth over.

1 Like

A post was split to a new topic: Bike 2 Stylesheet feedback

Ah, that was it, I had it set to the Default theme. That’s a dramatic improvement in legibility.

OK, I have to admit, I had doubts about the scaling implementation, but I think it could work. Makes it look kind of like a minimap in an IDE. Have you tried adding an opacity fade to the scaled text?

Here’s what I see:

  • when I cmd-shift-F and search for a term/outline path, the outline filters out when expected, but when I hit Return, it takes me to the second match, not the first one as I would expect
  • matches don’t show ancestor path out of the box. Is there any other way to do this other than with outline path union //<search term>/ancestor::*?
  • don’t see a clear way to select only matches and manipulate only those. Contiguous selection doesn’t seem possible.
  • shorthand for the most obvious searches would be very welcome. It’s one thing to write out something like //*/run::@highlight/..* union //*/run::@highlight/..*/ancestor::*// to find highlighted text vs. just highlight:. It gets even weirder and more complicated when you’re looking for highlighted text that’s also a task.

I understand that last bullet is (partially) the point of extension API, but from a UX perspective from a non-coder…do I really have to learn a new computer language in order to perform basic search functions? This is what drives me crazy with Roam Research, Tana, Logseq etc., something I’ve ranted about on this forum before and something Tiago Forte goes into in depth as well. I love the power that comes under Bike’s hood, but dammit, give me something I don’t need to spend an hour searching community forums for :rofl: So…maybe a “Core” (official but non-obligatory) extension that allows for simplicity in searches?

Please, don’t take the above as personal or disrespectful. I have immense appreciation for what Bike is, does, this whole community and you as a developer. I think it’s top tier software, especially once compared to the other options that are out there and feel like they’re from 1997 and beyond. It’s part of the reason I’m so passionate about it—I want the power when I need it, but I also want it to feel comfortable to dimwits like me that need LLMs to understand how and what to search for.

This sounds like a good idea. :ok_hand:t2:

Good catch, this is just a bug I need to fix.

This is more easily controlled in stylesheet. Right now the built in stylesheet scaling everything small and then only scaling filter-match() back to normal size, but you can also use filter-match-ancestor() to scale match ancestors. Probably that should be done, but I just haven’t experimented with that possibility yet.

Yes, Bike doesn’t support discontiguous selections. It might someday, but probably not in 2.0 release. My solution for manipulating the matches is if you click on the match count in the filter bar you’ll get a popup … EXCEPT those actions are not actually implemented yet, but that’s the plan.

Maybe if you could break out a new topic with some suggested obvious searches that would be a good starting point. Along with any ideas you have for bringing simplicity to Bike searches. I think Bike’s outline path syntax is here to stay as powerful, but complex. But if there are things I can make easier I will try.

If you “shorthand” you mean predefined named searches, I think that might work. But I don’t think a new simpler search language would be simplifying at the moment.

The best way to limit that complexity that I can think of is saved (and maybe predefined) searches. So you only need to compose the search once, and then can reuse.

Not sure, but maybe this is a simpler way for task with highlighted text?

//task/run::@highlight

No! I appreciate the feedback, thanks for taking a look and thinking about how it all should fit together.

1 Like