this config was based off of uncle daves emacs who i am forever grateful to for allowing me a user friendly entry point to emacs check out uncle daves repo at https://github.com/daedreth/UncleDavesEmacs
Since we are going to use emacs as our window manager, it would be nice to have some external software to make our life easier.
xorg-server
, for obvious reasons. (there is no wayland support as of now)pulsemixer
, available fromhttps://github.com/GeorgeFilipkin/pulsemixer
.imagemagick
, if you are going to be using emacs to take screenshots.ibus-daemon
, if you need multiple keyboard input options (emacs handles them well on its own but ibus is nice).terminus-font
, for it to work out of the box, if you don’t want terminus you need to edit yourinit.el
.
- A browser (sadly, the built in xwidgets-webkit thingie is unreliable).
- A composite manager (highly recommended, I personally use
compton
, the built in one does not work as intended.). noto-cjk
, for all the fonts imaginable.slock
, if you would like to lock the screen.
mpd
, since we are going to be using EMMS for music playback, I recommend setting up a working mpd server.mpv
, for video playback.
clang
, for c/c++ completion.sbcl
, for clisp completion and repl.virtualenv
, for python completion.lua
, for obvious reasons.
(let ((default-directory (concat user-emacs-directory
(convert-standard-filename "lisp/"))))
(normal-top-level-add-to-load-path '("."))
(normal-top-level-add-subdirs-to-load-path))
(use-package evil
:ensure t
:init
(setq evil-want-integration t)
(setq evil-want-keybinding nil)
:config
(evil-mode 1)
(define-key evil-insert-state-map (kbd "C-g") 'evil-normal-state))
(use-package evil-collection
:ensure t)
(use-package evil-surround
:ensure t)
(use-package undo-tree
:ensure t
:config
(global-undo-tree-mode))
(use-package modus-vivendi-theme
:ensure t
:init
(setq modus-vivendi-theme-slanted-constructs t
modus-vivendi-theme-bold-constructs t
modus-vivendi-theme-visible-fringes t
modus-vivendi-theme-3d-modeline t
modus-vivendi-theme-subtle-diffs t
modus-vivendi-theme-intense-standard-completions t
modus-vivendi-theme-distinct-org-blocks t
modus-vivendi-theme-rainbow-org-src-blocks t
modus-vivendi-theme-proportional-fonts t
modus-vivendi-theme-rainbow-headings t
modus-vivendi-theme-section-headings t)
:config
(load-theme 'modus-vivendi t))
;; Set default font
(set-face-attribute 'default nil
:family "Hack"
:height 150
;; :weight 'normal
:width 'normal)
;; set fallback font for emoji
(set-fontset-font t nil (font-spec :size 20 :name "Unifont"))
These are setting that do not depend on packages and are built-in enhancements to the UI.
(setq inhibit-startup-message t)
If you like using any of those, change -1
to 1
.
(tool-bar-mode -1)
(menu-bar-mode -1)
(scroll-bar-mode -1)
(setq locale-coding-system 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(set-selection-coding-system 'utf-8)
(prefer-coding-system 'utf-8)
hl-line
is awesome! It’s not very awesome in the terminal version of emacs though, so we don’t use that.
Besides, it’s only used for programming.
(when window-system (add-hook 'prog-mode-hook 'hl-line-mode))
(setq visible-bell t)
I don’t use either, you might want to turn those from nil
to t
if you do.
(setq make-backup-files nil)
(setq auto-save-default nil)
(defalias 'yes-or-no-p 'y-or-n-p)
use asynchronous processes wherever possible
(use-package async
:ensure t
:init (dired-async-mode 1))
Everything regarding the WM or DE-like functionality is bundled here, remove the entire section if you do not wish to use exwm
.
The only time I actually had to use comments, this is for ease of removal if you happen to not like exwm.
(use-package exwm
:ensure t
:config
;; necessary to configure exwm manually
(require 'exwm-config)
;; fringe size, most people prefer 1
(fringe-mode 3)
;; emacs as a daemon, use "emacsclient <filename>" to seamlessly edit files from the terminal directly in the exwm instance
(server-start)
;; this fixes issues with ido mode, if you use helm, get rid of it
;; (exwm-config-ido)
;; a number between 1 and 9, exwm creates workspaces dynamically so I like starting out with 1
(setq exwm-workspace-number 1)
;; this is a way to declare truly global/always working keybindings
;; this is a nifty way to go back from char mode to line mode without using the mouse
(exwm-input-set-key (kbd "s-r") #'exwm-reset)
(exwm-input-set-key (kbd "s-k") #'exwm-workspace-delete)
(exwm-input-set-key (kbd "s-w") #'exwm-workspace-swap)
(exwm-input-set-key (kbd "s-n") 'ibuffer)
(exwm-input-set-key (kbd "s-m") 'next-buffer)
(exwm-input-set-key (kbd "s-,") 'previous-buffer)
(exwm-input-set-key (kbd "s-/") 'kill-current-buffer)
(exwm-input-set-key (kbd "s-j") 'windmove-left)
(exwm-input-set-key (kbd "s-k") 'windmove-down)
(exwm-input-set-key (kbd "s-i") 'windmove-up)
(exwm-input-set-key (kbd "s-l") 'windmove-right)
(exwm-input-set-key (kbd "s-;") 'delete-window)
(exwm-input-set-key (kbd "s-s h") 'split-window-right)
(exwm-input-set-key (kbd "s-s j") 'split-window-below)
(exwm-input-set-key (kbd "s-s k") 'split-and-follow-horizontally)
(exwm-input-set-key (kbd "s-s l") 'split-and-follow-vertically)
;; the next loop will bind s-<number> to switch to the corresponding workspace
(dotimes (i 10)
(exwm-input-set-key (kbd (format "s-%d" i))
`(lambda ()
(interactive)
(exwm-workspace-switch-create ,i))))
;; the simplest launcher, I keep it in only if dmenu eventually stopped working or something
(exwm-input-set-key (kbd "s-&")
(lambda (command)
(interactive (list (read-shell-command "$ ")))
(start-process-shell-command command nil command)))
;; an easy way to make keybindings work *only* in line mode
(push ?\C-q exwm-input-prefix-keys)
(define-key exwm-mode-map [?\C-q] #'exwm-input-send-next-key)
;; simulation keys are keys that exwm will send to the exwm buffer upon inputting a key combination
(exwm-input-set-simulation-keys
'(
;; movement
([?\C-b] . left)
([?\M-b] . C-left)
([?\C-f] . right)
([?\M-f] . C-right)
([?\C-p] . up)
([?\C-n] . down)
([?\C-a] . home)
([?\C-e] . end)
([?\M-v] . prior)
([?\C-v] . next)
([?\C-d] . delete)
([?\C-k] . (S-end delete))
;; cut/paste
([?\C-w] . ?\C-x)
([?\M-w] . ?\C-c)
([?\C-y] . ?\C-v)
;; search
([?\C-f] . ?\C-f)
;; movement
([?\M-h] . return)
([?\M-m] . return)
([?\M-l] . right)
([?\M-k] . down)
([?\M-j] . left)
([?\M-\\] . prior)
([?\M-'] . next)))
;; this little bit will make sure that XF86 keys work in exwm buffers as well
(dolist (k '(XF86AudioLowerVolume
XF86AudioRaiseVolume
XF86PowerOff
XF86AudioMute
XF86AudioPlay
XF86AudioStop
XF86AudioPrev
XF86AudioNext
XF86ScreenSaver
XF68Back
XF86Forward
Scroll_Lock
print))
(cl-pushnew k exwm-input-prefix-keys))
;; this just enables exwm, it started automatically once everything is ready
(exwm-enable))
(require 'exwm-randr)
(setq exwm-randr-workspace-output-plist '(0 "DP-4"))
(add-hook 'exwm-randr-screen-change-hook
(lambda ()
(start-process-shell-command
"xrandr" nil "xrandr --output DP-4 --auto")))
(exwm-randr-enable)
;; autoname buffers
(add-hook 'exwm-update-class-hook
(lambda ()
(exwm-workspace-rename-buffer exwm-class-name)))
(require 'exwm-systemtray)
(exwm-systemtray-enable)
Since I do not use a GUI launcher and do not have an external one like dmenu or rofi, I figured the best way to launch my most used applications would be direct emacsy keybindings.
Who would’ve thought this was available, together with ido-vertical it’s a nice large menu with its own cache for most launched applications.
(use-package dmenu
:ensure t
:bind
("s-SPC" . 'dmenu))
This is a set of bindings to my XF86 keys that invokes pulsemixer with the correct parameters
It goes without saying that you are free to modify the modifier as you see fit, 4 is good enough for me though.
(defconst volumeModifier "4")
(defun audio/mute ()
(interactive)
(start-process "audio-mute" nil "pulsemixer" "--toggle-mute"))
(defun audio/raise-volume ()
(interactive)
(start-process "raise-volume" nil "pulsemixer" "--change-volume" (concat "+" volumeModifier)))
(defun audio/lower-volume ()
(interactive)
(start-process "lower-volume" nil "pulsemixer" "--change-volume" (concat "-" volumeModifier)))
You can also change those if you’d like, but I highly recommend keeping ‘em the same, chances are, they will just work.
(global-set-key (kbd "<XF86AudioMute>") 'audio/mute)
(global-set-key (kbd "<XF86AudioRaiseVolume>") 'audio/raise-volume)
(global-set-key (kbd "<XF86AudioLowerVolume>") 'audio/lower-volume)
I don’t need scrot to take screenshots, or shutter or whatever tools you might have. This is enough. These won’t work in the terminal version or the virtual console, obvious reasons.
(defun daedreth/take-screenshot ()
"Takes a fullscreen screenshot of the current workspace"
(interactive)
(when window-system
(loop for i downfrom 3 to 1 do
(progn
(message (concat (number-to-string i) "..."))
(sit-for 1)))
(message "Cheese!")
(sit-for 1)
(start-process "screenshot" nil "import" "-window" "root"
(concat (getenv "HOME") "/" (subseq (number-to-string (float-time)) 0 10) ".png"))
(message "Screenshot taken!")))
(global-set-key (kbd "<print>") 'daedreth/take-screenshot)
(defun daedreth/take-screenshot-region ()
"Takes a screenshot of a region selected by the user."
(interactive)
(when window-system
(call-process "import" nil nil nil ".newScreen.png")
(call-process "convert" nil nil nil ".newScreen.png" "-shave" "1x1"
(concat (getenv "HOME") "/" (subseq (number-to-string (float-time)) 0 10) ".png"))
(call-process "rm" nil nil nil ".newScreen.png")))
(global-set-key (kbd "<Scroll_Lock>") 'daedreth/take-screenshot-region)
gui applications from inside emacs using python repl connected to the lisp
(use-package eaf
:load-path "~/.emacs.d/site-lisp/emacs-application-framework" ; Set to "/usr/share/emacs/site-lisp/eaf" if installed from AUR
:custom
(eaf-find-alternate-file-in-dired t)
:config
(eaf-bind-key scroll_up "C-n" eaf-pdf-viewer-keybinding)
(eaf-bind-key scroll_down "C-p" eaf-pdf-viewer-keybinding)
(eaf-bind-key take_photo "p" eaf-camera-keybinding)
(define-key dired-mode-map (kbd "e") 'eaf-open-this-from-dired))
I use eww for most browsing, and I use icecat when I need to open something in an external browser.
(setq browse-url-browser-function 'eww-browse-url
browse-url-generic-program "icecat")
shrface for eww that is more like org mode
;; (use-package shrface
;; :defer t
;; :ensure t
;; :config
;; (shrface-basic)
;; (shrface-trial)
;; (setq shrface-href-versatile t))
;; (use-package eww
;; :init
;; (add-hook 'eww-after-render-hook #'shrface-mode)
;; :config
;; (require 'shrface))
sometimes i load a page and it has a lot of animated images and it makes eww crawl, or it has big images that make the page hard to read, so I dont open images by default, but this neat script i found lets you turn on and off images.
(defun my/eww-toggle-images ()
"Toggle whether images are loaded and reload the current page from cache."
(interactive)
(setq-local shr-inhibit-images (not shr-inhibit-images))
(eww-reload t)
(message "Images are now %s"
(if shr-inhibit-images "off" "on")))
;; (define-key eww-mode-map (kbd "I") #'my/eww-toggle-images)
;; (define-key eww-link-keymap (kbd "I") #'my/eww-toggle-images)
;; minimal rendering by default
(setq-default shr-inhibit-images t) ; toggle with `I`
(setq-default shr-use-fonts nil) ; toggle with `F`
this highlights syntax in eww, good for elisp snippets on the wiki.
;; syntax highlighting
(use-package language-detection
:ensure t
:config
(require 'cl-lib)
(defun eww-tag-pre (dom)
(let ((shr-folding-mode 'none)
(shr-current-font 'default))
(shr-ensure-newline)
(insert (eww-fontify-pre dom))
(shr-ensure-newline)))
(defun eww-fontify-pre (dom)
(with-temp-buffer
(shr-generic dom)
(let ((mode (eww-buffer-auto-detect-mode)))
(when mode
(eww-fontify-buffer mode)))
(buffer-string)))
(defun eww-fontify-buffer (mode)
(delay-mode-hooks (funcall mode))
(font-lock-default-function mode)
(font-lock-default-fontify-region (point-min)
(point-max)
nil))
(defun eww-buffer-auto-detect-mode ()
(let* ((map '((ada ada-mode)
(awk awk-mode)
(c c-mode)
(cpp c++-mode)
(clojure clojure-mode lisp-mode)
(csharp csharp-mode java-mode)
(css css-mode)
(dart dart-mode)
(delphi delphi-mode)
(emacslisp emacs-lisp-mode)
(erlang erlang-mode)
(fortran fortran-mode)
(fsharp fsharp-mode)
(go go-mode)
(groovy groovy-mode)
(haskell haskell-mode)
(html html-mode)
(java java-mode)
(javascript javascript-mode)
(json json-mode javascript-mode)
(latex latex-mode)
(lisp lisp-mode)
(lua lua-mode)
(matlab matlab-mode octave-mode)
(objc objc-mode c-mode)
(perl perl-mode)
(php php-mode)
(prolog prolog-mode)
(python python-mode)
(r r-mode)
(ruby ruby-mode)
(rust rust-mode)
(scala scala-mode)
(shell shell-script-mode)
(smalltalk smalltalk-mode)
(sql sql-mode)
(swift swift-mode)
(visualbasic visual-basic-mode)
(xml sgml-mode)))
(language (language-detection-string
(buffer-substring-no-properties (point-min) (point-max))))
(modes (cdr (assoc language map)))
(mode (cl-loop for mode in modes
when (fboundp mode)
return mode)))
(message (format "%s" language))
(when (fboundp mode)
mode)))
(setq shr-external-rendering-functions
'((pre . eww-tag-pre))))
(setq-default dired-listing-switches "-alh")
(use-package all-the-icons-dired
:ensure t
:hook (dired-mode . all-the-icons-dired-mode)
)
This makes sure that everything can be a project.
(use-package projectile
:ensure t
:init (projectile-mode 1)
:custom
(projectile-completion-system)
:bind ("C-c p" . 'projectile-command-map))
(use-package counsel-projectile
:ensure t
:config (counsel-projectile-mode))
(global-set-key (kbd "<f5>") 'projectile-compile-project)
Dashboard with recent files and projects
(use-package dashboard
:ensure t
:config
(dashboard-setup-startup-hook)
(setq dashboard-startup-banner "~/.emacs.d/img/dashLogo.png")
(setq dashboard-items '((recents . 5)
(projects . 5)))
(setq dashboard-banner-logo-title "TAYMACS"))
(setq display-time-24hr-format nil)
(setq display-time-format "%H:%M - %d %B %Y")
This turns on the clock globally.
(display-time-mode 1)
(defvar my-term-shell "/bin/bash")
(defadvice ansi-term (before force-bash)
(interactive (list my-term-shell)))
(ad-activate 'ansi-term)
;; (use-package counsel
;; :ensure t
;; :after ivy
;; :config (counsel-mode))
;; (use-package ivy
;; :ensure t
;; :config
;; (ivy-mode 1)
;; :bind
;; ("C-x C-b" . 'ivy-switch-buffer))
;; (use-package ivy-rich
;; :ensure t
;; :after counsel
;; :init
;; (ivy-rich-mode 1))
https://github.com/masasam/emacs-counsel-tramp
(use-package helm
:ensure t
:bind
("C-x C-f" . 'helm-find-files)
("C-x C-b" . 'helm-buffers-list)
("M-x" . 'helm-M-x)
:config
;; (defun daedreth/helm-hide-minibuffer ()
;; (when (with-helm-buffer helm-echo-input-in-header-line)
;; (let ((ov (make-overlay (point-min) (point-max) nil nil t)))
;; (overlay-put ov 'window (selected-window))
;; (overlay-put ov 'face
;; (let ((bg-color (face-background 'default nil)))
;; `(:background ,bg-color :foreground ,bg-color)))
;; (setq-local cursor-type nil))))
;; (add-hook 'helm-minibuffer-set-up-hook 'daedreth/helm-hide-minibuffer)
;; (setq helm-autoresize-max-height 0
;; helm-autoresize-min-height 40
;; helm-M-x-fuzzy-match t
;; helm-buffers-fuzzy-matching t
;; helm-recentf-fuzzy-match t
;; helm-semantic-fuzzy-match t
;; helm-imenu-fuzzy-match t
;; helm-split-window-in-side-p nil
;; helm-move-to-line-cycle-in-source nil
;; helm-ff-search-library-in-sexp t
;; helm-scroll-amount 8
;; helm-echo-input-in-header-line t)
:init
(helm-mode 1))
(require 'helm-config)
(helm-autoresize-mode 0)
;; (define-key helm-find-files-map (kbd "C-b") 'helm-find-files-up-one-level)
;; (define-key helm-find-files-map (kbd "C-f") 'helm-execute-persistent-action)
(use-package helm-ag
:ensure t)
automatic cheat sheet once you press part of a key series
(use-package which-key
:ensure t
:config
(which-key-mode))
better auto completion - sorts by length and prioritizes more commonly used selections
(use-package ivy-prescient
:ensure t
:after counsel
:config (ivy-prescient-mode 1))
Some of us have large displays, others have tiny netbook screens, but regardless of your hardware
you probably use more than 2 panes/windows at times, cycling through all of them with
C-c o
is annoying to say the least, it’s a lot of keystrokes and takes time, time you could spend doing something more productive.
switch window uses an ace type jump if more than 2 windows are open
(use-package switch-window
:ensure t
:config
(setq switch-window-input-style 'minibuffer)
(setq switch-window-increase 4)
(setq switch-window-threshold 2)
(setq switch-window-shortcut-style 'qwerty)
(setq switch-window-qwerty-shortcuts
'("a" "s" "d" "f" "j" "k" "l" "i" "o"))
:bind
([remap other-window] . switch-window))
After you split a window, your focus remains in the previous one. This annoyed me so much I wrote these two, they take care of it.
(defun split-and-follow-horizontally ()
(interactive)
(split-window-below)
(balance-windows)
(other-window 1))
(global-set-key (kbd "C-x 2") 'split-and-follow-horizontally)
(defun split-and-follow-vertically ()
(interactive)
(split-window-right)
(balance-windows)
(other-window 1))
(global-set-key (kbd "C-x 3") 'split-and-follow-vertically)
Another big thing is, buffers. If you use emacs, you use buffers, everyone loves them. Having many buffers is useful, but can be tedious to work with, let us see how we can improve it.
Doing C-x k
should kill the current buffer at all times, we have ibuffer
for more sophisticated thing.
(defun kill-current-buffer ()
"Kills the current buffer."
(interactive)
(kill-buffer (current-buffer)))
(global-set-key (kbd "C-x k") 'kill-current-buffer)
Unless you have the muscle memory, I recommend omitting this bit, as you may lose progress for no reason when working.
(setq kill-buffer-query-functions (delq 'process-kill-buffer-query-function kill-buffer-query-functions))
I don’t understand how ibuffer isn’t the default option by now. It’s vastly superior in terms of ergonomics and functionality, you can delete buffers, rename buffer, move buffers, organize buffers etc.
(global-set-key (kbd "C-x b") 'ibuffer)
If you feel like you know how ibuffer works and need not to be asked for confirmation after every serious command, enable this as follows.
;;(setq ibuffer-expert t)
Relative line numbers
(use-package linum-relative
:ensure t
:config
(setq linum-relative-current-symbol "")
(add-hook 'prog-mode-hook 'linum-relative-mode))
personally i have tried using avy but plain isearch seems to do the job the best for me so far, i may revisit avy at some point in the far future if i feel the need
(use-package ace-link
:ensure t
:config
(ace-link-setup-default)
)
(use-package mark-multiple
:ensure t
:bind ("C-c q" . 'mark-next-like-this))
everything is inner-object because the rest is easy enough in emacs way
kill - k copy - w mark - m yank into occur multicursor
(defun daedreth/kill-inner-word ()
"Kills the entire word your cursor is in. Equivalent to 'ciw' in vim."
(interactive)
(forward-char 1)
(backward-word)
(kill-word 1))
(global-set-key (kbd "C-c v w k") 'daedreth/kill-inner-word)
And again, the same as above but we make sure to not delete the source word.
(defun daedreth/copy-whole-word ()
(interactive)
(save-excursion
(forward-char 1)
(backward-word)
(kill-word 1)
(yank)))
(global-set-key (kbd "C-c v w w") 'daedreth/copy-whole-word)
Regardless of where your cursor is, this quickly copies a line.
(defun daedreth/copy-whole-line ()
"Copies a line without regard for cursor position."
(interactive)
(save-excursion
(kill-new
(buffer-substring
(point-at-bol)
(point-at-eol)))))
(global-set-key (kbd "C-c v l w") 'daedreth/copy-whole-line)
And this quickly deletes a line.
(global-set-key (kbd "C-c v l k") 'kill-whole-line)
(global-set-key (kbd "C-c d m") 'emms)
(global-set-key (kbd "C-c a d") 'emms-add-dired)
(global-set-key (kbd "C-c a f") 'emms-add-find)
(global-set-key (kbd "C-c d s") 'emms-streams)
(global-set-key (kbd "C-c d n") 'emms-next)
(global-set-key (kbd "C-c d p") 'emms-previous)
(global-set-key (kbd "C-c d SPC") 'emms-pause)
(global-set-key (kbd "C-c w w") 'eww)
(global-set-key (kbd "C-c j") 'org-capture)
Emacs is at it’s best when it just does things for you, shows you the way, guides you so to speak. This can be best achieved using a number of small extensions. While on their own they might not be particularly impressive. Together they create a nice environment for you to work in.
Quickly edit ~/.emacs.d/config.org
(defun config-visit ()
(interactive)
(find-file "~/.emacs.d/config.org"))
(global-set-key (kbd "C-c e") 'config-visit)
Simply pressing Control-c r
will reload this file, very handy.
You can also manually invoke config-reload
.
(defun config-reload ()
"Reloads ~/.emacs.d/config.org at runtime"
(interactive)
(org-babel-load-file (expand-file-name "~/.emacs.d/config.org")))
(global-set-key (kbd "C-c r") 'config-reload)
Emacs treats camelCase strings as a single word by default, this changes said behaviour.
(global-subword-mode 1)
autocomplete pairs
(setq electric-pair-pairs '(
(?\{ . ?\})
(?\( . ?\))
(?\[ . ?\])
(?\" . ?\")))
And now to enable it
(electric-pair-mode t)
shows color of hex color
(use-package rainbow-mode
:ensure t
:init
(add-hook 'prog-mode-hook 'rainbow-mode))
highlight matching paren
(show-paren-mode 1)
Colors parentheses and other delimiters depending on their depth
(use-package rainbow-delimiters
:ensure t
:init
(add-hook 'prog-mode-hook #'rainbow-delimiters-mode))
grow region over levels of semantic objects.
(use-package expand-region
:ensure t
:bind ("C-M-q" . er/expand-region))
Backspace or Delete will get rid of all whitespace until the next non-whitespace character is encountered.
(use-package hungry-delete
:ensure t
:config
(global-hungry-delete-mode))
Minor, non-completion related settings and plugins for writing code.
(use-package paredit
:ensure t
:config
(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))
(use-package yasnippet
:ensure t
:config
(use-package yasnippet-snippets
:ensure t)
(yas-reload-all))
(use-package flycheck
:ensure t
:config
(add-hook 'after-init-hook #'global-flycheck-mode)
(flycheck-add-mode 'javascript-eslint 'web-mode 'scala-mode))
I set the delay for company mode to kick in to half a second, I also make sure that it starts doing its magic after typing in only 2 characters.
I prefer C-n
and C-p
to move around the items, so I remap those accordingly.
(use-package company
:ensure t
:bind (:map company-active-map
("<tab>" . company-complete-selection))
:config
(setq company-idle-delay 0)
(setq company-minimum-prefix-length 1))
emacs
Be it for code or prose, completion is a must.
After messing around with auto-completion
for a while I decided to drop it
in favor of company
, and it turns out to have been a great decision.
Each category also has additional settings.
(add-hook 'c++-mode-hook 'yas-minor-mode)
(add-hook 'c-mode-hook 'yas-minor-mode)
(use-package flycheck-clang-analyzer
:ensure t
:config
(with-eval-after-load 'flycheck
(require 'flycheck-clang-analyzer)
(flycheck-clang-analyzer-setup)))
Requires libclang to be installed.
(with-eval-after-load 'company
(add-hook 'c++-mode-hook 'company-mode)
(add-hook 'c-mode-hook 'company-mode))
(use-package company-c-headers
:ensure t)
(use-package company-irony
:ensure t
:config
(setq company-backends '((company-c-headers
company-dabbrev-code
company-irony))))
(use-package irony
:ensure t
:config
(add-hook 'c++-mode-hook 'irony-mode)
(add-hook 'c-mode-hook 'irony-mode)
(add-hook 'irony-mode-hook 'irony-cdb-autosetup-compile-options))
(add-hook 'python-mode-hook 'yas-minor-mode)
(add-hook 'python-mode-hook 'flycheck-mode)
(with-eval-after-load 'company
(add-hook 'python-mode-hook 'company-mode))
(use-package company-jedi
:ensure t
:config
(require 'company)
(add-to-list 'company-backends 'company-jedi))
(defun python-mode-company-init ()
(setq-local company-backends '((company-jedi
company-etags
company-dabbrev-code))))
(use-package company-jedi
:ensure t
:config
(require 'company)
(add-hook 'python-mode-hook 'python-mode-company-init))
(add-hook 'emacs-lisp-mode-hook 'eldoc-mode)
(add-hook 'emacs-lisp-mode-hook 'yas-minor-mode)
(add-hook 'emacs-lisp-mode-hook 'company-mode)
(use-package slime
:ensure t
:config
(setq inferior-lisp-program "/usr/bin/sbcl")
(setq slime-contribs '(slime-fancy)))
(use-package slime-company
:ensure t
:init
(require 'company)
(slime-setup '(slime-fancy slime-company)))
(add-hook 'lua-mode-hook 'yas-minor-mode)
(add-hook 'lua-mode-hook 'flycheck-mode)
(add-hook 'lua-mode-hook 'company-mode)
(defun custom-lua-repl-bindings ()
(local-set-key (kbd "C-c C-s") 'lua-show-process-buffer)
(local-set-key (kbd "C-c C-h") 'lua-hide-process-buffer))
(defun lua-mode-company-init ()
(setq-local company-backends '((company-lua
company-etags
company-dabbrev-code))))
(use-package company-lua
:ensure t
:config
(require 'company)
(setq lua-indent-level 4)
(setq lua-indent-string-contents t)
(add-hook 'lua-mode-hook 'custom-lua-repl-bindings)
(add-hook 'lua-mode-hook 'lua-mode-company-init))
(add-hook 'shell-mode-hook 'yas-minor-mode)
(add-hook 'shell-mode-hook 'flycheck-mode)
(add-hook 'shell-mode-hook 'company-mode)
(defun shell-mode-company-init ()
(setq-local company-backends '((company-shell
company-shell-env
company-etags
company-dabbrev-code))))
(use-package company-shell
:ensure t
:config
(require 'company)
(add-hook 'shell-mode-hook 'shell-mode-company-init))
(use-package haskell-mode
:ensure t)
(add-hook 'emacs-lisp-mode-hook 'company-mode)
(add-hook 'emacs-lisp-mode-hook 'yas-minor-mode)
(use-package js2-mode
:ensure t
:init
(setq js-basic-indent 2)
(setq js2-strict-missing-semi-warning nil)
(setq js2-missing-semi-one-line-override t)
(setq-default js2-basic-indent 2
js2-basic-offset 2
js2-auto-indent-p t
js2-cleanup-whitespace t
js2-enter-indents-newline t
js2-indent-on-enter-key t
js2-global-externs (list "window" "module" "require" "buster" "sinon" "assert" "refute" "setTimeout" "clearTimeout" "setInterval" "clearInterval" "location" "__dirname" "console" "JSON" "jQuery" "$"))
(add-hook 'js2-mode-hook
(lambda ()
(push '("function" . ?ƒ) prettify-symbols-alist)))
(add-hook 'js2-mode-hook 'company-mode)
(add-hook 'js2-mode-hook 'yas-minor-mode)
(add-to-list 'auto-mode-alist '("\\.js$" . js2-mode)))
;; jump to definition
;;(use-package tern
;; :ensure t
;; :init (add-hook 'js2-mode-hook (lambda () (tern-mode t)))
;; :config
;; (use-package company-tern
;; :ensure t
;; :init (add-to-list 'company-backends 'company-tern)))
;; refactoring (C-c)
(use-package js2-refactor
:ensure t
:init (add-hook 'js2-mode-hook 'js2-refactor-mode)
:config (js2r-add-keybindings-with-prefix "C-c ."))
(use-package prettier
:ensure t
:config
(add-hook 'after-init-hook #'global-prettier-mode)
;; (add-hook 'js2-mode-hook 'prettier-mode)
;; (add-hook 'web-mode-hook 'prettier-mode)
)
(autoload 'drools-mode "drools-mode")
(defun set-extension-mode (extension mode)
(setq auto-mode-alist
(cons (cons (concat "\\" extension "\\'") mode)
auto-mode-alist) ) )
(set-extension-mode ".drl" 'drools-mode)
(set-extension-mode ".dslr" 'drools-mode)
(add-hook 'drools-mode-hook 'my-drools-hook)
(defun drools-return-and-indent()
(interactive)
(newline) (indent-for-tab-command) )
(defun my-drools-hook ()
(setq indent-tabs-mode nil)
(local-set-key [?\C-m] 'drools-return-and-indent) )
(use-package scala-mode
:ensure t
:interpreter
("scala" . scala-mode))
(use-package sbt-mode
:commands sbt-start sbt-command
:ensure t
:config
;; WORKAROUND: https://github.com/ensime/emacs-sbt-mode/issues/31
;; allows using SPACE when in the minibuffer
(substitute-key-definition
'minibuffer-complete-word
'self-insert-command
minibuffer-local-completion-map)
;; sbt-supershell kills sbt-mode: https://github.com/hvesalai/emacs-sbt-mode/issues/152
(setq sbt:program-options '("-Dsbt.supershell=false"))
)
(use-package lsp-mode
;; Optional - enable lsp-mode automatically in scala files
:ensure t
:hook (scala-mode . lsp)
(lsp-mode . lsp-lens-mode)
:config (setq lsp-prefer-flymake nil))
;; Add metals backend for lsp-mode
(use-package lsp-metals
:ensure t
:config (setq lsp-metals-treeview-show-when-views-received nil))
;; Enable nice rendering of documentation on hover
(use-package lsp-ui
:ensure t)
;; Add company-lsp backend for metals
(use-package company-lsp
:ensure t)
;; Use the Debug Adapter Protocol for running tests and debugging
(use-package posframe
:ensure t
;; Posframe is a pop-up tool that must be manually installed for dap-mode
)
(use-package dap-mode
:ensure t
:hook
(lsp-mode . dap-mode)
(lsp-mode . dap-ui-mode)
)
(use-package tide
:ensure t
:config
(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))
(add-hook 'web-mode-hook
(lambda ()
(when (string-equal "tsx" (file-name-extension buffer-file-name))
(setup-tide-mode))))
(use-package vue-mode
:ensure t
:init (add-hook 'vue-mode-hook 'company-mode)
(add-hook 'vue-mode-hook 'yas-minor-mode)
:config
(setq mmm-submode-decoration-level 0))
(use-package vue-html-mode
:ensure t)
(use-package vue-mode
:ensure t)
(use-package emmet-mode
:ensure t)
(use-package web-mode
:ensure t
:init
(add-to-list 'auto-mode-alist '("\\.phtml\\'" . 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 '("\\.vue\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.tsx\\'" . web-mode))
(add-hook 'editorconfig-custom-hooks
(lambda (hash) (setq web-mode-block-padding 0)))
(add-hook 'web-mode-hook 'company-mode)
(add-hook 'web-mode-hook 'yas-minor-mode)
:config
(setq web-mode-enable-auto-indentation nil)
(setq web-mode-content-types-alist '(("jsx" . "\\.js[x]?\\'"))))
(use-package tex
:defer t
:ensure auctex
:config
(setq TeX-auto-save t))
;; (use-package auctex
;; :ensure t)
Countless are the times where I opened ansi-term to use git
on something.
These times are also something that I’d prefer stay in the past, since magit
is
great. It’s easy and intuitive to use, shows its options at a keypress and much more.
(use-package magit
:ensure t
:config
(setq magit-push-always-verify nil)
(setq git-commit-summary-max-length 80)
:bind
("C-c g" . sudo-edit))
(use-package diff-hl
:ensure t
:config
(global-diff-hl-mode))
(use-package forge
:ensure t
:after magit)
Pretty self-explanatory, useful as hell if you use exwm.
(use-package sudo-edit
:ensure t
:bind
("s-e" . sudo-edit))
One of the absolute greatest features of emacs is called “org-mode”. This very file has been written in org-mode, a lot of other configurations are written in org-mode, same goes for academic papers, presentations, schedules, blogposts and guides. Org-mode is one of the most complex things ever, lets make it a bit more usable with some basic configuration.
Those are all rather self-explanatory.
(setq org-ellipsis " ")
(setq org-src-fontify-natively t)
(setq org-src-tab-acts-natively t)
(setq org-confirm-babel-evaluate nil)
(setq org-export-with-smart-quotes t)
(setq org-src-window-setup 'current-window)
(add-hook 'org-mode-hook 'org-indent-mode)
(use-package org-journal
:ensure t
:defer t
:custom
(org-journal-dir "~/notes/journal/")
(org-journal-date-format "%A, %d %B %Y"))
(use-package htmlize
:ensure t)
(add-hook 'org-mode-hook
'(lambda ()
(visual-line-mode 1)))
(add-hook 'org-mode-hook
'(lambda ()
(flyspell-mode 1)))
edit the stuff in a src block with proper modes
(global-set-key (kbd "C-c '") 'org-edit-src-code)
change astrisks to bullets
(use-package org-bullets
:ensure t
:config
(add-hook 'org-mode-hook (lambda () (org-bullets-mode))))
Hitting tab after an “<el” in an org-mode file will create a template for elisp insertion.
(add-to-list 'org-structure-template-alist
'("el" "emacs-lisp"))
One of the best things about org is the ability to export your file to many formats. Here is how we add more of them!
(when (file-directory-p "/usr/share/emacs/site-lisp/tex-utils")
(add-to-list 'load-path "/usr/share/emacs/site-lisp/tex-utils")
(require 'xdvi-search))
(use-package elpher
:ensure t)
You might want to edit the default nick, it’s password protected anyway so don’t bother.
This also hides some of the channel messages to avoid cluttering the buffer. The other line changes the prompt for each channel buffer to match the channel name, this way you always know who you are typing to.
(setq erc-nick "nobodynogroup")
(setq erc-prompt (lambda () (concat "[" (buffer-name) "]")))
(setq erc-hide-list '("JOIN" "PART" "QUIT"))
What it says on the tin, this changes the erc
history to include the server I connect to often.
(setq erc-server-history-list '("irc.libera.chat"
"localhost"))
You can even highlight nicks to make the buffers a bit more visually pleasing and easier to look at.
(use-package erc-hl-nicks
:ensure t
:config
(erc-update-modules))
(add-to-list 'load-path "~/elim/elisp")
(load-library "garak")
There is many backends, many players and codecs for EMMS, we use mpd now.
The non XF86 keys are made to be somewhat logical to follow and easy to remember. At the bottom part of the configuration, you will notice how XF86 keys are used by default, so unless you keyboard is broken it should work out of the box. Obviously you might have to adjust server-name and server-port to fit your configuration.
(use-package emms
:ensure t
:config
(require 'emms-setup)
(require 'emms-player-mpd)
(emms-all) ; don't change this to values you see on stackoverflow questions if you expect emms to work
(setq emms-seek-seconds 5)
(emms-default-players)
;; (setq emms-player-list '(emms-player-mpd))
;; (setq emms-info-functions '(emms-info-mpd))
(setq emms-player-mpd-server-name "localhost")
(setq emms-player-mpd-server-port "6600")
(setq emms-source-file-default-directory "~/Media/")
:bind
;; ("s-m p" . emms)
;; ("s-m b" . emms-smart-browse)
;; ("s-m r" . emms-player-mpd-update-all-reset-cache)
("<XF86AudioPrev>" . emms-previous)
("<XF86AudioNext>" . emms-next)
("<XF86AudioPlay>" . emms-pause)
("<XF86AudioPause>" . emms-pause)
("<XF86AudioStop>" . emms-stop))
We use non-default settings for the socket, to use the built in mpc
functionality we need to set up a variable.
Adjust according to your setup.
(setq mpc-host "localhost:6601")
(use-package emms-player-mpv
:ensure t
:config
(add-to-list 'emms-player-list 'emms-player-mpv))
If you have an absolutely massive music library, it might be a good idea to get rid of mpc-update
and only invoke it manually when needed.
(defun mpd/start-music-daemon ()
"Start MPD, connects to it and syncs the metadata cache."
(interactive)
(shell-command "mpd")
(mpd/update-database)
(emms-player-mpd-connect)
(emms-cache-set-from-mpd-all)
(message "MPD Started!"))
;;(global-set-key (kbd "s-m c") 'mpd/start-music-daemon)
(defun mpd/kill-music-daemon ()
"Stops playback and kill the music daemon."
(interactive)
(emms-stop)
(call-process "killall" nil nil nil "mpd")
(message "MPD Killed!"))
;;(global-set-key (kbd "s-m k") 'mpd/kill-music-daemon)
(defun mpd/update-database ()
"Updates the MPD database synchronously."
(interactive)
(call-process "mpc" nil nil nil "update")
(message "MPD Database Updated!"))
;;(global-set-key (kbd "s-m u") 'mpd/update-database)
(defun play-youtube (url)
"plays youtube."
(interactive "sUrl of video: ")
(shell-command (concat "youtube-dl " url " --add-metadata --write-info-json &" ))
(emms-add-file (substring (shell-command-to-string (concat "youtube-dl " url " --get-filename ")) 0 -1)))
M-x all-the-icons-install-fonts
(use-package all-the-icons
:ensure t)
;; https://stackoverflow.com/questions/88399/how-do-i-duplicate-a-whole-line-in-emacs
(defun duplicate-line (arg)
"Duplicate current line, leaving point in lower line."
(interactive "*p")
;; save the point for undo
(setq buffer-undo-list (cons (point) buffer-undo-list))
;; local variables for start and end of line
(let ((bol (save-excursion (beginning-of-line) (point)))
eol)
(save-excursion
;; don't use forward-line for this, because you would have
;; to check whether you are at the end of the buffer
(end-of-line)
(setq eol (point))
;; store the line and disable the recording of undo information
(let ((line (buffer-substring bol eol))
(buffer-undo-list t)
(count arg))
;; insert the line arg times
(while (> count 0)
(newline) ;; because there is no newline in 'line'
(insert line)
(setq count (1- count))))
;; create the undo information
(setq buffer-undo-list (cons (cons eol (point)) buffer-undo-list)))) ; end-of-let
;; put the point in the lowest line and return
(next-line arg))
(defun newline-below-go ()
"1. move to end of the line.
2. insert newline with index"
(interactive)
(let ((oldpos (point)))
(end-of-line)
(newline-and-indent)))
(defun newline-above-go ()
"1. move to end of the line.
2. insert newline with index"
(interactive)
(let ((oldpos (point)))
(beginning-of-line)
(newline-and-indent) ;;fixme indent the new line
(previous-line)
(end-of-line)))
(defun kill-previous-line ()
"1. move to end of the line.
2. insert newline with index"
(interactive)
(let ((oldpos (point)))
(previous-line)
(kill-whole-line)))
(defun kill-next-line ()
"1. move to end of the line.
2. insert newline with index"
(interactive)
(let ((oldpos (point)))
(next-line)
(kill-whole-line)))
(defun backward-kill-line (arg)
"Kill ARG lines backward."
(interactive "p")
(kill-line (- 1 arg)))
;; abolish tabs
(setq-default indent-tabs-mode nil)
(setq tab-stop-list (number-sequence 2 120 2))
(use-package editorconfig
:ensure t
:config
(editorconfig-mode 1))
:lighter
Your modeline is sacred, and if you have a lot of modes enabled, as you will if you use this config,
you might end up with a lot of clutter there, the package diminish
disables modes on the mode line but keeps
them running, it just prevents them from showing up and taking up space.
THIS WILL BE REMOVED SOON AS USE-PACKAGE HAS THE FUNCTIONALITY BUILT IN
Edit this list as you see fit!
(use-package diminish
:ensure t
:init
(diminish 'which-key-mode)
(diminish 'linum-relative-mode)
(diminish 'hungry-delete-mode)
(diminish 'visual-line-mode)
(diminish 'subword-mode)
(diminish 'beacon-mode)
(diminish 'irony-mode)
(diminish 'page-break-lines-mode)
(diminish 'auto-revert-mode)
(diminish 'rainbow-delimiters-mode)
(diminish 'editorconfig-mode)
(diminish 'subl-mode)
(diminish 'emo-mode)
(diminish 'org-indent-mode)
(diminish 'projectile-mode)
(diminish 'helm-mode)
(diminish 'company-mode)
(diminish 'undo-tree-mode)
(diminish 'ivy-mode)
(diminish 'flycheck-mode)
;; (diminish 'projectile-mode "➶")
;; (diminish 'helm-mode "⛫")
;; (diminish 'company-mode "✓")
(diminish 'rainbow-mode))
replacing gnus with elfeed
(use-package elfeed
:ensure t)
(use-package elfeed-org
:ensure t
:config
(elfeed-org)
(setq rmh-elfeed-org-files (list "~/Dropbox/newsfeeds.org" )))
i may turn this back on once i have a better grasp of gnus
(use-package nnhackernews
:ensure t
:config
(add-to-list 'gnus-secondary-select-methods '(nnhackernews "")))
i may turn this back on once i have a better grasp of gnus
;; (use-package nnreddit
;; :ensure t
;; :config
;; (add-to-list 'gnus-secondary-select-methods '(nnreddit "")))
;; (require 'mm-url)
;; (defadvice mm-url-insert (after DE-convert-atom-to-rss () )
;; "Converts atom to RSS by calling xsltproc."
;; (when (re-search-forward "xmlns=\"http://www.w3.org/.*/Atom\""
;; nil t)
;; (goto-char (point-min))
;; (message "Converting Atom to RSS... ")
;; (call-process-region (point-min) (point-max)
;; "xsltproc"
;; t t nil
;; (expand-file-name "~/atom2rss.xsl") "-")
;; (goto-char (point-min))
;; (message "Converting Atom to RSS... done")))
;; (ad-activate 'mm-url-insert)
(use-package eloud
:ensure t
:config
(setq eloud-espeak-path "/usr/bin/espeak"))
(setq org-todo-keywords
'((sequence "TODO(t)" "PLAN(p)" "WAIT(w@)" "|" "DONE(d!)" "CANCELED(c@)" "MISSED(m@)")))