literate-config

Literate config. See <a href="../readme.org">readme.org</a> for a better-formatted version
Log | Files | Refs

emacs.org (26555B)


      1 #+TITLE:Emacs config
      2 #+AUTHOR: Crazazy
      3 #+PROPERTY: header-args :tangle yes :noweb yes :results silent
      4 #+INCLUDE: ./style.org
      5 Welp, here it goes. This is a literal config for my emacs setup
      6 I will prbably copy-paste what I have in my literal config, and provide small, fun explanations along the way
      7 For now, prepare this to be not the best documented literal config you've seen.
      8 Also, if you just stumbled accross this at random, there is an easy tangle button at [[file:readme.org][readme.org]]
      9 * Before we start lisping
     10   This emacs config's dependencies are mostly managed by [[https://nixos.org][nix]], therefore we have to make a nix file before we
     11   do any emacs configuring by ourselves
     12   We also add webkitgtk support for (eventual) web browsing support
     13   #+begin_src nix :tangle emacs.nix
     14     let
     15       sources = import ./nix/sources.nix;
     16       packageOverlay = final: old: {
     17         emacs = old.emacs.override {
     18           withXwidgets = true;
     19         };
     20         emacsWithPackages = final.emacs.pkgs.withPackages;
     21       };
     22     in
     23     import sources.emacs {
     24       # put 'packageOverlay' in the overlays array for XWidgets (whenever they are stable i guess...)
     25       pkgs = import <nixpkgs> { overlays = [ ]; };
     26       configDir = ./emacsconfig;
     27     }
     28   #+end_src
     29 * Emacs configuring
     30   Now the real configuring begins!
     31   for some backwards compat purposes I have decided to but different config subjects into different files
     32   This won't matter too much as the nix framework is expecting multiple files anyway!
     33 ** The bases
     34    This is only better-defaults. It comes with ido-mode and some other defaults that I forgot to set in my
     35    init file that I stole from [[https://github.com/editor-bootstrap/emacs-bootstrap][emacs-bootstrap]] months ago
     36    #+begin_src emacs-lisp :mkdirp yes :tangle emacsconfig/base.el
     37      (use-package better-defaults)
     38    #+end_src
     39 *** Multiple terminals
     40     By default, =term= only supports 1 terminal. This version supports multiple terminals
     41     #+begin_src emacs-lisp :tangle emacsconfig/base.el
     42       (defun new-term (program)
     43         "start a new terminal emulator in a new buffer"
     44         (interactive (list (read-from-minibuffer "Run program: "
     45                                                  (or explicit-shell-file-name
     46                                                      (getenv "ESHELL")
     47                                                      shell-file-name))))
     48         (let* ((term-list (seq-filter
     49                            (lambda (s) (string-match-p "terminal" (buffer-name s)))
     50                            (buffer-list)))
     51                (term-num (number-to-string (length term-list))))
     52           (set-buffer (make-term (concat "terminal-" term-num) program))
     53           (term-mode)
     54           (term-char-mode)
     55           (switch-to-buffer (concat "*terminal-" term-num "*"))))
     56     #+end_src
     57 ** Generally nice emacs tools
     58 *** Magit
     59     Simple. Nice. default config. (almost)
     60     #+begin_src emacs-lisp :tangle emacsconfig/extras.el
     61       (use-package magit
     62 	:defer t
     63 	:config
     64 	(magit-add-section-hook 'magit-status-sections-hook
     65 				'magit-insert-modules
     66 				'magit-insert-stashes
     67 				'append)
     68 	:bind
     69 	("C-x g" . magit-status))
     70       (use-package forge
     71 	:after magit)
     72     #+end_src
     73 *** IRC
     74     I use IRC in emacs, with ERC. There is even a small macro so that I can easily join new servers
     75     with my preferred nickname
     76     #+begin_src emacs-lisp :tangle emacsconfig/extras.el
     77       (use-package erc
     78         :custom
     79         (erc-server-reconnect-attempts 10)
     80         (erc-nick "crazazy")
     81         (erc-autojoin-channel-alist '(("tilde.chat"
     82                                        "#cafe"
     83                                        "#meta")
     84                                       ("libera.chat"
     85                                        "#emacs"
     86                                        "#haskell"
     87                                        "#systemcrafters")))
     88         :config
     89         (defmacro irc-quickjoin (servername url &optional nick)
     90           "create a function to quickly join a server. Servers can be joined with M-x SERVERNAME-irc"
     91           `(defun ,(intern (concat (symbol-name servername) "-irc")) (password)
     92              (interactive (list (password-read "Password: ")))
     93              (erc-tls :server ,url
     94                       :nick ,(if nick
     95                                  nick
     96                                "crazazy")
     97                       :port 6697
     98                       :password password)))
     99 
    100         (irc-quickjoin tilde "eu.tilde.chat")
    101         (irc-quickjoin libera "irc.libera.chat"))
    102     #+end_src
    103 *** Dashboard
    104     Gives me access to the most recent files I edited, and some other stuff that I don't really care about
    105     #+begin_src emacs-lisp :tangle emacsconfig/extras.el
    106       (use-package dashboard
    107 	:config (dashboard-setup-startup-hook))
    108     #+end_src
    109 *** Elfeed
    110     I don't use elfeed in emacs that much anymore, as I have switched to [[https://www.seamonkey-project.org/][seamonkey]] for my RSS needs.
    111     Here is my old config anyways. If you want to browse through some default news feel free to remove the last
    112     =:custom= option
    113     #+begin_src emacs-lisp :tangle emacsconfig/extras.el
    114       (use-package elfeed
    115 	:bind
    116 	("C-x w" . elfeed)
    117 	(:map elfeed-search-mode-map
    118 	      ("C-c a" . elfeed-add-feed)
    119 	      ("C-c u" . elfeed-update)
    120 	      ("C-c f" . elfeed-update-feed)
    121 	      ("C-c r" . elfeed-mark-all-as-read))
    122 	:config
    123 	(defun elfeed-mark-all-as-read ()
    124 	  (interactive)
    125 	  (mark-whole-buffer)
    126 	  (elfeed-search-untag-all-unread))
    127 	:custom
    128 	(elfeed-search-filter  "@6-months-ago +quality")
    129 	(elfeed-feeds  '(("http://feeds.feedburner.com/tweakers/nieuws" NL tech exportable)
    130 			 ("https://discourse.nixos.org/c/announcements/8.rss" nixos programming quality)
    131 			 ("http://www.dnbradio.com/feeds" music podcasts)
    132 			 ("https://codepen.io/spark/feed/" programming quality)
    133 			 ("https://envs.net/~lucidiot/rsrsss/feed.xml" RSS quality)
    134 			 ("https://falseknees.tumblr.com/rss" comics quality)
    135 			 ("https://hackspace.raspberrypi.org/feed" tech programming)
    136 			 ("https://lobste.rs/rss" programming)
    137 			 ("https://news.rickcarlino.com/rss.rss" tech)
    138 			 ("https://nu.nl/rss" NL news exportable)
    139 			 ("https://planet.haskell.org/atom.xml" haskell programming)
    140 			 ("https://planet.nixos.org/atom.xml" nixos programming quality)
    141 			 ("https://reddit.com/r/dnb/.rss" reddit music)
    142 			 ("https://reddit.com/r/programming/.rss" reddit programming)
    143 			 ("https://reddit.com/r/realdubstep/.rss" reddit music)
    144 			 ("https://reddit.com/r/thenetherlands/.rss" NL reddit)
    145 			 ("https://sachachua.com/blog/category/emacs-news/feed" emacs quality programming)
    146 			 ("https://webzine.puffy.cafe/atom.xml" openbsd tech quality programming)
    147 			 ("https://www.fosskers.ca/en/rss" programming quality exportable)
    148 			 ("https://xkcd.com/atom.xml" comics)))
    149 	(elfeed-feeds nil)
    150 	(elfeed-search-filter  ""))
    151     #+end_src
    152 *** Org mode
    153     While the brunt of this file is relatively vanilla, There are still some things that I want to customize about the org-mode experience
    154     For now, I think it's best if I don't start depending on org-contrib, as it contains a lot of features and I would waste quite some time
    155     figuring out what all those features are.
    156 
    157     First of all, auto-indenting isn't enabled everywhere, so let's do that
    158     #+begin_src emacs-lisp :tangle emacsconfig/org.el
    159       (use-package org
    160         :custom
    161         (org-adapt-indentation t))
    162     #+end_src
    163 **** Syntax highlighting for HTML exports
    164      Normally, when I export my document to an html file for the website, syntax highlighting isn't automatically turned on. htmlize changes this
    165      by putting some colorful spans in all my source code. No need to configure anything either
    166      #+begin_src emacs-lisp :tangle emacsconfig/org.el
    167        (use-package htmlize)
    168      #+end_src
    169 **** Org roam                                                      :noexport:
    170      My parents are really urging me to take notes of stuff now. And I'm inclined to agree. I'll try and figure out what
    171      I need from my note taking program down the line, but for now here is a basic config
    172      Mostly stolen from [[https://systemcrafters.net/build-a-second-brain-in-emacs/][System crafters]]
    173      I will have to figure out what most of this does /exactly/ but from the description this all seems like
    174      stuff that I'd want for my note taking setup
    175      #+begin_src emacs-lisp :tangle no
    176        (use-package org-roam
    177 	 :ensure t
    178 	 :demand t  ;; Ensure org-roam is loaded by default
    179 	 :init
    180 	 (setq org-roam-v2-ack t)
    181 	 :custom
    182 	 (org-roam-directory "~/Documents/notes")
    183 	 (org-roam-completion-everywhere t)
    184 	 :bind (("C-c n l" . org-roam-buffer-toggle)
    185 		("C-c n f" . org-roam-node-find)
    186 		("C-c n i" . org-roam-node-insert)
    187 		("C-c n I" . org-roam-node-insert-immediate)
    188 		("C-c n p" . my/org-roam-find-project)
    189 		("C-c n t" . my/org-roam-capture-task)
    190 		("C-c n b" . my/org-roam-capture-inbox)
    191 		:map org-mode-map
    192 		("C-M-i" . completion-at-point)
    193 		:map org-roam-dailies-map
    194 		("Y" . org-roam-dailies-capture-yesterday)
    195 		("T" . org-roam-dailies-capture-tomorrow))
    196 	 :bind-keymap
    197 	 ("C-c n d" . org-roam-dailies-map)
    198 	 :config
    199 	 (require 'org-roam-dailies) ;; Ensure the keymap is available
    200 	 (org-roam-db-autosync-mode))
    201 
    202        (defun org-roam-node-insert-immediate (arg &rest args)
    203 	 (interactive "P")
    204 	 (let ((args (push arg args))
    205 	       (org-roam-capture-templates (list (append (car org-roam-capture-templates)
    206 							 '(:immediate-finish t)))))
    207 	   (apply #'org-roam-node-insert args)))
    208 
    209        (defun my/org-roam-filter-by-tag (tag-name)
    210 	 (lambda (node)
    211 	   (member tag-name (org-roam-node-tags node))))
    212 
    213        (defun my/org-roam-list-notes-by-tag (tag-name)
    214 	 (mapcar #'org-roam-node-file
    215 		 (seq-filter
    216 		  (my/org-roam-filter-by-tag tag-name)
    217 		  (org-roam-node-list))))
    218 
    219        (defun my/org-roam-refresh-agenda-list ()
    220 	 (interactive)
    221 	 (setq org-agenda-files (my/org-roam-list-notes-by-tag "Project")))
    222 
    223        ;; Build the agenda list the first time for the session
    224        (my/org-roam-refresh-agenda-list)
    225 
    226        (defun my/org-roam-project-finalize-hook ()
    227 	 "Adds the captured project file to `org-agenda-files' if the
    228        capture was not aborted."
    229 	 ;; Remove the hook since it was added temporarily
    230 	 (remove-hook 'org-capture-after-finalize-hook #'my/org-roam-project-finalize-hook)
    231 
    232 	 ;; Add project file to the agenda list if the capture was confirmed
    233 	 (unless org-note-abort
    234 	   (with-current-buffer (org-capture-get :buffer)
    235 	     (add-to-list 'org-agenda-files (buffer-file-name)))))
    236 
    237        (defun my/org-roam-find-project ()
    238 	 (interactive)
    239 	 ;; Add the project file to the agenda after capture is finished
    240 	 (add-hook 'org-capture-after-finalize-hook #'my/org-roam-project-finalize-hook)
    241 
    242 	 ;; Select a project file to open, creating it if necessary
    243 	 (org-roam-node-find
    244 	  nil
    245 	  nil
    246 	  (my/org-roam-filter-by-tag "Project")
    247 	  :templates
    248 	  '(("p" "project" plain "* Goals\n\n%?\n\n* Tasks\n\n** TODO Add initial tasks\n\n* Dates\n\n"
    249 	     :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+category: ${title}\n#+filetags: Project")
    250 	     :unnarrowed t))))
    251 
    252        (defun my/org-roam-capture-inbox ()
    253 	 (interactive)
    254 	 (org-roam-capture- :node (org-roam-node-create)
    255 			    :templates '(("i" "inbox" plain "* %?"
    256 					  :if-new (file+head "Inbox.org" "#+title: Inbox\n")))))
    257 
    258        (defun my/org-roam-capture-task ()
    259 	 (interactive)
    260 	 ;; Add the project file to the agenda after capture is finished
    261 	 (add-hook 'org-capture-after-finalize-hook #'my/org-roam-project-finalize-hook)
    262 
    263 	 ;; Capture the new task, creating the project file if necessary
    264 	 (org-roam-capture- :node (org-roam-node-read
    265 				   nil
    266 				   (my/org-roam-filter-by-tag "Project"))
    267 			    :templates '(("p" "project" plain "** TODO %?"
    268 					  :if-new (file+head+olp "%<%Y%m%d%H%M%S>-${slug}.org"
    269 								 "#+title: ${title}\n#+category: ${title}\n#+filetags: Project"
    270 								 ("Tasks"))))))
    271 
    272        (defun my/org-roam-copy-todo-to-today ()
    273 	 (interactive)
    274 	 (let ((org-refile-keep t) ;; Set this to nil to delete the original!
    275 	       (org-roam-dailies-capture-templates
    276 		'(("t" "tasks" entry "%?"
    277 		   :if-new (file+head+olp "%<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>\n" ("Tasks")))))
    278 	       (org-after-refile-insert-hook #'save-buffer)
    279 	       today-file
    280 	       pos)
    281 	   (save-window-excursion
    282 	     (org-roam-dailies--capture (current-time) t)
    283 	     (setq today-file (buffer-file-name))
    284 	     (setq pos (point)))
    285 
    286 	   ;; Only refile if the target file is different than the current file
    287 	   (unless (equal (file-truename today-file)
    288 			  (file-truename (buffer-file-name)))
    289 	     (org-refile nil nil (list "Tasks" today-file nil pos)))))
    290 
    291        (add-to-list 'org-after-todo-state-change-hook
    292 		    (lambda ()
    293 		      (when (equal org-state "DONE")
    294 			(my/org-roam-copy-todo-to-today))))
    295 
    296      #+end_src
    297 **** Denote
    298      I used to want to try out org-roam, but nothing came of that. However, right now I do have notes in denote,
    299      and since emacs-ng doesn't work with denote anymore (since its stuck at version 28.0.50) I have to move to
    300      the default version of emacs
    301      #+begin_src emacs-lisp :tangle emacsconfig/org.el
    302        (use-package denote
    303          :ensure t
    304          :custom
    305          (denote-directory "~/Documents/notes/")
    306          (denote-file-type nil)
    307          (denote-prompts '(title keywords))
    308          (denote-date-prompt-use-org-read-date t)
    309          :bind
    310          (("C-c n n" . denote)
    311           ("C-c n N" . denote-type)
    312           ("C-c n d" . denote-date)
    313           ("C-c n s" . denote-subdirectory)
    314           ("C-c n t" . denote-template)
    315           ("C-c n r" . denote-rename-file)
    316           :map org-mode-map
    317           ("C-c n i" . denote-link)
    318           ("C-c n I" . denote-link-add-links)
    319           ("C-c n l" . denote-link-find-file)
    320           ("C-c n b" . denote-link-backlinks)))
    321      #+end_src
    322 *** Evil mode
    323     I am originally a vim user, and the standard vim bindings have not left my hands yet,
    324     I am not a big configurer, so this is mostly just the standard configuration that [[https://github.com/emacs-evil/evil-collection#installation][evil-mode]] advices you to do
    325     #+begin_src emacs-lisp :tangle emacsconfig/evil.el
    326       (use-package evil
    327 	:init
    328 	(setq evil-want-integration t) ;; This is optional since it's already set to t by default.
    329 	(setq evil-want-keybinding nil)
    330 	:config
    331 	(evil-define-key 'normal global-map "," 'evil-execute-in-god-state)
    332 	(evil-mode 1))
    333 
    334       (use-package evil-collection
    335 	:after evil
    336 	:config
    337 	(evil-collection-init))
    338     #+end_src
    339 **** God-mode
    340      To further prove that I have no intentions at all to be busy with making evil bindings for eveything I find
    341      I have also installed god-mode to help me do effortless keybinding for those programs that don't have evil
    342      support
    343      #+begin_src emacs-lisp :tangle emacsconfig/evil.el
    344        (use-package evil-god-state
    345 	 :bind
    346 	 ("M-," . evil-god-state-bail))
    347 
    348        (use-package god-mode)
    349      #+end_src
    350 **** Tree-sitter
    351      There is a pre-configured package that allows for easy tree-sitter support for a few languages. Nixos + tree-sitter
    352      is surprisingly painless, so I figured I'd just add it
    353      #+begin_src emacs-lisp :tangle emacsconfig/evil.el
    354        (use-package evil-tree-edit
    355 	 :hook
    356 	 (java-mode . evil-tree-edit-mode)
    357 	 (python-mode . evil-tree-edit-mode))
    358      #+end_src
    359 *** Which-key
    360     Has god-mode support
    361     #+begin_src emacs-lisp :tangle emacsconfig/extras.el
    362       (use-package which-key
    363 	:after god-mode
    364 	:config
    365 	(which-key-enable-god-mode-support)
    366 	(which-key-mode))
    367     #+end_src
    368 *** PDF-tools
    369     I don't want to be at the mercy of my browser to figure out how to read a PDF
    370     #+begin_src emacs-lisp :tangle emacsconfig/extras.el
    371       (use-package pdf-tools
    372         :config
    373         (add-to-list 'auto-mode-alist '("\\.pdf$" . pdf-view-mode)))
    374     #+end_src
    375 ** Programming-related emacs tools
    376    I do computer science, so from now and then I tend to program a bit. Here are all the tools I use to accomplish
    377    that stuff
    378 *** Company
    379     Generally nice for auto-completion anywhere. I think here is also the place to note that I am not a huge fan
    380     of language-servers, as I've had bad experiences with them when I was still using vim
    381     #+begin_src emacs-lisp :tangle emacsconfig/extras.el
    382       (use-package company
    383 	:bind
    384 	("C-SPC" . company-complete))
    385     #+end_src
    386 *** Matching of parentheses and other stuff
    387     "ERROR: Unmatched parenteses/braces/whatever" is really a thing I would prefer to never see again
    388     It has nix and lisp support, but other langages are fairly standards so not much configuration needed there
    389     #+begin_src emacs-lisp :tangle emacsconfig/extras.el
    390       (use-package smartparens
    391 	:hook
    392 	(emacs-lisp-mode . smartparens-mode)
    393 	(nix-mode . smartparens-mode)
    394 	(lisp-mode . smartparens-mode)
    395 	:config
    396 	(sp-with-modes '(lisp-mode emacs-lisp-mode)
    397 		       (sp-local-pair "'" nil :actions nil)
    398 		       (sp-local-pair "`" nil :actions nil))
    399 
    400 	(sp-with-modes '(nix-mode)
    401 		       (sp-local-pair "'" nil :actions nil)
    402 		       (sp-local-pair "''" "''")))
    403     #+end_src
    404 *** Languages
    405     Other than that, there are some language-specific setups that I want to do,which are a bit more complicated
    406     than just "editing a file"
    407 **** Nix
    408      Nix is a fairly essential language here. Not just because I run NixOS, but also because it provides
    409      external packages (interpreters, compilers, tooling etc.) to the programs that need it
    410 ***** Nix mode
    411       This config is just part of editing nix config. It is supposed to come with company support, but
    412       the auto-completion backend turns out to not be that great. We'll see what I do with it
    413       #+begin_src emacs-lisp :tangle emacsconfig/nix.el
    414 	(use-package nix-mode
    415 	  :mode "\\.nix\\'"
    416 	  :hook
    417 	  (nix-mode . company-mode)
    418 	  :config
    419 	  ;; the company-nix backend is not available in melpa, but has no new dependencies
    420 	  (unless (package-installed-p 'company-nix)
    421 	    (with-temp-buffer
    422 	      (url-insert-file-contents "https://github.com/NixOS/nix-mode/raw/master/nix-company.el")
    423 	      (eval-buffer)))
    424 	  (add-hook 'nix-mode-hook (lambda ()
    425 				     (set (make-local-variable 'company-backends)
    426 					  '((company-nix)))))
    427 	  (add-hook 'nix-mode-hook 'company-mode))
    428       #+end_src
    429 ***** Nix package management
    430       I use nix-sandbox for managing nix package for other languages.
    431       One of the functions doesn't work that well for me so I replaced it with something that does
    432       #+begin_src emacs-lisp :tangle emacsconfig/nix.el
    433         (use-package nix-sandbox
    434           :demand
    435           :config
    436           (defun nix-executable-find (sandbox executable)
    437             "finds an EXECUTABLE in SANDBOX"
    438             (set (make-local-variable 'exec-path) (nix-exec-path sandbox))
    439             (executable-find executable))
    440       #+end_src
    441       Beyond that, there is a helper function that makes it easy to quickly define environments with the required
    442       packages for a programming language
    443       #+begin_src emacs-lisp :tangle emacsconfig/nix.el
    444         (defun intersperse (el ls) (if (cdr ls) `(,(car ls) ,el . ,(intersperse el (cdr ls))) ls))
    445         (defun nix-env-from-packages (name &rest packages)
    446           "create a nix environment from nix packages. returns the location of the environment"
    447           (interactive (append
    448                         (list (read-string "Environment name: " nil nil "nameless"))
    449                         (split-string (read-string "Packages: "))))
    450           (with-temp-buffer
    451             (insert (format "
    452                 { pkgs ? import %s {}}:
    453                 pkgs.mkShell {
    454                 buildInputs = with pkgs;[
    455                 %s
    456                 ];
    457                 }
    458                     " (or nix-nixpkgs-path "<nixpkgs>") (apply 'concat (intersperse "\n" packages))))
    459             (write-file (concat temporary-file-directory name "-env/shell.nix"))
    460             (nix-find-sandbox (concat temporary-file-directory name "-env")))))
    461       #+end_src
    462 **** Python
    463      Python is a bit weird. It had no intentions at all to do things the way I wanted it to do things with
    464      use-package, so I had to find a weird work-arounds with add-hook and all that stuff
    465      #+begin_src emacs-lisp :tangle emacsconfig/python.el :padline no :noweb no-export
    466        (add-hook 'python-mode-hook (lambda ()
    467 				     <<el-python-config>>))
    468 
    469      #+end_src
    470      First we set an interpreter with nix, it comes with all the python autocompletion tools we need
    471      #+begin_src emacs-lisp :noweb-ref el-python-config :tangle no
    472        (setq python-shell-interpreter
    473 	     (nix-executable-find
    474 	      (nix-env-from-packages "python" "(python3.withPackages (p: with p; [pygame virtualenvwrapper pip sqlite jedi flake8 yapf autopep8 black]))")
    475 	      "python"))
    476 
    477      #+end_src
    478      Then we introduce elpy with so that it can use all the tools immidiately without downloading them
    479      #+begin_src emacs-lisp :noweb-ref el-python-config :tangle no
    480        (use-package elpy
    481 	 :config
    482 	 (elpy-enable)
    483 	 (setq elpy-rpc-python-command python-shell-interpreter))
    484 
    485      #+end_src
    486 **** Haskell
    487      I have to use haskell in my new module, so there is now some haskell infra for that
    488      first we have to set up a nix environment for our haskell tools
    489      #+begin_src emacs-lisp :tangle emacsconfig/haskell.el
    490      #+end_src
    491      Then haskell-mode setup, which integrates company mode as well as the sandbox
    492      #+begin_src emacs-lisp :tangle emacsconfig/haskell.el
    493        (use-package haskell-mode
    494          :mode "\\.hs\\'"
    495          :after nix-sandbox
    496          :hook
    497          (haskell-mode . set-haskell-company-backends)
    498          (haskell-mode . company-mode)
    499          (haskell-mode . haskell-indentation-mode)
    500          :config
    501          (setq haskell-env (nix-env-from-packages "Haskell"
    502                                                   "ghc"
    503                                                   "cabal-install"
    504                                                   "haskellPackages.fourmolu"))
    505          (setq haskell-process-wrapper-function
    506                (lambda (args)
    507                  (cons
    508                   (nix-executable-find haskell-env (car args))
    509                   (cdr args))))
    510          (defun set-haskell-company-backends ()
    511            (set (make-local-variable 'company-backends)
    512                 '((dante-company company-files)))))
    513      #+end_src
    514      ormolu formats my haskell files, though I use fourmolu since I prefer prefixing chained infix functions
    515      #+begin_src emacs-lisp :tangle emacsconfig/haskell.el
    516        (use-package ormolu
    517          :after haskell-mode
    518          :hook
    519          (haskell-mode . ormolu-format-on-save-mode)
    520          (haskell-mode . (lambda ()
    521                            (set (make-local-variable 'ormolu-process-path)
    522                                 (nix-executable-find haskell-env "fourmolu"))))
    523          :bind
    524          (:map haskell-mode-map
    525                ("C-c r" . ormolu-format-buffer)))
    526      #+end_src
    527      Finally, dante runs as background interpreter of my haskell codes and checks stuff for errors
    528      #+begin_src emacs-lisp :tangle emacsconfig/haskell.el
    529        (use-package dante
    530          :after haskell-mode
    531          :hook
    532          (haskell-mode . dante-mode)
    533          :custom
    534          (dante-repl-command-line (nix-executable-find haskell-env "ghci"))
    535          (dante-methods '(nix-ghci bare-cabal bare-ghci)))
    536      #+end_src
    537 
    538 **** Web stuff
    539      I also have made some basic webpages. I haven't gotten too deep into JS with emacs yet, so this section
    540      might expand later, but so far this is what I have
    541 ***** Web mode
    542       General xml stuff editing. Fairly standard
    543       #+begin_src emacs-lisp :tangle emacsconfig/web.el
    544 	(use-package web-mode
    545 	  :mode (("\\.x?html?\\'" . web-mode)
    546 		 ("\\.x[sm]l\\'"  . web-mode)
    547 		 ("\\.css\\'"     . web-mode)
    548 		 ("\\.jsx?\\'"    . web-mode)
    549 		 ("\\.tsx?\\'"    . web-mode)
    550 		 ("\\.json\\'"    . web-mode))
    551 	  :custom
    552 	  (web-mode-markup-indent-offset 2) ; HTML
    553 	  (web-mode-css-indent-offset 2)    ; CSS
    554 	  (web-mode-code-indent-offset 2)   ; JS/JSX/TS/TSX
    555 	  (web-mode-content-types-alist '(("jsx" . "\\.js[x]?\\'"))))
    556 	(use-package elnode)
    557 
    558       #+end_src
    559 ***** Emmet mode
    560       for quickly inserting a whole XML tree
    561       #+begin_src emacs-lisp :tangle emacsconfig/web.el
    562 	(use-package emmet-mode
    563 	  :hook
    564 	  (sgml-mode . emmet-mode)
    565 	  (web-mode . emmet-mode)
    566 	  (css-mode . emmet-mode)
    567 	  :bind
    568 	  (:map emmet-mode-keymap
    569 		("TAB" . emmet-dwim))
    570 	  :config
    571 	  (defun emmet-dwim (prefix)
    572 	    (interactive "p")
    573 	    (or
    574 	     (emmet-go-to-edit-point prefix)
    575 	     (emmet-expand-line prefix)
    576 	     (evil-jump-forward prefix))))
    577       #+end_src
    578 ** Other, less useful stuff
    579 *** Themes
    580     I like to have a nice theme in my setup
    581     #+begin_src emacs-lisp :tangle emacsconfig/misc.el
    582       (use-package flatland-theme
    583 	:config
    584 	(load-theme 'flatland))
    585     #+end_src
    586     Also I want to theme my config exports
    587     #+begin_src emacs-lisp :tangle emacsconfig/extras.el
    588       (use-package htmlize)
    589     #+end_src
    590 *** Discord
    591     My discord buddies /have/ to know I'm using emacs whenever I have my computer running
    592     #+begin_src emacs-lisp :tangle emacsconfig/misc.el
    593       (use-package elcord
    594 	:config
    595 	(elcord-mode))
    596     #+end_src
    597 *** Emenu
    598     Since I'm using emacs as a daemon, it can also be benefical to make an application launcer
    599     #+begin_src emacs-lisp :tangle emacsconfig/misc.el
    600       (defun all-commands ()
    601 	"does a completing read of all the programs accessible to you in $PATH"
    602 	(let ((ls-output (mapcan (lambda (path)
    603 				   (when (file-readable-p path)
    604 				     (cl-remove-if (lambda (file)
    605 						     (let ((fullpath (concat path "/" file)))
    606 						       (or (file-directory-p fullpath)
    607 							   (not (file-executable-p fullpath)))))
    608 						   (directory-files path nil directory-files-no-dot-files-regexp nil))))
    609 				 (split-string (getenv "PATH") ":" t)))
    610 	      (alias-output (split-string (shell-command-to-string "alias -p | sed -E 's/^alias ([^=]*)=.*$/\\1/'") "\n")))
    611 	  (append ls-output alias-output)))
    612 
    613       (defun emenu (&optional command-list)
    614 	"A dmenu-inspired application launcher using a separate emacs frame"
    615 	(interactive)
    616 	(with-selected-frame (make-frame '((name . "emenu")
    617 					   (minibuffer . only)
    618 					   (width . 151)
    619 					   (height . 1)))
    620 	  (unwind-protect
    621 	      (progn
    622 		(call-process
    623 		 (ido-completing-read "Command: " (or
    624 						   command-list
    625 						   (all-commands)))
    626 		 nil
    627 		 0)
    628 		(keyboard-quit))
    629 	    (delete-frame))))
    630     #+end_src