├── README.md └── init.el /README.md: -------------------------------------------------------------------------------- 1 | If you reached here from [this video](https://www.youtube.com/watch?v=GJ4i10U_zzg), please 2 | see the [version tagged demo](https://github.com/digikar99/emacs-noob/tree/demo). 3 | 4 | *** 5 | 6 | ## Requirements 7 | 8 | Emacs 26 and up! (Due to helm, 25 and up; due to a auto-complete dependency, 26 and up!.) 9 | 10 | ## Installation 11 | 12 | Drop the `init.el` in your `~/.emacs.d/` and (re)start emacs. 13 | 14 | Emacs will download `use-package` and then the required packages. This should take 15 | a few minutes. Restart emacs. 16 | 17 | ## Features 18 | 19 | - Melpa added 20 | - Packages: use-package, tabbar-mode, ace-window, auto-complete, helm, goto-chg 21 | - `C-x` bindings not listed below are bound to nil: In case some exists that is missing below, it is a bug; report them! Known issue is `C-x 8-` key bindings which I've been unable to disable. 22 | - global auto-complete-mode, electric-pair-mode, show-paren-mode, auto-revert-mode, visual-line-mode, linum-mode, column-number-mode, helm-mode 23 | - Slower scroll 24 | 25 | ## Usage Intention 26 | 27 | - Use intended when you are limited to a terminal interface and want a more-or-less familiar interface. The presence of terminal can mess up several keys, for instance `C-g` and `` become equivalent (unless there's a workaround I do not know of!). Another being the response of scroll, forcing the existence of *some* key bindings for scrolling; with that case, *why not keep the default one*? 28 | - Why not *complete* default? Because the default binding of `C-z` would frustrate the new user. There are several other keys. 29 | - If you have access to a full GUI emacs and *do not* want to learn emacs, take a look at [emacs-modern](https://github.com/digikar99/emacs-noob/tree/emacs-modern) branch. 30 | - If you are using emacs to learn Common Lisp and want to delay learning emacs, take a look at 31 | - [slime-company-modern](https://github.com/digikar99/emacs-noob/tree/slime-company-modern) if you have access to GUI emacs 32 | - [slime-company](https://github.com/digikar99/emacs-noob/tree/slime-company) if you do *not* have access to GUI emacs and are stuck to a terminal-only. This intends to keep the bindings of the master branch, and augment them with lisp specific bindings. 33 | 34 | ## Key-bindings 35 | 36 | **Text Editing** 37 | 38 | - C-a: Select all 39 | - C-s [std]: Search (forward); because changing this means changing several other maps 40 | and we don't want to go "too far" from vanilla emacs, so that you get used to it as well 41 | - C-r: Replace (forward); because see C-h next 42 | - C-h (Backspace): Delete word to the left - this is so because on the terminal backspace 43 | and C-h are equivalent. And I haven't searched enough for a workaround. 44 | - C-z: Undo - in emacs, redo is undo of undo; this also avoids loss of redo-undo "trees" 45 | - `C-` [std]: enter/exit text-selection mode 46 | - C-w [std]: Cut; because C-x is complicated 47 | - C-y [std]: Paste; because 48 | - C-v [std]: Scroll down 49 | - M-v [std]: Scroll up 50 | - C-g [std]: Cancel command 51 | - C-k [std]: Cut line this point forward 52 | - M-k: Delete line this point forward 53 | - C-/: Un/comment-line; also works for un/commenting region when selected 54 | - C-l: Goto line 55 | 56 |
57 | 58 | - M-S-/: Move line (selected region) up or down 59 | - C-M-s: Forward search symbol at point 60 | - C-M-r: Forward replace symbol at point 61 | - M-q: Quit emacs (with prompt) 62 | - C-.: Goto last change (useful when one scrolls) 63 | - C-,: Goto last change reverse 64 | 65 | 66 | **Window and Buffer Management** 67 | 68 | - F7: Split window horizontally: "" is more memorable, but its bound to something 69 | in some terminals 70 | - F8: Split window vertically - two parts of the "8" 71 | - F9: Expand window vertically 72 | - F11 [std]: Toggle "frame" full screen 73 | - S-F11: Delete other windows (this, to avoid accidentally pressing "" while 74 | trying to go full screen) 75 | - C-o [~std]: Switch window 76 | - M-o: Switch buffer 77 | 78 | - C-t: Open `*scratch*` buffer 79 | - C-S-t: Reopen closed file 80 | - `C-` / `C-S-`: Switch tabs 81 | - M-x [std]: arbitrary commands (helm-M-x) 82 | - C-x C-f [std]: Open file (helm-find-files) 83 | - C-x C-s [std]: Save file 84 | - C-x C-d [~std]: Open directory. Press '?' for help. (dired) 85 | - C-x C-w: Close file (kill-this-buffer) 86 | - C-x C-r: Rename file (and buffer) 87 | - C-x C-k: Delete this window 88 | 89 | **Miscellaneous** 90 | 91 | - M-h k: Help key 92 | - M-h v: Help variable 93 | - M-h f: Help function 94 | 95 | - M-m: ansi-term switch between line and char modes 96 | - M-n: ansi-term next command 97 | - M-p: ansi-term previous command -------------------------------------------------------------------------------- /init.el: -------------------------------------------------------------------------------- 1 | 2 | ;; Added by Package.el. This must come before configurations of 3 | ;; installed packages. Don't delete this line. If you don't want it, 4 | ;; just comment it out by adding a semicolon to the start of the line. 5 | ;; You may delete these explanatory comments. 6 | (package-initialize) 7 | 8 | (custom-set-variables 9 | ;; custom-set-variables was added by Custom. 10 | ;; If you edit it by hand, you could mess it up, so be careful. 11 | ;; Your init file should contain only one such instance. 12 | ;; If there is more than one, they won't work right. 13 | '(inhibit-startup-screen t) 14 | '(make-backup-files nil) 15 | '(package-selected-packages (quote (goto-chg ace-window auto-complete tabbar helm use-package))) 16 | '(tool-bar-mode nil)) 17 | (custom-set-faces 18 | ;; custom-set-faces was added by Custom. 19 | ;; If you edit it by hand, you could mess it up, so be careful. 20 | ;; Your init file should contain only one such instance. 21 | ;; If there is more than one, they won't work right. 22 | '(tabbar-default ((t (:inherit variable-pitch :background "white smoke" :foreground "black" :height 1.0)))) 23 | '(tabbar-highlight ((t (:background "spring green")))) 24 | '(tabbar-selected ((t (:inherit tabbar-default :background "cyan" :foreground "black" :box (:line-width 1 :color "white" :style pressed-button)))))) 25 | 26 | (prefer-coding-system 'utf-8) 27 | (require 'package) 28 | (add-to-list 'package-archives 29 | '("melpa-stable" . "https://stable.melpa.org/packages/")) 30 | 31 | (unless (package-installed-p 'use-package) 32 | (package-refresh-contents) 33 | (package-install-selected-packages)) 34 | 35 | (use-package helm 36 | :ensure t 37 | :bind (:map helm-map 38 | ("" . helm-execute-persistent-action)) 39 | :bind* (("M-x" . helm-M-x) 40 | ("C-x C-f" . helm-find-files))) 41 | 42 | (use-package tabbar 43 | :bind ((:map tabbar-mode-map 44 | ("" . tabbar-forward-tab) 45 | ("" . tabbar-backward-tab))) 46 | :ensure t 47 | :config 48 | (defun my-tabbar-buffer-groups () ;; customize to show all normal files in one group 49 | "Returns the name of the tab group names the current buffer belongs to. 50 | There are two groups: Emacs buffers (those whose name starts with '*', plus 51 | dired buffers), and the rest. This works at least with Emacs v24.2 using 52 | tabbar.el v1.7." 53 | (list (cond ((string= (buffer-name) "*scratch*") "user") 54 | ((string-equal "*" (substring (buffer-name) 0 1)) "emacs") 55 | (t "user")))) 56 | (setq tabbar-buffer-groups-function 'my-tabbar-buffer-groups)) 57 | 58 | (use-package auto-complete 59 | :ensure t 60 | :bind (:map ac-menu-map 61 | ("C-n" . ac-next) 62 | ("C-p" . ac-previous)) 63 | :config 64 | (setq ac-auto-start 1 65 | ac-auto-show-menu 0.1 66 | ac-use-menu-map t)) 67 | 68 | (use-package term 69 | :bind (:map term-raw-map 70 | ("M-m" . term-line-mode) 71 | ("M-n" . term-send-down) 72 | ("M-p" . term-send-up) 73 | :map term-mode-map 74 | ("M-m" . term-raw-mode) 75 | ("M-n" . term-send-down) 76 | ("M-p" . term-send-up))) 77 | 78 | (use-package ace-window 79 | :ensure t 80 | :config 81 | (setq aw-scope 'frame)) 82 | 83 | (use-package fundamental-mode 84 | 85 | :init 86 | 87 | (defun isearch-query-replace-symbol-at-point () 88 | (interactive) 89 | (isearch-forward-symbol-at-point) 90 | (isearch-query-replace)) 91 | 92 | (defun rename-file-and-buffer (new-name) 93 | "Renames both current buffer and file it's visiting to NEW-NAME." 94 | (interactive "sNew Name: ") 95 | (let ((name (buffer-name)) 96 | (filename (buffer-file-name))) 97 | (if (not filename) 98 | (message "Buffer '%s' is not visiting a file!" name) 99 | (if (get-buffer new-name) 100 | (message "A buffer named '%s' already exists!" new-name) 101 | (progn 102 | (rename-file filename new-name 1) 103 | (rename-buffer new-name) 104 | (set-visited-file-name new-name) 105 | (set-buffer-modified-p nil)))))) 106 | 107 | ;;; C-S-t to restore killed tab 108 | (defvar killed-file-list nil "List of recently killed files, used for restoring them.") 109 | (defun add-file-to-killed-file-list () 110 | (when buffer-file-name 111 | (push buffer-file-name killed-file-list))) 112 | (add-hook 'kill-buffer-hook #'add-file-to-killed-file-list) 113 | (defun reopen-killed-file () 114 | (interactive) 115 | (when killed-file-list 116 | (find-file (pop killed-file-list)))) 117 | 118 | ;;; M-S-up/down to move selected text up and down 119 | (defun move-text-internal (arg) 120 | (cond ((and mark-active transient-mark-mode) 121 | (if (> (point) (mark)) 122 | (exchange-point-and-mark)) 123 | (let ((column (current-column)) 124 | (text (delete-and-extract-region (point) (mark)))) 125 | (forward-line arg) 126 | (move-to-column column t) 127 | (set-mark (point)) 128 | (insert text) 129 | (exchange-point-and-mark) 130 | (setq deactivate-mark nil))) 131 | (t 132 | (beginning-of-line) 133 | (when (or (> arg 0) (not (bobp))) 134 | (forward-line) 135 | (when (or (< arg 0) (not (eobp))) 136 | (transpose-lines arg)) 137 | (forward-line -1))))) 138 | 139 | (defun move-text-down (arg) 140 | "Move region (transient-mark-mode-active) or current-line arg lines down" 141 | (interactive "*p") 142 | (move-text-internal arg)) 143 | 144 | (defun move-text-up (arg) 145 | "Move region (transient-mark-mode-active) or current-line arg lines down" 146 | (interactive "*p") 147 | (move-text-internal (- arg))) 148 | 149 | ;;; C-w only works when region is selected 150 | (defun kill-region-when-active () 151 | (interactive) 152 | (when (region-active-p) 153 | (if (> (point) (mark)) 154 | (exchange-point-and-mark)) 155 | (kill-region (point) (mark)))) 156 | 157 | ;;; M-k 158 | (defun ruthlessly-kill-line () 159 | (interactive) 160 | (delete-char (- (line-end-position) (point)) nil)) 161 | 162 | ;;; Disable key bindings with C-x prefix 163 | (cl-loop for ch below 128 164 | do (global-set-key (kbd (concat "C-x " (string ch))) nil)) 165 | 166 | ;;; FIXME: C-x 8 doesn't set to nil 167 | ;; (cl-loop for ch below 128 168 | ;; do (define-key iso-transl-ctl-x-8-map (kbd (concat "C-x 8 " (string ch))) nil)) 169 | 170 | ;; Source: https://www.reddit.com/r/emacs/comments/4ermj9/how_to_restore_last_window_size_in_emacs/ 171 | ;; Custom functions/hooks for persisting/loading frame geometry upon save/load 172 | (defun save-frameg () 173 | "Gets the current frame's geometry and saves to ~/.emacs.frameg." 174 | (let ((frameg-font (frame-parameter (selected-frame) 'font)) 175 | (frameg-left (frame-parameter (selected-frame) 'left)) 176 | (frameg-top (frame-parameter (selected-frame) 'top)) 177 | (frameg-width (frame-parameter (selected-frame) 'width)) 178 | (frameg-height (frame-parameter (selected-frame) 'height)) 179 | (frameg-file (expand-file-name "~/.emacs.frameg"))) 180 | (with-temp-buffer 181 | ;; Turn off backup for this file 182 | (make-local-variable 'make-backup-files) 183 | (setq make-backup-files nil) 184 | (insert 185 | ";;; This file stores the previous emacs frame's geometry.\n" 186 | ";;; Last generated " (current-time-string) ".\n" 187 | "(setq initial-frame-alist\n" 188 | ;; " '((font . \"" frameg-font "\")\n" 189 | " '(" 190 | (format " (top . %d)\n" (max frameg-top 0)) 191 | (format " (left . %d)\n" (max frameg-left 0)) 192 | (format " (width . %d)\n" (max frameg-width 0)) 193 | (format " (height . %d)))\n" (max frameg-height 0))) 194 | (when (file-writable-p frameg-file) 195 | (write-file frameg-file))))) 196 | 197 | (defun load-frameg () 198 | "Loads ~/.emacs.frameg which should load the previous frame's geometry." 199 | (let ((frameg-file (expand-file-name "~/.emacs.frameg"))) 200 | (when (file-readable-p frameg-file) 201 | (load-file frameg-file)))) 202 | 203 | :bind (("C-a" . mark-whole-buffer) 204 | ("C-s" . isearch-forward) 205 | ("C-M-s" . isearch-forward-symbol-at-point) 206 | ("C-M-r" . isearch-query-replace-symbol-at-point) 207 | ("C-r" . query-replace) 208 | ("C-h" . backward-kill-word) ; also bound to C- in terminal mode! 209 | ("C-z" . undo) 210 | ("C-j" . newline) 211 | ("C-w" . kill-region-when-active) 212 | ("C-y" . yank) 213 | ("C-l" . goto-line) 214 | ("C-/" . comment-line) 215 | ("C-." . goto-last-change) 216 | ("C-," . goto-last-change-reverse) 217 | ("M-k" . ruthlessly-kill-line) 218 | ("C-t" . (lambda () (interactive) (switch-to-buffer "*scratch*"))) 219 | ("C-S-t" . reopen-killed-file)) 220 | :bind* (("M-o" . switch-to-buffer) 221 | ("C-v" . scroll-up) 222 | ("M-v" . scroll-down) 223 | ("C-o" . ace-window) 224 | ("" . split-window-vertically) 225 | ("" . delete-other-windows-vertically) 226 | ("" . split-window-horizontally) 227 | ("S-" . delete-other-windows) 228 | ("" . toggle-frame-fullscreen) 229 | ("C-x C-e" . eval-last-sexp) 230 | ("C-x C-r" . rename-file-and-buffer) 231 | ("C-x C-w" . kill-this-buffer) 232 | ("C-x C-d" . dired) 233 | ("C-x C-k" . delete-window) 234 | ("C-x C-s" . save-buffer) 235 | ("M-h" . help-command) 236 | ("M-q" . save-buffers-kill-emacs) 237 | ("M-S-" . move-text-up) 238 | ("M-S-" . move-text-down))) 239 | 240 | (progn 241 | (put 'upcase-region 'disabled nil) 242 | ;;; Smoother scrolling 243 | (setq mouse-wheel-scroll-amount '(1 ((shift) . 1)) 244 | mouse-wheel-progressive-speed t 245 | mouse-wheel-follow-mouse t 246 | scroll-step 1) 247 | ;;; Save/Load window-geometry 248 | (when window-system 249 | (add-hook 'after-init-hook 'load-frameg) 250 | (add-hook 'kill-emacs-hook 'save-frameg)) 251 | ;;; Enable additional modes 252 | (helm-mode) 253 | (tabbar-mode) 254 | (electric-pair-mode) 255 | (show-paren-mode) 256 | (column-number-mode) 257 | (global-auto-revert-mode t) 258 | (global-auto-complete-mode 1) 259 | (global-linum-mode) 260 | ;;; Confirm 261 | (setq confirm-kill-emacs 'yes-or-no-p)) 262 | --------------------------------------------------------------------------------