[vim keymap] Visual mode rewrite and other changes #8420
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "github/fork/metatheos/master"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
My second batch of changes, containing the remaining additions from my local setup. Should also fix some problems discussed in Issue #1246.
Changes
moveByLinesToFirstNonWhiteSpaceCharacter, used to implement the motions+(move{repeat}lines down, then to the first non-whitespace-character on that line),-(same for up) and_(same as+but with repeat reduced by 1, so with a repeat of 1 it behaves like^).Enter,SpaceorDown) would pass it on as string (see Issue #1246). These keys are now converted to a printable character if possible and rejected otherwise.r{character}replaces all individual characters in the selection by{character}, while leaving linebreaks intact. Special case as by vim help is\nas{character}, which creates only one linebreak for anroperation.DIY-Example: Inputting
ggOTitle<Esc>yypVr=(with<Esc>being the escape-key) should now behave just as it does in vim.Notes on moveByLinesToFirstNonWhiteSpaceCharacter
I'm on the fence about whether to keep
moveByLinesToFirstNonWhiteSpaceCharacteror merge it withmoveToFirstNonWhiteSpaceCharacter. Merging means there would be one less motion, but instead one with anifat the start picking between the two code paths. I also find the name to be obscenely long.@mightyguavawhat would you prefer here?Notes on visual mode (selection)
Vim's cursor is not between characters but on one. This also has implications on the selection model. For the beginning of the selection the left side of the cursor is used, while for the end it is the right side. This requires
sel.toto be incremented by 1 from the position CodeMirror'ssetSelectionwould place it at. Even more of a special case is linewise selection. Heresel.fromis moved to the first character of the line, whilesel.tois moved behind the last one.CodeMirror as it is doesn't seem to require
sel.fromandsel.toto be eithersel.anchororsel.head. I'm not sure if I should expect this special case to be stable and especially whether I really want you to maintain this rather exotic use-case. I am replicatingsetSelection's behavior for now in an own function (vim.js:1511) and adapt the values at the end. From my testing it seemed to work out quite well. Obviously it cannot deal with folding yet, since I cannot accessskipAtomicfrom my code (a hacky workaround would be callingsetCursor(curEnd)or something similar before the custom operation). The only other problem I ran into is how CodeMirror restores selection on undo, which is a separate issue I'll look into as well. Also of course replicating internal code is really bad, I'll try to think of a way that doesn't need much change to the API but still allows me to get the core-code out of mysetSelection.I made one change to
codemirror.css. The reason is that settingshowCursorWhenSelectingdoesn't help if the cursor is covered by the selection (selection hasz-indexset to 1).Great!
@mightyguavaI'd like you to glance over this again (if you don't have time for these reviews, let me know, I'll stop notifying you.)Sorry for the delay. I was away for the long weekend. The new visual mode looks vastly superior to the previous version. Thanks!
If you want to merge
moveByLinesToFirstNonWhiteSpaceCharacter, I suggest merging withmoveByLinesinstead, and add an additional argument for which character the cursor lands on the line. It would also make a bit more structural sense and probably less duplication.Regarding the custom selection function. I strongly agree that that changing CodeMirror's internal state here is bad. A rule I followed implementing
vim.jswas to not change CodeMirror's internal state in any way. This made some parts of the logic a bit convoluted, but letvim.jsbe much more future proof. As you said, a better solution would be to refactor CodeMirror's selection API a bit to make it work for thevimuse case. Maybe changingsetSelectionto accept aselobject withanchor,head,from, andto? Defer to@marijnhhere.Now I feel stupid. I'll do just that. Any idea how I could improve the handling of 0-based repeat on
_, while I'm at it? I don't like how I introducemotionArgs.repeatOffsetjust for that.Also: would you mind if I rename
textObjectManipulationtotextObjectRangeand invert itsinclusive-parameter, renaming it toinner? I found these names rather confusing as they are.As for the detection for mouse interaction, I've restored that for now, but I hope I can take a stab at solving #1084 the way
@marijnhsuggests soon. This might result in some tools to handle various mouse-related issues and also help with solving #1038.Sorry, don't have a better idea. I find
_weird by itself, and don't see how you could not special case it.Sure. The text object manipulation motion is a bad hack I threw in to carry over the functionality from the original
vim.jsimplementation. Any changes to clean it up is fine by me.Sounds great. I didn't do it earlier because the fix would be v3 specific and somewhat involved. At this point, keeping
vim.jsv2 compatible is moot.I just looked through it while trying to improve
cw, which led me to looking intoawandiw. At first "Manipulation" confused me a bit, I think "Limits" gives a better idea what it is there for. Alsoinclusivehas a special meaning in vim that is -- as far as I can tell -- unrelated to the use there, soinnermight be more descriptive. I had a patch to improveawandiwbut just noticed that it still needs some tweaks to behavior around the end of lines. The actual fix forcwseems to be even more tricky.I merged the two motions, and added two small fixes in another patch. One was an oversight by me (
gjandgkare not considered linewise in vim) and the other one wastwalking back if there was no such character on the line (because it could not tell whether it got an actual coordinate or an error-value).Since you mention v2, how relevant is support for the version? I'm not too familiar with how CodeMirror is used by others so I hope I'm not ignorantly trampling on anything here.
I don't have a clear grasp of what the selection problem you're having is like, exactly. Just an idea -- would a
beforeSelectionChangeevent, similar to thebeforeChangeevent added this week, which allows you to check and adjust selection changes as they are made, be helpful for you? If not, please explain the nature of the problem or point me to a previous explanation.Should I merge the patches here as they stand, by the way, or is there going to be more adjustment?
The idea of
beforeSelectionChangesounds really interesting, maybe that would work even better than an extended api forsetSelection().As I've written in the notes on visual mode, there are a few differences between vim-selection and the default selection handling. The short version: it covers at least one additional character at the end, and sometimes more in both directions (moving
sel.fromandsel.towithout changingsel.anchororsel.head).You can also try the vim-demo if you prefer that, press
vto activate visual mode and move around using hjkl/arrow keys to select text. You'll notice that in the current version on the homepage the selection does not include the character under the cursor, while in my version the selection expands under the cursor as well. One notable special situation is that on pressingv, initiallysel.tois set tosel.head+1, whilesel.anchorandsel.headare still in the same position, which would makesetSelection()return early (in the homepage-version there is some flipping ofheadandanchorto avoid that and I could work around that by moving the cursor before setting selection). Another thing to try isVfor linewise visual mode, which now allows to move the cursor freely within the selected lines (sosel.fromandsel.toare only moved wheneversel.headchanges lines).While what I do works whenever I am actively setting selection, a few areas are out of reach this way (namely click/drag and undo). The vim-keymap does not register for any events at this point, but I'm planning to try your suggestion from #1084 soon. What I like about
beforeSelectionChangeis that it might allow me to cover both cases with common code. Do you think it should be safe to modifysel.fromandsel.toin general and especially duringbeforeSelectionChange? In that case I would call the normalsetSelection()(which I now emulate instead) and do my final touches in the event handler.As for the merge it depends on whether
@mightyguavalikes the current state and the way I implemented his suggestions. Especially he might not want the workaround of reimplementingsetSelection()to stay in, which I would understand.+1 vote for something like beforeSelectionChange - that definitely has uses on my end as well.
👍 for
beforeSelectionChange-- Would be useful in my project.If it would be safe to modify
sel.fromandsel.toin abeforeSelectionChangeevent, without changingsel.anchorandsel.head, then I agree it could make for a great solution.Ah didn't know you were waiting on me for this. If
@marijnhwill be addingbeforeSelectionChange, then I would rather the code to emulatesetSelectionto not be merged. As I said before my concern is forward compatibility with possible future changes to CodeMirror's selection model (for example, multi selections https://github.com/marijnh/CodeMirror/issues/778). I don't mean to make it hard on you but I'd rather not chance breaking visual mode completely down the road. Thanks for bearing with me.There's an invariant that from/to always correspond to anchor/head (from to the lesser one, to to the greater). This invariant is not going away.
Ok, that kicks my approach out of the window. I understand that you don't want to risk stability issues you'd have to deal with though, I'll see if I can get my changes to visual mode out again so the remaining ones can be merged.
@mightyguavaare you ok with how the patch looks right now? In that case I'd suggest a merge asAlso I'd like you to take a look at d776f74 if you're interested. There I played around with making the selection right but the (now hidden) cursor wrong.
I've merged the changes as they stand.
(I somehow missed the horrible things you were doing in your
setSelectionreplacement before. Such an approach is not acceptable. All selection changes are supposed to go through CodeMirror's internalsetSelection, and poking at the selection from outside is bound to create all kinds of inconsistencies.)You're right, the original commit would have better just been an use-case. I should have opened a normal Issue first to ask whether
sel.from/sel.tovalues not being a permutation ofsel.anchor/sel.headis something CodeMirror is designed to handle. If it was, I still could have made a pull-request with proper api-access to the values. Sorry about that.Pull request closed