You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
15 KiB
15 KiB
- Editing
- Added functionality
- Save/load
- Platform dependent
- Tramp configuration
- Major modes
- Minor modes/misc
- Navigation/auto-completion
- Look and feel
Editing
IEdit mode
(use-package iedit
:bind ("C-;" . iedit-mode))
Spellcheck
(global-set-key (kbd "C-!") 'ispell-buffer)
Undo tree
(use-package undo-tree
:config
(global-undo-tree-mode))
Added functionality
Multiline sexp with symbol
Jump to symbol, go up list, lispy-multiline. Great for diff-friendly custom
(require 'isearch)
(require 'lispy)
(defun rlbr/multiline-sexp-with-symbol (symbol-name)
(save-excursion
(beginning-of-buffer)
(search-forward-regexp (isearch-symbol-regexp symbol-name))
(backward-up-list)
(lispy-alt-multiline)))
Output matches
Run command for each matching exe and see if output-p is true when fed the command output
(defun rlbr/output-matches (output-matches-p exe args) "locate the executable whose output satisfies output-matches-p when fed args and return the full-path" (let ((exec-path exec-path) (output) (bad) (command-output) (current-exe) (failed)) (while (not (or output failed)) (setq current-exe (executable-find exe)) (if current-exe (progn (setq command-output (shell-command-to-string (format "%s %s" (rlbr/quote-exe current-exe) args))) (if (funcall output-matches-p command-output) (setq output current-exe) (progn (setq bad (replace-regexp-in-string "/$" "" (file-name-directory current-exe))) (setq exec-path (seq-filter (lambda (item) (not (rlbr/case-insensitive-match item bad))) exec-path))))) (setq failed t))) output))
Save buffer-output to file
This handy function is a customized ripoff of custom-save-all
(defun rlbr/save-buffer-func-to-file (visit-file func args)
"Rip off of custom-save-all"
(let* ((filename visit-file)
(recentf-exclude (if recentf-mode
(append
`(,(concat "\\`" (regexp-quote (recentf-expand-file-name visit-file)) "\\'")
,(concat "\\`" (regexp-quote (file-truename (recentf-expand-file-name visit-file))) "\\'"))
recentf-exclude)))
(old-buffer (find-buffer-visiting filename))
old-buffer-name)
(with-current-buffer
(let ((find-file-visit-truename t))
(or old-buffer
(let ((delay-mode-hooks t))
(find-file-noselect filename))))
(when old-buffer
(setq old-buffer-name
(buffer-file-name))
(set-visited-file-name
(file-chase-links filename)))
(unless (eq major-mode
'emacs-lisp-mode)
(delay-mode-hooks
(emacs-lisp-mode)))
(let ((inhibit-read-only t)
(print-length nil)
(print-level nil))
(apply func args))
(let ((file-precious-flag t))
(save-buffer))
(if old-buffer
(progn
(set-visited-file-name
old-buffer-name)
(set-buffer-modified-p nil))
(kill-buffer (current-buffer))))))
Save/load
Backup/auto-save
(let ((backup-dir "~/.emacs.d/backup")
(auto-save-dir "~/.emacs.d/autosave"))
(if (not (file-directory-p backup-dir))
(make-directory backup-dir))
(if (not (file-directory-p
auto-save-dir))
(make-directory auto-save-dir)))
On save
(add-hook 'before-save-hook 'delete-trailing-whitespace)
Recent files mode
(use-package recentf
:config
(recentf-mode 1))
Platform dependent
Windows
(when (string-equal system-type "windows-nt")
(progn
(defun rlbr/quote-exe (path)
(w32-short-file-name path))
(defun rlbr/start-external-shell ()
(interactive)
(start-process-shell-command (format "cmd(%s)" default-directory) nil "start default.bat"))
(global-set-key (kbd "C-S-C") 'rlbr/start-external-shell)
(defun rlbr/start-windows-explorer-here ()
(interactive)
(start-process-shell-command "explorer" nil (format "explorer %s" (replace-regexp-in-string "/" (regexp-quote "\\") (expand-file-name default-directory)))))
(global-set-key (kbd "C-S-E") 'rlbr/start-windows-explorer-here)
(defun rlbr/case-insensitive-match (string1 string2)
(apply 'string-equal (mapcar 'downcase (list string1 string2))))
(let ((find)
(grep)
(ls))
(progn
(setq find
(rlbr/output-matches
(lambda (output) (string-equal ".\n" output))
"find" "-maxdepth 0"))
(if find
(setq find-program (rlbr/quote-exe find)))
(setq grep (rlbr/output-matches
(lambda (output) (string-match "grep (\\w+ grep)" output))
"grep" "-V"))
(if grep
(setq grep-program
(rlbr/quote-exe grep)))
(setq ls (rlbr/output-matches
(lambda (output) (string-match "ls: .*'\\?/': No such file or directory" output))
"ls" "?/"))
(if ls
(setq insert-directory-program (rlbr/quote-exe ls)))))))
Tramp configuration
Tramp append plist to connection properties
(use-package kv
:config
(defun rlbr/add-config-to-tramp (matches-regexp config-plist)
(let ((config-alist (kvplist->alist config-plist)))
(dolist (pair config-alist)
(let ((config (list
matches-regexp
(car pair)
(cdr pair))))
(add-to-list
'tramp-connection-properties
config))))))
Android
(use-package tramp
:config
(let ((android-config (let ((default-directory "/data/data/com.termux/files"))
(list "tmpdir" (expand-file-name "home/temp/")
"remote-shell" (expand-file-name "usr/bin/sh")
"remote-process-environment" (append (list (concat "PREFIX=" default-directory "usr")) tramp-remote-process-environment)
"remote-path" (append (mapcar 'expand-file-name '("home/.local/bin" "usr/bin" "usr/bin/applets")) '("/sbin" "/vendor/bin" "/system/sbin" "/system/bin" "/system/xbin"))))))
(rlbr/add-config-to-tramp "/ssh:termux.*:" android-config)))
Major modes
Java
JavaScript
(use-package js2-mode
:mode "\\.js\\'"
:hook ((js2-mode . js2-imenu-extras-mode)
(js2-mode . (lambda () (add-hook 'xref-backend-functions #'xref-js2-xref-backend nil t))))
:config
(use-package js2-refactor
:hook (js2-mode . js2-refactor-mode)
:bind
(:map js2-mode-map
("C-k" . js2r-kill))
:config
(js2r-add-keybindings-with-prefix "C-c C-r"))
(use-package xref-js2
:demand t)
(define-key js-mode-map (kbd "M-.") nil)
(defun rlbr/jump-to-definition ()
"Jump to a definition."
(interactive)
(condition-case-unless-debug nil
(js2-jump-to-definition)
(error
(progn
(ignore-errors
(xref-pop-marker-stack))
(xref-find-definitions (xref-backend-identifier-at-point (xref-find-backend)))))))
(define-key js-mode-map (kbd "M-.") #'rlbr/jump-to-definition))
Magit
(use-package magit
:bind (("C-x g" . magit-status))
:config
(use-package git-commit
:hook (git-commit-setup . git-commit-turn-on-flyspell)))
Python
Platform specific
(setq elpy-rpc-python-command (cond ((string-equal system-type "gnu/linux") "python3") ((string-equal system-type "windows-nt") "pythonw.exe")))
custom feature
(defun rlbr/split-venv-with-number (name-number)
"Split a virtualenv name with either a ~ seperating the name and the number, or nothing"
(let ((split-result (split-string name-number (regexp-quote "~")))
(ret))
(if (= 1 (length split-result))
(progn
(setq ret (car split-result))
(push 0 ret))
(progn
(setq ret
(string-join
(butlast split-result)
"~"))
(push
(string-to-number
(car (last split-result)))
ret)))
ret))
(defun rlbr/join-venv-with-number (number-name)
"Join a list with a name and a number"
(let
((number (car number-name))
(name (cdr number-name)))
(if (= number 0)
name
(string-join (list name (number-to-string number)) "~"))))
(defun rlbr/get-venv-name (&optional library-root)
"Generate venv name based off of the base-name of the library root"
(file-name-base
(directory-file-name
(if library-root
library-root
(elpy-library-root)))))
(defun rlbr/handle-name-conflicts (venv-name)
"Deal with potential name conflicts in venv"
(let ((venv-conflicts)
(venv-partition-name))
(setq venv-partition-name (rlbr/split-venv-with-number venv-name))
(setq venv-conflicts
(seq-filter
(lambda (item) (string-equal (cdr item) venv-name))
(mapcar #'rlbr/split-venv-with-number (pyvenv-virtualenv-list))))
(when venv-conflicts
(setcar venv-partition-name (1+ (apply 'max (mapcar #'car venv-conflicts)))))
(rlbr/join-venv-with-number venv-partition-name)))
(require 'vc)
(defun rlbr/setup-python-venv-dirlocals (&optional library-root venv-name)
"Setup .dir-locals file in library root and tell vc system to ignore .dir-locals file"
(let* ((library-root (if library-root
library-root
(elpy-library-root)))
(venv-name (if venv-name venv-name (rlbr/get-venv-name library-root)))
(default-directory library-root)
(dir-locals-path (expand-file-name
".dir-locals.el")))
(rlbr/save-buffer-func-to-file dir-locals-path 'add-dir-local-variable
`(python-mode pyvenv-workon ,venv-name))
(let* ((vc-root (vc-find-root dir-locals-path ".git"))
(vc-ignore-file (vc-call-backend 'Git 'find-ignore-file vc-root)))
(if (apply 'string-equal (mapcar 'directory-file-name (mapcar 'file-truename (list vc-root library-root))))
(progn
(unless (file-exists-p vc-ignore-file)
(with-temp-buffer
(write-file vc-ignore-file)))
(vc-ignore ".dir-locals.el"))
(when (y-or-n-p (format "Ignore .dir-locals.el in repo '%s' ?" vc-root))
(unless (file-exists-p vc-ignore-file)
(with-temp-buffer
(write-file vc-ignore-file)))
(vc-ignore ".dir-locals.el"))))))
(defun rlbr/get-python-executable ()
(read-file-name "Python interpreter to use: " (file-name-directory (executable-find "python")) nil nil "python"))
(defun rlbr/init-python-venv-in-library-root (&optional library-root)
"Prompt to either create one or use default"
(let ((venv-name (rlbr/get-venv-name))
(library-root (if library-root
library-root
(elpy-library-root))))
(setq venv-name (rlbr/handle-name-conflicts venv-name))
(if (y-or-n-p (format "Create venv '%s'?" venv-name))
(pyvenv-create venv-name (rlbr/get-python-executable))
(progn
(unless (member "emacs-default-venv" (pyvenv-virtualenv-list))
(pyvenv-create venv-name (rlbr/get-python-executable)))
(setq venv-name "emacs-default-venv")))
(rlbr/setup-python-venv-dirlocals library-root venv-name)
venv-name))
(require 'dash)
(defun rlbr/init-venv ()
(when (eq major-mode 'python-mode)
(unless
(let ((buffer-file-name (file-truename buffer-file-name)))
(-any (lambda (file-prefix) (string-prefix-p file-prefix buffer-file-name))
(mapcar 'file-truename
(list
(elpy-rpc-get-or-create-virtualenv)
(pyvenv-workon-home)))))
(cond
((and pyvenv-workon (not (member pyvenv-workon (pyvenv-virtualenv-list))))
(if (y-or-n-p
(format "Venv '%s' is specified but does not exist. Create it?" pyvenv-workon))
(progn
(pyvenv-create pyvenv-workon (rlbr/get-python-executable))
(pyvenv-workon pyvenv-workon))
(rlbr/save-buffer-func-to-file
(let ((default-directory (elpy-library-root)))
(expand-file-name
".dir-locals.el"))
'add-dir-local-variable
'(python-mode pyvenv-workon "emacs-default-venv"))
(setq-local
pyvenv-workon
"emacs-default-venv")))
((not pyvenv-workon)
(setq-local
pyvenv-workon
(rlbr/init-python-venv-in-library-root))))
(pyvenv-workon pyvenv-workon))))
bindings/settings
(use-package python
:hook ((python-mode . blacken-mode)
(python-mode . pyvenv-mode)
(hack-local-variables . rlbr/init-venv))
:config
(use-package elpy
:bind (("C-=" . elpy-goto-assignment))
:config (when (require 'flycheck nil t)
(setq elpy-modules (delq 'elpy-module-flymake elpy-modules))))
(elpy-enable))
SSH config mode
(use-package ssh-config-mode
:mode "~/.ssh/config\\'")
Tramp
Webmode
(use-package web-mode
:mode
(("\\.phtml\\'" . web-mode)
("\\.tpl\\.php\\'" . web-mode)
("\\.[agj]sp\\'" . web-mode)
("\\.as[cp]x\\'" . web-mode)
("\\.erb\\'" . web-mode)
("\\.mustache\\'" . web-mode)
("\\.djhtml\\'" . web-mode)
("\\.html?\\'" . web-mode)))
YAML
(use-package yaml-mode
:mode "\\.yml\\'")
Minor modes/misc
Kill the things
Buffer
(global-set-key (kbd "C-x k") 'kill-this-buffer)
Emacs
(global-set-key (kbd "C-x C-k C-x C-k") 'kill-emacs)
Lispy
(use-package lispy
:hook ((emacs-lisp-mode) . lispy-mode))
Custom custom
(advice-add 'custom-save-faces :after (lambda () (rlbr/multiline-sexp-with-symbol "custom-set-faces"))) (advice-add 'custom-save-variables :after (lambda () (rlbr/multiline-sexp-with-symbol "custom-set-variables")))
Navigation/auto-completion
Ace window
(use-package ace-window
:bind (("M-Q" . ace-window)))
Hippie expand
(use-package hippie-exp
:bind ("M-/" . hippie-expand))
IBuffer mode
(use-package ibbufer-vc
:hook ((ibuffer-mode . ibuffer-vc-set-filter-groups-by-vc-root)))
(use-package ibuffer
:bind (("C-x C-b" . ibuffer))
:config
(define-ibuffer-column size-h
;; Use human readable Size column instead of original one
(:name "Size" :inline t)
(cond ((> (buffer-size) 1000000)
(format "%7.1fM" (/ (buffer-size) 1000000.0)))
((> (buffer-size) 100000)
(format "%7.0fk" (/ (buffer-size) 1000.0)))
((> (buffer-size) 1000)
(format "%7.1fk" (/ (buffer-size) 1000.0)))
(t
(format "%8d" (buffer-size))))))
Ivy
(use-package ivy
:config
(use-package swiper
:bind ("C-s" . swiper))
(ivy-mode))
Look and feel
Line numbers
(global-display-line-numbers-mode)
Mode line bell
(use-package mode-line-bell
:config
(mode-line-bell-mode))
Spaceline
(use-package spaceline-config
:config
(use-package winum
:init
(setq winum-keymap
(let ((map (make-sparse-keymap)))
(define-key map (kbd "M-0") 'winum-select-window-0-or-10)
(define-key map (kbd "M-1") 'winum-select-window-1)
(define-key map (kbd "M-2") 'winum-select-window-2)
(define-key map (kbd "M-3") 'winum-select-window-3)
(define-key map (kbd "M-4") 'winum-select-window-4)
(define-key map (kbd "M-5") 'winum-select-window-5)
(define-key map (kbd "M-6") 'winum-select-window-6)
(define-key map (kbd "M-7") 'winum-select-window-7)
(define-key map (kbd "M-8") 'winum-select-window-8)
map)))
(spaceline-spacemacs-theme)
(winum-mode))