diff --git a/notetaking/flake.lock b/notetaking/flake.lock new file mode 100644 index 0000000..c5e45df --- /dev/null +++ b/notetaking/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1779560665, + "narHash": "sha256-tpyBcxPpcQb8ukyNF7DoCwfSY3VPsxHoYwj00Cayv5o=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "64c08a7ca051951c8eae34e3e3cb1e202fe36786", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/notetaking/flake.nix b/notetaking/flake.nix new file mode 100644 index 0000000..fba1029 --- /dev/null +++ b/notetaking/flake.nix @@ -0,0 +1,63 @@ +{ + description = "Emacs Notetaking flake"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: let + pkgs = import nixpkgs { + inherit system; + overlays = [ + (import (builtins.fetchTarball { + url = "https://github.com/nix-community/emacs-overlay/archive/master.tar.gz"; + })) + ]; + }; + + plugins = with pkgs.emacsPackages; [ + ]; + in { + devShells.default = pkgs.mkShell { + packages = [ + # https://github.com/nix-community/emacs-overlay + (pkgs.emacsWithPackagesFromUsePackage { + config = ./init.el; + + package = pkgs.emacs; # pkgs.emacs-git + extraEmacsPackages = epkgs: [ + epkgs.unicode-fonts + epkgs.pdf-tools + epkgs.org-pdftools + + pkgs.shellcheck + ]; + }) + + pkgs.hunspell + pkgs.hunspellDicts.nl_NL + pkgs.hunspellDicts.en_GB-large + pkgs.ghostscript + pkgs.graphviz + pkgs.imagemagickBig + pkgs.poppler-utils + pkgs.ripgrep + + pkgs.wl-clipboard + + # Any less than medium isn't guaranteed to work + (pkgs.texlive.withPackages (ps: with ps; [ + scheme-medium + latexmk + # File '*.sty' not found + wrapfig + capt-of + ])) + # required by +jupyter + (pkgs.python314.withPackages (ps: with ps; [ jupyter ])) + ]; + }; + }); +} diff --git a/notetaking/init.el b/notetaking/init.el new file mode 100644 index 0000000..db72510 --- /dev/null +++ b/notetaking/init.el @@ -0,0 +1,170 @@ +;; -*- lexical-binding: t; -*- + +(require 'package) +(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/")) +(setq package-install-upgrade-built-in t) +(package-initialize) +;(package-refresh-contents) ;; Avoid long startup times, I think this is handled by Nix anyway? + +(use-package transient + :ensure t) + +;; Global settings +(desktop-save-mode 1) ;; Remember window layouts and open buffers +(electric-pair-mode 1) ;; Automatic bracket matching +(global-auto-revert-mode t) ;; Automatically refresh buffers when changes on disk +(global-display-line-numbers-mode 1) +(save-place-mode 1) ;; Remember cursor/scroll position +(setq-default indent-tabs-mode nil) + +;; Isolate backup and auto-save files +(setq backup-directory-alist + `(("." . ,(expand-file-name "backups" user-emacs-directory)))) +(setq auto-save-file-name-transforms + `((".*" ,(expand-file-name "auto-saves/" user-emacs-directory) t))) +(setq create-lockfiles nil) ;; Disables .#filename lockfiles + +;; External modules +(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory)) +(load (expand-file-name "modules/my-org.el" user-emacs-directory)) + +;; Search and navigation + +(use-package vertico ;; https://github.com/minad/vertico + :ensure t + ;:custom + ;(vertico-scroll-margin 0) ;; Different scroll margin + ;(vertico-count 20) ;; Show more candidates + ;(vertico-resize t) ;; Grow and shrink the Vertico minibuffer + ;(vertico-cycle t) ;; Enable cycling for `vertico-next/previous' + :init + (vertico-mode) + ) + +(use-package savehist + :init + (savehist-mode) + ) + +(use-package saveplace-pdf-view + :ensure t + :after (:any doc-view pdf-tools) + :demand t) + +(use-package orderless + :ensure t + :custom + ;; Configure a custom style dispatcher (see the Consult wiki) + ;; (orderless-style-dispatchers '(+orderless-consult-dispatch orderless-affix-dispatch)) + ;; (orderless-component-separator #'orderless-escapable-split-on-space) + (completion-styles '(orderless basic)) + (completion-category-overrides '((file (styles partial-completion)))) + (completion-category-defaults nil) ;; Disable defaults, use our settings + (completion-pcm-leading-wildcard t) ;; Emacs 31: partial-completion behaves like substring + ) + +(use-package marginalia + :ensure t + :init + (marginalia-mode) + ) + +(use-package emacs + :custom + ;; Enable context menu. `vertico-multiform-mode' adds a menu in the minibuffer + ;; to switch display modes. + (context-menu-mode t) + ;; Support opening new minibuffers from inside existing minibuffers. + (enable-recursive-minibuffers t) + ;; Hide commands in M-x which do not work in the current mode. Vertico + ;; commands are hidden in normal buffers. This setting is useful beyond + ;; Vertico. + (read-extended-command-predicate #'command-completion-default-include-p) + ;; Do not allow the cursor in the minibuffer prompt + (minibuffer-prompt-properties + '(read-only t cursor-intangible t face minibuffer-prompt))) + +(use-package consult ;; https://github.com/minad/consult + :ensure t + :bind (("C-x b" . consult-buffer) ;; Fuzzy find open buffers, recents, & bookmarks + ("M-y" . consult-yank-pop) ;; Better paste history + ("M-s r" . consult-ripgrep) ;; Search text INSIDE all your files + ("M-g g" . consult-goto-line))) + +;; Interaction & tools + +(use-package evil + :ensure t + :init + (setq evil-shift-width 2) + :config + (evil-mode 1) + (with-eval-after-load 'evil-maps (define-key evil-motion-state-map (kbd "TAB") nil)) + ) + +(use-package pdf-tools ;; https://github.com/vedang/pdf-tools + :ensure t + :custom + (pdf-util-convert-program "magick") ;; "The pdf-util-convert-program is unset or non-executable" + (pdf-view-incompatible-modes nil) ;; Silences the annoying warning popup + :init + (add-hook 'pdf-view-mode-hook (lambda () (display-line-numbers-mode -1))) + (add-hook 'pdf-view-mode-hook (lambda () (blink-cursor-mode -1))) + :config + (pdf-loader-install) + ) + +(use-package olivetti + :ensure t + ) ;; Activate with M-x olivetti-mode + +(use-package auto-dark + :ensure t + :custom + (auto-dark-themes '((modus-vivendi) (modus-operandi))) + :hook + (auto-dark-dark-mode + . (lambda () + (pdf-view-midnight-minor-mode 1) + )) + (auto-dark-light-mode + . (lambda () + ;; something to execute when light mode is detected + (pdf-view-midnight-minor-mode -1) + )) + :init + (auto-dark-mode) + ) + +;; TODO Make M-x also fuzzy +;; TODO Make Find file fuzzy +;; TODO Save file search history across sessions + +;; TODO Clicking links shows the content of that link in the adjacent pane. Often there is a PDF in that pane. I would like to choose to open links in the current pane instead. Idk, is Shift+Click or some actual keybind possible? Also, what is the current keybind for following links using key strokes? +;; TODO Is there some quicker way to switch between buffers, other than using the Buffer tab in the Menu bar, or :b with matching? + +;; TODO org-roam stores everything with a prefix. Is there a way to disable that or not? +;; TODO Put exports in their own directory? (now filename-prefix.pdf) +;; TODO Put dailies in "journals" instead of "daily" +;; TODO I store my lecture PDFs in ~/Nextcloud/Documents/UGent//theory/*.pdf, is there some way to make a shortcut for this (related to Fuzzy finding files etc.). Maybe consider integrating with Zotero and storing PDFs there? + +;; Additional package to explore +;; TODO https://magit.vc/ <-> Nextcloud WebDAV? What about mobile? FolderSync seems unreliable (currently using for LogSeq, often reports failures without actually being recently modified files.) I have my own Git server, but what about keys - I don't really like just making new keysets for this..? + +;; Turn on Auto Fill mode automatically in Text mode and related modes (see Hooks). +;; TODO (add-hook 'text-mode-hook 'auto-fill-mode) +;; Do I want this? + +;; TODO Automatically save buffer when going to other file -- maybe interactively? +;; TODO Spellchecking (UK & Dutch) + +;; TODO Some automation to create anki cards intext without having to write the boilerplate +;; TODO Currently, failing exports (latexmk) just show that something has gone wrong. I have to run the command manually to see the output. Is there some log buffer or something? + +;; TODO Is there some way to split the "org-mode/org-roam" environment from the rest of the config? Say that I want to use this for editing programming languages in the future too? + +;; TODO I was thinking of syncing (1-way) Org TO-DO's to CalDav (Nextcloud), new calendar, so I can quickly see them in my tasklist. (https://github.com/dengste/org-caldav) + +;; TODO Finally, compare experience to organice https://organice.200ok.ch/ + +;; TODO Remember collapse states in files diff --git a/notetaking/modules/my-org.el b/notetaking/modules/my-org.el new file mode 100644 index 0000000..93beabd --- /dev/null +++ b/notetaking/modules/my-org.el @@ -0,0 +1,124 @@ +;; -*- lexical-binding: t; -*- + +(defvar my-org-roam-base-dir (file-truename "~/Nextcloud/Documenten/Persoonlijk/org-roam") + "Base directory for Org-roam and related assets.") +(make-directory (expand-file-name "assets" my-org-roam-base-dir) t) +(make-directory (expand-file-name "dailies" my-org-roam-base-dir) t) +(make-directory (expand-file-name "notes" my-org-roam-base-dir) t) + +;; Display rules + +(add-to-list 'display-buffer-alist + '("\\.pdf'" + (display-buffer-in-direction) + (direction . left) + (window-width . 0.5))) ;; Force PDF to left half + +;; Knowledge + +(use-package org + :init + (add-hook 'org-mode-hook 'visual-line-mode) ;; Make text wrap in org mode + (add-hook 'org-mode-hook (lambda () (display-line-numbers-mode -1))) ;; Hide line numbers in org mode + :custom + (org-hide-emphasis-markers t) ;; Required for org-appear to work + (org-pretty-entities t) + (org-image-actual-width nil) ;; Allows resizing images + (org-link-window-setup 'current-window) ;; Force links to open in the current window + (org-startup-folded 'showall) ;; https://orgmode.org/manual/Initial-visibility.html + :config + (setq org-latex-compiler "lualatex") + (setq org-link-frame-setup + '((vm . vm-visit-folder-other-frame) + (vm-mail . vm-mail-other-frame) + (gnus . org-gnus-no-new-news) + (file . find-file) + (wl . wl-other-frame))) + (setq org-todo-keywords + '((sequence "TODO" "DOING" "|" "DONE" "SKIPPED"))) + ) ;; TODO How to configure keybinds from below? + ;; Keybinds + ;(global-set-key (kbd "C-c a") #'org-agenda) + ;(global-set-key (kbd "C-c c") #'org-capture) + +(use-package org-roam + :ensure t + :custom + (org-roam-directory my-org-roam-base-dir) + (org-roam-dailies-directory "dailies/") + (org-roam-completion-everywhere t) + :bind ( + ("C-c r f" . org-roam-node-find) + ("C-c r j" . org-roam-dailies-capture-today) + ("C-c r t" . org-roam-dailies-goto-today) + ) + :init + (setq org-roam-mode-sections ;; https://www.orgroam.com/manual.html#Configuring-what-is-displayed-in-the-buffer-1 + (list #'org-roam-backlinks-section + #'org-roam-reflinks-section + #'org-roam-unlinked-references-section + ) + ) + :config + (org-roam-setup) + (org-roam-db-autosync-mode) + + (setq org-roam-capture-templates + '(("d" "default" plan "%?" + :target (file+head "notes/%<%Y%m%d%H%M%S>-${slug}.org" + "#+title: ${title}\n") + :unnarrowed t)) + ) + + (add-to-list 'display-buffer-alist + '("\\*org-roam\\*" + (display-buffer-in-direction) + (direction . right) + (window-width . 0.33) + (window-height . fit-window-to-buffer) + ) + ) ;; Open backlinks on the right. + ) + +(use-package org-download + :ensure t + :after org + :custom + (org-download-method 'directory) + (org-download-image-dir (expand-file-name "assets" my-org-roam-base-dir)) + (org-download-heading-lvl nil) + (org-download-timestamp "org_%Y%m%d-%H%M%S_") + (org-startup-with-inline-images t) + :bind + ("C-c i" . org-download-clipboard) + ) + +;; Prettifying + +;(use-package org-appear + ;:ensure t + ;:hook (org-mode . org-appear-mode)) + +;(use-package org-fragtog + ;:ensure t + ;:hook (org-mode . org-fragtog-mode)) + +(use-package org-appear + :ensure t + :hook (org-mode . org-appear-mode) + :custom + (org-appear-trigger 'manual) + :config + (add-hook 'org-mode-hook + (lambda () + (add-hook 'evil-insert-state-entry-hook #'org-appear-manual-start nil t) + (add-hook 'evil-insert-state-exit-hook #'org-appear-manual-stop nil t)))) + +(use-package org-fragtog + :ensure t + :hook (org-mode . org-fragtog-mode) + :config + (add-hook 'org-mode-hook + (lambda () + (add-hook 'evil-insert-state-entry-hook (lambda () (org-fragtog-mode -1)) nil t) + (add-hook 'evil-insert-state-exit-hook (lambda () (org-fragtog-mode 1)) nil t))))