FIameCaster / prism-code-editor

Lightweight, extensible code editor component for the web using Prism
https://prism-code-editor.netlify.app
MIT License
57 stars 7 forks source link

Show Invisibles and Multiple Selections / Cursors #27

Closed amxmln closed 2 months ago

amxmln commented 3 months ago

Hi! First of all, I love this project and am very much looking forward to integrating it into a couple ideas of mine. Thank you for building something like this! šŸ˜Š

I have two feature requests that Iā€™d like to make:

  1. An option for showing "invisibles", i.e. space and tab characters, usually as little dots and arrows (see "Invisible characters" option in VS Code) -> Perhaps this could be supported by adding the characters only to the "overlay" and not the textarea?
  2. Support for multiple cursors / selections like in the "big" code editorsā€”I realise this will be probably quite complex and might be beyond the scope of the project, but since I didnā€™t see an issue for it yet, I figured I might as well ask. šŸ˜‰

Keep up the awesome work and thank you for your time and effort!

FIameCaster commented 3 months ago

An option for showing "invisibles", i.e. space and tab characters, usually as little dots and arrows (see "Invisible characters" option in VS Code) -> Perhaps this could be supported by adding the characters only to the "overlay" and not the textarea?

There's actually a Prism plugin called Show invisibles that does this. It works by modifying grammars, which is not possible here. Adding these dots and arrows as an overlay instead is a great idea! The VSCode extension only shows these invisibles when they're selected. It looks rather messy when they're always shown, so I think we should do the same. The extension would have to update the overlay every time the selection changes. It would likely not have amazing performance when lots of text is selected, but it should be fast enough.

Support for multiple cursors / selections like in the "big" code editorsā€”I realise this will be probably quite complex and might be beyond the scope of the project, but since I didnā€™t see an issue for it yet, I figured I might as well ask. šŸ˜‰

Yup, this would likely require re-implementing the browser's native cursor and selection handling. I don't see this happening.

amxmln commented 3 months ago

Ah yes, I stumbled over that plugin myself, but it really does look messy. šŸ˜… I think just showing spaces and tabs would be enough and personally I like having them visible all the time, so maybe that could be configurable? Especially since making them available only within the selection might come with a performance cost. šŸ¤”

RE multiple cursors: completely understandable, thatā€™s what we have CodeMirror et al. for. šŸ‘

FIameCaster commented 3 months ago

personally I like having them visible all the time, so maybe that could be configurable

Making that configurable with a boolean argument would not be an issue.

Especially since making them available only within the selection might come with a performance cost.

Having them visible all the time would improve performance when changing the selection since then they won't have to be updated. Simultaneously, it would perform worse when typing since then there usually won't be any text selected.

panoply commented 3 months ago

Though not part of PCE itself, extending language grammars will allow you to capture invisibles. Definitely not advisable, considering it will result in perf hits doing it on the grammar level, but worth noting it is not impossible even in the current state.

https://github.com/user-attachments/assets/3b698799-eb53-4c54-bf20-8dcf48c4e745

FIameCaster commented 2 months ago

I added the showInvisibles extension in the most recent 3.4.0 beta. It's used in the autocomplete demo if you want to try it.

By default, the invisibles are only shown in selected text as showing them all the time led to worse performance overall. The extension takes a boolean argument to always show them.

I tried using a mask-image to style the invisibles, but this had poor performance, so I switched to clip-path instead.

amxmln commented 2 months ago

Thanks for the update! I might be doing something wrong, I couldnā€™t get the invisibles to show up in the example you linkedā€”but I had a look at the code.

What if instead of using clip-paths, you used Unicode characters like the official Prism invisibles plugin? šŸ¤”

FIameCaster commented 2 months ago

I couldnā€™t get the invisibles to show up in the example you linked

Oops, I somehow sent the wrong link. Here's the correct one: https://stackblitz.com/edit/vitejs-vite-tjcjyl?file=src%2Fautocomplete.ts

What if instead of using clip-paths, you used Unicode characters like the official Prism invisibles plugin?

Can't imagine that yielding better performance, plus it's less customizable.

amxmln commented 2 months ago

Now itā€™s working! Looking great. Do you have any figures regarding how much this impacts performance? Especially when showing them for the entire document?

Can't imagine that yielding better performance, plus it's less customizable.

If it doesnā€™t impact performance, then the clip-paths are just fine!

Thank you so much for adding this so quickly! The experimental autocomplete looks pretty mind-blowing as well! Iā€™m very impressed.

FIameCaster commented 2 months ago

If it doesnā€™t impact performance, then the clip-paths are just fine!

Only the mask images were bad due to having to paint the SVGs most likely. The clip paths performed much better.

Do you have any figures regarding how much this impacts performance? Especially when showing them for the entire document?

Typing performance is roughly halved when they're always shown. It also adds more elements to the DOM, slowing down the entire website. When changing the selection, always showing them also performs worse unless most of the document is selected.

amxmln commented 2 months ago

Thatā€™s quite the price. šŸ˜… Thank you for adding the feature nonetheless. šŸ‘

Feel free to close this issue whenever it suits you, Iā€™m not sure if you usually keep them open until a new release is out.

FIameCaster commented 2 months ago

Safari and Chrome didn't render masks or clip paths on inline elements properly, so I had to add display: inline-block. Unfortunately that caused another issue. Tab characters can have a different width depending on which column they start in, but with display: inline-block they always have the same width.

Basically, I switched to Unicode characters in pseudo-elements; ā†’ for tabs and Ā· for space. It works without issue and performs about the same as clip-paths. I did prefer the look of the previous tabs, but it's obviously more important that it works properly.