Added Langmap Feature
What this PR does / why we need it This pull request implements the langmap feature of Vim. It's an essential accessibility feature for people who use an alternate keyboard layout like Dvorak, Colemak, or a layout specific to a language like Greek or Russian.
It works by specifying the map under vscode.langmap in Code's JSON settings.
Example langmap for Greek:
ΑA,ΒB,ΨC,ΔD,ΕE,ΦF,ΓG,ΗH,ΙI,ΞJ,ΚK,ΛL,ΜM,ΝN,ΟO,ΠP,QQ,ΡR,ΣS,ΤT,ΘU,ΩV,WW,ΧX,ΥY,ΖZ,αa,βb,ψc,δd,εe,φf,γg,ηh,ιi,ξj,κk,λl,μm,νn,οo,πp,qq,ρr,σs,τt,θu,ωv,ςw,χx,υy,ζz
Example langmap for Dvorak:
'q,\\,w,.e,pr,yt,fy,gu,ci,ro,lp,/[,=],aa,os,ed,uf,ig,dh,hj,tk,nl,s\\;,-',\\;z,qx,jc,kv,xb,bn,mm,w\\,,v.,z/,[-,]=,\"Q,<W,>E,PR,YT,FY,GU,CI,RO,LP,?{,+},AA,OS,ED,UF,IG,DH,HJ,TK,NL,S:,_\",:Z,QX,JC,KV,XB,BN,MM,W<,V>,Z?
You may find the exact format under :help langmap in Vim.
Keystrokes are then remapped based on the passed langmap, unless they're to be interpreted as text. Most frequently, one would use this feature to at least remap the movement keys to be at the physical positions of the "hjkl" keys on the keyboard, whilst still being able to type with one's chosen layout.
Which issue(s) this PR fixes Feature Request #2217
Special notes for your reviewer I have made sure to keep the changes to working code minimal. Additionally, no remapping is called if the passed langmap is an empty string (default value). That way, no unexpected behaviour or performance penalty should be introduced, unless you actively override the default value in your settings. Furthermore, I'm willing to write unit tests for this feature in the future.
It would be nice to also support the from:to syntax specified in help langmap:
2. A list of "from" characters, a semi-colon and a list of "to" characters. Example: "abc;ABC" Example: "aA,fgh;FGH,cCdDeE"```
Also being able to pull the setting from .vimrc if applicable would be very convenient!
Thanks for making this PR, been wanting this feature for a while! Hopefully it gets approved soon..
It's completely compliant with how vim parses langmap, including the "from to" syntax. I also believe it should already work with .vimrc but let me test that when I'm back home in a few days.
Hmm, my colemak from:to langmap doesn't seem to work here, but works fine in vim:
"vim.langmap": "qwfpgjluy\\;arstdhneiozxcvbkmQWFPGJLUY:ARSTDHNEIOZXCVBKM;qwertyuiopasdfghjkl\\;zxcvbnmQWERTYUIOPASDFGHJKL:ZXCVBNM",
If I convert it to the other format however, it works fine:
"vim.langmap": "qq,ww,fe,pr,gt,jy,lu,ui,yo,\\;p,aa,rs,sd,tf,dg,hh,nj,ek,il,o\\;,zz,xx,cc,vv,bb,kn,mm,QQ,WW,FE,PR,GT,JY,LU,UI,YO,:P,AA,RS,SD,TF,DG,HH,NJ,EK,IL,O:,ZZ,XX,CC,VV,BB,KN,MM",
Will check the bug, thanks for reporting!
I've identified and fixed the issue with parsing, but I'm yet to check if my code already works with .vimrc @ryan-mooore
All works beautifully for me now 👍
Is there any hope on getting this merged? @J-Fields
Mind adding a few test cases?
Done.
One annoyance I'm not happy with yet is the need for 14eba0bd.
Basically, Vim handles registers separetly from other <character>-like directives when it comes to remapping:
- When for example searching for a character, it must not be langmapped: Assuming a Greek langmap,
θθshould becomefθand notff. - When using registers, the register must be langmapped, otherwise you'd be trying to use an invalid register (e.g. the register
θdoes not exist).
As is right now, there is no way to distinguish mappings like f<character> from @<character>, so I have to manually go to all the places that registers are used and do the mapping logic there.
If instead something like @<register> or @<r-character> could be introduced, then the central langmap logic could just handle it all. That's how we ended up doing it in codemirror-vim.
(Side note: Why does recording a macro use q<alpha>, but playing @<character>? What's the difference?)
If instead something like
@<register>or@<r-character>could be introduced, then the central langmap logic could just handle it all.
Yeah adding <register> sounds good to me.
(Side note: Why does recording a macro use
q<alpha>, but playing@<character>? What's the difference?)
I'm not sure, only thing that really comes to mind is it may be a hacky way to ensure q/ and q? have the right mappings.
@J-Fields I changed the code accordingly. I ended up having to introduce <register> and <macro> separately. This is due to some edge cases with macro recording, which used <alpha> and <number> instead of <character>, as previously mentioned. Using just <register> caused some issues with obscure tests concerning remapping that I could not decipher.
With the current setup, all tests are passing, and the branch is up-to-date with upstream.