Plugin: Better Code Blocks


Better Code Blocks

Enhances code blocks with inline rendering, autocompletion, and more

preview

Features

  • Renders code blocks inline with Minimal or Standard styles
  • Adds copy button for inline code blocks
  • Autocompletes code blocks on Enter
  • Changes Select All to select the current code block

Settings

Setting Options Description
Autocompletion Enabled, Disabled Enables/disables automatic completion of code blocks when Enter is pressed
Rendering Enabled, Disabled Enables/disables rendering of code blocks
Behavior of Select All inside code block Enabled, Disabled Changes the behavior of Select All while the cursor is inside code blocks
Render layout Minimal, Standard Changes the layout of rendered code blocks
Corner style Square, Round Changes the border style of rendered code blocks
Excluded languages (comma-separated list) Disables rendering of code blocks for specific languages
Copy button behavior Copy code, Copy code and fences Controls what's copied when the Copy Code button is clicked

Hey all!

I frequently use code fences in my notes to keep track of snippets and documentation when I'm researching. But I find that the enclosing back-ticks kinda get in the way when I'm copying/modifying the code.

I also prefer to mess around in the note itself rather than using the preview pane.

So I created a plugin that "hides" the code fences and renders the code inline.

I added some other useful features like auto-completion of code blocks, a (hidden) copy button for quickly copying code, and a nifty hook to change "Select All" to select a code block instead if the cursor's currently inside one (you can "Select All" once more to get the normal behavior).

One of my goals with the rendering was to make it look as "native" as possible. So I was careful not to introduce extra vertical space when compared to the normal Joplin / CodeMirror rendering. I replaced the HTML of the fences (should be the same height :crossed_fingers:), but I didn't mess with the actual code lines.

If you don't like the rendering, you can disable it in settings and still get the auto-completion. I think the auto-completion alone is a really nice feature to have!

I added a bunch of CSS classes to the code block lines, so it should be pretty easy to customize everything to your liking.

Please let me know if you find bugs or have any feature requests! My CSS powers are extremely limited, so any styling contributions would also be greatly appreciated!

6 Likes

This is great!

I'm not clear on what you mean by "rendering". Could you say more?

Also, I see a bunch of flashing when a note is opened for the first time. Is that expected? It is the fencing area that flashes.

Personally, I'd rather have the copy button visible. With it hidden you kind of have to fish around for it. I think the copy button is such a standard element of code blocks that it makes sense just to have it visible.

Love the select all thing. Brilliant!

I'm not clear on what you mean by "rendering". Could you say more?

Sure, I got so used to referring to it this way in the code that I forgot it's actually pretty vague. It sounds more sophisticated than it actually is.

The plugin basically just changes the display of the beginning and end code fences (```python & ```) to make them unselectable. This makes it easier to edit and select the code inside. It does this using the built-in widget replacement functions of CodeMirror (the note editor). The fences still remain inside the note. You can copy the note text and they'll still be there. CodeMirror just lets the plugin change the HTML of that portion of the note.

I currently added two "layouts" for this. One hides the fences completely and moves the python part below the code block. The other makes it look like the fences are unchanged, but they've actually been replaced by different HTML elements and have been made unselectable.

For brevity, I starter referring to this as "rendering", similar to how the preview pane shows the rendered HTML.

The end result of all this is that code blocks act more like discrete cells/widgets which hopefully makes the code easier to manipulate.

Personally, I'd rather have the copy button visible. With it hidden you kind of have to fish around for it. I think the copy button is such a standard element of code blocks that it makes sense just to have it visible.

That's interesting. The reason I hid it was to make it less intrusive when editing, but that definitely a personal preference. I was also thinking about having an option to remove it altogether.
Would you want it to show up all the time or only when hovering over the code block with the cursor? I've seen both patterns used in the wild. Making it appear only when hovering is tricky I think, since I really only have control over individual lines in the note rather than a "wrapper" for each code block. That's just the way CodeMirror renders documents. Code fences are just normal lines.

Also, I see a bunch of flashing when a note is opened for the first time. Is that expected? It is the fencing area that flashes.

It is unfortunately expected. I noticed this happening in other similar plugins that mess with the HTML of the notes (e.g. Enhancement, Rich Markdown ), so I was thinking it was inevitable. But I should definitely take another look at it. No doubt it has something to do with re-rendering before/after the plugin is applied. Might be able to add a delay or something.

1 Like

This looks great, thanks for sharing!

Sorry for my, probably quite stupid question. I am new to Joplin and have no idea how to use your plugin. I have installed it successfully.
But I don't see any new icon or anything like that. Typing '...typescript' does nothing.
So what do I have to do to see the desired result?

Hey, are you typing backticks? (e.g. ```typescript)

Joplin supports using backticks and tildes for creating "code fences".
You can check out the full description in the markdown specification here.

For example, if you paste the following into a new document, does it show correctly?

```typescript
console.log("Hello World")
```

(Note that you also need to be using "markdown mode" instead of the "rich text editor mode")

1 Like

Thank you so much for creating this. I think it will be very useful to me, as I put lotas code into my Joplin notes.

The guy who does the Rich Markdown plugin once told me it was not possible to have code blocks scroll horizontally via overflow instead of wrapping due to the mechanics of CodeMirror. Not to say I don't believe him, because I've tried all manner of CSS hacks myself to no avail, but I don't suppose you might've come up with something to make that happen, eh?

1 Like

not possible to have code blocks scroll horizontally via overflow instead of wrapping due to the mechanics of CodeMirror.

As far as I can tell, this is true because the CodeMirror line layout is flat (i.e. there is a single codemirror container that holds all of the lines). There is no subcontainer created to hold lines that are part of the same code block. So there is no real way to work on the code block lines as an individual unit.

So I think CSS would only let you scroll all lines in the note or individual lines in the note. Whereas you would want to scroll all lines of the same code block in the note.

i.e. codemirror has

<container>
  <line># Heading</line>
  <line>```typescript</line>
  <line>```</line>
</container>

which lets you add a scrollbar for (all the lines inside) the container or for each individual line.

but you'd need

<container>
  <line># Heading</line>
  <subcontainer>
    <line>```typescript</line>
    <line>```</line>
  </subcontainer>
</container>

which would allow you to instead add a scrollbar for (the lines inside) the subcontainer.

Question…

If I have the setting turned on to lock the ``` Then say I have this:

```typescript
console.log("Hello World")

How am I supposed to change typescript to js without either disabling the plugin or disabling that feature?

The work around I have found is to type three back tics on their own line after the ```typescript line. This then tricks the plugin into thinking that I have an empty fence. it then unlocks it. I can change the text and then delete my extra three ticks.

Is that what we are expected to do?

Yeah I did consider this limitation, but I'm not sure how common it is to change languages for already-created code blocks. Do you have a specific usecase that requires it often?

Is that what we are expected to do?

Yeah there's kinda three ways to change the language:

  1. Add extra backticks like you are doing
  2. Backspace right at the beginning (inside of the code block) to delete the opening ```javascript
  3. Backspace right after the end (outside the code block) to delete the closing ```

Any time the plugin is unable to find a matching pair of ``` it will let you edit like normal. This is deliberate to allow you to type new code fences and edit existing ones.

Of course the best approach for editing the language would be to show a modal/dropdown/etc when you click the language. But I wasn't sure if this was worth the effort since I never really had the usecase to change languages. It does seem like a nice addition though.

Mostly I wanted to make sure I wasn't missing something.

What will sometimes (often? I'm not sure) happens is that I build the block and forget to put in the language. Sometimes CM does an ok job of figuring out how to lint, but sometimes not.

I agree that a context menu item would be overkill.

Thanks for the plugin!