Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/FredeEB/.emacs.d

My personal Emacs config
https://github.com/FredeEB/.emacs.d

Last synced: about 2 months ago
JSON representation

My personal Emacs config

Awesome Lists containing this project

README

        

* introduction
This is my config. It does just about everything I need it to do, and /a lot/ more than that too.
I run emacs 28 which is why it's included as a submodule. It has been running rocksolid since forever.
** this is my personal config (DISCLAIMER)
Just to let you know. If you want to use it, or parts of it, be my guest. All of the configuration is in [[https://github.com/FredeEB/.emacs.d/blob/master/config.org][config.org]]. I've been very sparse with comments, but the headings should be pretty descriptive, however if you're looking for something in there, just ==, ==, =/= or what ever you do.

I'm running this config for work with emacs 28.0.50, and thus I cannot guarentee but might work with previous versions without modification, or it might not.

To use it, just clone this repo to whereever your emacs config is (usually =/home/$(USER)/.emacs.d=) and remember to back up your old one, if you have one. You can then try it with whatever version of Emacs you have installed to see if it works. But as mentioned, it's only been tested with Emacs 28.0.50, meaning you'd have to either build it from source, or fetch a binary from your local software pusher (soure can be found here [[https://git.savannah.gnu.org/git/emacs.git]]).

Also, I'm /NOT/ responsible for anything that happens to anything that touches these files.
* basics
Setting up the basics early, so if the config breaks further along, I'll still have evil
also, setting some code block properties that help.
#+PROPERTY: header-args :results silent
** package manager
I use straight for managing packages. It's a very painless process to spin up a new machine, just by downloading the repo and starting up emacs.
The config for this can be found in [[file:init.el::defvar bootstrap-version][init.el]].
** evil-mode
Yes, I also came from [neo]vi[m], so ofc evil is gonna be in here.
These are some nice packages that relate to evil, however there are "evil-*" packages more throughout the file
#+begin_src emacs-lisp :tangle yes
(setq evil-want-integration t
evil-want-keybinding nil
evil-want-C-i-jump nil)

(use-package evil-leader
:init
(global-evil-leader-mode)
(evil-leader/set-leader ""))

(use-package evil-collection
:after evil-leader
:custom
(evil-collection-company-use-tng nil)
:init
(evil-collection-init))

(use-package evil
:after evil-collection
:custom (evil-undo-system 'undo-tree)
:init
(evil-mode 1))

(use-package evil-anzu)
(use-package evil-surround
:config
(global-evil-surround-mode))

(use-package evil-owl
:custom
(evil-owl-display-method 'posframe)
(evil-owl-extra-posfram-args '(:width 50 :height 20))
(evil-owl-idle-delay 0)
:init
(evil-owl-mode))

(use-package evil-matchit)

(use-package evil-avy
:mode (prog-mode . evil-avy-mode))
#+end_src
** misc
misc default settings
#+begin_src emacs-lisp :tangle yes
(setq-default scroll-conservatively 100
inhibit-startup-message t
initial-scratch-message ""
indent-tabs-mode nil
ring-bell-function 'ignore
tab-width 4
create-lockfiles nil
default-directory (expand-file-name "~/")
tramp-default-method "ssh"
large-file-warning-threshold nil
custom-file (expand-file-name "customs.el" user-emacs-directory)
delete-trailing-lines t
tramp-smb-conf nil
windmove-wrap-around t
c-basic-offset 4)

(add-hook 'prog-mode-hook
(lambda ()
(make-local-variable 'scroll-margin)
(setq scroll-margin 20)))

(use-package undo-tree
:config (global-undo-tree-mode))

(defvaralias 'c-basic-offset 'tab-width)
(defalias 'yes-or-no-p 'y-or-n-p)
(defvaralias 'c-basic-offset 'tab-width)

(global-subword-mode)

(tool-bar-mode -1)
(menu-bar-mode -1)
(scroll-bar-mode -1)
(add-hook 'prog-mode-hook 'display-line-numbers-mode)

(setq shell-file-name "bash")
(setq shell-command-switch "-c")

(setq auto-save-visited-file-name t)

;; Autorevert buffers
(global-auto-revert-mode)

;; File beautification
(add-hook 'before-save-hook 'delete-trailing-whitespace)

;; Electricity!!
(add-hook 'prog-mode-hook 'electric-pair-mode)

;; environments
(use-package exec-path-from-shell
:config (exec-path-from-shell-initialize))

;; make tramp play nice
(eval-after-load 'tramp '(setenv "SHELL" "/bin/bash"))

;; File beautification
(setq delete-trailing-lines t)
(add-hook 'before-save-hook 'delete-trailing-whitespace)

;; font
(add-to-list 'default-frame-alist '(font . "Iosevka Nerd Font 10"))
#+end_src
** helm
#+begin_src emacs-lisp :tangle yes
(use-package helm
:init
(require 'helm-config)
(helm-mode)
:custom
(helm-mini-default-sources
'(helm-source-buffers-list
helm-source-buffer-not-found)))
(use-package helm-company)
(use-package helm-projectile)
(use-package helm-rg)

(use-package helm-fzf
:straight (helm-fzf :type git :host github :repo "ibmandura/helm-fzf"))
(use-package helm-make
:custom
(helm-make-build-dir "build"))
(use-package helm-flyspell)
(add-hook 'org-mode-hook 'flyspell-mode)
(add-hook 'markdown-mode-hook 'flyspell-mode)
(use-package helm-lsp)
#+end_src
* utils
** elfeed
#+begin_src emacs-lisp :tangle yes
(use-package elfeed
:custom
(elfeed-feeds
'(
;;dr.dk
"https://www.dr.dk/nyheder/service/feeds/allenyheder"

;;ing.dk
"https://ing.dk/rss/nyheder"

;;dev.to
"http://dev.to/feed"

;;reddit
"http://reddit.com/r/clojure/.rss"
"http://reddit.com/r/cpp/.rss"
"http://reddit.com/r/emacs/.rss"
"http://reddit.com/r/golang/.rss"
"http://reddit.com/r/rust/.rss"
"http://reddit.com/r/bindingofisaac/.rss"

;;hackernews
"https://news.ycombinator.com/rss"

;;medium
"https://medium.com/feed/topic/technology"
"https://medium.com/feed/topic/programming"
"https://medium.com/feed/topic/gaming"

;;other blogs
"https://cestlaz.github.io/rss.xml"
)))
#+end_src
** mail
#+BEGIN_SRC emacs-lisp :tangle yes
(when (file-exists-p "/usr/share/emacs/site-lisp/mu4e")
(add-to-list 'load-path "/usr/share/emacs/site-lisp/mu4e")
(require 'mu4e)

(use-package mu4e-alert))
#+END_SRC
** dashboard
#+begin_src emacs-lisp :tangle yes
(use-package dashboard
:config
(dashboard-setup-startup-hook)
:custom
;; set initial buffer for emacsclient
(initial-buffer-choice (lambda () (get-buffer "*dashboard*")))
(dashboard-banner-logo-title "")
(dashboard-startup-banner (expand-file-name "banner.png" user-emacs-directory))
(dashboard-center-content t))
#+end_src
* git
** magit
magit is the best git client in the multiverse. I use the evil variant.
#+begin_src emacs-lisp :tangle yes
(use-package evil-magit
:init
(evil-magit-init)
:custom
(magit-repository-directories (expand-file-name "~/git/projects"))
(magit-module-sections-nested nil))

(magit-add-section-hook 'magit-status-sections-hook
'magit-insert-modules
'magit-insert-unpulled-from-upstream)
#+end_src

As well as some other packages that relate
#+begin_src emacs-lisp :tangle yes
(use-package forge)
(use-package ssh-agency)
#+end_src

Tools for more git integration. Git timemachine let's you check the git log in the buffer and is extremely useful
git gutter are the plus and minus signs that show you what's added/removed/changed on the left
#+begin_src emacs-lisp :tangle yes
(use-package git-timemachine)
(use-package git-gutter-fringe+
:config
(global-git-gutter+-mode)
(git-gutter-fr+-minimal))
#+end_src
** dired
#+begin_src emacs-lisp :tangle yes
(defun dired-run-at-point ()
(interactive)
(let ((process (dired-file-name-at-point)))
(async-start-process (file-name-base process) process '(lambda (arg)))))

(dired-async-mode 1)
#+end_src
* p4
As long as it lasts
#+begin_src emacs-lisp :tangle yes
(defun p4-edit-file ()
(interactive)
(call-process-shell-command (format "p4 edit %s" (buffer-file-name)))
(revert-buffer t t nil))

(defun p4-revert-file ()
(interactive)
(call-process-shell-command (format "p4 revert %s" (buffer-file-name)))
(revert-buffer t t nil))

(defun p4-add-file ()
(interactive)
(call-process-shell-command (format "p4 add %s" (buffer-file-name)))
(revert-buffer t t nil))

(defun p4-integrate-file ()
(interactive)
(call-process-shell-command (format "p4 integrate %s" (buffer-file-name)))
(revert-buffer t t nil))

(defun p4-diff-file ()
(interactive)
(let ((buffer "*p4-diff*"))
(call-process-shell-command (format "p4 diff %s" (buffer-file-name)) nil buffer)
(switch-to-buffer buffer)
(diff-mode)
(view-mode-enter nil 'kill-buffer)))
#+end_src
* qol
Quality of life packages. many require external software. Look at each package for dependecies
** engine
used to search web resources.
#+begin_src emacs-lisp :tangle yes
(use-package engine-mode
:straight (:branch "main")
:config
(defengine cppreference
"https://en.cppreference.com/mwiki/index.php?search=%s")
(defengine cmake
"https://cmake.org/cmake/help/latest/search.html?q=%s&check_keywords=yes&area=default")
(defengine google
"https://google.com/search?q=%s")
(defengine youtube
"https://www.youtube.com/results?search_query=%s")
(defengine dockerhub
"https://hub.docker.com/search?q=%s&type=image")
(defengine github
"https://github.com/search?q=%s")
(defengine rustdoc
"https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html?search=%s")
(defengine wikipedia
"https://en.wikipedia.org/wiki/%s"))
#+end_src
** utilities
#+begin_src emacs-lisp :tangle yes
(use-package sudo-edit)
#+end_src
** docker
#+begin_src emacs-lisp :tangle yes
(use-package docker)
(straight-use-package '(dockerfile-mode :type git :repo "fredeeb/dockerfile-mode"))
(setq dockerfile-use-buildkit t)
(use-package docker-compose-mode
:mode ("docker-compose.yml\\'" . docker-compose-mode))
(use-package docker-tramp
:config (add-to-list 'tramp-remote-path 'tramp-own-remote-path))
#+end_src
** openwith
requires zathura for pdf reading. feh for image viewing (not all formats are tested).
#+begin_src emacs-lisp :tangle yes
(use-package openwith
:config
(openwith-mode t)
:custom
(openwith-associations
'(("\\.pdf\\'" "zathura" (file))
("\\.jpg\\'" "feh" (file))
("\\.svg\\'" "feh" (file))
("\\.jpeg\\'" "feh" (file))
("\\.bmp\\'" "feh" (file))
("\\.flac\\'" "mpv" (file))
("\\.mkv\\'" "mpv" (file))
("\\.wav\\'" "mpv" (file))
("\\.mp3\\'" "mpv" (file))
("\\.mp4\\'" "mpv" (file)))))
#+end_src
** vterm
#+begin_src emacs-lisp :tangle yes
(use-package vterm
:custom
(vterm-shell "zsh")
:custom
(vterm-always-compile-module t))
#+end_src
** compilation
#+begin_src emacs-lisp :tangle yes
(setq compilation-scroll-output t
compilation-window-height 20)

(require 'ansi-color)
(defun colorize-compilation ()
"Colorize from `compilation-filter-start' to `point'."
(let ((inhibit-read-only t))
(ansi-color-apply-on-region
compilation-filter-start (point))))

(add-hook 'compilation-filter-hook
#'colorize-compilation)

;; C++
;; set ctest to output on failure
(setenv "CTEST_OUTPUT_ON_FAILURE" "1")
(defun compile-c++-things ()
(interactive)
(if-let* ((root (vc-root-dir))
(cmake (concat root "/CMakeLists.txt"))
(build (concat root "/build")))
(call-process "cmake" nil nil nil "-S" root "-B" build)
(message "Not in a repository"))
(helm-make-projectile (string-to-number (first (process-lines "nproc")))))
#+end_src
* org stuff
** journals
I've created a personal journal system that creates a new journal entry in =journal-dir= every day. This file is the default target for org agenda entries created with =M-x org-capture t= and =M-x org-capture n= for TODO items under TODAY and miscellaneous notes under the NOTES header, respectively.

Issues with questions or bugs and PR's are welcome, but I only fix/merge things i feel improves my workflow.

#+begin_src emacs-lisp :tangle yes
(defvar journal-dir
(expand-file-name"~/journals/"))

(defvar journal
(format "%sjournal%s.org"
journal-dir
(format-time-string "%Y%m%d")))

(defvar org-journal-template
(concat
"#+TITLE: Journal\n"
"#+DATE: " (format-time-string "%A %d/%m/%Y\n")
"* TODAY\n"
"* NOTES"))

(defun find-journal (days-ago)
"Find journal from DAYS-AGO"
(interactive "p")
(if (not current-prefix-arg)
(find-file
journal)
(find-file
(concat
journal-dir
"journal"
(format-time-string
"%Y%m%d"
(seconds-to-time (- (time-to-seconds) (* days-ago 86400))))
".org"))))
#+end_src

Setting org todo keyword and agenda templates
#+begin_src emacs-lisp :tangle yes
(setq org-todo-keywords
'((sequence "TODO(t)" "DOING(p)" "|" "DONE(d)" "|" "NOT FINISHED(n)"))
org-columns-default-format
"%25ITEM %TODO %DEADLINE %EFFORT %TAGS"
org-capture-templates
'(("t" "Todo" entry (file+headline journal "TODAY")
"** TODO %?\n")
("n" "Note" entry (file+headline journal "NOTES")
"** %?\n\n")))
#+end_src
** sourceblocks
Modes and settings for org source blocks
#+begin_src emacs-lisp :tangle yes
(use-package ob-async)
(use-package ob-rust)
(require 'org-tempo)
(setq org-confirm-babel-evaluate nil
org-startup-with-inline-images t
org-startup-with-latex-preview t
org-export-babel-evaluate nil)

(org-babel-do-load-languages
'org-babel-load-languages
'((C . t)
(calc . t)
(clojure . t)
(emacs-lisp . t)
(js . t)
(makefile . t)
(plantuml . t)
(python . t)
(rust . t)
(shell . t)))
#+end_src
** misc
pretty things
#+begin_src emacs-lisp :tangle yes
(add-hook 'org-mode-hook 'visual-line-mode)
(add-hook 'markdown-mode-hook 'visual-line-mode)

(use-package org-bullets
:config
(add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))
#+end_src
** flyspell
#+begin_src emacs-lisp :tangle yes
#+end_src
* programming
** company
company completes anything and it works wonderfully
#+begin_src emacs-lisp :tangle yes
(use-package company
:hook ((prog-mode docker-compose-mode) . company-mode)
:custom
(company-idle-delay 0)
(company-minimum-prefix-length 1)
(company-tooltip-align-annotations t)
(company-tooltip-limit 10)
(company-idle-delay 0)
(company-echo-delay (if (display-graphic-p) nil 0))
(company-minimum-prefix-length 2)
(company-require-match 'never)
(company-show-numbers t)
(company-global-modes '(not erc-mode message-mode help-mode gud-mode eshell-mode shell-mode))
(company-backends '(company-capf)))

(use-package company-box
:hook (company-mode . company-box-mode))

(use-package company-posframe
:config
(company-posframe-mode)
:custom
(company-posframe-quickhelp-delay nil))
#+end_src
** flycheck
#+begin_src emacs-lisp :tangle yes
(use-package flycheck)
#+end_src
** lsp
#+begin_src emacs-lisp :tangle yes
(use-package lsp-mode
:hook
((c++-mode c-mode rust-mode go-mode csharp-mode python-mode cmake-mode) . lsp)
:custom
(lsp-diagnostic-package :flycheck)
(lsp-prefer-capf t)
(read-process-output-max (* 1024 1024)))
(use-package lsp-ui
:custom
(lsp-ui-doc-max-width 80)
(lsp-ui-doc-position 'top))
(use-package lsp-treemacs)
(use-package dap-mode
:init
(require 'dap-gdb-lldb)
(require 'dap-go)
;;download debuggers, REQUIRES unzip
(when (not (file-exists-p (expand-file-name ".extension" user-emacs-directory)))
(dap-gdb-lldb-setup t)
(dap-go-setup t)))
#+end_src
** lisp
All the lispy things
#+begin_src emacs-lisp :tangle yes
(use-package evil-paredit
:hook
(emacs-lisp-mode-hook . evil-paredit-mode)
(emacs-lisp-mode-hook . paredit-mode))

;; elisp
(use-package elsa)
(use-package eros
:hook (eros-mode . emacs-lisp-mode))
#+end_src
** python
#+begin_src emacs-lisp :tangle yes
(use-package pipenv
:hook (python-mode . pipenv-mode)
:custom
(pipenv-projectile-after-switch-function #'pipenv-projectile-after-switch-extended))
#+end_src
** c++
this is what I use most in this configuration
#+begin_src emacs-lisp :tangle yes
(c-set-offset 'substatement-open 0)
(c-set-offset 'innamespace 0)
(c-set-offset 'brace-list-open 0)
(setq c-basic-offset 4)

(setq lsp-clients-clangd-args
'("-j=8"
"--header-insertion=never"
"--all-scopes-completion"
"--background-index"
"--clang-tidy"
"--compile-commands-dir=build"
"--cross-file-rename"
"--suggest-missing-includes"))

(use-package modern-cpp-font-lock
:config
(modern-c++-font-lock-global-mode))

(use-package cmake-mode)
#+end_src
** rust
#+begin_src emacs-lisp :tangle yes
(use-package cargo
:hook (rust-mode . cargo-minor-mode)
:custom
(lsp-rust-server 'rust-analyzer))
(use-package toml-mode)
#+end_src
** lua
#+begin_src emacs-lisp :tangle yes
(use-package lua-mode
:mode ("\\.lua\\'")
:hook (lua-mode . lsp))
#+end_src
** go
#+begin_src emacs-lisp :tangle yes
(use-package go-mode
:config
(push (expand-file-name "~/go/bin") exec-path))

(defun go-run ()
(interactive)
(save-buffer)
(let ((buffer "*go*"))
(start-process "*go*" buffer "go" "run" (buffer-name))
(switch-to-buffer buffer)
(view-mode)))
#+end_src
** web
#+begin_src emacs-lisp :tangle yes
(use-package emmet-mode
:custom
(emmet-expand-jsx-className t))

(use-package web-mode
:mode ("\\.ts\\'" "\\.tsx\\'" "\\.js\\'" "\\.jsx\\'")
:hook (web-mode . lsp))
(use-package restclient)
(use-package ob-restclient)
#+end_src
** yasnippet
All the snippets! (or atleast most of them)
#+begin_src emacs-lisp :tangle yes
(use-package yasnippet-snippets)
(use-package react-snippets)

(use-package yasnippet
:init
(yas-global-mode 1))

(use-package auto-yasnippet)

(defun company-yasnippet-or-completion ()
(interactive)
(let ((yas-fallback-behavior nil))
(unless (yas-expand)
(call-interactively #'company-complete-common))))

(add-hook 'company-mode-hook
(lambda () (substitute-key-definition
'company-complete-common
'company-yasnippet-or-completion
company-active-map)))
#+end_src
** others
#+begin_src emacs-lisp :tangle yes
(use-package yaml-mode)
(use-package json-mode)
(use-package protobuf-mode)
;; (use-package gnuplot)
#+end_src
* misc
** shell
insert stdout from terminal (try "Q" on the next line)
seq 0 255 | xargs printf "%.2x\n" | fmt -w 49
#+begin_src emacs-lisp :tangle yes
(defun insert-output-of-executed-line ()
"executes line at point in default shell and inserts stdout"
(interactive)
(insert
(shell-command-to-string
(delete-and-extract-region
(point-at-bol)
(point-at-eol)))))
#+end_src

shell-pop for temporary shells

#+begin_src emacs-lisp :tangle yes
(use-package shell-pop
:custom
(shell-pop-shell-type '("terminal" "*Terminal*" 'eshell))
(shell-pop-window-position "bottom"))
#+end_src
** polymode
#+begin_src emacs-lisp :tangle yes
(use-package polymode)
(use-package poly-markdown
:hook (markdown-mode . poly-markdown-mode))
(use-package poly-org
:hook (org-mode . poly-org-mode))
#+end_src
* ui
** theme
The theme is a custom version of doom dracula
#+begin_src emacs-lisp :tangle yes
(use-package doom-themes
:init
(load-theme 'doom-dracula t)
:config
(custom-set-faces
'(button ((t (:inherit link :foreground "#ffb86c" :underline nil))))
'(font-lock-comment-face ((t (:foreground "#6272a4" :slant italic))))
'(font-lock-preprocessor-face ((t (:inherit nil :foreground "#bd93f9"))))
'(variable-pitch ((t (:family "Fira Sans"))))))
#+end_src

I also use doom-modeline cause it looks damn good

#+begin_src emacs-lisp :tangle yes
(use-package doom-modeline
:hook (after-init . doom-modeline-init)
:custom
(doom-modeline-buffer-file-name-style 'relative-from-project)
(doom-modeline-height 35)
(doom-modeline-bar-width 4)
(doom-modeline-icon t)
(doom-modeline-major-mode-icon t)
(doom-modeline-major-mode-color-icon nil))
#+end_src

Solaire mode is awesome for introducing a few extra shades of gray

#+begin_src emacs-lisp :tangle yes
(use-package solaire-mode
:init
(solaire-global-mode))
#+end_src
** which key
Whichkey is for when I can't remember the keys I'm supposed to press
#+begin_src emacs-lisp :tangle yes
(use-package which-key
:init
(which-key-mode))
#+end_src
* hotkeys
#+begin_src emacs-lisp :tangle yes
;; Leader keys
(evil-leader/set-key
;;buffers & windows
"b" 'helm-buffers-list
"y" 'helm-show-kill-ring
"o" 'other-window
"q" 'kill-buffer-and-window
"h" 'windmove-left
"j" 'windmove-down
"k" 'windmove-up
"l" 'windmove-right

;;misc
"a" 'comment-dwim
"i" 'indent-region

;;buffer
"" 'evil-avy-goto-char-timer
"e" 'ediff-buffers
"u" 'calc-embedded

;;files
"f f" 'treemacs-select-window
"f d" 'dired-jump
"f t" '(lambda () (interactive) (find-file "/tmp"))
"f e" '(lambda () (interactive) (find-file (expand-file-name "config.org" user-emacs-directory)))
"f z" '(lambda () (interactive) (find-file (expand-file-name "~/.zshrc")))
"f p" '(lambda () (interactive) (find-file (expand-file-name "~/src/")))
"f i" '(lambda () (interactive) (find-file (expand-file-name "~/.config/")))
"f h" '(lambda () (interactive) (find-file (expand-file-name "~/")))
"f n" '(lambda () (interactive) (find-file (expand-file-name "notes.org" (vc-root-dir))))
"f d" 'dired-jump
"f j" 'find-journal

;;config reload
"f r" '(lambda () (interactive) (load-file (expand-file-name "init.el" user-emacs-directory)))

;;Git
"g s" 'magit-status
"g t" 'git-timemachine
"g f" 'global-git-gutter+-mode
"g g" 'helm-projectile-grep
"g r" 'git-gutter+-revert-hunk
"g m" 'magit-blame-addition

;;elfeed
"n" 'elfeed

;;lsp
"r d" 'lsp-ui-peek-find-definitions
"r e" 'lsp-execute-code-action
"r o" 'lsp-rename
"r r" 'lsp-ui-peek-find-references
"r s" 'helm-lsp-workspace-symbol
"r l" 'lsp-treemacs-errors-list
"r i" 'lsp-format-region
"r b" 'lsp-format-buffer

;;dap
"d r" 'dap-debug-restart
"d l" 'dap-debug-last
"d f" 'dap-debug-recent
"d d" 'dap-debug
"d t" 'dap-debug-edit-template
"d h" '(lambda () (interactive) (dap-ui-mode t) (dap-hydra))

;;compile
"c" 'helm-make-projectile

;;find stuff
"p a" 'helm-projectile-rg

;;Docker
"g d" 'docker
"g c" 'docker-compose

;;utilities
"+" 'calc
"-" 'mu4e
"" 'vterm

;;projectile
"p p" 'helm-projectile
"p f" 'helm-projectile-find-file-dwim
"p s" 'projectile-add-known-project
"p c" 'projectile-compile-project
"v m" '(lambda () (interactive) (find-file "./CMakeLists.txt"))
"v d" '(lambda () (interactive) (find-file "./Dockerfile"))
"v c" '(lambda () (interactive) (find-file "./docker-compose.yml"))
"v p" '(lambda () (interactive) (find-file "./Pipfile"))

;;engine
"s c" 'engine/search-cppreference
"s b" 'engine/search-cmake
"s y" 'engine/search-youtube
"s d" 'engine/search-dockerhub
"s r" 'engine/search-rustdoc
"s w" 'engine/search-wikipedia
"s g i" 'engine/search-github
"s g o" 'engine/search-google

;; window management
"w w" 'tear-off-window
"w h" 'windmove-swap-states-left
"w j" 'windmove-swap-states-down
"w k" 'windmove-swap-states-up
"w l" 'windmove-swap-states-right)

(evil-leader/set-key-for-mode 'dired-mode
"d i" '(lambda () (interactive) (start-process "sxiv" "*sxiv*" "sxiv" (dired-filename-at-point)))
"d e" 'dired-run-at-point)

(evil-leader/set-key-for-mode 'emacs-lisp-mode
"e" 'eval-last-sexp
"k" 'eval-buffer)

(setq local-function-key-map (delq '(kp-tab . [9]) local-function-key-map))
;;global state
(evil-define-key nil global-map
(kbd "M-*") 'helm-rg
(kbd "M-r") 'recompile
(kbd "C-x C-f") 'helm-find-files
(kbd "C-x C-d") 'helm-fzf-project-root
(kbd "C-x C-b") 'helm-buffers-list
(kbd "M-x") 'helm-M-x
(kbd "M-p") 'emmet-expand-yas
(kbd "C-S-c") 'aya-create
(kbd "C-S-e") 'aya-expand
(kbd "C-s") 'save-buffer
(kbd "C-c l") 'org-store-link
(kbd "C-c a") 'org-todo-list
(kbd "C-k") 'kill-buffer-and-window
(kbd "C-c c") 'org-capture
(kbd "C-;") 'shell-pop)

(evil-define-key nil org-mode-map
(kbd "M-H") 'org-shiftleft
(kbd "M-J") 'org-shiftdown
(kbd "M-K") 'org-shiftup
(kbd "M-L") 'org-shiftright
(kbd "M-h") 'org-metaleft
(kbd "M-j") 'org-metadown
(kbd "M-k") 'org-metaup
(kbd "M-l") 'org-metaright)

(evil-define-key 'normal compilation-mode-map
(kbd "C-n") 'compilation-next-error
(kbd "C-p") 'compilation-previous-error)

(evil-define-key 'normal dired-mode-map
(kbd "Y") '(lambda () (interactive) (dired-copy-filename-as-kill 0))
(kbd "y") 'dired-copy-filename-as-kill)

(evil-define-key nil go-mode-map
(kbd "C-c C-c") 'go-run)

(evil-define-key 'normal global-map
(kbd "Q") 'insert-output-of-executed-line)

(evil-define-key 'visual global-map
(kbd "S") 'evil-surround-region)

;; paredit mode
(evil-define-key nil paredit-mode-map
(kbd "M-l") 'paredit-forward-slurp-sexp
(kbd "M-h") 'paredit-backward-slurp-sexp
(kbd "M-L") 'paredit-backward-barf-sexp
(kbd "M-H") 'paredit-forward-barf-sexp)

(evil-define-key nil cider-repl-mode-map
(kbd "C-k") 'cider-repl-backward-input
(kbd "C-j") 'cider-repl-forward-input)

(evil-define-key 'normal global-map
(kbd "U") 'undo-tree-visualize)
#+end_src