* Emacs configuration ** Configure ~use-package~ #+BEGIN_SRC emacs-lisp (unless (package-installed-p 'use-package) (package-refresh-contents) (package-install 'use-package)) (setq use-package-always-ensure t use-package-verbose t) (require 'use-package) #+END_SRC ** Set up my personal keymap I set it up early so I can use it in ~use-package~ calls immediately. #+BEGIN_SRC emacs-lisp (defvar gpolonkai/pers-map (make-sparse-keymap) "My own, personal, keymap!") (define-prefix-command 'gpolonkai/pers-map) (define-key ctl-x-map "t" 'gpolonkai/pers-map) #+END_SRC ** I really don’t want to type more than I really must… #+BEGIN_SRC emacs-lisp (defalias 'yes-or-no-p 'y-or-n-p) #+END_SRC * Set personal information ** Who am I? Where am I? #+BEGIN_SRC emacs-lisp (setq user-full-name "Gergely Polonkai" user-mail-address "gergely@polonkai.eu" calendar-latitude 47.4 calendar-longitude 19.0 calendar-location-name "Budapest, Hungary") #+END_SRC * Add ~lisp/~ to ~load-path~ #+BEGIN_SRC emacs-lisp (add-to-list 'load-path (expand-file-name (convert-standard-filename "lisp/") user-emacs-directory)) #+END_SRC * Custom commands and functions ** Misc text manipulation functions *** Delete the current line #+BEGIN_SRC emacs-lisp (defun gpolonkai/delete-current-line () "Kill the whole line on which point is." (interactive) (beginning-of-line) (kill-line 1)) #+END_SRC *** Duplicate current line #+BEGIN_SRC emacs-lisp (defun gpolonkai/duplicate-line() "Duplicate line at point." (interactive) (save-excursion (move-beginning-of-line 1) (kill-line) (yank) (open-line 1) (forward-line 1) (yank))) #+END_SRC *** Toggle case of character at point Based on [[http://ergoemacs.org/emacs/modernization_upcase-word.html][Xah’s toggle letter case defun version 2015-12-22]] #+BEGIN_SRC emacs-lisp (defun toggle-char-case (arg-move-point) "Toggle the case of the char after point. If prefix argument ARG-MOVE-POINT is non-nil, move point after the char." (interactive "P") (let ((case-fold-search nil)) (cond ((looking-at "[[:lower:]]") (upcase-region (point) (1+ (point)))) ((looking-at "[[:upper:]]") (downcase-region (point) (1+ (point))))) (cond (arg-move-point (right-char))))) #+END_SRC *** Open a new line below Copied from http://whattheemacsd.com/editing-defuns.el-01.html #+BEGIN_SRC emacs-lisp (defun open-line-below () "Open a new line below point." (interactive) (end-of-line) (newline) (indent-for-tab-command)) #+END_SRC *** Open a new line above #+BEGIN_SRC emacs-lisp (defun open-line-above () "Open a new line above point." (interactive) (beginning-of-line) (newline) (forward-line -1) (indent-for-tab-command)) #+END_SRC *** TODO Kill or copy the whole line Got from Xah’s site (TODO is for adding a link here.) #+BEGIN_SRC emacs-lisp (defun æ-kill-or-copy-whole-line (kill) "Kill or copy the whole line point is on. If KILL is non-nil, the line gets killed. Otherwise, it gets just copied to the kill ring." (interactive "P") (if kill (kill-whole-line) (let ((beginning (progn (beginning-of-line) (point))) (end (progn (end-of-line) (point)))) (copy-region-as-kill beginning end)))) #+END_SRC *** Enclose region in a specific character #+BEGIN_SRC emacs-lisp (defun æ-enclose-region (character &optional start end) "Enclose region in CHARACTER. If region is empty, simply inserts CHARACTER two times and moves point between them. If character is present in `insert-pair-alist', this function will enclose region in the corresponding pair. In this case, CHARACTER must be the opening member of the pair." (interactive "cWhat character? \nr") (setq open character close character) (let ((pair (assq character insert-pair-alist))) (if pair (if (nth 2 pair) (setq open (nth 1 pair) close (nth 2 pair)) (setq open (nth 0 pair) close (nth 1 pair))))) (unless (and open close) (setq open character) (setq close character)) (unless (use-region-p) (setq start (point) end (point))) (save-excursion (goto-char end) (insert-char close) (goto-char start) (insert-char open)) (unless (use-region-p) (forward-char))) #+END_SRC *** Convert camelCase to snake_case #+BEGIN_SRC emacs-lisp (defun camel-to-snake-case (arg) "Convert a camel case (camelCase or CamelCase) word to snake case (snake_case). If the prefix argument ARG is non-nil, convert the text to uppercase." (interactive "p") (progn (let ((start (region-beginning)) (end (region-end)) (case-fold-search nil) (had-initial-underscore nil)) (goto-char start) (when (looking-at "_") (setq had-initial-underscore t)) (while (re-search-forward "\\([A-Z]\\)" end t) (replace-match "_\\1") (setq end (1+ end))) (if arg (upcase-region start end) (downcase-region start end)) (goto-char start) (unless had-initial-underscore (delete-char 1))))) #+END_SRC *** Insert two spaces after specific characters #+BEGIN_SRC emacs-lisp (defun org-space-key (&optional arg) "Insert two spaces after a period. ARG will be passed down verbatim to `self-insert-command'" (interactive "p") (when (looking-back "[.!?…]" nil) (call-interactively 'self-insert-command arg)) (call-interactively 'self-insert-command arg)) #+END_SRC *** Fill or unfill a paragraph From http://pages.sachachua.com/.emacs.d/Sacha.html #+BEGIN_SRC emacs-lisp (defun sachachua/fill-or-unfill-paragraph (&optional unfill region) "Fill (or unfill, if UNFILL is non-nil) paragraph (or REGION)." (interactive (progn (barf-if-buffer-read-only) (list (if current-prefix-arg 'unfill) t))) (let ((fill-column (if unfill (point-max) fill-column))) (fill-paragraph nil region))) #+END_SRC *** Swap occurences of strings Copied from http://emacs.stackexchange.com/a/27170/507 #+BEGIN_SRC emacs-lisp (defun so/query-swap-strings (from-string to-string &optional delimited start end) "Swap occurrences of FROM-STRING and TO-STRING. DELIMITED, START, and END are passed down verbatim to `perform-replace'." (interactive (let ((common (query-replace-read-args (concat "Query swap" (if current-prefix-arg (if (eq current-prefix-arg '-) " backward" " word") "") (if (use-region-p) " in region" "")) nil))) (list (nth 0 common) (nth 1 common) (nth 2 common) (if (use-region-p) (region-beginning)) (if (use-region-p) (region-end))))) (perform-replace (concat "\\(" (regexp-quote from-string) "\\)\\|" (regexp-quote to-string)) `(replace-eval-replacement replace-quote (if (match-string 1) ,to-string ,from-string)) t t delimited nil nil start end)) #+END_SRC ** Navigation *** Move to different beginnings of the current line Inspired by Bozhidar Batsov's [[http://emacsredux.com/blog/2013/05/22/smarter-navigation-to-the-beginning-of-a-line/][solution]]. #+BEGIN_SRC emacs-lisp (defun gpolonkai/move-to-beginning-of-line () "Move to different beginnings of the line. These are, in order: - beginning of the visual line if `visual-line-mode' is active, - the first non-whitespace (indentation), - the actual beginning of the line. This function will jump between the first character and the indentation if used multiple times." (interactive) (let ((last-pos (point))) (when visual-line-mode (beginning-of-visual-line)) (when (= (point) last-pos) (back-to-indentation)) (when (= (point) last-pos) (beginning-of-line)) (when (and (eq major-mode 'org-mode) (= (point) last-pos)) (org-beginning-of-line)) (when (= (point) last-pos) (back-to-indentation)))) #+END_SRC *** Move to the different ends of the current line #+BEGIN_SRC emacs-lisp (defun gpolonkai/move-to-end-of-line () "Move to the end of the line. If `visual-line-mode' is active, jump to the end of the visual line first. Then jump to the actual end of the line." (interactive) (let ((last-pos (point))) (when visual-line-mode (end-of-visual-line)) (when (= (point) last-pos) (end-of-line)) (when (and (eq major-mode 'org-mode) (= (point) last-pos)) (org-end-of-line)))) #+END_SRC ** File manipulation *** Rename the current file Copied from http://whattheemacsd.com/file-defuns.el-01.html #+BEGIN_SRC emacs-lisp (defun rename-current-buffer-file () "Renames current buffer and file it is visiting." (interactive) (let ((name (buffer-name)) (filename (buffer-file-name))) (if (not (and filename (file-exists-p filename))) (error "Buffer '%s' is not visiting a file!" name) (let ((new-name (read-file-name "New name: " filename))) (if (get-buffer new-name) (error "A buffer named '%s' already exists!" new-name) (rename-file filename new-name 1) (rename-buffer new-name) (set-visited-file-name new-name) ; TODO: this is suspicious for me… (set-buffer-modified-p nil) (message "File '%s' successfully renamed to '%s'" name (file-name-nondirectory new-name))))))) #+END_SRC *** Delete the current file Copied from http://whattheemacsd.com/file-defuns.el-02.html #+BEGIN_SRC emacs-lisp (defun delete-current-buffer-file () "Remove file connected to current buffer and kill the buffer." (interactive) (let ((filename (buffer-file-name)) (name (buffer-name)) (buffer (current-buffer))) (if (not (and filename (file-exists-p filename))) (kill-buffer buffer) (when (yes-or-no-p "Are you sure you want to remove this file? ") (delete-file filename) (kill-buffer buffer) (message "File '%s' successfully removed" filename))))) #+END_SRC *** Allow reopening the previously closed file #+BEGIN_SRC emacs-lisp (defvar gpolonkai/last-killed-buffer-file-name nil "The last killed buffer. Used by `gpolonkai/kill-this-buffer' and `gpolonkai/undo-buffer-kill'.") (defun gpolonkai/kill-this-buffer () "Kill the current buffer, but save the buffer file name so it can be undone." (interactive) (setq gpolonkai/last-killed-buffer-file-name (buffer-file-name)) (kill-this-buffer)) (defun gpolonkai/undo-buffer-kill () "Undo killing the last buffer. Esentially it visits the file again." (interactive) (if gpolonkai/last-killed-buffer-file-name (progn (find-file gpolonkai/last-killed-buffer-file-name) (setq gpolonkai/last-killed-buffer-file-name nil)) (message "The buffer last killed didn’t visit a file."))) #+END_SRC *** Open this file as another user #+BEGIN_SRC emacs-lisp (defun open-this-file-as-other-user (user) "Edit current file as USER, using `tramp' and `sudo'. If the current buffer is not visiting a file, prompt for a file name." (interactive "sEdit as user (default: root): ") (when (string= "" user) (setq user "root")) (let* ((filename (or buffer-file-name (read-file-name (format "Find file (as %s): " user)))) (tramp-path (concat (format "/sudo:%s@localhost:" user) filename))) (if buffer-file-name (find-alternate-file tramp-path) (find-file tramp-path)))) #+END_SRC *** Open my own ~init.el~ #+BEGIN_SRC emacs-lisp (defun gpolonkai/visit-init-file () "Open the init file." (interactive) (find-file-other-window user-init-file)) #+END_SRC *** Open my Org-mode index file #+BEGIN_SRC emacs-lisp (defun gpolonkai/visit-org-index () "Visit the root of Org-mode notes." (interactive) (find-file-other-window (concat (file-name-as-directory org-directory) "index.org"))) #+END_SRC ** Frame manipulation *** Hidden modeline mode To temporarily hide the mode line. Copied from http://emacs-doctor.com/emacs-strip-tease.html #+BEGIN_SRC emacs-lisp (defvar hidden-mode-line-mode nil) (defvar hide-mode-line nil) (define-minor-mode hidden-mode-line-mode "Minor mode to hide the mode-line in the current buffer." :init-value nil :global nil :variable hidden-mode-line-mode :group 'editing-basics (if hidden-mode-line-mode (setq hide-mode-line mode-line-format mode-line-format nil) (setq mode-line-format hide-mode-line hide-mode-line nil)) (force-mode-line-update) (redraw-display) (when (and (called-interactively-p 'interactive) hidden-mode-line-mode) (run-with-idle-timer 0 nil 'message (concat "Hidden Mode Line Mode enabled. " "Use M-x hidden-mode-line-mode to make mode-line appear.")))) #+END_SRC ** ~c-mode~ related *** Copy the prototype of the current function #+BEGIN_SRC emacs-lisp (defun gpolonkai/copy-func-prototype () "Copy the current function's prototype to the kill ring." (interactive) (save-excursion (beginning-of-defun) (let ((protocopy-begin (point))) (forward-list) (let ((protocopy-end (point))) (kill-ring-save protocopy-begin protocopy-end))))) #+END_SRC ** Programming related *** Check if we are inside a string #+BEGIN_SRC emacs-lisp (defun gpolonkai/prog-in-string-p () "Return t if point is inside a string." (nth 3 (syntax-ppss))) #+END_SRC *** Check if we are inside a comment #+BEGIN_SRC emacs-lisp (defun gpolonkai/prog-in-comment-p () "Return t if point is inside a comment." (nth 4 (syntax-ppss))) #+END_SRC ** ~python-mode~ related *** Add a docstring to the current thing …be it a function, class, or a module #+BEGIN_SRC emacs-lisp (defun gpolonkai/python-add-docstring () "Add a Python docstring to the current thing. If point is inside a function, add docstring to that. If point is in a class, add docstring to that. If neither, add docstring to the beginning of the file." (interactive) (save-restriction (widen) (beginning-of-defun) (if (not (looking-at-p "\\(def\\|class\\) ")) (progn (goto-char (point-min)) (back-to-indentation) (forward-char) (while (gpolonkai/prog-in-comment-p) (forward-line) (back-to-indentation) (forward-char))) (search-forward ":") (while (or (gpolonkai/prog-in-string-p) (gpolonkai/prog-in-comment-p)) (search-forward ":"))) (if (eq 1 (count-lines 1 (point))) (open-line-above) (open-line-below)) (insert "\"\"\"") (open-line-below) (insert "\"\"\"") (open-line-above))) #+END_SRC ** EShell related *** Delete a character, or close ~eshell~ if nothing to delet Copied from https://ryuslash.org/posts/C-d-to-close-eshell.html #+BEGIN_SRC emacs-lisp (defun eshell-C-d () "Either call `delete-char' interactively or quit." (interactive) (condition-case err (call-interactively #'delete-char) (error (if (and (eq (car err) 'end-of-buffer) (looking-back eshell-prompt-regexp nil)) (kill-buffer) (signal (car err) (cdr err)))))) #+END_SRC ** ~idm~ (ID manager) related functions *** Get specific fields from a record in ~idm~ #+BEGIN_SRC emacs-lisp (defun gpolonkai/idm-record-get-field (record field) "Get FIELD of an id-manager RECORD." (let ((funcname (intern (concat "idm-record-" (symbol-name field))))) (when (fboundp funcname) (funcall funcname record)))) (defun gpolonkai/idm-get-field-for-account (account field) "Get id-manager password for ACCOUNT." (let ((db (idm-load-db)) (lookup-record nil)) (dolist (record (funcall db 'get-all-records) password) (when (string= account (idm-record-name record)) (setq lookup-record (gpolonkai/idm-record-get-field record field)))) lookup-record)) (defmacro gpolonkai/idm-get-password-for-account (account) `(gpolonkai/idm-get-field-for-account ,account 'password)) (defmacro gpolonkai/idm-get-id-for-account (account) `(gpolonkai/idm-get-field-for-account ,account 'account-id)) #+END_SRC * UI preferences ** Tweak window chrome Turn off the scroll bar (that’s why Nyan-cat is here), the toolbar (I don’t really use it), and the menu bar (I rarely use it, and in those rare occasions I can simply turn it on.) Also, maximise the frame. #+BEGIN_SRC emacs-lisp (tool-bar-mode 0) (menu-bar-mode 0) (when window-system (scroll-bar-mode -1)) (set-frame-parameter nil 'fullscreen 'maximized) #+END_SRC ** Set the default font and configure font resizing #+BEGIN_SRC emacs-lisp (set-face-attribute 'default t :font "Hack-10") (set-frame-font "Hack-10" nil t) #+END_SRC * Set up global minor modes provided by Emacs ** Pretty lambdas Because we can. #+BEGIN_SRC emacs-lisp (global-prettify-symbols-mode t) #+END_SRC * ~use-package~ packages ** Highlight the current line #+BEGIN_SRC emacs-lisp (use-package hl-line :config (when window-system (global-hl-line-mode))) #+END_SRC ** Hide certain modes from the mode line #+BEGIN_SRC emacs-lisp (use-package diminish :defer t) #+END_SRC