joshnajera / godot-vim

VIM bindings for godot 4
MIT License
235 stars 24 forks source link

Missing bindings #1

Open claychinasky opened 1 year ago

claychinasky commented 1 year ago

Hello, great addon hope to see this improved with maybe more with c++ source editing, like better cursor visuals (faster blinks or solid block cursor etc.)

I think most of the binding there but w is missing, its the most important one I think. Secondly when cursor at middle of a word, if you do dw, it deletes the whole word, so its doing diw, where it is the most useful, to delete half of the word. Third one is probably easy too, D should delete everything after the cursor.

I tried to implement the first one, it is working I think, have no idea what I'm doing but here it is:

func move_to_next_word():
    var current_text = code_editor.get_line(curr_line())
    var i = curr_column()
    while i < len(current_text) - 1:
        i+= 1
        if current_text[i] in [' ',':','(',')','.',',']:
            break
        move_column_relative(1)
    move_column_relative(2)
    if i == len(current_text):
        move_line_relative(1)
        code_editor.set_caret_column(1)
    update_selection()  

It's not fully functioning as it should, when cursor at end of the line and the end character is listed in that if statement, you have to press 2 times w to go next word, and if next line's first character is tab, it select the tab instead of the word.

joshnajera commented 1 year ago

Hey thanks! Woo, It's super exciting to see someone interacting with the repo!! lol I've been thinking about trying to do it with GDExtension, we'll see how it goes though...

Ooooh, ok! I got started with the changes (quickly implemented D (shift+d) on my machine). I I'll look into correcting dw and implementing w better, and push out an update when I can. Thanks for the input! :)

claychinasky commented 1 year ago

Nice, I like to help also where I can, and I see some settings in godot editor for caret related values btw, you might wanna check that out, I will look into more at the source code.

Another thing I might add, when you do dw, if its in middle of the word, cursor should stay at same position but if the cursor at the beginning of the word after dw it should call w again to set cursor for the next word beginning. so in theory, you can spam dw per word one by one and delete them.

joshnajera commented 1 year ago

I saw something regarding the carets.... but I've only seen empty block style and vertical line style, but I will look again.

Also, I just pushed an update to github; fixing dw, adding w and Shift+d, found a problem with the b command, fixed that too!

Please try it out and let me know if you see any problems! I'll probably push a new version to the godot asset lib after I get a few more tweaks in.

claychinasky commented 1 year ago

Found a few issues: w is skipping the first word when it moves line +1 sometimes (most of the time) and also skips ready() where it should break on , like skipping func keyword on next line.

For example when w on this line, it should catch v a : A = [ a b c d ... ] and not the ' or ,

var alphanumeric : Array = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']

w on this line, it should break on v b : A = [ : ; ( ) [ ] , . ? (in theory, w shouldn't catch any symbol but if its in ' it is valued as a string) etc. cause those are the words inside the ' I think this is the where regex must be used in or more LSP helper or c++ parser, not sure how to solve this. but I think it could be assumed to break on every char AFTER the ' or " cause those are high chance are string values and words. But if you do that it will also break on closing ' or " which is mostly whitespace or ,, so if its whitespace or ,it should call w again on white space so it will jump to next word.

var breakers : Array = [':','(',')','[',']','.',',','?','+','=','-','$','%','\'','"']

I will test this more, maybe using regex is the key to move forward, so in theory you could create a long regex to catch wordson whole line, so it can parse a word between quotes fast and reliable. or to simplify, if you do regex.compile("\w+") it will catch every alphabet character and digits but not any other symbols. (in short all words) and if you want to also include _, regex.compile("\w+|_") or more characters.

But more string calculation added, it will get slower, however regex is known to be really fast so. I know this exists https://github.com/onivim/libvim but it's far too complicated to look at and I'm not good at low level languages. I know this implementation can never be good as native vim, but I think it also really nice to have if it gets to a point where its good enough to use. I'm using chatGPT to create complicated regex'es and online tools to test the regex'es, so you might as well, really cool tools.

joshnajera commented 1 year ago

Thanks for the follow up! Yeah, it seems there was a bug with wrapping when nonwhitespace was on first column of a line... I think it should now be fixed for w,b,e,W,B,E functions. Additionally, it should no longer completely skip underscore prefixed things.

However regarding which specific characters they stop on ( ' and , ) I am confused about, as when I'm in vim or nvim, it breaks on all punctuations... I'm wary to stray from the original bindings.

The move to regex sounds like a good idea, I'll let the ideas for implementing it marinate in my mind, lol.

As for your original post

...like better cursor visuals (faster blinks or solid block cursor etc.)...

So I just learned that it is possible to change the blink speed, and thickness of the vertical caret, so now it is possible to do more with it. Also it is possible to set the caret color, but I don't know if that's too "extra".... lol

Thanks for your input so far 🙏🙏

claychinasky commented 1 year ago

yeah you are right about ' and ,, I think I'm used to use code specific custom configs and forgot about vanilla implementation, it's better to stick with original implementation I think. According to documentation (don't think this is from official docs tho just found it searching for iskeyword settings):

                            word
A word consists of a sequence of letters, digits and underscores, or a
sequence of other non-blank characters, separated with white space (spaces,
tabs, <EOL>).  This can be changed with the ['iskeyword'](http://neovim.io/doc/user/options.html#'iskeyword') option.  An empty line
is also considered to be a word.
                            WORD
A WORD consists of a sequence of non-blank characters, separated with white
space.  An empty line is also considered to be a WORD.
A sequence of folded lines is counted for one word of a single character.
"w" and "W", "e" and "E" move to the start/end of the first word or WORD after
a range of folded lines.  "b" and "B" move to the start of the first word or
WORD before the fold.
Special case: "cw" and "cW" are treated like "ce" and "cE" if the cursor is
on a non-blank.  This is Vi-compatible, see [cpo-_](http://neovim.io/doc/user/options.html#cpo-_) to change the behavior.
Another special case: When using the "w" motion in combination with an
operator and the last word moved over is at the end of a line, the end of
that word becomes the end of the operated text, not the first word in the
next line.
The original Vi implementation of "e" is buggy.  For example, the "e" command
will stop on the first character of a line if the previous line was empty.
But when you use "2e" this does not happen.  In Vim "ee" and "2e" are the
same, which is more logical.  However, this causes a small incompatibility
between Vi and Vim.

The original implementation is created for creating text based documents I believe, then it's evolved more into technical modal editing. So any non-blank character is considered a word. I updated the addon but it's still not breaking on _ prefix, and also same goes for ! : * etc. I think rewriting in regex with clear these things up better.

joshnajera commented 1 year ago

I naively was guessing which special characters were included.... I shoulda just read the docs >.<;;;

Had ChatGPT generated another list of all the special characters in single quotes, comma separated. lol Added in de

Regarding the _ Could it be that you updated the plugin while godot was still running? If it was, you will need to either reload the plugin under project settings, or restart godot.

I'll be looking into regex solutions

claychinasky commented 1 year ago

Yup, after the restart it worked as should. I think for now it's looking good, but yet to use it in serious manner but will do a list of findings properly. And there is an addon called plugin refresher (4.x), you might want to install that also. Thanks for the updates, cheers.

claychinasky commented 1 year ago

after playing with it a bit, these are my findings:

data-flux commented 1 year ago

I don't mean to be a negative nancy, and I appreciate the work you've already put into this plugin, but I think a major rewrite is in order, rather sooner than later, to make supporting more keybindings less painful in the future.

Specifically, you probably want to decouple commands from motions.

To prevent having to implement dw, diw, d2w, all seperately, using the d command should wait for the next motion, and after a motion has been entered perform its function. Implementing the motions separately means the same motion will work for movement, deletion, yanking, etc.

Unfortunately, there are also exceptions to this: yy and dd do not follow the \<command>\<motion> paradigm exactly, so y should only be a motion for the yank command, and d only for the delete command.

 

I'm still very new to gdscript, so I can't help much, but I'm willing to help test your plugin :)