Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configurable "jump to bracket" mcharacters/words (based on indentation, do/end, etc.) #176694

Closed
Nezteb opened this issue Mar 9, 2023 · 5 comments
Assignees

Comments

@Nezteb
Copy link

Nezteb commented Mar 9, 2023

Previous Issue(s)

A similar issue was made in 2017 but closed because it wasn't put on the roadmap: #32085

I figured I'd bring the issue back up; a lot can happen in six years. 😉

Related Feature

VS Code supports jump to bracket: https://code.visualstudio.com/docs/editor/editingevolved#_bracket-matching

This will jump the user's cursor between pairs of symbols like [/], {/},(/), etc.

The bracket matching looks like it's handled in https://github.com/microsoft/vscode/blob/main/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts, but I don't see where the list of "brackets" is stored.

New Feature

One thing I've always wanted in VS Code is a "jump to block" function that lets you jump to the start and end of a block based off of its indentation level.

Another similar/alternative feature would be to be able to configure what characters/words can be jumped to. For example, several languages use the do and end keywords to denote blocks of code.

There's a popular extension called metaGo that can do similar things, so I also created an issue there just in case the VS Code team isn't willing to consider this feature: metaseed/metaGo#113

@RedCMD
Copy link
Contributor

RedCMD commented Mar 9, 2023

but I don't see where the list of "brackets" is stored.

the list is stored inside language-configuration.json in each language extension

@Nezteb
Copy link
Author

Nezteb commented Mar 9, 2023

the list is stored inside language-configuration.json in each language extension

@RedCMD ahh thank you!

It looks like none of the built-in languages have any keywords in their "brackets" list: https://github.com/search?q=repo%3Amicrosoft%2Fvscode+path%3Alanguage-configuration.json+brackets&type=code

I found that the Ruby extension adds Ruby's various block start/end keywords though: https://github.com/rubyide/vscode-ruby/blob/main/packages/vscode-ruby/language-configuration-ruby.json

In my case, I wanted this originally for Elixir. I assume it'd be as easy as a PR to https://github.com/elixir-lsp/vscode-elixir-ls/blob/master/elixir-language-configuration.json to add those keywords? 🤔

In any case, it'd be nice for this configurable by the user directly instead of up to the individual extensions. 😅

@RedCMD
Copy link
Contributor

RedCMD commented Mar 10, 2023

It looks like none of the built-in languages have any keywords in their "brackets" list

idk how github search works, but every extension does have their defined brackets

"brackets": [
["{", "}"],
["[", "]"],
["(", ")"]
],

it is quite easy to define keywords if, end etc as brackets
problem is else wouldn't be supported
and the language textmate syntax would also have to support the keywords in the form of disabling the bracket keywords when they aren't a bracket
in the form of "unbalancedBracketScopes" under "grammars" in package.json

I found that the Ruby extension adds Ruby's various block start/end keywords though

yes. just like how Ruby has done it
Ruby is a builtin extension as well. but just doesn't have any keywords defined as brackets

In any case, it'd be nice for this configurable by the user directly instead of up to the individual extensions.

you can config it in settings

"[ruby]": {
	"editor.language.colorizedBracketPairs": [
		["{", "}"],
		["[", "]"],
		["(", ")"],
		["begin","end"],
		["def","end"],
		["if","end"],
		["case","end"],
		["unless","end"],
		["do","end"],
		["class","end"],
		["module","end"]
	]
}

tho you are up to the mercy of how the textmate syntax handles its bracket tokens

@Nezteb
Copy link
Author

Nezteb commented Mar 10, 2023

Okay, I figured out something that partially works. editor.language.colorizedBracketPairs obviously only controlled colorization but your suggestion made me realize I could also just use editor.language.brackets!

Here is a video demo: https://www.dropbox.com/s/u6m68bd6xclzqy9/vscode-elixir-brackets-demo.mov

So far this is what I have:

"[elixir]": {
    "editor.language.brackets": [
        ["{", "}"],
        ["[", "]"],
        ["(", ")"],
        // ["do","end"], // weird behavior with this one
        ["begin","end"],
        ["def","end"],
        ["defp","end"],
        ["if","end"],
        ["case","end"],
        ["cond","end"],
        ["unless","end"],
        ["defmodule","end"],
        ["defmacro","end"],
        ["quote","end"],
        ["with","end"],
    ]
}

However, there are some Elixir-specific quirks because both of these are valid:

def some_func() do
	true
end
def some_func(), do: true

I'll keep playing with it, but I imagine that I won't be able to define multiple matching pairs like:

["def","end"],
["def","do:"],

Because I imagine they'll conflict somehow.

For now I'll close this issue, but if I get a fully working config for Elixir I'll post again just in case other people are interested. :D

@Nezteb Nezteb closed this as completed Mar 10, 2023
@Nezteb
Copy link
Author

Nezteb commented Mar 10, 2023

It turns out that multiple matching pairs with the same starting bracket works!

Here's what I've landed on so far:

"[elixir]": {
    "editor.language.brackets": [
        ["{", "}"],
        ["[", "]"],
        ["(", ")"],
        ["fn","end"],
        // ["do:", "\n"], // Need this or it will conflict with the full do blocks
        // ["do","end"], // Weird behavior with this one in combination with the ones below
        // The above three pairs alone will get you pretty far!
        ["def","do:"],
        ["def","end"],
        ["defp","do:"],
        ["defp","end"],
        ["with","end"],
        ["try","end"],
        ["if","end"],
        ["if","do:"],
        ["unless","end"],
        ["unless","do:"],
        ["for","end"],
        ["for","do:"],
        ["receive","end"],
        ["case","end"],
        ["cond","end"],
        ["defprotocol", "end"],
        ["defdelegate", "to:"],
        ["defmodule","end"],
        ["defmacro","end"],
        ["defmacrop","end"],
        ["quote","end"],
        ["quote","do:"],
        // The hard part is that you need to define any custom macro as a bracket
        ["setup","end"],
        ["describe","end"],
        ["test","end"],
    ]
}

This works for 95% (a subjective made up percentage of course) of cases that I've tried using the official https://github.com/elixir-lang/elixir repo as a test.

Things that don't work so far

This has made me realize just how interesting Elixir's parsing and syntax is. 😄

It might just be simpler to stick with:

"[elixir]": {
    "editor.language.brackets": [
        ["{", "}"],
        ["[", "]"],
        ["(", ")"],
        ["fn","end"],
        ["do:", "\n"], // Need this or it will conflict with the full do blocks
        ["do","end"],
    ]
}

@github-actions github-actions bot locked and limited conversation to collaborators Apr 24, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants