aboutsummaryrefslogtreecommitdiff
path: root/Emacs
diff options
context:
space:
mode:
Diffstat (limited to 'Emacs')
-rw-r--r--Emacs/.config/emacs/app.org787
-rw-r--r--Emacs/.config/emacs/config.org1534
-rw-r--r--Emacs/.config/emacs/core.org738
-rw-r--r--Emacs/.config/emacs/elisp/literate.el22
4 files changed, 1563 insertions, 1518 deletions
diff --git a/Emacs/.config/emacs/app.org b/Emacs/.config/emacs/app.org
new file mode 100644
index 0000000..46839d8
--- /dev/null
+++ b/Emacs/.config/emacs/app.org
@@ -0,0 +1,787 @@
+#+title: Applications for Emacs
+#+author: Aryadev Chavali
+#+description: Applications for my Emacs OS™
+#+date: 2023-09-29
+#+property: header-args:emacs-lisp :tangle app.el :comments link :results none
+#+options: toc:nil
+#+startup: noindent
+
+Applications are greater than packages; they provide a set of
+functionality to create an interface in Emacs. Emacs comes with
+applications and others may be installed.
+
+* WIP Dashboard
+:PROPERTIES:
+:header-args:emacs-lisp: :tangle no
+:END:
+Dashboard creates a custom dashboard for Emacs that replaces the
+initial startup screen in default Emacs. It has a lot of customising
+options.
+
+Unfortunately not that useful, many things are easier to invoke
+directly such as recent files or project changing.
+#+begin_src emacs-lisp
+(use-package dashboard
+ :straight t
+ :demand t
+ :general
+ (app-leader
+ "b" #'dashboard-refresh-buffer)
+ (:states '(normal motion emacs)
+ :keymaps 'dashboard-mode-map
+ "q" (proc (interactive) (kill-this-buffer)))
+ (nmmap
+ :keymaps 'dashboard-mode-map
+ "r" #'dashboard-jump-to-recent-files
+ "p" #'dashboard-jump-to-projects
+ "}" #'dashboard-next-section
+ "{" #'dashboard-previous-section)
+ :init
+ (setq initial-buffer-choice nil
+ dashboard-banner-logo-title "Oreomacs"
+ dashboard-center-content t
+ dashboard-set-init-info t
+ dashboard-startup-banner (no-littering-expand-etc-file-name "dashboard/logo.png")
+ dashboard-set-footer t
+ dashboard-set-navigator t
+ dashboard-items '((projects . 5)
+ (recents . 5))
+ dashboard-footer-messages (list
+ "Collecting parentheses..."
+ "Linking 'coffee_machine.o'..."
+ "Uploading ip to hacker named 4chan..."
+ "Dividing by zero..."
+ "Solving 3-sat..."
+ "Obtaining your health record..."
+ (format "Recompiling Emacs for the %dth time..." (random 1000))
+ "Escaping the cycle of samsara..."))
+ :config
+ (dashboard-setup-startup-hook))
+#+end_src
+* EWW
+Emacs Web Wowser is the inbuilt text based web browser for Emacs. It
+can render images and basic CSS styles but doesn't have a JavaScript
+engine, which makes sense as it's primarily a text interface.
+#+begin_src emacs-lisp
+(use-package eww
+ :defer t
+ :general
+ (app-leader
+ "w" #'eww)
+ :straight nil
+ :config
+ (with-eval-after-load "evil-collection"
+ (evil-collection-eww-setup)))
+#+end_src
+* Calendar
+Calendar is a simple inbuilt application that helps with date
+functionalities. I add functionality to copy dates from the calendar
+to the kill ring and bind it to "Y".
+#+begin_src emacs-lisp
+(use-package calendar
+ :straight nil
+ :defer t
+ :commands (+calendar/copy-date +calendar/toggle-calendar)
+ :display
+ ("\\*Calendar\\*"
+ (display-buffer-at-bottom)
+ (inhibit-duplicate-buffer . t)
+ (window-height . 0.17))
+ :general
+ (nmmap
+ :keymaps 'calendar-mode-map
+ "Y" #'+calendar/copy-date)
+ (app-leader
+ "d" #'+calendar/toggle-calendar)
+ :config
+ (defun +calendar/copy-date ()
+ "Copy date under cursor into kill ring."
+ (interactive)
+ (if (use-region-p)
+ (call-interactively #'kill-ring-save)
+ (let ((date (calendar-cursor-to-date)))
+ (when date
+ (setq date (encode-time 0 0 0 (nth 1 date) (nth 0 date) (nth 2 date)))
+ (kill-new (format-time-string "%Y-%m-%d" date))))))
+ (+oreo/create-toggle-function
+ +calendar/toggle-calendar
+ "*Calendar*"
+ calendar
+ nil))
+#+end_src
+* Mail
+Mail is a funny thing; most people use it just for business or
+advertising and it's come out of use in terms of personal
+communication in the west for the most part (largely due to "social"
+media applications). However, this isn't true for the open source and
+free software movement who heavily use mail for communication.
+
+Integrating mail into Emacs helps as I can send source code and
+integrate it into my workflow just a bit better.
+** Notmuch
+#+begin_src emacs-lisp
+(use-package notmuch
+ :defer t
+ :commands (notmuch +mail/flag-thread)
+ :general
+ (app-leader "m" #'notmuch)
+ (nmap
+ :keymaps 'notmuch-search-mode-map
+ "f" #'+mail/flag-thread)
+ :init
+ (defconst +mail/signature "---------------\nAryadev Chavali")
+ (defconst +mail/local-dir (concat user-emacs-directory ".mail/"))
+ (setq notmuch-show-logo nil
+ notmuch-search-oldest-first nil
+ notmuch-hello-sections '(notmuch-hello-insert-saved-searches
+ notmuch-hello-insert-alltags
+ notmuch-hello-insert-recent-searches)
+ notmuch-archive-tags '("-inbox" "-unread" "+archive")
+ mail-signature +mail/signature
+ mail-default-directory +mail/local-dir
+ mail-source-directory +mail/local-dir
+ message-signature +mail/signature
+ message-auto-save-directory +mail/local-dir
+ message-directory +mail/local-dir)
+
+ (defun +mail/sync-mail ()
+ "Sync mail via mbsync."
+ (interactive)
+ (start-process-shell-command "" nil "mbsync -a"))
+ (defun +mail/trash-junk ()
+ "Delete any mail in junk"
+ (interactive)
+ (start-process-shell-command "" nil "notmuch search --output=files --format=text0 tag:deleted tag:spam tag:trash tag:junk | xargs -r0 rm"))
+ :config
+ (defun +mail/flag-thread (&optional unflag beg end)
+ (interactive (cons current-prefix-arg (notmuch-interactive-region)))
+ (notmuch-search-tag
+ (notmuch-tag-change-list '("-inbox" "+flagged") unflag) beg end)
+ (when (eq beg end)
+ (notmuch-search-next-thread)))
+ (advice-add #'notmuch-poll-and-refresh-this-buffer :before
+#'+mail/sync-mail)
+ (advice-add #'notmuch-poll-and-refresh-this-buffer :after
+#'+mail/trash-junk)
+ (with-eval-after-load "evil-collection"
+ (evil-collection-notmuch-setup)))
+#+end_src
+** Smtpmail
+#+begin_src emacs-lisp
+(use-package smtpmail
+ :after notmuch
+ :commands mail-send
+ :custom
+ (smtpmail-smtp-server "mail.aryadevchavali.com")
+ (smtpmail-smtp-user "aryadev")
+ (smtpmail-smtp-service 587)
+ (smtpmail-stream-type 'starttls)
+ :init
+ (setq send-mail-function #'smtpmail-send-it
+ message-send-mail-function #'smtpmail-send-it))
+#+end_src
+* Dired
+Setup for dired. Make dired-hide-details-mode the default mode when
+using dired-mode, as it removes the clutter. Setup evil collection
+for dired (even though dired doesn't really conflict with evil, there
+are some corners I'd like to adjust).
+#+begin_src emacs-lisp
+(use-package dired
+ :straight nil
+ :commands (dired find-dired)
+ :hook
+ (dired-mode-hook . auto-revert-mode)
+ (dired-mode-hook . dired-hide-details-mode)
+ :init
+ (setq-default dired-listing-switches "-AFBl --group-directories-first"
+ dired-omit-files "^\\."
+ dired-dwim-target t)
+ (with-eval-after-load "evil-collection"
+ (evil-collection-dired-setup))
+ :general
+ (nmmap
+ :keymaps 'dired-mode-map
+ "T" #'dired-create-empty-file
+ "H" #'dired-up-directory
+ "L" #'dired-find-file)
+ (dir-leader
+ "f" #'find-dired
+ "d" #'dired
+ "D" #'dired-other-frame
+ "i" #'image-dired
+ "p" `((proc (interactive)
+ (dired "~/Text/PDFs/"))
+ :which-key "Open PDFs"))
+ :config
+ (defun +dired/insert-all-subdirectories ()
+ "Insert all subdirectories currently viewable."
+ (interactive)
+ (dired-mark-directories nil)
+ (dolist #'dired-insert-subdir (dired-get-marked-files))
+ (dired-unmark-all-marks))
+
+ (nmmap
+ :keymaps 'dired-mode-map
+ "SPC" nil
+ "SPC ," nil)
+
+ (nmmap
+ :keymaps 'image-dired-thumbnail-mode-map
+ "h" #'image-dired-backward-image
+ "l" #'image-dired-forward-image
+ "j" #'image-dired-next-line
+ "k" #'image-dired-previous-line
+ "H" #'image-dired-display-previous
+ "L" #'image-dired-display-next
+ "RET" #'image-dired-display-this
+ "m" #'image-dired-mark-thumb-original-file
+ "q" #'quit-window)
+
+ (local-leader
+ :keymaps 'dired-mode-map
+ "l" #'dired-maybe-insert-subdir
+ "m" #'dired-mark-files-regexp
+ "u" #'dired-undo))
+#+end_src
+
+** fd-dired
+Uses fd for finding file results in a directory: ~find-dired~ ->
+~fd-dired~.
+
+#+begin_src emacs-lisp
+(use-package fd-dired
+ :after dired
+ :straight t
+ :general
+ (dir-leader
+ "g" #'fd-dired))
+#+end_src
+* Xwidget
+Xwidget is a package which allows for the insertion of arbitrary
+xwidgets into Emacs through buffers. It must be compiled into Emacs
+so you might need to customise your install. One of its premier uses
+is in navigating the web which it provides through the function
+~xwidget-webkit-browse-url~. This renders a fully functional web
+browser within Emacs.
+
+Though I am not to keen on using Emacs to browse the web /via/ xwidget
+(EWW does a good job on its own), I am very interested in its
+capability to render pages with JavaScript, as it may come of use when
+doing web development. I can see the results of work very quickly
+without switching windows all within Emacs.
+** Xwidget Core
+#+begin_src emacs-lisp
+(use-package xwidget
+ :straight nil
+ :general
+ (app-leader
+ "u" #'xwidget-webkit-browse-url)
+ (nmmap
+ :keymaps 'xwidget-webkit-mode-map
+ "q" #'quit-window
+ "h" #'xwidget-webkit-scroll-backward
+ "j" #'xwidget-webkit-scroll-up
+ "k" #'xwidget-webkit-scroll-down
+ "l" #'xwidget-webkit-scroll-forward
+ "+" #'xwidget-webkit-zoom-in
+ "-" #'xwidget-webkit-zoom-out
+ (kbd "C-f") #'xwidget-webkit-scroll-up
+ (kbd "C-b") #'xwidget-webkit-scroll-down
+ "H" #'xwidget-webkit-back
+ "L" #'xwidget-webkit-forward
+ "gu" #'xwidget-webkit-browse-url
+ "gr" #'xwidget-webkit-reload
+ "gg" #'xwidget-webkit-scroll-top
+ "G" #'xwidget-webkit-scroll-bottom))
+#+end_src
+** Xwidget Extensions
+Define a function ~+xwidget/render-file~ that reads a file name and
+presents it in an xwidget. If the current file is an HTML file, ask
+if user wants to open current file. Bind it to ~aU~ in the leader.
+
+Also define a function ~+xwidget/search-query~ that first asks the
+user what search engine they want to use ([[https://duckduckgo.com][Duck Duck Go]] and [[https://devdocs.io][DevDocs]]
+currently) then asks for a query, which it parses then presents in an
+xwidget window. Bind to ~as~ in the leader.
+#+begin_src emacs-lisp
+(use-package xwidget
+ :straight nil
+ :commands (+xwidget/render-file +xwidget/search)
+ :general
+ (app-leader
+ "U" #'+xwidget/render-file
+ "s" #'+xwidget/search)
+ :config
+ (setenv "WEBKIT_FORCE_SANDBOX" "0")
+ (defun +xwidget/render-file (&optional FORCE)
+ "Find file (or use current file) and render in xwidget."
+ (interactive)
+ (cond
+ ((and (not FORCE) (or (string= (replace-regexp-in-string ".*.html"
+ "html" (buffer-name)) "html")
+ (eq major-mode 'web-mode)
+ (eq major-mode 'html-mode))) ; If in html file
+ (if (y-or-n-p "Open current file?: ") ; Maybe they want to open a separate file
+ (xwidget-webkit-browse-url (format "file://%s" (buffer-file-name)))
+ (+xwidget/render-file t))) ; recurse and open file via prompt
+ (t
+ (xwidget-webkit-browse-url
+ (format "file://%s" (read-file-name "Enter file to open: "))))))
+
+ (defun +xwidget/search ()
+ "Run a search query on some search engine and display in
+xwidget."
+ (interactive)
+ (let* ((engine (completing-read "Engine: " '("duckduckgo.com" "devdocs.io") nil t))
+ (query-raw (read-string "Enter query: "))
+ (query
+ (cond
+ ((string= engine "duckduckgo.com") query-raw)
+ ((string= engine "devdocs.io") (concat "_ " query-raw)))))
+ (xwidget-webkit-browse-url (concat "https://" engine "/?q=" query)))))
+#+end_src
+* Eshell
+** Why Eshell?
+Eshell is an integrated shell environment for Emacs, written in Emacs
+Lisp. I argue that it is the best shell/command interpreter to use in
+Emacs.
+
+Eshell is unlike the alternatives in Emacs as it's a /shell/ first,
+not a terminal emulator. It has the ability to spoof some aspects of a
+terminal emulator (through the shell parser), but it is NOT a terminal
+emulator.
+
+The killer benefits of eshell (which would appeal to Emacs users) are
+a direct result of eshell being written in Emacs lisp:
+- incredible integration with Emacs utilities (such as ~dired~,
+ ~find-file~, any read functions, to name a few)
+- very extensible, easy to write new commands which leverage Emacs
+ commands as well as external utilities
+- agnostic of platform: "eshell/cd" will call the underlying change
+ directory function for you, so commands will (usually) mean the same
+ thing regardless of platform
+ - this means as long as Emacs runs, you can run eshell
+
+However, my favourite feature of eshell is the set of evaluators that
+run on command input. Some of the benefits listed above come as a
+result of this powerful feature. These evaluators are described below.
+
+Lisp evaluator: works on braced expressions, evaluating them as Lisp
+expressions (e.g. ~(message "Hello, World!\n")~). Any returned
+objects are printed. This makes eshell a LISP REPL!
+
+External evaluator: works within curly braces, evaluating them via
+some external shell process (like sh) (e.g. ~{echo "Hello,
+world!\n"}~). This makes eshell a (kinda dumb) terminal emulator!
+
+The alias evaluator is the top level evaluator. It is the main
+evaluator for each expression given to eshell. When given an
+expression it tries to evaluate it by testing against these conditions:
+- it's an alias defined by the user or in the ~eshell/~ namespace of
+ functions (simplest evaluator)
+- it's some form of lisp expression (lisp evaluator)
+- it's an external command (bash evaluator)
+Essentially, you get the best of both Emacs and external shell
+programs *ALL WITHIN* Emacs for free.
+** Eshell functionality
+Bind some evil-like movements for easy shell usage, and a toggle
+function to pull up the eshell quickly.
+#+begin_src emacs-lisp
+(use-package eshell
+ :commands +shell/toggle-eshell
+ :general
+ (shell-leader
+ "t" #'+shell/toggle-eshell)
+ :init
+ (add-hook
+ 'eshell-mode-hook
+ (proc
+ (interactive)
+ (general-def
+ :states '(normal insert)
+ :keymaps 'eshell-mode-map
+ "M-l" (proc (interactive) (eshell/clear)
+ "M-j" #'eshell-next-matching-input-from-input
+ "M-k" #'eshell-previous-matching-input-from-input)
+ (local-leader
+ :keymaps 'eshell-mode-map
+ "c" (proc (interactive) (eshell/clear)
+ (recenter))
+ "k" #'eshell-kill-process))))
+ :config
+ (+oreo/create-toggle-function
+ +shell/toggle-eshell
+ "*eshell*"
+ eshell
+ t))
+#+end_src
+** Eshell pretty symbols and display
+Pretty symbols and a display record.
+#+begin_src emacs-lisp
+(use-package eshell
+ :defer t
+ :pretty
+ (eshell-mode-hook
+ ("lambda" . "λ")
+ ("numberp" . "ℤ")
+ ("t" . "⊨")
+ ("nil" . "Ø"))
+ :display
+ ("\\*e?shell\\*" ; for general shells as well
+ (display-buffer-at-bottom)
+ (window-height . 0.25)))
+#+end_src
+** Eshell variables and aliases
+Set some sane defaults, a banner and a prompt. The prompt checks for
+a git repo in the current directory and provides some extra
+information in that case (in particular, branch name and if there any
+changes that haven't been committed).
+
+Also add ~eshell/goto~, which is actually a command accessible from
+within eshell (this is because ~eshell/*~ creates an accessible
+function within eshell with name ~*~). ~eshell/goto~ makes it easier
+to change directories by using Emacs' find-file interface (which is
+much faster than ~cd ..; ls -l~).
+#+begin_src emacs-lisp
+(use-package eshell
+ :config
+ (defun +eshell/get-git-properties ()
+ (let* ((git-branch (shell-command-to-string "git branch"))
+ (is-repo (string= (if (string= git-branch "") ""
+ (substring git-branch 0 1)) "*")))
+ (if (not is-repo) ""
+ (concat
+ "("
+ (nth 2 (split-string git-branch "\n\\|\\*\\| "))
+ "<"
+ (if (string= "" (shell-command-to-string "git status | grep 'up to date'"))
+ "×"
+ "✓")
+ ">)"))))
+ (setq eshell-cmpl-ignore-case t
+ eshell-cd-on-directory t
+ eshell-banner-message (concat (shell-command-to-string "figlet eshell") "\n")
+ eshell-prompt-function
+ (proc
+ (let ((properties (+eshell/get-git-properties)))
+ (concat
+ properties
+ (format "[%s]\n" (abbreviate-file-name (eshell/pwd)))
+ "λ ")))
+ eshell-prompt-regexp "^λ ")
+
+ (defun eshell/goto (&rest args)
+ "Use `read-directory-name' to change directories."
+ (eshell/cd (list (read-directory-name "Enter directory to go to:")))))
+#+end_src
+** Eshell change directory quickly
+~eshell/goto~ is a better ~cd~ for eshell. However it is really just
+a plaster over a bigger issue for my workflow; many times I want
+eshell to be present in the current directory of the buffer I am
+using.
+
+#+begin_src emacs-lisp
+(use-package eshell
+ :straight nil
+ :general
+ (shell-leader
+ "T" #'+eshell/current-buffer)
+ :config
+ (defun +eshell/current-buffer ()
+ (interactive)
+ (let ((dir (if buffer-file-name
+ (file-name-directory buffer-file-name)
+ (if default-directory
+ default-directory
+ nil)))
+ (buf (eshell)))
+ (if dir
+ (with-current-buffer buf
+ (eshell/cd dir)
+ (eshell-send-input))
+ (message "Could not switch eshell: buffer is not real file")))))
+#+end_src
+* Elfeed
+Elfeed is the perfect RSS feed reader, integrated into Emacs
+perfectly. I've got a set of feeds that I use for a large variety of
+stuff, mostly media and entertainment. I've also bound "<leader> ar"
+to elfeed for loading the system.
+#+begin_src emacs-lisp
+(use-package elfeed
+ :general
+ (app-leader "r" #'elfeed)
+ (nmmap
+ :keymaps 'elfeed-search-mode-map
+ "gr" #'elfeed-update
+ "s" #'elfeed-search-live-filter
+ "<return>" #'elfeed-search-show-entry)
+ :init
+ (setq elfeed-db-directory (no-littering-expand-var-file-name "elfeed/"))
+ (setq +rss/feed-urls
+ '(("Arch Linux"
+ "https://www.archlinux.org/feeds/news/"
+ Linux)
+ ("LEMMiNO"
+ "https://www.youtube.com/feeds/videos.xml?channel_id=UCRcgy6GzDeccI7dkbbBna3Q"
+ YouTube Stories)
+ ("The Onion"
+ "https://www.theonion.com/rss"
+ Social)
+ ("Stack exchange"
+ "http://morss.aryadevchavali.com/stackexchange.com/feeds/questions"
+ Social)
+ ("Dark Sominium"
+ "https://www.youtube.com/feeds/videos.xml?channel_id=UC_e39rWdkQqo5-LbiLiU10g"
+ YouTube Stories)
+ ("Dark Sominium Music"
+ "https://www.youtube.com/feeds/videos.xml?channel_id=UCkLiZ_zLynyNd5fd62hg1Kw"
+ YouTube Music)
+ ("Nexpo"
+ "https://www.youtube.com/feeds/videos.xml?channel_id=UCpFFItkfZz1qz5PpHpqzYBw"
+ YouTube)
+ ("Techquickie"
+ "https://www.youtube.com/feeds/videos.xml?channel_id=UC0vBXGSyV14uvJ4hECDOl0Q"
+ YouTube)
+ ("3B1B"
+ "https://www.youtube.com/feeds/videos.xml?channel_id=UCYO_jab_esuFRV4b17AJtAw"
+ YouTube)
+ ("Fredrik Knusden"
+ "https://www.youtube.com/feeds/videos.xml?channel_id=UCbWcXB0PoqOsAvAdfzWMf0w"
+ YouTube Stories)
+ ("Barely Sociable"
+ "https://www.youtube.com/feeds/videos.xml?channel_id=UC9PIn6-XuRKZ5HmYeu46AIw"
+ YouTube Stories)
+ ("Atrocity Guide"
+ "https://www.youtube.com/feeds/videos.xml?channel_id=UCn8OYopT9e8tng-CGEWzfmw"
+ YouTube Stories)
+ ("Hacker News"
+ "http://morss.aryadevchavali.com/news.ycombinator.com/rss"
+ Social)
+ ("Hacker Factor"
+ "https://www.hackerfactor.com/blog/index.php?/feeds/index.rss2"
+ Social)
+ ("BBC Top News"
+ "http://morss.aryadevchavali.com/feeds.bbci.co.uk/news/rss.xml"
+ News)
+ ("BBC Tech News"
+ "http://morss.aryadevchavali.com/feeds.bbci.co.uk/news/technology/rss.xml"
+ News)))
+ :config
+ (with-eval-after-load "evil-collection"
+ (evil-collection-elfeed-setup))
+ (setq elfeed-feeds (cl-map 'list #'(lambda (item)
+ (append (list (nth 1 item)) (cdr (cdr item))))
+ +rss/feed-urls)))
+#+end_src
+* Magit
+Magit is *the* git porcelain for Emacs, which perfectly encapsulates
+the git cli. In this case I just need to setup the bindings for it.
+As magit will definitely load after evil (as it must be run by a
+binding, and evil will load after init), I can use evil-collection
+freely. Also, define an auto insert for commit messages so that I
+don't need to write everything myself.
+
+#+begin_src emacs-lisp
+(use-package magit
+ :defer t
+ :display
+ ("magit:.*"
+ (display-buffer-same-window)
+ (inhibit-duplicate-buffer . t))
+ ("magit-diff:.*"
+ (display-buffer-below-selected))
+ ("magit-log:.*"
+ (display-buffer-same-window))
+ :general
+ (leader
+ "g" '(magit-dispatch :which-key "Magit")
+ "vf" '(magit-file-dispatch :which-key "Magit file")
+ "vb" '(magit-blame :which-key "Magit blame"))
+ (code-leader
+ "b" #'magit-blame)
+ :auto-insert
+ (("COMMIT_EDITMSG" . "Commit skeleton")
+ ""
+ "(" (read-string "Enter feature/module: ") ")"
+ (read-string "Enter simple description: ") "\n\n")
+ :init
+ (setq vc-follow-symlinks t
+ magit-blame-echo-style 'lines)
+ :config
+ (with-eval-after-load "evil"
+ (evil-set-initial-state 'magit-status-mode 'motion))
+ (with-eval-after-load "evil-collection"
+ (evil-collection-magit-setup)))
+#+end_src
+* IBuffer
+#+begin_src emacs-lisp
+(use-package ibuffer
+ :general
+ (buffer-leader
+ "i" #'ibuffer)
+ :config
+ (with-eval-after-load "evil-collection"
+ (evil-collection-ibuffer-setup)))
+#+end_src
+* Processes
+Emacs has two systems for process management:
++ proced: a general 'top' like interface which allows general
+ management of linux processes
++ list-processes: a specific Emacs based system that lists processes
+ spawned by Emacs (similar to a top for Emacs specifically)
+
+** Proced
+Core proced config, just a few bindings and evil collection setup.
+#+begin_src emacs-lisp
+(use-package proced
+ :straight nil
+ :general
+ (app-leader
+ "p" #'proced)
+ (nmap
+ :keymaps 'proced-mode-map
+ "za" #'proced-toggle-auto-update)
+ :display
+ ("\\*Proced\\*"
+ (display-buffer-at-bottom)
+ (window-height . 0.25))
+ :init
+ (setq proced-auto-update-interval 0.5)
+ :config
+ (with-eval-after-load "evil-collection"
+ (evil-collection-proced-setup)))
+#+end_src
+
+Along with that I setup the package ~proced-narrow~ which allows
+further filtering of the process list.
+#+begin_src emacs-lisp
+(use-package proced-narrow
+ :straight t
+ :after proced
+ :general
+ (nmap
+ :keymaps 'proced-mode-map
+ "%" #'proced-narrow))
+#+end_src
+* Calculator
+Surprise, surprise Emacs comes with a calculator.
+
+Greater surprise, this thing is over powered. It can perform the
+following (and more):
+- Matrix calculations
+- Generalised calculus operations
+- Equation solvers for n-degree multi-variable polynomials
+- Embedded mode (check below)!
+
+~calc-mode~ is a calculator system within Emacs that provides a
+diverse array of mathematical operations. It uses reverse polish
+notation to do calculations (though there is a standard infix
+algebraic notation mode).
+
+Embedded mode allows computation with the current buffer as the echo
+area. This basically means I can compute stuff within a buffer
+without invoking calc directly: $1 + 2\rightarrow_{\text{calc-embed}} 3$.
+
+#+begin_src emacs-lisp
+(use-package calc
+ :straight nil
+ :display
+ ("*Calculator*"
+ (display-buffer-at-bottom)
+ (window-height . 0.18))
+ :general
+ (app-leader
+ "c" #'calc-dispatch)
+ (mode-leader
+ "c" #'calc-embedded)
+ :init
+ (setq calc-algebraic-mode t)
+ :config
+ (with-eval-after-load "evil-collection"
+ (evil-collection-calc-setup)))
+#+end_src
+** WIP Calctex
+:PROPERTIES:
+:header-args:emacs-lisp: :tangle no
+:END:
+~calc-mode~ also has a 3rd party package called ~calctex~. It renders
+mathematical expressions within calc as if they were rendered in TeX.
+You can also copy the expressions in their TeX forms, which is pretty
+useful when writing a paper. I've set a very specific lock on this
+repository as it's got quite a messy work-tree and this commit seems to
+work for me given the various TeX utilities installed via Arch.
+
+#+begin_src emacs-lisp
+(use-package calctex
+ :after calc
+ :straight (calctex :type git :host github :repo "johnbcoughlin/calctex")
+ :hook (calc-mode-hook . calctex-mode))
+#+end_src
+* Ledger
+#+begin_src emacs-lisp
+(use-package ledger-mode
+ :defer t)
+
+(use-package evil-ledger
+ :after ledger-mode)
+#+end_src
+* WIP Zone
+:PROPERTIES:
+:header-args:emacs-lisp: :tangle no
+:END:
+Of course Emacs has a cool screensaver software.
+
+#+begin_src emacs-lisp
+(use-package zone-matrix
+ :straight t
+ :after dashboard
+ :init
+ (setq zone-programs
+ [zone-pgm-jitter
+ zone-pgm-putz-with-case
+ zone-pgm-dissolve
+ zone-pgm-whack-chars
+ zone-pgm-drip
+ zone-pgm-rat-race
+ zone-pgm-random-life
+ zone-matrix
+ ])
+ :config
+ (zone-when-idle 15))
+#+end_src
+* (Wo)man
+Man pages are the user manuals for most software on Linux. Really
+useful when writing code for Un*x systems, though they can be very
+verbose.
+
+2023-08-17: `Man-notify-method' is the reason the `:display' record
+doesn't work here. I think it's to do with how Man pages are rendered
+or something, but very annoying as it's a break from standards!
+#+begin_src emacs-lisp
+(use-package man
+ :demand t
+ :straight nil
+ :init
+ (setq Man-notify-method 'pushy)
+ :display
+ ("^\\*Man.*"
+ (display-buffer-reuse-mode-window display-buffer-same-window))
+ :general
+ (file-leader
+ "m" #'man) ;; kinda like "find man page"
+ (nmmap
+ :keymaps 'Man-mode-map
+ "RET" #'man-follow))
+#+end_src
+* gif-screencast
+Little application that uses =gifsicle= to make essentially videos of
+Emacs. Useful for demonstrating features.
+#+begin_src emacs-lisp
+(use-package gif-screencast
+ :straight t
+ :general
+ (app-leader
+ "x" #'gif-screencast-start-or-stop)
+ :init
+ (setq gif-screencast-output-directory (expand-file-name "~/Media/emacs/")))
+#+end_src
diff --git a/Emacs/.config/emacs/config.org b/Emacs/.config/emacs/config.org
index 7e09fba..d2116e3 100644
--- a/Emacs/.config/emacs/config.org
+++ b/Emacs/.config/emacs/config.org
@@ -389,748 +389,12 @@ Eww who uses a mouse?
#+begin_src emacs-lisp
(setq use-file-dialog nil)
#+end_src
-* Core packages
-Packages that are absolutely necessary for the rest of the
-configuration. These yield core functionality such as keybinding,
-modal editing, completion, auto typing to name a few.
-** General
-General provides a great solution for binding keys. It has evil and
-use-package support so it fits nicely into configuration. In this
-case, I define a "definer" for the "LEADER" keys. Leader is bound to
-~SPC~ and it's functionally equivalent to the doom/spacemacs leader.
-Local leader is bound to ~SPC ,~ and it's similar to doom/spacemacs
-leader but doesn't try to fully assimilate the local-leader map,
-instead just picking stuff I think is useful. This forces me to learn
-only as many bindings as I find necessary; no more, no less.
-
-I also define prefix leaders for differing applications. These are
-quite self explanatory by their name and provide a nice way to
-visualise all bindings under a specific heading just by searching the
-code.
-#+begin_src emacs-lisp
-(use-package general
- :demand t
- :config
- ;; General which key definitions for leaders
- (general-def
- :states '(normal motion)
- "SPC" 'nil
- "\\" '(nil :which-key "Local leader")
- "SPC c" '(nil :which-key "Code")
- "SPC f" '(nil :which-key "File")
- "SPC t" '(nil :which-key "Shell")
- "SPC m" '(nil :which-key "Toggle modes")
- "SPC a" '(nil :which-key "Applications")
- "SPC s" '(nil :which-key "Search")
- "SPC b" '(nil :which-key "Buffers")
- "SPC q" '(nil :which-key "Quit/Literate")
- "SPC i" '(nil :which-key "Insert")
- "SPC d" '(nil :which-key "Directories"))
-
- (general-create-definer leader
- :states '(normal motion)
- :keymaps 'override
- :prefix "SPC")
-
- (general-create-definer local-leader
- :states '(normal motion)
- :prefix "\\")
-
- (general-create-definer code-leader
- :states '(normal motion)
- :keymaps 'override
- :prefix "SPC c")
-
- (general-create-definer file-leader
- :states '(normal motion)
- :keymaps 'override
- :prefix "SPC f")
-
- (general-create-definer shell-leader
- :states '(normal motion)
- :keymaps 'override
- :prefix "SPC t")
-
- (general-create-definer mode-leader
- :states '(normal motion)
- :keymaps 'override
- :prefix "SPC m")
-
- (general-create-definer app-leader
- :states '(normal motion)
- :keymaps 'override
- :prefix "SPC a")
-
- (general-create-definer search-leader
- :states '(normal motion)
- :keymaps 'override
- :prefix "SPC s")
-
- (general-create-definer buffer-leader
- :states '(normal motion)
- :keymaps 'override
- :prefix "SPC b")
-
- (general-create-definer quit-leader
- :states '(normal motion)
- :keymaps 'override
- :prefix "SPC q")
-
- (general-create-definer insert-leader
- :states '(normal motion)
- :keymaps 'override
- :prefix "SPC i")
-
- (general-create-definer dir-leader
- :states '(normal motion)
- :keymaps 'override
- :prefix "SPC d")
-
- (general-create-definer general-nmmap
- :states '(normal motion))
-
- (defalias 'nmmap #'general-nmmap)
-
- (general-evil-setup t))
-#+end_src
-*** Some binds in Emacs
-Some bindings that I couldn't fit elsewhere easily.
-#+begin_src emacs-lisp
-(use-package emacs
- :straight nil
- :general
- (general-def
- "C-x d" #'delete-frame)
-
- (nmmap
- "C--" #'text-scale-decrease
- "C-=" #'text-scale-increase)
-
- (leader
- "SPC" '(execute-extended-command :which-key "M-x")
- "'" '(browse-url-emacs :which-key "Open url in Emacs")
- ";" 'eval-expression
- ":" `(,(proc (interactive) (switch-to-buffer "*scratch*"))
- :which-key "Switch to *scratch*")
- "!" '(async-shell-command :which-key "Async shell command")
- "h" '(help-command :which-key "Help"))
-
- (mode-leader
- "t" #'+oreo/switch-theme)
-
- (code-leader
- "F" `(,(proc (interactive) (find-file "~/Code/"))
- :which-key "Open ~/Code/"))
-
- (file-leader
- "f" #'find-file
- "F" #'find-file-other-frame
- "s" #'save-buffer
- "p" `(,(proc (interactive)
- (find-file (concat user-emacs-directory "config.org")))
- :which-key "Open config.org"))
-
- (quit-leader
- "q" #'save-buffers-kill-terminal
- "c" #'+literate/compile-config
- "l" #'+literate/load-config
- "d" #'delete-frame)
-
- (search-leader "i" #'imenu))
-#+end_src
-** Evil
-My editor journey started off with Vim rather than Emacs, so my brain
-has imprinted on its style. Thankfully Emacs is super extensible so
-there exists a package (more of a supreme system) for porting Vim's
-modal editing style to Emacs, called Evil (Emacs Vi Layer).
-
-However there are a lot of packages in Vim that provide greater
-functionality, for example 'vim-surround'. Emacs, by default, has
-these capabilities but there are further packages which integrate them
-into Evil.
-*** Evil core
-Setup the evil package, with some opinionated keybindings:
-- Switch ~evil-upcase~ and ~evil-downcase~ because I use ~evil-upcase~
- more
-- Switch ~evil-goto-mark~ and ~evil-goto-mark-line~ as I'd rather have
- the global one closer to the home row
-- Use 'T' character as an action for transposing objects
-#+begin_src emacs-lisp
-(use-package evil
- :demand t
- :hook (after-init-hook . evil-mode)
- :general
- (leader
- "w" '(evil-window-map :which-key "Window")
- "wd" #'delete-frame)
-
- (nmmap
- "TAB" #'evil-jump-item
- "r" #'evil-replace-state
- "zC" #'hs-hide-level
- "zO" #'hs-show-all
- "'" #'evil-goto-mark
- "`" #'evil-goto-mark-line
- "C-w" #'evil-window-map
- "gu" #'evil-upcase
- "gU" #'evil-downcase
- "T" nil)
-
- (nmmap
- :infix "T"
- "w" #'transpose-words
- "c" #'transpose-chars
- "s" #'transpose-sentences
- "p" #'transpose-paragraphs
- "e" #'transpose-sexps
- "l" #'transpose-lines)
- :init
- (setq evil-want-keybinding nil
- evil-split-window-below t
- evil-vsplit-window-right t
- evil-want-abbrev-expand-on-insert-exit t
- evil-undo-system #'undo-tree)
- :config
- (fset #'evil-window-vsplit #'make-frame))
-#+end_src
-*** Evil surround
-Evil surround is a port for vim-surround.
-#+begin_src emacs-lisp
-(use-package evil-surround
- :after evil
- :config
- (global-evil-surround-mode))
-#+end_src
-*** Evil commentary
-Allows generalised commenting of objects easily.
-#+begin_src emacs-lisp
-(use-package evil-commentary
- :after evil
- :config
- (evil-commentary-mode))
-#+end_src
-*** Evil multi cursor
-Setup for multi cursors in Evil mode. Don't let evil-mc setup it's own
-keymap because it uses 'gr' as its prefix, which I don't like.
-#+begin_src emacs-lisp
-(use-package evil-mc
- :after evil
- :init
- (defvar evil-mc-key-map (make-sparse-keymap))
- :general
- (nmap
- :infix "gz"
- "q" #'evil-mc-undo-all-cursors
- "d" #'evil-mc-make-and-goto-next-match
- "j" #'evil-mc-make-cursor-move-next-line
- "k" #'evil-mc-make-cursor-move-prev-line
- "j" #'evil-mc-make-cursor-move-next-line
- "m" #'evil-mc-make-all-cursors
- "z" #'evil-mc-make-cursor-here
- "r" #'evil-mc-resume-cursors
- "s" #'evil-mc-pause-cursors
- "u" #'evil-mc-undo-last-added-cursor)
- :config
- ;; (evil-mc-define-vars)
- ;; (evil-mc-initialize-vars)
- ;; (add-hook 'evil-mc-before-cursors-created #'evil-mc-pause-incompatible-modes)
- ;; (add-hook 'evil-mc-before-cursors-created #'evil-mc-initialize-active-state)
- ;; (add-hook 'evil-mc-after-cursors-deleted #'evil-mc-teardown-active-state)
- ;; (add-hook 'evil-mc-after-cursors-deleted #'evil-mc-resume-incompatible-modes)
- ;; (advice-add #'evil-mc-initialize-hooks :override #'ignore)
- ;; (advice-add #'evil-mc-teardown-hooks :override #'evil-mc-initialize-vars)
- ;; (advice-add #'evil-mc-initialize-active-state :before #'turn-on-evil-mc-mode)
- ;; (advice-add #'evil-mc-teardown-active-state :after #'turn-off-evil-mc-mode)
- ;; (add-hook 'evil-insert-state-entry-hook #'evil-mc-resume-cursors)
- (global-evil-mc-mode))
-#+end_src
-
-*** Evil collection
-Provides a community based set of keybindings for most modes in
-Emacs. I don't necessarily like all my modes having these bindings
-though, as I may disagree with some. So I use it in a mode to mode basis.
-#+begin_src emacs-lisp
-(use-package evil-collection
- :after evil)
-#+end_src
-** Completion
-Emacs is a text based interface. Completion is its bread and butter
-in providing good user experience. By default Emacs provides
-'completions-list' which produces a buffer of options which can be
-searched and selected. We can take this further though!
-
-Ido and Icomplete are packages distributed with Emacs to provide
-greater completion interfaces. They utilise the minibuffer to create
-a more interactive experience, allowing incremental searches and
-option selection.
-
-Ivy and Helm provide more modern interfaces, though Helm is quite
-heavy. Ivy, on the other hand, provides an interface similar to Ido
-with less clutter and better customisation options.
-*** Ivy
-Ivy is a completion framework for Emacs, and my preferred one. It has
-a great set of features with little to no pain with setting up.
-**** Ivy Core
-Setup for ivy, in preparation for counsel. Turn on ivy-mode just
-after init.
-
-Setup vim-like bindings for the minibuffer ("M-(j|k)" for down|up the
-selection list).
-#+begin_src emacs-lisp
-(use-package ivy
- :defer t
- :hook (after-init-hook . ivy-mode)
- :general
- (general-def
- :keymaps 'ivy-minibuffer-map
- "C-j" #'ivy-yank-symbol
- "M-j" #'ivy-next-line-or-history
- "M-k" #'ivy-previous-line-or-history
- "C-SPC" #'ivy-occur)
- (general-def
- :keymaps 'ivy-switch-buffer-map
- "M-j" #'ivy-next-line-or-history
- "M-k" #'ivy-previous-line-or-history)
- (nmap
- :keymaps '(ivy-occur-mode-map ivy-occur-grep-mode-map)
- "RET" #'ivy-occur-press-and-switch
- "J" #'ivy-occur-press
- "gr" #'ivy-occur-revert-buffer
- "q" #'quit-window
- "D" #'ivy-occur-delete-candidate
- "W" #'ivy-wgrep-change-to-wgrep-mode
- "{" #'compilation-previous-file
- "}" #'compilation-next-file)
- :init
- (with-eval-after-load "evil"
- (evil-set-initial-state 'ivy-occur-mode 'normal)
- (evil-set-initial-state 'ivy-occur-grep-mode 'normal))
- (with-eval-after-load "amx"
- (setq amx-backend 'ivy))
-
- (setq ivy-height 10
- ivy-wrap t
- ivy-fixed-height-minibuffer t
- ivy-use-virtual-buffers nil
- ivy-virtual-abbreviate 'full
- ivy-on-del-error-function #'ignore
- ivy-use-selectable-prompt t)
- :config
- (require 'counsel nil t))
-#+end_src
-**** Counsel
-Setup for counsel. Load after ivy and helpful.
-#+begin_src emacs-lisp
-(use-package counsel
- :defer t
- :general
- (search-leader
- "s" #'counsel-grep-or-swiper
- "r" #'counsel-rg)
- (file-leader
- "r" #'counsel-recentf)
- (insert-leader
- "c" #'counsel-unicode-char)
- (general-def
- [remap describe-bindings] #'counsel-descbinds
- [remap load-theme] #'counsel-load-theme)
- :config
- (setq ivy-initial-inputs-alist '((org-insert-link . "^"))
- counsel-describe-function-function #'helpful-callable
- counsel-describe-variable-function #'helpful-variable
- counsel-grep-swiper-limit 1500000
- ivy-re-builders-alist '((swiper . ivy--regex-plus)
- (counsel-grep-or-swiper . ivy--regex-plus)
- (counsel-rg . ivy--regex-plus)
- (t . ivy--regex-ignore-order)))
- (counsel-mode))
-#+end_src
-**** WIP Ivy posframe
-:PROPERTIES:
-:header-args:emacs-lisp: :tangle no
-:END:
-This makes ivy minibuffer windows use child frames.
-Very nice eyecandy, but can get kinda annoying.
-#+begin_src emacs-lisp
-(use-package ivy-posframe
- :hook (ivy-mode-hook . ivy-posframe-mode)
- :straight t
- :init
- (setq ivy-posframe-parameters
- '((left-fringe . 0)
- (right-fringe . 0)
- (background-color . "grey7")))
-
- (setq ivy-posframe-display-functions-alist
- '((t . ivy-posframe-display-at-window-center))))
-#+end_src
-**** WIP Counsel etags
-:PROPERTIES:
-:header-args:emacs-lisp: :tangle no
-:END:
-Counsel etags allows me to search generated tag files for tags. I
-already have a function defined to generate the tags, so it's just
-searching them which I find to be a bit of a hassle, and where this
-package comes in.
-
-This has been replaced by [[*xref][xref]] which is inbuilt.
-#+begin_src emacs-lisp
-(use-package counsel-etags
- :after counsel
- :general
- (search-leader
- "t" #'counsel-etags-find-tag))
-#+end_src
-*** WIP Ido
-:PROPERTIES:
-:header-args:emacs-lisp: :tangle no
-:END:
-Ido is a very old completion package that still works great to this
-day. Though it is limited in its scope (and may thus be called a
-completion add-on rather than a full on framework), it is still a very
-powerful package. With the use of ido-completing-read+, it may be used
-similarly to a fully fledged completion framework.
-
-#+begin_src emacs-lisp
-(use-package ido
- :demand t
- :general
- (general-def
- :keymaps '(ido-buffer-completion-map
- ido-file-completion-map
- ido-file-dir-completion-map
- ido-common-completion-map)
- (kbd "M-j") #'ido-next-match
- (kbd "M-k") #'ido-prev-match
- (kbd "C-x o") #'evil-window-up)
- :init
- (setq ido-decorations
- (list "{" "}" " \n" " ..." "[" "]" " [No match]" " [Matched]"
- " [Not readable]" " [Too big]" " [Confirm]")
- completion-styles '(flex partial-completion intials emacs22))
- (setq-default ido-enable-flex-matching t
- ido-enable-dot-prefix t
- ido-enable-regexp nil)
- (with-eval-after-load "magit"
- (setq magit-completing-read-function 'magit-ido-completing-read))
- :config
- (ido-mode)
- (ido-everywhere))
-#+end_src
-**** Ido ubiquitous
-Ido completing-read+ is a package that extends the ido package to work
-with more text based functions.
-#+begin_src emacs-lisp
-(use-package ido-completing-read+
- :after ido
- :config
- (ido-ubiquitous-mode +1))
-#+end_src
-*** Amx
-Amx is a fork of Smex that works to enhance the
-execute-extended-command interface. It also provides support for ido
-or ivy (though I'm likely to use ido here) and allows you to switch
-between them.
-
-It provides a lot of niceties such as presenting the key bind when
-looking for a command.
-
-#+begin_src emacs-lisp
-(use-package amx
- :config
- (amx-mode))
-#+end_src
-*** Orderless
-Orderless sorting method for completion, probably one of the best
-things ever.
-#+begin_src emacs-lisp
-(use-package orderless
- :after (ivy ido)
- :config
- (setf (alist-get t ivy-re-builders-alist) 'orderless-ivy-re-builder))
-#+end_src
-*** Completions-list
-In case I ever use the completions list, some basic commands to look
-around.
-#+begin_src emacs-lisp
-(use-package simple
- :straight nil
- :general
- (nmmap
- :keymaps 'completion-list-mode-map
- "l" #'next-completion
- "h" #'previous-completion
- "ESC" #'delete-completion-window
- "q" #'quit-window
- "RET" #'choose-completion)
- :config
- (with-eval-after-load "evil"
- (setq evil-emacs-state-modes (cl-remove-if
- #'(lambda (x) (eq 'completions-list-mode x))
- evil-emacs-state-modes))
- (add-to-list 'evil-normal-state-modes 'completions-list-mode)))
-#+end_src
-*** Company
-Company is the auto complete system I use. I don't like having heavy
-setups for company as it only makes it slower to use. In this case,
-just setup some evil binds for company.
-#+begin_src emacs-lisp
-(use-package company
- :straight t
- :hook
- (prog-mode-hook . company-mode)
- (eshell-mode-hook . company-mode)
- :general
- (imap
- "C-SPC" #'company-complete)
- (general-def
- :states '(normal insert)
- "M-j" #'company-select-next
- "M-k" #'company-select-previous))
-#+end_src
-** Pretty symbols
-Prettify symbols mode allows for users to declare 'symbols' that
-replace text within certain modes. Though this may seem like useless
-eye candy, it has aided my comprehension and speed of recognition
-(recognising symbols is easier than words).
-
-Essentially a use-package keyword which makes declaring pretty symbols
-for language modes incredibly easy. Checkout my [[C/C++][C/C++]] configuration
-for an example.
-#+begin_src emacs-lisp
-(use-package prog-mode
- :straight nil
- :init
- (setq prettify-symbols-unprettify-at-point t)
- :config
- (with-eval-after-load "use-package-core"
- (add-to-list 'use-package-keywords ':pretty)
- (defun use-package-normalize/:pretty (_name-symbol _keyword args)
- args)
-
- (defun use-package-handler/:pretty (name _keyword args rest state)
- (use-package-concat
- (use-package-process-keywords name rest state)
- (mapcar
- #'(lambda (arg)
- (let ((mode (car arg))
- (rest (cdr arg)))
- `(add-hook
- ',mode
- #'(lambda nil
- (setq prettify-symbols-alist ',rest)
- (prettify-symbols-mode)))))
- args)))))
-#+end_src
-
-Here's a collection of keywords and possible associated symbols for
-any prog language of choice. Mostly for reference and copying.
-#+begin_example
-("null" . "Ø")
-("list" . "ℓ")
-("string" . "𝕊")
-("true" . "⊤")
-("false" . "⊥")
-("char" . "ℂ")
-("int" . "ℤ")
-("float" . "ℝ")
-("!" . "¬")
-("&&" . "∧")
-("||" . "∨")
-("for" . "∀")
-("return" . "⟼")
-("print" . "ℙ")
-("lambda" . "λ")
-#+end_example
-** Window management
-Emacs' default window management is quite bad, eating other windows on
-a whim and not particularly caring for the current window setup.
-Thankfully you can change this via the ~display-buffer-alist~ which
-matches buffer names with how the window for the buffer should be
-displayed. I add a use-package keyword to make ~display-buffer-alist~
-records within use-package.
-
-I have no idea whether it's optimal AT ALL, but it works for me.
-#+begin_src emacs-lisp
-(use-package window
- :straight nil
- :general
- (buffer-leader
- "b" #'switch-to-buffer
- "d" #'kill-current-buffer
- "K" #'kill-buffer
- "j" #'next-buffer
- "k" #'previous-buffer
- "D" '(+oreo/clean-buffer-list :which-key "Kill most buffers"))
- :init
- (with-eval-after-load "use-package-core"
- (add-to-list 'use-package-keywords ':display)
- (defun use-package-normalize/:display (_name-symbol _keyword args)
- args)
-
- (defun use-package-handler/:display (name _keyword args rest state)
- (use-package-concat
- (use-package-process-keywords name rest state)
- (mapcar
- #'(lambda (arg)
- `(add-to-list 'display-buffer-alist
- ',arg))
- args)))))
-#+end_src
-*** Some display records
-Using the ~:display~ keyword, setup up some ~display-buffer-alist~
-records. This is mostly for packages that aren't really configured
-(like [[info:woman][woman]]) or packages that were configured before
-(like [[Ivy][Ivy]]).
-#+begin_src emacs-lisp
-(use-package window
- :straight nil
- :defer t
- :display
- ("\\*Process List\\*"
- (display-buffer-at-bottom)
- (window-height . 0.25))
-
- ("\\*\\(Ido \\)?Completions\\*"
- (display-buffer-in-side-window)
- (window-height . 0.25)
- (side . bottom))
-
- ("\\*ivy-occur.*"
- (display-buffer-at-bottom)
- (window-height . 0.25))
-
- ("\\*Async Shell Command\\*"
- (display-buffer-at-bottom)
- (window-height . 0.25)))
-#+end_src
-** Auto typing
-Snippets are a pretty nice way of automatically inserting code. Emacs
-provides a ton of packages by default to do this, but there are great
-packages to install as well.
-
-Abbrevs and skeletons make up a popular solution within Emacs default.
-Abbrevs are for simple expressions wherein the only input is the key,
-and the output is some Elisp function. They provide a lot of inbuilt
-functionality and are quite useful. Skeletons, on the other hand, are
-for higher level insertions
-
-The popular external solution is Yasnippet. Yasnippet is a great
-package for snippets, which I use heavily in programming and org-mode.
-I setup here the global mode for yasnippet and a collection of
-snippets for ease of use.
-*** Abbrevs
-Just define a few abbrevs for various date-time operations. Also
-define a macro that will assume a function for the expansion, helping
-with abstracting a few things away.
-#+begin_src emacs-lisp
-(use-package abbrev
- :straight nil
- :hook
- (prog-mode-hook . abbrev-mode)
- (text-mode-hook . abbrev-mode)
- :init
- (defmacro +abbrev/define-abbrevs (abbrev-table &rest abbrevs)
- `(progn
- ,@(mapcar #'(lambda (abbrev)
- `(define-abbrev
- ,abbrev-table
- ,(car abbrev)
- ""
- (proc (insert ,(cadr abbrev)))))
- abbrevs)))
- (setq save-abbrevs nil)
- :config
- (+abbrev/define-abbrevs
- global-abbrev-table
- ("sdate"
- (format-time-string "%Y-%m-%d" (current-time)))
- ("stime"
- (format-time-string "%H:%M:%S" (current-time)))
- ("sday"
- (format-time-string "%A" (current-time)))
- ("smon"
- (format-time-string "%B" (current-time)))))
-#+end_src
-*** WIP Skeletons
-:PROPERTIES:
-:header-args:emacs-lisp: :tangle no
-:END:
-Defines a macro for generating a skeleton + abbrev for a given mode.
-Doesn't sanitise inputs because I assume callers are /rational/ actors
-who would *only* use this for their top level Emacs config.
-
-Honestly didn't find much use for this currently, so disabled.
+* Core packages (loading)
+For my core packages, whose configuration doesn't change much anyway,
+I have a [[file:core.org][separate file]]. Here I'll load it up for
+usage later on.
#+begin_src emacs-lisp
-(use-package skeleton
- :straight nil
- :after abbrev
- :config
- (defmacro +autotyping/gen-skeleton-abbrev (mode abbrev &rest skeleton)
- (let* ((table (intern (concat (symbol-name mode) "-abbrev-table")))
- (skeleton-name (intern (concat "+skeleton/" (symbol-name mode) "/" abbrev))))
- `(progn
- (define-skeleton
- ,skeleton-name
- ""
- ,@skeleton)
- (define-abbrev ,table
- ,abbrev
- ""
- ',skeleton-name)))))
-#+end_src
-*** Auto insert
-Allows inserting text immediately upon creating a new buffer with a
-given name. Supports skeletons for inserting text. To make it easier
-for later systems to define their own auto inserts, I define a
-~use-package~ keyword ~auto-insert~ which allows one to define an
-entry for ~auto-insert-alist~.
-#+begin_src emacs-lisp
-(use-package autoinsert
- :straight nil
- :demand t
- :hook (after-init-hook . auto-insert-mode)
- :config
- (with-eval-after-load "use-package-core"
- (add-to-list 'use-package-keywords ':auto-insert)
- (defun use-package-normalize/:auto-insert (_name-symbol _keyword args)
- args)
- (defun use-package-handler/:auto-insert (name _keyword args rest state)
- (use-package-concat
- (use-package-process-keywords name rest state)
- (mapcar
- #'(lambda (arg)
- `(add-to-list
- 'auto-insert-alist
- ',arg))
- args)))))
-#+end_src
-*** Yasnippet default
-Look at the snippets [[file:.config/yasnippet/snippets/][folder]] for
-all snippets I've got.
-#+begin_src emacs-lisp
-(use-package yasnippet
- :defer t
- :hook
- (prog-mode-hook . yas-minor-mode)
- :general
- (insert-leader
- "i" #'yas-insert-snippet)
- :config
- (yas-load-directory (no-littering-expand-etc-file-name "yasnippet/snippets")))
-#+end_src
-** Licensing
-Loads [[file:elisp/license.el][license.el]] for inserting licenses.
-Licenses are important for distribution and attribution to be defined clearly.
-#+begin_src emacs-lisp
-(use-package license
- :straight nil
- :load-path "elisp/"
- :demand t
- :general
- (insert-leader
- "l" #'+license/insert-copyright-notice
- "L" #'+license/insert-complete-license))
+(load-file (concat user-emacs-directory "core.el"))
#+end_src
* Small packages
** ISearch
@@ -1460,784 +724,28 @@ text. That's what this is mainly for.
(mode-leader
"r" #'toggle-rot13-mode))
#+end_src
-* Applications
-Applications are greater than packages; they provide a set of
-functionality to create an interface in Emacs. Emacs comes with
-applications and others may be installed.
-** WIP Dashboard
-:PROPERTIES:
-:header-args:emacs-lisp: :tangle no
-:END:
-Dashboard creates a custom dashboard for Emacs that replaces the
-initial startup screen in default Emacs. It has a lot of customising
-options.
-
-Unfortunately not that useful, many things are easier to invoke
-directly such as recent files or project changing.
-#+begin_src emacs-lisp
-(use-package dashboard
- :straight t
- :demand t
- :general
- (app-leader
- "b" #'dashboard-refresh-buffer)
- (:states '(normal motion emacs)
- :keymaps 'dashboard-mode-map
- "q" (proc (interactive) (kill-this-buffer)))
- (nmmap
- :keymaps 'dashboard-mode-map
- "r" #'dashboard-jump-to-recent-files
- "p" #'dashboard-jump-to-projects
- "}" #'dashboard-next-section
- "{" #'dashboard-previous-section)
- :init
- (setq initial-buffer-choice nil
- dashboard-banner-logo-title "Oreomacs"
- dashboard-center-content t
- dashboard-set-init-info t
- dashboard-startup-banner (no-littering-expand-etc-file-name "dashboard/logo.png")
- dashboard-set-footer t
- dashboard-set-navigator t
- dashboard-items '((projects . 5)
- (recents . 5))
- dashboard-footer-messages (list
- "Collecting parentheses..."
- "Linking 'coffee_machine.o'..."
- "Uploading ip to hacker named 4chan..."
- "Dividing by zero..."
- "Solving 3-sat..."
- "Obtaining your health record..."
- (format "Recompiling Emacs for the %dth time..." (random 1000))
- "Escaping the cycle of samsara..."))
- :config
- (dashboard-setup-startup-hook))
-#+end_src
-** EWW
-Emacs Web Wowser is the inbuilt text based web browser for Emacs. It
-can render images and basic CSS styles but doesn't have a JavaScript
-engine, which makes sense as it's primarily a text interface.
-#+begin_src emacs-lisp
-(use-package eww
- :defer t
- :general
- (app-leader
- "w" #'eww)
- :straight nil
- :config
- (with-eval-after-load "evil-collection"
- (evil-collection-eww-setup)))
-#+end_src
-** Calendar
-Calendar is a simple inbuilt application that helps with date
-functionalities. I add functionality to copy dates from the calendar
-to the kill ring and bind it to "Y".
-#+begin_src emacs-lisp
-(use-package calendar
- :straight nil
- :defer t
- :commands (+calendar/copy-date +calendar/toggle-calendar)
- :display
- ("\\*Calendar\\*"
- (display-buffer-at-bottom)
- (inhibit-duplicate-buffer . t)
- (window-height . 0.17))
- :general
- (nmmap
- :keymaps 'calendar-mode-map
- "Y" #'+calendar/copy-date)
- (app-leader
- "d" #'+calendar/toggle-calendar)
- :config
- (defun +calendar/copy-date ()
- "Copy date under cursor into kill ring."
- (interactive)
- (if (use-region-p)
- (call-interactively #'kill-ring-save)
- (let ((date (calendar-cursor-to-date)))
- (when date
- (setq date (encode-time 0 0 0 (nth 1 date) (nth 0 date) (nth 2 date)))
- (kill-new (format-time-string "%Y-%m-%d" date))))))
- (+oreo/create-toggle-function
- +calendar/toggle-calendar
- "*Calendar*"
- calendar
- nil))
-#+end_src
-** Mail
-Mail is a funny thing; most people use it just for business or
-advertising and it's come out of use in terms of personal
-communication in the west for the most part (largely due to "social"
-media applications). However, this isn't true for the open source and
-free software movement who heavily use mail for communication.
-
-Integrating mail into Emacs helps as I can send source code and
-integrate it into my workflow just a bit better.
-*** Notmuch
-#+begin_src emacs-lisp
-(use-package notmuch
- :defer t
- :commands (notmuch +mail/flag-thread)
- :general
- (app-leader "m" #'notmuch)
- (nmap
- :keymaps 'notmuch-search-mode-map
- "f" #'+mail/flag-thread)
- :init
- (defconst +mail/signature "---------------\nAryadev Chavali")
- (defconst +mail/local-dir (concat user-emacs-directory ".mail/"))
- (setq notmuch-show-logo nil
- notmuch-search-oldest-first nil
- notmuch-hello-sections '(notmuch-hello-insert-saved-searches
- notmuch-hello-insert-alltags
- notmuch-hello-insert-recent-searches)
- notmuch-archive-tags '("-inbox" "-unread" "+archive")
- mail-signature +mail/signature
- mail-default-directory +mail/local-dir
- mail-source-directory +mail/local-dir
- message-signature +mail/signature
- message-auto-save-directory +mail/local-dir
- message-directory +mail/local-dir)
-
- (defun +mail/sync-mail ()
- "Sync mail via mbsync."
- (interactive)
- (start-process-shell-command "" nil "mbsync -a"))
- (defun +mail/trash-junk ()
- "Delete any mail in junk"
- (interactive)
- (start-process-shell-command "" nil "notmuch search --output=files --format=text0 tag:deleted tag:spam tag:trash tag:junk | xargs -r0 rm"))
- :config
- (defun +mail/flag-thread (&optional unflag beg end)
- (interactive (cons current-prefix-arg (notmuch-interactive-region)))
- (notmuch-search-tag
- (notmuch-tag-change-list '("-inbox" "+flagged") unflag) beg end)
- (when (eq beg end)
- (notmuch-search-next-thread)))
- (advice-add #'notmuch-poll-and-refresh-this-buffer :before
-#'+mail/sync-mail)
- (advice-add #'notmuch-poll-and-refresh-this-buffer :after
-#'+mail/trash-junk)
- (with-eval-after-load "evil-collection"
- (evil-collection-notmuch-setup)))
-#+end_src
-*** Smtpmail
-#+begin_src emacs-lisp
-(use-package smtpmail
- :after notmuch
- :commands mail-send
- :custom
- (smtpmail-smtp-server "mail.aryadevchavali.com")
- (smtpmail-smtp-user "aryadev")
- (smtpmail-smtp-service 587)
- (smtpmail-stream-type 'starttls)
- :init
- (setq send-mail-function #'smtpmail-send-it
- message-send-mail-function #'smtpmail-send-it))
-#+end_src
-** Dired
-Setup for dired. Make dired-hide-details-mode the default mode when
-using dired-mode, as it removes the clutter. Setup evil collection
-for dired (even though dired doesn't really conflict with evil, there
-are some corners I'd like to adjust).
-#+begin_src emacs-lisp
-(use-package dired
- :straight nil
- :commands (dired find-dired)
- :hook
- (dired-mode-hook . auto-revert-mode)
- (dired-mode-hook . dired-hide-details-mode)
- :init
- (setq-default dired-listing-switches "-AFBl --group-directories-first"
- dired-omit-files "^\\."
- dired-dwim-target t)
- (with-eval-after-load "evil-collection"
- (evil-collection-dired-setup))
- :general
- (nmmap
- :keymaps 'dired-mode-map
- "T" #'dired-create-empty-file
- "H" #'dired-up-directory
- "L" #'dired-find-file)
- (dir-leader
- "f" #'find-dired
- "d" #'dired
- "D" #'dired-other-frame
- "i" #'image-dired
- "p" `((proc (interactive)
- (dired "~/Text/PDFs/"))
- :which-key "Open PDFs"))
- :config
- (defun +dired/insert-all-subdirectories ()
- "Insert all subdirectories currently viewable."
- (interactive)
- (dired-mark-directories nil)
- (dolist #'dired-insert-subdir (dired-get-marked-files))
- (dired-unmark-all-marks))
-
- (nmmap
- :keymaps 'dired-mode-map
- "SPC" nil
- "SPC ," nil)
-
- (nmmap
- :keymaps 'image-dired-thumbnail-mode-map
- "h" #'image-dired-backward-image
- "l" #'image-dired-forward-image
- "j" #'image-dired-next-line
- "k" #'image-dired-previous-line
- "H" #'image-dired-display-previous
- "L" #'image-dired-display-next
- "RET" #'image-dired-display-this
- "m" #'image-dired-mark-thumb-original-file
- "q" #'quit-window)
-
- (local-leader
- :keymaps 'dired-mode-map
- "l" #'dired-maybe-insert-subdir
- "m" #'dired-mark-files-regexp
- "u" #'dired-undo))
-#+end_src
-
-*** fd-dired
-Uses fd for finding file results in a directory: ~find-dired~ ->
-~fd-dired~.
-
-#+begin_src emacs-lisp
-(use-package fd-dired
- :after dired
- :straight t
- :general
- (dir-leader
- "g" #'fd-dired))
-#+end_src
-** Xwidget
-Xwidget is a package which allows for the insertion of arbitrary
-xwidgets into Emacs through buffers. It must be compiled into Emacs
-so you might need to customise your install. One of its premier uses
-is in navigating the web which it provides through the function
-~xwidget-webkit-browse-url~. This renders a fully functional web
-browser within Emacs.
-
-Though I am not to keen on using Emacs to browse the web /via/ xwidget
-(EWW does a good job on its own), I am very interested in its
-capability to render pages with JavaScript, as it may come of use when
-doing web development. I can see the results of work very quickly
-without switching windows all within Emacs.
-*** Xwidget Core
-#+begin_src emacs-lisp
-(use-package xwidget
- :straight nil
- :general
- (app-leader
- "u" #'xwidget-webkit-browse-url)
- (nmmap
- :keymaps 'xwidget-webkit-mode-map
- "q" #'quit-window
- "h" #'xwidget-webkit-scroll-backward
- "j" #'xwidget-webkit-scroll-up
- "k" #'xwidget-webkit-scroll-down
- "l" #'xwidget-webkit-scroll-forward
- "+" #'xwidget-webkit-zoom-in
- "-" #'xwidget-webkit-zoom-out
- (kbd "C-f") #'xwidget-webkit-scroll-up
- (kbd "C-b") #'xwidget-webkit-scroll-down
- "H" #'xwidget-webkit-back
- "L" #'xwidget-webkit-forward
- "gu" #'xwidget-webkit-browse-url
- "gr" #'xwidget-webkit-reload
- "gg" #'xwidget-webkit-scroll-top
- "G" #'xwidget-webkit-scroll-bottom))
-#+end_src
-*** Xwidget Extensions
-Define a function ~+xwidget/render-file~ that reads a file name and
-presents it in an xwidget. If the current file is an HTML file, ask
-if user wants to open current file. Bind it to ~aU~ in the leader.
-
-Also define a function ~+xwidget/search-query~ that first asks the
-user what search engine they want to use ([[https://duckduckgo.com][Duck Duck Go]] and [[https://devdocs.io][DevDocs]]
-currently) then asks for a query, which it parses then presents in an
-xwidget window. Bind to ~as~ in the leader.
-#+begin_src emacs-lisp
-(use-package xwidget
- :straight nil
- :commands (+xwidget/render-file +xwidget/search)
- :general
- (app-leader
- "U" #'+xwidget/render-file
- "s" #'+xwidget/search)
- :config
- (setenv "WEBKIT_FORCE_SANDBOX" "0")
- (defun +xwidget/render-file (&optional FORCE)
- "Find file (or use current file) and render in xwidget."
- (interactive)
- (cond
- ((and (not FORCE) (or (string= (replace-regexp-in-string ".*.html"
- "html" (buffer-name)) "html")
- (eq major-mode 'web-mode)
- (eq major-mode 'html-mode))) ; If in html file
- (if (y-or-n-p "Open current file?: ") ; Maybe they want to open a separate file
- (xwidget-webkit-browse-url (format "file://%s" (buffer-file-name)))
- (+xwidget/render-file t))) ; recurse and open file via prompt
- (t
- (xwidget-webkit-browse-url
- (format "file://%s" (read-file-name "Enter file to open: "))))))
-
- (defun +xwidget/search ()
- "Run a search query on some search engine and display in
-xwidget."
- (interactive)
- (let* ((engine (completing-read "Engine: " '("duckduckgo.com" "devdocs.io") nil t))
- (query-raw (read-string "Enter query: "))
- (query
- (cond
- ((string= engine "duckduckgo.com") query-raw)
- ((string= engine "devdocs.io") (concat "_ " query-raw)))))
- (xwidget-webkit-browse-url (concat "https://" engine "/?q=" query)))))
-#+end_src
-** Eshell
-*** Why Eshell?
-Eshell is an integrated shell environment for Emacs, written in Emacs
-Lisp. I argue that it is the best shell/command interpreter to use in
-Emacs.
-
-Eshell is unlike the alternatives in Emacs as it's a /shell/ first,
-not a terminal emulator. It has the ability to spoof some aspects of a
-terminal emulator (through the shell parser), but it is NOT a terminal
-emulator.
-
-The killer benefits of eshell (which would appeal to Emacs users) are
-a direct result of eshell being written in Emacs lisp:
-- incredible integration with Emacs utilities (such as ~dired~,
- ~find-file~, any read functions, to name a few)
-- very extensible, easy to write new commands which leverage Emacs
- commands as well as external utilities
-- agnostic of platform: "eshell/cd" will call the underlying change
- directory function for you, so commands will (usually) mean the same
- thing regardless of platform
- - this means as long as Emacs runs, you can run eshell
-
-However, my favourite feature of eshell is the set of evaluators that
-run on command input. Some of the benefits listed above come as a
-result of this powerful feature. These evaluators are described below.
-
-Lisp evaluator: works on braced expressions, evaluating them as Lisp
-expressions (e.g. ~(message "Hello, World!\n")~). Any returned
-objects are printed. This makes eshell a LISP REPL!
-
-External evaluator: works within curly braces, evaluating them via
-some external shell process (like sh) (e.g. ~{echo "Hello,
-world!\n"}~). This makes eshell a (kinda dumb) terminal emulator!
-
-The alias evaluator is the top level evaluator. It is the main
-evaluator for each expression given to eshell. When given an
-expression it tries to evaluate it by testing against these conditions:
-- it's an alias defined by the user or in the ~eshell/~ namespace of
- functions (simplest evaluator)
-- it's some form of lisp expression (lisp evaluator)
-- it's an external command (bash evaluator)
-Essentially, you get the best of both Emacs and external shell
-programs *ALL WITHIN* Emacs for free.
-*** Eshell functionality
-Bind some evil-like movements for easy shell usage, and a toggle
-function to pull up the eshell quickly.
-#+begin_src emacs-lisp
-(use-package eshell
- :commands +shell/toggle-eshell
- :general
- (shell-leader
- "t" #'+shell/toggle-eshell)
- :init
- (add-hook
- 'eshell-mode-hook
- (proc
- (interactive)
- (general-def
- :states '(normal insert)
- :keymaps 'eshell-mode-map
- "M-l" (proc (interactive) (eshell/clear)
- "M-j" #'eshell-next-matching-input-from-input
- "M-k" #'eshell-previous-matching-input-from-input)
- (local-leader
- :keymaps 'eshell-mode-map
- "c" (proc (interactive) (eshell/clear)
- (recenter))
- "k" #'eshell-kill-process))))
- :config
- (+oreo/create-toggle-function
- +shell/toggle-eshell
- "*eshell*"
- eshell
- t))
-#+end_src
-*** Eshell pretty symbols and display
-Pretty symbols and a display record.
-#+begin_src emacs-lisp
-(use-package eshell
- :defer t
- :pretty
- (eshell-mode-hook
- ("lambda" . "λ")
- ("numberp" . "ℤ")
- ("t" . "⊨")
- ("nil" . "Ø"))
- :display
- ("\\*e?shell\\*" ; for general shells as well
- (display-buffer-at-bottom)
- (window-height . 0.25)))
-#+end_src
-*** Eshell variables and aliases
-Set some sane defaults, a banner and a prompt. The prompt checks for
-a git repo in the current directory and provides some extra
-information in that case (in particular, branch name and if there any
-changes that haven't been committed).
-
-Also add ~eshell/goto~, which is actually a command accessible from
-within eshell (this is because ~eshell/*~ creates an accessible
-function within eshell with name ~*~). ~eshell/goto~ makes it easier
-to change directories by using Emacs' find-file interface (which is
-much faster than ~cd ..; ls -l~).
-#+begin_src emacs-lisp
-(use-package eshell
- :config
- (defun +eshell/get-git-properties ()
- (let* ((git-branch (shell-command-to-string "git branch"))
- (is-repo (string= (if (string= git-branch "") ""
- (substring git-branch 0 1)) "*")))
- (if (not is-repo) ""
- (concat
- "("
- (nth 2 (split-string git-branch "\n\\|\\*\\| "))
- "<"
- (if (string= "" (shell-command-to-string "git status | grep 'up to date'"))
- "×"
- "✓")
- ">)"))))
- (setq eshell-cmpl-ignore-case t
- eshell-cd-on-directory t
- eshell-banner-message (concat (shell-command-to-string "figlet eshell") "\n")
- eshell-prompt-function
- (proc
- (let ((properties (+eshell/get-git-properties)))
- (concat
- properties
- (format "[%s]\n" (abbreviate-file-name (eshell/pwd)))
- "λ ")))
- eshell-prompt-regexp "^λ ")
-
- (defun eshell/goto (&rest args)
- "Use `read-directory-name' to change directories."
- (eshell/cd (list (read-directory-name "Enter directory to go to:")))))
-#+end_src
-*** Eshell change directory quickly
-~eshell/goto~ is a better ~cd~ for eshell. However it is really just
-a plaster over a bigger issue for my workflow; many times I want
-eshell to be present in the current directory of the buffer I am
-using.
-
-#+begin_src emacs-lisp
-(use-package eshell
- :straight nil
- :general
- (shell-leader
- "T" #'+eshell/current-buffer)
- :config
- (defun +eshell/current-buffer ()
- (interactive)
- (let ((dir (if buffer-file-name
- (file-name-directory buffer-file-name)
- (if default-directory
- default-directory
- nil)))
- (buf (eshell)))
- (if dir
- (with-current-buffer buf
- (eshell/cd dir)
- (eshell-send-input))
- (message "Could not switch eshell: buffer is not real file")))))
-#+end_src
-** Elfeed
-Elfeed is the perfect RSS feed reader, integrated into Emacs
-perfectly. I've got a set of feeds that I use for a large variety of
-stuff, mostly media and entertainment. I've also bound "<leader> ar"
-to elfeed for loading the system.
-#+begin_src emacs-lisp
-(use-package elfeed
- :general
- (app-leader "r" #'elfeed)
- (nmmap
- :keymaps 'elfeed-search-mode-map
- "gr" #'elfeed-update
- "s" #'elfeed-search-live-filter
- "<return>" #'elfeed-search-show-entry)
- :init
- (setq elfeed-db-directory (no-littering-expand-var-file-name "elfeed/"))
- (setq +rss/feed-urls
- '(("Arch Linux"
- "https://www.archlinux.org/feeds/news/"
- Linux)
- ("LEMMiNO"
- "https://www.youtube.com/feeds/videos.xml?channel_id=UCRcgy6GzDeccI7dkbbBna3Q"
- YouTube Stories)
- ("The Onion"
- "https://www.theonion.com/rss"
- Social)
- ("Stack exchange"
- "http://morss.aryadevchavali.com/stackexchange.com/feeds/questions"
- Social)
- ("Dark Sominium"
- "https://www.youtube.com/feeds/videos.xml?channel_id=UC_e39rWdkQqo5-LbiLiU10g"
- YouTube Stories)
- ("Dark Sominium Music"
- "https://www.youtube.com/feeds/videos.xml?channel_id=UCkLiZ_zLynyNd5fd62hg1Kw"
- YouTube Music)
- ("Nexpo"
- "https://www.youtube.com/feeds/videos.xml?channel_id=UCpFFItkfZz1qz5PpHpqzYBw"
- YouTube)
- ("Techquickie"
- "https://www.youtube.com/feeds/videos.xml?channel_id=UC0vBXGSyV14uvJ4hECDOl0Q"
- YouTube)
- ("3B1B"
- "https://www.youtube.com/feeds/videos.xml?channel_id=UCYO_jab_esuFRV4b17AJtAw"
- YouTube)
- ("Fredrik Knusden"
- "https://www.youtube.com/feeds/videos.xml?channel_id=UCbWcXB0PoqOsAvAdfzWMf0w"
- YouTube Stories)
- ("Barely Sociable"
- "https://www.youtube.com/feeds/videos.xml?channel_id=UC9PIn6-XuRKZ5HmYeu46AIw"
- YouTube Stories)
- ("Atrocity Guide"
- "https://www.youtube.com/feeds/videos.xml?channel_id=UCn8OYopT9e8tng-CGEWzfmw"
- YouTube Stories)
- ("Hacker News"
- "http://morss.aryadevchavali.com/news.ycombinator.com/rss"
- Social)
- ("Hacker Factor"
- "https://www.hackerfactor.com/blog/index.php?/feeds/index.rss2"
- Social)
- ("BBC Top News"
- "http://morss.aryadevchavali.com/feeds.bbci.co.uk/news/rss.xml"
- News)
- ("BBC Tech News"
- "http://morss.aryadevchavali.com/feeds.bbci.co.uk/news/technology/rss.xml"
- News)))
- :config
- (with-eval-after-load "evil-collection"
- (evil-collection-elfeed-setup))
- (setq elfeed-feeds (cl-map 'list #'(lambda (item)
- (append (list (nth 1 item)) (cdr (cdr item))))
- +rss/feed-urls)))
-#+end_src
-** Magit
-Magit is *the* git porcelain for Emacs, which perfectly encapsulates
-the git cli. In this case I just need to setup the bindings for it.
-As magit will definitely load after evil (as it must be run by a
-binding, and evil will load after init), I can use evil-collection
-freely. Also, define an auto insert for commit messages so that I
-don't need to write everything myself.
-
-#+begin_src emacs-lisp
-(use-package magit
- :defer t
- :display
- ("magit:.*"
- (display-buffer-same-window)
- (inhibit-duplicate-buffer . t))
- ("magit-diff:.*"
- (display-buffer-below-selected))
- ("magit-log:.*"
- (display-buffer-same-window))
- :general
- (leader
- "g" '(magit-dispatch :which-key "Magit")
- "vf" '(magit-file-dispatch :which-key "Magit file")
- "vb" '(magit-blame :which-key "Magit blame"))
- (code-leader
- "b" #'magit-blame)
- :auto-insert
- (("COMMIT_EDITMSG" . "Commit skeleton")
- ""
- "(" (read-string "Enter feature/module: ") ")"
- (read-string "Enter simple description: ") "\n\n")
- :init
- (setq vc-follow-symlinks t
- magit-blame-echo-style 'lines)
- :config
- (with-eval-after-load "evil"
- (evil-set-initial-state 'magit-status-mode 'motion))
- (with-eval-after-load "evil-collection"
- (evil-collection-magit-setup)))
-#+end_src
-** IBuffer
-#+begin_src emacs-lisp
-(use-package ibuffer
- :general
- (buffer-leader
- "i" #'ibuffer)
- :config
- (with-eval-after-load "evil-collection"
- (evil-collection-ibuffer-setup)))
-#+end_src
-** Processes
-Emacs has two systems for process management:
-+ proced: a general 'top' like interface which allows general
- management of linux processes
-+ list-processes: a specific Emacs based system that lists processes
- spawned by Emacs (similar to a top for Emacs specifically)
-
-*** Proced
-Core proced config, just a few bindings and evil collection setup.
-#+begin_src emacs-lisp
-(use-package proced
- :straight nil
- :general
- (app-leader
- "p" #'proced)
- (nmap
- :keymaps 'proced-mode-map
- "za" #'proced-toggle-auto-update)
- :display
- ("\\*Proced\\*"
- (display-buffer-at-bottom)
- (window-height . 0.25))
- :init
- (setq proced-auto-update-interval 0.5)
- :config
- (with-eval-after-load "evil-collection"
- (evil-collection-proced-setup)))
-#+end_src
-
-Along with that I setup the package ~proced-narrow~ which allows
-further filtering of the process list.
-#+begin_src emacs-lisp
-(use-package proced-narrow
- :straight t
- :after proced
- :general
- (nmap
- :keymaps 'proced-mode-map
- "%" #'proced-narrow))
-#+end_src
-** Calculator
-Surprise, surprise Emacs comes with a calculator.
-
-Greater surprise, this thing is over powered. It can perform the
-following (and more):
-- Matrix calculations
-- Generalised calculus operations
-- Equation solvers for n-degree multi-variable polynomials
-- Embedded mode (check below)!
-
-~calc-mode~ is a calculator system within Emacs that provides a
-diverse array of mathematical operations. It uses reverse polish
-notation to do calculations (though there is a standard infix
-algebraic notation mode).
-
-Embedded mode allows computation with the current buffer as the echo
-area. This basically means I can compute stuff within a buffer
-without invoking calc directly: $1 + 2\rightarrow_{\text{calc-embed}} 3$.
-
+** Licensing
+Loads [[file:elisp/license.el][license.el]] for inserting licenses.
+Licenses are important for distribution and attribution to be defined clearly.
#+begin_src emacs-lisp
-(use-package calc
+(use-package license
:straight nil
- :display
- ("*Calculator*"
- (display-buffer-at-bottom)
- (window-height . 0.18))
- :general
- (app-leader
- "c" #'calc-dispatch)
- (mode-leader
- "c" #'calc-embedded)
- :init
- (setq calc-algebraic-mode t)
- :config
- (with-eval-after-load "evil-collection"
- (evil-collection-calc-setup)))
-#+end_src
-*** WIP Calctex
-:PROPERTIES:
-:header-args:emacs-lisp: :tangle no
-:END:
-~calc-mode~ also has a 3rd party package called ~calctex~. It renders
-mathematical expressions within calc as if they were rendered in TeX.
-You can also copy the expressions in their TeX forms, which is pretty
-useful when writing a paper. I've set a very specific lock on this
-repository as it's got quite a messy work-tree and this commit seems to
-work for me given the various TeX utilities installed via Arch.
-
-#+begin_src emacs-lisp
-(use-package calctex
- :after calc
- :straight (calctex :type git :host github :repo "johnbcoughlin/calctex")
- :hook (calc-mode-hook . calctex-mode))
-#+end_src
-** Ledger
-#+begin_src emacs-lisp
-(use-package ledger-mode
- :defer t)
-
-(use-package evil-ledger
- :after ledger-mode)
-#+end_src
-** WIP Zone
-:PROPERTIES:
-:header-args:emacs-lisp: :tangle no
-:END:
-Of course Emacs has a cool screensaver software.
-
-#+begin_src emacs-lisp
-(use-package zone-matrix
- :straight t
- :after dashboard
- :init
- (setq zone-programs
- [zone-pgm-jitter
- zone-pgm-putz-with-case
- zone-pgm-dissolve
- zone-pgm-whack-chars
- zone-pgm-drip
- zone-pgm-rat-race
- zone-pgm-random-life
- zone-matrix
- ])
- :config
- (zone-when-idle 15))
-#+end_src
-** (Wo)man
-Man pages are the user manuals for most software on Linux. Really
-useful when writing code for Un*x systems, though they can be very
-verbose.
-
-2023-08-17: `Man-notify-method' is the reason the `:display' record
-doesn't work here. I think it's to do with how Man pages are rendered
-or something, but very annoying as it's a break from standards!
-#+begin_src emacs-lisp
-(use-package man
+ :load-path "elisp/"
:demand t
- :straight nil
- :init
- (setq Man-notify-method 'pushy)
- :display
- ("^\\*Man.*"
- (display-buffer-reuse-mode-window display-buffer-same-window))
:general
- (file-leader
- "m" #'man) ;; kinda like "find man page"
- (nmmap
- :keymaps 'Man-mode-map
- "RET" #'man-follow))
+ (insert-leader
+ "l" #'+license/insert-copyright-notice
+ "L" #'+license/insert-complete-license))
#+end_src
-** gif-screencast
-Little application that uses =gifsicle= to make essentially videos of
-Emacs. Useful for demonstrating features.
+* Applications (loading)
+Emacs is basically an operating system whose primary datatype is text.
+Applications are interfaces/environments which serve a variety of
+purposes, but provide a lot of capability. I have a
+[[file:app.org][separate file]] for such configuration (2023-09-29:
+mainly because it was so goddamn huge).
+
#+begin_src emacs-lisp
-(use-package gif-screencast
- :straight t
- :general
- (app-leader
- "x" #'gif-screencast-start-or-stop)
- :init
- (setq gif-screencast-output-directory (expand-file-name "~/Media/emacs/")))
+(load-file (concat user-emacs-directory "app.el"))
#+end_src
* Text modes
Standard packages and configurations for text-mode and its derived
diff --git a/Emacs/.config/emacs/core.org b/Emacs/.config/emacs/core.org
new file mode 100644
index 0000000..687b226
--- /dev/null
+++ b/Emacs/.config/emacs/core.org
@@ -0,0 +1,738 @@
+#+title: Core packages
+#+author: Aryadev Chavali
+#+description: The core components of my configuration
+#+date: 2023-09-29
+#+property: header-args:emacs-lisp :tangle core.el :comments link :results none
+#+options: toc:nil
+#+startup: noindent
+
+Packages that are absolutely necessary for the rest of the
+configuration. These yield core functionality such as keybinding,
+modal editing, completion, auto typing to name a few.
+* General
+General provides a great solution for binding keys. It has evil and
+use-package support so it fits nicely into configuration. In this
+case, I define a "definer" for the "LEADER" keys. Leader is bound to
+~SPC~ and it's functionally equivalent to the doom/spacemacs leader.
+Local leader is bound to ~SPC ,~ and it's similar to doom/spacemacs
+leader but doesn't try to fully assimilate the local-leader map,
+instead just picking stuff I think is useful. This forces me to learn
+only as many bindings as I find necessary; no more, no less.
+
+I also define prefix leaders for differing applications. These are
+quite self explanatory by their name and provide a nice way to
+visualise all bindings under a specific heading just by searching the
+code.
+#+begin_src emacs-lisp
+(use-package general
+ :straight t
+ :demand t
+ :config
+ ;; General which key definitions for leaders
+ (general-def
+ :states '(normal motion)
+ "SPC" 'nil
+ "\\" '(nil :which-key "Local leader")
+ "SPC c" '(nil :which-key "Code")
+ "SPC f" '(nil :which-key "File")
+ "SPC t" '(nil :which-key "Shell")
+ "SPC m" '(nil :which-key "Toggle modes")
+ "SPC a" '(nil :which-key "Applications")
+ "SPC s" '(nil :which-key "Search")
+ "SPC b" '(nil :which-key "Buffers")
+ "SPC q" '(nil :which-key "Quit/Literate")
+ "SPC i" '(nil :which-key "Insert")
+ "SPC d" '(nil :which-key "Directories"))
+
+ (general-create-definer leader
+ :states '(normal motion)
+ :keymaps 'override
+ :prefix "SPC")
+
+ (general-create-definer local-leader
+ :states '(normal motion)
+ :prefix "\\")
+
+ (general-create-definer code-leader
+ :states '(normal motion)
+ :keymaps 'override
+ :prefix "SPC c")
+
+ (general-create-definer file-leader
+ :states '(normal motion)
+ :keymaps 'override
+ :prefix "SPC f")
+
+ (general-create-definer shell-leader
+ :states '(normal motion)
+ :keymaps 'override
+ :prefix "SPC t")
+
+ (general-create-definer mode-leader
+ :states '(normal motion)
+ :keymaps 'override
+ :prefix "SPC m")
+
+ (general-create-definer app-leader
+ :states '(normal motion)
+ :keymaps 'override
+ :prefix "SPC a")
+
+ (general-create-definer search-leader
+ :states '(normal motion)
+ :keymaps 'override
+ :prefix "SPC s")
+
+ (general-create-definer buffer-leader
+ :states '(normal motion)
+ :keymaps 'override
+ :prefix "SPC b")
+
+ (general-create-definer quit-leader
+ :states '(normal motion)
+ :keymaps 'override
+ :prefix "SPC q")
+
+ (general-create-definer insert-leader
+ :states '(normal motion)
+ :keymaps 'override
+ :prefix "SPC i")
+
+ (general-create-definer dir-leader
+ :states '(normal motion)
+ :keymaps 'override
+ :prefix "SPC d")
+
+ (general-create-definer general-nmmap
+ :states '(normal motion))
+
+ (defalias 'nmmap #'general-nmmap)
+
+ (general-evil-setup t))
+#+end_src
+** Some binds in Emacs
+Some bindings that I couldn't fit elsewhere easily.
+#+begin_src emacs-lisp
+(use-package emacs
+ :straight nil
+ :general
+ (general-def
+ "C-x d" #'delete-frame)
+
+ (nmmap
+ "C--" #'text-scale-decrease
+ "C-=" #'text-scale-increase)
+
+ (leader
+ "SPC" '(execute-extended-command :which-key "M-x")
+ "'" '(browse-url-emacs :which-key "Open url in Emacs")
+ ";" 'eval-expression
+ ":" `(,(proc (interactive) (switch-to-buffer "*scratch*"))
+ :which-key "Switch to *scratch*")
+ "!" '(async-shell-command :which-key "Async shell command")
+ "h" '(help-command :which-key "Help"))
+
+ (mode-leader
+ "t" #'+oreo/switch-theme)
+
+ (code-leader
+ "F" `(,(proc (interactive) (find-file "~/Code/"))
+ :which-key "Open ~/Code/"))
+
+ (file-leader
+ "f" #'find-file
+ "F" #'find-file-other-frame
+ "s" #'save-buffer
+ "p" `(,(proc (interactive)
+ (find-file (concat user-emacs-directory "config.org")))
+ :which-key "Open config.org"))
+
+ (quit-leader
+ "q" #'save-buffers-kill-terminal
+ "c" #'+literate/compile-config
+ "l" #'+literate/load-config
+ "d" #'delete-frame)
+
+ (search-leader "i" #'imenu))
+#+end_src
+* Evil
+My editor journey started off with Vim rather than Emacs, so my brain
+has imprinted on its style. Thankfully Emacs is super extensible so
+there exists a package (more of a supreme system) for porting Vim's
+modal editing style to Emacs, called Evil (Emacs Vi Layer).
+
+However there are a lot of packages in Vim that provide greater
+functionality, for example 'vim-surround'. Emacs, by default, has
+these capabilities but there are further packages which integrate them
+into Evil.
+** Evil core
+Setup the evil package, with some opinionated keybindings:
+- Switch ~evil-upcase~ and ~evil-downcase~ because I use ~evil-upcase~
+ more
+- Switch ~evil-goto-mark~ and ~evil-goto-mark-line~ as I'd rather have
+ the global one closer to the home row
+- Use 'T' character as an action for transposing objects
+#+begin_src emacs-lisp
+(use-package evil
+ :demand t
+ :hook (after-init-hook . evil-mode)
+ :general
+ (leader
+ "w" '(evil-window-map :which-key "Window")
+ "wd" #'delete-frame)
+
+ (nmmap
+ "TAB" #'evil-jump-item
+ "r" #'evil-replace-state
+ "zC" #'hs-hide-level
+ "zO" #'hs-show-all
+ "'" #'evil-goto-mark
+ "`" #'evil-goto-mark-line
+ "C-w" #'evil-window-map
+ "gu" #'evil-upcase
+ "gU" #'evil-downcase
+ "T" nil)
+
+ (nmmap
+ :infix "T"
+ "w" #'transpose-words
+ "c" #'transpose-chars
+ "s" #'transpose-sentences
+ "p" #'transpose-paragraphs
+ "e" #'transpose-sexps
+ "l" #'transpose-lines)
+ :init
+ (setq evil-want-keybinding nil
+ evil-split-window-below t
+ evil-vsplit-window-right t
+ evil-want-abbrev-expand-on-insert-exit t
+ evil-undo-system #'undo-tree)
+ :config
+ (fset #'evil-window-vsplit #'make-frame))
+#+end_src
+** Evil surround
+Evil surround is a port for vim-surround.
+#+begin_src emacs-lisp
+(use-package evil-surround
+ :after evil
+ :config
+ (global-evil-surround-mode))
+#+end_src
+** Evil commentary
+Allows generalised commenting of objects easily.
+#+begin_src emacs-lisp
+(use-package evil-commentary
+ :after evil
+ :config
+ (evil-commentary-mode))
+#+end_src
+** Evil multi cursor
+Setup for multi cursors in Evil mode. Don't let evil-mc setup it's own
+keymap because it uses 'gr' as its prefix, which I don't like.
+#+begin_src emacs-lisp
+(use-package evil-mc
+ :after evil
+ :init
+ (defvar evil-mc-key-map (make-sparse-keymap))
+ :general
+ (nmap
+ :infix "gz"
+ "q" #'evil-mc-undo-all-cursors
+ "d" #'evil-mc-make-and-goto-next-match
+ "j" #'evil-mc-make-cursor-move-next-line
+ "k" #'evil-mc-make-cursor-move-prev-line
+ "j" #'evil-mc-make-cursor-move-next-line
+ "m" #'evil-mc-make-all-cursors
+ "z" #'evil-mc-make-cursor-here
+ "r" #'evil-mc-resume-cursors
+ "s" #'evil-mc-pause-cursors
+ "u" #'evil-mc-undo-last-added-cursor)
+ :config
+ ;; (evil-mc-define-vars)
+ ;; (evil-mc-initialize-vars)
+ ;; (add-hook 'evil-mc-before-cursors-created #'evil-mc-pause-incompatible-modes)
+ ;; (add-hook 'evil-mc-before-cursors-created #'evil-mc-initialize-active-state)
+ ;; (add-hook 'evil-mc-after-cursors-deleted #'evil-mc-teardown-active-state)
+ ;; (add-hook 'evil-mc-after-cursors-deleted #'evil-mc-resume-incompatible-modes)
+ ;; (advice-add #'evil-mc-initialize-hooks :override #'ignore)
+ ;; (advice-add #'evil-mc-teardown-hooks :override #'evil-mc-initialize-vars)
+ ;; (advice-add #'evil-mc-initialize-active-state :before #'turn-on-evil-mc-mode)
+ ;; (advice-add #'evil-mc-teardown-active-state :after #'turn-off-evil-mc-mode)
+ ;; (add-hook 'evil-insert-state-entry-hook #'evil-mc-resume-cursors)
+ (global-evil-mc-mode))
+#+end_src
+
+** Evil collection
+Provides a community based set of keybindings for most modes in
+Emacs. I don't necessarily like all my modes having these bindings
+though, as I may disagree with some. So I use it in a mode to mode basis.
+#+begin_src emacs-lisp
+(use-package evil-collection
+ :after evil)
+#+end_src
+* Completion
+Emacs is a text based interface. Completion is its bread and butter
+in providing good user experience. By default Emacs provides
+'completions-list' which produces a buffer of options which can be
+searched and selected. We can take this further though!
+
+Ido and Icomplete are packages distributed with Emacs to provide
+greater completion interfaces. They utilise the minibuffer to create
+a more interactive experience, allowing incremental searches and
+option selection.
+
+Ivy and Helm provide more modern interfaces, though Helm is quite
+heavy. Ivy, on the other hand, provides an interface similar to Ido
+with less clutter and better customisation options.
+** Ivy
+Ivy is a completion framework for Emacs, and my preferred one. It has
+a great set of features with little to no pain with setting up.
+*** Ivy Core
+Setup for ivy, in preparation for counsel. Turn on ivy-mode just
+after init.
+
+Setup vim-like bindings for the minibuffer ("M-(j|k)" for down|up the
+selection list).
+#+begin_src emacs-lisp
+(use-package ivy
+ :defer t
+ :hook (after-init-hook . ivy-mode)
+ :general
+ (general-def
+ :keymaps 'ivy-minibuffer-map
+ "C-j" #'ivy-yank-symbol
+ "M-j" #'ivy-next-line-or-history
+ "M-k" #'ivy-previous-line-or-history
+ "C-SPC" #'ivy-occur)
+ (general-def
+ :keymaps 'ivy-switch-buffer-map
+ "M-j" #'ivy-next-line-or-history
+ "M-k" #'ivy-previous-line-or-history)
+ (nmap
+ :keymaps '(ivy-occur-mode-map ivy-occur-grep-mode-map)
+ "RET" #'ivy-occur-press-and-switch
+ "J" #'ivy-occur-press
+ "gr" #'ivy-occur-revert-buffer
+ "q" #'quit-window
+ "D" #'ivy-occur-delete-candidate
+ "W" #'ivy-wgrep-change-to-wgrep-mode
+ "{" #'compilation-previous-file
+ "}" #'compilation-next-file)
+ :init
+ (with-eval-after-load "evil"
+ (evil-set-initial-state 'ivy-occur-mode 'normal)
+ (evil-set-initial-state 'ivy-occur-grep-mode 'normal))
+ (with-eval-after-load "amx"
+ (setq amx-backend 'ivy))
+
+ (setq ivy-height 10
+ ivy-wrap t
+ ivy-fixed-height-minibuffer t
+ ivy-use-virtual-buffers nil
+ ivy-virtual-abbreviate 'full
+ ivy-on-del-error-function #'ignore
+ ivy-use-selectable-prompt t)
+ :config
+ (require 'counsel nil t))
+#+end_src
+*** Counsel
+Setup for counsel. Load after ivy and helpful.
+#+begin_src emacs-lisp
+(use-package counsel
+ :defer t
+ :general
+ (search-leader
+ "s" #'counsel-grep-or-swiper
+ "r" #'counsel-rg)
+ (file-leader
+ "r" #'counsel-recentf)
+ (insert-leader
+ "c" #'counsel-unicode-char)
+ (general-def
+ [remap describe-bindings] #'counsel-descbinds
+ [remap load-theme] #'counsel-load-theme)
+ :config
+ (setq ivy-initial-inputs-alist '((org-insert-link . "^"))
+ counsel-describe-function-function #'helpful-callable
+ counsel-describe-variable-function #'helpful-variable
+ counsel-grep-swiper-limit 1500000
+ ivy-re-builders-alist '((swiper . ivy--regex-plus)
+ (counsel-grep-or-swiper . ivy--regex-plus)
+ (counsel-rg . ivy--regex-plus)
+ (t . ivy--regex-ignore-order)))
+ (counsel-mode))
+#+end_src
+*** WIP Ivy posframe
+:PROPERTIES:
+:header-args:emacs-lisp: :tangle no
+:END:
+This makes ivy minibuffer windows use child frames.
+Very nice eyecandy, but can get kinda annoying.
+#+begin_src emacs-lisp
+(use-package ivy-posframe
+ :hook (ivy-mode-hook . ivy-posframe-mode)
+ :straight t
+ :init
+ (setq ivy-posframe-parameters
+ '((left-fringe . 0)
+ (right-fringe . 0)
+ (background-color . "grey7")))
+
+ (setq ivy-posframe-display-functions-alist
+ '((t . ivy-posframe-display-at-window-center))))
+#+end_src
+*** WIP Counsel etags
+:PROPERTIES:
+:header-args:emacs-lisp: :tangle no
+:END:
+Counsel etags allows me to search generated tag files for tags. I
+already have a function defined to generate the tags, so it's just
+searching them which I find to be a bit of a hassle, and where this
+package comes in.
+
+This has been replaced by [[*xref][xref]] which is inbuilt.
+#+begin_src emacs-lisp
+(use-package counsel-etags
+ :after counsel
+ :general
+ (search-leader
+ "t" #'counsel-etags-find-tag))
+#+end_src
+** WIP Ido
+:PROPERTIES:
+:header-args:emacs-lisp: :tangle no
+:END:
+Ido is a very old completion package that still works great to this
+day. Though it is limited in its scope (and may thus be called a
+completion add-on rather than a full on framework), it is still a very
+powerful package. With the use of ido-completing-read+, it may be used
+similarly to a fully fledged completion framework.
+
+#+begin_src emacs-lisp
+(use-package ido
+ :demand t
+ :general
+ (general-def
+ :keymaps '(ido-buffer-completion-map
+ ido-file-completion-map
+ ido-file-dir-completion-map
+ ido-common-completion-map)
+ (kbd "M-j") #'ido-next-match
+ (kbd "M-k") #'ido-prev-match
+ (kbd "C-x o") #'evil-window-up)
+ :init
+ (setq ido-decorations
+ (list "{" "}" " \n" " ..." "[" "]" " [No match]" " [Matched]"
+ " [Not readable]" " [Too big]" " [Confirm]")
+ completion-styles '(flex partial-completion intials emacs22))
+ (setq-default ido-enable-flex-matching t
+ ido-enable-dot-prefix t
+ ido-enable-regexp nil)
+ (with-eval-after-load "magit"
+ (setq magit-completing-read-function 'magit-ido-completing-read))
+ :config
+ (ido-mode)
+ (ido-everywhere))
+#+end_src
+*** Ido ubiquitous
+Ido completing-read+ is a package that extends the ido package to work
+with more text based functions.
+#+begin_src emacs-lisp
+(use-package ido-completing-read+
+ :after ido
+ :config
+ (ido-ubiquitous-mode +1))
+#+end_src
+** Amx
+Amx is a fork of Smex that works to enhance the
+execute-extended-command interface. It also provides support for ido
+or ivy (though I'm likely to use ido here) and allows you to switch
+between them.
+
+It provides a lot of niceties such as presenting the key bind when
+looking for a command.
+
+#+begin_src emacs-lisp
+(use-package amx
+ :config
+ (amx-mode))
+#+end_src
+** Orderless
+Orderless sorting method for completion, probably one of the best
+things ever.
+#+begin_src emacs-lisp
+(use-package orderless
+ :after (ivy ido)
+ :config
+ (setf (alist-get t ivy-re-builders-alist) 'orderless-ivy-re-builder))
+#+end_src
+** Completions-list
+In case I ever use the completions list, some basic commands to look
+around.
+#+begin_src emacs-lisp
+(use-package simple
+ :straight nil
+ :general
+ (nmmap
+ :keymaps 'completion-list-mode-map
+ "l" #'next-completion
+ "h" #'previous-completion
+ "ESC" #'delete-completion-window
+ "q" #'quit-window
+ "RET" #'choose-completion)
+ :config
+ (with-eval-after-load "evil"
+ (setq evil-emacs-state-modes (cl-remove-if
+ #'(lambda (x) (eq 'completions-list-mode x))
+ evil-emacs-state-modes))
+ (add-to-list 'evil-normal-state-modes 'completions-list-mode)))
+#+end_src
+** Company
+Company is the auto complete system I use. I don't like having heavy
+setups for company as it only makes it slower to use. In this case,
+just setup some evil binds for company.
+#+begin_src emacs-lisp
+(use-package company
+ :straight t
+ :hook
+ (prog-mode-hook . company-mode)
+ (eshell-mode-hook . company-mode)
+ :general
+ (imap
+ "C-SPC" #'company-complete)
+ (general-def
+ :states '(normal insert)
+ "M-j" #'company-select-next
+ "M-k" #'company-select-previous))
+#+end_src
+* Pretty symbols
+Prettify symbols mode allows for users to declare 'symbols' that
+replace text within certain modes. Though this may seem like useless
+eye candy, it has aided my comprehension and speed of recognition
+(recognising symbols is easier than words).
+
+Essentially a use-package keyword which makes declaring pretty symbols
+for language modes incredibly easy. Checkout my [[C/C++][C/C++]] configuration
+for an example.
+#+begin_src emacs-lisp
+(use-package prog-mode
+ :straight nil
+ :init
+ (setq prettify-symbols-unprettify-at-point t)
+ :config
+ (with-eval-after-load "use-package-core"
+ (add-to-list 'use-package-keywords ':pretty)
+ (defun use-package-normalize/:pretty (_name-symbol _keyword args)
+ args)
+
+ (defun use-package-handler/:pretty (name _keyword args rest state)
+ (use-package-concat
+ (use-package-process-keywords name rest state)
+ (mapcar
+ #'(lambda (arg)
+ (let ((mode (car arg))
+ (rest (cdr arg)))
+ `(add-hook
+ ',mode
+ #'(lambda nil
+ (setq prettify-symbols-alist ',rest)
+ (prettify-symbols-mode)))))
+ args)))))
+#+end_src
+
+Here's a collection of keywords and possible associated symbols for
+any prog language of choice. Mostly for reference and copying.
+#+begin_example
+("null" . "Ø")
+("list" . "ℓ")
+("string" . "𝕊")
+("true" . "⊤")
+("false" . "⊥")
+("char" . "ℂ")
+("int" . "ℤ")
+("float" . "ℝ")
+("!" . "¬")
+("&&" . "∧")
+("||" . "∨")
+("for" . "∀")
+("return" . "⟼")
+("print" . "ℙ")
+("lambda" . "λ")
+#+end_example
+* Window management
+Emacs' default window management is quite bad, eating other windows on
+a whim and not particularly caring for the current window setup.
+Thankfully you can change this via the ~display-buffer-alist~ which
+matches buffer names with how the window for the buffer should be
+displayed. I add a use-package keyword to make ~display-buffer-alist~
+records within use-package.
+
+I have no idea whether it's optimal AT ALL, but it works for me.
+#+begin_src emacs-lisp
+(use-package window
+ :straight nil
+ :general
+ (buffer-leader
+ "b" #'switch-to-buffer
+ "d" #'kill-current-buffer
+ "K" #'kill-buffer
+ "j" #'next-buffer
+ "k" #'previous-buffer
+ "D" '(+oreo/clean-buffer-list :which-key "Kill most buffers"))
+ :init
+ (with-eval-after-load "use-package-core"
+ (add-to-list 'use-package-keywords ':display)
+ (defun use-package-normalize/:display (_name-symbol _keyword args)
+ args)
+
+ (defun use-package-handler/:display (name _keyword args rest state)
+ (use-package-concat
+ (use-package-process-keywords name rest state)
+ (mapcar
+ #'(lambda (arg)
+ `(add-to-list 'display-buffer-alist
+ ',arg))
+ args)))))
+#+end_src
+** Some display records
+Using the ~:display~ keyword, setup up some ~display-buffer-alist~
+records. This is mostly for packages that aren't really configured
+(like [[info:woman][woman]]) or packages that were configured before
+(like [[Ivy][Ivy]]).
+#+begin_src emacs-lisp
+(use-package window
+ :straight nil
+ :defer t
+ :display
+ ("\\*Process List\\*"
+ (display-buffer-at-bottom)
+ (window-height . 0.25))
+
+ ("\\*\\(Ido \\)?Completions\\*"
+ (display-buffer-in-side-window)
+ (window-height . 0.25)
+ (side . bottom))
+
+ ("\\*ivy-occur.*"
+ (display-buffer-at-bottom)
+ (window-height . 0.25))
+
+ ("\\*Async Shell Command\\*"
+ (display-buffer-at-bottom)
+ (window-height . 0.25)))
+#+end_src
+* Auto typing
+Snippets are a pretty nice way of automatically inserting code. Emacs
+provides a ton of packages by default to do this, but there are great
+packages to install as well.
+
+Abbrevs and skeletons make up a popular solution within Emacs default.
+Abbrevs are for simple expressions wherein the only input is the key,
+and the output is some Elisp function. They provide a lot of inbuilt
+functionality and are quite useful. Skeletons, on the other hand, are
+for higher level insertions
+
+The popular external solution is Yasnippet. Yasnippet is a great
+package for snippets, which I use heavily in programming and org-mode.
+I setup here the global mode for yasnippet and a collection of
+snippets for ease of use.
+** Abbrevs
+Just define a few abbrevs for various date-time operations. Also
+define a macro that will assume a function for the expansion, helping
+with abstracting a few things away.
+#+begin_src emacs-lisp
+(use-package abbrev
+ :straight nil
+ :hook
+ (prog-mode-hook . abbrev-mode)
+ (text-mode-hook . abbrev-mode)
+ :init
+ (defmacro +abbrev/define-abbrevs (abbrev-table &rest abbrevs)
+ `(progn
+ ,@(mapcar #'(lambda (abbrev)
+ `(define-abbrev
+ ,abbrev-table
+ ,(car abbrev)
+ ""
+ (proc (insert ,(cadr abbrev)))))
+ abbrevs)))
+ (setq save-abbrevs nil)
+ :config
+ (+abbrev/define-abbrevs
+ global-abbrev-table
+ ("sdate"
+ (format-time-string "%Y-%m-%d" (current-time)))
+ ("stime"
+ (format-time-string "%H:%M:%S" (current-time)))
+ ("sday"
+ (format-time-string "%A" (current-time)))
+ ("smon"
+ (format-time-string "%B" (current-time)))))
+#+end_src
+** WIP Skeletons
+:PROPERTIES:
+:header-args:emacs-lisp: :tangle no
+:END:
+Defines a macro for generating a skeleton + abbrev for a given mode.
+Doesn't sanitise inputs because I assume callers are /rational/ actors
+who would *only* use this for their top level Emacs config.
+
+Honestly didn't find much use for this currently, so disabled.
+#+begin_src emacs-lisp
+(use-package skeleton
+ :straight nil
+ :after abbrev
+ :config
+ (defmacro +autotyping/gen-skeleton-abbrev (mode abbrev &rest skeleton)
+ (let* ((table (intern (concat (symbol-name mode) "-abbrev-table")))
+ (skeleton-name (intern (concat "+skeleton/" (symbol-name mode) "/" abbrev))))
+ `(progn
+ (define-skeleton
+ ,skeleton-name
+ ""
+ ,@skeleton)
+ (define-abbrev ,table
+ ,abbrev
+ ""
+ ',skeleton-name)))))
+#+end_src
+** Auto insert
+Allows inserting text immediately upon creating a new buffer with a
+given name. Supports skeletons for inserting text. To make it easier
+for later systems to define their own auto inserts, I define a
+~use-package~ keyword ~auto-insert~ which allows one to define an
+entry for ~auto-insert-alist~.
+#+begin_src emacs-lisp
+(use-package autoinsert
+ :straight nil
+ :demand t
+ :hook (after-init-hook . auto-insert-mode)
+ :config
+ (with-eval-after-load "use-package-core"
+ (add-to-list 'use-package-keywords ':auto-insert)
+ (defun use-package-normalize/:auto-insert (_name-symbol _keyword args)
+ args)
+ (defun use-package-handler/:auto-insert (name _keyword args rest state)
+ (use-package-concat
+ (use-package-process-keywords name rest state)
+ (mapcar
+ #'(lambda (arg)
+ `(add-to-list
+ 'auto-insert-alist
+ ',arg))
+ args)))))
+#+end_src
+** Yasnippet default
+Look at the snippets [[file:../.config/yasnippet/snippets/][folder]]
+for all snippets I've got.
+#+begin_src emacs-lisp
+(use-package yasnippet
+ :defer t
+ :hook
+ (prog-mode-hook . yas-minor-mode)
+ :general
+ (insert-leader
+ "i" #'yas-insert-snippet)
+ :config
+ (yas-load-directory (no-littering-expand-etc-file-name "yasnippet/snippets")))
+#+end_src
diff --git a/Emacs/.config/emacs/elisp/literate.el b/Emacs/.config/emacs/elisp/literate.el
index 67ee88e..114c3bb 100644
--- a/Emacs/.config/emacs/elisp/literate.el
+++ b/Emacs/.config/emacs/elisp/literate.el
@@ -33,7 +33,17 @@
(cons first (+literate/filter predicate rest))
(+literate/filter predicate rest)))))
-(defconst +literate/org-files (list (concat user-emacs-directory "config.org")))
+(defun +literate/org-p (filename)
+ (string= "org" (file-name-extension filename)))
+
+(defun +literate/el-p (filename)
+ (string= "el" (file-name-extension filename)))
+
+(defconst +literate/org-files
+ (+literate/filter
+ #'+literate/org-p
+ (mapcar #'(lambda (file) (concat user-emacs-directory file))
+ (cddr (directory-files user-emacs-directory)))))
(defconst +literate/output-files
(mapcar #'(lambda (x) (replace-regexp-in-string ".org" ".el" x)) +literate/org-files))
@@ -41,11 +51,12 @@
(defconst +literate/elisp-files
`(,(concat user-emacs-directory "early-init.el")
,(concat user-emacs-directory "init.el")
+ ,@+literate/output-files
,@(mapcar
#'(lambda (name) (concat user-emacs-directory "elisp/" name))
;; Only take .el files
(+literate/filter
- (lambda (name) (string= "el" (file-name-extension name)))
+ #'+literate/el-p
(cddr (directory-files (concat user-emacs-directory "elisp/")))))))
;; Setup predicates and loading
@@ -62,14 +73,15 @@
(file-exists-p (car +literate/output-files))))
(defun +literate/load-config ()
- "Load all files in +literate/output-files."
+ "Load the first file in +literate/output-files."
(interactive)
- (mapc #'(lambda (x) (load-file x)) +literate/output-files))
+ (load-file (concat user-emacs-directory "config.el")))
(autoload #'org-babel-tangle-file "ob-tangle")
(defun +literate/tangle-if-old (org-file)
(let ((output-file (replace-regexp-in-string ".org" ".el" org-file)))
+ (message "Tangle(%s)->%s" org-file output-file)
(if (or (not (file-exists-p output-file)) (file-newer-than-file-p org-file output-file))
(org-babel-tangle-file org-file))))
@@ -88,7 +100,7 @@
(message "Byte-compiling literate files...")
(mapc #'+literate/byte-compile-if-old +literate/output-files)
(message "Literate files byte-compiled")
- (message "Byte compiling init.el, early-init.el, elisp/*")
+ (message "Byte compiling init.el, early-init.el, *.org~>*.el elisp/*")
(mapc #'+literate/byte-compile-if-old +literate/elisp-files)
(message "Finished byte-compiling"))