Repository: neovim
Issue: Proposal: readonly text with extmarks
Labels: enhancement,marks

### Feature already in Vim?

No.

### Feature description

The requested feature would entail providing a lua API and some extra editor behavior to create readonly sections of text in a buffer, via use of extmarks. In principle, this could be boolean `readonly` key passed to the `opts` parameter of `nvim_buf_set_extmark`. It would default to false, for compatibility, and could be toggled to add special behavior to the section.

### Details

The aforementioned extra behavior is to prevent modification of the marked areas, by either disabling actions that can change them or redirecting the action to a non-readonly section. As an example, picture the following:

```
    <I am read|only.> I am not.
``` 

If `<` and `>` mark the beginning and end of the extmark, plus the cursor is at the pipe's position above, then pressing <kbd>x</kbd> in normal mode to delete a character could do one of two things (this is to be discussed, and could possibly be configurable):

- Nothing.
- Remove the next non-readonly character in the buffer (the space before `I am not.` in this case).

Similarly, pressing <kbd>i</kbd> to enter insert mode could do either:

- Nothing.
- Enter insert mode before the readonly section (in this case before where the `<` is). Typing some text here would move the extmark, such that the text inside it is kept. Note that if `right_gravity` is `false`, the cursor would have to be one character before to be able to type, whereas with `right_gravity = true` being on the first character allows insert. (This behavior is to prevent the user from being able to write at the beginning of the buffer, before any extmarks)

Navigating with the arrow keys in insert mode could do:

- Nothing (requiring the user to be in normal mode to go through the readonly text).
- Skip to the next character in the direction of movement.

### Use case

There are plugins (Neogit, nvim-tree, dapui, to name some) that create a special buffer that shouldn't be edited directly by the user, instead containing machine generated content that reflects the functionality of the plugin. Managing such a buffer can be troublesome at times, in particular if you can't get away with disabling insert mode and handling keybinds manually. Most of the plugins I mentioned can, indeed, get away with that, but I think I found a use case that can't be implemented without either some support for readonly content  or a lot of hackery witchcraft.

It's a project search and replace plugin, that would work like the following:

1. The user  types a command to get into the search and replace buffer.
2. On top, the user can enter their search patterns in the proper location (but should not be able to edit the instructions on the buffer).
3. As they stop typing, the section below the search field is dynamically populated with matched file contents.
4.  Once the query is finished, they can press enter to lock the search. Now the search field vanishes and only the matches remain (with optionally some lines of context around them and origin file annotations).
5. Now the user can edit the matches (but not the context) and the changes are applied to the respective files on enter.

The user could also run a regex substitution to change many at a time, and only the matches should be touchable, not the context. This last bit seem to not be possible currently, and preventing regular editing from messing up the buffer is also quite hard and unreliable.

This is only my own use case for the proposed feature, but it seems like something generally desirable from a UI perspective, and could allow smarter, less error prone plugins without the author having to think of every corner case and escape mechanism.

### Alternatives

I've considered virtual text for this, but it seems to not be right choice, because 1) its not real text, so the user wouldn't be able to do motions, put the cursor over or search through it; 2) From my understanding, you're not supposed to (and maybe you can't even) make a buffer entirely or almost entirely with virtual text, there has to be some content, and if only the matches were text we'd have weird jumpy behavior due to 1.

As for why this can't be a plugin or an external feature of some sort, that's because it doesn't seem to be possible that way. In my plugin I tried to do it, but it is over complicated and could break easily.

### Implementation

I think I can provide a start to this myself, though since I'm inexperienced in the project's codebase I'd appreciate some pointers. Also, everything I've proposed here is up for discussion, in fact, there are design decisions still to be made that need discussion.

Side note: The plugin I mentioned is not public yet, but if requested I can provide the partial implementation as an example.