From 5a4a604487016f457ed687ac2603fe4f822b127e Mon Sep 17 00:00:00 2001 From: Emmet Date: Wed, 10 May 2023 21:10:52 -0500 Subject: [PATCH] Trying nix-doom-emacs --- user/app/doom-emacs/arch.png | Bin 0 -> 21161 bytes user/app/doom-emacs/config.el | 965 ++++++++++ user/app/doom-emacs/doom.org | 1563 +++++++++++++++++ user/app/doom-emacs/init.el | 175 ++ user/app/doom-emacs/packages.el | 21 + .../copy-link-or-file-to-clipboard.sh | 10 + .../scripts/ox-odp/ox-odp-xml-parse.py | 157 ++ user/app/doom-emacs/scripts/ox-odp/ox-odp.sh | 47 + user/home.nix | 18 +- 9 files changed, 2943 insertions(+), 13 deletions(-) create mode 100644 user/app/doom-emacs/arch.png create mode 100644 user/app/doom-emacs/config.el create mode 100644 user/app/doom-emacs/doom.org create mode 100644 user/app/doom-emacs/init.el create mode 100644 user/app/doom-emacs/packages.el create mode 100755 user/app/doom-emacs/scripts/copy-link-or-file/copy-link-or-file-to-clipboard.sh create mode 100755 user/app/doom-emacs/scripts/ox-odp/ox-odp-xml-parse.py create mode 100755 user/app/doom-emacs/scripts/ox-odp/ox-odp.sh diff --git a/user/app/doom-emacs/arch.png b/user/app/doom-emacs/arch.png new file mode 100644 index 0000000000000000000000000000000000000000..6f90b4be390047e94e7a3f30d94c77a3272dee93 GIT binary patch literal 21161 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 YB)$7BkjlISxG#^v)78&qol`;+0RFU*!~g&Q literal 0 HcmV?d00001 diff --git a/user/app/doom-emacs/config.el b/user/app/doom-emacs/config.el new file mode 100644 index 00000000..a3dac0a5 --- /dev/null +++ b/user/app/doom-emacs/config.el @@ -0,0 +1,965 @@ +;;; $DOOMDIR/config.el -*- lexical-binding: t; -*- + +;;;------ User configuration ------;;; + +;; My default user identity as my yt alias +(setq user-full-name "librephoenix") + +;; I prefer visual lines +(setq display-line-numbers-type 'visual + line-move-visual t) +(use-package-hook! evil + :pre-init + (setq evil-respect-visual-line-mode t) ;; sane j and k behavior + t) + +;; I also like evil mode visual movement +(map! :map evil-normal-state-map + :desc "Move to next visual line" + "j" 'evil-next-visual-line + :desc "Move to previous visual line" + "k" 'evil-previous-visual-line) + +;; Theme and font +(setq doom-theme 'doom-old-hope) +(setq doom-font (font-spec :family "Inconsolata" :size 20)) + +;; Transparent background +(set-frame-parameter (selected-frame) 'alpha '(90 . 90)) +(add-to-list 'default-frame-alist '(alpha . (90 . 90))) + +;; Icons in completion buffers +(add-hook 'marginalia-mode-hook #'all-the-icons-completion-marginalia-setup) +(all-the-icons-completion-mode) + +;; This makes non-main buffers dimmer, so you can focus on main buffers +(solaire-global-mode +1) + +;; Grammar tasing should be voluntary +(setq writegood-mode nil) + +;; Beacon shows where the cursor is, even when fast scrolling +(setq beacon-mode t) + +;; Quicker window management keybindings +(bind-key* "C-j" #'evil-window-down) +(bind-key* "C-k" #'evil-window-up) +(bind-key* "C-h" #'evil-window-left) +(bind-key* "C-l" #'evil-window-right) +(bind-key* "C-q" #'evil-window-delete) + +;; Mouse buffer management +(bind-key* "" #'previous-buffer) +(bind-key* "" #'next-buffer) + +;; Disables custom.el +(setq custom-file null-device) + +;; Fancy splash image +(setq fancy-splash-image "~/.doom.d/arch.png") + +(setq +doom-dashboard-menu-sections +'(("Open org roam overview" :icon + (all-the-icons-octicon "globe" :face 'doom-dashboard-menu-title) + :face + (:inherit + (doom-dashboard-menu-title bold)) + :action org-roam-default-overview) + ("Roam to another db" :icon + (all-the-icons-fileicon "org" :face 'doom-dashboard-menu-title) + :action org-roam-switch-db) + ("Open agenda" :icon + (all-the-icons-octicon "calendar" :face 'doom-dashboard-menu-title) + :when + (fboundp 'org-agenda) + :action org-agenda-list + :key "SPC o A a") + ("Open private configuration" :icon + (all-the-icons-octicon "tools" :face 'doom-dashboard-menu-title) + :when + (file-directory-p doom-user-dir) + :action doom/open-private-config) + ("Open documentation" :icon + (all-the-icons-octicon "book" :face 'doom-dashboard-menu-title) + :action doom/help) + ("Quit emacs" :icon + (all-the-icons-faicon "level-down" :face 'doom-dashboard-menu-title) + :action save-buffers-kill-terminal) + ) +) + +;; Requires for faster loading +(require 'org-agenda) +(require 'dired) + +;; Garbage collection to speed things up +(add-hook 'after-init-hook + #'(lambda () + (setq gc-cons-threshold (* 100 1000 1000)))) +(add-hook 'focus-out-hook 'garbage-collect) +(run-with-idle-timer 5 t 'garbage-collect) + +;; Enable autorevert globally so that buffers update when files change on disk. +;; Very useful when used with file syncing (i.e. syncthing) +(setq global-auto-revert-mode nil) +(setq auto-revert-use-notify t) + +;;;------ Registers ------;;; + +(map! :leader + :desc "Jump to register" + "r" 'jump-to-register) + +(set-register ?f '(file . "/home/librephoenix/Org/Family.s/Notes/hledger.org")) +(set-register ?r '(file . "/home/librephoenix/README.org")) +(set-register ?d '(file . "/home/librephoenix/.doom.d/doom.org")) +(set-register ?h '(file . "/home/librephoenix")) +(set-register ?x '(file . "/home/librephoenix/.xmonad/xmonad.org")) +(set-register ?s '(file . "/home/librephoenix/.install/install.org")) + +;;;------ Org mode configuration ------;;; + +;; Set default org directory +(setq org-directory "~/.Org") + +(remove-hook 'after-save-hook #'+literate|recompile-maybe) +(set-company-backend! 'org-mode nil) + +;; Automatically show images but manually control their size +(setq org-startup-with-inline-images t + org-image-actual-width nil) + +;; Top-level headings should be bigger! +(custom-set-faces! + '(org-level-1 :inherit outline-1 :height 1.3) + '(org-level-2 :inherit outline-2 :height 1.25) + '(org-level-3 :inherit outline-3 :height 1.2) + '(org-level-4 :inherit outline-4 :height 1.1) + '(org-level-5 :inherit outline-5 :height 1.1) + '(org-level-6 :inherit outline-6 :height 1.05) + '(org-level-7 :inherit outline-7 :height 1.05) + ) + +;(custom-set-faces! +; '(org-link :foreground nil)) + +;; Pretty org bullets +;;(use-package org-bullets +;; :ensure t +;; :init +;; (add-hook 'org-mode-hook (lambda () +;; (org-bullets-mode 1)))) + +(with-eval-after-load 'org (global-org-modern-mode)) + +;; Add frame borders and window dividers +(modify-all-frames-parameters + '((right-divider-width . 10) + (internal-border-width . 10))) +(dolist (face '(window-divider + window-divider-first-pixel + window-divider-last-pixel)) + (face-spec-reset-face face) + (set-face-foreground face (face-attribute 'default :background))) +(set-face-background 'fringe (face-attribute 'default :background)) + +(setq + ;; Edit settings + org-auto-align-tags nil + org-tags-column 0 + org-catch-invisible-edits 'show-and-error + org-special-ctrl-a/e t + org-insert-heading-respect-content t + + ;; Org styling, hide markup etc. + org-hide-emphasis-markers t + org-pretty-entities t + org-ellipsis "…") + +(setq-default line-spacing 0.1) + +; Automatic table of contents is nice +(if (require 'toc-org nil t) + (progn + (add-hook 'org-mode-hook 'toc-org-mode) + (add-hook 'markdown-mode-hook 'toc-org-mode)) + (warn "toc-org not found")) + +;;---- this block from http://fgiasson.com/blog/index.php/2016/06/21/optimal-emacs-settings-for-org-mode-for-literate-programming/ ----;; +;; Tangle Org files when we save them +(defun tangle-on-save-org-mode-file() + (when (string= (message "%s" major-mode) "org-mode") + (org-babel-tangle))) + +(add-hook 'after-save-hook 'tangle-on-save-org-mode-file) +;; ---- end block ---- ;; + +;; Better org table editing +(setq-default evil-insert-state-exit-hook '(org-update-parent-todo-statistics + t)) +(setq org-table-automatic-realign nil) + +;; Better for org source blocks +(setq electric-indent-mode nil) +(setq org-src-window-setup 'current-window) +(delete + '("^\\*Org Src" + (+popup-buffer) + (actions) + (side . bottom) + (size . 0.42) + (window-width . 40) + (window-height . 0.42) + (slot) + (vslot) + (window-parameters + (ttl) + (quit) + (select . t) + (modeline . t) + (autosave . t) + (transient . t) + (no-other-window . t))) + display-buffer-alist) + +(require 'org-download) + +;; Drag-and-drop to `dired` +(add-hook 'dired-mode-hook 'org-download-enable) + +(setq org-download-screenshot-method "flameshot gui -p %s") +(after! org-download + (setq org-download-method 'directory)) + +(after! org + (setq-default org-download-image-dir "img/" + org-download-heading-lvl nil)) + +(defun my-org-screenshot () + "Take a screenshot into a time stamped unique-named file in the +same directory as the org-buffer and insert a link to this file." + (interactive) + (setq filename + (concat + (make-temp-name + (concat (buffer-file-name) + "_" + (format-time-string "%Y%m%d_%H%M%S_")) ) ".png")) + (shell-command (concat "emacs-wayshot " filename)) + (insert (concat "[[" filename "]]")) + (org-display-inline-images)) + +(defun my-org-paste() + "Take an image from the clipboard into a time stamped unique-named file in the +same directory as the org-buffer and insert a link to this file." + (interactive) + (setq filename + (concat + (make-temp-name + (concat (file-name-directory (buffer-file-name)) + "img/" + (file-name-nondirectory (buffer-file-name)) + "_" + (format-time-string "%Y%m%d_%H%M%S_")) ) ".png")) + (shell-command (concat "wl-paste > " filename)) + (insert (concat "[[" filename "]]")) + (org-display-inline-images)) + +(defun my-org-new-file-from-template() + "Copy a template from ~/Templates into a time stamped unique-named file in the +same directory as the org-buffer and insert a link to this file." + (interactive) + (setq template-file (completing-read "Template file:" (directory-files "~/Templates"))) + (setq filename + (concat + (make-temp-name + (concat (file-name-directory (buffer-file-name)) + "files/" + (file-name-nondirectory (buffer-file-name)) + "_" + (format-time-string "%Y%m%d_%H%M%S_")) ) (file-name-extension template-file t))) + (copy-file (concat "/home/librephoenix/Templates/" template-file) filename) + (setq prettyname (read-from-minibuffer "Pretty name:")) + (insert (concat "[[./files/" (file-name-nondirectory filename) "][" prettyname "]]")) + (org-display-inline-images)) + +(when (require 'openwith nil 'noerror) + (setq openwith-associations + (list + (list (openwith-make-extension-regexp + '("mpg" "mpeg" "mp3" "mp4" + "avi" "wmv" "wav" "mov" "flv" + "ogm" "ogg" "mkv")) + "mpv" + '(file)) + (list (openwith-make-extension-regexp + '("doc" "xls" "ppt" "odt" "ods" "odg" "odp")) + "libreoffice" + '(file)) + '("\\.lyx" "lyx" (file)) + '("\\.chm" "kchmviewer" (file)) + (list (openwith-make-extension-regexp + '("pdf" "ps" "ps.gz" "dvi")) + "atril" + '(file)) + (list (openwith-make-extension-regexp + '("kdenlive")) + "kdenlive" + '(file)) + (list (openwith-make-extension-regexp + '("kra")) + "krita" + '(file)) + (list (openwith-make-extension-regexp + '("blend" "blend1")) + "blender" + '(file)) + (list (openwith-make-extension-regexp + '("helio")) + "helio" + '(file)) + (list (openwith-make-extension-regexp + '("svg")) + "inkscape" + '(file)) + (list (openwith-make-extension-regexp + '("flp")) + "~/.local/bin/flstudio" + '(file)) + )) + (openwith-mode 1)) + +(add-to-list 'display-buffer-alist '("^*Async Shell Command*" . (display-buffer-no-window))) + +(map! :leader + :desc "Insert a screenshot" +;; "i s" 'my-org-screenshot) + "i s" 'org-download-screenshot) + +(defun org-download-clipboard-basename () + (interactive) + (setq org-download-path-last-dir org-download-image-dir) + (setq org-download-image-dir (completing-read "directory: " (-filter #'f-directory-p (directory-files-recursively "." "" t)) nil t)) + (org-download-clipboard (completing-read "basename: " '() nil nil)) + (setq org-download-image-dir org-download-path-last-dir) +) + +(map! :leader + :desc "Insert image from clipboard" + "i p" 'org-download-clipboard + "i P" 'org-download-clipboard-basename) + +(map! :leader + :desc "Create a new file from a template and insert a link at point" + "i t" 'my-org-new-file-from-template) + +(defun org-copy-link-to-clipboard-at-point () + "Copy current link at point into clipboard (useful for images and links)" + (interactive) + (if (eq major-mode #'org-mode) + (link-hint-copy-link-at-point) + ) + (if (eq major-mode #'ranger-mode) + (ranger-copy-absolute-file-paths) + ) + (if (eq major-mode #'image-mode) + (image-mode-copy-file-name-as-kill) + ) + (shell-command (concat "~/.doom.d/scripts/copy-link-or-file/copy-link-or-file-to-clipboard.sh " (gui-get-selection 'CLIPBOARD)) nil nil) +) + +(map! :leader + :desc "Copy link/file at point into system clipbord (C-g to escape if copying a file)" + "y y" 'org-copy-link-to-clipboard-at-point) + +;; Online images inside of org mode is pretty cool +;; This snippit is from Tobias on Stack Exchange +;; https://emacs.stackexchange.com/questions/42281/org-mode-is-it-possible-to-display-online-images +(require 'org-yt) + +(defun org-image-link (protocol link _description) + "Interpret LINK as base64-encoded image data." + (cl-assert (string-match "\\`img" protocol) nil + "Expected protocol type starting with img") + (let ((buf (url-retrieve-synchronously (concat (substring protocol 3) ":" link)))) + (cl-assert buf nil + "Download of image \"%s\" failed." link) + (with-current-buffer buf + (goto-char (point-min)) + (re-search-forward "\r?\n\r?\n") + (buffer-substring-no-properties (point) (point-max))))) + +(org-link-set-parameters + "imghttp" + :image-data-fun #'org-image-link) + +(org-link-set-parameters + "imghttps" + :image-data-fun #'org-image-link) + +;; Mermaid diagrams +(setq ob-mermaid-cli-path "/usr/bin/mmdc") + +;; Print org mode +(defun org-simple-print-buffer () + "Open an htmlized form of current buffer and open in a web browser to print" + (interactive) + (htmlize-buffer) + (browse-url-of-buffer (concat (buffer-name) ".html")) + (sleep-for 1) + (kill-buffer (concat (buffer-name) ".html"))) + +;; Doesn't work yet, bc htmlize-region takes arguments BEG and END +;(defun org-simple-print-region() +; "Open an htmlized form of current region and open in a web browser to print" +; (interactive) +; (htmlize-region ) +; (browse-url-of-buffer (concat (buffer-name) ".html")) +; (sleep-for 1) +; (kill-buffer (concat (buffer-name) ".html"))) + +(map! :leader + :prefix ("P" . "Print") + :desc "Simple print buffer in web browser" + "p" 'org-simple-print-buffer) + +(map! :leader + :prefix ("P" . "Print") + :desc "Simple print buffer in web browser" + "b" 'org-simple-print-buffer) + +;(map! :leader +; :prefix ("P" . "Print") +; :desc "Simple print region in web browser" +; "r" 'org-simple-print-region) + +;; Custom function to convert org mode to ODP presentation +;; Depends on bash, libreoffice, and pandoc +(defun my-ox-odp () + "Convert an org mode file to an ODP presentation." + (interactive) + (setq file-name (buffer-file-name)) + (setq output-pptx-file-name (replace-regexp-in-string "\.org" "\.pptx" (buffer-file-name))) + (setq output-odp-file-name (replace-regexp-in-string "\.org" "\.odp" (buffer-file-name))) + (setq odp-style-file-name (completing-read "Choose style: " + '("/home/librephoenix/.doom.d/scripts/ox-odp/styles/water.odp" + "/home/librephoenix/.doom.d/scripts/ox-odp/styles/dark.odp" + ) nil t)) + (shell-command (concat "~/.doom.d/scripts/ox-odp/ox-odp.sh \"" (buffer-file-name) "\" \"" odp-style-file-name "\" > /dev/null")) + ) + +(map! :leader + :desc "Convert org document to odp presentation" + "e p" 'my-ox-odp) + +;;;------ Org roam configuration ------;;; + +(require 'org-roam) +(require 'org-roam-dailies) + +(setq org-roam-directory "~/Org/Personal/Notes" + org-roam-db-location "~/Org/Personal/Notes/org-roam.db") + +(setq org-roam-node-display-template + "${title:65}📝${tags:*}") + +(org-roam-db-autosync-mode) + +(setq full-org-roam-db-list nil) + +(setq full-org-roam-db-list (directory-files "~/Org" t "\\.[p,s]$")) +(dolist (item full-org-roam-db-list) + (setq full-org-roam-db-list + (append (directory-files item t "\\.[p,s]$") full-org-roam-db-list))) + +(setq org-roam-db-choice "Default") +(setq full-org-roam-db-list-pretty (list "Default")) +(dolist (item full-org-roam-db-list) + (setq full-org-roam-db-list-pretty + (append (list + (replace-regexp-in-string "\\/home\\/librephoenix\\/Org\\/" "" item)) full-org-roam-db-list-pretty))) + +(defun org-roam-open-dashboard () + "Open ${org-roam-directory}/dashboard.org (I use this naming convention to create dashboards for each of my org roam maps)" + (interactive) + (if (file-exists-p (concat org-roam-directory "/dashboard.org")) + (org-open-file (concat org-roam-directory "/dashboard.org")) + (dired org-roam-directory)) +) + +(defun org-roam-switch-db (&optional arg silent) + "Switch to a different org-roam database, arg" + (interactive) + (when (not arg) + (setq full-org-roam-db-list nil) + + (setq full-org-roam-db-list (directory-files "~/Org" t "\\.[p,s]$")) + (dolist (item full-org-roam-db-list) + (setq full-org-roam-db-list + (append (directory-files item t "\\.[p,s]$") full-org-roam-db-list))) + + (setq full-org-roam-db-list-pretty (list "Default")) + (dolist (item full-org-roam-db-list) + (setq full-org-roam-db-list-pretty + (append (list + (replace-regexp-in-string "\\/home\\/librephoenix\\/Org\\/" "" item)) full-org-roam-db-list-pretty))) + + (setq org-roam-db-choice (completing-read "Select org roam database: " + full-org-roam-db-list-pretty nil t))) + (when arg + (setq org-roam-db-choice arg)) + + (if (string= org-roam-db-choice "Default") + (setq org-roam-directory (file-truename "~/Org/Personal/Notes") + org-roam-db-location (file-truename "~/Org/Personal/Notes/org-roam.db") + org-directory (file-truename"~/Org/Personal/Notes")) + (setq org-roam-directory (file-truename (concat "~/Org/" org-roam-db-choice "/Notes")) + org-roam-db-location (file-truename (concat "~/Org/" org-roam-db-choice "/Notes/org-roam.db")) + org-directory (file-truename (concat "~/Org/" org-roam-db-choice "/Notes")))) + (when (not silent) + (org-roam-open-dashboard)) + + (org-roam-db-sync) + + (message (concat "Switched to " org-roam-db-choice " org-roam database!"))) + +(defun org-roam-default-overview () + (interactive) + (org-roam-switch-db "Default")) + +(defun org-roam-switch-db-id-open (arg ID &optional switchpersist) + "Switch to another org-roam db and visit file with id arg" + "If switchpersist is non-nil, stay in the new org-roam db after visiting file" + (interactive) + (setq prev-org-roam-db-choice org-roam-db-choice) + (org-roam-switch-db arg 1) + (org-roam-id-open ID) + (when (not switchpersist) + (org-roam-switch-db prev-org-roam-db-choice 1))) + +;;;------ Org-roam-agenda configuration ------;;; +(defun text-in-buffer-p (TEXT) +(save-excursion (goto-char (point-min)) (search-forward TEXT nil t))) + +(defun apply-old-todos-tag-maybe (&optional FILE) + (interactive) + (if (stringp FILE) + (setq the-daily-node-filename FILE) + (setq the-daily-node-filename buffer-file-name)) + (if (org-roam-dailies--daily-note-p the-daily-node-filename) + (if (<= (nth 2 (org-roam-dailies-calendar--file-to-date the-daily-node-filename)) (nth 2 org-agenda-current-date)) + (if (<= (nth 1 (org-roam-dailies-calendar--file-to-date the-daily-node-filename)) (nth 1 org-agenda-current-date)) + (if (<= (nth 0 (org-roam-dailies-calendar--file-to-date the-daily-node-filename)) (nth 0 org-agenda-current-date)) + (funcall (lambda () + (with-current-buffer (get-file-buffer the-daily-node-filename) (org-roam-tag-add '("old-todos"))) + (with-current-buffer (get-file-buffer the-daily-node-filename) (org-roam-tag-remove '("todos"))) + ) + ) + ) + ) + ) + ) +) + +(defun apply-old-todos-tag-maybe-and-save (FILE) + (interactive) + (find-file-noselect FILE) + (apply-old-todos-tag-maybe FILE) + (with-current-buffer (get-file-buffer the-daily-node-filename) (save-buffer)) + (with-current-buffer (get-file-buffer the-daily-node-filename) (kill-buffer)) +) + +; This has a bug where it won't sync a new agenda file +; if I'm editing an org roam node file while set to another +; org roam db +(defun add-todos-tag-on-save-org-mode-file() + (interactive) + (when (string= (message "%s" major-mode) "org-mode") + (if (org-roam-node-p (org-roam-node-at-point)) + (funcall (lambda() + (if (or (text-in-buffer-p "SCHEDULED: <") (text-in-buffer-p "DEADLINE: <")) + (org-roam-tag-add '("todos")) + (org-roam-tag-remove '("todos")) + ) + (apply-old-todos-tag-maybe) + ) + ) + ) + ) +) + +(add-hook 'before-save-hook 'add-todos-tag-on-save-org-mode-file) + +(defun org-roam-filter-by-tag (tag-name) + (lambda (node) + (member tag-name (org-roam-node-tags node)))) + +(defun org-roam-list-notes-by-tag (tag-name) + (mapcar #'org-roam-node-file + (seq-filter + (org-roam-filter-by-tag tag-name) + (org-roam-node-list)))) + +(defun org-roam-dailies-apply-old-todos-tags-to-all () +; (dolist (daily-node org-roam-dailies-files) +; (apply-old-todos-tag-maybe-and-save daily-node) +; ) + (setq num 0) + (while (< num (list-length (org-roam-list-notes-by-tag "todos"))) + (apply-old-todos-tag-maybe-and-save (nth num (org-roam-list-notes-by-tag "todos"))) + (setq num (1+ num)) + ) +) + +(defun org-roam-append-notes-to-agenda (tag-name db) + (org-roam-switch-db db t) +; (org-roam-dailies-apply-old-todos-tags-to-all) + (setq org-agenda-files (append org-agenda-files (org-roam-list-notes-by-tag "todos"))) +) + +(defun org-roam-refresh-agenda-list () + (interactive) + (setq prev-org-roam-db-choice org-roam-db-choice) + (setq org-agenda-files '()) + (dolist (DB full-org-roam-db-list-pretty) + (org-roam-append-notes-to-agenda "todos" DB) + ) + (org-roam-switch-db prev-org-roam-db-choice 1) +) + +;; Build agenda for first time during this session +(org-roam-refresh-agenda-list) + +(map! :leader + :prefix ("N" . "org-roam notes") + + :desc "Capture new roam node" + "c" 'org-roam-capture + + :desc "Insert roam node link at point" + "i" 'org-roam-node-insert + + :desc "Find roam node" + "." 'org-roam-node-find + + :desc "Switch org-roam database" + "s" 'org-roam-switch-db + + :desc "Update current org-roam database" + "u" 'org-roam-db-sync + + :desc "Re-zoom on current node in org-roam-ui" + "z" 'org-roam-ui-node-zoom + + :desc "Visualize org-roam database with org-roam-ui" + "O" 'org-roam-default-overview + + :desc "Visualize org-roam database with org-roam-ui" + "o" 'org-roam-open-dashboard) + +(after! org-roam + (setq org-roam-capture-templates + '(("d" "default" plain "%?" :target + (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n") + :unnarrowed t)))) + +(defun org-roam-olivetti-mode () + (interactive) + (if (org-roam-file-p) + (olivetti-mode)) + (if (org-roam-file-p) + (doom-disable-line-numbers-h))) + +(add-hook 'org-mode-hook 'org-roam-olivetti-mode) + +(use-package org-roam-dblocks + :hook (org-mode . org-roam-dblocks-autoupdate-mode)) + +(setq org-id-extra-files 'org-agenda-text-search-extra-files) + +;(add-to-list 'display-buffer-alist '("^\\ORUI" display-buffer-in-side-window +; '(side . right) +; (window-width . 50) +;)) +;(add-to-list 'display-buffer-alist '("^\\localhost:35901" display-buffer-in-side-window +; '(side . right) +; (window-width . 50) +;)) + +(defun open-org-roam-ui () + (interactive) + (+evil/window-vsplit-and-follow) + (org-roam-ui-open) + (evil-window-left)) + +(defun kill-org-roam-ui () + (interactive) + (delete-window (get-buffer-window "ORUI" t)) + (kill-buffer "ORUI") + (kill-buffer "*httpd*") +) + +(map! :leader + :prefix ("N" . "org-roam notes") + :desc "Visualize org-roam database with org-roam-ui" + "v" 'open-org-roam-ui) + +(map! :leader + :prefix ("N" . "org-roam notes") + :desc "Kill all org roam ui buffers" + "V" 'kill-org-roam-ui) + +;;;------ Org agenda configuration ------;;; + +;; Set span for agenda +(setq org-agenda-span 1 + org-agenda-start-day "+0d") + +;; Ricing org agenda +(setq org-agenda-current-time-string "") +(setq org-agenda-time-grid '((daily) () "" "")) + +(setq org-agenda-prefix-format '( +(agenda . " %?-2i %t ") + (todo . " %i %-12:c") + (tags . " %i %-12:c") + (search . " %i %-12:c"))) + +(setq org-agenda-hide-tags-regexp ".*") + +(setq org-agenda-category-icon-alist + `(("Teaching" ,(list (all-the-icons-faicon "graduation-cap" :height 0.8)) nil nil :ascent center) + ("Family" ,(list (all-the-icons-faicon "home" :v-adjust 0.005)) nil nil :ascent center) + ("Producer" ,(list (all-the-icons-faicon "youtube-play" :height 0.9)) nil nil :ascent center) + ("Bard" ,(list (all-the-icons-faicon "music" :height 0.9)) nil nil :ascent center) + ("Story" ,(list (all-the-icons-faicon "book" :height 0.9)) nil nil :ascent center) + ("Author" ,(list (all-the-icons-faicon "pencil" :height 0.9)) nil nil :ascent center) + ("Gamedev" ,(list (all-the-icons-faicon "gamepad" :height 0.9)) nil nil :ascent center) + ("Tech" ,(list (all-the-icons-faicon "laptop" :height 0.9)) nil nil :ascent center) +)) + +;; Function to be run when org-agenda is opened +(defun org-agenda-open-hook () + "Hook to be run when org-agenda is opened" + (olivetti-mode)) + +;; Adds hook to org agenda mode, making follow mode active in org agenda +(add-hook 'org-agenda-mode-hook 'org-agenda-open-hook) + +;; Function to list all my available org agenda files and switch to them +(defun list-and-switch-to-agenda-file () + "Lists all available agenda files and switches to desired one" + (interactive) + (setq full-agenda-file-list nil) + (setq choice (completing-read "Select agenda file:" org-agenda-files nil t)) + (find-file choice)) + +(map! :leader + :desc "Switch to specific org agenda file" + "o a s" 'list-and-switch-to-agenda-file) + +(map! :leader + :desc "Open org calendar" + "o c" #'cfw:open-org-calendar) + +(require 'org-super-agenda) + +(setq org-super-agenda-groups + '(;; Each group has an implicit boolean OR operator between its selectors. + (:name "Home Tech" + :and(:file-path "librephoenix/Agenda" :not (:tag "event")) + :order 3) + + (:name "Family" + :and(:file-path "Family" :not (:tag "event")) + :order 3) + + (:name "Teaching Prep" + :and(:file-path "Teaching.p" :tag "planning" :not (:tag "grading") :not (:tag "event")) + :order 3) + + (:name "Teaching Secretarial" + :and(:file-path "Teaching.p" :tag "secretarial" :not (:tag "grading") :not (:tag "event")) + :order 3) + + (:name "Teaching Grading" + :and(:file-path "Teaching.p" :tag "grading" :not (:tag "planning") :not (:tag "event")) + :order 3) + + (:name "School Side Projects" + :and(:file-path "Teaching.p" :tag "tech" :not (:tag "planning") :not (:tag "event")) + :order 3) + + (:name "Gamedev Current Projects" + :and (:file-path "Gamedev" :todo "STRT") + :order 5) + + (:name "Youtube" + :tag "youtube" + :order 6) + + (:name "Learning" + :tag "learning" + :order 7) + + (:name "Today" ; Optionally specify section name + :time-grid t + :date today + :scheduled today + :order 1) +)) + +(org-super-agenda-mode t) + +(map! :desc "Next line" + :map org-super-agenda-header-map + "j" 'org-agenda-next-line) + +(map! :desc "Next line" + :map org-super-agenda-header-map + "k" 'org-agenda-previous-line) + +;;;------ magit configuration ------;;; + +;; Need the following two blocks to make magit work with git bare repos +(defun ~/magit-process-environment (env) + "Add GIT_DIR and GIT_WORK_TREE to ENV when in a special directory. +https://github.com/magit/magit/issues/460 (@cpitclaudel)." + (let ((default (file-name-as-directory (expand-file-name default-directory))) + (home (expand-file-name "~/"))) + (when (string= default home) + (let ((gitdir (expand-file-name "~/.dotfiles.git/"))) + (push (format "GIT_WORK_TREE=%s" home) env) + (push (format "GIT_DIR=%s" gitdir) env)))) + env) + +(advice-add 'magit-process-environment + :filter-return #'~/magit-process-environment) + +;;;------ dired configuration ------;;; + +(add-hook 'dired-mode-hook 'all-the-icons-dired-mode) + +(map! :desc "Increase font size" + "C-=" 'text-scale-increase + + :desc "Decrease font size" + "C--" 'text-scale-decrease) + +;;;------ ranger configuration ------;;; + +(map! :map ranger-mode-map + :desc "Mark current file" + "m" 'ranger-mark + + :desc "Toggle mark on current file" + "x" 'ranger-toggle-mark + + :desc "Open ranger" + "o d" 'ranger) + +;;;-- hledger-mode configuration ;;;-- + +;;; Basic configuration +(require 'hledger-mode) + +;; To open files with .journal extension in hledger-mode +(add-to-list 'auto-mode-alist '("\\.journal\\'" . hledger-mode)) + +;; The default journal location is too opinionated. +(setq hledger-jfile "/home/librephoenix/Org/Family.s/Notes/hledger.journal") + +;;; Auto-completion for account names +;; For company-mode users: +(add-to-list 'company-backends 'hledger-company) + +(evil-define-key* 'normal hledger-view-mode-map "q" 'kill-current-buffer) +(evil-define-key* 'normal hledger-view-mode-map "[" 'hledger-prev-report) +(evil-define-key* 'normal hledger-view-mode-map "]" 'hledger-next-report) + +(map! :leader + :prefix ("l" . "hledger") + :desc "Exec hledger command" + "c" 'hledger-run-command + + :desc "Generate hledger balancesheet" + "b" 'hledger-balancesheet* + + :desc "Exec hledger command" + "d" 'hledger-daily-report*) + +(map! :localleader + :map hledger-mode-map + + :desc "Reschedule transaction at point" + "d s" 'hledger-reschedule + + :desc "Edit amount at point" + "t a" 'hledger-edit-amount) + +;;;-- tab-bar-mode configuration ;;;-- + +;; Kbd tab navigation +(map! + :map evil-normal-state-map + "H" #'tab-bar-switch-to-prev-tab + "L" #'tab-bar-switch-to-next-tab + "C-" #'tab-bar-switch-to-prev-tab + "C-" #'tab-bar-switch-to-next-tab) + +(evil-global-set-key 'normal (kbd "C-w") 'tab-bar-close-tab) +(evil-global-set-key 'normal (kbd "C-t") 'tab-bar-new-tab) + +(setq tab-bar-new-tab-choice "*doom*") + +(tab-bar-mode t) + +(require 'focus) + +(map! :leader + :prefix ("F" . "Focus mode") + :desc "Toggle focus mode" + "t" 'focus-mode + + :desc "Pin focused section" + "p" 'focus-pin + + :desc "Unpin focused section" + "u" 'focus-unpin) + +(add-to-list 'focus-mode-to-thing '(org-mode . org-element)) +(add-to-list 'focus-mode-to-thing '(python-mode . paragraph)) +(add-to-list 'focus-mode-to-thing '(lisp-mode . paragraph)) + +;(add-hook 'org-mode-hook #'focus-mode) + +;;;-- Load emacs application framework;;;-- +(use-package! eaf + :load-path "~/.local/bin/emacs-application-framework/" + :init + :custom + (eaf-browser-continue-where-left-off t) + (eaf-browser-enable-adblocker t) + (browse-url-browser-function 'eaf-open-browser) ;; Make EAF Browser my default browser + :config + (defalias 'browse-web #'eaf-open-browser) + + (require 'eaf-pdf-viewer) + (require 'eaf-browser) + + (require 'eaf-evil) + (define-key key-translation-map (kbd "SPC") + (lambda (prompt) + (if (derived-mode-p 'eaf-mode) + (pcase eaf--buffer-app-name + ("browser" (if (string= (eaf-call-sync "eval_function" eaf--buffer-id "is_focus") "True") + (kbd "SPC") + (kbd eaf-evil-leader-key))) + ("pdf-viewer" (kbd eaf-evil-leader-key)) + ("image-viewer" (kbd eaf-evil-leader-key)) + (_ (kbd "SPC"))) + (kbd "SPC"))))) + +(map! :leader + :desc "Open web browser" + "o w" #'eaf-open-browser-with-history) diff --git a/user/app/doom-emacs/doom.org b/user/app/doom-emacs/doom.org new file mode 100644 index 00000000..0c08c9ec --- /dev/null +++ b/user/app/doom-emacs/doom.org @@ -0,0 +1,1563 @@ +#+TITLE: Doom Emacs Literate Config +#+AUTHOR: librephoenix + +* Table of Contents :TOC:QUOTE: +#+BEGIN_QUOTE +- [[#what-is-doom-emacs][What is Doom Emacs?]] +- [[#configuration-for-doom-emacs][Configuration for Doom Emacs]] +- [[#my-configel][My config.el]] + - [[#preamble--user-configuration][Preamble + User Configuration]] + - [[#registers][Registers]] + - [[#org-mode-configuration][Org Mode Configuration]] + - [[#org-roam-configuration][Org Roam Configuration]] + - [[#org-agenda-configuration][Org Agenda Configuration]] + - [[#magit-configuration][Magit Configuration]] + - [[#dired-configuration][Dired Configuration]] + - [[#ranger-configuration][Ranger Configuration]] + - [[#hledger-mode-configuration][hledger-mode Configuration]] + - [[#tab-bar-configuration][Tab Bar Configuration]] + - [[#focus-mode-configuration][Focus Mode Configuration]] + - [[#eaf][EAF]] +- [[#my-initel][My init.el]] +- [[#my-packagesel][My packages.el]] +#+END_QUOTE + +* What is Doom Emacs? +[[https://github.com/doomemacs/doomemacs][Doom Emacs]] is a distribution of the [[https://www.gnu.org/software/emacs/][Emacs Text Editor]] designed for [[https://www.vim.org/][Vim]] users. I like to use Emacs due to its extensibility and extra features it is capable of (besides text editing). Some of these extra features include: +- [[https://orgmode.org/][Org Mode]] (Hierarchical text-based document format) +- [[https://www.orgroam.com/][Org Roam]] (A second brain / personal wiki) +- [[https://orgmode.org/][Org Agenda]] (Calendar and todo list) +- [[https://magit.vc/][magit]] (Git Client) + +I have found Emacs to be incredibly efficient, and transferring my workflow to fit inside of Emacs has allowed me to get much more work done. + +* Configuration for Doom Emacs +Doom Emacs is configured via 3 main files, written in Elisp, a dialect of the Lisp programming langauge designed for Emacs. These 3 main files are: +- [[./config.el][config.el]] - Stores your main configuration and allows to set user variables. +- [[./init.el][init.el]] - Allows quick downloads of groups of Emacs packages. These groups of Emacs packages are curated by the Doom Emacs developers. +- [[./packages.el][packages.el]] - Allows you to download additional packages from Melpa (Emacs package manager). + +By storing your configuration in these 3 files, it allows for quick reproducible builds of Doom Emacs. + +You can also load separate files inside of [[./config.el][config.el]] via the =load!= function, like so: + +#+BEGIN_SRC emacs-lisp +(load! "~/.doom.d/private.el") +#+END_SRC + +I use this functionality to load my private config file with non-public information. + +* My [[./config.el][config.el]] +** Preamble + User Configuration +#+BEGIN_SRC emacs-lisp :tangle config.el +;;; $DOOMDIR/config.el -*- lexical-binding: t; -*- + +;;;------ User configuration ------;;; + +;; My default user identity as my yt alias +(setq user-full-name "librephoenix") + +;; I prefer visual lines +(setq display-line-numbers-type 'visual + line-move-visual t) +(use-package-hook! evil + :pre-init + (setq evil-respect-visual-line-mode t) ;; sane j and k behavior + t) + +;; I also like evil mode visual movement +(map! :map evil-normal-state-map + :desc "Move to next visual line" + "j" 'evil-next-visual-line + :desc "Move to previous visual line" + "k" 'evil-previous-visual-line) + +;; Theme and font +(setq doom-theme 'doom-old-hope) +(setq doom-font (font-spec :family "Inconsolata" :size 20)) + +;; Transparent background +(set-frame-parameter (selected-frame) 'alpha '(90 . 90)) +(add-to-list 'default-frame-alist '(alpha . (90 . 90))) + +;; Icons in completion buffers +(add-hook 'marginalia-mode-hook #'all-the-icons-completion-marginalia-setup) +(all-the-icons-completion-mode) + +;; This makes non-main buffers dimmer, so you can focus on main buffers +(solaire-global-mode +1) + +;; Grammar tasing should be voluntary +(setq writegood-mode nil) + +;; Beacon shows where the cursor is, even when fast scrolling +(setq beacon-mode t) + +;; Quicker window management keybindings +(bind-key* "C-j" #'evil-window-down) +(bind-key* "C-k" #'evil-window-up) +(bind-key* "C-h" #'evil-window-left) +(bind-key* "C-l" #'evil-window-right) +(bind-key* "C-q" #'evil-window-delete) + +;; Mouse buffer management +(bind-key* "" #'previous-buffer) +(bind-key* "" #'next-buffer) + +;; Disables custom.el +(setq custom-file null-device) + +;; Fancy splash image +(setq fancy-splash-image "~/.doom.d/arch.png") + +(setq +doom-dashboard-menu-sections +'(("Open org roam overview" :icon + (all-the-icons-octicon "globe" :face 'doom-dashboard-menu-title) + :face + (:inherit + (doom-dashboard-menu-title bold)) + :action org-roam-default-overview) + ("Roam to another db" :icon + (all-the-icons-fileicon "org" :face 'doom-dashboard-menu-title) + :action org-roam-switch-db) + ("Open agenda" :icon + (all-the-icons-octicon "calendar" :face 'doom-dashboard-menu-title) + :when + (fboundp 'org-agenda) + :action org-agenda-list + :key "SPC o A a") + ("Open private configuration" :icon + (all-the-icons-octicon "tools" :face 'doom-dashboard-menu-title) + :when + (file-directory-p doom-user-dir) + :action doom/open-private-config) + ("Open documentation" :icon + (all-the-icons-octicon "book" :face 'doom-dashboard-menu-title) + :action doom/help) + ("Quit emacs" :icon + (all-the-icons-faicon "level-down" :face 'doom-dashboard-menu-title) + :action save-buffers-kill-terminal) + ) +) + +;; Requires for faster loading +(require 'org-agenda) +(require 'dired) + +;; Garbage collection to speed things up +(add-hook 'after-init-hook + #'(lambda () + (setq gc-cons-threshold (* 100 1000 1000)))) +(add-hook 'focus-out-hook 'garbage-collect) +(run-with-idle-timer 5 t 'garbage-collect) + +;; Enable autorevert globally so that buffers update when files change on disk. +;; Very useful when used with file syncing (i.e. syncthing) +(setq global-auto-revert-mode nil) +(setq auto-revert-use-notify t) + +#+END_SRC +** Registers +#+BEGIN_SRC emacs-lisp :tangle config.el +;;;------ Registers ------;;; + +(map! :leader + :desc "Jump to register" + "r" 'jump-to-register) + +(set-register ?f '(file . "/home/librephoenix/Org/Family.s/Notes/hledger.org")) +(set-register ?r '(file . "/home/librephoenix/README.org")) +(set-register ?d '(file . "/home/librephoenix/.doom.d/doom.org")) +(set-register ?h '(file . "/home/librephoenix")) +(set-register ?x '(file . "/home/librephoenix/.xmonad/xmonad.org")) +(set-register ?s '(file . "/home/librephoenix/.install/install.org")) + +#+END_SRC +** Org Mode Configuration +*** Standard Org Mode Configuration +#+BEGIN_SRC emacs-lisp :tangle config.el +;;;------ Org mode configuration ------;;; + +;; Set default org directory +(setq org-directory "~/.Org") + +(remove-hook 'after-save-hook #'+literate|recompile-maybe) +(set-company-backend! 'org-mode nil) + +;; Automatically show images but manually control their size +(setq org-startup-with-inline-images t + org-image-actual-width nil) + +;; Top-level headings should be bigger! +(custom-set-faces! + '(org-level-1 :inherit outline-1 :height 1.3) + '(org-level-2 :inherit outline-2 :height 1.25) + '(org-level-3 :inherit outline-3 :height 1.2) + '(org-level-4 :inherit outline-4 :height 1.1) + '(org-level-5 :inherit outline-5 :height 1.1) + '(org-level-6 :inherit outline-6 :height 1.05) + '(org-level-7 :inherit outline-7 :height 1.05) + ) + +;(custom-set-faces! +; '(org-link :foreground nil)) + +;; Pretty org bullets +;;(use-package org-bullets +;; :ensure t +;; :init +;; (add-hook 'org-mode-hook (lambda () +;; (org-bullets-mode 1)))) + +(with-eval-after-load 'org (global-org-modern-mode)) + +;; Add frame borders and window dividers +(modify-all-frames-parameters + '((right-divider-width . 10) + (internal-border-width . 10))) +(dolist (face '(window-divider + window-divider-first-pixel + window-divider-last-pixel)) + (face-spec-reset-face face) + (set-face-foreground face (face-attribute 'default :background))) +(set-face-background 'fringe (face-attribute 'default :background)) + +(setq + ;; Edit settings + org-auto-align-tags nil + org-tags-column 0 + org-catch-invisible-edits 'show-and-error + org-special-ctrl-a/e t + org-insert-heading-respect-content t + + ;; Org styling, hide markup etc. + org-hide-emphasis-markers t + org-pretty-entities t + org-ellipsis "…") + +(setq-default line-spacing 0.1) + +; Automatic table of contents is nice +(if (require 'toc-org nil t) + (progn + (add-hook 'org-mode-hook 'toc-org-mode) + (add-hook 'markdown-mode-hook 'toc-org-mode)) + (warn "toc-org not found")) + +;;---- this block from http://fgiasson.com/blog/index.php/2016/06/21/optimal-emacs-settings-for-org-mode-for-literate-programming/ ----;; +;; Tangle Org files when we save them +(defun tangle-on-save-org-mode-file() + (when (string= (message "%s" major-mode) "org-mode") + (org-babel-tangle))) + +(add-hook 'after-save-hook 'tangle-on-save-org-mode-file) +;; ---- end block ---- ;; + +;; Better org table editing +(setq-default evil-insert-state-exit-hook '(org-update-parent-todo-statistics + t)) +(setq org-table-automatic-realign nil) + +;; Better for org source blocks +(setq electric-indent-mode nil) +(setq org-src-window-setup 'current-window) +(delete + '("^\\*Org Src" + (+popup-buffer) + (actions) + (side . bottom) + (size . 0.42) + (window-width . 40) + (window-height . 0.42) + (slot) + (vslot) + (window-parameters + (ttl) + (quit) + (select . t) + (modeline . t) + (autosave . t) + (transient . t) + (no-other-window . t))) + display-buffer-alist) + +#+END_SRC +*** Org Download, Image Capture, and Opening Files in External Programs +#+BEGIN_SRC emacs-lisp :tangle config.el +(require 'org-download) + +;; Drag-and-drop to `dired` +(add-hook 'dired-mode-hook 'org-download-enable) + +(setq org-download-screenshot-method "flameshot gui -p %s") +(after! org-download + (setq org-download-method 'directory)) + +(after! org + (setq-default org-download-image-dir "img/" + org-download-heading-lvl nil)) + +(defun my-org-screenshot () + "Take a screenshot into a time stamped unique-named file in the +same directory as the org-buffer and insert a link to this file." + (interactive) + (setq filename + (concat + (make-temp-name + (concat (buffer-file-name) + "_" + (format-time-string "%Y%m%d_%H%M%S_")) ) ".png")) + (shell-command (concat "emacs-wayshot " filename)) + (insert (concat "[[" filename "]]")) + (org-display-inline-images)) + +(defun my-org-paste() + "Take an image from the clipboard into a time stamped unique-named file in the +same directory as the org-buffer and insert a link to this file." + (interactive) + (setq filename + (concat + (make-temp-name + (concat (file-name-directory (buffer-file-name)) + "img/" + (file-name-nondirectory (buffer-file-name)) + "_" + (format-time-string "%Y%m%d_%H%M%S_")) ) ".png")) + (shell-command (concat "wl-paste > " filename)) + (insert (concat "[[" filename "]]")) + (org-display-inline-images)) + +(defun my-org-new-file-from-template() + "Copy a template from ~/Templates into a time stamped unique-named file in the +same directory as the org-buffer and insert a link to this file." + (interactive) + (setq template-file (completing-read "Template file:" (directory-files "~/Templates"))) + (setq filename + (concat + (make-temp-name + (concat (file-name-directory (buffer-file-name)) + "files/" + (file-name-nondirectory (buffer-file-name)) + "_" + (format-time-string "%Y%m%d_%H%M%S_")) ) (file-name-extension template-file t))) + (copy-file (concat "/home/librephoenix/Templates/" template-file) filename) + (setq prettyname (read-from-minibuffer "Pretty name:")) + (insert (concat "[[./files/" (file-name-nondirectory filename) "][" prettyname "]]")) + (org-display-inline-images)) + +(when (require 'openwith nil 'noerror) + (setq openwith-associations + (list + (list (openwith-make-extension-regexp + '("mpg" "mpeg" "mp3" "mp4" + "avi" "wmv" "wav" "mov" "flv" + "ogm" "ogg" "mkv")) + "mpv" + '(file)) + (list (openwith-make-extension-regexp + '("doc" "xls" "ppt" "odt" "ods" "odg" "odp")) + "libreoffice" + '(file)) + '("\\.lyx" "lyx" (file)) + '("\\.chm" "kchmviewer" (file)) + (list (openwith-make-extension-regexp + '("pdf" "ps" "ps.gz" "dvi")) + "atril" + '(file)) + (list (openwith-make-extension-regexp + '("kdenlive")) + "kdenlive" + '(file)) + (list (openwith-make-extension-regexp + '("kra")) + "krita" + '(file)) + (list (openwith-make-extension-regexp + '("blend" "blend1")) + "blender" + '(file)) + (list (openwith-make-extension-regexp + '("helio")) + "helio" + '(file)) + (list (openwith-make-extension-regexp + '("svg")) + "inkscape" + '(file)) + (list (openwith-make-extension-regexp + '("flp")) + "~/.local/bin/flstudio" + '(file)) + )) + (openwith-mode 1)) + +(add-to-list 'display-buffer-alist '("^*Async Shell Command*" . (display-buffer-no-window))) + +(map! :leader + :desc "Insert a screenshot" +;; "i s" 'my-org-screenshot) + "i s" 'org-download-screenshot) + +(defun org-download-clipboard-basename () + (interactive) + (setq org-download-path-last-dir org-download-image-dir) + (setq org-download-image-dir (completing-read "directory: " (-filter #'f-directory-p (directory-files-recursively "." "" t)) nil t)) + (org-download-clipboard (completing-read "basename: " '() nil nil)) + (setq org-download-image-dir org-download-path-last-dir) +) + +(map! :leader + :desc "Insert image from clipboard" + "i p" 'org-download-clipboard + "i P" 'org-download-clipboard-basename) + +(map! :leader + :desc "Create a new file from a template and insert a link at point" + "i t" 'my-org-new-file-from-template) + +#+END_SRC +*** Copy Links/Files into Clipboard +#+BEGIN_SRC emacs-lisp :tangle config.el +(defun org-copy-link-to-clipboard-at-point () + "Copy current link at point into clipboard (useful for images and links)" + (interactive) + (if (eq major-mode #'org-mode) + (link-hint-copy-link-at-point) + ) + (if (eq major-mode #'ranger-mode) + (ranger-copy-absolute-file-paths) + ) + (if (eq major-mode #'image-mode) + (image-mode-copy-file-name-as-kill) + ) + (shell-command (concat "~/.doom.d/scripts/copy-link-or-file/copy-link-or-file-to-clipboard.sh " (gui-get-selection 'CLIPBOARD)) nil nil) +) + +(map! :leader + :desc "Copy link/file at point into system clipbord (C-g to escape if copying a file)" + "y y" 'org-copy-link-to-clipboard-at-point) + +#+END_SRC +**** Copy Link/File to Clipboard Helper Script +Shamelessly stolen from [[https://unix.stackexchange.com/questions/30093/copy-image-from-command-line-to-clipboard][here]] and modified for my use. +#+BEGIN_SRC shell :tangle ./scripts/copy-link-or-file/copy-link-or-file-to-clipboard.sh :tangle-mode (identity #o755) +#!/bin/sh +#command -v xclip >/dev/null 2>&1 || { echo "Need command xclip. Aborting." >&2; exit 1; } +if [[ -f "$1" ]]; then + TYPE=$(file -b --mime-type "$1") + xclip -selection clipboard -t "$TYPE" -i "$1" +else + echo $1 | xclip -selection clipboard -t text/plain &> /dev/null + exit +fi +exit +#+END_SRC +*** Org Online Images +#+BEGIN_SRC emacs-lisp :tangle config.el +;; Online images inside of org mode is pretty cool +;; This snippit is from Tobias on Stack Exchange +;; https://emacs.stackexchange.com/questions/42281/org-mode-is-it-possible-to-display-online-images +(require 'org-yt) + +(defun org-image-link (protocol link _description) + "Interpret LINK as base64-encoded image data." + (cl-assert (string-match "\\`img" protocol) nil + "Expected protocol type starting with img") + (let ((buf (url-retrieve-synchronously (concat (substring protocol 3) ":" link)))) + (cl-assert buf nil + "Download of image \"%s\" failed." link) + (with-current-buffer buf + (goto-char (point-min)) + (re-search-forward "\r?\n\r?\n") + (buffer-substring-no-properties (point) (point-max))))) + +(org-link-set-parameters + "imghttp" + :image-data-fun #'org-image-link) + +(org-link-set-parameters + "imghttps" + :image-data-fun #'org-image-link) +#+END_SRC +*** Org Mermaid Diagrams +#+BEGIN_SRC emacs-lisp :tangle config.el +;; Mermaid diagrams +(setq ob-mermaid-cli-path "/usr/bin/mmdc") +#+END_SRC +*** Org Simple Printing +#+BEGIN_SRC emacs-lisp :tangle config.el +;; Print org mode +(defun org-simple-print-buffer () + "Open an htmlized form of current buffer and open in a web browser to print" + (interactive) + (htmlize-buffer) + (browse-url-of-buffer (concat (buffer-name) ".html")) + (sleep-for 1) + (kill-buffer (concat (buffer-name) ".html"))) + +;; Doesn't work yet, bc htmlize-region takes arguments BEG and END +;(defun org-simple-print-region() +; "Open an htmlized form of current region and open in a web browser to print" +; (interactive) +; (htmlize-region ) +; (browse-url-of-buffer (concat (buffer-name) ".html")) +; (sleep-for 1) +; (kill-buffer (concat (buffer-name) ".html"))) + +(map! :leader + :prefix ("P" . "Print") + :desc "Simple print buffer in web browser" + "p" 'org-simple-print-buffer) + +(map! :leader + :prefix ("P" . "Print") + :desc "Simple print buffer in web browser" + "b" 'org-simple-print-buffer) + +;(map! :leader +; :prefix ("P" . "Print") +; :desc "Simple print region in web browser" +; "r" 'org-simple-print-region) + +#+END_SRC +*** Org -> ODP Presentation Export +#+BEGIN_SRC emacs-lisp :tangle config.el +;; Custom function to convert org mode to ODP presentation +;; Depends on bash, libreoffice, and pandoc +(defun my-ox-odp () + "Convert an org mode file to an ODP presentation." + (interactive) + (setq file-name (buffer-file-name)) + (setq output-pptx-file-name (replace-regexp-in-string "\.org" "\.pptx" (buffer-file-name))) + (setq output-odp-file-name (replace-regexp-in-string "\.org" "\.odp" (buffer-file-name))) + (setq odp-style-file-name (completing-read "Choose style: " + '("/home/librephoenix/.doom.d/scripts/ox-odp/styles/water.odp" + "/home/librephoenix/.doom.d/scripts/ox-odp/styles/dark.odp" + ) nil t)) + (shell-command (concat "~/.doom.d/scripts/ox-odp/ox-odp.sh \"" (buffer-file-name) "\" \"" odp-style-file-name "\" > /dev/null")) + ) + +(map! :leader + :desc "Convert org document to odp presentation" + "e p" 'my-ox-odp) + +#+END_SRC +**** Org -> ODP Helper Scripts +These are helper scripts for =my-ox-odp= (defined above), which converts an org document to an ODP presentation. This fundamentally functions by running a shell script ([[./scripts/ox-odp/ox-odp.sh][ox-odp.sh]]), which also calls a Python script ([[./scripts/ox-odp/ox-odp-xml-parse.py][ox-odp-xml-parse.py]]). +***** [[./scripts/ox-odp/ox-odp.sh][ox-odp.sh]] +#+BEGIN_SRC shell :tangle ./scripts/ox-odp/ox-odp.sh :tangle-mode (identity #o755) +#!/bin/sh + +filename=$1 +echo $filename +stylefile=$2 +echo $stylefile + +filenamebase=$(basename "$filename") +filenameext="${filenamebase##*.}" +echo $filenameext + +if [ $filenameext = "org" ]; then + stylefilebase=$(basename "$stylefile") + stylefileext="${stylefilebase##*.}" + + if [ $stylefileext = "odp" ]; then + output="${filename//\.org/\.pptx}" + finaloutput="${filename//\.org/\.odp}" + pandoc "$filename" -o "$output" + soffice --convert-to odp "$output" + unzip "$finaloutput" content.xml + unzip "$stylefile" styles.xml + + sed 's~~~g' content.xml + sed 's~~~g' content.xml + + python3 ~/.doom.d/scripts/ox-odp/ox-odp-xml-parse.py + + zip -d $finaloutput styles.xml + zip -m $finaloutput styles.xml + + zip -d $finaloutput content.xml + zip -m $finaloutput content.xml + + rm $output + + exit + + else + echo "Style file is not an odp file." + fi +else + echo "Base file is not an org file." + exit +fi + +exit + +#+END_SRC +***** [[./scripts/ox-odp/ox-odp-xml-parse.py][ox-odp-xml-parse.py]] +This script parses through the raw LibreOffice XML to fix some common formatting errors with the standard Org to pptx to odp conversion strategy. +#+BEGIN_SRC python :tangle ./scripts/ox-odp/ox-odp-xml-parse.py :tangle-mode (identity #o755) +#!/usr/bin/env python3 + +import xml.etree.ElementTree as ET +import copy + +# Read content.xml into parser +mytree = ET.parse('./content.xml') +myroot = mytree.getroot() + +# Read styles.xml into parser +styletree = ET.parse('./styles.xml') +styleroot = styletree.getroot() + +# Remove direct-formatting from text:style-name attributes in text:p elements +counter = 0 +for text in myroot.iter('{urn:oasis:names:tc:opendocument:xmlns:text:1.0}p'): + if '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name' in text.keys(): + stylename = text.attrib['{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name'] + if stylename[0] == "P": + counter += 1 + text.attrib.pop('{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name') +print('Deleted '+str(counter)+' text:style-name attributes in text:p elements.') + +# Remove direct-formatting from text:style-name attributes in text:span elements +counter = 0 +for span in myroot.iter('{urn:oasis:names:tc:opendocument:xmlns:text:1.0}span'): + if '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name' in span.keys(): + span.attrib.pop('{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name') +print('Deleted '+str(counter)+' text:style-name attributes in text:span elements.') + +# Remove direct-formatting from draw:text-style-name attributes in draw:frame elements +counter = 0 +for drawing in myroot.iter('{urn:oasis:names:tc:opendocument:xmlns:drawing:1.0}frame'): + if '{urn:oasis:names:tc:opendocument:xmlns:drawing:1.0}text-style-name' in drawing.keys(): + stylename = drawing.attrib['{urn:oasis:names:tc:opendocument:xmlns:drawing:1.0}text-style-name'] + if stylename[0] == "P": + counter += 1 + drawing.attrib.pop('{urn:oasis:names:tc:opendocument:xmlns:drawing:1.0}text-style-name') +print('Deleted '+str(counter)+' draw:text-style-name attributes in text:p elements.') + +# Redefine default styles (style:style elements) and purge unnecessary ones +counter = 0 +kounter = 0 +for style in myroot.iter('{urn:oasis:names:tc:opendocument:xmlns:style:1.0}style'): + if '{urn:oasis:names:tc:opendocument:xmlns:style:1.0}name' in style.keys(): + stylename = style.attrib['{urn:oasis:names:tc:opendocument:xmlns:style:1.0}name'] + if stylename == "pr1": + counter += 1 + style.set('{urn:oasis:names:tc:opendocument:xmlns:style:1.0}parent-style-name','DefaultTheme-title') + elif stylename == "pr2": + counter += 1 + style.set('{urn:oasis:names:tc:opendocument:xmlns:style:1.0}parent-style-name','DefaultTheme-subtitle') + elif stylename == "pr3": + counter += 1 + style.set('{urn:oasis:names:tc:opendocument:xmlns:style:1.0}parent-style-name','DefaultTheme-notes') + elif stylename == "pr4": + counter += 1 + style.set('{urn:oasis:names:tc:opendocument:xmlns:style:1.0}parent-style-name','DefaultTheme-outline1') +print('Redefined '+str(counter)+' style:parent-style-name attributes in style:style elements.') +print('Deleted '+str(kounter)+' style:style elements.') + +# Search for automatic-styles element +i = 0 +col1 = 0 +while (i < len(myroot)): + print(myroot[i].tag) + if myroot[i].tag=="{urn:oasis:names:tc:opendocument:xmlns:office:1.0}automatic-styles": + col1 = i + i += 1 + +# Remove unnecessary style:style and test:list-style elements underneath automatic-styles +i = 0 +while (i < len(myroot[col1])): + if (myroot[col1][i].tag == "{urn:oasis:names:tc:opendocument:xmlns:style:1.0}style"): + if ("{urn:oasis:names:tc:opendocument:xmlns:style:1.0}name" in myroot[col1][i].keys()): + if myroot[col1][i].attrib["{urn:oasis:names:tc:opendocument:xmlns:style:1.0}name"] in ["pr5","pr6","pr7","pr8","pr9"]: + print("Removing "+myroot[col1][i].tag) + myroot[col1].remove(myroot[col1][i]) + i -= 1 + elif myroot[col1][i].attrib["{urn:oasis:names:tc:opendocument:xmlns:style:1.0}name"][0] == "P": + print("Removing "+myroot[col1][i].tag) + myroot[col1].remove(myroot[col1][i]) + i -= 1 + if (myroot[col1][i].tag == "{urn:oasis:names:tc:opendocument:xmlns:text:1.0}list-style"): + print("Removing "+myroot[col1][i].tag) + myroot[col1].remove(myroot[col1][i]) + i -= 1 + i += 1 + +#i = 0 +#while (i < len(myroot[col1])): +# print(myroot[col1][i].attrib) +# i += 1 + +# Find ML1 in styles.xml and copy it into L1 in content.xml +# Search for automatic-styles element +i = 0 +stylecol1 = 0 +while (i < len(styleroot)): + print(styleroot[i].tag) + if styleroot[i].tag=="{urn:oasis:names:tc:opendocument:xmlns:office:1.0}automatic-styles": + stylecol1 = i + i += 1 + +# Remove unnecessary style:style and test:list-style elements underneath automatic-styles +i = 0 +while (i < len(styleroot[stylecol1])): + if (styleroot[stylecol1][i].tag == "{urn:oasis:names:tc:opendocument:xmlns:text:1.0}list-style"): + if (styleroot[stylecol1][i].attrib["{urn:oasis:names:tc:opendocument:xmlns:style:1.0}name"] == "ML1"): + liststyle_copy = copy.deepcopy(styleroot[stylecol1][i]) + myroot[col1].append(liststyle_copy) + myroot[col1][-1].attrib['{urn:oasis:names:tc:opendocument:xmlns:style:1.0}name'] = "L1" + i += 1 + +# Update presentation:style-name attribute of all draw:frame elements +counter = 0 +for frame in myroot.iter('{urn:oasis:names:tc:opendocument:xmlns:drawing:1.0}frame'): + if '{urn:oasis:names:tc:opendocument:xmlns:presentation:1.0}class' in frame.keys(): + classname = frame.attrib['{urn:oasis:names:tc:opendocument:xmlns:presentation:1.0}class'] + if classname == "title": + counter += 1 + frame.set('{urn:oasis:names:tc:opendocument:xmlns:presentation:1.0}style-name','pr1') + elif classname == "subtitle": + counter += 1 + frame.set('{urn:oasis:names:tc:opendocument:xmlns:presentation:1.0}style-name','pr2') + elif classname == "notes": + counter += 1 + frame.set('{urn:oasis:names:tc:opendocument:xmlns:presentation:1.0}style-name','pr3') + elif classname == "outline": + counter += 1 + frame.set('{urn:oasis:names:tc:opendocument:xmlns:presentation:1.0}style-name','pr4') +print("Updated "+str(counter)+" draw:frame elements") + +# Update draw:master-page-name attributes in all draw:page elements +# Also delete all presentation:presentation-page-layout attributes +counter = 0 +for page in myroot.iter('{urn:oasis:names:tc:opendocument:xmlns:drawing:1.0}page'): + if '{urn:oasis:names:tc:opendocument:xmlns:drawing:1.0}master-page-name' in page.keys(): + page.set('{urn:oasis:names:tc:opendocument:xmlns:drawing:1.0}master-page-name','DefaultTheme') + counter += 1 + if '{urn:oasis:names:tc:opendocument:xmlns:presentation:1.0}presentation-page-layout' in page.keys(): + page.attrib.pop('{urn:oasis:names:tc:opendocument:xmlns:presentation:1.0}presentation-page-layout') + +print("Updated "+str(counter)+" draw:page elements") + +# Update all text:list elements to have text:style-name = L1 +counter = 0 +for page in myroot.iter('{urn:oasis:names:tc:opendocument:xmlns:text:1.0}list'): + if '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name' in page.keys(): + page.set('{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name','L1') + counter += 1 + +print("Updated "+str(counter)+" text:list elements") + +#mytree.canonicalize(out='content.xml') +mytree.write('content.xml') +styletree.write('styles.xml') + +#+END_SRC +** Org Roam Configuration +*** Standard Org Roam Configuration +#+BEGIN_SRC emacs-lisp :tangle config.el +;;;------ Org roam configuration ------;;; + +(require 'org-roam) +(require 'org-roam-dailies) + +(setq org-roam-directory "~/Org/Personal/Notes" + org-roam-db-location "~/Org/Personal/Notes/org-roam.db") + +(setq org-roam-node-display-template + "${title:65}📝${tags:*}") + +(org-roam-db-autosync-mode) + +#+END_SRC +*** Multi Org Roam Configuration +#+BEGIN_SRC emacs-lisp :tangle config.el +(setq full-org-roam-db-list nil) + +(setq full-org-roam-db-list (directory-files "~/Org" t "\\.[p,s]$")) +(dolist (item full-org-roam-db-list) + (setq full-org-roam-db-list + (append (directory-files item t "\\.[p,s]$") full-org-roam-db-list))) + +(setq org-roam-db-choice "Default") +(setq full-org-roam-db-list-pretty (list "Default")) +(dolist (item full-org-roam-db-list) + (setq full-org-roam-db-list-pretty + (append (list + (replace-regexp-in-string "\\/home\\/librephoenix\\/Org\\/" "" item)) full-org-roam-db-list-pretty))) + +(defun org-roam-open-dashboard () + "Open ${org-roam-directory}/dashboard.org (I use this naming convention to create dashboards for each of my org roam maps)" + (interactive) + (if (file-exists-p (concat org-roam-directory "/dashboard.org")) + (org-open-file (concat org-roam-directory "/dashboard.org")) + (dired org-roam-directory)) +) + +(defun org-roam-switch-db (&optional arg silent) + "Switch to a different org-roam database, arg" + (interactive) + (when (not arg) + (setq full-org-roam-db-list nil) + + (setq full-org-roam-db-list (directory-files "~/Org" t "\\.[p,s]$")) + (dolist (item full-org-roam-db-list) + (setq full-org-roam-db-list + (append (directory-files item t "\\.[p,s]$") full-org-roam-db-list))) + + (setq full-org-roam-db-list-pretty (list "Default")) + (dolist (item full-org-roam-db-list) + (setq full-org-roam-db-list-pretty + (append (list + (replace-regexp-in-string "\\/home\\/librephoenix\\/Org\\/" "" item)) full-org-roam-db-list-pretty))) + + (setq org-roam-db-choice (completing-read "Select org roam database: " + full-org-roam-db-list-pretty nil t))) + (when arg + (setq org-roam-db-choice arg)) + + (if (string= org-roam-db-choice "Default") + (setq org-roam-directory (file-truename "~/Org/Personal/Notes") + org-roam-db-location (file-truename "~/Org/Personal/Notes/org-roam.db") + org-directory (file-truename"~/Org/Personal/Notes")) + (setq org-roam-directory (file-truename (concat "~/Org/" org-roam-db-choice "/Notes")) + org-roam-db-location (file-truename (concat "~/Org/" org-roam-db-choice "/Notes/org-roam.db")) + org-directory (file-truename (concat "~/Org/" org-roam-db-choice "/Notes")))) + (when (not silent) + (org-roam-open-dashboard)) + + (org-roam-db-sync) + + (message (concat "Switched to " org-roam-db-choice " org-roam database!"))) + +(defun org-roam-default-overview () + (interactive) + (org-roam-switch-db "Default")) + +(defun org-roam-switch-db-id-open (arg ID &optional switchpersist) + "Switch to another org-roam db and visit file with id arg" + "If switchpersist is non-nil, stay in the new org-roam db after visiting file" + (interactive) + (setq prev-org-roam-db-choice org-roam-db-choice) + (org-roam-switch-db arg 1) + (org-roam-id-open ID) + (when (not switchpersist) + (org-roam-switch-db prev-org-roam-db-choice 1))) + +#+END_SRC +*** Org Roam "todos" Tagging for Org Agenda +#+BEGIN_SRC emacs-lisp :tangle config.el +;;;------ Org-roam-agenda configuration ------;;; +(defun text-in-buffer-p (TEXT) +(save-excursion (goto-char (point-min)) (search-forward TEXT nil t))) + +(defun apply-old-todos-tag-maybe (&optional FILE) + (interactive) + (if (stringp FILE) + (setq the-daily-node-filename FILE) + (setq the-daily-node-filename buffer-file-name)) + (if (org-roam-dailies--daily-note-p the-daily-node-filename) + (if (<= (nth 2 (org-roam-dailies-calendar--file-to-date the-daily-node-filename)) (nth 2 org-agenda-current-date)) + (if (<= (nth 1 (org-roam-dailies-calendar--file-to-date the-daily-node-filename)) (nth 1 org-agenda-current-date)) + (if (<= (nth 0 (org-roam-dailies-calendar--file-to-date the-daily-node-filename)) (nth 0 org-agenda-current-date)) + (funcall (lambda () + (with-current-buffer (get-file-buffer the-daily-node-filename) (org-roam-tag-add '("old-todos"))) + (with-current-buffer (get-file-buffer the-daily-node-filename) (org-roam-tag-remove '("todos"))) + ) + ) + ) + ) + ) + ) +) + +(defun apply-old-todos-tag-maybe-and-save (FILE) + (interactive) + (find-file-noselect FILE) + (apply-old-todos-tag-maybe FILE) + (with-current-buffer (get-file-buffer the-daily-node-filename) (save-buffer)) + (with-current-buffer (get-file-buffer the-daily-node-filename) (kill-buffer)) +) + +; This has a bug where it won't sync a new agenda file +; if I'm editing an org roam node file while set to another +; org roam db +(defun add-todos-tag-on-save-org-mode-file() + (interactive) + (when (string= (message "%s" major-mode) "org-mode") + (if (org-roam-node-p (org-roam-node-at-point)) + (funcall (lambda() + (if (or (text-in-buffer-p "SCHEDULED: <") (text-in-buffer-p "DEADLINE: <")) + (org-roam-tag-add '("todos")) + (org-roam-tag-remove '("todos")) + ) + (apply-old-todos-tag-maybe) + ) + ) + ) + ) +) + +(add-hook 'before-save-hook 'add-todos-tag-on-save-org-mode-file) + +#+END_SRC +*** Setup Org Agenda from Org Roam +#+BEGIN_SRC emacs-lisp :tangle config.el +(defun org-roam-filter-by-tag (tag-name) + (lambda (node) + (member tag-name (org-roam-node-tags node)))) + +(defun org-roam-list-notes-by-tag (tag-name) + (mapcar #'org-roam-node-file + (seq-filter + (org-roam-filter-by-tag tag-name) + (org-roam-node-list)))) + +(defun org-roam-dailies-apply-old-todos-tags-to-all () +; (dolist (daily-node org-roam-dailies-files) +; (apply-old-todos-tag-maybe-and-save daily-node) +; ) + (setq num 0) + (while (< num (list-length (org-roam-list-notes-by-tag "todos"))) + (apply-old-todos-tag-maybe-and-save (nth num (org-roam-list-notes-by-tag "todos"))) + (setq num (1+ num)) + ) +) + +(defun org-roam-append-notes-to-agenda (tag-name db) + (org-roam-switch-db db t) +; (org-roam-dailies-apply-old-todos-tags-to-all) + (setq org-agenda-files (append org-agenda-files (org-roam-list-notes-by-tag "todos"))) +) + +(defun org-roam-refresh-agenda-list () + (interactive) + (setq prev-org-roam-db-choice org-roam-db-choice) + (setq org-agenda-files '()) + (dolist (DB full-org-roam-db-list-pretty) + (org-roam-append-notes-to-agenda "todos" DB) + ) + (org-roam-switch-db prev-org-roam-db-choice 1) +) + +;; Build agenda for first time during this session +(org-roam-refresh-agenda-list) + +#+END_SRC +*** Org Roam Keybindings +#+BEGIN_SRC emacs-lisp :tangle config.el +(map! :leader + :prefix ("N" . "org-roam notes") + + :desc "Capture new roam node" + "c" 'org-roam-capture + + :desc "Insert roam node link at point" + "i" 'org-roam-node-insert + + :desc "Find roam node" + "." 'org-roam-node-find + + :desc "Switch org-roam database" + "s" 'org-roam-switch-db + + :desc "Update current org-roam database" + "u" 'org-roam-db-sync + + :desc "Re-zoom on current node in org-roam-ui" + "z" 'org-roam-ui-node-zoom + + :desc "Visualize org-roam database with org-roam-ui" + "O" 'org-roam-default-overview + + :desc "Visualize org-roam database with org-roam-ui" + "o" 'org-roam-open-dashboard) + +#+END_SRC +*** Org Roam Capture Templates +#+BEGIN_SRC emacs-lisp :tangle config.el +(after! org-roam + (setq org-roam-capture-templates + '(("d" "default" plain "%?" :target + (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n") + :unnarrowed t)))) + +#+END_SRC +*** Org Roam Olivetti Mode +#+BEGIN_SRC emacs-lisp :tangle config.el +(defun org-roam-olivetti-mode () + (interactive) + (if (org-roam-file-p) + (olivetti-mode)) + (if (org-roam-file-p) + (doom-disable-line-numbers-h))) + +(add-hook 'org-mode-hook 'org-roam-olivetti-mode) + +#+END_SRC +*** Org Roam Dynamic Blocks +#+BEGIN_SRC emacs-lisp :tangle config.el +(use-package org-roam-dblocks + :hook (org-mode . org-roam-dblocks-autoupdate-mode)) + +#+END_SRC +*** Org Roam Export Setup +#+BEGIN_SRC emacs-lisp :tangle config.el +(setq org-id-extra-files 'org-agenda-text-search-extra-files) + +#+END_SRC +*** TODO Org Roam UI Setup +I want this to be able to automatically open ORUI in EAF Browser in a split to the right. This kinda works now? +#+BEGIN_SRC emacs-lisp :tangle config.el +;(add-to-list 'display-buffer-alist '("^\\ORUI" display-buffer-in-side-window +; '(side . right) +; (window-width . 50) +;)) +;(add-to-list 'display-buffer-alist '("^\\localhost:35901" display-buffer-in-side-window +; '(side . right) +; (window-width . 50) +;)) + +(defun open-org-roam-ui () + (interactive) + (+evil/window-vsplit-and-follow) + (org-roam-ui-open) + (evil-window-left)) + +(defun kill-org-roam-ui () + (interactive) + (delete-window (get-buffer-window "ORUI" t)) + (kill-buffer "ORUI") + (kill-buffer "*httpd*") +) + +(map! :leader + :prefix ("N" . "org-roam notes") + :desc "Visualize org-roam database with org-roam-ui" + "v" 'open-org-roam-ui) + +(map! :leader + :prefix ("N" . "org-roam notes") + :desc "Kill all org roam ui buffers" + "V" 'kill-org-roam-ui) + +#+END_SRC +** Org Agenda Configuration +*** Standard Org Agenda Configuration +#+BEGIN_SRC emacs-lisp :tangle config.el +;;;------ Org agenda configuration ------;;; + +;; Set span for agenda +(setq org-agenda-span 1 + org-agenda-start-day "+0d") + +;; Ricing org agenda +(setq org-agenda-current-time-string "") +(setq org-agenda-time-grid '((daily) () "" "")) + +(setq org-agenda-prefix-format '( +(agenda . " %?-2i %t ") + (todo . " %i %-12:c") + (tags . " %i %-12:c") + (search . " %i %-12:c"))) + +(setq org-agenda-hide-tags-regexp ".*") + +(setq org-agenda-category-icon-alist + `(("Teaching" ,(list (all-the-icons-faicon "graduation-cap" :height 0.8)) nil nil :ascent center) + ("Family" ,(list (all-the-icons-faicon "home" :v-adjust 0.005)) nil nil :ascent center) + ("Producer" ,(list (all-the-icons-faicon "youtube-play" :height 0.9)) nil nil :ascent center) + ("Bard" ,(list (all-the-icons-faicon "music" :height 0.9)) nil nil :ascent center) + ("Story" ,(list (all-the-icons-faicon "book" :height 0.9)) nil nil :ascent center) + ("Author" ,(list (all-the-icons-faicon "pencil" :height 0.9)) nil nil :ascent center) + ("Gamedev" ,(list (all-the-icons-faicon "gamepad" :height 0.9)) nil nil :ascent center) + ("Tech" ,(list (all-the-icons-faicon "laptop" :height 0.9)) nil nil :ascent center) +)) + +;; Function to be run when org-agenda is opened +(defun org-agenda-open-hook () + "Hook to be run when org-agenda is opened" + (olivetti-mode)) + +;; Adds hook to org agenda mode, making follow mode active in org agenda +(add-hook 'org-agenda-mode-hook 'org-agenda-open-hook) + +#+END_SRC +*** Org Agenda Convenience Functions +#+BEGIN_SRC emacs-lisp :tangle config.el +;; Function to list all my available org agenda files and switch to them +(defun list-and-switch-to-agenda-file () + "Lists all available agenda files and switches to desired one" + (interactive) + (setq full-agenda-file-list nil) + (setq choice (completing-read "Select agenda file:" org-agenda-files nil t)) + (find-file choice)) + +(map! :leader + :desc "Switch to specific org agenda file" + "o a s" 'list-and-switch-to-agenda-file) + +(map! :leader + :desc "Open org calendar" + "o c" #'cfw:open-org-calendar) + +#+END_SRC +*** Org Super Agenda Configuration +#+BEGIN_SRC emacs-lisp :tangle config.el +(require 'org-super-agenda) + +(setq org-super-agenda-groups + '(;; Each group has an implicit boolean OR operator between its selectors. + (:name "Home Tech" + :and(:file-path "librephoenix/Agenda" :not (:tag "event")) + :order 3) + + (:name "Family" + :and(:file-path "Family" :not (:tag "event")) + :order 3) + + (:name "Teaching Prep" + :and(:file-path "Teaching.p" :tag "planning" :not (:tag "grading") :not (:tag "event")) + :order 3) + + (:name "Teaching Secretarial" + :and(:file-path "Teaching.p" :tag "secretarial" :not (:tag "grading") :not (:tag "event")) + :order 3) + + (:name "Teaching Grading" + :and(:file-path "Teaching.p" :tag "grading" :not (:tag "planning") :not (:tag "event")) + :order 3) + + (:name "School Side Projects" + :and(:file-path "Teaching.p" :tag "tech" :not (:tag "planning") :not (:tag "event")) + :order 3) + + (:name "Gamedev Current Projects" + :and (:file-path "Gamedev" :todo "STRT") + :order 5) + + (:name "Youtube" + :tag "youtube" + :order 6) + + (:name "Learning" + :tag "learning" + :order 7) + + (:name "Today" ; Optionally specify section name + :time-grid t + :date today + :scheduled today + :order 1) +)) + +(org-super-agenda-mode t) + +(map! :desc "Next line" + :map org-super-agenda-header-map + "j" 'org-agenda-next-line) + +(map! :desc "Next line" + :map org-super-agenda-header-map + "k" 'org-agenda-previous-line) + +#+END_SRC +** Magit Configuration +#+BEGIN_SRC emacs-lisp :tangle config.el +;;;------ magit configuration ------;;; + +;; Need the following two blocks to make magit work with git bare repos +(defun ~/magit-process-environment (env) + "Add GIT_DIR and GIT_WORK_TREE to ENV when in a special directory. +https://github.com/magit/magit/issues/460 (@cpitclaudel)." + (let ((default (file-name-as-directory (expand-file-name default-directory))) + (home (expand-file-name "~/"))) + (when (string= default home) + (let ((gitdir (expand-file-name "~/.dotfiles.git/"))) + (push (format "GIT_WORK_TREE=%s" home) env) + (push (format "GIT_DIR=%s" gitdir) env)))) + env) + +(advice-add 'magit-process-environment + :filter-return #'~/magit-process-environment) + +#+END_SRC +** Dired Configuration +#+BEGIN_SRC emacs-lisp :tangle config.el +;;;------ dired configuration ------;;; + +(add-hook 'dired-mode-hook 'all-the-icons-dired-mode) + +(map! :desc "Increase font size" + "C-=" 'text-scale-increase + + :desc "Decrease font size" + "C--" 'text-scale-decrease) + +#+END_SRC +** Ranger Configuration +#+BEGIN_SRC emacs-lisp :tangle config.el +;;;------ ranger configuration ------;;; + +(map! :map ranger-mode-map + :desc "Mark current file" + "m" 'ranger-mark + + :desc "Toggle mark on current file" + "x" 'ranger-toggle-mark + + :desc "Open ranger" + "o d" 'ranger) + +#+END_SRC +** hledger-mode Configuration +#+BEGIN_SRC emacs-lisp :tangle config.el +;;;-- hledger-mode configuration ;;;-- + +;;; Basic configuration +(require 'hledger-mode) + +;; To open files with .journal extension in hledger-mode +(add-to-list 'auto-mode-alist '("\\.journal\\'" . hledger-mode)) + +;; The default journal location is too opinionated. +(setq hledger-jfile "/home/librephoenix/Org/Family.s/Notes/hledger.journal") + +;;; Auto-completion for account names +;; For company-mode users: +(add-to-list 'company-backends 'hledger-company) + +(evil-define-key* 'normal hledger-view-mode-map "q" 'kill-current-buffer) +(evil-define-key* 'normal hledger-view-mode-map "[" 'hledger-prev-report) +(evil-define-key* 'normal hledger-view-mode-map "]" 'hledger-next-report) + +(map! :leader + :prefix ("l" . "hledger") + :desc "Exec hledger command" + "c" 'hledger-run-command + + :desc "Generate hledger balancesheet" + "b" 'hledger-balancesheet* + + :desc "Exec hledger command" + "d" 'hledger-daily-report*) + +(map! :localleader + :map hledger-mode-map + + :desc "Reschedule transaction at point" + "d s" 'hledger-reschedule + + :desc "Edit amount at point" + "t a" 'hledger-edit-amount) + +#+END_SRC +** Tab Bar Configuration +I don't have this active right now since I'm exploring tab-bar mode instead! +#+BEGIN_SRC emacs-lisp :tangle config.el +;;;-- tab-bar-mode configuration ;;;-- + +;; Kbd tab navigation +(map! + :map evil-normal-state-map + "H" #'tab-bar-switch-to-prev-tab + "L" #'tab-bar-switch-to-next-tab + "C-" #'tab-bar-switch-to-prev-tab + "C-" #'tab-bar-switch-to-next-tab) + +(evil-global-set-key 'normal (kbd "C-w") 'tab-bar-close-tab) +(evil-global-set-key 'normal (kbd "C-t") 'tab-bar-new-tab) + +(setq tab-bar-new-tab-choice "*doom*") + +(tab-bar-mode t) + +#+END_SRC +** Focus Mode Configuration +#+BEGIN_SRC emacs-lisp :tangle config.el +(require 'focus) + +(map! :leader + :prefix ("F" . "Focus mode") + :desc "Toggle focus mode" + "t" 'focus-mode + + :desc "Pin focused section" + "p" 'focus-pin + + :desc "Unpin focused section" + "u" 'focus-unpin) + +(add-to-list 'focus-mode-to-thing '(org-mode . org-element)) +(add-to-list 'focus-mode-to-thing '(python-mode . paragraph)) +(add-to-list 'focus-mode-to-thing '(lisp-mode . paragraph)) + +;(add-hook 'org-mode-hook #'focus-mode) + +#+END_SRC +** EAF +#+BEGIN_SRC emacs-lisp :tangle config.el +;;;-- Load emacs application framework;;;-- +(use-package! eaf + :load-path "~/.local/bin/emacs-application-framework/" + :init + :custom + (eaf-browser-continue-where-left-off t) + (eaf-browser-enable-adblocker t) + (browse-url-browser-function 'eaf-open-browser) ;; Make EAF Browser my default browser + :config + (defalias 'browse-web #'eaf-open-browser) + + (require 'eaf-pdf-viewer) + (require 'eaf-browser) + + (require 'eaf-evil) + (define-key key-translation-map (kbd "SPC") + (lambda (prompt) + (if (derived-mode-p 'eaf-mode) + (pcase eaf--buffer-app-name + ("browser" (if (string= (eaf-call-sync "eval_function" eaf--buffer-id "is_focus") "True") + (kbd "SPC") + (kbd eaf-evil-leader-key))) + ("pdf-viewer" (kbd eaf-evil-leader-key)) + ("image-viewer" (kbd eaf-evil-leader-key)) + (_ (kbd "SPC"))) + (kbd "SPC"))))) + +(map! :leader + :desc "Open web browser" + "o w" #'eaf-open-browser-with-history) + +#+END_SRC +* My [[./init.el][init.el]] +This section is the [[./init.el][init.el]] section, which controls which Doom modules are loaded. + +=SPC h d h= (vim) or =C-h d h= (non-vim) can be used to access Doom's documentation (including a "Module Index"). + +=K= (vim) or =C-c c k= (non-vim) can be used to view a module's documentation (this can help you discover module flags as well). + +=gd= (vim) or =C-c c d= (non-vim) will let you browse a module's directory (source code). + +#+BEGIN_SRC emacs-lisp :tangle init.el +(doom! :input + ;;chinese + ;;japanese + ;;layout ; auie,ctsrnm is the superior home row + + :completion + company ; the ultimate code completion backend + ;;helm ; the *other* search engine for love and life + ;;ido ; the other *other* search engine... + ;;ivy ; a search engine for love and life + vertico ; the search engine of the future + + :ui + ;;deft ; notational velocity for Emacs + doom ; what makes DOOM look the way it does + doom-dashboard ; a nifty splash screen for Emacs + doom-quit ; DOOM quit-message prompts when you quit Emacs + (emoji +unicode) ; 🙂 + hl-todo ; highlight TODO/FIXME/NOTE/DEPRECATED/HACK/REVIEW + ;;hydra + ;;indent-guides ; highlighted indent columns + ;;ligatures ; ligatures and symbols to make your code pretty again + ;;minimap ; show a map of the code on the side + modeline ; snazzy, Atom-inspired modeline, plus API + nav-flash ; blink cursor line after big motions + neotree ; a project drawer, like NERDTree for vim + ophints ; highlight the region an operation acts on + (popup +defaults) ; tame sudden yet inevitable temporary windows + ;;tabs ; a tab bar for Emacs + treemacs ; a project drawer, like neotree but cooler + unicode ; extended unicode support for various languages + vc-gutter ; vcs diff in the fringe + vi-tilde-fringe ; fringe tildes to mark beyond EOB + window-select ; visually switch windows + workspaces ; tab emulation, persistence & separate workspaces + ;;zen ; distraction-free coding or writing + + :editor + (evil +everywhere); come to the dark side, we have cookies + file-templates ; auto-snippets for empty files + fold ; (nigh) universal code folding + (format +onsave) ; automated prettiness + ;;god ; run Emacs commands without modifier keys + ;;lispy ; vim for lisp, for people who don't like vim + ;;multiple-cursors ; editing in many places at once + ;;objed ; text object editing for the innocent + ;;parinfer ; turn lisp into python, sort of + ;;rotate-text ; cycle region at point between text candidates + snippets ; my elves. They type so I don't have to + word-wrap ; soft wrapping with language-aware indent + + :emacs + (dired +ranger) ; making dired pretty [functional] + electric ; smarter, keyword-based electric-indent + ibuffer ; interactive buffer management + undo ; persistent, smarter undo for your inevitable mistakes + vc ; version-control and Emacs, sitting in a tree + + :term + eshell ; the elisp shell that works everywhere + ;;shell ; simple shell REPL for Emacs + ;;term ; basic terminal emulator for Emacs + vterm ; the best terminal emulation in Emacs + + :checkers + syntax ; tasing you for every semicolon you forget + (spell +flyspell) ; tasing you for misspelling mispelling + ;;grammar ; tasing grammar mistake every you make + + :tools + ;;ansible + ;;biblio ; Writes a PhD for you (citation needed) + ;;debugger ; FIXME stepping through code, to help you add bugs + ;;direnv + ;;docker + ;;editorconfig ; let someone else argue about tabs vs spaces + ;;ein ; tame Jupyter notebooks with emacs + (eval +overlay) ; run code, run (also, repls) + ;;gist ; interacting with github gists + lookup ; navigate your code and its documentation + lsp ; M-x vscode + magit ; a git porcelain for Emacs + ;;make ; run make tasks from Emacs + ;;pass ; password manager for nerds + ;;pdf ; pdf enhancements + ;;prodigy ; FIXME managing external services & code builders + rgb ; creating color strings + ;;taskrunner ; taskrunner for all your projects + ;;terraform ; infrastructure as code + ;;tmux ; an API for interacting with tmux + ;;upload ; map local to remote projects via ssh/ftp + + :os + ;;(:if IS-MAC macos) ; improve compatibility with macOS + tty ; improve the terminal Emacs experience + + :lang + ;;agda ; types of types of types of types... + ;;beancount ; mind the GAAP + cc ; C > C++ == 1 + ;;clojure ; java with a lisp + common-lisp ; if you've seen one lisp, you've seen them all + ;;coq ; proofs-as-programs + ;;crystal ; ruby at the speed of c + ;;csharp ; unity, .NET, and mono shenanigans + data ; config/data formats + ;;(dart +flutter) ; paint ui and not much else + ;;dhall + ;;elixir ; erlang done right + ;;elm ; care for a cup of TEA? + emacs-lisp ; drown in parentheses + ;;erlang ; an elegant language for a more civilized age + ;;ess ; emacs speaks statistics + ;;factor + ;;faust ; dsp, but you get to keep your soul + ;;fortran ; in FORTRAN, GOD is REAL (unless declared INTEGER) + ;;fsharp ; ML stands for Microsoft's Language + ;;fstar ; (dependent) types and (monadic) effects and Z3 + gdscript ; the language you waited for + ;;(go +lsp) ; the hipster dialect + (haskell +lsp) ; a language that's lazier than I am + ;;hy ; readability of scheme w/ speed of python + ;;idris ; a language you can depend on + json ; At least it ain't XML + ;;(java +meghanada) ; the poster child for carpal tunnel syndrome + ;;javascript ; all(hope(abandon(ye(who(enter(here)))))) + ;;julia ; a better, faster MATLAB + ;;kotlin ; a better, slicker Java(Script) + latex ; writing papers in Emacs has never been so fun + ;;lean ; for folks with too much to prove + ;;ledger ; be audit you can be + lua ; one-based indices? one-based indices + markdown ; writing docs for people to ignore + ;;nim ; python + lisp at the speed of c + ;;nix ; I hereby declare "nix geht mehr!" + ;;ocaml ; an objective camel + (org +roam2) ; organize your plain life in plain text + ;;php ; perl's insecure younger brother + ;;plantuml ; diagrams for confusing people more + ;;purescript ; javascript, but functional + python ; beautiful is better than ugly + ;;qt ; the 'cutest' gui framework ever + ;;racket ; a DSL for DSLs + ;;raku ; the artist formerly known as perl6 + ;;rest ; Emacs as a REST client + ;;rst ; ReST in peace + ;;(ruby +rails) ; 1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"} + ;;rust ; Fe2O3.unwrap().unwrap().unwrap().unwrap() + ;;scala ; java, but good + ;;(scheme +guile) ; a fully conniving family of lisps + sh ; she sells {ba,z,fi}sh shells on the C xor + ;;sml + ;;solidity ; do you need a blockchain? No. + ;;swift ; who asked for emoji variables? + ;;terra ; Earth and Moon in alignment for performance. + web ; the tubes + yaml ; JSON, but readable + ;;zig ; C, but simpler + + :email + ;;(mu4e +org) + ;;notmuch + ;;(wanderlust +gmail) + + :app + calendar + ;;emms + ;;everywhere ; *leave* Emacs!? You must be joking + ;;irc ; how neckbeards socialize + ;;(rss +org) ; emacs as an RSS reader + ;;twitter ; twitter client https://twitter.com/vnought + + :config + ;;literate + (default +bindings +smartparens)) + +#+END_SRC + +* My [[./packages.el][packages.el]] +The [[./packages.el][packages.el]] file allows extra packages to be configured outside of the typical Doom modules from [[./init.el][init.el]]. + +Packages are declared via =(package! some-package)= where =some-package= is from MELPA, ELPA, or emacsmirror. + +There are other ways to install packages outside of Emacs package archives, including directly from git. Installing a package directly from git requires a =:recipe=. Here is [[https://github.com/raxod502/straight.el#the-recipe-format][a full documentation of the recipe format]]. + +Doom's built-in packages can also be modified here: +- =(package! builtin-package :disable t)= to disable +- =(package! builtin-package-2 :recipe (:repo "myfork/package"))= to override the recipe + - Side-note: the full recipe for built-in packages does not need specification, as the override will inherit the unspecified properties directly from Doom + +Any git package can be configured for a particular commit or branch: +- =(package! builtin-package :recipe (:branch "develop")= for a particular branch +- =(package! builtin-package :pin "1a2b3c4d5e")= for a particular commit +- =(unpin! pinned-package another-pinned-package)= to get bleeding edge instead of Doom's stability + +#+BEGIN_SRC emacs-lisp :tangle packages.el +;;(package! org-bullets) +(package! org-modern) +(package! org-super-agenda) +(package! emacsql :pin "c1a4407") +(package! org-roam-ui) +(package! org-roam-nursery :recipe (:repo "https://github.com/chrisbarrett/nursery")) +(package! lister) +(package! org-download) +(package! org-yt) +(package! toc-org) +(package! all-the-icons-dired) +(package! all-the-icons-completion) +(package! ox-reveal) +(package! hledger-mode) +(package! rainbow-mode) +(package! crdt) +(package! ess) +(package! openwith) +(package! ob-mermaid) +(package! focus) +(package! olivetti) +#+END_SRC diff --git a/user/app/doom-emacs/init.el b/user/app/doom-emacs/init.el new file mode 100644 index 00000000..d9356c9f --- /dev/null +++ b/user/app/doom-emacs/init.el @@ -0,0 +1,175 @@ +(doom! :input + ;;chinese + ;;japanese + ;;layout ; auie,ctsrnm is the superior home row + + :completion + company ; the ultimate code completion backend + ;;helm ; the *other* search engine for love and life + ;;ido ; the other *other* search engine... + ;;ivy ; a search engine for love and life + vertico ; the search engine of the future + + :ui + ;;deft ; notational velocity for Emacs + doom ; what makes DOOM look the way it does + doom-dashboard ; a nifty splash screen for Emacs + doom-quit ; DOOM quit-message prompts when you quit Emacs + (emoji +unicode) ; 🙂 + hl-todo ; highlight TODO/FIXME/NOTE/DEPRECATED/HACK/REVIEW + ;;hydra + ;;indent-guides ; highlighted indent columns + ;;ligatures ; ligatures and symbols to make your code pretty again + ;;minimap ; show a map of the code on the side + modeline ; snazzy, Atom-inspired modeline, plus API + nav-flash ; blink cursor line after big motions + neotree ; a project drawer, like NERDTree for vim + ophints ; highlight the region an operation acts on + (popup +defaults) ; tame sudden yet inevitable temporary windows + ;;tabs ; a tab bar for Emacs + treemacs ; a project drawer, like neotree but cooler + unicode ; extended unicode support for various languages + vc-gutter ; vcs diff in the fringe + vi-tilde-fringe ; fringe tildes to mark beyond EOB + window-select ; visually switch windows + workspaces ; tab emulation, persistence & separate workspaces + ;;zen ; distraction-free coding or writing + + :editor + (evil +everywhere); come to the dark side, we have cookies + file-templates ; auto-snippets for empty files + fold ; (nigh) universal code folding + (format +onsave) ; automated prettiness + ;;god ; run Emacs commands without modifier keys + ;;lispy ; vim for lisp, for people who don't like vim + ;;multiple-cursors ; editing in many places at once + ;;objed ; text object editing for the innocent + ;;parinfer ; turn lisp into python, sort of + ;;rotate-text ; cycle region at point between text candidates + snippets ; my elves. They type so I don't have to + word-wrap ; soft wrapping with language-aware indent + + :emacs + (dired +ranger) ; making dired pretty [functional] + electric ; smarter, keyword-based electric-indent + ibuffer ; interactive buffer management + undo ; persistent, smarter undo for your inevitable mistakes + vc ; version-control and Emacs, sitting in a tree + + :term + eshell ; the elisp shell that works everywhere + ;;shell ; simple shell REPL for Emacs + ;;term ; basic terminal emulator for Emacs + vterm ; the best terminal emulation in Emacs + + :checkers + syntax ; tasing you for every semicolon you forget + (spell +flyspell) ; tasing you for misspelling mispelling + ;;grammar ; tasing grammar mistake every you make + + :tools + ;;ansible + ;;biblio ; Writes a PhD for you (citation needed) + ;;debugger ; FIXME stepping through code, to help you add bugs + ;;direnv + ;;docker + ;;editorconfig ; let someone else argue about tabs vs spaces + ;;ein ; tame Jupyter notebooks with emacs + (eval +overlay) ; run code, run (also, repls) + ;;gist ; interacting with github gists + lookup ; navigate your code and its documentation + lsp ; M-x vscode + magit ; a git porcelain for Emacs + ;;make ; run make tasks from Emacs + ;;pass ; password manager for nerds + ;;pdf ; pdf enhancements + ;;prodigy ; FIXME managing external services & code builders + rgb ; creating color strings + ;;taskrunner ; taskrunner for all your projects + ;;terraform ; infrastructure as code + ;;tmux ; an API for interacting with tmux + ;;upload ; map local to remote projects via ssh/ftp + + :os + ;;(:if IS-MAC macos) ; improve compatibility with macOS + tty ; improve the terminal Emacs experience + + :lang + ;;agda ; types of types of types of types... + ;;beancount ; mind the GAAP + cc ; C > C++ == 1 + ;;clojure ; java with a lisp + common-lisp ; if you've seen one lisp, you've seen them all + ;;coq ; proofs-as-programs + ;;crystal ; ruby at the speed of c + ;;csharp ; unity, .NET, and mono shenanigans + data ; config/data formats + ;;(dart +flutter) ; paint ui and not much else + ;;dhall + ;;elixir ; erlang done right + ;;elm ; care for a cup of TEA? + emacs-lisp ; drown in parentheses + ;;erlang ; an elegant language for a more civilized age + ;;ess ; emacs speaks statistics + ;;factor + ;;faust ; dsp, but you get to keep your soul + ;;fortran ; in FORTRAN, GOD is REAL (unless declared INTEGER) + ;;fsharp ; ML stands for Microsoft's Language + ;;fstar ; (dependent) types and (monadic) effects and Z3 + gdscript ; the language you waited for + ;;(go +lsp) ; the hipster dialect + (haskell +lsp) ; a language that's lazier than I am + ;;hy ; readability of scheme w/ speed of python + ;;idris ; a language you can depend on + json ; At least it ain't XML + ;;(java +meghanada) ; the poster child for carpal tunnel syndrome + ;;javascript ; all(hope(abandon(ye(who(enter(here)))))) + ;;julia ; a better, faster MATLAB + ;;kotlin ; a better, slicker Java(Script) + latex ; writing papers in Emacs has never been so fun + ;;lean ; for folks with too much to prove + ;;ledger ; be audit you can be + lua ; one-based indices? one-based indices + markdown ; writing docs for people to ignore + ;;nim ; python + lisp at the speed of c + ;;nix ; I hereby declare "nix geht mehr!" + ;;ocaml ; an objective camel + (org +roam2) ; organize your plain life in plain text + ;;php ; perl's insecure younger brother + ;;plantuml ; diagrams for confusing people more + ;;purescript ; javascript, but functional + python ; beautiful is better than ugly + ;;qt ; the 'cutest' gui framework ever + ;;racket ; a DSL for DSLs + ;;raku ; the artist formerly known as perl6 + ;;rest ; Emacs as a REST client + ;;rst ; ReST in peace + ;;(ruby +rails) ; 1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"} + ;;rust ; Fe2O3.unwrap().unwrap().unwrap().unwrap() + ;;scala ; java, but good + ;;(scheme +guile) ; a fully conniving family of lisps + sh ; she sells {ba,z,fi}sh shells on the C xor + ;;sml + ;;solidity ; do you need a blockchain? No. + ;;swift ; who asked for emoji variables? + ;;terra ; Earth and Moon in alignment for performance. + web ; the tubes + yaml ; JSON, but readable + ;;zig ; C, but simpler + + :email + ;;(mu4e +org) + ;;notmuch + ;;(wanderlust +gmail) + + :app + calendar + ;;emms + ;;everywhere ; *leave* Emacs!? You must be joking + ;;irc ; how neckbeards socialize + ;;(rss +org) ; emacs as an RSS reader + ;;twitter ; twitter client https://twitter.com/vnought + + :config + ;;literate + (default +bindings +smartparens)) diff --git a/user/app/doom-emacs/packages.el b/user/app/doom-emacs/packages.el new file mode 100644 index 00000000..2172feca --- /dev/null +++ b/user/app/doom-emacs/packages.el @@ -0,0 +1,21 @@ +;;(package! org-bullets) +(package! org-modern) +(package! org-super-agenda) +(package! emacsql :pin "c1a4407") +(package! org-roam-ui) +(package! org-roam-nursery :recipe (:repo "https://github.com/chrisbarrett/nursery")) +(package! lister) +(package! org-download) +(package! org-yt) +(package! toc-org) +(package! all-the-icons-dired) +(package! all-the-icons-completion) +(package! ox-reveal) +(package! hledger-mode) +(package! rainbow-mode) +(package! crdt) +(package! ess) +(package! openwith) +(package! ob-mermaid) +(package! focus) +(package! olivetti) diff --git a/user/app/doom-emacs/scripts/copy-link-or-file/copy-link-or-file-to-clipboard.sh b/user/app/doom-emacs/scripts/copy-link-or-file/copy-link-or-file-to-clipboard.sh new file mode 100755 index 00000000..85b3f064 --- /dev/null +++ b/user/app/doom-emacs/scripts/copy-link-or-file/copy-link-or-file-to-clipboard.sh @@ -0,0 +1,10 @@ +#!/bin/sh +#command -v xclip >/dev/null 2>&1 || { echo "Need command xclip. Aborting." >&2; exit 1; } +if [[ -f "$1" ]]; then + TYPE=$(file -b --mime-type "$1") + xclip -selection clipboard -t "$TYPE" -i "$1" +else + echo $1 | xclip -selection clipboard -t text/plain &> /dev/null + exit +fi +exit diff --git a/user/app/doom-emacs/scripts/ox-odp/ox-odp-xml-parse.py b/user/app/doom-emacs/scripts/ox-odp/ox-odp-xml-parse.py new file mode 100755 index 00000000..e4f34e0a --- /dev/null +++ b/user/app/doom-emacs/scripts/ox-odp/ox-odp-xml-parse.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python3 + +import xml.etree.ElementTree as ET +import copy + +# Read content.xml into parser +mytree = ET.parse('./content.xml') +myroot = mytree.getroot() + +# Read styles.xml into parser +styletree = ET.parse('./styles.xml') +styleroot = styletree.getroot() + +# Remove direct-formatting from text:style-name attributes in text:p elements +counter = 0 +for text in myroot.iter('{urn:oasis:names:tc:opendocument:xmlns:text:1.0}p'): + if '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name' in text.keys(): + stylename = text.attrib['{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name'] + if stylename[0] == "P": + counter += 1 + text.attrib.pop('{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name') +print('Deleted '+str(counter)+' text:style-name attributes in text:p elements.') + +# Remove direct-formatting from text:style-name attributes in text:span elements +counter = 0 +for span in myroot.iter('{urn:oasis:names:tc:opendocument:xmlns:text:1.0}span'): + if '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name' in span.keys(): + span.attrib.pop('{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name') +print('Deleted '+str(counter)+' text:style-name attributes in text:span elements.') + +# Remove direct-formatting from draw:text-style-name attributes in draw:frame elements +counter = 0 +for drawing in myroot.iter('{urn:oasis:names:tc:opendocument:xmlns:drawing:1.0}frame'): + if '{urn:oasis:names:tc:opendocument:xmlns:drawing:1.0}text-style-name' in drawing.keys(): + stylename = drawing.attrib['{urn:oasis:names:tc:opendocument:xmlns:drawing:1.0}text-style-name'] + if stylename[0] == "P": + counter += 1 + drawing.attrib.pop('{urn:oasis:names:tc:opendocument:xmlns:drawing:1.0}text-style-name') +print('Deleted '+str(counter)+' draw:text-style-name attributes in text:p elements.') + +# Redefine default styles (style:style elements) and purge unnecessary ones +counter = 0 +kounter = 0 +for style in myroot.iter('{urn:oasis:names:tc:opendocument:xmlns:style:1.0}style'): + if '{urn:oasis:names:tc:opendocument:xmlns:style:1.0}name' in style.keys(): + stylename = style.attrib['{urn:oasis:names:tc:opendocument:xmlns:style:1.0}name'] + if stylename == "pr1": + counter += 1 + style.set('{urn:oasis:names:tc:opendocument:xmlns:style:1.0}parent-style-name','DefaultTheme-title') + elif stylename == "pr2": + counter += 1 + style.set('{urn:oasis:names:tc:opendocument:xmlns:style:1.0}parent-style-name','DefaultTheme-subtitle') + elif stylename == "pr3": + counter += 1 + style.set('{urn:oasis:names:tc:opendocument:xmlns:style:1.0}parent-style-name','DefaultTheme-notes') + elif stylename == "pr4": + counter += 1 + style.set('{urn:oasis:names:tc:opendocument:xmlns:style:1.0}parent-style-name','DefaultTheme-outline1') +print('Redefined '+str(counter)+' style:parent-style-name attributes in style:style elements.') +print('Deleted '+str(kounter)+' style:style elements.') + +# Search for automatic-styles element +i = 0 +col1 = 0 +while (i < len(myroot)): + print(myroot[i].tag) + if myroot[i].tag=="{urn:oasis:names:tc:opendocument:xmlns:office:1.0}automatic-styles": + col1 = i + i += 1 + +# Remove unnecessary style:style and test:list-style elements underneath automatic-styles +i = 0 +while (i < len(myroot[col1])): + if (myroot[col1][i].tag == "{urn:oasis:names:tc:opendocument:xmlns:style:1.0}style"): + if ("{urn:oasis:names:tc:opendocument:xmlns:style:1.0}name" in myroot[col1][i].keys()): + if myroot[col1][i].attrib["{urn:oasis:names:tc:opendocument:xmlns:style:1.0}name"] in ["pr5","pr6","pr7","pr8","pr9"]: + print("Removing "+myroot[col1][i].tag) + myroot[col1].remove(myroot[col1][i]) + i -= 1 + elif myroot[col1][i].attrib["{urn:oasis:names:tc:opendocument:xmlns:style:1.0}name"][0] == "P": + print("Removing "+myroot[col1][i].tag) + myroot[col1].remove(myroot[col1][i]) + i -= 1 + if (myroot[col1][i].tag == "{urn:oasis:names:tc:opendocument:xmlns:text:1.0}list-style"): + print("Removing "+myroot[col1][i].tag) + myroot[col1].remove(myroot[col1][i]) + i -= 1 + i += 1 + +#i = 0 +#while (i < len(myroot[col1])): +# print(myroot[col1][i].attrib) +# i += 1 + +# Find ML1 in styles.xml and copy it into L1 in content.xml +# Search for automatic-styles element +i = 0 +stylecol1 = 0 +while (i < len(styleroot)): + print(styleroot[i].tag) + if styleroot[i].tag=="{urn:oasis:names:tc:opendocument:xmlns:office:1.0}automatic-styles": + stylecol1 = i + i += 1 + +# Remove unnecessary style:style and test:list-style elements underneath automatic-styles +i = 0 +while (i < len(styleroot[stylecol1])): + if (styleroot[stylecol1][i].tag == "{urn:oasis:names:tc:opendocument:xmlns:text:1.0}list-style"): + if (styleroot[stylecol1][i].attrib["{urn:oasis:names:tc:opendocument:xmlns:style:1.0}name"] == "ML1"): + liststyle_copy = copy.deepcopy(styleroot[stylecol1][i]) + myroot[col1].append(liststyle_copy) + myroot[col1][-1].attrib['{urn:oasis:names:tc:opendocument:xmlns:style:1.0}name'] = "L1" + i += 1 + +# Update presentation:style-name attribute of all draw:frame elements +counter = 0 +for frame in myroot.iter('{urn:oasis:names:tc:opendocument:xmlns:drawing:1.0}frame'): + if '{urn:oasis:names:tc:opendocument:xmlns:presentation:1.0}class' in frame.keys(): + classname = frame.attrib['{urn:oasis:names:tc:opendocument:xmlns:presentation:1.0}class'] + if classname == "title": + counter += 1 + frame.set('{urn:oasis:names:tc:opendocument:xmlns:presentation:1.0}style-name','pr1') + elif classname == "subtitle": + counter += 1 + frame.set('{urn:oasis:names:tc:opendocument:xmlns:presentation:1.0}style-name','pr2') + elif classname == "notes": + counter += 1 + frame.set('{urn:oasis:names:tc:opendocument:xmlns:presentation:1.0}style-name','pr3') + elif classname == "outline": + counter += 1 + frame.set('{urn:oasis:names:tc:opendocument:xmlns:presentation:1.0}style-name','pr4') +print("Updated "+str(counter)+" draw:frame elements") + +# Update draw:master-page-name attributes in all draw:page elements +# Also delete all presentation:presentation-page-layout attributes +counter = 0 +for page in myroot.iter('{urn:oasis:names:tc:opendocument:xmlns:drawing:1.0}page'): + if '{urn:oasis:names:tc:opendocument:xmlns:drawing:1.0}master-page-name' in page.keys(): + page.set('{urn:oasis:names:tc:opendocument:xmlns:drawing:1.0}master-page-name','DefaultTheme') + counter += 1 + if '{urn:oasis:names:tc:opendocument:xmlns:presentation:1.0}presentation-page-layout' in page.keys(): + page.attrib.pop('{urn:oasis:names:tc:opendocument:xmlns:presentation:1.0}presentation-page-layout') + +print("Updated "+str(counter)+" draw:page elements") + +# Update all text:list elements to have text:style-name = L1 +counter = 0 +for page in myroot.iter('{urn:oasis:names:tc:opendocument:xmlns:text:1.0}list'): + if '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name' in page.keys(): + page.set('{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name','L1') + counter += 1 + +print("Updated "+str(counter)+" text:list elements") + +#mytree.canonicalize(out='content.xml') +mytree.write('content.xml') +styletree.write('styles.xml') diff --git a/user/app/doom-emacs/scripts/ox-odp/ox-odp.sh b/user/app/doom-emacs/scripts/ox-odp/ox-odp.sh new file mode 100755 index 00000000..47dc7ce0 --- /dev/null +++ b/user/app/doom-emacs/scripts/ox-odp/ox-odp.sh @@ -0,0 +1,47 @@ +#!/bin/sh + +filename=$1 +echo $filename +stylefile=$2 +echo $stylefile + +filenamebase=$(basename "$filename") +filenameext="${filenamebase##*.}" +echo $filenameext + +if [ $filenameext = "org" ]; then + stylefilebase=$(basename "$stylefile") + stylefileext="${stylefilebase##*.}" + + if [ $stylefileext = "odp" ]; then + output="${filename//\.org/\.pptx}" + finaloutput="${filename//\.org/\.odp}" + pandoc "$filename" -o "$output" + soffice --convert-to odp "$output" + unzip "$finaloutput" content.xml + unzip "$stylefile" styles.xml + + sed 's~~~g' content.xml + sed 's~~~g' content.xml + + python3 ~/.doom.d/scripts/ox-odp/ox-odp-xml-parse.py + + zip -d $finaloutput styles.xml + zip -m $finaloutput styles.xml + + zip -d $finaloutput content.xml + zip -m $finaloutput content.xml + + rm $output + + exit + + else + echo "Style file is not an odp file." + fi +else + echo "Base file is not an org file." + exit +fi + +exit diff --git a/user/home.nix b/user/home.nix index 5c94a1a0..eca56af2 100644 --- a/user/home.nix +++ b/user/home.nix @@ -97,19 +97,6 @@ in lxappearance (pkgs.writeScriptBin "phoenix" myPhoenixScript) - # Doom emacs - emacs - binutils - (ripgrep.override {withPCRE2 = true;}) - gnutls - fd - imagemagick - zstd - nodePackages.javascript-typescript-langserver - sqlite - editorconfig-core-c - emacs-all-the-icons-fonts - # Office libreoffice-qt mate.atril @@ -358,6 +345,11 @@ in shellAliases = myAliases; }; + programs.doom-emacs = { + enable = true; + doomPrivateDir = ./app/doom-emacs; + }; + nixpkgs.overlays = [ (self: super: {