yi-editor / yi

The Haskell-Scriptable Editor
GNU General Public License v2.0
1.5k stars 200 forks source link

Composable Modes #844

Open jhance opened 8 years ago

jhance commented 8 years ago

I kind of tried to look at doing this like two years ago, and hopefully I'm smarter now than I was then.

My vision is this: We need some sort of minor-vs-major distinction so that we can ensure that only one "major" mode is active at a time. I think the best way to do this is to have separate types, but a boolean record might be better.

A ModeStack should probably be different than a Mode. In particular a ModeStack needs to compose most of the things inside Mode, but not all, for example the name of a ModeStack should be a list of the underyling modes (in precedence order).

We need to define how certain parts of modes. Some parts should be major-mode only (think for example the modeline). We can convert a MajorMode into a ModeStack and then add a minor-mode into a ModeStack, changing the properties of the mode. Then AnyModeStack replaces AnyMode.

The type for minor modes can be littered with Maybes and hence we can have like a emptyMinorMode :: T.Text -> MinorMode which creates one with a bunch of Nothing.

(Names subject to change, its easiest to make the naming such that AnyMode = forall syntax. ModeStack syntax)

Note: This will first require composability of ExtHL. We can't make these monoids, but we can make them something structurally similar (like a product-preserving map?)

jhance commented 8 years ago

I made a PR on yi-language that starts this off by making ExtHL composable.

noughtmare commented 6 years ago

@jhance I think the most important thing to do is to define semantics for the compositions of modes. For example, what does it mean when two modes are composed and one wants to highlight a word red and the other wants to highlight it blue? Or if one mode binds a key to insert text and another binds that same key to delete some text?

I think the easiest semantics just always follow the semantics of the first mode (if there is a conflict), but that can cause unexpected behavior when a mode expects all its keybindings to actually be bound, what if a vim based mode would suddenly lose its escape key?

We can also define a composition of modes that only works if they don't conflict. For example, you wouldn't be able to compose a vim keybindings mode with an emacs keybdinding mode, because they have overlapping keybindings.

I think a better solution is to add a more nuanced way of composing modes where you can give priority to certain semantics. For example, you could say that errors are more important than warnings when highlighting text, so the highlighter should show an error if it overlaps with a warning.