Skip to content

vim: Add use_match_quotes setting for % motion, default is true#42615

Merged
dinocosta merged 17 commits intozed-industries:mainfrom
Kalmaegi:add_use_match_quotes_setting_for_vim
Jan 9, 2026
Merged

vim: Add use_match_quotes setting for % motion, default is true#42615
dinocosta merged 17 commits intozed-industries:mainfrom
Kalmaegi:add_use_match_quotes_setting_for_vim

Conversation

@Kalmaegi
Copy link
Contributor

@Kalmaegi Kalmaegi commented Nov 13, 2025

Add a new Vim setting use_match_quotes that controls whether the % motion should treat quotes (`', ", `)
as matching pairs.
In Vim, % only matches pairs of ([{}]) — doesn’t consider quotes, to avoid breaking existing behavior in Zed, this new setting defaults to true, but users who prefer Vim’s original behavior can now disable it by setting:
"use_match_quotes": false

While implementing this, I noticed there’s an existing helper:

fn is_bracket_delimiter(buffer: &BufferSnapshot, start: usize, _end: usize) -> bool {
matches!(
buffer.chars_at(start).next(),
Some('(' | '[' | '{' | '<' | '|')
)
}

I'm wondering if it might be cleaner to expose a small wrapper or helper here, so we can reuse the same quote detection logic instead of duplicating it.

If this overall approach looks good, I’ll proceed to add unit tests.

Release Notes:

  • vim: Added match_quotes parameter to the vim::Matching action to control whether % matches quote characters

@cla-bot cla-bot bot added the cla-signed The user has signed the Contributor License Agreement label Nov 13, 2025
@dinocosta
Copy link
Member

Thank you for opening this Pull Request @Kalmaegi ! Will think a little bit more about this and try to take a look in the coming days, will keep you posted 🙂

@dinocosta
Copy link
Member

dinocosta commented Dec 3, 2025

Hey @Kalmaegi 👋

Thank you for opening this and sorry that it took me a while to get back to you, was checking with the team whether we'd like to introduce this, but Conrad told me he already chatted with you on Discord about it. Approach looks good to me, will see if we can simply the make_range_filter closure a little bit, seems to be getting a bit complicated 🤔

In the meantime, would you be able to:

  • Rebase this with main
    Seems there's conflicts in crates/vim/src/motion.rs
  • Write a test to confirm that Matching { match_quotes: false } behaves differently from Matching { match_quotes: true}
    Let me know if you need help with this one, I can also try adding it myself

Thanks!

P.S.: Regarding the helper function you shared, vim::object::is_bracket_delimiter, it seems there's also vim::object::is_quote_delimiter already, so we can probably leverage one of, if not both, functions 🙂

@Kalmaegi
Copy link
Contributor Author

Kalmaegi commented Dec 3, 2025

Hey @Kalmaegi 👋

Thank you for opening this and sorry that it took me a while to get back to you, was checking with the team whether we'd like to introduce this, but Conrad told me he already chatted with you on Discord about it. Approach looks good to me, will see if we can simply the make_range_filter closure a little bit, seems to be getting a bit complicated 🤔

In the meantime, would you be able to:

  • Rebase this with main
    Seems there's conflicts in crates/vim/src/motion.rs
  • Write a test to confirm that Matching { match_quotes: false } behaves differently from Matching { match_quotes: true}
    Let me know if you need help with this one, I can also try adding it myself

Thanks!

P.S.: Regarding the helper function you shared, vim::object::is_bracket_delimiter, it seems there's also vim::object::is_quote_delimiter already, so we can probably leverage one of, if not both, functions 🙂

Sure! Sorry for the lack of updates lately. I’ll fetch on main, resolve the conflicts, and add the test for the match_quotes behavior. I’ll also clean up the code a bit while I’m at it.

…s_setting_for_vim

# Conflicts:
#	crates/vim/src/motion.rs
@Kalmaegi Kalmaegi marked this pull request as draft December 4, 2025 12:18
@Kalmaegi Kalmaegi marked this pull request as ready for review December 7, 2025 11:12
@Kalmaegi
Copy link
Contributor Author

Kalmaegi commented Dec 7, 2025

Hi @dinocosta
I’ve added some test cases and I also tested the tag support, and luckily everything still works fine — nothing got affected.
Regarding the new setting: use_match_quotes initially, I wanted to handle it directly inside the matching method, since that would make the logic a bit cleaner. But I realized that matching doesn’t have access to the necessary context for the VimSettings, so I had to move that logic up one level instead.
Hopefully this change is alright — fingers crossed XD

- Update the documentation for
  `settings::settings_content::VimSettingsContent.use_match_quotes` in
  order for it to be shown in the documentation modal when user is
  editing their settings.
- Update the documentation for `vim.use_match_quotes` in
  `assets/settings/default.json`.
- Small refactoring of `vim::motion::matching` in order to leverage
  `Option<T>.is_some_and` and prefer use of `char` instead of
  `Option<char>` in closure.
@dinocosta
Copy link
Member

Thank you @Kalmaegi ! I've pushed two more commits, one to just bring this branch up to date with main and another one with a very tiny refactor and adding documentation so that we get documentation on this setting when the user is updating their settings file :)

Hi @dinocosta I’ve added some test cases and I also tested the tag support, and luckily everything still works fine — nothing got affected. Regarding the new setting: use_match_quotes initially, I wanted to handle it directly inside the matching method, since that would make the logic a bit cleaner. But I realized that matching doesn’t have access to the necessary context for the VimSettings, so I had to move that logic up one level instead. Hopefully this change is alright — fingers crossed XD

Honestly, I believe it's possible to just have it in the Matching motion, you already added the match_quotes field there, I believe the only thing we'd need to do is:

  1. Update the Matching action with the same match_quotes field
  2. Update the default vim keymap (assets/keymaps/vim.json) to use ["vim::Matching", { "match_quotes": true }]
  3. Possibly update Zed's Vim Mode documentation to mention that % can behave like Vim by simply updating the keymap, removing the match_quotes parameter

Let me know what you think! No rush on this one, so we can also explore that option.

@Kalmaegi
Copy link
Contributor Author

Thank you @Kalmaegi ! I've pushed two more commits, one to just bring this branch up to date with main and another one with a very tiny refactor and adding documentation so that we get documentation on this setting when the user is updating their settings file :)

Hi @dinocosta I’ve added some test cases and I also tested the tag support, and luckily everything still works fine — nothing got affected. Regarding the new setting: use_match_quotes initially, I wanted to handle it directly inside the matching method, since that would make the logic a bit cleaner. But I realized that matching doesn’t have access to the necessary context for the VimSettings, so I had to move that logic up one level instead. Hopefully this change is alright — fingers crossed XD

Honestly, I believe it's possible to just have it in the Matching motion, you already added the match_quotes field there, I believe the only thing we'd need to do is:

  1. Update the Matching action with the same match_quotes field
  2. Update the default vim keymap (assets/keymaps/vim.json) to use ["vim::Matching", { "match_quotes": true }]
  3. Possibly update Zed's Vim Mode documentation to mention that % can behave like Vim by simply updating the keymap, removing the match_quotes parameter

Let me know what you think! No rush on this one, so we can also explore that option.

Sorry i'm late, I didn't think of that approach! That makes a lot more sense.

Just to confirm my understanding: with this approach, users only need to override the default
parameter in their keymap to achieve the same effect, right? They wouldn't need a separate
global setting at all.

I really like this solution! If my understanding is correct, I'll refactor the code
accordingly. Thanks for the great suggestion!

@dinocosta
Copy link
Member

Just to confirm my understanding: with this approach, users only need to override the default
parameter in their keymap to achieve the same effect, right? They wouldn't need a separate
global setting at all.

Exactly. One could even have different bindings for both behaviors, as it would simply be a parameter in the dispatched action 🙂

Let me know if you need help with it, we can also schedule some pairing time if needed!

@Kalmaegi Kalmaegi marked this pull request as draft January 6, 2026 12:05
@Kalmaegi
Copy link
Contributor Author

Kalmaegi commented Jan 6, 2026

I can’t run the Rust project on my macbook right now, but I’ll update and submit a fix as soon as possible.

@Kalmaegi Kalmaegi marked this pull request as ready for review January 8, 2026 12:14
@Kalmaegi
Copy link
Contributor Author

Kalmaegi commented Jan 8, 2026

I’ve tweaked the code and tested it, hope everything works as expected.

Copy link
Member

@dinocosta dinocosta left a comment

Choose a reason for hiding this comment

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

@Kalmaegi Thank you for taking the time to update these changes and including these tests, appreciate it! 🙇

I've pushed a commit adding some documentation to the match_quotes field, as well as also including "match_quotes": true in the Helix keymap, so that it continues working as Zed's defaults after this is merged. Thanks! ✌️

@dinocosta dinocosta merged commit 1062e2c into zed-industries:main Jan 9, 2026
24 checks passed
@github-project-automation github-project-automation bot moved this from Community PRs to Done in Quality Week – December 2025 Jan 9, 2026
@Kalmaegi
Copy link
Contributor Author

@Kalmaegi Thank you for taking the time to update these changes and including these tests, appreciate it! 🙇

I've pushed a commit adding some documentation to the match_quotes field, as well as also including "match_quotes": true in the Helix keymap, so that it continues working as Zed's defaults after this is merged. Thanks! ✌️

thanks, I forgot Helix mode XD

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed The user has signed the Contributor License Agreement

Projects

Development

Successfully merging this pull request may close these issues.

2 participants