Skip to content

impl auto pairs config - #1624

Merged
archseer merged 13 commits into
helix-editor:masterfrom
dead10ck:auto_pairs_config_simple
Feb 25, 2022
Merged

impl auto pairs config#1624
archseer merged 13 commits into
helix-editor:masterfrom
dead10ck:auto_pairs_config_simple

Conversation

@dead10ck

@dead10ck dead10ck commented Feb 7, 2022

Copy link
Copy Markdown
Member

Implements configuration for which pairs of tokens get auto completed.

In order to help with this, the logic for when not to auto complete has been generalized from a specific hardcoded list of characters to simply testing if the next/prev char is alphanumeric.

It is possible to configure a global list of pairs as well as at the language level. The language config will take precedence over the global config. This is specifically intended to address and close #992 and #1347; it adds a pair mapping to the Rust section of the default languages.toml that excludes single quotes.

I had some ideas for more sophisticated configs for pairings, such as lexical rules, tree-sitter node lineage, etc, but I think these can be separate PRs. In particular, I'd really like to add a rule for checking a regex pattern on the line before and/or after the cursor to determine if a closer should be paired; e.g. pair <> but only if the < is directly adjacent to an alphabetic char to avoid pairing in "less than" expressions.

@dead10ck dead10ck mentioned this pull request Feb 7, 2022
Comment thread helix-core/src/auto_pairs.rs Outdated
Comment thread helix-core/src/auto_pairs.rs Outdated
Comment thread helix-core/src/auto_pairs.rs Outdated
Comment thread helix-core/src/auto_pairs.rs Outdated
@sudormrfbin sudormrfbin linked an issue Feb 7, 2022 that may be closed by this pull request
@dead10ck
dead10ck force-pushed the auto_pairs_config_simple branch 2 times, most recently from 39f20cd to 5715e38 Compare February 7, 2022 16:38
Comment thread helix-view/src/editor.rs Outdated
/// otherwise, falls back to the global auto pairs config.
pub fn get_document_auto_pairs(&self, id: DocumentId) -> Option<&AutoPairs> {
let global_config = (&self.auto_pairs).as_ref();
let doc = self.document(id)?;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In both cases you already have a &Document, but you pass in an id then look up the document again.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems a bit nicer if this is a method on the document: doc.auto_pairs(&editor.config)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I see what you mean, but I don't think we'd want to pass in the editor config, because then we'd be reconstructing a HashMap on every keystroke. And if we put the parsed AutoPairs object in the Document instead, then we'd have a choice between:

  • Each Document would need to have a copy of the parsed AutoPairs, which is recreated from the config on every new Document or
  • Still keep the parsed AutoPairs at the Editor level and have an Rc member in the Document

Neither would be an awful choice, but it seems like a lot just to avoid an array index operation to look up the same Document.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not following, why would we be reconstructing the map? It would be the exact same function, but doc would be the &self receiver, and &editor/&editor.config as the passed in global_config.

Even without the change to the API, the function signature could be pub fn get_document_auto_pairs(&'_ self, doc: &Document) -> Option<&'_ AutoPairs>

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not following, why would we be reconstructing the map? It would be the exact same function, but doc would be the &self receiver, and &editor/&editor.config as the passed in global_config.

Oh, in your earlier comment, you suggested passing in editor.config, but this is just the representation of the config, not the parsed auto pairs. If all we have is the config, then we'd have to get the parsed representation of it somehow, so we'd have to either parse it again or keep a reference to the parsed object, like I mentioned above.

However, I hadn't considered using the whole Editor. I changed it to a method on Document with this approach.

Comment thread helix-view/src/editor.rs
Comment thread helix-view/src/document.rs
Comment thread helix-core/src/syntax.rs Outdated
Comment thread helix-core/src/syntax.rs Outdated
Comment on lines -4512 to -4063
// run through insert hooks, stopping on the first one that returns Some(t)
for hook in hooks {
if let Some(transaction) = hook(text, selection, c) {
doc.apply(&transaction, view.id);
break;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason for the changes here? This was intended to be a point where we could inject additional hooks in the future.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also just realized it's not possible to opt out of auto pairs anymore: before setting auto_pairs = false would disable this entirely, but now language specific settings are always applied even if the global config is none.

@dead10ck dead10ck Feb 8, 2022

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason for the changes here? This was intended to be a point where we could inject additional hooks in the future.

Yeah, because now the auto pairs hook and the insert char hook have different interfaces. I say this with all due respect, but I'm actually not so sure it would have been a good starting point for a chain of hooks anyway. I don't think we can expect every hook imaginable to take a Rope, Selection, and char, nor would we necessarily always want to stop after the first hook is applied successfully. I think if we want a hook system (and that would be a good idea, especially for plugins), then we probably need a very general purpose hook system for any kind of text edit, not just a special hook for typing characters in insert mode.

Edit: But with this said, do you have any suggestions for the handling this incompatibility in a more preferable way?

I also just realized it's not possible to opt out of auto pairs anymore: before setting auto_pairs = false would disable this entirely, but now language specific settings are always applied even if the global config is none.

Hmm, yeah, I was actually thinking about this as a feature—having it be off by default, but only on in certain languages—but thinking about it a bit more, if we are going to have specific language defaults, like one without single quotes for Rust, then it becomes very annoying to turn it off if you don't want it at all. I'll change the logic to special case having the global config value = false to take precedence even over language config.

@dead10ck
dead10ck force-pushed the auto_pairs_config_simple branch from f8ea609 to 05a2b5e Compare February 13, 2022 02:10
@dead10ck

Copy link
Copy Markdown
Member Author

@archseer do you have any other thoughts about my comments?

Comment thread helix-view/src/editor.rs Outdated
Comment thread helix-core/src/auto_pairs.rs
Implements configuration for which pairs of tokens get auto completed.

In order to help with this, the logic for when *not* to auto complete
has been generalized from a specific hardcoded list of characters to
simply testing if the next/prev char is alphanumeric.

It is possible to configure a global list of pairs as well as at the
language level. The language config will take precedence over the
global config.
@dead10ck
dead10ck force-pushed the auto_pairs_config_simple branch from 9a93f83 to 6c335f9 Compare February 22, 2022 15:34
@archseer
archseer merged commit a494f47 into helix-editor:master Feb 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Disable auto-pairing for ' in Rust Enable config for auto-pairs

2 participants