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

Implemented EasyMotion plugin functionality #993

Merged
merged 24 commits into from
Nov 1, 2016

Conversation

AlexanderArvidsson
Copy link
Contributor

@AlexanderArvidsson AlexanderArvidsson commented Oct 26, 2016

Yay! We love PRs! 🎊

Please include a description of your change and ensure:

  • Commit message has a short title & issue references
  • Each commit does a logical chunk of work.
  • It builds and tests pass (e.g gulp)

More info can be found on our contribution guide.

This implements the common motions found in the EasyMotion vim plugin, which is s, w, e, b. More to come later.
Now also supports the motions t, T, f, F.



// Only register the EasyMotion actions if the configuration is set
if (Configuration.getInstance().easymotion) {
Copy link
Member

Choose a reason for hiding this comment

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

Instead of this can you check for the configuration inside the exec() function that switches to the EasyMotion mode?

return match.position;
}

public processMarkers(matches: EasyMotion.Match[], position: Position, vimState: VimState) {
Copy link
Member

Choose a reason for hiding this comment

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

Can you put the call to clearMarkers() inside this function?

Also, can you rename this function to recreateAllMarkers? Or something that indicates a little better what's going on?

I actually think this entire function might want to be located on the easyMotion object on VimState instead. It seems more associated with that object than BaseEasyMotionCommand.

Copy link
Contributor Author

@AlexanderArvidsson AlexanderArvidsson Oct 27, 2016

Choose a reason for hiding this comment

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

You're right about it belonging in EasyMotion object, but then I would have to pass in the getMatchPosition as a callback in order to map the matches differently on each action (e, T, t have different match mappings). Do you think this should be preferred?

this.processMarkers(matches, position, vimState);

// Let EasyMotion update all decorations
vimState.easyMotion.updateDecorations(position);
Copy link
Member

Choose a reason for hiding this comment

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

This should be called from our updateView function in ModeHandler.

Copy link
Member

Choose a reason for hiding this comment

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

(That's where we do all our view changing stuff.)


// Only register the EasyMotion actions if the configuration is set
if (Configuration.getInstance().easymotion) {
class BaseEasyMotionCommand extends BaseCommand {
Copy link
Member

Choose a reason for hiding this comment

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

Could this class be made abstract?

/**
* Search and sort using the index of a match compared to the index of position (usually the cursor)
*/
public sortedSearch(position: Position, searchString = "", options: EasyMotion.SearchOptions = {}): EasyMotion.Match[] {
Copy link
Member

Choose a reason for hiding this comment

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

Instead of passing in isRegex: true, simply make the type of searchString string | RegExp. Then you can do if (typeof searchString === "string") and TypeScript is intelligent enough to infer that within the curly braces of that if, searchString is now a string (similarly with the RegExp).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea, I was following the StateSearch method. This suggestion applies to StateSearch as well!

}

@RegisterAction
class CommandEscEasyMotionMode extends BaseCommand {
Copy link
Member

Choose a reason for hiding this comment

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

Can you consolidate this with our normal CommandEsc stuff? Just be like if (vimState.currentMode === ModeName.EasyMotionMode) and then do the custom handling you have here.

Copy link
Member

Choose a reason for hiding this comment

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

I actually disagree

Originally I was going to make the same comment, however I then thought this was more modular if/when he moves it to its own file

Why do we have a Replace vs VisualReplace sort of thing, behavior is different so its a different action

return position;
}

// "nail" refers to the accumulated depth keys
Copy link
Member

Choose a reason for hiding this comment

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

Why is it called nail? :P

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I honestly have no idea, I couldn't find a decent word to describe what it does, which is why I am referring to it as "accumulated depth keys". Got a better name? :)

public exitMode() {
this._vimState.currentMode = ModeName.Normal;

this.accumulation = "";
Copy link
Member

Choose a reason for hiding this comment

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

Instead of doing this (which requires you to remember to add new properties here as well), you can just do something like vimState.easyMotionObject = new EasyMotion()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Vimstate already has vimstate.easymotion = new EasyMotion(vimstate)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Recreating the whole object instead of individual variables just puts unnecessary load on the garbage collector. Any particular reason you want it this way instead?

Copy link
Member

Choose a reason for hiding this comment

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

Yes. Until we have actual profiling data that show that memory consumption or gc cycles are issues, we shouldn't worry at all about performance. Code quality is much more important.

My concern with the way we're doing here is that every time you add another property to the EasyMotion object, you also have to remember to clear it out in exitMode(). This is an easy way to end up adding bugs when someone comes back to modify this class months down the line.

I follow this pattern in ModeHandler with RecordedState - look for the multiple instances of new RecordedState() - because I got bitten by similar bugs. :)

@johnfn
Copy link
Member

johnfn commented Oct 27, 2016

Pretty amazing stuff. It's awesome that you did this!

BEST VIM PLUGIN EVER!!!

@kidproquo
Copy link

Awesome! This is a really cool plugin. Thanks for doing this!

@johnfn
Copy link
Member

johnfn commented Oct 28, 2016

Also, I don't have any problem with defaulting easymotion to on. :)

@johnfn
Copy link
Member

johnfn commented Nov 1, 2016

Thanks for the amazing work, @Metamist!

@johnfn johnfn merged commit 19deb1e into VSCodeVim:master Nov 1, 2016
var uri = vscode.Uri.parse(
`data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ` +
`13" height="14" width="${width}"><rect width="${width}" height="14" rx="2" ry="2" ` +
`style="fill: ${backgroundColor};"></rect><text font-family="Consolas" font-size="14px" ` +

Choose a reason for hiding this comment

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

This shows a serif font in the editor in EasyMotion mode on Ubuntu.

Choose a reason for hiding this comment

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

Consolas font isn't installed on my macbook either. Why not just lookup the font-family being used in the user-settings?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dsifford, Good point, this was the first time I had ever touched anything regarding extensions for VSCode, so I didn't know I could look it up. If someone who has more experience regarding this can fix it that would be great!

Copy link

@dsifford dsifford Jan 23, 2017

Choose a reason for hiding this comment

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

@Metamist Not even totally sure my suggestion is possible. I'm a "converted-atom-user-in-progress" so I have very little experience on the ins and outs of VSCode for now.

That said, an even easier solution for now would be to just give a bunch of fallback font options ending with monospace.

So, for example, font-family: Consolas, Monaco, 'Courier New', monospace; might work in a wider range of machines.

@casprwang
Copy link

casprwang commented Nov 21, 2016

Do we have a shortcut for this motion? I've tried 'ctrl+alt+\', but It doesn't work.

@hastebrot
Copy link

hastebrot commented Nov 21, 2016

@wangsongiam \ \ s (backslash then backslash then s-key) and then the character to search, worked for me.

settings.json:

{
    "vim.easymotion": true
}

@AlexanderArvidsson
Copy link
Contributor Author

AlexanderArvidsson commented Nov 21, 2016

@wangsongiam, you can use most basic motions with EasyMotion, such as s, e, w, b, ge, f, F, t, F, with s being the most useful one IMO. All these motions are prefixed with \\.

@casprwang
Copy link

casprwang commented Nov 21, 2016

@Metamist worked, thanks! but can I change the prefix \\ to something else? Also, It would be helpful if we make other link hint styles(as black and red are not very recognizable for some light themes), or we can configure the hint style in css like vimium.

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.

7 participants