doomemacs / doomemacs

An Emacs framework for the stubborn martian hacker
MIT License
19.17k stars 3.04k forks source link

Support colemak keyboard layout #783

Open ar1a opened 6 years ago

ar1a commented 6 years ago

Planning on trying out new layouts soon, figured maybe we should have a support module.

Might be based off https://github.com/wbolster/evil-colemak-basics ?

JonathanReeve commented 4 years ago

A big +1 for this. There is also the way Spacemacs does it.

HaoZeke commented 4 years ago

I've been using colemak for a year without needing any changes to the bindings, but I guess these might be better?

JonathanReeve commented 4 years ago

The Spacemacs method is just to swap out the keybindings hjkl for hnei. That way, you maintain the directional keys on the home row, like vim does.

JonathanReeve commented 4 years ago

FWIW, this is what's preventing me from switching to Doom from Spacemacs.

wis commented 4 years ago

I remap n e i o to h j k l, o+O to l+L, i+I to t+T and n+N to f+F

$ touch ~/.doom.d/bindings.el

(setq doom-leader-key ","
      doom-leader-alt-key ",")
(map! :n "t" 'evil-insert
      :n "T" 'evil-insert-line
      :n "l" 'evil-open-below
      :n "L" 'evil-open-above
      :n "f" 'evil-ex-search-next
      :n "F" 'evil-ex-search-previous
      :n "n" 'evil-backward-char
      :n "e" 'evil-next-line
      :n "i" 'evil-previous-line
      :n "o" 'evil-forward-char
      )

load it at the end of ~/doom.d/config.el $ echo '(load! "bindings")' >> ~/.doom.d/config.el I couldn't find docs on the web for these special strings, but I could find them by emacs's describe-key, ctrl+h then press k, then the key you want to find the special string for.

@JonathanReeve

pauldub commented 4 years ago

IMO evil-colemak-basics has the best keybindings for vim like colemak experience, if anyone is interesed in setting it up until there is a keyboard layout support, here is how I do it.

config.el

(use-package! evil-colemak-basics
  :after evil
  :config
  (setq evil-colemak-basics-rotate-t-f-j t))

(after! evil (global-evil-colemak-basics-mode))

packages.el

(package! evil-colemak-basics)
neeasade commented 4 years ago

I'm a colemak-DH user with my own key rotation going on -- I think a flexible option would be if I could redirect bindings in the map! macro itself somehow (something similar to how evil-collection does it)

AnthonyDiGirolamo commented 4 years ago

About to take the doom plunge myself. What is the recommended way to remap keys? Is wis's suggestion above the way to go?

I haven't met another colemak user who uses my bindings. It's sort of like half of what https://github.com/wbolster/evil-colemak-basics does. Here's what I do in vim

" h/l stay in default colemak locations
" n/e remapped to down up
nnoremap n gj|xnoremap n gj|onoremap n gj|
nnoremap e gk|xnoremap e gk|onoremap e gk|
" Use k/K for next/previous search hits
nnoremap k n|xnoremap k n|onoremap k n|
nnoremap K N|xnoremap K N|onoremap K N|
HaoZeke commented 4 years ago

About to take the doom plunge myself. What is the recommended way to remap keys? Is wis's suggestion above the way to go?

I haven't met another colemak user who uses my bindings. It's sort of like half of what https://github.com/wbolster/evil-colemak-basics does. Here's what I do in vim

" h/l stay in default colemak locations
" n/e remapped to down up
nnoremap n gj|xnoremap n gj|onoremap n gj|
nnoremap e gk|xnoremap e gk|onoremap e gk|
" Use k/K for next/previous search hits
nnoremap k n|xnoremap k n|onoremap k n|
nnoremap K N|xnoremap K N|onoremap K N|

I do have the k/K setup, along with the down/up; some details here

fosskers commented 3 years ago

@pauldub 's setup works like a charm as-is. Let's get that into a flag for the layout module.

fosskers commented 3 years ago

I spoke too soon about it working perfectly. I have had to rewire some muscle memory on a few bindings (which is fine), and it seems that undo functionality (by pressing l) doesn't work at all.

fosskers commented 3 years ago

And now a question (I just installed Doom today): how do I make custom bindings apply after ones defined by a package? For instance, the following doesn't work:

;; Colemak
(use-package! evil-colemak-basics
  :after evil
  :config
  (setq evil-colemak-basics-rotate-t-f-j t))

(after! evil (global-evil-colemak-basics-mode))

;; Flip what evil-colemak-basics applies.
(map! :n "u" 'evil-undo
      :n "l" 'evil-insert)

Namely, my two custom bindings at the bottom don't seem to be respected.

fosskers commented 3 years ago

In the meantime, to restore undo functionality, I'm avoiding evil-colemak-basics and hand-rolling my bindings. I'm attempting to emulate what the settings of colemak-hnei from Spacemacs:

(after! evil
  (map! :n "l" 'evil-insert
        :n "L" 'evil-insert-line
        :nv "h" 'evil-backward-char
        :nv "i" 'evil-forward-char
        :nv "n" 'evil-next-line
        :nv "e" 'evil-previous-line
        :nv "k" 'evil-forward-word-end
        :n "N" 'evil-join
        :n "j" 'evil-ex-search-next))

(after! magit
  (map! :map magit-mode-map
        :n "n" 'magit-next-line
        :n "e" 'magit-previous-line))

(map! :map org-agenda-mode-map
      :m "n" 'org-agenda-next-line
      :m "e" 'org-agenda-previous-line
      )

Work-in-progress. Not sure if the afters are necessary.

pauldub commented 3 years ago

it seems that undo functionality (by pressing l) doesn't work at all.

I do not have that issue but my setup has changed a little:

(use-package! evil-colemak-basics
  :after evil
+ :hook (after-init . global-evil-colemak-basics-mode)
  :config
  (setq evil-colemak-basics-rotate-t-f-j t))

(after! evil (global-evil-colemak-basics-mode t))

It is not clear to me how the initialisation of evil-colemak-basics should be handled :\

RobertoGoAm commented 3 years ago

Not sure if this is the right way to do it, far from an emacs expert, but adding this to config.el seems to work well:

;; Colemak DH Evil binds

;; Unbinds
(define-key evil-normal-state-map "i" nil)
(define-key evil-normal-state-map "I" nil)
(define-key evil-normal-state-map "J" nil)
(define-key evil-normal-state-map "gi" nil)
(define-key evil-normal-state-map "gJ" nil)
(define-key evil-window-map "j" nil)
(define-key evil-window-map "J" nil)
(define-key evil-window-map "k" nil)
(define-key evil-window-map "K" nil)
(define-key evil-window-map "l" nil)
(define-key evil-window-map "L" nil)
(define-key evil-window-map "n" nil)
(define-key evil-motion-state-map "e" nil)
(define-key evil-motion-state-map "E" nil)
(define-key evil-motion-state-map "j" nil)
(define-key evil-motion-state-map "k" nil)
(define-key evil-motion-state-map "l" nil)
(define-key evil-motion-state-map "K" nil)
(define-key evil-motion-state-map "L" nil)
(define-key evil-motion-state-map "n" nil)
(define-key evil-motion-state-map "N" nil)
(define-key evil-motion-state-map "ge" nil)
(define-key evil-motion-state-map "gE" nil)
(define-key evil-motion-state-map "gj" nil)
(define-key evil-motion-state-map "gk" nil)
(define-key evil-motion-state-map "C-e" nil)
(define-key evil-motion-state-map "gn" nil)
(define-key evil-motion-state-map "gN" nil)
(define-key evil-visual-state-map "I" nil)
(define-key evil-visual-state-map "i" nil)
(define-key evil-operator-state-map "i" nil)

;; Normal state
(define-key evil-normal-state-map "l" 'evil-insert)
(define-key evil-normal-state-map "L" 'evil-insert-line)
(define-key evil-normal-state-map "N" 'evil-join)
(define-key evil-normal-state-map "gl" 'evil-insert-resume)
(define-key evil-normal-state-map "gN" 'evil-join-whitespace)

;; Window commands
(define-key evil-window-map "n" 'evil-window-down)
(define-key evil-window-map "N" 'evil-window-move-very-bottom)
(define-key evil-window-map "e" 'evil-window-up)
(define-key evil-window-map "E" 'evil-window-move-very-top)
(define-key evil-window-map "i" 'evil-window-right)
(define-key evil-window-map "I" 'evil-window-move-far-right)
(define-key evil-window-map "j" 'evil-window-new)

;; Motion state
(define-key evil-motion-state-map "k" 'evil-forward-word-end)
(define-key evil-motion-state-map "K" 'evil-forward-WORD-end)
(define-key evil-motion-state-map "n" 'evil-next-line)
(define-key evil-motion-state-map "e" 'evil-previous-line)
(define-key evil-motion-state-map "i" 'evil-forward-char)
(define-key evil-motion-state-map "E" 'evil-lookup)
(define-key evil-motion-state-map "I" 'evil-window-bottom)
(define-key evil-motion-state-map "j" 'evil-search-next)
(define-key evil-motion-state-map "J" 'evil-search-previous)
(define-key evil-motion-state-map "gk" 'evil-backward-word-end)
(define-key evil-motion-state-map "gK" 'evil-backward-WORD-end)
(define-key evil-motion-state-map "gn" 'evil-next-visual-line)
(define-key evil-motion-state-map "ge" 'evil-previous-visual-line)
(define-key evil-motion-state-map "C-k" 'evil-scroll-line-down)

;; Text objects
(define-key evil-motion-state-map "gj" 'evil-next-match)
(define-key evil-motion-state-map "gJ" 'evil-previous-match)

;; Visual state
(define-key evil-visual-state-map "L" 'evil-insert)
(define-key evil-visual-state-map "l" evil-inner-text-objects-map)

;; Operator-Pending statea
(define-key evil-operator-state-map "l" evil-inner-text-objects-map)

It switches jkl for nei and viceversa, which is what I prefer

azzamsa commented 2 years ago

I want to migrate to doom from vanilla emacs after 5+ year. Unfortunately, I am type in Colemak-DH.

Anyone use this PR https://github.com/hlissner/doom-emacs/pull/5835 so far? Is it works well and don't conflict with default doom keys?

Thanks.

Lord-Valen commented 2 years ago

@azzamsa Until #5835 is merged, this should work fine for colemak-DH:

;; ~/.doom.d/packages.el
(package! evil-colemak-basics) ; colemak remaps
;; ~/.doom.d/config.el
(use-package! evil-colemak-basics
  :after evil
  :init
  (setq evil-colemak-basics-layout-mod `mod-dh) ; Swap "h" and "m"
  :config
  (global-evil-colemak-basics-mode) ; Enable colemak rebinds
  )
azzamsa commented 2 years ago

@Lord-Valen Thanks for the info.

I tried it a day as a vim beginner and it works well for me.

azzamsa commented 2 years ago

Using the following config:

(use-package! evil-colemak-basics
  :after evil
  :init
  (setq evil-colemak-basics-layout-mod `mod-dh) 
  :config
  (global-evil-colemak-basics-mode))

Is anyone having an issue with magit keybindings?

  1. magit-log (default to l) doesn't work. It is even not assigned to any key

image

  1. During rebase

image

azzamsa commented 2 years ago

The issue disappears in a newer version of doom. I upgraded (reinstalled) and the issue disappears.

f for fixup still moves the cursor forward, to make it change the status to fixup. Switch to insert mode (U) then press f.

~  5s
❯ ~/.emacs.d/bin/doom info
> Executing 'doom info' with Emacs 29.0.50 at 2022-02-16 17:38:51
    generated    Feb 16, 2022 17:38:51
      system       Debian GNU/Linux 11 (bullseye) Linux 5.10.0-11-amd64 x86_64
      emacs        29.0.50 master 2ab73286b ~/.emacs.d/ -> ~/.emacs.d/
      doom         21.12.0-alpha grafted, HEAD -> master, origin/master, origin/HEAD 26d5163 2022-02-16 02:13:35 +0100 ~/.doom.d/ -> ~/.doom.d/
      shell        /usr/bin/fish
      features     ACL CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GPM GSETTINGS HARFBUZZ JPEG JSON LCMS2 LIBOTF LIBSELINUX LIBSYSTEMD LIBXML2 MODULES NATIVE_COMP NOTIFY INOTIFY PDUMPER PGTK PNG RSVG SECCOMP SOUND THREADS TIFF TOOLKIT_SCROLL_BARS XIM GTK3 ZLIB
      traits       batch server-running envvar-file
      modules      :completion company vertico :ui doom doom-dashboard doom-quit hl-todo indent-guides ligatures (modeline +light) nav-flash ophints (popup +defaults) vc-gutter vi-tilde-fringe workspaces :editor (evil +everywhere) file-templates fold multiple-cursors snippets :emacs (dired +ranger) electric undo vc :checkers syntax (spell +flyspell) :tools editorconfig (eval +overlay) lookup lsp magit:lang emacs-lisp javascript lua markdown org (python +lsp) (rust +lsp) sh web yaml :app everywhere :config (default +bindings +smartparens)
      packages     (evil-colemak-basics) (super-save)

image

fosskers commented 2 years ago

Can I finally remove my custom colemak hacks?

azzamsa commented 2 years ago

This is all my config: https://github.com/azzamsa/doom.d/blob/b2c25cddfd5bb8f1595fcd19eb04a36dae49e9dc/config.el#L74

azzamsa commented 2 years ago

Update:

The same thing for magit-log in magit status buffer. It is bound to l by default. So it doesn't work. The workaround is to enter insert mode (U) in magit-status buffer then hit l.