1101 lines
29 KiB
EmacsLisp
1101 lines
29 KiB
EmacsLisp
;;; Below are fragments from my Emacs configuration file
|
||
;;; (`~/.emacs.d/init.el`).
|
||
|
||
;;; <!--more-->
|
||
|
||
;;; The newest version of this config is available from a [github
|
||
;;; repo](https://github.com/lukpank/.emacs.d).
|
||
|
||
;;; I recommend watching the following video by BuildFunThings called
|
||
;;; [My GNU Emacs configuration for programming](https://www.youtube.com/watch?v=I28jFkpN5Zk).
|
||
|
||
;;; If you put this config on a new machine with no Emacs packages
|
||
;;; installed then you will be asked if you want automatically install
|
||
;;; all packages used below.
|
||
|
||
;;; Later, if you add new packages you can temporary set
|
||
;;; `use-package-always-ensure` below to `t` start Emacs and then set
|
||
;;; it back to `nil` (or always have it set to `t`, if you prefer).
|
||
|
||
;;; **Note** that for Emacs 25 you first need to install new ELPA
|
||
;;; signing key as described
|
||
;;; [here](https://elpa.gnu.org/packages/gnu-elpa-keyring-update.html).
|
||
|
||
|
||
;;; Basic settings
|
||
;;; --------------
|
||
|
||
|
||
;;; ### Directory with local Emacs lisp files ###
|
||
|
||
;;; I add a directory to the lisp search path where I can add my own
|
||
;;; lisp code and (now less often) downloaded lisp code which is not
|
||
;;; available through [MELPA](https://melpa.org). Then I initialize
|
||
;;; secure downloading from GNU and MELPA archives of Emacs packages.
|
||
|
||
|
||
(let ((path (expand-file-name "~/.emacs.d/lisp")))
|
||
(if (file-accessible-directory-p path)
|
||
(add-to-list 'load-path path t)))
|
||
|
||
|
||
;;; ### Add MELPA package list ###
|
||
|
||
;;; You can install many Emacs packages from [MELPA](https://melpa.org)
|
||
;;; repository. To add MELPA to the package list add the following to your
|
||
;;; `~/.emacs.d/init.el` file
|
||
|
||
|
||
(require 'package)
|
||
(setq package-archives
|
||
'(("gnu" . "https://elpa.gnu.org/packages/")
|
||
("melpa-stb" . "https://stable.melpa.org/packages/")
|
||
("melpa" . "https://melpa.org/packages/"))
|
||
tls-checktrust t
|
||
tls-program '("gnutls-cli --x509cafile %t -p %p %h")
|
||
gnutls-verify-error t)
|
||
|
||
(package-initialize)
|
||
|
||
(setq use-package-always-ensure nil)
|
||
|
||
;;; This also turns on checking TLS certificates (in both possible
|
||
;;; modes) with `tls-program` set to only the first value from the
|
||
;;; default value (for more info see [Your Text Editor Is
|
||
;;; Malware](https://glyph.twistedmatrix.com/2015/11/editor-malware.html)).
|
||
|
||
;;; Now you can list available packages by running `M-x list-packages`.
|
||
;;; Mark packages you want to install by pressing `i` and later press `x`
|
||
;;; to install all marked packages (the necessary dependencies will be
|
||
;;; installed automatically).
|
||
|
||
;;; Now, load [use-package](https://github.com/jwiegley/use-package/)
|
||
;;; package or propose automatic installation if it is not yet
|
||
;;; installed.
|
||
|
||
(unless (require 'use-package nil t)
|
||
(if (not (yes-or-no-p (concat "Refresh packages, install use-package and"
|
||
" other packages used by init file? ")))
|
||
(error "you need to install use-package first")
|
||
(package-refresh-contents)
|
||
(package-install 'use-package)
|
||
(require 'use-package)
|
||
(setq use-package-always-ensure t)))
|
||
|
||
;;; After loading `use-package` we can use it to configure other
|
||
;;; packages.
|
||
|
||
|
||
;;; ### Workaround for security vulnerability in Emacs >= 21.1 and < 25.3 ###
|
||
;;;
|
||
;;; See [Changes in Emacs 25.3](https://www.gnu.org/software/emacs/news/NEWS.25.3)
|
||
|
||
(eval-after-load "enriched"
|
||
'(defun enriched-decode-display-prop (start end &optional param)
|
||
(list start end)))
|
||
|
||
|
||
;;; Productivity
|
||
;;; ------------
|
||
|
||
|
||
;;; ### Key discoverability ###
|
||
|
||
;;; If you type a prefix key (such as `C-x r`) and wait some time then
|
||
;;; display window with keys that can follow.
|
||
|
||
(use-package which-key
|
||
:config
|
||
(which-key-mode))
|
||
|
||
;;; Helm version for `C-h b`.
|
||
|
||
(use-package helm-descbinds
|
||
:demand
|
||
:config
|
||
(helm-descbinds-mode))
|
||
|
||
;;; List of personal key bindings
|
||
|
||
(global-set-key (kbd "C-c h b") 'describe-personal-keybindings)
|
||
|
||
|
||
;;; ### More efficient buffer/file selection ###
|
||
|
||
(setq recentf-max-saved-items 100)
|
||
|
||
(global-set-key "\C-cq" #'bury-buffer)
|
||
|
||
(use-package helm
|
||
:demand
|
||
:init
|
||
(setq helm-split-window-default-side 'other
|
||
helm-split-window-inside-p t
|
||
helm-command-prefix-key "s-c")
|
||
:config
|
||
(require 'helm-config) ; required to setup "s-c" keymap
|
||
(helm-mode 1)
|
||
(helm-autoresize-mode 1)
|
||
;; Only rebind M-x and C-x C-f on successful load of helm to remain
|
||
;; this basic operations if helm is not installed.
|
||
(bind-key "M-x" #'helm-M-x)
|
||
(bind-key "C-x C-f" #'helm-find-files)
|
||
:bind
|
||
(("M-y" . helm-show-kill-ring)
|
||
("C-c o" . helm-occur)
|
||
("C-x b" . helm-mini)
|
||
("C-x r b" . helm-bookmarks)
|
||
("C-h a" . helm-apropos)
|
||
("C-h d" . helm-info-at-point)
|
||
("C-c a" . helm-all-mark-rings)
|
||
("C-c h e" . helm-info-emacs)
|
||
("C-c h g" . helm-info-gnus)
|
||
("C-c R" . helm-register)
|
||
("s-p" . helm-run-external-command)
|
||
;; More key bindings in "s-c" keymap
|
||
:map helm-find-files-map
|
||
("<backtab>" . helm-select-action)
|
||
("C-i" . helm-execute-persistent-action)))
|
||
|
||
;;; Install [ripgrep](https://github.com/BurntSushi/ripgrep) (rg) and
|
||
;;; add
|
||
|
||
(use-package helm-rg
|
||
:bind
|
||
(("C-c r" . helm-rg)))
|
||
|
||
;;; File explorer sidebar
|
||
|
||
(use-package treemacs
|
||
:bind
|
||
(("C-c t" . treemacs)
|
||
("s-a" . treemacs)))
|
||
|
||
;;; Cycle through buffers' history
|
||
|
||
(use-package buffer-flip
|
||
:bind
|
||
(("s-o" . buffer-flip)
|
||
:map buffer-flip-map
|
||
("s-o" . buffer-flip-forward)
|
||
("s-O" . buffer-flip-backward)
|
||
("C-g" . buffer-flip-abort)))
|
||
|
||
;;; [fzf](https://github.com/junegunn/fzf) and
|
||
;;; [lcd](https://github.com/lukpank/lcd) for finding files and
|
||
;;; directories
|
||
|
||
(defun my-lcd ()
|
||
(interactive)
|
||
(fzf/start default-directory
|
||
(fzf/grep-cmd "lcd" "-l %s")))
|
||
|
||
(use-package fzf
|
||
:commands fzf/start
|
||
:bind
|
||
(("C-c f" . fzf)
|
||
("C-c D" . my-lcd)))
|
||
|
||
|
||
;;; ### Window selection enhancements ###
|
||
|
||
|
||
(use-package ace-window
|
||
:bind
|
||
("C-x o" . ace-window))
|
||
|
||
(use-package windmove
|
||
:demand
|
||
:bind
|
||
(("C-s-n" . windmove-down)
|
||
("C-s-p" . windmove-up)
|
||
("C-s-b" . windmove-left)
|
||
("C-s-f" . windmove-right)
|
||
("s-j" . windmove-down)
|
||
("s-k" . windmove-up)
|
||
("s-h" . windmove-left)
|
||
("s-l" . windmove-right))
|
||
:config
|
||
(windmove-default-keybindings))
|
||
|
||
;;; Switch between window configurations
|
||
|
||
(use-package eyebrowse
|
||
:config
|
||
(eyebrowse-mode))
|
||
|
||
;;; Allow for Undo/Redo of window manipulations (such as `C-x 1`)
|
||
|
||
(winner-mode 1)
|
||
|
||
|
||
;;; ### In buffer movement enhancements ###
|
||
|
||
;;; Improved in buffer search
|
||
|
||
(use-package helm-swoop
|
||
:bind
|
||
(("C-s" . helm-swoop-without-pre-input)
|
||
("C-S-s" . helm-swoop)))
|
||
|
||
;;; Type substring and wait to select one of its visible occurrences
|
||
;;; (even in other windows) with a single or two letters.
|
||
|
||
(use-package avy
|
||
:bind
|
||
("s-;" . avy-goto-char-timer))
|
||
|
||
;;; Bind key `o` to selection of a link in help or info buffers by a
|
||
;;; single or two letters.
|
||
|
||
(use-package ace-link
|
||
:config
|
||
(ace-link-setup-default))
|
||
|
||
;;; Select from visible errors by a single letter
|
||
|
||
(use-package avy-flycheck
|
||
:bind
|
||
("C-c '" . avy-flycheck-goto-error))
|
||
|
||
;;; Go to last change in the current buffer
|
||
|
||
(use-package goto-chg
|
||
:bind
|
||
("C-c G" . goto-last-change))
|
||
|
||
|
||
;;; ### Editing enhancements ###
|
||
|
||
;;; Context aware insertion of pairs of parenthesis
|
||
|
||
(use-package smartparens
|
||
:defer)
|
||
|
||
;;; Edit with multiple cursors
|
||
|
||
(use-package multiple-cursors
|
||
:bind
|
||
(("C-c n" . mc/mark-next-like-this)
|
||
("C-c p" . mc/mark-previous-like-this)))
|
||
|
||
;;; Fix trailing spaces but only in modified lines
|
||
|
||
(use-package ws-butler
|
||
:hook (prog-mode . ws-butler-mode))
|
||
|
||
|
||
;;; ### Spell checking ###
|
||
|
||
(setq ispell-dictionary "american")
|
||
|
||
(defun my-american-dict ()
|
||
"Change dictionary to american."
|
||
(interactive)
|
||
(setq ispell-local-dictionary "american")
|
||
(flyspell-mode 1)
|
||
(flyspell-buffer))
|
||
|
||
(defun my-polish-dict ()
|
||
"Change dictionary to polish."
|
||
(interactive)
|
||
(setq ispell-local-dictionary "polish")
|
||
(flyspell-mode 1)
|
||
(flyspell-buffer))
|
||
|
||
(defalias 'ir #'ispell-region)
|
||
|
||
|
||
;;; ### Shell and terminal ###
|
||
|
||
(use-package shell-pop
|
||
:init
|
||
(setq shell-pop-full-span t)
|
||
:bind (("C-c s" . shell-pop)))
|
||
|
||
(use-package helm-mt
|
||
:bind (("C-c z" . helm-mt))
|
||
;; hooks for fish shell (term-mode for Emacs 26 and term-exec for
|
||
;; Emacs 27)
|
||
:hook ((term-mode . toggle-truncate-lines)
|
||
(term-exec . toggle-truncate-lines)))
|
||
|
||
|
||
;;; ### Git ###
|
||
|
||
(use-package magit
|
||
:bind ("C-x g" . magit-status))
|
||
|
||
(use-package git-commit
|
||
:hook (git-commit-mode . my-american-dict))
|
||
|
||
(use-package git-messenger
|
||
:bind ("C-x G" . git-messenger:popup-message)
|
||
:config
|
||
(setq git-messenger:show-detail t
|
||
git-messenger:use-magit-popup t))
|
||
|
||
(use-package helm-git-grep
|
||
:bind
|
||
(("C-c j" . helm-git-grep)
|
||
("C-c J" . helm-git-grep-at-point)))
|
||
|
||
(use-package helm-ls-git
|
||
:bind
|
||
(("C-c g" . helm-ls-git-ls)))
|
||
|
||
|
||
;;; ### Switching buffers ###
|
||
|
||
;;; Bind keys from `s-s a` to `s-s z` to switch to buffers from a
|
||
;;; register from `a` to `z`.
|
||
|
||
(defalias 'pr #'point-to-register)
|
||
|
||
(defun my-switch-to-register ()
|
||
"Switch to buffer given by a register named by last character
|
||
of the key binding used to execute this command."
|
||
(interactive)
|
||
(let* ((v (this-command-keys-vector))
|
||
(c (aref v (1- (length v))))
|
||
(r (get-register c)))
|
||
(if (and (markerp r) (marker-buffer r))
|
||
(switch-to-buffer (marker-buffer r))
|
||
(jump-to-register c))))
|
||
|
||
(setq my-switch-to-register-map (make-sparse-keymap))
|
||
|
||
(let ((character ?a))
|
||
(while (<= character ?z)
|
||
(define-key my-switch-to-register-map
|
||
(char-to-string character) #'my-switch-to-register)
|
||
(setq character (1+ character))))
|
||
|
||
(global-set-key (kbd "s-s") my-switch-to-register-map)
|
||
|
||
|
||
;;; ### Yasnippet and abbrev mode ###
|
||
|
||
(setq-default abbrev-mode 1)
|
||
|
||
(use-package yasnippet
|
||
:hook (after-init . yas-global-mode)
|
||
:bind
|
||
(:map yas-minor-mode-map
|
||
("C-c & t" . yas-describe-tables)
|
||
("C-c & &" . org-mark-ring-goto)))
|
||
|
||
(use-package yasnippet-snippets
|
||
:defer)
|
||
|
||
(use-package helm-c-yasnippet
|
||
:bind
|
||
(("C-c y" . helm-yas-complete)))
|
||
|
||
|
||
;;; Programming languages
|
||
;;; ---------------------
|
||
|
||
|
||
;;; ### Common settings for programming modes ###
|
||
|
||
;;; For modes using [company](https://company-mode.github.io/) for tab
|
||
;;; completion add
|
||
|
||
(use-package company
|
||
:init
|
||
(setq company-idle-delay nil ; avoid auto completion popup, use TAB
|
||
; to show it
|
||
company-tooltip-align-annotations t)
|
||
:hook (after-init . global-company-mode)
|
||
:bind
|
||
(:map prog-mode-map
|
||
("C-i" . company-indent-or-complete-common)
|
||
("C-M-i" . completion-at-point)))
|
||
|
||
;;; For modes that also use Language Server Protocol from
|
||
;;; [lsp-mode](https://github.com/emacs-lsp/lsp-mode) add
|
||
|
||
(use-package company-lsp
|
||
:defer)
|
||
|
||
(use-package lsp-mode
|
||
:commands lsp
|
||
;; reformat code and add missing (or remove old) imports
|
||
:hook ((before-save . lsp-format-buffer)
|
||
(before-save . lsp-organize-imports))
|
||
:bind (("C-c d" . lsp-describe-thing-at-point)
|
||
("C-c e n" . flymake-goto-next-error)
|
||
("C-c e p" . flymake-goto-prev-error)
|
||
("C-c e r" . lsp-find-references)
|
||
("C-c e R" . lsp-rename)
|
||
("C-c e i" . lsp-find-implementation)
|
||
("C-c e t" . lsp-find-type-definition)))
|
||
|
||
;;; Compilation
|
||
|
||
(global-set-key "\C-ck" #'compile)
|
||
|
||
(use-package helm-make
|
||
:bind
|
||
(("C-c K" . helm-make)))
|
||
|
||
|
||
;;; [my common settings for programming modes]: #common-settings-for-programming-modes
|
||
|
||
|
||
;;; ### C and C++ ###
|
||
|
||
;;; The following Emacs packages [from MELPA](#add-melpa-package-list)
|
||
;;; need to be installed: [cmake-ide](https://melpa.org/#/cmake-ide),
|
||
;;; [company](https://melpa.org/#/company),
|
||
;;; [rtags](https://melpa.org/#/rtags), and
|
||
;;; [company-rtags](https://melpa.org/#/company-rtags). Package
|
||
;;; `cmake-ide` automatically configures other C++ Emacs packages
|
||
;;; (here `company` and `rtags`) when you open a C/C++ file from a
|
||
;;; project which uses [cmake](https://cmake.org) to build.
|
||
|
||
(defconst my-cc-style
|
||
'("k&r"
|
||
(c-offsets-alist . ((innamespace . [0])))))
|
||
|
||
(c-add-style "my-cc-mode" my-cc-style)
|
||
|
||
(setq-default c-basic-offset 8)
|
||
(setq c-default-style '((java-mode . "java")
|
||
(awk-mode . "awk")
|
||
(c++-mode . "my-cc-mode")
|
||
(other . "k&r"))
|
||
company-async-timeout 5 ; completion may be slow
|
||
rtags-completions-enabled t)
|
||
|
||
(use-package rtags
|
||
:defer
|
||
:config
|
||
(rtags-enable-standard-keybindings nil "C-c R"))
|
||
|
||
(use-package company-rtags
|
||
:defer)
|
||
|
||
(use-package cmake-ide
|
||
:after cc-mode
|
||
:config
|
||
(cmake-ide-setup))
|
||
|
||
(defun my-c-c++-mode-hook-fn ()
|
||
(set (make-local-variable 'company-backends) '(company-rtags))
|
||
(company-mode)
|
||
(local-set-key (kbd "M-.") #'rtags-find-symbol-at-point)
|
||
(local-set-key (kbd "M-,") #'rtags-location-stack-back)
|
||
(local-set-key "\C-i" #'company-indent-or-complete-common)
|
||
(local-set-key (kbd "<tab>") #'company-indent-or-complete-common)
|
||
(local-set-key "\C-\M-i" #'company-indent-or-complete-common))
|
||
|
||
(add-hook 'c-mode-hook #'my-c-c++-mode-hook-fn)
|
||
(add-hook 'c++-mode-hook #'my-c-c++-mode-hook-fn)
|
||
|
||
;;; Now:
|
||
|
||
;;; 1. Install [clang](http://clang.llvm.org/) compiler or more accurately
|
||
;;; `libclang` development package (package `libclang-dev` or may be newer
|
||
;;; `libclang-X-dev` under Debian) which is required by `rtags`.
|
||
|
||
;;; 2. Under Emacs having `rtags` package installed press `M-:` and
|
||
;;; evaluate expression `(require 'rtags)` and then press `M-:` and
|
||
;;; evaluate expression `(rtags-install nil
|
||
;;; '("-DRTAGS_NO_ELISP_FILES=true"))` (should work if you have
|
||
;;; `llvm-config` or `llvm-config-X` in your `PATH`) and wait until
|
||
;;; it compiles to 100%. The `rtags-install` command needs to be
|
||
;;; rerun if you install newer `rtags` from MELPA and the below
|
||
;;; commands do not work complaining about protocol mismatch.
|
||
|
||
;;; 3. Usefull `rtags` functions (use `C-c R C-h` to see these and other key bindings)
|
||
|
||
;;; | Key | Function
|
||
;;; |-----------|----------
|
||
;;; | `C-c R .` | `rtags-find-symbol-at-point`
|
||
;;; | `C-c R [` | `rtags-location-stack-back`
|
||
;;; | `C-c R ,` | `rtags-find-references-at-point`
|
||
;;; | `C-c R /` | `rtags-find-all-references-at-point`
|
||
;;; | | `rtags-find-references-current-file`
|
||
;;; | | `rtags-find-references-current-dir`
|
||
;;; | `C-c R v` | `rtags-find-virtuals-at-point`
|
||
;;; | `C-c R ;` | `rtags-find-file` (in the current project no metter in which directory)
|
||
|
||
|
||
;;; ### Lisp and Emacs lisp ###
|
||
|
||
;; in emacs 25.1: M-. runs xref-find-definitions, M-, jumps back
|
||
(global-set-key (kbd "C-c e l") #'find-library)
|
||
|
||
(setq slime-lisp-implementations '((sbcl ("sbcl")))
|
||
slime-default-lisp 'sbcl
|
||
slime-contribs '(slime-fancy))
|
||
|
||
(let ((path "/usr/local/share/doc/HyperSpec/"))
|
||
(if (file-accessible-directory-p path)
|
||
(setq common-lisp-hyperspec-root (concat "file://" path))))
|
||
|
||
(use-package paredit
|
||
:hook (eval-expression-minibuffer-setup . paredit-mode))
|
||
|
||
(use-package paren-face
|
||
:defer)
|
||
|
||
;; I do not want completion in extra frame
|
||
(setq helm-show-completion-display-function #'helm-default-display-buffer)
|
||
|
||
(defun my-emacs-lisp-mode-hook-fn ()
|
||
(set (make-local-variable 'lisp-indent-function) #'lisp-indent-function)
|
||
(paredit-mode 1)
|
||
(local-set-key (kbd "C-c S") (global-key-binding (kbd "M-s")))
|
||
(local-set-key (kbd "C-c C-z")
|
||
(lambda () (interactive) (switch-to-buffer "*scratch*")))
|
||
(local-set-key (kbd "C-M-i") #'helm-lisp-completion-at-point)
|
||
(show-paren-mode 1)
|
||
(paren-face-mode))
|
||
|
||
(use-package slime-company
|
||
:defer)
|
||
|
||
(use-package slime
|
||
:demand
|
||
:config
|
||
(slime-setup '(slime-fancy slime-company slime-cl-indent)))
|
||
|
||
(defun my-lisp-mode-hook-fn ()
|
||
(set (make-local-variable 'lisp-indent-function)
|
||
#'common-lisp-indent-function)
|
||
(paredit-mode 1)
|
||
(local-set-key (kbd "C-c S") (global-key-binding (kbd "M-s")))
|
||
(show-paren-mode 1)
|
||
(paren-face-mode)
|
||
(set (make-local-variable 'company-backends) '(company-slime))
|
||
(company-mode)
|
||
(local-set-key "\C-i" #'company-indent-or-complete-common))
|
||
|
||
(add-hook 'emacs-lisp-mode-hook #'my-emacs-lisp-mode-hook-fn)
|
||
(add-hook 'lisp-mode-hook #'my-lisp-mode-hook-fn)
|
||
|
||
|
||
;;; ### JavaScript ###
|
||
|
||
(setq js-indent-level 8)
|
||
|
||
|
||
;;; ### Go ###
|
||
|
||
;;; <div class="warning">
|
||
;;; This is my new Go setup (partially) based on <a
|
||
;;; href="https://github.com/golang/tools/blob/master/gopls/README.md">gopls</a> (which is
|
||
;;; still in alpha stage) and may not work for you if that is the case
|
||
;;; try my <a href="#old-go-setup">old Go setup
|
||
;;; (below)</a>. <code>gopls</code> supports Go modules outside of
|
||
;;; <code>GOPATH</code> (some Go tools, for example <code>guru</code>
|
||
;;; <a href="https://github.com/golang/go/issues/24661">does not</a>).
|
||
;;; </div>
|
||
|
||
;;; I use the following setup for the [go-mode] in my
|
||
;;; `~/.emacs.d/init.el`. This adds syntax highlighting but without
|
||
;;; fontifing names of called functions, autocompletion and info on
|
||
;;; called function in mode line, auto formatting of the code on save
|
||
;;; with adding of missing imports.
|
||
|
||
;;; It is quite long as I define two interactive functions:
|
||
|
||
;;; 1. `my-go-electric-brace` which is bind to `{` key and inserts an
|
||
;;; indented pair of braces (if previous character is a space,
|
||
;;; otherwise it inserts single opening brace),
|
||
|
||
;;; 2. `my-godoc-package` which is bind to `C-c P` key and display
|
||
;;; documentation for a package choosen from a list of installed
|
||
;;; packages.
|
||
|
||
;;; [go-mode]: https://github.com/dominikh/go-mode.el
|
||
|
||
;;; For **tab completion** and **lsp** support also add [my common
|
||
;;; settings for programming modes].
|
||
|
||
(defun my-go-electric-brace ()
|
||
"Insert an opening brace may be with the closing one.
|
||
If there is a space before the brace also adds new line with
|
||
properly indented closing brace and moves cursor to another line
|
||
inserted between the braces between the braces."
|
||
(interactive)
|
||
(insert "{")
|
||
(when (looking-back " {")
|
||
(newline)
|
||
(indent-according-to-mode)
|
||
(save-excursion
|
||
(newline)
|
||
(insert "}")
|
||
(indent-according-to-mode))))
|
||
|
||
(defun my-godoc-package ()
|
||
"Display godoc for given package (with completion)."
|
||
(interactive)
|
||
(godoc (or (helm :sources (helm-build-sync-source "Go packages"
|
||
:candidates (go-packages))
|
||
:buffer "*godoc packages*")
|
||
(signal 'quit nil))))
|
||
|
||
(use-package go-guru
|
||
:after go-mode)
|
||
|
||
(use-package go-mode
|
||
:init
|
||
(setq go-fontify-function-calls nil) ; fontifing names of called
|
||
; functions is too much for me
|
||
:bind
|
||
(:map go-mode-map
|
||
("C-c e g" . godoc)
|
||
("C-c P" . my-godoc-package)
|
||
("{" . my-go-electric-brace))
|
||
:hook ((go-mode . lsp)
|
||
(go-mode . smartparens-mode)))
|
||
|
||
;; Go/speedbar integration
|
||
|
||
(eval-after-load 'speedbar
|
||
'(speedbar-add-supported-extension ".go"))
|
||
|
||
|
||
;;; Now, in go buffers you can use `M-.` to jump to the definition of
|
||
;;; the identifier at point (use `M-,` to jump back as for normal tags
|
||
;;; in Emacs 25.1) and you can also use `C-c C-d` for a short
|
||
;;; description of the identifier at point (actually it is constantly
|
||
;;; displayed in the mode line by enabled lsp support). You can
|
||
;;; use `C-c d` for a longer description of the identifier at point.
|
||
|
||
;;; For this to work you have to
|
||
|
||
;;; 1. After adding above to your emacs config file see how to
|
||
;;; [install from MELPA all required packages](#add-melpa-package-list).
|
||
;;; Or just install [go-mode], [go-guru], [company-lsp].
|
||
|
||
;;; 2. Install Go compiler. Under Debian you may install `golang` package
|
||
;;; (but in Debian 10 Buster it is 1.11 compared to the current 1.13,
|
||
;;; so you may consider
|
||
;;; [downloading the current version of Go](https://golang.org/dl/)). Otherwise
|
||
;;; search for the package for your system or
|
||
;;; see [Getting started](https://golang.org/doc/install).
|
||
|
||
;;; 3. Install [gopls](https://github.com/golang/go/wiki/gopls) with
|
||
;;; (but in your home directory, not inside some Go module)
|
||
|
||
;;; ```
|
||
;;; $ GO111MODULE=on go get golang.org/x/tools/cmd/gopls@latest
|
||
;;; ```
|
||
|
||
;;; 4. Install [guru](https://godoc.org/golang.org/x/tools/cmd/guru)
|
||
;;; with
|
||
|
||
;;; ```
|
||
;;; $ go get -u golang.org/x/tools/cmd/guru
|
||
;;; ```
|
||
|
||
;;; 5. Add your `$GOPATH/bin` to your `PATH` environment variable (or
|
||
;;; copy the `gopls` and `guru` executables from
|
||
;;; `$GOPATH/bin` to some directory which is in your `PATH`).
|
||
|
||
;;; See also
|
||
;;; [Go, pls stop breaking my editor - GopherCon SG 2019](https://www.youtube.com/watch?v=gZ7N3HulAb0)
|
||
;;; and [Writing Go in Emacs](http://dominik.honnef.co/posts/2013/03/writing_go_in_emacs/)
|
||
;;; for more info.
|
||
|
||
;;; [company-lsp]: https://melpa.org/#/company-lsp
|
||
;;; [go-guru]: https://melpa.org/#/go-guru
|
||
|
||
|
||
;;; {{old-go.el}}
|
||
|
||
|
||
;;; ### Python ###
|
||
|
||
(use-package company-jedi
|
||
:defer)
|
||
|
||
(defun my-python-mode-hook-fn ()
|
||
(set (make-local-variable 'company-backends) '(company-jedi))
|
||
(company-mode)
|
||
(smartparens-mode 1)
|
||
(local-set-key (kbd "M-.") #'jedi:goto-definition)
|
||
(local-set-key (kbd "M-,") #'jedi:goto-definition-pop-marker)
|
||
(local-set-key "\C-i" #'company-indent-or-complete-common))
|
||
|
||
(add-hook 'python-mode-hook #'my-python-mode-hook-fn)
|
||
|
||
|
||
;;; ### Nim ###
|
||
|
||
(use-package lsp-mode
|
||
:commands lsp
|
||
:config
|
||
;; Register `nimlsp` from https://github.com/PMunch/nimlsp
|
||
(add-to-list 'lsp-language-id-configuration '(nim-mode . "nim"))
|
||
(lsp-register-client
|
||
(make-lsp-client :new-connection (lsp-stdio-connection '("nimlsp"))
|
||
:major-modes '(nim-mode)
|
||
:server-id 'nim-ls)))
|
||
|
||
(use-package highlight-indent-guides
|
||
:defer
|
||
:init
|
||
(setq highlight-indent-guides-method 'character))
|
||
|
||
(use-package nim-mode
|
||
:hook ((nim-mode . highlight-indent-guides-mode)
|
||
(nim-mode . lsp)))
|
||
|
||
|
||
;;; ### Rust ###
|
||
|
||
;;; If you have Emacs 26 than you need
|
||
;;; [Rustup](https://www.rust-lang.org/learn/get-started) and using
|
||
;;; Rustup you should install component
|
||
;;; [rls](https://github.com/rust-lang/rls) with the command
|
||
;;;
|
||
;;; ```
|
||
;;; $ rustup component add rls
|
||
;;; ```
|
||
;;;
|
||
;;; For **tab completion** and **lsp** support add [my common settings
|
||
;;; for programming modes] and then add
|
||
|
||
(when (>= emacs-major-version 26)
|
||
(defun my-rustic-mode-hook-fn ()
|
||
"needed for lsp-format-buffer to indent with 4 spaces"
|
||
(setq tab-width 4
|
||
indent-tabs-mode nil))
|
||
|
||
(use-package rustic
|
||
:init
|
||
;; to use rustic-mode even if rust-mode also installed
|
||
(setq auto-mode-alist (delete '("\\.rs\\'" . rust-mode) auto-mode-alist))
|
||
:hook (rustic-mode . my-rustic-mode-hook-fn)))
|
||
|
||
;;; But if you have Emacs older than 26 than you should install
|
||
;;; [racer](https://github.com/racer-rust/racer) and for **tab
|
||
;;; completion** add [my common settings for programming modes] and
|
||
;;; then add
|
||
|
||
(when (< emacs-major-version 26)
|
||
(use-package cargo
|
||
:defer)
|
||
|
||
(use-package racer
|
||
:defer)
|
||
|
||
(use-package rust-mode
|
||
:init
|
||
(setq rust-format-on-save t)
|
||
:hook ((rust-mode . company-mode)
|
||
(rust-mode . cargo-minor-mode)
|
||
(rust-mode . racer-mode)
|
||
(rust-mode . eldoc-mode))))
|
||
|
||
|
||
;;; ### Meson build system ###
|
||
|
||
(use-package meson-mode
|
||
:defer
|
||
:init
|
||
(setq meson-indent-basic 4))
|
||
|
||
|
||
;;; ### Vala ###
|
||
|
||
(use-package lsp-mode
|
||
:commands lsp
|
||
:config
|
||
(add-to-list 'lsp-language-id-configuration '(vala-mode . "vala"))
|
||
(lsp-register-client
|
||
(make-lsp-client :new-connection (lsp-stdio-connection
|
||
'("vala-language-server"))
|
||
:major-modes '(vala-mode)
|
||
:server-id 'vala-ls)))
|
||
|
||
(use-package dumb-jump
|
||
:defer)
|
||
|
||
(defun my-vala-mode-hook-fn ()
|
||
(setq c-basic-offset 4
|
||
tab-width 8
|
||
indent-tabs-mode nil)
|
||
(set (make-local-variable 'company-backends) '(company-lsp))
|
||
(company-mode 1)
|
||
(dumb-jump-mode)
|
||
(local-set-key "\C-i" #'company-indent-or-complete-common)
|
||
(lsp))
|
||
|
||
(use-package vala-mode
|
||
:hook (vala-mode . my-vala-mode-hook-fn))
|
||
|
||
|
||
;;; ### Dart ###
|
||
|
||
;;; NOTE: `pub` and `dart` must be in `PATH` for lsp to start in
|
||
;;; dart-mode.
|
||
|
||
;;; For **tab completion** and **lsp** support also add [my common
|
||
;;; settings for programming modes].
|
||
|
||
(use-package dart-mode
|
||
:init
|
||
(setq lsp-dart-analysis-sdk-dir "~/local/flutter/bin/cache/dart-sdk/")
|
||
:hook ((dart-mode . smartparens-mode)
|
||
(dart-mode . lsp)))
|
||
|
||
(use-package flutter
|
||
:after dart-mode
|
||
:init
|
||
(setq flutter-sdk-path "~/local/flutter/")
|
||
:bind
|
||
(:map dart-mode-map
|
||
("C-M-x" . #'flutter-run-or-hot-reload)))
|
||
|
||
|
||
;;; ### PHP ###
|
||
|
||
(use-package php-mode
|
||
:defer)
|
||
|
||
(use-package company-php
|
||
:defer)
|
||
|
||
(defun my-php-mode-hook-fn()
|
||
(when (require 'company-php nil t)
|
||
(set (make-local-variable 'company-backends)
|
||
'(company-ac-php-backend))
|
||
(company-mode t)
|
||
(local-set-key (kbd "M-.") #'ac-php-find-symbol-at-point)))
|
||
|
||
(add-hook 'php-mode-hook #'my-php-mode-hook-fn)
|
||
|
||
|
||
;;; ### TypeScript ###
|
||
|
||
(defun my-setup-tide-mode ()
|
||
(tide-setup)
|
||
(flycheck-mode 1)
|
||
(setq flycheck-check-syntax-automatically '(save mode-enabled))
|
||
(eldoc-mode 1)
|
||
(company-mode 1))
|
||
|
||
(use-package typescript-mode
|
||
:init
|
||
(setq typescript-indent-level 2)
|
||
:bind
|
||
(:map typescript-mode-map
|
||
("C-i" . company-indent-or-complete-common)
|
||
("C-M-i" . company-indent-or-complete-common)))
|
||
|
||
(use-package tide
|
||
:after typescript-mode
|
||
:hook ((before-save . tide-format-before-save)
|
||
(typescript-mode . my-setup-tide-mode)))
|
||
|
||
(use-package ng2-mode
|
||
:defer)
|
||
|
||
|
||
;;; Other modes
|
||
;;; -----------
|
||
|
||
|
||
;;; ### Web mode ###
|
||
|
||
(defun my-web-mode-hook-fn()
|
||
(cond
|
||
((string= web-mode-engine "php")
|
||
(my-php-mode-hook-fn))))
|
||
|
||
(use-package web-mode
|
||
:init
|
||
(add-hook 'web-mode-hook #'my-web-mode-hook-fn)
|
||
(add-to-list 'auto-mode-alist '("\\.php\\'" . web-mode))
|
||
:bind
|
||
(:map web-mode-map
|
||
("C-i" . company-indent-or-complete-common)))
|
||
|
||
|
||
;;; ### CSS ###
|
||
|
||
(use-package rainbow-mode
|
||
:hook (css-mode . rainbow-mode))
|
||
|
||
|
||
;;; ### Org mode ###
|
||
|
||
(use-package org-bullets
|
||
:defer)
|
||
|
||
(use-package org
|
||
:init
|
||
(setq org-default-notes-file "~/org/notes.org"
|
||
org-highlight-latex-and-related '(latex)
|
||
org-bullets-bullet-list '("●" "○" "✸" "✿")
|
||
org-ellipsis "…"
|
||
org-catch-invisible-edits 'smart
|
||
gnuplot-program "pyxplot")
|
||
(defun my-org-timer-done ()
|
||
(shell-command "echo Timer timed out; date &"))
|
||
:bind
|
||
(("C-c A" . org-agenda)
|
||
("C-c B" . org-switchb)
|
||
("C-c c" . org-capture)
|
||
("C-c l" . org-store-link))
|
||
:hook ((org-timer-done . my-org-timer-done)
|
||
(org-mode . org-bullets-mode))
|
||
:config
|
||
(require 'ox-beamer))
|
||
|
||
|
||
;;; ### Search engines ###
|
||
|
||
(use-package engine-mode
|
||
:config
|
||
(engine-mode t)
|
||
(defengine duckduckgo
|
||
"https://duckduckgo.com/?q=%s"
|
||
:keybinding "d")
|
||
(defengine google
|
||
"http://www.google.com/search?ie=utf-8&oe=utf-8&q=%s"
|
||
:keybinding "g"))
|
||
|
||
|
||
;;; ### WWW browsers ###
|
||
|
||
(setq my-browsers
|
||
'(("Firefox" . browse-url-firefox)
|
||
("Chromium" . browse-url-chromium)
|
||
("EWW" . eww-browse-url)))
|
||
|
||
(defun my-browse-url (&rest args)
|
||
"Select the prefered browser from a helm menu before opening the URL."
|
||
(interactive)
|
||
(let ((browser (or (helm :sources (helm-build-sync-source "WWW browsers"
|
||
:candidates (mapcar 'car my-browsers))
|
||
:buffer "*my browsers*")
|
||
(signal 'quit nil))))
|
||
(apply (cdr (assoc browser my-browsers)) args)))
|
||
|
||
(setq browse-url-browser-function #'my-browse-url)
|
||
|
||
(defun my-eww-scale-adjust ()
|
||
"Slightly bigger font but text shorter than text."
|
||
(interactive)
|
||
(text-scale-adjust 0)
|
||
(text-scale-adjust 1)
|
||
(eww-toggle-fonts)
|
||
(split-window-right)
|
||
(eww-toggle-fonts)
|
||
(other-window 1)
|
||
(sleep-for 1)
|
||
(delete-window))
|
||
|
||
|
||
;;; ### API documentation ###
|
||
|
||
(when (require 'devdocs-lookup nil t)
|
||
(devdocs-setup))
|
||
|
||
|
||
;;; Appearance and custom file
|
||
;;; --------------------------
|
||
|
||
|
||
;;; ### Minimalistic look ###
|
||
|
||
(setq inhibit-startup-screen t
|
||
frame-title-format (list "[" user-login-name "@" (system-name)
|
||
"] %b")
|
||
ediff-window-setup-function #'ediff-setup-windows-plain)
|
||
(set-scroll-bar-mode 'right)
|
||
(menu-bar-mode 0)
|
||
(tool-bar-mode 0)
|
||
|
||
|
||
;;; ### Easy switching between some fonts ###
|
||
|
||
(setq my-font-list '("Fantasque Sans Mono" "Go mono" "IBM 3270"
|
||
"Inconsolata" "Monofur" "Monoid" "mononoki"))
|
||
|
||
(defun my-set-frame-font (font-name size &optional frames)
|
||
"Set font to one of the fonts from `my-font-list'
|
||
Argument FRAMES has the same meaning as for `set-frame-font'"
|
||
(interactive
|
||
(list (or (helm :prompt "Font name: "
|
||
:resume 'noresume
|
||
:sources (helm-build-sync-source "Fonts"
|
||
:candidates my-font-list)
|
||
:buffer "*font selection*")
|
||
(signal 'quit nil))
|
||
(read-number "Font size: ")))
|
||
(set-frame-font
|
||
(format "%s:pixelsize=%d:antialias=true:autohint=true" font-name size)
|
||
nil frames))
|
||
|
||
(global-set-key (kbd "C-c F") #'my-set-frame-font)
|
||
|
||
|
||
;;; ### Easy switching between themes ###
|
||
|
||
(defun my-helm-themes-after ()
|
||
(set-face-background 'scroll-bar "#908070"))
|
||
|
||
(use-package helm-themes
|
||
:bind
|
||
(("C-c T" . helm-themes))
|
||
:config
|
||
;; need to update powerline after changing theme
|
||
(advice-add 'helm-themes :after #'my-helm-themes-after))
|
||
|
||
|
||
;;; ### Toggle between dark and light themes with a key ###
|
||
|
||
(setq my-dark-theme 'gruvbox-dark-medium
|
||
my-light-theme 'gruvbox-light-medium)
|
||
|
||
(defun my-toggle-theme ()
|
||
"Toggle between dark and light themes"
|
||
(interactive)
|
||
(let ((dark-p (custom-theme-enabled-p my-dark-theme)))
|
||
(mapc #'disable-theme custom-enabled-themes)
|
||
(load-theme (if dark-p my-light-theme my-dark-theme) t))
|
||
(my-helm-themes-after))
|
||
|
||
(global-set-key (kbd "C-S-<f6>") #'my-toggle-theme)
|
||
|
||
(use-package gruvbox-theme
|
||
:config
|
||
(my-toggle-theme))
|
||
|
||
(defun my-frame-setup-fn (&optional frame)
|
||
(unless (display-graphic-p frame)
|
||
(set-face-background 'default "unspecified-bg"
|
||
(or frame (selected-frame)))))
|
||
|
||
(add-hook 'after-make-frame-functions #'my-frame-setup-fn)
|
||
(add-hook 'window-setup-hook #'my-frame-setup-fn)
|
||
|
||
|
||
;;; ### My customization for some used themes ###
|
||
|
||
(eval-after-load 'firebelly-theme
|
||
'(custom-theme-set-faces
|
||
'firebelly
|
||
'(font-lock-comment-delimiter-face ((t (:foreground "#505050"))))))
|
||
|
||
(eval-after-load 'nimbus-theme
|
||
'(custom-theme-set-faces
|
||
'nimbus
|
||
'(region ((t (:background "#505050"))))))
|
||
|
||
|
||
;;; ### Use separate custom file ###
|
||
|
||
(setq custom-file "~/.emacs.d/custom.el")
|
||
(if (file-exists-p custom-file)
|
||
(load custom-file))
|