Last active
April 3, 2024 13:53
-
-
Save kliph/0f0d513c3d66197841787593852427a4 to your computer and use it in GitHub Desktop.
My local emacs config. See https://github.com/promptworks/dotfiles for base emacs configuration.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; -*- mode: emacs-lisp -*- | |
;;; Emacs is a platform written in 1976 (yes, almost half a century ago) for | |
;;; writing software to make you more productive, masquerading as a text | |
;;; editor. -- Steve Yegge | |
;;; Use Paredit | |
(unless (package-installed-p 'paredit) | |
(package-install 'paredit)) | |
(require 'paredit) | |
(add-hook 'emacs-lisp-mode-hook #'enable-paredit-mode) | |
(add-hook 'clojure-mode-hook #'enable-paredit-mode) | |
(require 'ruby-mode) | |
;;; Opt out of hard indentation for content https://orgmode.org/manual/Hard-indentation.html | |
(setq org-adapt-indentation nil) | |
(defun kliph/paredit-newline-dwim () | |
"Do what I mean when I want a newline. Sometimes I want to see | |
the evaluation of the last sexp. This function is meant to be | |
bound to C-j in the `paredit-mode-map'." | |
(interactive) | |
(cond ((and (eolp) | |
(not (eq (kliph/get-cur-buffer-major-mode) 'clojure-mode))) | |
(eval-print-last-sexp)) | |
(t (paredit-newline)))) | |
(defun kliph/paredit-forward-up-dwim () | |
"Don't throw a silly scan error when I just want to move to the | |
next sexp. This function is meant to be bound to C-M-n in the | |
`paredit-mode-map'." | |
(interactive) | |
(cond ((or (eolp) (bolp)) (paredit-forward)) | |
(t (paredit-forward-up)))) | |
(defun kliph/paredit-backward-down-dwim () | |
"Don't throw a silly scan error when I just want to move back | |
through sexps. This function is meant to be bound to C-M-p in the | |
`paredit-mode-map'." | |
(interactive) | |
(cond ((not (looking-back "\)")) (paredit-backward)) | |
(t (paredit-backward-down)))) | |
(define-key paredit-mode-map (kbd "C-j") 'kliph/paredit-newline-dwim) | |
(define-key paredit-mode-map (kbd "C-M-n") 'kliph/paredit-forward-up-dwim) | |
(define-key paredit-mode-map (kbd "C-M-p") 'kliph/paredit-backward-down-dwim) | |
(define-key paredit-mode-map (kbd "C->") 'paredit-forward-barf-sexp) | |
(define-key paredit-mode-map (kbd "C-<") 'paredit-backward-barf-sexp) | |
(global-set-key (kbd "C-M-s-9") 'paredit-mode) | |
;;; Show line numbers and cols in bottom bar | |
(setq line-number-mode 1) | |
(setq column-number-mode 1) | |
(unless (package-installed-p 'ace-window) | |
(package-install 'ace-window)) | |
(require 'ace-window) | |
(global-set-key (kbd "M-`") 'ace-window) | |
(setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)) | |
;;; Bye bye white space | |
(add-hook 'before-save-hook 'delete-trailing-whitespace) | |
(global-display-line-numbers-mode) | |
(unless (package-installed-p 'clojure-mode) | |
(package-install 'clojure-mode)) | |
(require 'clojure-mode) | |
(unless (package-installed-p 'cider) | |
(package-install 'cider)) | |
(require 'cider) | |
(add-to-list 'exec-path "/usr/local/bin") | |
(show-paren-mode 1) | |
(unless (package-installed-p 'web-mode) | |
(package-install 'web-mode)) | |
(require 'web-mode) | |
(add-to-list 'auto-mode-alist '("\\.erb" . web-mode)) | |
(add-to-list 'auto-mode-alist '("\\.html.erb" . web-mode)) | |
(add-to-list 'auto-mode-alist '("\\.tsx" . web-mode)) | |
(setq web-mode-enable-current-element-highlight 't) | |
(setq web-mode-enable-auto-quoting nil) | |
(add-hook 'web-mode-hook | |
(lambda () | |
(when (or (string-equal "tsx" (file-name-extension buffer-file-name)) | |
(string-equal "js" (file-name-extension buffer-file-name))) | |
(setup-tide-mode)))) | |
(define-key web-mode-map (kbd "C-c /") 'web-mode-element-close) | |
(define-key web-mode-map (kbd "s-r") 'web-mode-element-rename) | |
(defun kliph/toggle-keyword-string () | |
"Convert the string or keyword at point to keyword or string." | |
(interactive) | |
(let ((original-point (point))) | |
(while (and (> (point) 1) | |
(not (equal "\'" (buffer-substring-no-properties (point) (+ 1 (point))))) | |
(not (equal ":" (buffer-substring-no-properties (point) (+ 1 (point)))))) | |
(backward-char)) | |
(cond | |
((equal 1 (point)) | |
(error "Beginning of file reached, this was probably a mistake")) | |
((equal "\'" (buffer-substring-no-properties (point) (+ 1 (point)))) | |
(insert ":" (substring (kliph/delete-and-extract-dwim) 1 -1))) | |
((equal ":" (buffer-substring-no-properties (point) (+ 1 (point)))) | |
(insert "\'" (substring (kliph/delete-and-extract-dwim) 1) "\'"))) | |
(goto-char original-point))) | |
(define-key ruby-mode-map (kbd "C-:") 'kliph/toggle-keyword-string) | |
(define-key web-mode-map (kbd "C-:") 'kliph/toggle-keyword-string) | |
(unless (package-installed-p 'tide) | |
(package-install 'tide)) | |
(require 'tide) | |
(unless (package-installed-p 'flycheck) | |
(package-install 'flycheck)) | |
(require 'flycheck) | |
(flycheck-add-mode 'javascript-eslint 'web-mode) | |
;;; Check typescript first and go on to check eslint if there are no errors. | |
(flycheck-add-next-checker 'tsx-tide '(warning . javascript-eslint)) | |
(add-hook 'python-mode-hook | |
(lambda () | |
(flycheck-mode 1) | |
(setq flycheck-checker 'python-pylint))) | |
(add-hook 'ruby-mode-hook | |
'flycheck-mode) | |
(add-hook 'js2-mode-hook | |
'flycheck-mode) | |
(add-hook 'org-src-mode-hook | |
(lambda () | |
(flycheck-mode 0))) | |
(add-hook 'sql-mode-hook | |
'flycheck-mode) | |
(defun kliph/use-eslint-from-node-modules () | |
(let* ((root (locate-dominating-file | |
(or (buffer-file-name) default-directory) | |
"node_modules")) | |
(eslint (and root | |
(expand-file-name "node_modules/.bin/eslint" | |
root)))) | |
(when (and eslint (file-executable-p eslint)) | |
(setq-local flycheck-javascript-eslint-executable eslint)))) | |
(add-hook 'flycheck-mode-hook #'kliph/use-eslint-from-node-modules) | |
;;; See also http://www.flycheck.org/en/latest/user/syntax-checkers.html#variable-flycheck-checker for setting eslint as Flycheck checker in .dir-locals.el | |
(unless (package-installed-p 'rjsx-mode) | |
(package-install 'rjsx-mode)) | |
(require 'rjsx-mode) | |
(global-set-key (kbd "C-.") 'rjsx-mode) | |
(global-set-key (kbd "s-.") 'js2-mode) | |
(add-to-list 'auto-mode-alist '("\\.js\\'" . rjsx-mode)) | |
(setq ispell-program-name "aspell") | |
(require 'evil) | |
(define-key evil-normal-state-map (kbd "C-p") 'projectile-find-file) | |
(setq visible-bell nil) | |
(setq ring-bell-function | |
(lambda () | |
(invert-face 'mode-line) | |
(run-with-timer 0.1 nil 'invert-face 'mode-line))) | |
(unless (package-installed-p 'expand-region) | |
(package-install 'expand-region)) | |
(require 'expand-region) | |
(global-set-key (kbd "C-=") 'er/expand-region) | |
(eval-after-load 'rjsx-mode '(require 'web-mode-expansions)) | |
;;; How to do this without setting the theme to solarized? | |
(defun kliph/load-solarized-light-theme-dwim () | |
(interactive) | |
(load-theme 'solarized-light) | |
(setq solarized-use-variable-pitch nil | |
solarized-scale-org-headlines nil) | |
(add-to-list 'default-frame-alist '(ns-appearance . light)) | |
(set-face-background 'hl-line "#EEE8D4")) | |
(defun kliph/load-solarized-dark-theme-dwim () | |
(interactive) | |
(load-theme 'solarized-dark) | |
(setq solarized-use-variable-pitch nil | |
solarized-scale-org-headlines nil) | |
(set-face-background 'hl-line "#03333F")) | |
(unless (package-installed-p 'panda-theme) | |
(package-install 'panda-theme)) | |
(require 'panda-theme) | |
(defun kliph/load-panda-theme-dwim () | |
(interactive) | |
(load-theme 'panda) | |
(let ((bg- "#1A1816") | |
(bg "#292A2B") | |
(bg+ "#404954")) | |
;; (set-face-background 'linum bg) | |
(set-face-background 'mode-line bg) | |
(set-face-attribute 'mode-line nil | |
:overline bg- | |
:underline bg+ | |
:background bg+ | |
:box bg) | |
(set-face-background 'mode-line-inactive bg-) | |
(set-face-attribute 'mode-line-inactive nil | |
:overline bg+ | |
:underline bg- | |
:box bg) | |
(set-face-background 'hl-line bg+) | |
(set-face-background 'magit-diff-hunk-heading bg) | |
(set-face-background 'magit-diff-hunk-heading-highlight bg) | |
(set-face-background 'magit-diff-file-heading-highlight bg))) | |
(defalias 'solarize 'kliph/load-solarized-light-theme-dwim) | |
(defalias 'solarize-dark 'kliph/load-solarized-dark-theme-dwim) | |
(defalias 'panda 'kliph/load-panda-theme-dwim) | |
(defalias 'panda-panda-panda-panda-panda-panda-panda 'panda) | |
(unless (package-installed-p 'rvm) | |
(package-install 'rvm)) | |
(require 'rvm) | |
(rvm-use-default) | |
(unless (package-installed-p 'rubocop) | |
(package-install 'rubocop)) | |
(require 'rubocop) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; http://stackoverflow.com/questions/5543989/pylint-not-working-with-emacs-gui-on-os-x-works-from-command-line/5558223#5558223 | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
(defun set-exec-path-from-shell-PATH () | |
(let ((path-from-shell (replace-regexp-in-string | |
"[ \t\n]*$" | |
"" | |
(shell-command-to-string "/bin/zsh --login -i -c 'echo $PATH'")))) | |
(setenv "PATH" path-from-shell) | |
(setq exec-path (split-string path-from-shell path-separator)))) | |
(when (memq window-system '(mac ns)) | |
;; When started from Emacs.app or similar, ensure $PATH | |
;; is the same the user would see in Terminal.app | |
(set-exec-path-from-shell-PATH)) | |
(shell-command "ssh-add -K ~/.ssh/id_ed25519") | |
(unless (package-installed-p 'haml-mode) | |
(package-install 'haml-mode)) | |
(require 'haml-mode) | |
(require 'ox-md) | |
(defun kliph/unfill-paragraphs-to-be-one-line (min max) | |
"Fill individual paragraphs with a large fill column so they're | |
on one line. Keeps paragraph breaks intact." | |
(interactive "r") | |
(let ((fill-column 100000)) | |
(fill-individual-paragraphs min max))) | |
(unless (package-installed-p 'htmlize) | |
(package-install 'htmlize)) | |
(require 'htmlize) | |
(unless (package-installed-p 's) | |
(package-install 's)) | |
(require 's) | |
(defun kliph/message-git-user () | |
"Remind me of the current git user name. Meant to be added to | |
the `magit-mode-hook'." | |
(message (s-trim | |
(format "Current git user name is: %s" | |
(shell-command-to-string "git config user.name"))))) | |
(add-hook 'magit-mode-hook 'kliph/message-git-user) | |
;; https://github.com/toctan/toggle-quotes.el | |
(add-to-list 'load-path "~/.emacs.d/toggle-quotes/") | |
(require 'toggle-quotes) | |
(global-set-key (kbd "C-'") 'toggle-quotes) | |
(global-set-key (kbd "C-\"") 'toggle-quotes) | |
(defun toggle-camelcase-underscores () | |
"Toggle between camelcase and underscore notation for the symbol at point." | |
(interactive) | |
(save-excursion | |
(let* ((bounds (bounds-of-thing-at-point 'symbol)) | |
(start (car bounds)) | |
(end (cdr bounds)) | |
(currently-using-underscores-p (progn (goto-char start) | |
(re-search-forward "_" end t)))) | |
(if currently-using-underscores-p | |
(progn | |
(upcase-initials-region start end) | |
(replace-string "_" "" nil start end) | |
(downcase-region start (1+ start))) | |
(replace-regexp "\\([A-Z]\\)" "_\\1" nil (1+ start) end) | |
(downcase-region start (cdr (bounds-of-thing-at-point 'symbol))))))) | |
(unless (package-installed-p 'rg) | |
(package-install 'rg)) | |
(require 'rg) | |
(global-set-key (kbd "M-s-.") 'rg-dwim) | |
(unless (package-installed-p 'slim-mode) | |
(package-install 'slim-mode)) | |
(require 'slim-mode) | |
(unless (package-installed-p 'dumb-jump) | |
(package-install 'dumb-jump)) | |
(require 'dumb-jump) | |
(define-key ruby-mode-map (kbd "M-.") 'dumb-jump-go) | |
(define-key ruby-mode-map (kbd "M-,") 'dumb-jump-back) | |
;;; The default keybinding C-M-p clobbers some movement from paredit. | |
;;; Let's prefer paredit keybinding because I use them more | |
;;; frequently. I don't think the `(kbd "C-s-p")' actually works | |
;;; because of how OS X sends keyboard signals to emacs. So if I | |
;;; start to use this keybinding it may make sense to remap it | |
;;; further. | |
(define-key dumb-jump-mode-map (kbd "C-s-p") 'dumb-jump-back) | |
(define-key dumb-jump-mode-map (kbd "C-M-p") nil) | |
(unless (package-installed-p 'swift-mode) | |
(package-install 'swift-mode)) | |
(require 'swift-mode) | |
(defun kliph/delete-and-extract-dwim () | |
"Delete the surrounding sexp and return it." | |
(let ((begin (point))) | |
(forward-sexp) | |
(let ((result (buffer-substring begin (point)))) | |
(delete-region begin (point)) | |
result))) | |
(unless (package-installed-p 'markdown-mode) | |
(package-install 'markdown-mode)) | |
(require 'markdown-mode) | |
(define-key markdown-mode-map (kbd "C-<return>") 'markdown-insert-header-dwim) | |
(define-key markdown-mode-map (kbd "C-c C-l") 'markdown-insert-link) | |
(when (memq window-system '(mac ns)) | |
(toggle-scroll-bar -1)) | |
(add-hook 'org-mode-hook 'turn-on-visual-line-mode) | |
(add-hook 'org-mode-hook 'flyspell-mode) | |
(add-hook 'org-mode-hook (lambda () | |
(setq-local electric-pair-inhibit-predicate | |
`(lambda (c) | |
(if (char-equal c ?\() t (,electric-pair-inhibit-predicate c)))))) | |
(add-hook 'org-mode-hook #'(lambda () (electric-indent-local-mode 0))) | |
(add-hook 'markdown-mode-hook 'turn-on-visual-line-mode) | |
(add-hook 'markdown-mode-hook 'flyspell-mode) | |
(unless (package-installed-p 'json-reformat) | |
(package-install 'json-reformat)) | |
(require 'json-reformat) | |
(unless (package-installed-p 'emojify) | |
(package-install 'emojify)) | |
(require 'emojify) | |
(defun to-underscore () | |
(interactive) | |
(progn (replace-regexp "\\([A-Z]\\)" "_\\1" nil (region-beginning) (region-end)) | |
(downcase-region (region-beginning) (region-end)))) | |
(defalias 'camelCase-to-underscore 'to-underscore) | |
(defun to-kebab () | |
(interactive) | |
(progn (replace-regexp "\\([A-Z]\\)" "-\\1" nil (region-beginning) (region-end)) | |
(downcase-region (region-beginning) (region-end)))) | |
(defun mapcar-head (fn-head fn-rest list) | |
"Like MAPCAR, but applies a different function to the first element." | |
(if list | |
(cons (funcall fn-head (car list)) (mapcar fn-rest (cdr list))))) | |
(defun underscore-to-camelCase () | |
(interactive) | |
(let* ((s (buffer-substring (region-beginning) (region-end))) | |
(camel-string (mapconcat 'identity (mapcar-head | |
'downcase | |
'(lambda (word) (capitalize (downcase word))) | |
(split-string s "_")) | |
""))) | |
(delete-region (region-beginning) (region-end)) | |
(insert camel-string))) | |
(defun underscore-to-CamelCase () | |
(interactive) | |
(let* ((s (buffer-substring (region-beginning) (region-end))) | |
(camel-string (mapconcat 'identity (mapcar-head | |
'(lambda (word) (capitalize (downcase word))) | |
'(lambda (word) (capitalize (downcase word))) | |
(split-string s "_")) | |
""))) | |
(delete-region (region-beginning) (region-end)) | |
(insert camel-string))) | |
(unless (package-installed-p 'json-mode) | |
(package-install 'json-mode)) | |
(require 'json-mode) | |
(add-to-list 'auto-mode-alist '("\\.json\\'" . json-mode)) | |
(add-to-list 'auto-mode-alist '("\\.json" . json-mode)) | |
(scroll-bar-mode -1) | |
(add-hook 'cider-mode-hook 'turn-on-eldoc-mode) | |
(add-hook 'python-mode-hook | |
(lambda () | |
(setq-local completion-at-point-functions nil))) | |
;;; Ensure you have proselint installed via homebrew | |
(when (executable-find "proselint") | |
(add-hook 'markdown-mode-hook | |
(lambda () | |
(flycheck-mode 1) | |
(setq flycheck-checker 'proselint)))) | |
(require 'ob-clojure) | |
(setq org-babel-clojure-backend 'cider) | |
(require 'ob-python) | |
(defun setup-tide-mode () | |
(interactive) | |
(tide-setup) | |
(flycheck-mode +1) | |
(setq flycheck-check-syntax-automatically '(save mode-enabled)) | |
(eldoc-mode +1) | |
(tide-hl-identifier-mode +1) | |
;; company is an optional dependency. You have to | |
;; install it separately via package-install | |
;; `M-x package-install [ret] company` | |
(company-mode +1)) | |
;; aligns annotation to the right hand side | |
(setq company-tooltip-align-annotations t) | |
;; formats the buffer before saving | |
(add-hook 'before-save-hook 'tide-format-before-save) | |
(add-hook 'typescript-mode-hook #'setup-tide-mode) | |
;;; See: https://github.com/ananthakumaran/tide/issues/114 | |
(setq tide-tsserver-executable nil) | |
(define-key tide-mode-map (kbd "s-r") 'tide-rename-symbol) | |
(setq-default tide-user-preferences '(:importModuleSpecifierPreference | |
"non-relative" | |
:includeCompletionsForModuleExports t | |
:includeCompletionsWithInsertText t | |
:allowTextChangesInNewFiles t)) | |
(defalias 'tide-find-references 'tide-references) | |
(setq kliph/yarn-lint-command "yarn eslint %s --fix") | |
(put 'kliph/yarn-lint-command 'safe-local-variable #'stringp) | |
(defun kliph/yarn-lint () | |
(interactive) | |
(shell-command (format kliph/yarn-lint-command buffer-file-name)) | |
(revert-buffer nil 't)) | |
(defun kliph/rubocop-lint () | |
(interactive) | |
(shell-command (format "rubocop -a %s" buffer-file-name)) | |
(revert-buffer nil 't)) | |
(global-set-key (kbd "M-s-l") 'kliph/yarn-lint) | |
(global-set-key (kbd "M-s-r") 'kliph/rubocop-lint) | |
(global-set-key (kbd "s-l") 'goto-line) | |
;;; Transparent titlebar | |
;; https://github.com/d12frosted/homebrew-emacs-plus/blob/master/Formula/emacs-plus.rb#L98 | |
;; https://github.com/d12frosted/homebrew-emacs-plus/issues/55 | |
;; https://www.gnu.org/software/emacs/manual/html_node/elisp/Properties-in-Mode.html#Properties-in-Mode | |
(when (memq window-system '(mac ns)) | |
(add-to-list 'default-frame-alist '(ns-appearance . dark)) | |
(add-to-list 'default-frame-alist '(ns-transparent-titlebar . t))) | |
(unless (package-installed-p 'sws-mode) | |
(package-install 'sws-mode)) | |
(require 'sws-mode) | |
(unless (package-installed-p 'stylus-mode) | |
(package-install 'stylus-mode)) | |
(require 'stylus-mode) | |
(define-key git-commit-mode-map (kbd "s-.") 'text-mode) | |
(define-key git-commit-mode-map (kbd "C-.") 'text-mode) | |
(unless (package-installed-p 'use-package) | |
(package-install 'use-package)) | |
(require 'use-package) | |
(setq lsp-keymap-prefix "s-y") | |
(unless (package-installed-p 'lsp-mode) | |
(package-install 'lsp-mode)) | |
(require 'lsp-mode) | |
(add-hook 'js2-mode-hook | |
'lsp) | |
(add-hook 'rjsx-mode-hook | |
'lsp) | |
(add-hook 'python-mode-hook | |
'lsp) | |
;;; I've run into issues where Emacs is using a different version of node to what the project specifies in `.nvmrc'. I haven't come up with a good solution for this. | |
;;; I just check which version emacs is using via `M-! node --version' and then ensure the dependencies are installed for that version via switching to it using nvm and running `npm i -g typescript-language-server typescript' | |
;;; I've run into problems resolving aliases in JavaScript projects using jsconfig.json. https://github.com/microsoft/vscode/issues/16320#issuecomment-540415092 was helpful. | |
;;; | |
;;; My current jsonconfig.json looks like: | |
;; { | |
;; "compilerOptions": { | |
;; "baseUrl": "./", | |
;; "jsx": "preserve", | |
;; "paths": { | |
;; "models/*": ["src/scripts/domain/models/*"], | |
;; ... | |
;; } | |
;; } | |
;; } | |
(define-key lsp-mode-map (kbd "s-r") 'lsp-rename) | |
(define-key lsp-mode-map (kbd "M-.") 'lsp-find-definition) | |
(add-to-list 'auto-mode-alist '("\\.Rmd" . markdown-mode)) | |
(unless (package-installed-p 'js2-refactor) | |
(package-install 'js2-refactor)) | |
(require 'js2-refactor) | |
(add-hook 'js2-mode-hook #'js2-refactor-mode) | |
;;; I'd like to use their kill but it doesn't work well with styled component template strings | |
(define-key js2-refactor-mode-map (kbd "s->") 'js2r-toggle-arrow-function-and-expression) | |
(define-key js2-refactor-mode-map (kbd "C-)") 'js2r-forward-slurp) | |
;;; Save session | |
(when (display-graphic-p) | |
(desktop-save-mode 1)) | |
(setq js-indent-level 2) | |
(setq indent-tabs-mode nil) | |
(defun kliph/highlight-current-line () | |
(interactive) | |
(if (display-graphic-p) | |
(global-hl-line-mode 1) | |
(global-hl-line-mode -1))) | |
(global-set-key (kbd "M-s-y") 'kliph/highlight-current-line) | |
(require 'uniquify) | |
(setq uniquify-buffer-name-style 'forward) | |
(setq uniquify-separator "/") | |
(setq uniquify-after-kill-buffer-p t) | |
(setq uniquify-ignore-buffers-re "^\\*") | |
(lsp-register-client | |
(make-lsp-client :new-connection (lsp-stdio-connection '("/usr/local/bin/terraform-ls" "serve")) | |
:major-modes '(terraform-mode) | |
:server-id 'terraform-ls)) | |
(add-hook 'terraform-mode-hook #'lsp) | |
(add-hook 'yaml-mode-hook #'highlight-indentation-mode) | |
(global-set-key (kbd "C-x t t") 'window-swap-states) | |
(projectile-register-project-type 'lein-test '("project.clj") | |
:compile "lein compile" | |
:test "lein test" | |
:test-suffix "_test") | |
(unless (package-installed-p 'go-mode) | |
(package-install 'go-mode)) | |
(require 'go-mode) | |
(electric-pair-mode 1) | |
;;; From https://geeksocket.in/posts/emacs-lsp-go/ | |
(defun lsp-go-install-save-hooks () | |
(add-hook 'before-save-hook #'lsp-format-buffer t t) | |
(add-hook 'before-save-hook #'lsp-organize-imports t t)) | |
(add-hook 'go-mode-hook #'lsp-go-install-save-hooks) | |
(add-hook 'go-mode-hook #'lsp-deferred) | |
(add-hook 'go-mode-hook #'yas-minor-mode-on) | |
(add-hook 'go-mode-hook (lambda () (electric-pair-mode 0))) | |
(add-hook 'go-mode-hook (lambda () (flycheck-add-next-checker 'lsp 'golangci-lint))) | |
(define-key org-mode-map (kbd "C-c s") 'org-insert-structure-template) | |
(define-key org-mode-map (kbd "C-c C-s") 'org-insert-structure-template) | |
(define-key org-mode-map (kbd "C-c M-p") 'org-previous-visible-heading) | |
(define-key org-mode-map (kbd "C-c M-n") 'org-next-visible-heading) | |
(define-key web-mode-map (kbd "C-c C-e C-r") 'web-mode-element-rename) | |
(define-key rjsx-mode-map (kbd "C-c C-e C-r") 'rjsx-rename-tag-at-point) | |
(define-key rjsx-mode-map (kbd "C-s-r") 'rjsx-rename-tag-at-point) | |
(setq lsp-file-watch-threshold 3000) | |
(setq sh-basic-offset 2) | |
(global-set-key (kbd "M-_") 'undo-redo) | |
;; See https://github.com/bbatsov/projectile/commit/981ef7de7cd4d2465e95ae649993561783d85bc8 | |
(setq projectile-git-submodule-command nil) | |
(define-key web-mode-map (kbd "C-c C-r") 'tide-find-references) | |
(define-key rjsx-mode-map (kbd "C-c C-r") 'lsp-find-references) | |
(define-key go-mode-map (kbd "C-c C-r") 'lsp-find-references) | |
(unless (package-installed-p 'rainbow-delimiters) | |
(package-install 'rainbow-delimiters)) | |
(setq backup-directory-alist '(("." . "~/.emacs.d/backups"))) | |
;;; https://www.blogbyben.com/2022/05/gotcha-emacs-on-mac-os-too-many-files.html | |
(defun file-notify-rm-all-watches () | |
"Remove all existing file notification watches from Emacs." | |
(interactive) | |
(maphash | |
(lambda (key _value) | |
(file-notify-rm-watch key)) | |
file-notify-descriptors) | |
(message "File notification watches removed.")) | |
(global-set-key (kbd "C-x &") 'file-notify-rm-all-watches) | |
(unless (package-installed-p 'string-inflection) | |
(package-install 'string-inflection-all-cycle)) | |
(require 'string-inflection) | |
(global-set-key (kbd "C-c i") 'string-inflection-cycle) | |
(global-set-key (kbd "C-c C") 'string-inflection-camelcase) ;; Force to CamelCase | |
(global-set-key (kbd "C-c L") 'string-inflection-lower-camelcase) ;; Force to lowerCamelCase | |
(setq backup-directory-alist | |
`((".*" . "~/.emacs-auto-saves"))) | |
(setq auto-save-file-name-transforms | |
`((".*" "~/.emacs-auto-saves" t))) | |
(unless (package-installed-p 'editorconfig) | |
(package-install 'editorconfig)) | |
(unless (package-installed-p 's) | |
(package-install 's)) | |
;;; Installed by cloning the repo here https://github.com/zerolfx/copilot.el to ~/.emacs.d | |
(add-to-list 'load-path "~/.emacs.d/copilot.el/") | |
(require 'copilot) | |
(add-hook 'prog-mode-hook 'copilot-mode) | |
(with-eval-after-load 'company | |
;; disable inline previews | |
(delq 'company-preview-if-just-one-frontend company-frontends)) | |
(define-key copilot-completion-map (kbd "C-<tab>") 'copilot-accept-completion) | |
(define-key copilot-completion-map (kbd "C-TAB") 'copilot-accept-completion) | |
(global-set-key (kbd "s-]") 'copilot-mode) | |
;;; By default copilot checks if evil is in insert mode. Since I'm not using | |
;;; evil, this causes issues. If I do use evil in the future, I can add a hook | |
;;; to update the predicates in my keybindings that invoke evil mode. See | |
;;; https://github.com/zerolfx/copilot.el/pull/124 | |
(setq copilot-enable-predicates '(copilot--buffer-changed)) | |
;;; Don't display copilot completions when company completions are active | |
(add-to-list 'copilot-disable-display-predicates #'company--active-p) | |
(add-hook 'company-pre-command-hook #'copilot-clear-overlay) | |
(add-to-list 'load-path "~/.emacs.d/flycheck-golangci-lint/") | |
(require 'flycheck-golangci-lint) | |
(eval-after-load 'flycheck | |
'(add-hook 'flycheck-mode-hook #'flycheck-golangci-lint-setup)) | |
(defun kliph/character-uppercase-p (char) | |
"Return t if CHAR is an uppercase character." | |
(eq (upcase char) char)) | |
(defun kliph/toggle-case () | |
"Toggle the case of the character at point." | |
(interactive) | |
(let ((char (char-after))) | |
(if (kliph/character-uppercase-p char) | |
(downcase-region (point) (+ 1 (point))) | |
(upcase-region (point) (+ 1 (point)))))) | |
(global-set-key (kbd "C-`") 'kliph/toggle-case) | |
(global-set-key (kbd "C-~") 'kliph/toggle-case) | |
(defalias 'lsp-restart-workspace 'lsp-workspace-restart) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment