Bike 2.0 (Preview 274)

  • Added button to show/hide inspector
  • Added Restore All Settings in General preferences
  • Compress redundant text in breadcrumb (Navigate to calendar day for example)
  • Fixed word-granularity drag selection losing the original double-clicked word
  • Fixed font size slider changing line height
  • Fixed font family popup resetting size to 13pt
  • Fixed window opening with zero height after Restore All Settings

Extensions

  • Replaced AppleScript resolve with get row command
  • Fixed showAlert fields being silently dropped
  • Fixed bike.defaults.observe never firing in app context
  • Fixed shared Settings/Inspector bike.defaults

Download:

2 Likes

This is very minor, but would it be possible to have editor get focus once you click on a date in the calendar? Caret seems to place itself correctly in 274, but it’s greyed out. I notice cmd+Return can create a new row, but just Return, shift+Return or ESC don’t do anything.

BTW redundant text removal in breadcrumbs works great!

I had it this way originally, but want to keep it current way, at least for now. Seems a bit more consistent with standard view interactinos.

I just added this last release. I’m not sure if I will keep, but the idea is to always show caret, even when outline editor doesn’t have keyboard focus. But when it doesn’t have focus I stop it blinking and show in unfocused selewction color.

Is there a way to get back to the editor with the keyboard?

Shift-Tab should do it. Or Tab multiple times depending on what views you have open.

Works with Keyboard navigation OFF in macOS system settings. With ON, it seems to advance/backtrack the day selection in calendar but without any visual feedback. If I then press Return, I’ll get a new calendar entry depending on how far I’ve shifted.

Just feedback on what I see. I’m not sure I have a suggestion/request here at the moment. I’m thinking it would be nice if calendar could get a keyboard-driven upgrade at some point.

1 Like

Thanks, good to know.

In that case then I think Control-Tab might work to switch focus back to editor. I’ll also investigate the behavior you describe.

Links in documents are followed here, when I select one and use āŒ˜ā‡§O,

but they don’t seem to be clickable, and I see no pointing hand cursor when hovering over them.

Could, of course, be something to do with my particular setup so I’ve:

  • disabled all extensions,
  • tried Bike > Settings > General > Reset All Settings
  • and restarted Bike 2.0 Preview (274)

Might there be something else that I’m missing, or is this perhaps a known issue for 274 ?

( a side-effect of the enriched id and persistentId model ? )

Doesn’t work for me, either. I don’t remember if there was ever a pointing hand on hover or not, and I’m 80% sure only the outward pointing arrow at the end of the link was clickable (not the link text), but that doesn’t seem to work in 274, either.

I also notice if I try to commit the link this way:

  1. Select word(s)
  2. Cmd+K
  3. Type in link
  4. Cmd+Return

I get a blank new row but no link. Just Return seems to work as expected. Is this intended?

Thanks, that’s helpful – I’ll stop looking for the moment :slight_smile:

The only thing I notice, with logging enabled, is:

[warning] ExtensionManager: Skipping old !bike core extension

So I wonder if there’s some house-keeping that I need to do.

Oh, this is bug I introduced in last release. I changed zIndex of those link button decorations to -1, so that strikethrough would draw behind them, forgetting that would also put them behind text layer, where they can’t be clicked. Fixed for next release.

Return is the intended action to commit the link. Command+Return is being picked up by Outline > New Row. It’s a weird edge case, but I think the current behavior is good enough for now.

This shouldn’t be causing any problems, but you can get rid of that warning by going in to the Extensions folder and deleting the !bike.bkext. A few released back I renamed it to bike.bkext. The ā€œ!ā€ version is just left over when you run an earlier release of Bike 2.0.

1 Like

In the spirit of this kind of HTML idiom

<a href="#contact-section">Jump to Contact Info</a>

<!-- OR, as in Pandoc MD -->

<a href="#contact-section">[^contact-section]</a>

<h2 id="contact-section">Contact Information</h2>

(where href attribute values are #-prefixed ids, pointing elsewhere on the same page)

and with Pandoc export, custom .persistentId labels (and Markdown mapping) in mind, I’ve had fun experimenting with this kind of pattern in build 274


As in:

<li>
  <p><a href="#contact-section">Jump to Contact Info</a></p>
</li>

<li>
  <p><a href="#contact-section">[^contact-section]</a></p>
</li>

<li id="contact-section" data-type="heading">
  <p>Contact Information</p>
</li>

Where the link address, rather than an https:// or bike:// url, is simply a hash-prefix followed by a Row.persistentId.


It seems to work, roughed out in draft extension code.

Draft app/main.ts
import { AppExtensionContext, Row, Selection } from 'bike/app'

type Either<L, R> = { type: "Either"; Left: L } | { type: "Either"; Right: R };
const Left = <L>(x: L): Either<L, never> => ({ type: "Either", Left: x });
const Right = <R>(x: R): Either<never, R> => ({ type: "Either", Right: x });

const bindLR = <L, R>(lr: Either<L, R>) =>
  <R2>(mf: (r: R) => Either<L, R2>): Either<L, R2> =>
    "Left" in lr
      ? Left(lr.Left)
      : mf(lr.Right);


const either = <L, C>(fl: (l: L) => C) =>
  <R>(fr: (r: R) => C) =>
    (e: Either<L, R>): C =>
      "Left" in e
        ? fl(e.Left)
        : fr(e.Right);


const firstInternalLinkInRowLR = (row: Row): Either<string, string> => {
  const text = row.text;
  for (let i = 0; i < text.count; i++) {
    const href = text.attributeAt('a', i);
    if (href && href.startsWith('#')) {
      return Right(href);
    }
  }
  return Left("No #link in first row of block.");
};


export async function activate(context: AppExtensionContext) {
  bike.commands.addCommands({
    commands: {
      'pandoc:jump-to-footnote': (cmdContext) => {
        const { editor, selection } = cmdContext;

        if (!editor || !selection) return false;

        // EITHER a status message,
        return either(
          (message: string) => (
            editor.showStatusMessage(message, 3000),
            false

          )
        )(
          // OR a revealed row, (if a target row found).
          (targetRow: Row) => (
            editor.revealRow(targetRow),
            editor.selectCaret(targetRow, 0),
            true
          )
        )(
          bindLR(
            (editor && selection)
              ? Right(selection)
              : Left("No selection found.")
          )(
            (seln: Selection) => bindLR(
              'text' === seln.type
                ? Right(seln.detail.text.attributeAt('a', 0))
                : 'caret' === seln.type
                  ? (() => {
                    const detail = seln.detail;

                    return Right(
                      seln.row.text.attributeAt(
                        'a', detail.char,
                        detail.runAffinity
                      )
                    );
                  })()
                  : 'block' === seln.type
                    ? firstInternalLinkInRowLR(seln.detail.startRow)
                    : Left(`Selection type not text, caret, or block.`)
            )(
              targetUrl => targetUrl && targetUrl.startsWith('#')
                ? (() => {
                  const targetId = targetUrl.substring(1);
                  const targetRow = editor.outline.getRowById(targetId);

                  return targetRow
                    ? Right(targetRow)
                    : Left(`Target footnote '${targetId}' not found.`);
                })()
                : Left("No #identifier link found.")
            )
          )
        );
      }
    }
  });
}
Draft dom/main.ts
import { Color, defineEditorStyleModifier } from 'bike/style'


defineEditorStyleModifier('footnote-jumper', 'Internal Link Jumper')
  .layer('run-formatting', (_, run) => {

    // Outline path matching runs that have an 
    // 'a' (link) attribute starting with a hash (#).
    run('.@a beginswith "#"', (_, runStyle) => {

      runStyle.color = Color.systemBlue();
      runStyle.underline.single = true;

  
      runStyle.decoration('footnote-click-target', (decoration, layout) => {
        decoration.width = layout.width;
        decoration.height = layout.height;

        // Route clicks to registered command
        decoration.commandName = 'pandoc:jump-to-footnote';

        decoration.zPosition = 10;
      });
    });
  });

A possible extension of the behaviour of standard link-following in Bike ?

(Assuming a bit of UI for assigning a mnemonic persistent id to a target row)


Links like <a href="#contact-section"> already work, of course,
if a .bike file is opened in a browser.

Can we show project folder name on Bike 2’s Title bar, like we can in VS Code?

You’ve probably covered this before, so I apologize. I want to start using Bike 2.0 as I LOVE the navigation features you added for the left side so I can jump around easier than the navigation bar (at least for me).

If I start working with the preview code, will it time out at any point? (Meaning it has a window of usability). I only say this as if I start putting stuff in it, I don’t want to get locked out of it as you continue forward with the development.

I want to try moving a bunch of different outlines into the same outline with focusing on the left navigation before I start playing with the new scripting you’ve added!

Glad you are liking 2.0, and the preview has no timeout.

Excellent! Then I will dive right in.

Hello, hope you’re enjoying a well-deserved break!

When you get back, I think I’ve found a bug in this release: clicking the arrow icon to the right of a link used to open the link, but doesn’t anymore.

1 Like

tried to add link to row, and first time i tried, i got the beachball, which then just ended with nothing happening. the second time, i got the beachball for a couple of seconds, and then i got the menu for selecting the row, which i successfully did add.

would it be possible to get a short Quickstart for the Calendar extension? I have no idea how to activate it or use it to generate a year’s worth of dates. thanks in advance.

Best way to approach search and replace row type ?

If I import a literate Haskell file (plain text, every code line prefixed with ā€˜>’) then I may end up with a good .bike file in which every code row has the type quote, and all other lines feed into body rows.

(Importing as markdown, or through a custom Pandoc bike-writer)

At this point, if I want to change all //@type=quote rows to type=code,
then while my first guess might be to sketch a quick script, especially if I am going to read and compose many such documents, I did also wonder, for a moment, whether I could do something like:

  • Filter on //@type=quote
  • Selection > Select All
  • Format > Row > Code Block

but perhaps the semantics of ⌘A Select All are not really intended for (or logically compatible with) query / filtered views ?


( Perhaps all I really need is an option, in my bike-writer.lua, to write out quote rows as data-type="code" )


Ah … turns out to need just a line or two at the Safari console – I should have tried sooner :slight_smile:

bike.frontmostOutlineEditor.outline.query("//@type=quote").value
.forEach(row => row.type="code")