dotfiles

how i generate this site and disorganize my life using one git repo

this document generates my system configuration. it is full of unclear choices and cryogenically-preserved commented-out cruft.

my desiderata for computer tools are these:

  1. don't make me use some arcane file format, everything should ultimately be in plain text
  2. don't make me store data unencrypted on anybody else's server
  3. chaining simpler programs and scripts together is preferable to all-in-one solutions

following these intuitions has caused me to end up with an eccentric hodgepodge of tools, but it mostly works out.

org-mode

i keep all of my notes in org-mode format. the format is similar conceptually to markdown: you write in plain text following certain conventions (/slashes/ for italics, etc.) and can then export to html, latex, pdf, et cetera. writing in this way makes it easy to generate pdfs for papers and html for this site.

org-mode is an emacs module. although by birth a vim user, i now use emacs heavily, with the doom emacs framework and evil mode for vi-style keybindings. thanks to the org-babel component, one of org-mode's functions is as a literate programming system, as you see in this page. thus a <<chunk>> of code can be named in one embedded code block, but specified in detail in another, and a keystroke (C-c C-v t) will tangle those chunks together, exporting them to finished files.

org-mode focuses heavily on outlining and to-do behavior. in practice i use the to-do functions most heavily on my phone (which runs grapheneos btw🤓), thanks to orgzly. the one case where i do use org-mode's to-do functions in emacs more frequently than on my phone is for tracking my reading list.i deleted my goodreads bc the feds don't check neocities

for managing my citations and storing my ebook library, i use the software zotero. being yoked to a big gui database is not super in line with my ideals, but it's unavoidable in this case, and zotero is good software. thanks to the better bibtex plugin, i can automatically export my library to a biblatex file, then reference that in my org files and let pandoc format the citations for me.

this site

this site is created using an improvised static site generator consisting of a pandoc template and a short tupfile (think makefile):

: padma.org |> pandoc %f --citeproc --bibliography=zotero.bib --csl chicago-note-bibliography.csl --shift-heading-level-by=1 --section-divs --toc --filter pandoc-sidenote --template=style/tufte.html5 -c padma.css -c style/pandoc.css -c style/tufte.css --lua-filter=padma.lua -o %o |> padma/index.html
: foreach *.org |> pandoc "%f" --citeproc --bibliography=zotero.bib --csl chicago-note-bibliography.csl --shift-heading-level-by=1 --section-divs --toc --filter pandoc-sidenote --template=style/tufte.html5 -c padma.css -c style/pandoc.css -c style/tufte.css --lua-filter=padma.lua -o "%o" |> padma/%B.html
: foreach bibliographies/*.org |> pandoc "%f" --citeproc --bibliography=zotero.bib --csl chicago-annotated-bib.csl --shift-heading-level-by=1 --section-divs --toc --filter pandoc-sidenote --template=style/tufte.html5 -c ../style/pandoc.css -c ../style/tufte.css --lua-filter=padma.lua --metadata=suppress-bibliography:true -o "%o" |> padma/bibliographies/%B.html
: |> ln -s ../style padma/style |> padma/style
: foreach style/*.css style/*.html5 style/*.ttf style/*.woff style/*.eot style/*.svg |> cp "%f" "%o" |> style/%f
: foreach *.css *.jpg *.png *.gif *.svg |> cp "%f" "%o" |> padma/%f

this transforms every org file into an html file in the output directory.

the job of the lua filter is to rewrite links so that i can link to the file example.org in my org notes, and in the html it'll become a link to the file html.org. my first attempt at setting this up, it broke all links to websites ending in dot org.

function Link(el)
  el.target = string.gsub(string.gsub(string.gsub(el.target, "%.org/", ".orn/"), "%.org", ".html"), "%.orn/", ".org/")
  return el
end

now, all i have to do to update the website content is run tup and neocities push the output directory.

configure org-mode

enable org-mode related modules for doom

:lang (org +pretty +pandoc +dragndrop +noter +pomodoro)
:ui deft
:tools biblio
:app calendar

install extra org-mode related packages

(package! org-books)
(package! org-super-links
  :recipe
  (:host github
   :repo "toshism/org-super-links"
   :branch "develop") :pin "dd303357f996993074d8d251fcb2c9e18d8036af")
(package! anki-editor
:recipe (:host github :repo "anki-editor/anki-editor") :pin "75367008d43d5c120341b3511c4a098b7abd5cbc")
;; (package! mplayer-mode ;; fork of mplayer-mode to support orgqda-transcript
;;   :recipe
;;   (:host github
;;    :repo "andersjohansson/mplayer-mode"
;;    :branch "org-sessions") :pin "0e2f2cd1f3697002d55fe50f28cb601151bbbdd9")
;; (package! orgqda
;;   :recipe
;;   (:repo "https://gitlab.com/andersjohansson/orgqda.git"
;;    :branch "main"
;;    :host nil
;;    :type "git")
;;   :pin "8ea5c286174c6a65d2cdb9fc53a9d9d6722f9495")
(package! org-translate)

configure org-mode

(setq! citar-bibliography '("~/zotero.bib"))
(setq deft-directory "~/")
(setq org-directory "~/")
(setq org-books-file "~/books-2025.org")
(use-package! org-habit
  :after org
  :config
  (setq org-log-into-drawer "LOGBOOK") ;;Not necessarily the best place to put this. Ensures compatibility with orgzly
  )

(map! :map org-mode-map
        :localleader
        :prefix ("S" . "org-super-links")
        "l" #'org-super-links-link
        "s" #'org-super-links-store-link
        "S" #'org-super-links-insert-link
)

(map! :map org-mode-map
      :localleader)

(use-package! anki-editor-ui)
(map! :map org-mode-map
      :localleader
      "N" #'anki-editor-ui)

;; (use-package! orgqda-completion
;;   :hook 'orgqda-mode-hook #'orgqda-completion-mode)
;; (use-package! orgqda-transcript)

;; (use-package! org-noter
;;   :after org-roam
;;   :config
;;   (org-noter-enable-org-roam-integration)
;;   ;; (setq org-noter-create-session-from-document-hook '(org-noter--create-session-from-document-file-supporting-org-roam))
;; )
;; (use-package! org-attach-git)
;; (use-package! orgqda-transcript
;;   :custom
;;   (orgqda-transcript-bind-fn-keys t)
;;   (orgqda-transcript-bind-1-4-keys t)
;;   (orgqda-transcript-set-up-speaker-keys t)
;;   (orgqda-transcript-set-up-speaker-keys-5-9 t)
;;   (orgqda-transcript-rebind-c-s-ret t)
;;   (orgqda-transcript-rebind-s-ret t)
;;   :config
;;   )
;; (use-package! org-translate
;;   :after org
;;   )

;; (use-package! anki-editor ;taken from https://yiufung.net/post/anki-org/
;;   :after org
;;   :bind (:map org-mode-map
;;               ("<f12>" . anki-editor-cloze-region-auto-incr)
;;               ("<f11>" . anki-editor-cloze-region-dont-incr)
;;               ("<f10>" . anki-editor-reset-cloze-number)
;;               ("<f9>"  . anki-editor-push-tree))
;;   :hook (org-mode . anki-editor-mode)
;;   :hook (org-capture-after-finalize . anki-editor-reset-cloze-number) ; Reset cloze-number after each capture.
;;   :config
;;   (setq anki-editor-create-decks t ;; Allow anki-editor to create a new deck if it doesn't exist
;;         anki-editor-org-tags-as-anki-tags t)
;;
;;   (defun anki-editor-cloze-region-auto-incr (&optional arg)
;;     "Cloze region without hint and increase card number."
;;     (interactive)
;;     (anki-editor-cloze-region my-anki-editor-cloze-number "")
;;     (setq my-anki-editor-cloze-number (1+ my-anki-editor-cloze-number))
;;     (forward-sexp))
;;   (defun anki-editor-cloze-region-dont-incr (&optional arg)
;;     "Cloze region without hint using the previous card number."
;;     (interactive)
;;     (anki-editor-cloze-region (1- my-anki-editor-cloze-number) "")
;;     (forward-sexp))
;;   (defun anki-editor-reset-cloze-number (&optional arg)
;;     "Reset cloze number to ARG or 1"
;;     (interactive)
;;     (setq my-anki-editor-cloze-number (or arg 1)))
;;   (defun anki-editor-push-tree ()
;;     "Push all notes under a tree."
;;     (interactive)
;;     (anki-editor-push-notes '(4))
;;     (anki-editor-reset-cloze-number))
;;   ;; Initialize
;;   (anki-editor-reset-cloze-number)
;;   )

git

effectively everything important to me is stored in one git repository. at the top level, i have the files that make up this website. in subdirectories are my personal notes, as well as my massive ebook library; ebooks are kept in the right places thanks to the zotmoov plugin for zotero. of course, it's not a good idea to check a lot of big binary files directly into git: instead i use git-annex, which moves them into a content-addressed store and instead does version control on the checksums. this way i can store references to the state of the filesystem without bloating my git repo, checking out only the files i need. git-annex is a very powerful tool for managing multiple copies of files and running backups; i have to admit i'm not currently using it to its full potential. i don't really need to track media libraries and notes together, so in fact the subfolders for books, movies, music, et cetera are separate git branches which appear as subdirectories using git worktree. again, this means i don't need to have those sub-branches cluttering up the directory structure on every clone unless i specifically choose to.

git also serves as my cloud data sync/backup solution. i don't want all my notes sitting unencrypted on somebody else's computer, so before syncing to a github repo i use git-remote-gcrypt to pgp encrypt them. syncing this to my phone is definitely the hackiest part of my setup, as i have to use a termux script and had to make some modifications to git-remote-crypt to get it to run. most of the time it works, though sometimes the remote gets corrupted and i have to wipe and reupload it.

configure git

install git and related packages

git
haskellPackages.git-annex
git-remote-gcrypt

configure identity

programs.git = {
  enable = true;
  userName = "I W";
  userEmail = "wildthyme+git@protonmail.com";
};

enable git oh-my-zsh plugin

"git"

enable doom module

:tools magit

password-store

pass is a simple unixy password manager that uses gpg and git. it lives in another branch/worktree of my main git repo. it has an android app, though active development has ceased.

configure for nixos:

pinentry-curses
passExtensions.pass-import
(pass.withExtensions (ext: with ext; [ pass-import ]))
pass

enable doom module

:tools pass

set up chromium extension

programs.browserpass = {
  enable = true;
  browsers = [ "chromium" ];
};

nix flake

the nix flake is the entry point from which the entire config is built. provided only this git repo, my whole system could (nominally) be reconfigured from scratch

create a flake.nix.

{
  description = "I.W.'s nix config'";

  inputs = {
    nixpkgs = {
      url = "github:nixos/nixpkgs/nixpkgs-unstable";
    };
    <<flake-inputs>>
  };

  outputs = inputs @ { self, nixpkgs, home-manager, nix-doom-emacs-unstraightened, ... }: {
    <<flake-outputs>>
  };
}

enable the experimental flake feature in my laptop's nix config, so that it can actually be built.

nix = {
package = pkgs.nixVersions.latest;
extraOptions = ''
    experimental-features = nix-command flakes
'';
};

nixos

in the flake, define my laptop, a nixos system named ai with a user i controlled by home-manager.

nixosConfigurations.ai = nixpkgs.lib.nixosSystem {
    system = "x86_64-linux";
    modules = [
        ./nix/ai.nix
        home-manager.nixosModules.home-manager
        {
                home-manager.useGlobalPkgs = true;
                home-manager.useUserPackages = true;
                home-manager.sharedModules = [ inputs.nix-doom-emacs-unstraightened.hmModule ];
                home-manager.users.i = import ./nix/home.nix;
                home-manager.backupFileExtension = "backup";
        }
        ({ pkgs, ... }: {
                nixpkgs.overlays = [ nix-doom-emacs-unstraightened.overlays.default ];
        })
    ];
};

configure it.

{ config, pkgs, ... }:

{
  imports =
    [ # Include the results of the hardware scan.
      ./ai-hardware-configuration.nix
    ];

  # Bootloader
  boot.loader.grub.enable = true;
  boot.loader.grub.device = "/dev/nvme0n1";
  boot.loader.grub.useOSProber = true;

  # Setup keyfile
  boot.initrd.secrets = {
    "/crypto_keyfile.bin" = null;
  };

  boot.loader.grub.enableCryptodisk=true;

  boot.initrd.luks.devices."luks-b64b7411-f1bc-400c-9427-a51e91d90509".keyFile = "/crypto_keyfile.bin";
  networking.hostName = "ai"; # ai for ai-ren 愛人
  networking.networkmanager.enable = true; # enable networking
  time.timeZone = "Asia/Taipei"; # set time zone

  # select internationalisation properties.
  i18n.defaultLocale = "en_US.UTF-8";
  i18n.extraLocaleSettings = {
    LC_ADDRESS = "en_US.UTF-8";
    LC_IDENTIFICATION = "en_US.UTF-8";
    LC_MEASUREMENT = "en_US.UTF-8";
    LC_MONETARY = "en_US.UTF-8";
    LC_NAME = "en_US.UTF-8";
    LC_NUMERIC = "en_US.UTF-8";
    LC_PAPER = "en_US.UTF-8";
    LC_TELEPHONE = "en_US.UTF-8";
    LC_TIME = "en_US.UTF-8";
  };

  # set up graphics and kde
  services.xserver.enable = true;
  services.displayManager.sddm.enable = true;
  services.desktopManager.plasma6.enable = true;
  services.xserver = {
    xkb.layout = "us";
    xkb.variant = "";
  };

  services.printing.enable = true; # enable printing

  # set up sound
  # services.pulseaudio.enable = false; # shouldn't need to specifically enable
  security.rtkit.enable = true;
  services.pipewire = {
    enable = true;
    alsa.enable = true;
    alsa.support32Bit = true;
    pulse.enable = true;
  };

  users.users.i = { # define me
    isNormalUser = true;
    description = "Inge Winsome";
    extraGroups = [ "networkmanager" "wheel" "adbusers" ];
  };


  nixpkgs.config.allowUnfree = true; # allow unfree packages

  environment.systemPackages = with pkgs; [ # install some basics
    vim
    wget
    ncdu
    git
    zip
    unzip
    <<nixos-packages>>
  ];

  programs.gnupg.agent = { # for pass etc.
    enable = true;
    enableSSHSupport = true;
  };

  services.openssh = { # enable openssh daemon
    enable = true;
    settings.PasswordAuthentication = false;
    ports = [ 17856 ]; # 😳
  };

  # before changing this value read the documentation for this option (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
  system.stateVersion = "23.11"; # did you read the comment?

  <<nixos-section>>

  programs.steam.enable = true; # 🎮
  hardware.bluetooth.enable = true; #  藍芽

}

hardware config

configure hardware (VERY BORING)

# Do not modify this file!  It was generated by ‘nixos-generate-config’
# and may be overwritten by future invocations.  Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:

{
  imports =
    [ (modulesPath + "/installer/scan/not-detected.nix")
    ];

  boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "sd_mod" ];
  boot.initrd.kernelModules = [ ];
  boot.kernelModules = [ "kvm-intel" ];
  boot.extraModulePackages = [ ];

  fileSystems."/" =
    { device = "/dev/disk/by-uuid/6ecb174c-be9a-4cff-9525-235c86200dc6";
      fsType = "ext4";
    };

  boot.initrd.luks.devices."luks-b64b7411-f1bc-400c-9427-a51e91d90509".device = "/dev/disk/by-uuid/b64b7411-f1bc-400c-9427-a51e91d90509";

  fileSystems."/omnibus" =
    { device = "/dev/disk/by-uuid/8d60f73d-6b51-4f5c-a9a3-44353698266e";
      fsType = "ext4";
    };

  swapDevices = [ ];

  # Enables DHCP on each ethernet and wireless interface. In case of scripted networking
  # (the default) this is the recommended approach. When using systemd-networkd it's
  # still possible to use this option, but it's recommended to use it in conjunction
  # with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
  networking.useDHCP = lib.mkDefault true;
  # networking.interfaces.enp0s31f6.useDHCP = lib.mkDefault true;
  # networking.interfaces.wlp61s0.useDHCP = lib.mkDefault true;

  nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
  hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}

home

add home-manager to flake inputs. this allows for declarative control of user-facing app settings, and potentially for sharing the same user setup between nixos and other (darwin/linux) nix environments.

home-manager = {
  url = "github:nix-community/home-manager/master";
  inputs.nixpkgs.follows = "nixpkgs";
};

configure home environment using home-manager.

{ config, pkgs, ... }:

{
  programs.home-manager.enable = true; # let home manager install and manage itself.
  home.username = "i";
  home.homeDirectory = "/home/i";
  home.stateVersion = "21.05"; # determines the home manager release that the configuration is compatible with
  nixpkgs.config.allowUnfree = true;

  home.packages = with pkgs; [ # many of these packages i have no memory of the purposes for which i installed
    vim # old habit
    htop # tui for running processes
    glances # fancier tui for system status
    autoconf # 爲什麼是手控安裝的?
    automake # 爲什麼是手控安裝的?
    libpng # 爲什麼是手控安裝的?
    zlib # 爲什麼是手控安裝的?
    sqlite # 爲什麼是手控安裝的?
    unrar # work with rar archives
    file-rename # batch rename files using regex
    tup # like an austere form of make
    ncdu # ncurses disk usage analyzer
    w3m # tui web browser
    neocities # cli upload
    # pciutils # 爲什麼安裝了?
    # fwupd # 爲什麼安裝了?
    # beets # powerful cli music library manager
    <<home-packages>>
  ];

  programs.direnv.enable = true;
  programs.direnv.nix-direnv.enable = true;

  home.sessionPath = [
    "$HOME/.local/bin"
    "$HOME/.local/share/gem/ruby/3.3.0/bin"
    "$HOME/.config/emacs/bin"
  ];

  # services.kdeconnect.enable = true;

  <<home-config>>
}

shell

users.defaultUserShell = pkgs.zsh;
programs.command-not-found.enable = true;
programs.zsh = {
  enable = true;
  ohMyZsh = {
    enable = true;
    theme = "random";
    plugins = [
      "history-substring-search"
      "vi-mode"
      "command-not-found"
      <<zsh-plugins>>
    ];
  };
};

document and data tools

scantailor-advanced # preprocess book scans (graphical)
tesseract5 # ocr book scans
hocr-tools # work with ocr data from tesseract
briss # crop ugly pdfs, split ones that have a full spread per page (graphical)
pdfsandwich # add ocr layer to pdfs which lack it
pdftk # extract certain pages from pdf or combine multiple pdfs
tectonic # most workable latex→pdf engine (unicode/hanzi works)
biber # work with biblatex
pandoc # document conversion swiss army knife
haskellPackages.pandoc-sidenote # sidenotes >>>>> footnotes/endnotes

# calibre # worst piece of software ever written but sometimes necessary for ebook conversion and deDRM
# pythonPackages.pycryptodome # needed for calibre deDRM plugin - removed for now because it was trying to build a python2 version? figure out later which version is correct https://github.com/noDRM/DeDRM_tools
# poppler # 爲什麼安裝了?
# poppler_utils # 爲什麼安裝了?
# minidjvu # has vulnerabilities and so not allowed 2024-12-14
# djvulibre
# imagemagick # i believe the following were all installed as part of a failed attempt to get pdfbeads working again
# ruby
# rubyPackages.rmagick
# rubyPackages.nokogiri
# rubyPackages.iconv
# openjpeg
# jbig2enc
# pkg-config

graphical applications

signal-desktop # 🤫
soulseekqt # licit music downloads
transmission_4-gtk # licit anime downloads
anki # 🧠
zotero # 🧠

vlc # vlchads >>>>>
mpv # mpvirgins <<<<<
syncplay # meet me in peach garden

exiftool # digikam dep
kolourpaint # mspaint for linux
digikam # kde photo management
koreader # greatest pdf/epub/cbz reader on android/ereaders, less great on desktop
kdePackages.kdeconnect-kde # gimmick app that never works
kdePackages.yakuake # drop-down terminal

lutris # muramasa pls work
winetricks # muramasa pls work
wineWowPackages.waylandFull # muramasa pls work

configure chromium

programs.chromium = {
  enable = true;
  package = pkgs.ungoogled-chromium;
  commandLineArgs = [
    "--enable-features=UseOzonePlatform"
    "--ozone-platform=wayland"
    "--enable-wayland-ime" # force chinese input to work on wayland
  ];
  extensions = [
    { id = "ocaahdebbfolfmndjeplogmgcagdmblk"; } # chromium web store
    { id = "cjpalhdlnbpafiamejdnhcphjbkeiagm"; } # ublock origin
    { id = "dbepggeogbaibhgnhhndojpepiihcmeb"; } # vimium
    { id = "ophjlpahpchlmihnnnihgmmeilfjmjjc"; } # 美眉想不想交換賴?
    { id = "ekhagklcjbdpajgpjgmbionohlpdbjgc"; } # zotero connector
    { id = "cimiefiiaegbelhefglklhhakcgmhkai"; } # kde integration, seems broken <2025-01-14 Tue>
    <<chromium-extensions>>
  ];
};

fonts and theming

install fonts

fonts.fontconfig.enable = true;
fonts.packages = with pkgs; [
  sarasa-gothic
  noto-fonts-cjk-sans
  noto-fonts-cjk-serif
  kreative-square-fonts
];

configure doom appearance

(setq doom-font (font-spec :family "Sarasa Mono Slab SC" :size 18 :weight 'semi-light)
      doom-variable-pitch-font (font-spec :family "Sarasa Gothic SC" :size 18))

(setq doom-theme 'doom-flatwhite)

(setq display-line-numbers-type t)

input methods

configure fcitx for Chinese input. the default pinyin input is probably fine. however, the alternative RIME provides an interesting option labeled 地球拼音, which lets you specify tone 1/2/3/4 by typing - / , \. m17n has a method which allows using numerals to add tone diacritics to pinyin, though you can also just use the compose key to do this.

i18n.inputMethod = {
  enabled = "fcitx5";
  fcitx5 = {
    addons = with pkgs; [
      kdePackages.fcitx5-chinese-addons
      kdePackages.fcitx5-with-addons
      kdePackages.fcitx5-qt
      fcitx5-pinyin-zhwiki # 維基百科 wordlist
      fcitx5-pinyin-moegirl # 萌娘百科 wordlist
      fcitx5-gtk # unsure if this is necessary under kde
      fcitx5-rime
      fcitx5-m17n
    ];
  };
};

enable doom emacs chinese input module. the main benefit is that chinese input is temporarily disabled when you leave insert mode.

:input chinese

configure fcitx support in emacs

(setq fcitx-remote-command "fcitx5-remote")

emacs

add unstraightened doom emacs to flake inputs, so that doom will also be controlled by the master flake

nix-doom-emacs-unstraightened.url = "github:marienz/nix-doom-emacs-unstraightened";
nix-doom-emacs-unstraightened.inputs.nixpkgs.follows = "";

install packages desired by doom emacs

ripgrep
ispell
fd
haskellPackages.nixfmt # :lang nix
wl-clipboard-rs # :lang org
maim # :lang org
shellcheck # :lang sh
html-tidy # :lang web
stylelint # :lang web
jsbeautifier # :lang web

configure unstraightened doom emacs

programs.doom-emacs = {
  enable = true;
  emacs = pkgs.emacs29-pgtk; # pure gtk for native wayland
  doomDir = ./doom;
};

doom config

;;; $DOOMDIR/config.el -*- lexical-binding: t; -*-
(setq user-full-name "I W"
      user-mail-address "wildthyme@protonmail.com")

<<doom-config>>

(use-package! nov
  :mode ("\\.epub\\'" . nov-mode)
  :config
  (setq nov-save-place-file (concat doom-cache-dir "nov-places")))
(pdf-tools-install)

;; (advice-add 'make-auto-save-file-name :around ;;Default was to make auto-save file names contain the path to the original, which could easily be too long for a filename. Using hash instead. Source: https://emacs.stackexchange.com/a/48310
;;             #'my-shorten-auto-save-file-name)
;; (defun my-shorten-auto-save-file-name (&rest args)
;;   (let ((buffer-file-name
;;          (when buffer-file-name (sha1 buffer-file-name))))
;;     (apply args)))
;;

;; (use-package! subed
;;   :config
;;   ;; Disable automatic movement of point by default
;;   ;; (add-hook 'subed-mode-hook 'subed-disable-sync-point-to-player)
;;   ;; Remember cursor position between sessions
;;   (add-hook 'subed-mode-hook 'save-place-local-mode)
;;   ;; Break lines automatically while typing
;;   (add-hook 'subed-mode-hook 'turn-on-auto-fill)
;;   ;; Break lines at 40 characters
;;   ;; (add-hook 'subed-mode-hook (lambda () (setq-local fill-column 40)))
;;   )

doom packages

install additional packages not part of doom modules. using unstraightened doom, it's necessary that any packages from git each be pinned to a specific commit.

;; -*- no-byte-compile: t; -*-
;;; $DOOMDIR/packages.el

(package! nov) ;; nov.el for reading epubs
;; (package! transmission)
;; (package! elmacro)
;; (package! toc-mode
;;   :recipe (:host github :repo "dalanicolai/toc-mode"))
;; (package! dictation ;;old package for playing and pausing a recording while you transcribe
;;   :recipe (:host github :repo "dischoen/dictation.el"))
;; (package! spray
;;   :recipe (:host github :repo "emacsmirror/spray"))

<<doom-packages>>

doom init

this file controls what doom modules are enabled and what order they load in. press SPC h d h to access doom docs.

;;; init.el -*- lexical-binding: t; -*-
(doom! :completion company vertico

       :ui doom doom-dashboard (emoji +unicode) hl-todo indent-guides ligatures minimap modeline ophints (popup +defaults) unicode (vc-gutter +pretty) vi-tilde-fringe workspaces

       :editor (evil +everywhere) file-templates fold (format +onsave) parinfer rotate-text snippets word-wrap

       :emacs dired electric undo vc

       :term eshell
       :tools lsp
       :checkers syntax (spell +flyspell)

       :tools (eval +overlay) lookup pdf

       :os (:if IS-MAC macos) tty

       :lang emacs-lisp (json +lsp) (javascript +lsp) (latex +lsp) lua markdown nix (python +lsp) (sh +lsp) (web +lsp) (yaml +lsp)

       <<doom-modules>>

       :config (default +bindings +smartparens)
)