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

Support for a Vintage-style "Jump to Matching Bracket" Command #412

Closed
tansongyang opened this issue Apr 16, 2017 · 10 comments
Closed

Support for a Vintage-style "Jump to Matching Bracket" Command #412

tansongyang opened this issue Apr 16, 2017 · 10 comments

Comments

@tansongyang
Copy link

Description

I am trying to implement a Vintage-style move to brackets command. The command jumps between matching brackets. BH has "jump to left" and "jump to right", but not "jump to matching". Essentially, I want "Find Matching Offscreen Bracket", but without the requirement for the match to be offscreen.

After some experimentation, this is what I ended up with:

{
    "keys": ["ctrl+m"],
    "command": "bh_key",
    "args": {
        "lines" : true,
        "plugin": {
            "type": ["__all__"],
            "command": "bh_modules.bracketselect",
            "args": {"select": "right", "alternate": true}
        }
    }
}

In the following descriptions, an underscore before a character indicates that the cursor is on that character. For each pair of lines, the first line indicates the state before running the command, and the second line indicates the state after.

It meets the following requirements.

  1. When the cursor is on a left bracket, it jumps to the right bracket:

     _"foo"
     "foo_"
    
  2. When the cursor is in between a pair of brackets, it jumps to the innermost right bracket.

     ["fo_o"]
     ["foo_"]
    

It does not meet the following requirements.

  1. When the cursor is on a right bracket, it should jump to the left bracket. Instead, it jumps to the character after the left bracket.

     // Expected
     "foo_"
     _"foo"
     // Actual
     "foo_"
     "_foo"
    
  2. It also has the following unexpected behaviors in specific cases.

     // Expected (Two right brackets in a row)
     ["foo"_]
     _["foo"]        
     // Actual
     ["foo"_]
     ["foo_"]
    
     // Expected (Right bracket followed by left bracket)
     [foo]_(bar)
     [foo](bar_)     
     // Actual
     [foo]_(bar)
     [foo_](bar)
    

I'm guessing the root cause of all of these is that the command was not designed to work when the cursor is on characters as opposed to in between characters.

Is it possible to get the behavior I want, and, if so, how?

Of course, thanks for all the hard work on an incredibly helpful plugin.

Support Info

  • ST ver.: 3126
  • Platform: windows
  • Arch: x64
  • Plugin ver.: 2.23.3
  • Install via PC: True
  • mdpopups ver.: 1.13.1
  • backrefs ver.: 1.0.post1
  • markdown ver.: 2.6.6
  • pygments ver.: 2.1a0
  • jinja2 ver.: 2.8
@facelessuser
Copy link
Owner

Add "no_outside_adj": true, to your command to get rid of some of the oddities. But when you understand how BH works they won't seem odd anymore, but maybe you just expect it to work different than it does.

BH always defers to the bracket on the left when given two choices. That allows for consistency. Maybe some matchers defer to the right. Left is what I chose though when I wrote this. I get the impression that you expect it to defer right. Changing the whole match engine's preference (or providing a configurable preference) would be kind of a pain. Not sure if I'm willing to do that.

So, as an example, if you are allowing the cursor to match a bracket when it is on adjacent on the outside (()_), then when presented with [()_] it will match () and not []. Makes sense? By turning off outside adjacent when do the match. [] will be matched instead of ().

@facelessuser
Copy link
Owner

As for controlling where the cursor is placed for a given match, you write your own bh_plugin using the current when to get you started: https://github.com/facelessuser/BracketHighlighter/blob/master/bh_modules/bracketselect.py.

You can drop your personal one in a subdirectory in your user directory and load it instead of the provided one. But preference will still be left unless I overhaul things in the future.

@tansongyang
Copy link
Author

tansongyang commented Apr 17, 2017

Thanks for the quick reply. Setting no_outside_adj gets closer, and your explanation of how BH works is helpful.

It just occurred to me that I may have over complicated my original description. I believe the behavior I'm looking for boils down to getting the "Find Matching Offscreen Bracket" "jump to bracket" link behavior as its own command. That is:

tmp

How feasible is it to get the behavior of the link separated out into its own command? I took a look at bh_popup.py, and it wasn't clear to me how the jumping happens.

@facelessuser
Copy link
Owner

Try block cursor mode as well. Turn off "outside adjacent" and turn on block cursor mode. I forgot that I added this for a vintage user: #275.

// Experimental outside adjancent bracket matching
    "bracket_outside_adjacent": false,

    // EXPERIMENTAL: Special matching mode for block cursor.
    // Essentially, this provides a matching mode that makes a little more
    // sense to some in regards to the visual representation of block cursors.
    // This will override "match_only_adjacet" and "bracket_outside_adjacent".
    "block_cursor_mode": true,

Anyways, I think this "block mode" is more what you are looking for.

@facelessuser
Copy link
Owner

But to position cursor "on" the character when matching, you would need to modify the bh_plugin I pointed you at.

@tansongyang
Copy link
Author

Great, that's exactly it. Thanks for the help! I'll fiddle with a custom plugin and post here if I can get it working.

@facelessuser
Copy link
Owner

As for how the popup works, it just get fed the bracket location and selects it. It's a little different than the bh_plugin bracketselect. But there is no reason you couldn't write your own bracketselect that does the same thing instead of what it currently does.

@tansongyang
Copy link
Author

tansongyang commented Apr 17, 2017

Thanks for all the help. Basically, I removed the parts of bracketselect.py that I didn't need, and I used self.left.end - 1 instead of self.left.end

User\bh_modules\vimovetobracket.py

import BracketHighlighter.bh_plugin as bh_plugin
import sublime


class ViMoveToBracket(bh_plugin.BracketPluginCommand):
    """
    Move to Bracket plugin for Vintage.
    Based on [Select Bracket plugin](https://github.com/facelessuser/BracketHighlighter/blob/master/bh_modules/bracketselect.py).
    """

    def run(self, edit, name):
        """
        Jump to matching bracket
        """

        self.current_left, self.current_right = self.selection[0].begin(), self.selection[0].end()
        first, last = self.left.end, self.right.begin

        first, last = self.select_match(name, first, last)

        self.selection = [sublime.Region(first, last)]


    def select_match(self, name, first, last):
        """Select the matching bracket."""

        if self.left.end != self.right.end:
            first, last = self.right.begin, self.right.begin
            if first == self.current_left and last == self.current_right:
                self.refresh_match = True
                first, last = self.left.end - 1, self.left.end - 1
        else:
            first, last = self.right.end, self.right.end
            if first == self.current_left and last == self.current_right:
                self.refresh_match = True
        return first, last


def plugin():
    """Make plugin available."""

    return ViMoveToBracket

User\Default (Windows).sublime-keymap

{
    "keys": ["ctrl+m"],
    "command": "bh_key",
    "args": {
        "lines" : true,
        "plugin": {
            "type": ["__all__"],
            "command": "User.bh_modules.vimovetobracket"
        }
    }
},

@facelessuser
Copy link
Owner

Maybe in the future I will add a vim like bracket select module by default that people can use if they want to.

Anyways, glad you solved your problem. I'll go ahead and close this for now.

@tansongyang
Copy link
Author

I've added a gist. Any updates I make will go there.

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

No branches or pull requests

2 participants