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

Implementing a leap plugin #8197

Open
wants to merge 26 commits into
base: master
Choose a base branch
from
Open

Conversation

cuixiaorui
Copy link

@cuixiaorui cuixiaorui commented Jan 6, 2023

What this PR does / why we need it:

hi @J-Fields

I have implemented a leap functionality plugin in vscodevim

leap is currently a very popular mobile plugin in the neovim community, and it is really efficient. I believe there are many vscodevim users waiting for its arrival #8144

Functional Features

  • s c c -> search down
  • S c c -> Search up
  • s c -> Show cue marker points
  • s <enter> -> Execute the previous search
  • s c <space> -> Search c + \t

You can see how it behaves in vscodevim

show-vscode-leap

Docs

You can read leap documentation for more detailed information

Compare the functional differences between leap.nvim

Because the implementation of vscodevim is different from neovim. So in some functions it is not the same as leap.nvim

  • No automatic jumping to the first marker point
  • Selection of multiple markers
  • No support for using operators together

Does not automatically jump to the first marker point

When matching multiple tag points, it does not automatically jump to the first tag point position.

In leap.nvim you can recognize that when you press a character that is the tag of a marker point then it will automatically jump to the marker point, otherwise it will execute the character as if it was a command in normal mode, but unfortunately this is not possible in vscodevim.

Another problem is that this feature can be confusing. Sometimes it jumps automatically and sometimes it doesn't (for example when there are multiple jump points, or you set the corresponding configuration). So I simply killed this feature in my implementation.

Instead of jumping to the first match point by default, the implementation now requires you to press an s. This s can be modified by the configuration

Of course, if only one marker is matched, then it will automatically jump over

Multiple markers are selected in the following way

In leap.nvim, if there are too many matching tokens, then the selection method is to select the corresponding group by /.The problem with this method is that if three groups are matched, then needs to be pressed twice to select them. (Of course, this is a very extreme case, so you will not encounter it)

In my implementation, I refer to easymotion's jump implementation, which starts with one letter and uses two letters if it goes beyond that, so the advantage is that no matter how many matches are made, the two letters will directly locate the marker point.Of course, another reason is that this implementation is unified with easymotion. Because some mobile scenes use easymotion. So it would be difficult to have two sets of selections. (I believe many users of vscodeVim also use easymotion, so this behavior may be more preferable for them, but I'm not sure... haha... what do you think?)

vim-leap-01

Use with operators is not supported

Unfortunately, this feature is also not supported, again because of the underlying implementation of vscodevim. Currently there is no way to do this

But this feature scenario is not used very often

Can I map other keys if I don't want to use s S?

You can refer to the following configuration

Replace s with f

"vim.normalModeKeyBindingsNonRecursive": [
  {

      "before":[
        "f"
      ],

      "after":[
        "s"
      ]
    },

    {

      "before":[
        "s"
      ],

      "after":[
        "c",
        "l"
      ]
    },
]

How should I experience this feature before this pr merge?

You can install the experience locally based on my code branch

From time to time, I will merge new code from vscodevim into my branch until this pr is merged.

Here's how to do it:

  1. Download my code branch
  2. yarn
  3. yarn package
  4. code --install-extension vim-1.25.2.vsix --force
  5. set vim.leap.enable = true on setting.json

There is another easy way to download my compiled files directly
download vim-1.25.2.vsix

Issues

Conflict of S keys in visualization mode

the s/S in visualization mode contains both characters of the match
But now the problem is that S is used by the surround plugin.
How can I solve this key conflict problem? Does anyone have any good ideas?

Update

Support for using leap in visual mode

Use x / X instead of s / S on visual mode, because s/S is already taken by the surround plugin.

leap111

Support bidirectional search

vim_leap_search

set vim.leap.bidirectionalSearch": true enable the feature

Because I feel a little uncomfortable using ’S’. I need to reflect between ’s’ and ’S’ and ’S’ makes me press an extra ’shift’.
It also supports ’s’ and ’x’ in visual mode

@cuixiaorui cuixiaorui changed the title Feat implementation leap plugin Implementing a leap plugin Jan 6, 2023
@kabouzeid
Copy link

The settings need to be contributed to the package.json such that eg vim.leap=true can be set from the GUI.

@cuixiaorui
Copy link
Author

The settings need to be contributed to the package.json such that eg vim.leap=true can be set from the GUI.

thx your tips, it's fixed now.

Copy link
Contributor

@elazarcoh elazarcoh left a comment

Choose a reason for hiding this comment

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

Hi, I would love to see this PR get merge. Already built you version into my custom VSCodeVim build I'm using for my everyday work.
In the meantime, I made a review.
My main complaint is that you use ! too freely for my taste 🙃

private marker!: Marker;
private textEditorDecorationType: vscode.TextEditorDecorationType;

private static backgroundColors = ['#ccff88', '#99ccff'];
Copy link
Contributor

@elazarcoh elazarcoh Jan 8, 2023

Choose a reason for hiding this comment

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

probably need to be configurable (or theme dependent)

src/actions/plugins/leap/Marker.ts Outdated Show resolved Hide resolved
src/actions/plugins/leap/Marker.ts Outdated Show resolved Hide resolved
Comment on lines 264 to 267
leap = false;
leapShowMarkerPosition = 'after';
leapLabels = 'sklyuiopnm,qwertzxcvbahdgjf;';
leapCaseSensitive = false;
Copy link
Contributor

Choose a reason for hiding this comment

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

probably should be added to IConfiguration as well

Comment on lines 33 to 38
let pattern = '';
if (secondChar === ' ') {
pattern = firstChar + '\\s' + '|' + firstChar + '$';
} else {
pattern = firstChar + secondChar;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
let pattern = '';
if (secondChar === ' ') {
pattern = firstChar + '\\s' + '|' + firstChar + '$';
} else {
pattern = firstChar + secondChar;
}
const pattern =
secondChar === ' '
? `${firstChar}\\s|${firstChar}$'
: `${firstChar}{secondChar}`;

for me, this is clearer. maybe only for me, tough.

Copy link
Author

Choose a reason for hiding this comment

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

haha I forget to refactor this code, Thank you for reminding me

return new RegExp(getPattern(searchString), getFlags());
}

const MATCH_LINE_COUNT = 50;
Copy link
Contributor

Choose a reason for hiding this comment

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

It should be possible to get visible range of the document, instead of hard-coding it.
https://code.visualstudio.com/api/references/vscode-api#TextEditor

Comment on lines 15 to 23
previousMode!: Mode;
isRepeatLastSearch: boolean = false;
direction?: LeapSearchDirection;
leapAction?: LeapAction;
firstSearchString?: string;

constructor(vimState: VimState) {
this.vimState = vimState;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
previousMode!: Mode;
isRepeatLastSearch: boolean = false;
direction?: LeapSearchDirection;
leapAction?: LeapAction;
firstSearchString?: string;
constructor(vimState: VimState) {
this.vimState = vimState;
}
previousMode: Mode;
isRepeatLastSearch: boolean = false;
direction?: LeapSearchDirection;
leapAction?: LeapAction;
firstSearchString?: string;
constructor(vimState: VimState) {
this.vimState = vimState;
this.previousMode = vimState.currentMode;
}

How about this?

src/actions/plugins/leap/LeapAction.ts Show resolved Hide resolved
@kabouzeid
Copy link

in visual mode x and X don't jump to the right character. and s and S are not there at all.

@cuixiaorui
Copy link
Author

@kabouzeid I just found this detail

The x in visualization mode does not contain the match, while the s in visualization mode contains both characters of the match
But now the problem is that S is used by the surround plugin.
How can I solve this key conflict problem? Do you have any good ideas?

@cuixiaorui
Copy link
Author

fixed the bug that in visual mode x and X don't jump to the right character

in visual mode x and X don't jump to the right character. and s and S are not there at all.

@Leiyi548
Copy link

Leiyi548 commented Feb 9, 2023

@cuixiaorui leap.nvim can be set to support two-way search, do you plan to support it later?

@cuixiaorui
Copy link
Author

cuixiaorui commented Feb 10, 2023

@cuixiaorui leap.nvim can be set to support two-way search, do you plan to support it later?

Is there a description document for two-way search? I'll look into it.

@Leiyi548
Copy link

@cuixiaorui
Copy link
Author

@cuixiaorui image more information please see https://github.com/ggandor/leap.nvim#calling-leap-with-custom-arguments

Haha
Interesting feature
Sometimes I really don't like to use S because I have to press one more shift
I will implement this feature when I have time in a few days
I will update the documentation and then

@Leiyi548
Copy link

Yes, sometimes I have to think in my head whether to press shift or not, and it bothers me.

@cuixiaorui
Copy link
Author

cuixiaorui commented Mar 11, 2023

@Leiyi548
vim_leap_search

I finally finished implementing this function yesterday
You can use it to see
If you have problems, just give me feedback!

set vim.leap.bidirectionalSearch": true enable the feature

@Shaker-Pelcro
Copy link

Would love to see this merged.

package.json Outdated
@@ -621,6 +621,31 @@
"markdownDescription": "Enable the [CamelCaseMotion](https://github.com/bkad/CamelCaseMotion) plugin for Vim.",
"default": false
},
"vim.leap": {
Copy link
Member

Choose a reason for hiding this comment

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

Let's make this vim.leap.enabled and change others to vim.leap.showMarkerPosition, for instance

package.json Outdated
@@ -1190,6 +1215,7 @@
"ts-loader": "9.4.2",
"tslint": "6.1.3",
"typescript": "4.9.5",
"vitest": "^0.29.2",
Copy link
Member

Choose a reason for hiding this comment

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

I think this is unintended?

@Leiyi548
Copy link

Leiyi548 commented Apr 6, 2023

@cuixiaorui Can you add the option to uncheck visual mode x leap search, because most of the time I checked x for delete

@cuixiaorui
Copy link
Author

Hi @J-Fields @elazarcoh
thank you very much for taking the time to review Leap's code.
I have just fixed all the issues mentioned above. In addition, I have also updated the following features:

  1. Added the functionality of bidirectional search.
  2. Supported marker background color and font color configuration.
  3. Refactored the way to get Leap (removed it from vimState).

Please feel free to contact me if you have any questions.
I really like vscodeVim and promote it in many places.
I sincerely hope that vscodeVim will become better and better.

@Alan-MQ
Copy link

Alan-MQ commented Apr 7, 2023

I have a suggestion, make the first match always be "j", or have a setting where user can choose what character they want to jumo to the first match point. (you know they did similar stuff in neovim ,in neovim they support command , but that's whole another thing though)
eg: use "Sse" here , "j" will get me to the "use" of this line since in this line we have the first match. am I making myself clear?

@Alan-MQ
Copy link

Alan-MQ commented Apr 7, 2023

I have a suggestion, make the first match always be "j", or have a setting where user can choose what character they want to jumo to the first match point. (you know they did similar stuff in neovim ,in neovim they support command , but that's whole another thing though) eg: use "Sse" here , "j" will get me to the "use" of this line since in this line we have the first match. am I making myself clear?

You know what maybe make the first match the last command character
if the command = "sse" make the firt match jumping character is e, if command = "sid" make the first match jumping character is d. dynamic.

@cuixiaorui
Copy link
Author

cuixiaorui commented Apr 7, 2023

I have a suggestion, make the first match always be "j", or have a setting where user can choose what character they want to jumo to the first match point. (you know they did similar stuff in neovim ,in neovim they support command , but that's whole another thing though) eg: use "Sse" here , "j" will get me to the "use" of this line since in this line we have the first match. am I making myself clear?

You can set vim.leap.labels to modify the default value of "sklyuiopnm,qwertzxcvbahdgjf;", where "s" is the first jumping point.

@rennsax
Copy link

rennsax commented Jun 28, 2023

This PR wasn't merged yet?

@archilkarchava
Copy link

archilkarchava commented Jun 28, 2023

@cuixiaorui, thanks a lot for the plugin implementation.
I found a small issue. When multiple cursors are present and the leap plugin is invoked the extension gets stuck in Leap mode and it's not possible to move the cursor until the file is closed and reopened. The issue is reproducible with multiple cursors both in normal and visual modes.

Screen.Recording.2023-06-28.at.22.48.02.mp4

It's an easy fix, we just need to check for !vimState.isMultiCursor inside the doesActionApply function archilkarchava@2af6856.
In this case, the sneak plugin will be used instead as long as it is enabled.

@archilkarchava
Copy link

@cuixiaorui, the leap action is dot-repeatable, which is not desirable. Here's how we can exclude it from being marked as dot-repeatable archilkarchava@12da1ca.

@archilkarchava
Copy link

archilkarchava commented Jun 29, 2023

@cuixiaorui, also, I've discovered that the <s-Enter> to execute the previous search is disabled in the code for some reason if the vim.leap.bidirectionalSearch enabled.
I've reenabled it in my fork archilkarchava@e0d0f96 and it looks like it's working just fine.

@archilkarchava
Copy link

I've been daily driving this plugin for a couple of days and discovered a significant performance degradation over time when it comes to displaying the markers.
It turns out that calling the this.textEditorDecorationType.dispose is not enough and we can fix it by adding the this.editor.setDecorations(this.textEditorDecorationType, []); call to the dispose method on the marker.
Here's how I've fixed it in my fork archilkarchava@41b444d.

Here's a demo:

Before the fix

vscode-vim-leap-before-the-fix.mp4

After the fix

vscode-vim-after-the-fix.mp4

@cuixiaorui
Copy link
Author

I want to express my sincere gratitude for bringing these issues to my attention. Your feedback has been incredibly useful.

I have addressed and resolved the problems you pointed out. The code has been updated accordingly. I truly appreciate your help in improving the quality of this project.

Please feel free to check the updated code and let me know if you encounter any other issues. Your continued support and feedback are always welcome.

Thank you once again for your valuable contribution. @archilkarchava

@dykwok
Copy link

dykwok commented Aug 8, 2023

@J-Fields is this PR okay to merge?

@clamydo
Copy link

clamydo commented Aug 8, 2023

Love it!

For further reference and inspiration, if required, there is yet another alternative https://github.com/folke/flash.nvim, that also features remote actions, which I find rather ingenious.

Remote actions work like that:

  1. Cursor is at position A
  2. Start remote action: for example for yanking remotely press yr and then leap to a position B
  3. Do a motion, e.g. iw or another leap
  4. Cursor jumps back to A

@cuixiaorui
Copy link
Author

cuixiaorui commented Aug 9, 2023

Love it!

For further reference and inspiration, if required, there is yet another alternative https://github.com/folke/flash.nvim, that also features remote actions, which I find rather ingenious.

Remote actions work like that:

  1. Cursor is at position A
  2. Start remote action: for example for yanking remotely press yr and then leap to a position B
  3. Do a motion, e.g. iw or another leap
  4. Cursor jumps back to A

Soon I will implement flash-like functionality in vscodeVim!
Progress will be synchronized to this issue

@archilkarchava
Copy link

@cuixiaorui, thanks for your kind words. I've been using this plugin ever since and it's been a major improvement to my workflow.
I found another small issue: all matches get a label. This includes cases where a search string has a single match.
These labels only confuse the user since the cursor will jump to the match automatically without pressing a label key.

We can fix the issue by not assigning a label in case a search string only has a single corresponding match: archilkarchava@318fd31.

Before the fix

Screen.Recording.2023-10-07.at.00.08.55.mp4

After the fix

Screen.Recording.2023-10-07.at.00.04.07.mp4

@cooljser
Copy link

cooljser commented Mar 4, 2024

Why this PR not be merged? This is a realy used plugin for vim user.

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.

None yet