literate-config

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

emacs.org (29731B)


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