Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Statistically ergonomic keybinds for all keyboard layouts #506

Open
udayvir-singh opened this issue Sep 16, 2023 · 23 comments
Open

RFC: Statistically ergonomic keybinds for all keyboard layouts #506

udayvir-singh opened this issue Sep 16, 2023 · 23 comments
Labels
documentation Improvements or additions to documentation

Comments

@udayvir-singh
Copy link

udayvir-singh commented Sep 16, 2023

After 6 months of research, testing and multiple revisions, here is the most ergonomic layout I could create for meow:

image

Some notable features:

  • The layout is keyboard layout agnostic, although it may seem like it was created for qwerty layout due to c and v being copy and paste, the position of c and v was determined by command statistics and not due to mnemonics.

  • Uses ijkl instead of hjkl as it offers three benefits:

    • It is better layout overall, see xahlee.
    • It frees your pinky ;, which allows you to set ; as a prefix key.
    • It allows you to bind u and o above for word-wise movement and selection, instead of the awkward vim style b, w.
  • The layout is designed to maximize alternation and rolling, which increases the amount of actions/minute.

    • Examples of alternating keys:
      • [uo][df]: delete/change forward/backward word
      • [uo][er]: enter insert mode before/after forward/backward word
      • qp: start of line
      • sp: end of line
      • wp: start of block
      • ay: search word
      • x<space>: select space delimited word
      • ;f: save buffer [one of the most used commands]
    • Examples of rolling keys [All the keys on the left hand side were designed to roll very cleanly]:
      • a[er]: enter insert mode before/after word
      • a[df]: delete/change word
      • s[er]: enter insert mode before/after line
      • s[df]: delete/change line
      • qr: enter insert mode at start of line
      • qd: join line
      • w[er]: enter insert mode before after block
      • w[df]: delete/change block
  • Most used commands are placed in the order of home row -> top row -> bottom row.

  • Has 2 extra prefix keys n and ;, that only contain commands that can be used in a editable buffer.

    • n prefix is for editing commands like transpose-chars, sp-forward-barf-sexp, meow-comment, etc.
    • ; prefix is for non-editing/general-use commands like save-buffer, eglot-format, etc.
    • These two prefix maps are create separate from leader map because you don't need commands like save-buffer or transpose-chars in a non-editable buffer, hence, they end up as dead keys in other modes with leader map, wasting valuable keyboard space.
  • Adds many additions commands:

    • meow-word: a single command that combines meow-expand-word and meow-expand-symbol. it works as follows [| is the cursor]:
      • if you have the text |hello-word and press a, it expands to hello, if you press a again it expands to hello-world.
      • Hence, you can quickly do aa instead of having a separate keybind and doing <shift>a.
    • meow-kill-line: kills till end of line respecting meow-use-clipboard variable.
    • meow-change-line: kills till end of line and switches to INSERT state.
    • meow-save-clipboard: explicitly save to clipboard.
    • meow-yank-dwim and meow-yank-pop-dwim: adds vim-like behavior for yanking lines.
    • meow-smart-reverse: Reverses selection or begins negative argument.
    • meow-kmacro: Combines meow-kmacro-start and meow-kmacro end, behaves like vim's q.
    • meow-eldoc: Just a simple function that toggles eldoc buffer.

Source code

;; -------------------- ;;
;;         UTILS        ;;
;; -------------------- ;;
(defun meow-word ()
  "Expand word/symbol under cursor."
  (interactive)
  (if (and (use-region-p)
           (equal (car (region-bounds))
                  (bounds-of-thing-at-point 'word)))
      (meow-mark-symbol 1)
    (progn
      (when (and (mark)
                 (equal (car (region-bounds))
                        (bounds-of-thing-at-point 'symbol)))
        (meow-pop-selection))
      (meow-mark-word 1))))

(defun meow-kill-line ()
  "Kill till the end of line."
  (interactive)
  (let ((select-enable-clipboard meow-use-clipboard))
    (kill-line)))

(defun meow-change-line ()
  "Kill till end of line and switch to INSERT state."
  (interactive)
  (meow--cancel-selection)
  (meow-end-of-thing
   (car (rassoc 'line meow-char-thing-table)))
  (meow-change))

(defun meow-save-clipboard ()
  "Copy in clipboard."
  (interactive)
  (let ((meow-use-clipboard t))
    (meow-save)))

(defvar meow--trim-yank nil)

(defun meow-insert-for-yank-advice (orig-fn str)
  "Advice for `insert-for-yank' function to correctly insert lines."
  (when meow--trim-yank
    (set 'str (string-trim-right str "\n")))
  (if (and (not (eq (point) (+ 1 (line-end-position 0))))
           (string-match-p "^.+\n$" str))
      (save-excursion
        (beginning-of-line)
        (funcall orig-fn str))
    (funcall orig-fn str)))

(defun meow-yank-dwim ()
  "Smart yank."
  (interactive)
  (advice-add 'insert-for-yank :around 'meow-insert-for-yank-advice)
  (if (use-region-p)
      (let ((meow--trim-yank t))
        (delete-region (region-beginning) (region-end))
        (meow-yank))
    (meow-yank))
  (advice-remove 'insert-for-yank 'meow-insert-for-yank-advice))

(defun meow-yank-pop-dwim ()
  "Smart yank pop."
  (interactive)
  (advice-add 'insert-for-yank :around 'meow-insert-for-yank-advice)
  (if (use-region-p)
      (let ((meow--trim-yank t))
        (delete-region (region-beginning) (region-end))
        (meow-yank-pop))
    (meow-yank-pop))
  (advice-remove 'insert-for-yank 'meow-insert-for-yank-advice))

(defun meow-smart-reverse ()
  "Reverse selection or begin negative argument."
  (interactive)
  (if (use-region-p)
      (meow-reverse)
    (negative-argument nil)))

(defun meow-kmacro ()
  "Toggle recording of kmacro."
  (interactive)
  (if defining-kbd-macro
      (meow-end-kmacro)
    (meow-start-kmacro)))

(defun meow-eldoc ()
  "Toggle the display of the eldoc window."
  (interactive)
  (if (get-buffer-window eldoc--doc-buffer)
      (delete-window (get-buffer-window eldoc--doc-buffer))
    (eldoc-doc-buffer t)))

;; -------------------- ;;
;;       VARIABLES      ;;
;; -------------------- ;;
(meow-thing-register 'angle
                     '(pair ("<") (">"))
                     '(pair ("<") (">")))

(setq meow-char-thing-table
      '((?f . round)
        (?d . square)
        (?s . curly)
        (?a . angle)
        (?r . string)
        (?v . paragraph)
        (?c . line)
        (?x . buffer)))

(setq meow-selection-command-fallback
      '((meow-change . meow-change-char)
        (meow-kill . meow-delete)
        (meow-cancel-selection . keyboard-quit)
        (meow-pop-selection . meow-pop-grab)
        (meow-beacon-change . meow-beacon-change-char)))

;; -------------------- ;;
;;       MAPPINGS       ;;
;; -------------------- ;;
(meow-define-keys 'normal
 ; expansion
 '("0" . meow-expand-0)
 '("1" . meow-expand-1)
 '("2" . meow-expand-2)
 '("3" . meow-expand-3)
 '("4" . meow-expand-4)
 '("5" . meow-expand-5)
 '("6" . meow-expand-6)
 '("7" . meow-expand-7)
 '("8" . meow-expand-8)
 '("9" . meow-expand-9)
 '("'" . meow-smart-reverse)

 ; movement
 '("i" . meow-prev)
 '("k" . meow-next)
 '("j" . meow-left)
 '("l" . meow-right)

 '("y" . meow-search)
 '("/" . meow-visit)

 ; expansion
 '("I" . meow-prev-expand)
 '("K" . meow-next-expand)
 '("J" . meow-left-expand)
 '("L" . meow-right-expand)

 '("u" . meow-back-word)
 '("U" . meow-back-symbol)
 '("o" . meow-next-word)
 '("O" . meow-next-symbol)

 '("a" . meow-word)
 '("s" . meow-line)
 '("w" . meow-block)
 '("q" . meow-join)
 '("g" . meow-grab)
 '("G" . meow-pop-grab)
 '("p" . meow-cancel-selection)
 '("P" . meow-pop-selection)

 '("x" . meow-till)
 '("X" . meow-find)

 '("," . meow-beginning-of-thing)
 '("." . meow-end-of-thing)
 '("<" . meow-inner-of-thing)
 '(">" . meow-bounds-of-thing)

 '("[" . indent-rigidly-left-to-tab-stop)
 '("]" . indent-rigidly-right-to-tab-stop)

 ; editing
 '("b" . open-line)
 '("B" . split-line)
 '("d" . meow-kill)
 '("D" . meow-kill-line)
 '("f" . meow-change)
 '("F" . meow-change-line)
 '("c" . meow-save)
 '("C" . meow-save-clipboard)
 '("v" . meow-yank-dwim)
 '("V" . meow-yank-pop-dwim)

 '("e" . meow-insert)
 '("E" . meow-open-above)
 '("r" . meow-append)
 '("R" . meow-open-below)

 '("z" . query-replace-regexp)

 '("h" . undo-only)
 '("H" . undo-redo)

 '("m"  . meow-kmacro)
 '("M"  . kmacro-call-macro)
 '("nm" . kmacro-edit-macro) ;; 'n' prefix is for editing commands

 '("nf" . meow-comment)

 '("N"  . upcase-dwim)
 '("nn" . downcase-dwim)
 '("nN" . capitalize-dwim)

 ; eldoc
 '("t" . eldoc-box-help-at-point)
 '("T" . meow-eldoc)

 ; general
 '(";f" . save-buffer) ;; ';' prefix is for general commands
 '(";F" . save-some-buffers)

 ; ignore escape
 '("<escape>" . ignore))

This source code here is different from my actual dotfiles, as it uses some other plugins like expand-region, undo-tree, smartparens. Here are my actual config files which contain much more keybinds:

init-meow.el
init-mappings.el

Further improvements:

meow-block can be replaced with er/expand-region for more selection range. Here is config for expand-region that I use:

(require 'expand-region)

(setq er/try-expand-list
      '(er/mark-inside-quotes
        er/mark-outside-quotes
        er/mark-inside-pairs
        er/mark-outside-pairs))
@udayvir-singh
Copy link
Author

fixes #23

@udayvir-singh udayvir-singh changed the title Statistically ergonomic keybinds for any layout RFC: Statistically ergonomic keybinds for all keyboard layouts Sep 16, 2023
@DogLooksGood
Copy link
Collaborator

DogLooksGood commented Sep 16, 2023

@udayvir-singh Hey, it looks cool.

I saw there are lot reasonable points, I also like your idea about protecting the pinky finger, by leaving them for some other usages or putting a non-repeatable commands. The overall feeling of the command looks great. I just found some tricky combinations when I went through it. For example, az/aaz to replace current word/symbol. I know Xah Lee did great statistics based on the command frequency. However most of time we are not using a single command, so it could be important those combinations are easy to press. I never did, but how do you think about key travel based analysis. The two keys pressed by different hands ought to have a significant lower number than the two keys pressed by a single finger with crossing the rows. e.g. az, wc are bad and df, jk, ks are good. There aren't much bad combinations in this layout, but there aren't much good combinations neither based on this approach. Let me know what do you think?

@udayvir-singh
Copy link
Author

udayvir-singh commented Sep 16, 2023

@DogLooksGood

  1. z is query-replace-rexep, az does not replace current word/symbol. To replace current symbol/word do av or aav which is very ergonomic, it also work with sv to replace the current line.

  2. wc is also very ergonomic in practice. On a normal keyboard your wrists are angled at 60-70deg, hence wc is very fast to do as your wc is inline with your first 3 fingers due to the stagger.

@udayvir-singh
Copy link
Author

udayvir-singh commented Sep 16, 2023

The keyboard layout also takes into account normal english word usage, that was insert mode is e as it is close to the most used consonants r and t. The same is true for f which is bellow e and r.

@udayvir-singh
Copy link
Author

udayvir-singh commented Sep 16, 2023

There aren't much bad combinations in this layout, but there aren't much good combinations neither based on this approach.

The layout tries to minimize bad combinations, which there are very few. The first iterations tried to maximize good combinations but that ended up being way worse, here is a example:

  1. Would you have a layout that has 50% good combinations, 30% ok combinations and 20% bad combinations.

  2. Or would you have a layout that has 30% good combinations 70% ok combinations and no bad combinations.

I choose the later, as over a long coding session those bad combinations add up and start hurting your fingers really bad.

@udayvir-singh
Copy link
Author

udayvir-singh commented Sep 16, 2023

I prefer a smother experience over a fast and jerky one:

  1. The smother experience goes like this:

fast meh meh fast meh meh ...

  1. the faster goes like this:

fast fast bad fast bad fast ...

All those bad's add up really quickly.

@DogLooksGood
Copy link
Collaborator

The keyboard layout also takes into account normal english word usage, that was insert mode is e as it is close to the most used consonants r and t. The same is true for f which is bellow e and r.

This is a good point I've never thought about.

And there are some DWIM style commands I won't go with.

  1. The DWIM word/symbol command. By design, meow-word and meow-symbol push selected content into regexp-search-ring. And make it a DWIM command will add unnecessary history.
  2. After making yank/replace a DWIM command, we can't yank directly when there's a selection. The same to the DWIM commands of delete-char/kill and reverse/negative-argument. Because most meow commands create selection by default.

@udayvir-singh
Copy link
Author

udayvir-singh commented Sep 16, 2023

After making yank/replace a DWIM command, we can't yank directly when there's a selection

@DogLooksGood You could just use the global keybinds in those edge cases, like C-y or do M-x yank. The layout doesn't take edge cases like this into account as you rarely encounter them. Vim also replaces selection and nobody notices any problems in it.

@udayvir-singh
Copy link
Author

udayvir-singh commented Sep 16, 2023

And make it a DWIM command will add unnecessary history.

I just fixed it, so it doesn't pollute the history:

(defun meow-word ()
  "Expand word/symbol under cursor."
  (interactive)
  (if (and (use-region-p)
           (equal (car (region-bounds))
                  (bounds-of-thing-at-point 'word)))
      (progn
        (when (string-match-p 
               (or (car regexp-search-ring) "")
               (buffer-substring (region-beginning) (region-end)))
          (pop regexp-search-ring))
        (meow-mark-symbol 1))
    (progn
      (when (and (mark)
                 (equal (car (region-bounds))
                        (bounds-of-thing-at-point 'symbol)))
        (meow-pop-selection))
      (meow-mark-word 1))))

It can still just optionally included with the default suggestion being meow-mark-word and meow-mark-symbol on a and <shift>a.

@udayvir-singh
Copy link
Author

I can understand reverse/negative-argument dwim. It was just a experimental command. Just replace it will normal meow-reverse.

@udayvir-singh
Copy link
Author

udayvir-singh commented Sep 16, 2023

However, you can't replace delete-char with kill-line as the entire keyboard layout is based around d and f. It would break the entire layout. That's why kill-line is set to D.

@udayvir-singh
Copy link
Author

udayvir-singh commented Sep 16, 2023

To summarize:

  1. All the custom commands like meow-word, meow-yank-dwim, meow-change-line, meow-smart-reverse can be excluded as they are not important and don't affect the overall efficiency.

  2. However, delete-char can only be used with meow-kill, otherwise the entire layout goes to shit. I can understand why you would want to separate them as delete-char doesn't work with kill ring and doesn't work properly in beacon mode but the layout was based on real world command statistics collected by myself and xahlee.

The goal of the keyboard layout was to be good 90% of the time and be consistent in quality, after 8 iterations this is the final layout I came up with which fully exploits the weakness of a traditional stagger layout, Thus was never meant to be perfect in ideological sense but was made with real world data in mind.

@DogLooksGood
Copy link
Collaborator

In this case

foo bb|ar  baz
    ^    ^

How you delete the b in the beginning of the word bbar, or the extra whitespace after this word. It is supposed to be back-word delete-char and forward-word delete-char

@udayvir-singh
Copy link
Author

@DogLooksGood upd

@udayvir-singh
Copy link
Author

udayvir-singh commented Sep 16, 2023

Now that I think about it, meow-delete could just be mapped to t and d could retain the functionality of kill-line. I think you are right about keeping it the same. It wouldn't have any effect on the ergonomics. Now I remember the reason why I mapped d to meow-delete, It was because f change char but d deletes line, and I wanted to keep the behavior consistent.

You could also swap t and x and get vim like binding with t for till and x for delete-char.

@udayvir-singh
Copy link
Author

udayvir-singh commented Sep 16, 2023

Here is the final layout that I suggest:

image

;; -------------------- ;;
;;         UTILS        ;;
;; -------------------- ;;
(defun meow-change-line ()
  "Kill till end of line and switch to INSERT state."
  (interactive)
  (let ((beg (point)))
    (end-of-line)
    (delete-region beg (point))
    (meow-insert-mode)))

(defun meow-save-clipboard ()
  "Copy in clipboard."
  (interactive)
  (let ((meow-use-clipboard t))
    (meow-save)))

(defun meow-kmacro ()
  "Toggle recording of kmacro."
  (interactive)
  (if defining-kbd-macro
      (meow-end-kmacro)
    (meow-start-kmacro)))

;; -------------------- ;;
;;       VARIABLES      ;;
;; -------------------- ;;
(meow-thing-register 'angle
                     '(pair ("<") (">"))
                     '(pair ("<") (">")))

(setq meow-char-thing-table
      '((?f . round)
        (?d . square)
        (?s . curly)
        (?a . angle)
        (?r . string)
        (?v . paragraph)
        (?c . line)
        (?x . buffer)))

;; -------------------- ;;
;;       MAPPINGS       ;;
;; -------------------- ;;
(meow-define-keys 'normal
 ; expansion
 '("0" . meow-expand-0)
 '("1" . meow-expand-1)
 '("2" . meow-expand-2)
 '("3" . meow-expand-3)
 '("4" . meow-expand-4)
 '("5" . meow-expand-5)
 '("6" . meow-expand-6)
 '("7" . meow-expand-7)
 '("8" . meow-expand-8)
 '("9" . meow-expand-9)

 ; movement
 '("i" . meow-prev)
 '("k" . meow-next)
 '("j" . meow-left)
 '("l" . meow-right)

 '("y" . meow-search)
 '("/" . meow-visit)

 ; expansion
 '("I" . meow-prev-expand)
 '("K" . meow-next-expand)
 '("J" . meow-left-expand)
 '("L" . meow-right-expand)

 '("u" . meow-back-word)
 '("U" . meow-back-symbol)
 '("o" . meow-next-word)
 '("O" . meow-next-symbol)

 '("a" . meow-mark-word)
 '("A" . meow-mark-symbol)
 '("s" . meow-line)
 '("w" . meow-block)
 '("q" . meow-join)
 '("g" . meow-grab)
 '("G" . meow-pop-grab)
 '("p" . meow-cancel-selection)
 '("P" . meow-pop-selection)

 '("t" . meow-till)
 '("T" . meow-find)

 '("," . meow-beginning-of-thing)
 '("." . meow-end-of-thing)
 '("<" . meow-inner-of-thing)
 '(">" . meow-bounds-of-thing)

 '("[" . indent-rigidly-left-to-tab-stop)
 '("]" . indent-rigidly-right-to-tab-stop)

 ; editing
 '("b" . open-line)
 '("B" . split-line)
 '("d" . meow-kill)
 '("f" . meow-change)
 '("F" . meow-change-line)
 '("x" . meow-delete)
 '("c" . meow-save)
 '("C" . meow-save-clipboard)
 '("v" . meow-yank-dwim)
 '("V" . meow-yank-pop-dwim)

 '("e" . meow-insert)
 '("E" . meow-open-above)
 '("r" . meow-append)
 '("R" . meow-open-below)

 '("z" . query-replace-regexp)

 '("h" . undo-only)
 '("H" . undo-redo)

 '("m" . meow-kmacro)
 '("M" . kmacro-call-macro)

 ; prefix n
 '("nm" . kmacro-edit-macro)
 '("nf" . meow-comment)

 ; prefix ;
 '(";f" . save-buffer)
 '(";F" . save-some-buffers)

 ; ignore escape
 '("<escape>" . ignore))

@DogLooksGood
Copy link
Collaborator

I think we should add a for thing angle into core.

I think we don't really have a way to define the key for arbitrary keyboard layout with one command. So I will add it as an option in README for an ergonomic layout for QWERTY.

@udayvir-singh
Copy link
Author

udayvir-singh commented Sep 17, 2023

@DogLooksGood What do you think about adding meow-change-line and meow-kmacro into core, these commands are bug free, especially considering the utility of meow-kmacro, there is no reason to not add it.

@udayvir-singh
Copy link
Author

udayvir-singh commented Sep 17, 2023

@DogLooksGood After some more modifications, I found a extra improvement by replacing z with find.

image

;; -------------------- ;;
;;         UTILS        ;;
;; -------------------- ;;
(defun meow-change-line ()
  "Kill till end of line and switch to INSERT state."
  (interactive)
  (let ((beg (point)))
    (end-of-line)
    (delete-region beg (point))
    (meow-insert-mode)))

(defun meow-kmacro ()
  "Toggle recording of kmacro."
  (interactive)
  (if defining-kbd-macro
      (meow-end-kmacro)
    (meow-start-kmacro)))

;; -------------------- ;;
;;       VARIABLES      ;;
;; -------------------- ;;
(meow-thing-register 'angle
                     '(pair ("<") (">"))
                     '(pair ("<") (">")))

(setq meow-char-thing-table
      '((?f . round)
        (?d . square)
        (?s . curly)
        (?a . angle)
        (?r . string)
        (?v . paragraph)
        (?c . line)
        (?x . buffer)))

;; -------------------- ;;
;;       MAPPINGS       ;;
;; -------------------- ;;
(meow-define-keys 'normal
 ; expansion
 '("0" . meow-expand-0)
 '("1" . meow-expand-1)
 '("2" . meow-expand-2)
 '("3" . meow-expand-3)
 '("4" . meow-expand-4)
 '("5" . meow-expand-5)
 '("6" . meow-expand-6)
 '("7" . meow-expand-7)
 '("8" . meow-expand-8)
 '("9" . meow-expand-9)
 '("'" . meow-reverse)

 ; movement
 '("i" . meow-prev)
 '("k" . meow-next)
 '("j" . meow-left)
 '("l" . meow-right)

 '("y" . meow-search)
 '("/" . meow-visit)

 ; expansion
 '("I" . meow-prev-expand)
 '("K" . meow-next-expand)
 '("J" . meow-left-expand)
 '("L" . meow-right-expand)

 '("u" . meow-back-word)
 '("U" . meow-back-symbol)
 '("o" . meow-next-word)
 '("O" . meow-next-symbol)

 '("a" . meow-mark-word)
 '("A" . meow-mark-symbol)
 '("s" . meow-line)
 '("S" . meow-goto-line)
 '("w" . meow-block)
 '("q" . meow-join)
 '("g" . meow-grab)
 '("G" . meow-pop-grab)
 '("p" . meow-cancel-selection)
 '("P" . meow-pop-selection)

 '("x" . meow-till)
 '("z" . meow-find)

 '("," . meow-beginning-of-thing)
 '("." . meow-end-of-thing)
 '("<" . meow-inner-of-thing)
 '(">" . meow-bounds-of-thing)

 '("[" . indent-rigidly-left-to-tab-stop)
 '("]" . indent-rigidly-right-to-tab-stop)

 ; editing
 '("b" . open-line)
 '("B" . split-line)
 '("d" . meow-kill)
 '("f" . meow-change)
 '("F" . meow-change-line)
 '("t" . meow-delete)
 '("c" . meow-save)
 '("v" . meow-yank)
 '("V" . meow-yank-pop)

 '("e" . meow-insert)
 '("E" . meow-open-above)
 '("r" . meow-append)
 '("R" . meow-open-below)

 '("h" . undo-only)
 '("H" . undo-redo)

 '("m" . meow-kmacro)
 '("M" . kmacro-call-macro)

 ; prefix n
 '("nm" . kmacro-edit-macro)
 '("nf" . meow-comment)
 '("nd" . meow-swap-grab)
 '("ns" . meow-sync-grab)
 ;; .. etc

 ; prefix ;
 '(";f" . save-buffer)
 '(";F" . save-some-buffers)
 '(";d" . meow-query-replace-regexp)
 ;; .. etc

 ; ignore escape
 '("<escape>" . ignore))

@DogLooksGood
Copy link
Collaborator

Hey, @udayvir-singh sorry for the late reply.

I'm considering some minor modifications when merging into the doc.

I personally don't think meow-kmacro is something I'd like to add. Meow has no interest to simulate Vim behaviors. The emacs builtins have one command to start kmacro or insert counter, and another command to end or call kmacro. I see there's no disadvantage compares to Vim's solution, eventually we need at least 2 commands in total.

As for meow-change-line, it doesn't follow Meow's design. Since we completely separated the objects and behaviors, so it should be meow-end-of-line and meow-change instead of single command. we have existing thing command that can be used to select to the end of line, so we probably don't want a end-of-line command.

How do you think?

@udayvir-singh
Copy link
Author

@DogLooksGood No problem, the layout is meant as a guideline anyways for people to create there own layout that fits there editing style, I just wanted to add better starting keybinds for beginners.

@udayvir-singh
Copy link
Author

udayvir-singh commented Sep 22, 2023

Also I wanted to ask, what do you think about moving all the *.org docs in a docs/ folder instead of in the project root like this:

.
├── docs
│   ├── keybindings
│   │   ├── COLEMAK.ORG
│   │   ├── DVORAK.ORG
│   │   ├── DVP.ORG
│   │   └── QWERTY.ORG
│   ├── CHANGELOG.MD
│   ├── COMMANDS.ORG
│   ├── CUSTOMIZATIONS.ORG
│   ├── EXPLANATION.ORG
│   ├── FAQ.ORG
│   ├── GET_STARTED.ORG
│   ├── TUTORIAL.ORG
│   └── VIM_COMPARISON.ORG
├── LICENSE
├── meow-beacon.el
├── meow-cheatsheet.el
├── meow-cheatsheet-layout.el
├── meow-command.el
├── meow-core.el
├── meow.el
├── meow-esc.el
├── meow-face.el
├── meow-helpers.el
├── meow-keymap.el
├── meow-keypad.el
├── meow-shims.el
├── meow.svg
├── meow-thing.el
├── meow-tutor.el
├── meow-util.el
├── meow-var.el
├── meow-visual.el
└── README.org

Or without capitalization:

.
├── docs
│   ├── keybindings
│   │   ├── colemak.org
│   │   ├── dvorak.org
│   │   ├── dvp.org
│   │   └── qwerty.org
│   ├── changelog.md
│   ├── commands.org
│   ├── customizations.org
│   ├── explanation.org
│   ├── faq.org
│   ├── get_started.org
│   ├── tutorial.org
│   └── vim_comparison.org
├── LICENSE
├── meow-beacon.el
├── meow-cheatsheet.el
├── meow-cheatsheet-layout.el
├── meow-command.el
├── meow-core.el
├── meow.el
├── meow-esc.el
├── meow-face.el
├── meow-helpers.el
├── meow-keymap.el
├── meow-keypad.el
├── meow-shims.el
├── meow.svg
├── meow-thing.el
├── meow-tutor.el
├── meow-util.el
├── meow-var.el
├── meow-visual.el
└── README.org

@udayvir-singh
Copy link
Author

udayvir-singh commented Sep 22, 2023

@DogLooksGood Here is the final final revision of the layout with no extra bells-and-whistles:

image

;; -------------------- ;;
;;      THING TABLE     ;;
;; -------------------- ;;
(meow-thing-register 'angle
                     '(pair ("<") (">"))
                     '(pair ("<") (">")))

(setq meow-char-thing-table
      '((?f . round)
        (?d . square)
        (?s . curly)
        (?a . angle)
        (?r . string)
        (?v . paragraph)
        (?c . line)
        (?x . buffer)))

;; -------------------- ;;
;;       MAPPINGS       ;;
;; -------------------- ;;
(meow-define-keys 'normal
 ; expansion
 '("0" . meow-expand-0)
 '("1" . meow-expand-1)
 '("2" . meow-expand-2)
 '("3" . meow-expand-3)
 '("4" . meow-expand-4)
 '("5" . meow-expand-5)
 '("6" . meow-expand-6)
 '("7" . meow-expand-7)
 '("8" . meow-expand-8)
 '("9" . meow-expand-9)
 '("'" . meow-reverse)

 ; movement
 '("i" . meow-prev)
 '("k" . meow-next)
 '("j" . meow-left)
 '("l" . meow-right)

 '("y" . meow-search)
 '("/" . meow-visit)

 ; expansion
 '("I" . meow-prev-expand)
 '("K" . meow-next-expand)
 '("J" . meow-left-expand)
 '("L" . meow-right-expand)

 '("u" . meow-back-word)
 '("U" . meow-back-symbol)
 '("o" . meow-next-word)
 '("O" . meow-next-symbol)

 '("a" . meow-mark-word)
 '("A" . meow-mark-symbol)
 '("s" . meow-line)
 '("S" . meow-goto-line)
 '("w" . meow-block)
 '("q" . meow-join)
 '("g" . meow-grab)
 '("G" . meow-pop-grab)
 '("m" . meow-swap-grab)
 '("M" . meow-sync-grab)
 '("p" . meow-cancel-selection)
 '("P" . meow-pop-selection)

 '("x" . meow-till)
 '("z" . meow-find)

 '("," . meow-beginning-of-thing)
 '("." . meow-end-of-thing)
 '("<" . meow-inner-of-thing)
 '(">" . meow-bounds-of-thing)

 ; editing
 '("d" . meow-kill)
 '("f" . meow-change)
 '("t" . meow-delete)
 '("c" . meow-save)
 '("v" . meow-yank)
 '("V" . meow-yank-pop)

 '("e" . meow-insert)
 '("E" . meow-open-above)
 '("r" . meow-append)
 '("R" . meow-open-below)

 '("h" . undo-only)
 '("H" . undo-redo)

 '("b" . open-line)
 '("B" . split-line)

 '("[" . indent-rigidly-left-to-tab-stop)
 '("]" . indent-rigidly-right-to-tab-stop)

 ; prefix n
 '("nf" . meow-comment)
 '("nt" . meow-start-kmacro-or-insert-counter)
 '("nr" . meow-start-kmacro)
 '("ne" . meow-end-or-call-kmacro)
 ;; ...etc

 ; prefix ;
 '(";f" . save-buffer)
 '(";F" . save-some-buffers)
 '(";d" . meow-query-replace-regexp)
 ;; ... etc

 ; ignore escape
 '("<escape>" . ignore))

@DogLooksGood DogLooksGood added the documentation Improvements or additions to documentation label Jan 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

2 participants