The two largest sections of my config are separated into their own files now. Does increase init time, but I just can't handle how big this thing is. It'll be a bit nicer to look at and manage with separate files.
788 lines
26 KiB
Org Mode
788 lines
26 KiB
Org Mode
#+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
|