This repo has been deprecated and moved to https://github.com/jeremygooch/jeremacs.
- Update variables for local setup
- ripgrep (rg) for better grep
- node for JS cli, recommend nvm for managing versions
- Typescript server
- Angular Language Server
- Use Package cloned to .emacs.d
- eslint:
npm i -g eslint
- html support:
npm install -g vscode-html-languageserver-bin
- Roboto and Inconsolata fonts
- Latex (for some notes)
In Emacs >= 27.1, the early-init.el file is run before the GUI is created. This can be used to take care of a few miscellaneous odds and ends.
;; -*- lexical-binding: t; -*-
;; -------------------------------------------------------------------------------- ;;
;; This early-init.el file was auto-tangled from an orgmode file. ;;
;; -------------------------------------------------------------------------------- ;;
;; Garbage Collections
(setq gc-cons-threshold 100000000) ;; ~100mb
(setq read-process-output-max 3000000) ;; ~3mb
(setq gc-cons-percentage 0.6)
;; Compile Warnings
(setq comp-async-report-warnings-errors nil) ;; native-comp warning
(setq byte-compile-warnings '(not free-vars unresolved noruntime lexical make-local))
;; Whether to make packages available when Emacs starts
(setq package-enable-at-startup nil)
;; Disables bi-directional editing (i.e. writing in both Arabic and English)
(setq-default bidi-display-reordering 'left-to-right
bidi-paragraph-direction 'left-to-right)
(setq bidi-inhibit-bpa t) ; emacs 27 only - disables bidirectional parenthesis
;; Misc UI optimizations
(setq fast-but-imprecise-scrolling t)
(setq inhibit-compacting-font-caches t)
;; Slow down the UI updates a bit
(setq idle-update-delay 1.0)
Header of tangled output
;; -*- lexical-binding: t; -*-
;;;
;;; Jeremy's Emacs Configuration
;;;
;; Copyright (C) Jeremy Gooch
;; Author: Jeremy Gooch <jeremy.gooch@gmail.com>
;; URL: https://github.com/jeremygooch/dotemacs
;; This file is not part of GNU Emacs.
;; This file is free software.
;; ------- The following code was auto-tangled from an Orgmode file. ------- ;;
For the sake of completeness, configure name and email address
(setq user-full-name "Jeremy Gooch"
user-mail-address "jeremy.gooch@gmail.com")
Setup a prefix for custom commands.
(progn (define-prefix-command 'jrm-key-map))
(global-set-key (kbd "C-x C-j") jrm-key-map)
(require 'package)
(setq package-archives '(
("melpa-stable" . "http://stable.melpa.org/packages/")
("elpa" . "https://elpa.gnu.org/packages/")
("gnu" . "http://elpa.gnu.org/packages/")
("melpa" . "https://melpa.org/packages/")))
(package-initialize)
(eval-when-compile
(require 'use-package))
(require 'use-package-ensure)
(setq use-package-always-ensure t)
(setq use-package-verbose nil)
;; Allow use-package to install missing system packages
(use-package use-package-ensure-system-package :ensure t)
(use-package gcmh
:diminish gcmh-mode
:config
(setq gcmh-idle-delay 5
gcmh-high-cons-threshold (* 16 1024 1024)) ; 16mb
(gcmh-mode 1))
(add-hook 'emacs-startup-hook
(lambda ()
(setq gc-cons-percentage 0.1))) ;; Default value for `gc-cons-percentage'
Make sure to copy to ~/.emacs.d
(load (expand-file-name "jrm-variables.el" user-emacs-directory))
(if (file-exists-p "~/.emacs.d/jrm-util.el") (load "~/.emacs.d/jrm-util.el"))
(if (file-exists-p "~/.emacs.d/tf.el") (load "~/.emacs.d/tf.el"))
(setq exec-path (append exec-path '("/usr/local/bin")))
(use-package exec-path-from-shell
:init
(exec-path-from-shell-initialize))
;; (setq exec-path (cons (expand-file-name (concat *node-dir* "sass")) exec-path))
(setq exec-path (append exec-path '("/usr/local/git/bin")))
(setq exec-path (append exec-path (list (concat *node-dir* "bin/"))))
;; (setq exec-path (append exec-path (list *deno-dir*)))
;; (setq exec-path (cons (expand-file-name (concat *node-dir* "sass")) exec-path))
;; (setenv "PATH" (concat (getenv "PATH") ":/usr/local/git/bin"))
(setenv "PATH" (concat (getenv "PATH") (concat ":" *node-dir* "bin/")))
Setup a prefix for my custom commands.
(progn (define-prefix-command 'jrm-key-map))
(global-set-key (kbd "C-x C-j") jrm-key-map)
I prefer emacs to just ask y/n not yes/no
(fset 'yes-or-no-p 'y-or-n-p)
When killing a buffer always pick the current buffer by default
(defun kill-current-buffer ()
"Kills the current buffer."
(interactive)
(kill-buffer (current-buffer)))
(global-set-key (kbd "C-x k") 'kill-current-buffer)
Prevent async shell command buffers from popping-up:
(add-to-list 'display-buffer-alist
'("\\*Async Shell Command\\*.*" display-buffer-no-window))
Fix emacs’ regex
(setq-default pcre-mode t)
Use aspell for Mac (aspell can be installed with brew)
(setq ispell-program-name "/usr/local/bin/aspell")
Silence alarms
(setq ring-bell-function 'ignore)
(save-place-mode 1)
Some basic Dired setup
(global-auto-revert-mode 1)
(setq global-auto-revert-non-file-buffers t)
(setq auto-revert-verbose nil)
(setq dired-listing-switches "-alh")
It’s nice to be able to tab through directories in dired, and I’m a sucker for eye candy with icons
(defun jrm/dired-subtree-toggle-and-refresh ()
"Calls dired toggle and refreshes the buffer."
(interactive)
(dired-subtree-toggle)
(revert-buffer))
(use-package dired-subtree
:after dired
:config
(bind-key "<tab>" #'jrm/dired-subtree-toggle-and-refresh dired-mode-map)
(bind-key "<backtab>" #'dired-subtree-cycle dired-mode-map))
(use-package all-the-icons-dired)
(add-hook 'dired-mode-hook 'all-the-icons-dired-mode)
Allow uncompressing zip files
(eval-after-load "dired-aux"
'(add-to-list 'dired-compress-file-suffixes
'("\\.zip\\'" ".zip" "unzip")))
(use-package tramp :config (setq tramp-default-method "scp"))
Use ripgrep by default
(use-package rg
:config
(rg-define-search work
:flags ("--hidden -g '!e2e/'")))
(global-set-key (kbd "C-x C-b") 'ibuffer)
(setq ibuffer-saved-filter-groups
(quote (("default"
("dired" (mode . dired-mode))
("org" (mode . org-mode))
("shell" (mode . shell-mode))
("git" (name . "^magit\*"))
("Slack" (or (mode . slack-mode)
(name . "^\\*Slack.*$")))
("email" (name . "^\\*mu4e-.*\\*$"))
("ecmascript" (or (mode . javascript-mode)
(name . "^.*.js$")
(name . "^.*.ts")
(name . "^.*.json$")))
("markup" (or (mode . web-mode)
(name . "^.*.tpl")
(name . "^.*.mst")
(name . "^.*.html")))
("images" (name . "^.*png$"))
("process" (or (mode . grep-mode)
(name . "^\\*tramp*$")))
("emacs" (or (name . "^\\*scratch\\*$")
(name . "^\\*Messages\\*$")
(name . "^\\*eww\\*$")
(name . "^\\*GNU Emacs\\*$")))))))
(add-hook 'ibuffer-mode-hook (lambda () (ibuffer-switch-to-saved-filter-groups "default")))
Instead of using the display’s popup, prompt for gpg creds in the minibuffer
(setq epa-pinentry-mode 'loopback)
Generic auto-complete with Ivy which
(use-package ivy :demand
:diminish ivy-mode
:config
(setq ivy-use-virtual-buffers t
ivy-count-format "%d/%d ")
(global-set-key (kbd "C-x b") 'ivy-switch-buffer))
(ivy-mode 1)
(setq ivy-use-selectable-prompt t)
(use-package ivy-prescient
:config (ivy-prescient-mode))
Ivy enhanced search (swiper) and common Emacs meta commands (counsel)
(use-package counsel
:config
(global-set-key (kbd "M-x") 'counsel-M-x)
(global-set-key (kbd "C-M-SPC") 'counsel-git))
(use-package swiper
:config
(global-set-key (kbd "C-s") 'swiper-isearch))
Some quick help for when I get stuck in the middle of a command
(use-package which-key :config (which-key-mode))
Keep temporary and backup buffers out of current directory like a civilized human being.
(custom-set-variables
'(auto-save-file-name-transforms '((".*" "~/.emacs.d/autosaves/\\1" t)))
'(backup-directory-alist '((".*" . "~/.emacs.d/backups/")))
'(delete-old-versions t))
(make-directory "~/.emacs.d/autosaves/" t)
(setq create-lockfiles nil)
Replace region with next keystroke.
(delete-selection-mode 1)
Disable bidirectional editing for performance issues when opening large files.
(setq bidi-paragraph-direction 'left-to-right)
(use-package yasnippet
:init (setq yas-snippet-dirs
'("~/src/dotemacs/snippets"))
:config (yas-global-mode))
Easier paragraph jumping
(global-set-key (kbd "M-p") 'backward-paragraph)
(global-set-key (kbd "M-n") 'forward-paragraph)
Avy is great for speed-of-thought navigation
(use-package avy)
(global-set-key (kbd "M-s") 'avy-goto-char-timer)
(global-set-key (kbd "C-c SPC") 'avy-goto-line)
Turn on linum mode for almost everything.
(global-set-key (kbd "C-c l l") 'display-line-numbers-mode)
Adjust the local mark ring pop key sequence, so after pressing `C-u C-SPC`, you can just press `C-SPC` to keep jumping.
(setq set-mark-command-repeat-pop t)
Setup basic editorconfig plugin for closer integration with other tools
(use-package editorconfig
:ensure t
:config
(editorconfig-mode 1))
(use-package lsp-mode
:hook (typescript-mode . lsp)
:hook (javascript-mode . lsp)
:hook (js2-mode . lsp)
:hook (html-mode . lsp)
:hook (scss-mode . lsp)
:hook (sass-mode . lsp)
:hook (css-mode . lsp)
:hook (web-mode . lsp)
:hook (clojure-mode . lsp)
:commands lsp
:bind (("M-." . lsp-find-definition))
:bind (("M-n" . forward-paragraph))
:bind (("M-p" . backward-paragraph))
:config
(dolist (m '(clojure-mode
clojurec-mode
clojurescript-mode
clojurex-mode))
(add-to-list 'lsp-language-id-configuration `(,m . "clojure")))
:config
(with-eval-after-load 'lsp-mode
(add-to-list 'lsp-file-watch-ignored-directories "[/\\\\]\\test\\'")))
;; optionally
(use-package lsp-ui :commands lsp-ui-mode)
(use-package helm-lsp :commands helm-lsp-workspace-symbol)
(use-package lsp-treemacs :commands lsp-treemacs-errors-list)
;; optionally if you want to use debugger
(use-package dap-mode)
;; (global-set-key (kbd "M-p") 'backward-paragraph)
(define-key lsp-signature-mode-map (kbd "M-p") 'backward-paragraph)
(define-key lsp-signature-mode-map (kbd "M-n") 'forward-paragraph)
;; (global-set-key (kbd "M-n") 'forward-paragraph)
(setq lsp-eslint-unzipped-path (concat *node-dir* "bin"))
Lsp Mode Performance adjustments (see https://emacs-lsp.github.io/lsp-mode/page/performance/).
;; (setq gc-cons-threshold 100000000)
;; (setq read-process-output-max 3000000) ;; ~3mb
(setq lsp-idle-delay 1)
(setq lsp-html-server-command (quote ((concat *node-dir* "bin/html-languageserver") "--stdio")))
(setq lsp-clients-angular-language-server-command (quote
("node"
"/home/jrm/.nvm/versions/node/v16.13.2/lib/node_modules/@angular/language-server"
"--ngProbeLocations"
"/home/jrm/.nvm/versions/node/v16.13.2/lib/node_modules"
"--tsProbeLocations"
"/home/jrm/.nvm/versions/node/v16.13.2/lib/node_modules"
"--stdio")))
(defun jrm/lsp-clear-blacklist () "Clears the blacklist folders for LSP Mode"
(interactive)
(setf (lsp-session-folders-blacklist (lsp-session)) nil)
(lsp--persist-session (lsp-session)))
Dap is used for debugging in browser(s). More information at: https://emacs-lsp.github.io/lsp-mode/tutorials/reactjs-tutorial/
;; (require 'dap-chrome)
(require 'dap-node)
(defun jrm/dap-node-stop-all ()
"Kill all background node processes running in inspect"
(interactive)
(dap-delete-all-sessions)
(async-shell-command "kill `ps -A | grep 'inspect-brk' | awk '{print $1}'`"))
Paredit for maintaining sanity while working with lisp
(defun paredit-enable-modes () (add-hook 'emacs-lisp-mode-hook 'paredit-mode))
(use-package paredit :config (paredit-enable-modes))
Some general settings for lisp dialects (elisp, clojure, etc).
(autoload 'enable-paredit-mode "paredit" "Turn on pseudo-structural editing of Lisp code." t)
(add-hook 'emacs-lisp-mode-hook #'enable-paredit-mode)
(add-hook 'eval-expression-minibuffer-setup-hook #'enable-paredit-mode)
(add-hook 'ielm-mode-hook #'enable-paredit-mode)
(add-hook 'lisp-mode-hook #'enable-paredit-mode)
(add-hook 'lisp-interaction-mode-hook #'enable-paredit-mode)
(add-hook 'scheme-mode-hook #'enable-paredit-mode)
(add-hook 'clojure-mode-hook #'enable-paredit-mode)
Make evaluating elisp buffers even quicker
(global-set-key (kbd "C-c C-e") 'eval-buffer)
Clojure with Cider for interactive Clojure development
(use-package clojure-mode
:defer
:config
(add-to-list 'auto-mode-alist '("\\.edn$" . clojure-mode))
(add-to-list 'auto-mode-alist '("\\.boot$" . clojure-mode))
(add-to-list 'auto-mode-alist '("\\.cljs.*$" . clojure-mode))
(add-to-list 'auto-mode-alist '("lein-env" . enh-ruby-mode)))
(use-package eldoc :diminish eldoc-mode)
(use-package cider
:defer
:config
(add-hook 'cider-repl-mode-hook #'eldoc-mode)
(setq cider-repl-pop-to-buffer-on-connect t) ;; go to the repl when done connecting
(setq cider-show-error-buffer t)
(setq cider-auto-select-error-buffer t)) ;; jump to error message
A popup HSV color picker is helpful for quick prototyping/sketching
(defun convert-range-360 (val)
"Converts a value from a 0-1 range to 0-360 range. Used for calculating hue."
(* (/ (- val 0) (- 1 0)) (+ (- 360 0) 0)))
(defun jrm/insert-color-hsb ()
"Select a color and insert its hue/saturation/brightness[lumenosity] format."
(interactive "*")
(let ((buf (current-buffer)))
(custom-set-variables '(list-colors-sort (quote hsv)))
(list-colors-display
nil nil `(lambda (name)
(interactive)
(quit-window)
(with-current-buffer ,buf
(setq hsb (apply 'color-rgb-to-hsl (color-name-to-rgb name)))
(setq hue (convert-range-360 (nth 0 hsb)))
(setq sat (* 100 (nth 1 hsb)))
(insert (format "%s" hue 100) " " (format "%s" sat) " " (format "%s" 100.0)))))))
(global-set-key (kbd "C-x C-j H") 'jrm/insert-color-hsb)
Tern is a require package and can be installed with sudo npm install -g tern
Some basic code folding
(use-package yafolding
:hook ((js-mode . yafolding-mode)
(js2-mode . yafolding-mode)
(typescript-mode . yafolding-mode)
(fundamental-mode . yafolding-mode)))
Use js2 mode rather than the built in javascript mode.
(use-package js2-mode
:defer
:init
(add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
(add-to-list 'auto-mode-alist '("\\.mjs\\'" . js2-mode)))
(bind-keys*
("M-." . lsp-find-definition))
Setup ECMA unicode glyphs
(defun jrm/ecma-prettify-symbols ()
"Adds common ECMA symobls to prettify-symbols-alist."
(push '(">=" . ?≥) prettify-symbols-alist)
(push '("=>" . ?⇒) prettify-symbols-alist)
(push '("<=" . ?≤) prettify-symbols-alist)
(push '("===" . ?≡) prettify-symbols-alist)
(push '("!=" . ?≠) prettify-symbols-alist)
(push '("!==" . ?≢) prettify-symbols-alist)
(push '("&&" . ?∧) prettify-symbols-alist)
(prettify-symbols-mode))
(add-hook 'js2-mode-hook 'jrm/ecma-prettify-symbols)
(add-hook 'js-mode-hook 'jrm/ecma-prettify-symbols)
Web Beautify for unminifying assets
(use-package web-beautify)
(custom-set-variables
'(flycheck-javascript-eslint-executable (concat *eslint-dir* "eslint.js")))
(use-package flycheck :diminish flycheck-mode)
Enable typescript frameworks for just typescript and prototype
(setq typescript-enabled-frameworks '(typescript prototype))
Rjsx for JSX
(use-package rjsx-mode
:config (add-to-list 'auto-mode-alist '("src/elfeed-web-react/.*\\.js\\'" . rjsx-mode)))
Add prettier support. Assumes prettier is installed globally.
(defun prettier-before-save ()
"Add this to .emacs to run refmt on the current buffer when saving:
(add-hook 'before-save-hook 'prettier-before-save)."
(interactive)
(when (member major-mode '(js-mode js2-mode)) (prettier)))
(add-hook 'before-save-hook 'prettier-before-save)
Add ECMA unicode glyphs that I like
(add-hook 'typescript-mode-hook 'jrm/ecma-prettify-symbols)
Quick hack to show/hide import statements for JS/TS
(defcustom jrm/imports-placeholder-content "[imports...]"
"Text to show in place of a folded block."
:tag "Ellipsis"
:type 'string
:group 'jrmhideimports)
(defvar import-mark-fringe nil)
(defun jrm/add-import-mark-fringe ()
(interactive)
(let ((s (make-string 1 ?x)))
(when import-mark-fringe (delete-overlay import-mark-fringe))
(setq import-mark-fringe (make-overlay (point) (1+ (point))))
(put-text-property 0 1 'display '(left-fringe right-triangle) s)
(overlay-put import-mark-fringe 'before-string s)))
(defun jrm/remove-import-mark-fringe ()
(interactive)
(when import-mark-fringe (delete-overlay import-mark-fringe)))
(defun jrm/imports-placeholder ()
"Return propertized ellipsis content."
(concat " "
(propertize jrm/imports-placeholder-content 'face 'font-lock-comment-face)
" "))
(defun jrm/jsts-hide-imports ()
"Hide standard imports based on regex for standard JS/TS imports of multiple modules"
(let ((final-location (point)))
(funcall (lambda () "Use regex to hide the imports"
(end-of-buffer)
(search-backward-regexp "from[[:space:]\.].*;")
(next-line)
(set-mark-command nil)
(jrm/add-import-mark-fringe)
(beginning-of-buffer)
(let ((new-overlay (make-overlay (region-beginning) (region-end))))
(overlay-put new-overlay 'invisible t)
(overlay-put new-overlay 'intangible t)
(overlay-put new-overlay 'evaporate t)
(overlay-put new-overlay 'before-string (jrm/imports-placeholder))
(overlay-put new-overlay 'category "hide-js-imports"))
;; (next-line)
;; (beginning-of-buffer)
(goto-char final-location)
(pop-mark)
;; (next-line)
(message "Imports hidden")))))
(defun jrm/has-import-overlay ()
"Finds any matching overlays"
(mapcar (lambda (overlay)
(and (member "hide-js-imports" (overlay-properties overlay)) overlay))
(overlays-in (point-min) (point-max))))
(defun jrm/jsts-show-imports ()
"Show module imports"
(mapcar 'delete-overlay (delq nil (jrm/has-import-overlay)))
(jrm/remove-import-mark-fringe))
(defun jrm/jsts-toggle-imports ()
"Show/Hide standard module import code"
(interactive)
(if (delq nil (jrm/has-import-overlay))
(jrm/jsts-show-imports)
(jrm/jsts-hide-imports)))
Defining custom indentation based on project paths and setting them to functions that I can call as needed.
(defun jrm/setup-indent (n)
(setq indent-tabs-mode nil)
(setq-local c-basic-offset n)
(setq-local javascript-indent-level n)
(setq-local js-indent-level n)
(setq-local typescript-indent-level n)
(setq-local web-mode-markup-indent-offset n)
(setq-local web-mode-css-indent-offset n)
(setq-local web-mode-code-indent-offset n)
(setq-local sass-indent-offset n)
(setq-local css-indent-offset n))
(defun jrm/two-space-code-style ()
"indent 2 spaces width"
(interactive)
(message "Using 2 spaces coding style")
(jrm/setup-indent 2))
(defun jrm/four-space-code-style ()
"indent 4 spaces width"
(interactive)
(message "Using 4 spaces coding style")
(jrm/setup-indent 4))
(add-hook 'typescript-mode-hook 'jrm/four-space-code-style)
(add-hook 'lua-mode-hook 'jrm/four-space-code-style)
(add-hook 'web-mode-hook 'jrm/four-space-code-style)
(add-hook 'js-mode-hook 'jrm/four-space-code-style)
(add-hook 'js2-mode-hook 'jrm/four-space-code-style)
(add-hook 'sass-mode-hook 'jrm/four-space-code-style)
(add-hook 'scss-mode-hook 'jrm/four-space-code-style)
(add-hook 'typescript-mode-hook 'jrm/two-space-code-style)
(add-hook 'lua-mode-hook 'jrm/two-space-code-style)
(add-hook 'web-mode-hook 'jrm/two-space-code-style)
(add-hook 'json-mode-hook 'jrm/two-space-code-style)
(add-hook 'js2-mode-hook 'jrm/two-space-code-style)
;; (add-hook 'typescript-mode-hook 'jrm/develop-environment)
;; (add-hook 'lua-mode-hook 'jrm/develop-environment)
;; (add-hook 'web-mode-hook 'jrm/develop-environment)
;; (add-hook 'json-mode-hook 'jrm/neon-code-style)
(use-package sass-mode
:config
(add-to-list 'auto-mode-alist '("\\.scss\\'" . scss-mode)))
(use-package web-mode
:config
(add-to-list 'auto-mode-alist '("\\.phtml\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.html\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.tpl\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.mst\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.tpl\\.php\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.[agj]sp\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.as[cp]x\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.erb\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.mustache\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.djhtml\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.hbs\\'" . web-mode))
:custom (web-mode-enable-auto-indentation nil))
Quick utility for converting rems to px using base 16
(defun jrm/rem-to-px () "" (interactive)
(let (n) (setq n (read-number "Enter REM value: "))
(message "%spx" (* 16 n))))
(use-package php-mode
:defer
:config
(autoload 'php-mode "php-mode-improved" "Major mode for editing php code." t)
(add-to-list 'auto-mode-alist '("\\.php$" . php-mode))
(add-to-list 'auto-mode-alist '("\\.inc$" . php-mode)))
Various modes helpful for development
(use-package yaml-mode
:defer
:config (add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode)))
(use-package restclient :defer)
(use-package groovy-mode :defer)
(use-package go-mode :defer)
(use-package emmet-mode
:defer
:config
(add-hook 'sgml-mode-hook 'emmet-mode)
(add-hook 'css-mode-hook 'emmet-mode)
(add-hook 'web-mode-hook 'emmet-mode)
(add-hook 'sass-mode-hook 'emmet-mode))
Magit for version control
(use-package magit
:config
(global-set-key (kbd "C-x g") 'magit-status)
(add-hook 'magit-status-sections-hook 'magit-insert-stashes))
;; Getting an alist-void error when running magit commands that refresh the buffer. Narrowed down to this variable so turning off for now
(setq magit-section-cache-visibility nil)
(use-package company
:after lsp-mode
:hook (prog-mode . company-mode)
:config
(setq company-minimum-prefix-length 2)
(setq company-idle-delay 0.2))
(global-company-mode)
(global-set-key (kbd "TAB") #'company-indent-or-complete-common)
;;(setq tab-always-indent 'complete)
(setq company-tooltip-align-annotations t)
(use-package company-box
:hook (company-mode . company-box-mode))
(defun jrm/modus-operandi_extra-adjustments (theme)
"Updates additional colors and such based on the current modus theme"
(let ((isOperandi (string-equal theme "operandi")))
(if isOperandi
(custom-set-faces
'(org-block ((t (:inherit shadow :extend t :background "gray83"))))
'(org-block-begin-line ((t (:extend t :background "gray95" :foreground "gray59" :height 0.9))))
'(org-block-end-line ((t (:extend t :background "gray95" :foreground "gray59" :height 0.9)))))
(custom-set-faces
'(org-block ((t (:inherit shadow :extend t :background "gray20"))))
'(org-block-begin-line ((t (:extend t :background "gray11" :foreground "dim gray" :height 0.9))))
'(org-block-end-line ((t (:extend t :background "gray11" :foreground "dim gray" :height 0.9))))))
(if isOperandi
(setq dashboard-startup-banner (concat *dotemacs-dir* "assets/Lambda_light.png"))
(setq dashboard-startup-banner (concat *dotemacs-dir* "assets/Lambda_dark.png")))
;
; (if isOperandi
;; (set-face-background hl-line-face "LightSteelBlue1")
;; (set-face-background hl-line-face "#040e17"))
))
(defun jrm/modus-themes-toggle () ""
(interactive)
(pcase (modus-themes--current-theme)
('modus-operandi (jrm/modus-operandi_extra-adjustments "operandi"))
('modus-vivendi (jrm/modus-operandi_extra-adjustments "vivendi"))
(_ (message "No modus theme enabled"))))
(use-package modus-themes
:ensure
:init
;; Add all your customizations prior to loading the themes
(setq modus-themes-italic-constructs nil
modus-themes-bold-constructs t
modus-themes-mode-line '(borderless)
modus-themes-paren-match '(bold intense underline)
modus-themes-region '(bg-only))
;; Load the theme files before enabling a theme
;; (modus-themes-load-themes)
;; Enable personal customizations after loading a modus theme
(add-hook 'modus-themes-after-load-theme-hook 'jrm/modus-themes-toggle)
:config
;; Load the theme of your choice:
(load-theme 'modus-operandi :no-confirm) ;; (load-theme 'modus-vivendi)
:bind ("<f5>" . modus-themes-toggle))
Remove default scrollbars
(scroll-bar-mode -1)
Hide the default toolbars
(menu-bar-mode -1)
(tool-bar-mode -1)
I prefer to see trailing whitespace but not for every mode (e.g. org, elfeed, etc)
(use-package whitespace
:config
(setq-default show-trailing-whitespace t)
(defun no-trailing-whitespace ()
(setq show-trailing-whitespace nil))
(add-hook 'minibuffer-setup-hook 'no-trailing-whitespace)
(add-hook 'dashboard-mode-hook 'no-trailing-whitespace)
(add-hook 'eww-mode-hook 'no-trailing-whitespace)
(add-hook 'vterm-mode-hook 'no-trailing-whitespace)
(add-hook 'shell-mode-hook 'no-trailing-whitespace)
(add-hook 'mu4e:view-mode-hook 'no-trailing-whitespace)
(add-hook 'eshell-mode-hook 'no-trailing-whitespace)
(add-hook 'help-mode-hook 'no-trailing-whitespace)
(add-hook 'term-mode-hook 'no-trailing-whitespace)
(add-hook 'slack-message-buffer-mode-hook 'no-trailing-whitespace)
(add-hook 'mu4e:view-mode-hook 'no-trailing-whitespace)
(add-hook 'calendar-mode-hook 'no-trailing-whitespace))
Use visual line mode for text wrapping
(global-visual-line-mode t)
;; function to switch background color
(defun buffer-background-switch ()
(interactive)
(setq buffer-face-mode-face `(:background "#0a1310" :foreground "#218352"))
(custom-set-faces '(comint-highlight-prompt ((t (:inherit minibuffer-prompt :foreground "#2cc46c")))))
(buffer-face-mode 1))
(add-hook 'shell-mode-hook 'buffer-background-switch)
(add-hook 'eshell-mode-hook 'buffer-background-switch)
Set Org mode source block background color to dark gray so it stands out from the typical background
(custom-set-faces '(org-block ((t (:inherit shadow :background "gray83")))))
I commonly use org for db management so adding a quick way to shrink tables
(defun jrm/set-org-table-column-widths ()
"This adds a row after the current Org Table row with a width cookie for each column"
(interactive)
(let ((new-width (read-string "Set width to: ")))
(beginning-of-line)
(set-mark-command nil)
(end-of-line)
(kill-ring-save (region-beginning) (region-end))
(org-return)
(org-yank)
(beginning-of-line)
(set-mark-command nil)
(end-of-line)
(save-restriction
(narrow-to-region (region-beginning) (region-end))
(goto-char (point-min))
(while (search-forward-regexp "|[[:space:]][-_.A-Za-z0-9]+[[:space:]]" nil t)
(replace-match (concat "| <" new-width "> "))))
(org-table-shrink)
(beginning-of-line)))
I like a nice big splash screen.
(use-package dashboard
:config
(dashboard-setup-startup-hook)
(setq dashboard-startup-banner (concat *dotemacs-dir* "assets/Lambda_light.png"))
(setq dashboard-items '((recents . 10)))
(setq dashboard-banner-logo-title ""))
Helpful for finding the cursor when jumping around
(global-hl-line-mode +1)
(set-face-background hl-line-face "LightSteelBlue1")
(use-package ivy-posframe
:config
(setq ivy-posframe-display-functions-alist
'((swiper . ivy-posframe-display-at-frame-bottom-left)
(complete-symbol . ivy-posframe-display-at-point)
(counsel-M-x . ivy-posframe-display-at-frame-center)
(t . ivy-posframe-display)))
(ivy-posframe-mode 0)
(custom-set-faces '(ivy-posframe ((t (:inherit default :background "black"))))))
Use the spaceline from spacemacs
(use-package spaceline
:config
(require 'spaceline-config)
(setq powerline-default-separator (quote wave))
(spaceline-spacemacs-theme)
(setq powerline-height 20)
(set-face-attribute 'mode-line nil :box nil)
(set-face-attribute 'mode-line-inactive nil :box nil))
Show spaceline icons
(use-package spaceline-all-the-icons
:after spaceline
:config (spaceline-all-the-icons-theme))
(custom-set-variables
'(spaceline-all-the-icons-separator-type (quote arrow)))
Display the current time and battery indicator
(setq display-time-24hr-format t)
(setq display-time-format "%H:%M - %d.%b.%y")
(display-time-mode 1)
(display-battery-mode 1)
(add-to-list 'default-frame-alist '(ns-transparent-titlebar . t))
(add-to-list 'default-frame-alist '(ns-appearance . dark))
;; Autohide the top panel if necessary
(setq ns-auto-hide-menu-bar t)
(toggle-frame-maximized)
(set-face-attribute 'default nil :height 120)
(global-set-key (kbd "<f9>") 'other-frame)
Show symbols by default
(global-prettify-symbols-mode 1)
Go fullscreen and set the default font size.
(set-frame-parameter nil 'fullscreen 'fullboth)
(set-face-attribute 'default nil :height 140)
(set-face-attribute 'default nil :font "Inconsolata-14")
(set-face-attribute 'default nil :font "Inconsolata-18")
Load some basic minor modes by default
(add-hook 'org-mode-hook 'no-trailing-whitespace)
(add-hook 'org-mode-hook 'flyspell-mode)
(setq org-hide-emphasis-markers t)
;; Copy the visible text (without formatting marks) by default
;; (define-key org-mode-map (kbd "M-w") 'org-copy-visible)
;; (define-key org-mode-map (kbd "M-W") 'kill-ring-save)
Fonts and variable pitch mode for alignment issues with non-monospaced fonts. Variable pitch will use roboto, but override elements that need fixed-pitch (i.e. org-table) with a font that is monospaced (i.e. a font that is already fixed-pitch)
(add-hook 'org-mode-hook (lambda () (variable-pitch-mode t)))
(add-hook 'org-mode-hook (lambda () (set-face-attribute 'org-table nil :inherit 'fixed-pitch)))
(add-hook 'org-mode-hook (lambda () (set-face-attribute 'org-block nil :inherit 'fixed-pitch :height 0.8)))
(custom-set-faces
'(variable-pitch ((t (:family "Roboto"))))) ;; make sure this font is installed
(add-hook 'org-mode-hook (lambda () (set-face-attribute 'org-date nil :inherit 'fixed-pitch)))
Show the asterisks as bullets and set up indentation
(use-package org-bullets :config (add-hook 'org-mode-hook (lambda () (org-bullets-mode))))
(add-hook 'org-mode-hook 'org-indent-mode)
Show lists with a bullet rather than the -
character.
(font-lock-add-keywords 'org-mode
'(("^ *\\([-]\\) "
(0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "•"))))))
Setup an easy way to jump to an org headline using org-goto C-c C-j
(setq org-goto-interface 'outline-path-completion
org-goto-max-level 10)
(setq org-outline-path-complete-in-steps nil)
(global-set-key (kbd "C-o") 'other-window)
(define-key dired-mode-map (kbd "C-o") 'other-window)
(define-key rg-mode-map (kbd "C-o") 'other-window)
(define-key grep-mode-map (kbd "C-o") 'other-window)
;; (define-key bookmark-bmenu-mode-map (kbd "C-o") 'other-window)
When evaluating a source code block in org mode do not prompt for input, just run it.
(setq org-confirm-babel-evaluate nil)
Stylistic preferences for using the pre-v9 version of org mode (E.g. easy templates and how to split the source window when editing, make the source blocks full width.)
(require 'org-tempo)
(setq org-src-window-setup 'other-window)
(custom-set-faces
'(org-block ((t (:inherit shadow :extend t :background "gray83"))))
'(org-block-begin-line ((t (:extend t :background "gray95" :foreground "gray59"
:height 0.9))))
'(org-block-end-line ((t (:extend t :background "gray95" :foreground "gray59" :height 0.9)))))
Set the node environment
(setq org-babel-js-cmd (concat *node-dir* "bin/node"))
(add-to-list
'org-structure-template-alist
'("r" . "src restclient"))
(add-to-list
'org-structure-template-alist
'("js" . "src js"))
(add-to-list
'org-structure-template-alist
'("ts" . "src typescript"))
(add-to-list
'org-structure-template-alist
'("el" . "src emacs-lisp"))
(add-to-list
'org-structure-template-alist
'("b" . "src bash"))
(add-to-list
'org-structure-template-alist
'("elt" . "src emacs-lisp :tangle ~/.emacs"))
(add-to-list 'org-tempo-keywords-alist '("n" . "name"))
Add some export modes for getting content out of org. Adding diminish to ob-clojure
throws a Wrong type argument: stringp, :defer
error.
(use-package ox-twbs :defer)
(use-package ob-rust :defer)
(use-package ob-restclient)
(require 'ob-clojure)
(use-package ob-typescript :diminish typescript-mode)
Allow asynchronous execution of org-babel src blocks so you can keep using emacs during long running scripts
(use-package ob-async)
Load some languages by default
(add-to-list 'org-src-lang-modes '("js" . "javascript")
'("php" . "php"))
(org-babel-do-load-languages
'org-babel-load-languages
'((python . t)
(js . t)
(lisp . t)
(clojure . t)
(typescript . t)
(rust . t)
(sql . t)
(shell . t)
(java . t)))
I like org source blocks for typescript to use different compiler settings than what ships with ob-typescript. Not sure if there’s a better way to do this, but just overwriting the function from the source with the code below using the configuration I prefer.
(defun org-babel-execute:typescript (body params)
"Execute a block of Typescript code with org-babel. This function is called by `org-babel-execute-src-block'"
(let* ((tmp-src-file (org-babel-temp-file "ts-src-" ".ts"))
(tmp-out-file (org-babel-temp-file "ts-src-" ".js"))
(cmdline (cdr (assoc :cmdline params)))
(cmdline (if cmdline (concat " " cmdline) ""))
(jsexec (if (assoc :wrap params) ""
(concat " ; node " (org-babel-process-file-name tmp-out-file)))))
(with-temp-file tmp-src-file (insert body))
(let ((results (org-babel-eval (format "tsc %s --lib 'ES7,DOM' -out %s %s %s"
cmdline
(org-babel-process-file-name tmp-out-file)
(org-babel-process-file-name tmp-src-file)
jsexec) ""))
(jstrans (with-temp-buffer
(insert-file-contents tmp-out-file)
(buffer-substring-no-properties (point-min) (point-max)))))
(if (eq jsexec "") jstrans results))))
For org-babel’s clojure backend use cider rather than the default slime
(setq org-babel-clojure-backend 'cider)
Simple command to open emacs (assumes it’s already running) and launch org capture in a new frame. This can be bound to a global key sequence.
emacsclient -ne "(make-capture-frame)"
(server-start)
(defadvice org-capture-finalize
(after delete-capture-frame activate)
"Advise capture-finalize to close the frame"
(if (equal "capture" (frame-parameter nil 'name))
(delete-frame)))
(defadvice org-capture-destroy
(after delete-capture-frame activate)
"Advise capture-destroy to close the frame"
(if (equal "capture" (frame-parameter nil 'name))
(delete-frame)))
(use-package noflet
:ensure t )
(defun make-capture-frame ()
"Create a new frame and run org-capture."
(interactive)
(make-frame '((name . "capture")))
(select-frame-by-name "capture")
(delete-other-windows)
(noflet ((switch-to-buffer-other-window (buf) (switch-to-buffer buf)))
(org-capture)))
Helpful for bridging org and jira.
(use-package ox-jira)
This attempts to sync an org file on save if it detects the file is in the *org-dir*
directory.
(defun jrm/git-auto-sync ()
"Automatically stages, commits, pulls, and pushes the current branch's upstream settings. Commit message is current timestamp. Depends on Magit."
(interactive)
(if (string-match-p (regexp-quote *org-dir*) (file-name-directory buffer-file-name))
(progn
(magit-stage-modified)
(magit-run-git-with-editor "commit" "-m" (format-time-string "%a %d %b %Y %H:%M:%S %Z"))
(magit-run-git-async "pull")
(magit-run-git-async "push"))))
(add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook 'jrm/git-auto-sync nil t)))
Use xelatex for more latex options like fontspec
(setq org-latex-compiler "xelatex")
Show any latex previews by default
(custom-set-variables '(org-startup-with-latex-preview t))
Setup standard todo keywords
(setq org-use-fast-todo-selection t)
(setq org-todo-keywords
'((sequence "TODO(t!)" "|" "DONE(d!)")
(sequence "WORKFLOW TODO(w@/!)" "SOON(s@/!)" "|" "SOMEDAY(S@/!)")))
;; Custom colors for the keywords
(setq org-todo-keyword-faces
'(("TODO" :foreground "red" :weight bold)
("DONE" :foreground "forest green" :weight bold)
("WORKFLOW TODO" :foreground "#61afef" :weight bold)
("SOON" :foreground "#da8548" :weight bold)
("SOMEDAY" :foreground "#9963ad" :weight bold)))
File locations for org agenda
(global-set-key (kbd "C-c a") 'org-agenda)
(setq org-agenda-custom-commands
'(("p" "Personal Week and Task List"
((agenda "")
(alltodo)
(search "* DONE"))
((org-agenda-files '("~/org/personal"))))
("j" "Jira Kanban Board"
((search ":status: Open")
(search ":status: To Do")
(search ":status: Selected for Development")
(search ":status: In Development")
(search ":status: In Review")
;; (search ":status: Ready for Test")
;; (search ":status: In Test")
(search ":status: Ready for Demo"))
((org-agenda-files '("~/.org-jira"))))
("A" "Personal and Work Week and Task List"
((agenda "")
(alltodo)
(search "* DONE")))))
(custom-set-variables
'(org-export-backends '(ascii html icalendar latex md odt)))
(use-package grip-mode
:ensure-system-package (grip . "pip install grip"))
(use-package org-roam
:ensure t
:custom
(org-roam-directory "~/org-roam")
(org-roam-complete-everywhere t)
(org-roam-capture-templates
'(("d" "default" plain
"%?"
:if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n")
:unnarrowed t)
("p" "personal" plain
"%?"
:if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+filetags: :personal:\n")
:unnarrowed t)))
:bind (("C-c n l" . org-roam-buffer-toggle)
("C-c n f" . org-roam-node-find)
("C-c n i" . org-roam-node-insert)
("C-c n I" . org-roam-node-insert-immediate)
:map org-mode-map
("C-M-i" . completion-at-point))
:config
(org-roam-setup))
(defun org-roam-node-insert-immediate (arg &rest args)
(interactive "P")
(let ((args (push arg args))
(org-roam-capture-templates (list (append (car org-roam-capture-templates)
'(:immediate-finish t)))))
(apply #'org-roam-node-insert args)))
(use-package org-roam-ui)
(defun jrm/git-auto-sync-org-roam ()
"Automatically stages, commits, pulls, and pushes the current branch's upstream settings. Commit message is current timestamp. Depends on Magit."
(interactive)
(if (string-match-p (regexp-quote *org-roam-dir*) (file-name-directory buffer-file-name))
(progn
(magit-stage-untracked)
(magit-stage-modified)
(magit-run-git-with-editor "commit" "-m" (format-time-string "%a %d %b %Y %H:%M:%S %Z"))
(magit-run-git-async "pull")
(magit-run-git-async "push"))))
(add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook 'jrm/git-auto-sync-org-roam nil t)))
By default just use bash for all shells
(defvar my-term-shell "/bin/bash")
(defadvice ansi-term (before force-bash)
(interactive (list my-term-shell)))
(ad-activate 'ansi-term)
Make shells interactive (i.e. M-!, or source blocks in org)
(setq shell-command-switch "-c")
Make sure to unbind f9 for swtiching between frames
(use-package vterm)
;; for some reason, using a setq or the :config or :custom keyword in
;; use-package does not set the variable correctly for
;; vterm. Resorting to custom-set-variables.
(custom-set-variables
'(vterm-keymap-exceptions (push "<f9>" vterm-keymap-exceptions))
'(vterm-keymap-exceptions (push "C-o" vterm-keymap-exceptions)))
(define-key vterm-mode-map (kbd "C-q") #'vterm-send-next-key)
Many thanks to pragmatic emacs’ post for guidance on this setup.
(use-package elfeed-org
:config (elfeed-org) (setq rmh-elfeed-org-files (list (concat *org-dir* "personal/elfeed.org"))))
(defun jrm/elfeed-show-all ()
(interactive)
(bookmark-maybe-load-default-file)
(bookmark-jump "elfeed-all"))
(defun jrm/elfeed-show-development ()
(interactive)
(bookmark-maybe-load-default-file)
(bookmark-jump "elfeed-development"))
(defun jrm/elfeed-show-news ()
(interactive)
(bookmark-maybe-load-default-file)
(bookmark-jump "elfeed-news"))
(defun jrm/elfeed-show-emacs ()
(interactive)
(bookmark-maybe-load-default-file)
(bookmark-jump "elfeed-emacs"))
(defun jrm/elfeed-show-general ()
(interactive)
(bookmark-maybe-load-default-file)
(bookmark-jump "elfeed-general"))
(defun jrm/elfeed-load-db-and-open ()
"Wrapper to load the elfeed db from disk before opening"
(interactive)
(elfeed-db-load)
(elfeed)
(elfeed-search-update--force))
(defun jrm/elfeed-save-db-and-bury ()
"Wrapper to save the elfeed db to disk before burying buffer"
(interactive)
(elfeed-db-save)
(quit-window))
(use-package elfeed
:defer
:bind (:map elfeed-search-mode-map
("A" . jrm/elfeed-show-all)
("E" . jrm/elfeed-show-emacs)
("D" . jrm/elfeed-show-development)
("R" . jrm/elfeed-show-general)
("N" . jrm/elfeed-show-news)
("q" . jrm/elfeed-save-db-and-bury)))
(global-set-key (kbd "C-x e") 'jrm/elfeed-load-db-and-open)
Sometimes it’s helpful to hide images for certain posts.
(defun jrm/elfeed-show-hide-images ()
(interactive)
(let ((shr-inhibit-images t))
(elfeed-show-refresh)))
(global-set-key (kbd "C-x C-j e") 'jrm/elfeed-show-hide-images)
Most of the functions in this section are bound to C-x C-j
prefix key.
(defun jrm/copy-all ()
"Copy the current buffer without loosing your place"
(interactive)
(let ((original-position (point)))
(mark-whole-buffer)
(kill-ring-save 0 0 t)
(goto-char original-position)
(message "Buffer contents yanked.")))
(global-set-key (kbd "C-x C-j C-c") 'jrm/copy-all)
I find myself need specific font sizes for different scenarios, i.e. projecting, screen-sharing on conference calls, etc. So, binding these to a quick way to toggle through them.
Note: there might be a better way to handle this but things like M-+/M– won’t zoom things like line numbers, etc.
(defvar jrm/screens-alist '((?0 "xsmall" (lambda () (set-face-attribute 'default nil :height 70) 'default))
(?1 "small" (lambda () (set-face-attribute 'default nil :height 110) 'default))
(?2 "medium" (lambda () (set-face-attribute 'default nil :height 120) 'proj))
(?3 "large" (lambda () (set-face-attribute 'default nil :height 140) 'proj))
(?4 "xtra-large" (lambda () (set-face-attribute 'default nil :height 160) 'projLg))
(?5 "xxtra-large" (lambda () (set-face-attribute 'default nil :height 190) 'projLg))
(?6 "xxxtra-large" (lambda () (set-face-attribute 'default nil :height 210) 'projLg)))
"List that associates number letters to descriptions and actions.")
(defun jrm/adjust-font-size ()
"Lets the user choose the the font size and takes the corresponding action.
Returns whatever the action returns."
(interactive)
(let ((choice (read-char-choice
(mapconcat (lambda (item) (format "%c: %s" (car item) (cadr item)))
jrm/screens-alist "; ")
(mapcar #'car jrm/screens-alist))))
(funcall (nth 2 (assoc choice jrm/screens-alist)))))
(global-set-key (kbd "C-x C-j p") 'jrm/adjust-font-size)
Lifted from (http://ergoemacs.org/emacs/emacs_copy_file_path.html)
(defun jrm/copy-file-path (&optional *dir-path-only-p)
"Copy the current buffer's file path or dired path to `kill-ring'.
Result is full path."
(interactive "P")
(let ((-fpath
(if (equal major-mode 'dired-mode)
(expand-file-name default-directory)
(if (buffer-file-name)
(buffer-file-name)
(user-error "Current buffer is not associated with a file.")))))
(kill-new
(if *dir-path-only-p
(progn
(message "Directory path copied: 「%s」" (file-name-directory -fpath))
(file-name-directory -fpath))
(progn (message "File path copied: 「%s」" -fpath) -fpath )))))
(defun jrm/async-callback-run-callback (process signal cb)
(interactive)
(when (memq (process-status process) '(exit signal))
(cb)
(shell-command-sentinel process signal)))
(defun jrm/async-callback (cmd cb)
(let* ((output-buffer (generate-new-buffer "*Custom Shell Command*"))
(proc (progn
(async-shell-command cmd output-buffer)
(get-buffer-process output-buffer))))
(if (process-live-p proc)
(set-process-sentinel proc cb #'jrm/async-callback-run-callback)
(message "No process running."))))
(defun jrm/wifi-restart-ubuntu ()
"Restart wifi on ubuntu & derivities using network manager."
(interactive)
(shell-command (concat "echo " (shell-quote-argument (read-passwd "Enter Password: "))
" | sudo -S service network-manager restart")))
The following narrow was lifted from Protesilaos Stavrou blog/video: https://protesilaos.com/codelog/2021-07-24-emacs-misc-custom-commands/
(defun prot-common-window-bounds ()
"Determine start and end points in the window."
(list (window-start) (window-end)))
;;;###autoload
(defun prot-simple-narrow-visible-window ()
"Narrow buffer to wisible window area.
Also check `prot-simple-narrow-dwim'."
(interactive)
(let* ((bounds (prot-common-window-bounds))
(window-area (- (cadr bounds) (car bounds)))
(buffer-area (- (point-max) (point-min))))
(if (/= buffer-area window-area)
(narrow-to-region (car bounds) (cadr bounds))
(user-error "Buffer fits in the window; won't narrow"))))
;;;###autoload
(defun prot-simple-narrow-dwim ()
"Do-what-I-mean narrowing.
If region is active, narrow the buffer to the region's
boundaries.
If no region is active, narrow to the visible portion of the
window.
If narrowing is in effect, widen the view."
(interactive)
(unless mark-ring ; needed when entering a new buffer
(push-mark (point) t nil))
(cond
((and (use-region-p)
(null (buffer-narrowed-p)))
(let ((beg (region-beginning))
(end (region-end)))
(narrow-to-region beg end)))
((null (buffer-narrowed-p))
(prot-simple-narrow-visible-window))
(t
(widen)
(recenter))))
(global-set-key (kbd "C-x n n") 'prot-simple-narrow-dwim)
Disable the narrow-to-region message
(put 'narrow-to-region 'disabled nil)
(defun jrm/kill-and-comment-dwim (arg)
"Takes the active region duplicates it and comments
out the top copy. If no region is selected, the region selected with
mark-paragraph is used.
With a universal prefix argument, do not paste the content but saves
it to the kill ring."
(interactive "P")
(if (not mark-active) (mark-paragraph))
(let ((start (region-beginning))
(end (region-end)))
(kill-ring-save start end)
(comment-region start end)
(if (not (bound-and-true-p arg))
(progn
(goto-char end)
(end-of-line)
(insert "\n")
(yank)
;; Delete evidence
(pop kill-ring)
(when kill-ring-yank-pointer
(setq kill-ring-yank-pointer kill-ring))))))
(global-set-key (kbd "M-RET") 'jrm/kill-and-comment-dwim)
For various reasons ripgrep does not work with all the projects I need so customizing grep to my liking
(setq grep-find-ignored-directories (quote ("SCCS" "RCS" "CVS" "MCVS" ".src" ".svn" ".git" ".hg" ".bzr" "_MTN" "_darcs" "{arch}" "node_modules" "vendor" "dist" "coverage")))
Thank you mastering emacs!
(defun sudo ()
"Use TRAMP to `sudo' the current buffer."
(interactive)
(when buffer-file-name
(find-alternate-file
(concat "/sudo:root@localhost:"
buffer-file-name))))
(global-set-key (kbd "s-u") '(lambda () (interactive) (revert-buffer t (not (buffer-modified-p)) t)))
(provide '.emacs)