Merge pull request #3754 from gagbo/feature/input-layout

Add support for bépo layout in a dedicated module
This commit is contained in:
Henrik Lissner 2020-08-19 16:39:04 -04:00 committed by GitHub
commit ed264dcdb2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 485 additions and 0 deletions

View file

@ -0,0 +1,112 @@
;;; input/layout/+bepo.el -*- lexical-binding: t; -*-
;; NOTE: the evaluation loads the whole autoload/bepo.el file but it doesn't really matter as other
;; functions are eagerly called in this block
;; NOTE: since this file is loaded before $DOOMDIR/config.el, the cr-rotation-style variable
;; if not default needs to be set up in $DOOMDIR/init.el
(fset 'doom-bepo--evil-collection-hook
(doom-bepo-rotate-collection-keymaps-h-builder doom-bepo-cr-rotation-style))
(add-hook 'evil-collection-setup-hook #'doom-bepo--evil-collection-hook)
;; Highlight non breaking spaces as error in prog modes only
;; TODO: this variable is defined in a file called xdisp.c Will that work in non-X builds ?
(setq nobreak-char-display t)
(set-face-attribute 'nobreak-space nil :underline t)
(add-transient-hook! 'doom-init-modules-hook
;; "ts" would be a little too common for an evil escape sequence
(setq evil-escape-key-sequence "gq")
(setq avy-keys '(?a ?u ?i ?e ?, ?c ?t ?s ?r ?n)
lispy-avy-keys '(?a ?u ?i ?e ?, ?c ?t ?s ?r ?n ?m ?b ?p ?o ?v ?d ?l ?j ?z))
;; :ui window-select settings, ignoring +numbers flag for now
(after! ace-window
(setq aw-keys '(?a ?u ?i ?e ?, ?c ?t ?s ?r ?n)))
(after! switch-window
(setq switch-window-shortcut-style 'qwerty
switch-window-qwerty-shortcuts '("a" "u" "i" "e" "," "c" "t" "s" "r")))
(doom-bepo-rotate-ts-bare-keymap '(read-expression-map))
(doom-bepo-rotate-bare-keymap '(evil-window-map) doom-bepo-cr-rotation-style)
(map! :i "C-t" #'+default-newline
(:when (featurep! :editor multiple-cursors)
:prefix "gz"
:nv "t" #'evil-mc-make-cursor-move-next-line
:nv "s" #'evil-mc-make-cursor-move-prev-line
;; the old toggle mapping (t) is made available both on "T" for mnemonics and
;; "j" as a "classic" rotation
:nv "T" #'+multiple-cursors/evil-mc-toggle-cursors
:nv "j" #'+multiple-cursors/evil-mc-toggle-cursors)
(:when (featurep! :ui popup)
:n "C-$" #'+popup/toggle
:n "C-#" #'+popup/raise))
(map!
:leader
:desc "Window" "é" 'evil-window-map
(:when (featurep! :ui popup)
:desc "Toggle last popup" "#" #'+popup/toggle)
(:when (featurep! :ui workspaces)
:desc "Switch buffer" "«" #'switch-to-buffer)
:desc "Switch to last buffer" "$" #'evil-switch-to-windows-last-buffer
(:when (featurep! :ui workspaces)
(:prefix-map ("TAB" . "workspace")
:desc "Switch to last workspace" "$" #'+workspace/other
:desc "Next workspace" ")" #'+workspace/switch-right
:desc "Previous workspace" "(" #'+workspace/switch-left))
(:prefix-map ("b" . "buffer")
:desc "Previous buffer" "(" #'previous-buffer
:desc "Next buffer" ")" #'next-buffer)
(:prefix-map ("c" . "code")
:desc "Jump to documentation" "S" #'+lookup/documentation)
(:prefix-map ("g" . "git")
(:when (featurep! :ui vc-gutter)
:desc "Jump to next hunk" ")" #'git-gutter:next-hunk
:desc "Jump to previous hunk" "(" #'git-gutter:previous-hunk))
(:prefix-map ("p" . "project")
:desc "Browse other project" "»" #'doom/browse-in-other-project))
(after! treemacs
(doom-bepo-rotate-ts-bare-keymap '(evil-treemacs-state-map)))
(after! (:or helm ivy)
(doom-bepo-rotate-bare-keymap +default-minibuffer-maps doom-bepo-cr-rotation-style))
(after! company
(doom-bepo-rotate-bare-keymap '(company-active-map company-search-map) doom-bepo-cr-rotation-style))
(after! helm
(doom-bepo-rotate-bare-keymap '(helm-map) doom-bepo-cr-rotation-style))
(after! general
(doom-bepo-rotate-evil-keymap doom-bepo-cr-rotation-style))
(after! evil-snipe
(doom-bepo--evil-collection-hook
nil
'(evil-snipe-local-mode-map evil-snipe-override-local-mode-map)))
(after! lispyville
;; <> en direct
(general-translate-key '(normal motion) 'lispyville-mode-map
"«" "<"
"»" ">"))
(after! (evil magit evil-magit)
(doom-bepo-rotate-ts-bare-keymap
'(magit-mode-map
magit-diff-section-base-map
magit-staged-section-map
magit-unstaged-section-map
magit-untracked-section-map))
;; Without this, "s" is mapped to 'magit-delete-thing (the old "k" for "kill") and
;; takes precedence over the evil command to go up one line
(map! :map magit-mode-map "s" nil)
(doom-bepo--evil-collection-hook
nil
'(magit-mode-map
magit-cherry-mode-map
magit-mode-map
magit-blob-mode-map
magit-diff-mode-map
magit-log-mode-map
magit-log-select-mode-map
magit-reflog-mode-map
magit-status-mode-map
magit-file-mode-map
magit-log-read-revs-map
magit-process-mode-map
magit-refs-mode-map)))
(after! evil-easymotion
(doom-bepo-rotate-bare-keymap '(evilem-map) doom-bepo-cr-rotation-style)))

View file

@ -0,0 +1,90 @@
#+TITLE: input/layout
#+DATE: Jun 29, 2020
#+SINCE: v3.0
#+STARTUP: inlineimages nofold
* Table of Contents :TOC_3:noexport:
- [[#description][Description]]
- [[#maintainers][Maintainers]]
- [[#module-flags][Module Flags]]
- [[#plugins][Plugins]]
- [[#prerequisites][Prerequisites]]
- [[#features][Features]]
- [[#bépo][Bépo]]
- [[#leaving-mnemonics-alone-when-possible][Leaving mnemonics alone when possible]]
- [[#possible-contributions][Possible contributions]]
- [[#configuration][Configuration]]
- [[#bépo-1][Bépo]]
- [[#troubleshooting][Troubleshooting]]
- [[#how-to-deactivate-the-new-bindings-and-go-back-to-the-old-ones-][How to deactivate the new bindings and go back to the old ones ?]]
* Description
This module provides barebones support for using Doom with evil-mode with non-qwerty layouts.
** Maintainers
+ @gagbo (Author)
** Module Flags
+ =+bepo= Enables modifications for the BÉPO layout (customized with version 1.1 in mind)
** Plugins
None
* Prerequisites
This module should only be active if evil is enabled. It uses a general.el utility function, and
the hooks provided by evil-collection to make the necessary changes.
* Features
# An in-depth list of features, how to use them, and their dependencies.
** Bépo
Support for the bépo layout includes:
- Setting Avy keys to the correct home row keys
- Changing navigation keys to =ctsr=
+ old =t= is mapped to =j=
+ old =s= is mapped to =k= (i.e. staging in the magit status buffer is done with =k=)
+ See [[*Configuration][Configuration]] to see where old =c= and =r= functions
are remapped
- Bind =<>= functions to =«»= keys when possible
- Bind =[]= functions to =()= keys when possible
- Bind =é= key to =w= functions when possible
- Bind =è= key to useful functions when possible
- Bind =`~= functions to =$#= keys when possible
*** Leaving mnemonics alone when possible
Exchanging =hjkl= to =ctsr= has the effect of destroying a few mnemonics: the
change operator becomes =l= for example, or the window split becomes =SPC é k=.
The module tries to limit those changes to the minimum, especially in special
buffers. A concrete example is magit.
As the =magit: project= buffer (obtained with =magit-status=) does not need
left-right navigation, keys =c=, =r=, =h=, and =l= keep their "expected" bindings,
while =t=, =s=, =j=, and =k= are flipped:
- checking the log from a magit buffer is still on =l=
- staging a file/region has been moved to =k=
*** Possible contributions
A nice addition in the future might be to have all the normal mode bindings that
start with =g= start with =,= instead to avoid the curl on these common
bindings. This is *not* implemented for the time being.
* Configuration
** Bépo
=doom-bepo-cr-rotation-style= controls whether:
- =qwerty-c= functions are mapped on =bépo-l= key, and =qwerty-r= functions on
=bépo-h= key (='ergodis=), or
- =qwerty-c= functions are mapped on =bépo-h= key, and =qwerty-r= functions on
=bépo-l= key (='strict=)
='strict= would be the logical choice but the =c= functions are used more often
than the =r= ones so [[https://bepo.fr/wiki/Vim#Principe][Ergodis]] advises to
actually put all the =c= functions on the key that does not need a curl.
* Troubleshooting
# Common issues and their solution, or places to look for help.
** How to deactivate the new bindings and go back to the old ones ?
If you are learning a new layout you might want to go back to tho old one to
"get work done". Sadly the only way is to comment out the module, run =doom
sync= and restart emacs.
Restoring the session =SPC q l= by default helps to lower the impact of the
restart.

View file

@ -0,0 +1,268 @@
;;; input/keymaps/autoload/bepo.el -*- lexical-binding: t; -*-
;;;###autoload
(defun doom-bepo-rotate-ts-bare-keymap (keymaps)
"Rotate [jk] with [ts] in KEYMAP."
(dolist (keymap keymaps)
(general-translate-key nil keymap
"t" "j"
"T" "J"
"s" "k"
"S" "K"
"j" "t"
"J" "T"
"k" "s"
"K" "S"
"C-t" "C-j"
"C-s" "C-k"
"C-j" "C-t"
"C-k" "C-s"
"M-t" "M-j"
"M-s" "M-k"
"M-j" "M-t"
"M-k" "M-s"
"C-S-t" "C-S-j"
"C-S-s" "C-S-k"
"C-S-j" "C-S-t"
"C-S-k" "C-S-s"
"M-S-t" "M-S-j"
"M-S-s" "M-S-k"
"M-S-j" "M-S-t"
"M-S-k" "M-S-s")))
;;;###autoload
(defun doom-bepo-rotate-é-quotes-bare-keymap (keymaps)
"Rotate [w<>] with [é«»] in KEYMAP."
(dolist (keymap keymaps)
(general-translate-key nil keymap
"é" "w"
"É" "W"
"«" "<"
"»" ">"
"C-é" "C-w"
"C-«" "C-<"
"C-»" "C->"
"M-é" "M-w"
"M-«" "M-<"
"M-»" "M->"
"C-S-é" "C-S-w"
"C-S-«" "C-S-<"
"C-S-»" "C-S->"
"M-S-é" "M-S-w"
"M-S-«" "M-S-<"
"M-S-»" "M-S->")))
;;;###autoload
(defun doom-bepo-rotate-cr-bare-keymap (keymaps &optional style)
"Rotate [hl] with [cr] in KEYMAP.
If STYLE is nil or 'ergodis, the old 'c' bindings will be mapped on 'l' and the old 'r' on 'h'.
Otherwise if STYLE is 'strict, the old 'c' bindings will be mapped on 'h' and the old 'r' on 'l'.
Undefined behaviour in other cases, for forward compatibility."
(let ((style (or style 'ergodis)))
(dolist (keymap keymaps)
(progn
(general-translate-key nil keymap
"c" "h"
"C" "H"
"r" "l"
"R" "L"
"C-c" "C-h"
"C-r" "C-l"
"M-c" "M-h"
"M-r" "M-l"
"C-S-c" "C-S-h"
"C-S-r" "C-S-l"
"M-S-c" "M-S-h"
"M-S-r" "M-S-l")
(cond ((eq style 'ergodis)
(general-translate-key nil keymap
"h" "r"
"H" "R"
"l" "c"
"L" "C"
"C-h" "C-r"
"C-l" "C-c"
"M-h" "M-r"
"M-l" "M-c"
"C-S-h" "C-S-r"
"C-S-l" "C-S-c"
"M-S-h" "M-S-r"
"M-S-l" "M-S-c"))
(t
(general-translate-key nil keymap
"h" "c"
"H" "C"
"l" "r"
"L" "R"
"C-h" "C-c"
"C-l" "C-r"
"M-h" "M-c"
"M-l" "M-r"
"C-S-h" "C-S-c"
"C-S-l" "C-S-r"
"M-S-h" "M-S-c"
"M-S-l" "M-S-r")))))))
;;;###autoload
(defun doom-bepo-rotate-bare-keymap (keymaps &optional cr-style)
"Rotate [hjklw<>] with [ctsré«»] in KEYMAP.
See `doom-bepo-cr-rotation-style' for the meaning of CR-STYLE"
(doom-bepo-rotate-cr-bare-keymap keymaps cr-style)
(doom-bepo-rotate-ts-bare-keymap keymaps)
(doom-bepo-rotate-é-quotes-bare-keymap keymaps))
;;;###autoload
(defun doom-bepo-rotate-evil-keymap (&optional cr-style)
"Remap evil-{normal,operator,motion,...}-state-map
to be more natural with Bépo keyboard layout.
See `doom-bepo-cr-rotation-style' for the meaning of CR-STYLE."
(general-translate-key nil '(normal motion visual)
"c" "h"
"C" "H"
"t" "j"
"T" "J"
"s" "k"
"S" "K"
"r" "l"
"R" "L"
"j" "t"
"J" "T"
"k" "s"
"K" "S")
(cond ((eq cr-style 'ergodis)
(general-translate-key nil '(normal motion visual)
"h" "r"
"H" "R"
"l" "c"
"L" "C"))
(t
(general-translate-key nil '(normal motion visual)
"h" "c"
"H" "C"
"l" "r"
"L" "R")))
(general-translate-key nil '(insert)
"C-c" "C-h"
"C-C" "C-H"
"C-t" "C-j"
"C-T" "C-J"
"C-s" "C-k"
"C-S" "C-K"
"C-r" "C-l"
"C-R" "C-L"
"C-j" "C-t"
"C-J" "C-T"
"C-k" "C-s"
"C-K" "C-S")
(cond ((eq cr-style 'ergodis)
(general-translate-key nil '(insert)
"C-h" "C-r"
"C-H" "C-R"
"C-l" "C-c"
"C-L" "C-C"))
(t
(general-translate-key nil '(insert)
"C-h" "C-c"
"C-H" "C-C"
"C-l" "C-r"
"C-L" "C-R")))
;; <> as direct access
(general-translate-key nil '(normal motion)
"«" "<"
"»" ">")
;; " è replaces ^0 to go at BOL
(general-translate-key nil '(normal motion)
"è" "^"
"È" "0")
;; [W] -> [É]
;; [C-W] -> [W]
(general-translate-key nil '(normal motion operator)
"é" "w"
"É" "W"
"w" "C-w"
"W" "C-w C-w"))
;;;###autoload
(defun doom-bepo-rotate-collection-keymaps-h-builder (cr-style)
"Build a hook that remaps evil-collection customizations to be more natural
with Bépo keyboard layout, according to CR-STYLE (see `doom-bepo-cr-rotation-style')."
(let* ((cr-style (or cr-style 'ergodis))
(doom-bepo-hook (lambda (_mode mode-keymaps &rest _rest)
(dolist (keymap mode-keymaps)
(general-translate-key '(normal motion visual) keymap
"c" "h"
"C" "H"
"t" "j"
"T" "J"
"s" "k"
"S" "K"
"r" "l"
"R" "L"
"j" "t"
"J" "T"
"k" "s"
"K" "S")
(cond ((eq cr-style 'ergodis)
(general-translate-key '(normal motion visual) keymap
"h" "r"
"H" "R"
"l" "c"
"L" "C"))
(t
(general-translate-key '(normal motion visual) keymap
"h" "c"
"H" "C"
"l" "r"
"L" "R")))
(general-translate-key '(insert) keymap
"C-c" "C-h"
"C-C" "C-H"
"C-t" "C-j"
"C-T" "C-J"
"C-s" "C-k"
"C-S" "C-K"
"C-r" "C-l"
"C-R" "C-L"
"C-j" "C-t"
"C-J" "C-T"
"C-k" "C-s"
"C-K" "C-S")
(cond ((eq cr-style 'ergodis)
(general-translate-key '(insert) keymap
"C-h" "C-r"
"C-H" "C-R"
"C-l" "C-c"
"C-L" "C-C"))
(t
(general-translate-key '(insert) keymap
"C-h" "C-c"
"C-H" "C-C"
"C-l" "C-r"
"C-L" "C-R")))
;; <> en direct
(general-translate-key '(normal motion visual) keymap
"«" "<"
"»" ">")
;; è pour aller au début de ligne
(general-translate-key '(normal motion visual) keymap
"è" "^"
"È" "0")
;; [W] -> [É]
;; [C-W] -> [W]
(general-translate-key '(normal motion operator visual) keymap
"é" "w"
"É" "W"
"w" "C-w"
"W" "C-w C-w")))))
doom-bepo-hook))

View file

@ -0,0 +1,14 @@
;;; input/keymaps/config.el -*- lexical-binding: t; -*-
(defvar doom-bepo-cr-rotation-style 'ergodis
"Modify this variable in your $DOOMDIR/init.el
Style of binding rotation for the cr keys.
If 'ergodis, then the module maps the old 'c' bindings to 'l' and the old 'r' to 'h', as
the 'change' function is used more often and 'l' is easier to reach than 'h' in bépo.
If 'strict, the module does a normal swap and 'c' bindings go to 'h', 'r' bindings go to 'l'.
In all cases, 'h' functions go to 'c' and 'l' ones go to 'r' so the navigation keys still feel vim-like.")
(when (featurep! +bepo)
(load! "+bepo"))