Keyboard shortcut to quickly toggle editing the current code block

Hi! I’m quite new to SilverBullet, so sorry if there is already a solution for this. Also sorry for the giant wall of text, I’m a verbose person…


TL;DR: There are some unnecessary steps involved in leaving and re-entering a code block, which could perhaps be solved by a keyboard shortcut that toggles between editing and showing the results.

The Problem

When I’m working with complicated templates or Mermaid charts, I frequently find myself wanting to quickly check the result of the current code block, and then quickly get back into editing it. However, I feel like doing that takes a lot of steps.

As far as I can tell, the only way to leave editing mode is to move the cursor out of the code block, which either involves moving my hand over to the mouse and finding a selectable element, or doing something like Ctrl+Home that would consistently bring the cursor out of the block (but this could move the cursor very far away from the block, making it difficult to quickly return to it). And then to return to editing, the process involves clicking into the code block / moving the cursor back into it, and then - because the cursor is always reset to the top of the block - finding the position where you were previously, and then navigating back to that position. When working with complicated / lengthy blocks, it can be disorienting trying to figure out where you were when the code was completely hidden moments ago.

A Possible Solution

My idea to solve these papercuts is a keyboard shortcut that would toggle editing the current code block. While editing a code block, pressing it would take you out of editing mode (rendering the results, as if your cursor had left the block) and then pressing it again would take you back into editing mode at the same position you were previously.

This might seem like a minor improvement, but I think it would really improve efficiency when working with code blocks. To compare the two processes…

Current:

  1. Grab the mouse
  2. Find somewhere to click that would move the cursor
  3. Click
    (Look at results)
  4. Click the code block to leave editing mode
  5. Find where you were in the code
  6. Click the position

Proposed:

  1. Press the keybinding to show the results
    (Look at results)
  2. Press the same keybinding to resume editing

For the keybinding itself, my first thought was something like Ctrl+E or Alt+E (“E” for “Edit”). Or maybe it would be simplest to make this an additional function of Alt+Q, since showing the results of a template/query is very similar to its current function of refreshing templates/query results… though that might be a bit of a stretch…

Anyway, that’s it! Thanks for your time! SilverBullet is awesome!

Hi Chris, I don’t know of a solution to this so far, but luckily we have power overwhelming available in scripts.

This is a Space Script, you need to paste it into any note, run the System: Reload command, and Ctrl+E should work as you suggested.

```space-script
silverbullet.registerCommand({name: "Toggle editing code block", key: "Ctrl-e"}, async () => {
  const text = await syscall("editor.getText");
  const tree = await syscall("markdown.parseMarkdown", text);
  const cursorPos = await syscall("editor.getCursor");

  // console.log(JSON.stringify(tree, null, 2)); // here you can see what structure we're working with

  // in a Plug we'd have it ready-made in functions from plug-api/lib/tree.ts
  let node = tree;
  let insideCodeBlock = false;
  while (node.to >= cursorPos) {
    if (!node.children)
      break; // already found leaf node
  
    for (let child of node.children) {
      if (child.from <= cursorPos && child.to >= cursorPos) {
        if (node.type === "FencedCode") {
          insideCodeBlock = true;
          break;
        }
        node = child;
        break;
      }
    }
    if (insideCodeBlock)
      break;
  }
  // console.log("inside code", insideCodeBlock); // seems to work correctly
  if (insideCodeBlock) {
    document.toggleEditingCodeBlockCommandLastCursorPosition = cursorPos; // long name probably won't collide with anything
    await syscall("editor.moveCursor", node.from - 1);
  } else if (document.toggleEditingCodeBlockCommandLastCursorPosition) {
    await syscall("editor.moveCursor", document.toggleEditingCodeBlockCommandLastCursorPosition);
  } else {
    await syscall("editor.flashNotification", "'Toggle editing code block' command wasn't run from a code block on this page yet", "error");
  }
});

silverbullet.registerEventListener({name: "editor:pageLoaded"}, (event) => {
  // clear the saved position whenever we change page
  document.toggleEditingCodeBlockCommandLastCursorPosition = undefined;
});
```

I hope you enjoy it, let me know if it works.

By definition everyone in this forum writes more than usual, I hope my wall of code is a worthy riposte to your wall of text. Welcome to the community :smile:

3 Likes

Hi Marek! I’ve been away from my computer for a while, so I haven’t been able to try this out, but I just wanted to say THANK YOU!! I had no idea that the script system was so powerful! This is incredible and I can’t wait to mess around with this :slight_smile: