Vim mindset apply Emacs
Truth be told, the vim community is just driven by text editing efficiency!
They also have different modes to make cristal clear distinction when they are editing and when they are not. On the other hand, Emacs has some good counterparts.
Another great material is the blog post Stop the Vim Configuration Madness which can be easily transported to Emacs community too, there are a very vast amount of blogs, youtube videos, screencasts, and whatnot only about plugins. I do use a bunch of them, but I am currently interested in programming environments which consist for the majority of time on i) editing text, ii) reading text, iii) navigation in files, and therefore our motto here will be:
"You know what improves productivity? Mastering motions and operators."
I want to document here some tricks and best practices that I found in Vim material but back-ported to Emacs.
Very important note 1: There is not, yet, a clear order to how the material is laid out.
Very important note 2: I am not a good vimmer.
Very important note 3: I revisit the materials regularly, might complement with time
Invest time to sharp your editing skills!
Summary
- Vim Navigation Commands
- Improving Vim Speed
- Let Vim Do The Typing
- More instantly better vim
- My own customizations based on Vim lessons
- 7 Habits for Effective Text Editing 2.0 by Molenaar
General tips
- Install keyfreq and regularly monitor your usage.
- You should not use your mouse... I know you know.. but, really, install disable-mouse
- I keep
C-x C-s
to save my buffers, no need for that, use the builtinauto-save-visited-mode
. - Muscle memory is tough to change, keep this function around:
bk/shame-on-you
(defun bk/shame-on-you ()
(interactive)
(message "Stop this bad habbit!"))
(global-set-key (kbd "C-x C-s") #'bk/shame-on-you)
Vim Navigation Commands
1.Emacs Keys | Objective | Vim counterpart |
---|---|---|
M-r | Go to the last, middle,top visible line of the screen | {H,L,M} |
C-l | Center the current line | {z,z} |
C-v, M-v | Scroll without moving the cursor (bk/scroll-{up,down}) |
C-y, C-e |
C-a | bk/smart-beginning-of-line |
0 |
C-e | bk/smart-end-of-line |
$ |
M-s . | Search for the current word on point and look other occurrences | * |
C-c r p | Set a register at a specific point (bk/point-to-register) |
C-o |
C-c r j | Jump back to register specified above (bk/jump-to-register) |
C-i |
M-n | (jump-char-forward) |
f,t |
M-p | (jump-char-backward) |
F, T |
M-{a,e} | Move through paragraphs | { and } |
M-k | Kill paragraph | dap |
Custom functions referenced above
(defun bk/scroll-up ()
"Scroll only specific amount of lines. I don't like the defaults of whole screen."
(interactive)
(scroll-up-command 8))
(defun bk/scroll-down ()
"Scroll only specific amount of lines. I don't like the defaults of whole screen."
(interactive)
(scroll-down-command 8))
(defun smart-beginning-of-line ()
"Go back at the first non-whitespace character."
(interactive)
(let ((oldpos (point)))
(back-to-indentation)
(and (= oldpos (point))
(beginning-of-line))))
(defun smart-end-of-line ()
"Go to the end of the last non-whitespace character."
(interactive)
(move-end-of-line nil)
(re-search-backward "^\\|[^[:space:]]")
(forward-char))
(defun bk/point-to-register ()
"Store cursor position in a register."
(interactive)
(point-to-register 8)
(message "Point set"))
(defun bk/jump-to-register ()
"Switches between current position and pos stored."
(interactive)
(let ((tmp (point-marker)))
(jump-to-register 8)
(set-register 8 tmp)))
External packages necessary
- Jump char - similar to
f
andt
commands in Vim
Improving Vim Speed
2.Emacs | Vim |
---|---|
Should I use more commands to movements and editing | Stay away from insert mode |
Stop using arrow keys | Stop using arrow keys |
Use more jump-char to move around |
Use more f and t to movement |
If you hold any character consider this a smell | If you hold any character consider this a smell |
dotMode | Use the repeat command |
Use fuzzy finders (learn ripgrep though) | Use fuzzy finders |
I started using the dotmode.el
to reproduce the repeat
command, but to be honest, not very
useful so far. I used this to replace the recording of small macros.
Let Vim Do The Typing
3.Emacs Keys | Objectives | Vim |
---|---|---|
C-i | Complete word with previous occurrences | C-p |
M-/ | Complete with omni-completion | several keychords in ^X-mode |
M-\ | Complete file names (comint-dynamic-complete-filename) |
C-x C-f (in X mode) |
C-c l | Complete last line from context (bk/try-complete-line) |
C-x C-l (in X mode) |
C-x r s <char> | Copy region into register (copy-to-register) |
"yy |
C-x r i <char> | Insert text from register (insert-register) |
"p |
s-. | Find tags (C-Tags) |
- Vim users seems to take great advantage of registers
- Would be nice to have tabs? (Idk, for now I am just toooo used to changing buffers with
ido
) - Is real nice to have a
drop-down-menu
to your completions,company
package seems more suitable - C Tags is cool! I made the setup but I am not using that much.
You should read Saving Text in Registers
Interesting commands in company-mode
:
- When candidate drop-down appears, search for match using
C-M-s
I remapped toC-s
see below - Show numbers besides candidate name
(setq company-show-numbers t)
, choose based by number withM-<number>
(define-key company-active-map [(control) (meta) ?s] 'company-search-candidates)
(define-key company-active-map "\C-s" 'company-filter-candidates)
Functions
(fset 'bk/try-complete-line
(make-hippie-expand-function '(try-expand-line)))
;;; necessary to c-tags
(setq path-to-ctags "/usr/bin/ctags")
(defun bk/create-tags (dirname)
"Create tags file to a project located at DIRNAME."
(interactive "DDirectory: ")
(shell-command
(format "%s -f TAGS -e -R %s" path-to-ctags
(directory-file-name dirname))))
More instantly better vim
4.- Set column to 100 (I like this idea too)
(setq-default fill-column 100)
- Highlight all the chars that passes that column
(setq whitespace-line-column 100)
- No tabs in the beginning of the l2ines and no trailing spaces
- Highlight tabs and trailing whitespaces
(setq whitespace-style '(trailing tabs tab-mark))
- Remap very frequently commands to more useful ones
- Always think how to improve your current workflow instead of memorizing keys
[My own customizations based on Vim lessons]
5.kill-word
Yet another Emacs M-d
(kill-word)
actually kills the word from the cursor position forward. However, the
defaults of vim makes more sense to me: kill the entire word.
(defun bk/kill-inner-word ()
"Kills the entire word your cursor is in. Equivalent to ciw in vim."
(interactive)
(forward-char 1)
(backward-word)
(kill-word 1))
Bound that to C-c k w
, as C-c
is reserved to user bindings, them k w
is for kill word
.
Copy whole line
The same spirit for the above customization, the copy whole line works despite your position in the current line.
(defun bk/copy-whole-line ()
"Copies a line without regard for cursor position."
(interactive)
(save-excursion
(kill-new
(buffer-substring
(point-at-bol)
(point-at-eol)))))
Bound to C-c y l
meaning y l
yank line
.
Zap commands
I like the idea of the Zap commands. Killing forward up to a defined character, but I missed a kill backward up to
in the same sense, so you can change the direction of the default zap-up-to-char
using the Universal Argument C-u
and a negative arg e.g. C-u -1
.
(defun bk/zap-up-to-char-backward (arg char)
(interactive "p\ncZap up to char backward: ")
(save-excursion
(zap-up-to-char -1 char)))
Bound to C-c k f
and C-c k b
to kill forward
and kill backward
UPDATED: 2020-06-04
You can use this awesome package zzz-to-char which combines
zap-to-char
and avy
so you can proper chose to which character you want to go.
I am using the following bindings:
(global-set-key (kbd "C-c k u") 'zzz-up-to-char)
(global-set-key (kbd "C-c k c") 'zzz-to-char)
Meaning u
to up-to-char
and to-char
. Now, the direction is only controlled by avy
.
Thanks Ian for pointing out.
Change inner
I became very addicted to change-inner Emacs package from Magnars. I made the following bindings:
(global-set-key (kbd "M-i") 'change-inner)
(global-set-key (kbd "M-o") 'change-outer)
If you wanted to change
the text, well done you just did it. If you wanted to copy
the text,
well done you just did it... but you "lost" the text, right? Yeah, just use C-/
to undo and then
C-y
to paste where you want.
Same behaviour is also observed in Vim.
7 Habits for Effective Text Editing 2.0 by Molenaar
6.Selecting a good editor is the first step towards effective text editing.
Three basic steps:
- Detect inefficiency
- Find quicker way
- How to make it a habit
Use more the Emacs Wiki page to find ways to improve your workflow.
6.1. Moving around quickly
- The
*
command is very useful. Emacs:M-s .
- In emacs I also think we should keep using
ace-jump
withC-;
- Make folding a habit. I configured
hs-hide-mode
,C-=
,C-+
,C--
6.2. Don't type anything twice
C-n
autocompletion in Vim...Emacs:C-M-i
(completion),M-/
(dabbrev-expand).omni-completion
in Vim... Emacs:company-mode
6.3. Fix when it's wrong
- Emacs:
flyspell
- Emacs: make more abbreviations. See the functions below that help you out.
(defun bk/add-region-local-abbrev (start end)
"Go from START to END and add the selected text to a local abbrev."
(interactive "r")
(if (use-region-p)
(let ((num-words (count-words-region start end)))
(add-mode-abbrev num-words)
(deactivate-mark))
(message "No selected region!")))
(global-set-key (kbd "C-x a l") 'bk/add-region-local-abbrev)
(defun bk/add-region-global-abbrev (start end)
"Go from START to END and add the selected text to global abbrev."
(interactive "r")
(if (use-region-p)
(let ((num-words (count-words-region start end)))
(add-abbrev global-abbrev-table "Global" num-words)
(deactivate-mark))
(message "No selected region!")))
(global-set-key (kbd "C-x a g") 'bk/add-region-global-abbrev)
You can also define a global table of abbreviations
(define-abbrev-table 'global-abbrev-table
'(
("reuslt" "result" nil 0)
("requier" "require" nil 0)
))
And activate the mode
(add-hook 'prog-mode-hook 'abbrev-mode)
6.4. A file seldom comes alone
When you need move around files in a project.
- Emacs:
projectile
- Learn more CTAGS(?) Seems like
dumb-jump
andxref-find-definitions
is very very good enough to me - Use
grep
in the project to find full usages. Emacs:projectile
-many-many-subcommands
6.5. Let's work together
- Try to use more Emacs to do everything related to text editing
6.6. Text is structured
- Write some small programs to parse desired texts
6.7. Sharpen the saw
- You have to keep on tuning the set of commands you use for your needs.
- Use feedbacks: Learn from your usage.
Summary
Step 1: Detect inefficiency
- Find out what you waste time on Step 2: Find a quicker way
- read on-line help
- read the quick reference, books, etc
- ask friends and colleagues
- search the internet
- do it yourself Step 3: Make it a habit
- do it
- keep on improving