Compare commits
4
Commits
5ddfe643c3
...
1c4f950e3f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c4f950e3f | ||
|
|
2e6bbc77fd | ||
|
|
60c8d863d3 | ||
|
|
30c87a36af |
+7
-2
@@ -1,13 +1,18 @@
|
||||
# emacs
|
||||
config/emacs/.ignore
|
||||
config/emacs/var/
|
||||
config/emacs/elfeed/
|
||||
config/emacs/eshell/
|
||||
config/emacs/auto-save-list/
|
||||
# fish
|
||||
config/fish/conf.d
|
||||
config/fish/functions
|
||||
config/fish/fish_variables
|
||||
config/fish/generated_completions/
|
||||
# vim/nvim
|
||||
config/vim/autoload/
|
||||
config/vim/pack/
|
||||
config/vim/.netrwhist
|
||||
config/nvim/nvim-pack-lock.json
|
||||
config/awesome/bling
|
||||
scripts/bin/Obsidian
|
||||
# other
|
||||
scripts/bin/ols
|
||||
|
||||
+27
-39
@@ -4,9 +4,9 @@
|
||||
;; C-h works too, except in normal/motion state where it moves
|
||||
;; to the window on the left.
|
||||
;;; Code:
|
||||
|
||||
;;;; 1. Emac setup, files, packages and paths
|
||||
(let ((bin (expand-file-name "~/.local/bin")))
|
||||
(dolist (bin (list (expand-file-name "~/.local/bin")
|
||||
(expand-file-name "~/.go/bin")))
|
||||
(add-to-list 'exec-path bin)
|
||||
(setenv "PATH" (concat bin path-separator (getenv "PATH"))))
|
||||
|
||||
@@ -63,16 +63,25 @@
|
||||
(which-key-mode 1)
|
||||
|
||||
(add-to-list 'warning-suppress-types '(files))
|
||||
(use-package jbeans-theme
|
||||
:config
|
||||
(load-theme 'jbeans t))
|
||||
(use-package doom-themes :ensure t)
|
||||
(load-theme 'doom-one t)
|
||||
(doom-themes-set-faces 'user
|
||||
'(default :background "#131313")
|
||||
'(fringe :background "#131313")
|
||||
'(line-number :background "#131313")
|
||||
'(line-number-current-line :background "#131313")
|
||||
'(mode-line :background "#1a1a1a")
|
||||
'(mode-line-inactive :background "#131313"))
|
||||
|
||||
(set-face-attribute 'default nil :family "JetBrainsMono Nerd Font" :height 120)
|
||||
(setq-default line-spacing '(4 . 4))
|
||||
(use-package doom-modeline
|
||||
:ensure t
|
||||
:init (doom-modeline-mode 1))
|
||||
|
||||
;; set mode line at the top of each window
|
||||
(setq-default header-line-format mode-line-format mode-line-format nil)
|
||||
(set-face-attribute 'header-line nil :inherit 'mode-line :background "#131313")
|
||||
|
||||
(set-face-attribute 'default nil :family "JetBrainsMono Nerd Font" :height 120)
|
||||
(setq-default line-spacing '(4 . 4))
|
||||
|
||||
;; Command launcher.
|
||||
(keymap-global-set "C-S-p" #'execute-extended-command)
|
||||
@@ -234,41 +243,20 @@
|
||||
"." #'dired-omit-mode
|
||||
(kbd "RET") #'dired-find-file))
|
||||
|
||||
;;;; 8. Build
|
||||
(setq compile-command "./build.sh"
|
||||
compilation-read-command nil
|
||||
compilation-ask-about-save nil
|
||||
compilation-scroll-output t)
|
||||
;;;; 8. Modules - additional functionality outside of the core init.el
|
||||
;; Setup for orgmode
|
||||
(load (locate-user-emacs-file "modules/org.el") nil 'nomessage)
|
||||
|
||||
(add-hook 'compilation-filter-hook #'ansi-color-compilation-filter)
|
||||
;; Setup for rss feed
|
||||
(load (locate-user-emacs-file "modules/rss.el") nil 'nomessage)
|
||||
|
||||
;; Compilation buffer always at the bottom, full frame width.
|
||||
(add-to-list 'display-buffer-alist
|
||||
'((derived-mode . compilation-mode)
|
||||
(display-buffer-reuse-window display-buffer-at-bottom)
|
||||
(window-height . 0.45)))
|
||||
|
||||
;; C-c C-c builds from the project root.
|
||||
;; C-c b asks first: the prompt is pre-filled with ./build.sh, so type the args after it.
|
||||
(defun my/project-compile-prompt ()
|
||||
"Run `project-compile', prompting to edit the command."
|
||||
(interactive)
|
||||
(let ((compilation-read-command t))
|
||||
(call-interactively #'project-compile)))
|
||||
|
||||
(keymap-global-set "C-c C-c" #'project-compile)
|
||||
(keymap-global-set "C-c b" #'my/project-compile-prompt)
|
||||
|
||||
;; Focus the compilation window when a build starts.
|
||||
(add-hook 'compilation-start-hook
|
||||
(lambda (proc)
|
||||
(when-let* ((win (get-buffer-window (process-buffer proc))))
|
||||
(select-window win))))
|
||||
|
||||
;;;; 9. Modules - additional functionality outside of the core init.el
|
||||
;; Magit and the :git command live in modules/git.el.
|
||||
(load (locate-user-emacs-file "modules/git.el") nil 'nomessage)
|
||||
|
||||
;; Setup for personal build commands and system.
|
||||
(load (locate-user-emacs-file "modules/build.el") nil 'nomessage)
|
||||
|
||||
;; Setup for dev languages, modes, lsp and lsp keybinds.
|
||||
(load (locate-user-emacs-file "modules/development.el") nil 'nomessage)
|
||||
(load (locate-user-emacs-file "modules/dev.el") nil 'nomessage)
|
||||
|
||||
;;; init.el ends here
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
;;; build.el --- Project build, set up for Evil -*- lexical-binding: t; -*-
|
||||
;;; Commentary:
|
||||
;; Loaded from init.el after Evil.
|
||||
;;
|
||||
;; :build Run ./build.sh from the project root.
|
||||
;; :build ARGS Run ./build.sh ARGS, e.g. :build release -v
|
||||
;;
|
||||
;; The compilation buffer opens at the bottom (45% height, full width) and
|
||||
;; takes focus when the build starts. ANSI colours are rendered.
|
||||
;; Kill a running build with M-x kill-compilation.
|
||||
;;; Code:
|
||||
|
||||
(setq compile-command "./build.sh"
|
||||
compilation-read-command nil ; run without prompting
|
||||
compilation-ask-about-save nil
|
||||
compilation-scroll-output t)
|
||||
|
||||
(add-hook 'compilation-filter-hook #'ansi-color-compilation-filter)
|
||||
|
||||
;; Compilation buffer at the bottom, full frame width.
|
||||
(add-to-list 'display-buffer-alist
|
||||
'((derived-mode . compilation-mode)
|
||||
(display-buffer-reuse-window display-buffer-at-bottom)
|
||||
(window-height . 0.45)))
|
||||
|
||||
;; Focus the compilation window when a build starts.
|
||||
(add-hook 'compilation-start-hook
|
||||
(lambda (proc)
|
||||
(when-let* ((win (get-buffer-window (process-buffer proc))))
|
||||
(select-window win))))
|
||||
|
||||
;; :build runs ./build.sh; :build ARGS appends ARGS.
|
||||
(evil-define-command my/ex-build (args)
|
||||
"Run `./build.sh ARGS' from the project root."
|
||||
(interactive "<a>")
|
||||
(let ((compile-command (concat "./build.sh " args))) ; nil args -> ""
|
||||
(project-compile)))
|
||||
|
||||
(evil-ex-define-cmd "build" #'my/ex-build)
|
||||
|
||||
;;; build.el ends here
|
||||
@@ -0,0 +1,99 @@
|
||||
;;; development.el --- Languages, Eglot and code navigation -*- lexical-binding: t; -*-
|
||||
;;; Commentary:
|
||||
;; Loaded from init.el. Requires Evil.
|
||||
;;
|
||||
;; Languages:
|
||||
;; Markdown markdown-mode.
|
||||
;; PHP php-mode, PSR-2 style, 4 spaces.
|
||||
;; Odin odin-mode from git (needs Emacs 30+ for :vc), Eglot + OLS.
|
||||
;; Go go-mode, Eglot + gopls; organize imports and format on save.
|
||||
;;
|
||||
;; Normal/motion state:
|
||||
;; gd definitions gD references K eldoc
|
||||
;; C-t jump back ESC closes any open eldoc window.
|
||||
;;; Code:
|
||||
|
||||
;;;; Markdown
|
||||
(use-package markdown-mode)
|
||||
|
||||
;;;; PHP
|
||||
(use-package php-mode
|
||||
:mode "\\.php\\'"
|
||||
:hook
|
||||
(php-mode . (lambda ()
|
||||
(setq-local indent-tabs-mode nil)
|
||||
(setq-local tab-width 4)
|
||||
(setq-local c-basic-offset 4)))
|
||||
:custom
|
||||
(php-mode-coding-style 'psr2))
|
||||
|
||||
;;;; Odin
|
||||
(use-package odin-mode
|
||||
:vc (:url "https://github.com/mattt-b/odin-mode"
|
||||
:rev :newest)
|
||||
:mode "\\.odin\\'"
|
||||
:hook (odin-mode . eglot-ensure))
|
||||
|
||||
;;;; Go
|
||||
;; Emacs started from the desktop doesn't inherit fish env.
|
||||
(dolist (d '("/usr/local/go/bin" "/home/jason/.go/bin"))
|
||||
(add-to-list 'exec-path d)
|
||||
(setenv "PATH" (concat d ":" (getenv "PATH"))))
|
||||
(setenv "GOPATH" "/home/jason/.go")
|
||||
(setenv "GOCACHE" "/home/jason/.go/cache")
|
||||
|
||||
(defun my/go-before-save ()
|
||||
"Organize imports and format the buffer through Eglot."
|
||||
(when (eglot-managed-p)
|
||||
(eglot-code-actions nil nil "source.organizeImports" t)
|
||||
(eglot-format-buffer)))
|
||||
|
||||
(use-package go-mode
|
||||
:mode "\\.go\\'"
|
||||
:hook ((go-mode . eglot-ensure)
|
||||
(go-mode . (lambda ()
|
||||
(setq-local tab-width 4)
|
||||
(add-hook 'before-save-hook #'my/go-before-save nil t)))))
|
||||
|
||||
;;;; Eglot
|
||||
(use-package eglot
|
||||
:ensure nil
|
||||
:config
|
||||
(setq eglot-autoshutdown t)
|
||||
(add-to-list 'eglot-ignored-server-capabilities :signatureHelpProvider)
|
||||
|
||||
;; Explicit OLS configuration.
|
||||
(add-to-list
|
||||
'eglot-server-programs
|
||||
'(odin-mode
|
||||
. ("/home/jason/.local/bin/ols"
|
||||
:initializationOptions
|
||||
(:odin_command "/home/jason/.odin/odin"
|
||||
:enable_document_symbols t
|
||||
:enable_format t
|
||||
:collections
|
||||
[(:name "core"
|
||||
:path "/home/jason/.odin/core")
|
||||
(:name "vendor"
|
||||
:path "/home/jason/.odin/vendor")])))))
|
||||
|
||||
;; OLS built-in definitions.
|
||||
(setenv "OLS_BUILTIN_FOLDER" "/home/jason/ThirdParty/ols/builtin")
|
||||
|
||||
;;;; Code navigation
|
||||
;; Vim-style code navigation.
|
||||
(evil-define-key '(normal motion) 'global
|
||||
"gd" #'xref-find-definitions
|
||||
"gD" #'xref-find-references
|
||||
"K" #'eldoc
|
||||
(kbd "C-t") #'xref-go-back)
|
||||
|
||||
;; ESC closes any open eldoc window.
|
||||
(defun my/eldoc-close (&rest _)
|
||||
"Quit every window showing an *eldoc* buffer."
|
||||
(dolist (w (window-list))
|
||||
(when (string-prefix-p "*eldoc" (buffer-name (window-buffer w)))
|
||||
(quit-window nil w))))
|
||||
(advice-add 'evil-force-normal-state :after #'my/eldoc-close)
|
||||
|
||||
;;; development.el ends here
|
||||
@@ -1,48 +0,0 @@
|
||||
;;;; Markdown
|
||||
(use-package markdown-mode)
|
||||
|
||||
;;;; Odin
|
||||
(use-package odin-mode
|
||||
:vc (:url "https://github.com/mattt-b/odin-mode"
|
||||
:rev :newest)
|
||||
:mode "\\.odin\\'"
|
||||
:hook (odin-mode . eglot-ensure))
|
||||
|
||||
(use-package eglot
|
||||
:ensure nil
|
||||
:config
|
||||
(setq eglot-autoshutdown t)
|
||||
(add-to-list 'eglot-ignored-server-capabilities :signatureHelpProvider)
|
||||
|
||||
;; Explicit OLS configuration.
|
||||
(add-to-list
|
||||
'eglot-server-programs
|
||||
'(odin-mode
|
||||
. ("/home/jason/.local/bin/ols"
|
||||
:initializationOptions
|
||||
(:odin_command "/home/jason/.odin/odin"
|
||||
:enable_document_symbols t
|
||||
:enable_format t
|
||||
:collections
|
||||
[(:name "core"
|
||||
:path "/home/jason/.odin/core")
|
||||
(:name "vendor"
|
||||
:path "/home/jason/.odin/vendor")])))))
|
||||
|
||||
;; OLS built-in definitions.
|
||||
(setenv "OLS_BUILTIN_FOLDER" "/home/jason/ThirdParty/ols/builtin")
|
||||
|
||||
;;;; Code navigation
|
||||
;; Vim-style code navigation.
|
||||
(evil-define-key '(normal motion) 'global
|
||||
"gd" #'xref-find-definitions
|
||||
"gD" #'xref-find-references
|
||||
"K" #'eldoc
|
||||
(kbd "C-t") #'xref-go-back)
|
||||
|
||||
;; ESC closes any open eldoc window.
|
||||
(defun my/eldoc-close (&rest _)
|
||||
(dolist (w (window-list))
|
||||
(when (string-prefix-p "*eldoc" (buffer-name (window-buffer w)))
|
||||
(quit-window nil w))))
|
||||
(advice-add 'evil-force-normal-state :after #'my/eldoc-close)
|
||||
@@ -0,0 +1,58 @@
|
||||
;;; org.el --- Org appearance -*- lexical-binding: t; -*-
|
||||
;;; Code:
|
||||
|
||||
;; Styled stars, bullets, tags, tables and blocks.
|
||||
(use-package org-modern
|
||||
:hook (org-mode . org-modern-mode))
|
||||
|
||||
(setq org-directory "~/Projects/notebook")
|
||||
(setq org-startup-indented t ; visual indent per level, no real spaces
|
||||
org-hide-emphasis-markers t ; *bold* shows bold, markers hidden
|
||||
org-pretty-entities t ; \rarr, \alpha etc. as symbols
|
||||
org-ellipsis " ▾" ; folded-heading marker
|
||||
org-startup-folded 'show2levels ; open with headings only
|
||||
org-fontify-whole-heading-line t
|
||||
org-fontify-done-headline t
|
||||
org-fontify-quote-and-verse-blocks t
|
||||
org-src-fontify-natively t ; highlight src blocks with their own mode
|
||||
org-src-tab-acts-natively t
|
||||
org-edit-src-content-indentation 0
|
||||
org-return-follows-link t)
|
||||
|
||||
;; org-modern's recommended settings.
|
||||
(setq org-auto-align-tags nil
|
||||
org-tags-column 0
|
||||
org-catch-invisible-edits 'show-and-error
|
||||
org-special-ctrl-a/e t
|
||||
org-insert-heading-respect-content t)
|
||||
|
||||
(add-hook 'org-mode-hook #'visual-line-mode) ; wrap at window edge
|
||||
(add-hook 'org-mode-hook (lambda () (display-line-numbers-mode -1))) ; prose reads better without
|
||||
|
||||
;; doom-themes' own Org fontification fixes (blocks, headings).
|
||||
(doom-themes-org-config)
|
||||
|
||||
;; Heading sizes; 'user survives theme reloads, same as in init.el.
|
||||
(doom-themes-set-faces 'user
|
||||
'(org-document-title :height 1.3 :weight 'bold)
|
||||
'(org-level-1 :height 1.2 :weight 'bold)
|
||||
'(org-level-2 :height 1.15 :weight 'bold)
|
||||
'(org-level-3 :height 1.1 :weight 'bold)
|
||||
'(org-level-4 :height 1.0 :weight 'bold))
|
||||
|
||||
(defun my/notes-index ()
|
||||
"Open the notes index."
|
||||
(interactive)
|
||||
(find-file (expand-file-name "index.org" org-directory)))
|
||||
|
||||
(keymap-global-set "C-c n" #'my/notes-index)
|
||||
|
||||
;; Evil's TAB (= C-i, jump-forward) shadows Org's. Rebind for Org buffers only.
|
||||
(with-eval-after-load 'org
|
||||
(evil-define-key 'normal org-mode-map
|
||||
(kbd "TAB") #'org-cycle ; fold/unfold the heading at point
|
||||
(kbd "<tab>") #'org-cycle ; GUI emits <tab>, so bind both
|
||||
(kbd "RET") #'org-open-at-point
|
||||
(kbd "<backtab>") #'org-shifttab)) ; S-TAB: cycle all headings
|
||||
|
||||
;;; org.el ends here
|
||||
@@ -0,0 +1,278 @@
|
||||
;;; rss.el --- Elfeed for YouTube feeds, played in mpv -*- lexical-binding: t; -*-
|
||||
;;; Commentary:
|
||||
;; Elfeed with a little glue for Evil. Needs the `elfeed' package (MELPA).
|
||||
;;
|
||||
;; :rss / :rss get open elfeed / also fetch all feeds now
|
||||
;;
|
||||
;; Search buffer RET show the entry
|
||||
;; o play in mpv and mark read
|
||||
;; r/u mark read / unread
|
||||
;; A mark everything listed as read
|
||||
;; c pick a channel/feed by name and show only it
|
||||
;; s change the filter; TAB completes +tags
|
||||
;; (type "+seb" TAB -> "+Sebastian_Lague")
|
||||
;; gr fetch all feeds
|
||||
;; q quit
|
||||
;; Entry buffer o play in mpv
|
||||
;; q close
|
||||
;;
|
||||
;; Every feed is tagged with its category (+youtube, +news) and with its
|
||||
;; own channel tag: its name with spaces replaced by "_". So
|
||||
;; "gingerBill" is +gingerBill and "Sebastian Lague" is +Sebastian_Lague.
|
||||
;; Tags match exactly, but in the `s' prompt TAB completes them, ignoring
|
||||
;; case. Give a feed a short tag of your own with a third argument:
|
||||
;; (my/rss-yt "Jonathan Blow highlights" "UC..." 'blow).
|
||||
;;
|
||||
;; Everything else is your normal Evil keys. Nothing is fetched
|
||||
;; automatically; fetching is always manual (:rss get / gr). Fetch errors
|
||||
;; are logged in the *elfeed-log* buffer.
|
||||
;;
|
||||
;; Feeds live in `my/rss-categories' below, grouped by tag. Edit the list
|
||||
;; and restart Emacs.
|
||||
;;; Code:
|
||||
|
||||
(use-package elfeed
|
||||
:ensure t
|
||||
:defer t
|
||||
:custom
|
||||
(elfeed-search-filter "@1-month-ago +unread")
|
||||
;; Be gentle with YouTube: few simultaneous connections.
|
||||
(elfeed-curl-max-connections 4)
|
||||
:config
|
||||
;; Not in :custom: `my/rss-feeds' is defined below, and :custom runs
|
||||
;; immediately, while :config waits until elfeed loads.
|
||||
(setq elfeed-feeds (my/rss-feeds))
|
||||
(my/rss-apply-titles)
|
||||
(my/rss-retag))
|
||||
|
||||
(defun my/rss-yt (name channel-id &optional tag)
|
||||
"Feed entry for a YouTube channel, uploads only (no Shorts).
|
||||
TAG, a symbol, overrides the channel tag made from NAME."
|
||||
(let ((url (concat "https://www.youtube.com/feeds/videos.xml?playlist_id=UULF"
|
||||
(substring channel-id 2))))
|
||||
(if tag (list name url tag) (list name url))))
|
||||
|
||||
(defvar my/rss-categories
|
||||
(list
|
||||
(list 'youtube
|
||||
(my/rss-yt "Awesome" "UCXzw-OdotBUcNA9yhuYQBwA")
|
||||
(my/rss-yt "Coding with Sphere" "UCpwl7jNE9PJc-lBTShNs5TQ")
|
||||
(my/rss-yt "Computerphile" "UC9-y-6csu5WGm29I7JiwpnA")
|
||||
(my/rss-yt "gingerBill" "UCUSck1dOH7VKmG4lRW7tZXg")
|
||||
(my/rss-yt "Jonathan Blow highlights" "UCavhLwXoB9tkqd-KsXpovOQ")
|
||||
(my/rss-yt "Karl Zylinski" "UC5YnADU2rChK7598A9gKygQ")
|
||||
(my/rss-yt "Nic Barker" "UCz-yrxeZYIYdpEZgHGvIydA")
|
||||
(my/rss-yt "Nir Lichtman" "UCAMu6Dso0ENoNm3sKpQsy0g")
|
||||
(my/rss-yt "Ryan Fleury" "UCCsdwE2z_kRL3vfVsd5OGyA")
|
||||
(my/rss-yt "Tariq10x" "UCXyisNI9ezbv7fvGMoSaFKg")
|
||||
(my/rss-yt "The Coding Gopher" "UC-mTIBh__DzAqW495JHXy5A")
|
||||
(my/rss-yt "Tsoding Daily" "UCrqM0Ym_NbK1fqeQG2VIohg")
|
||||
(my/rss-yt "zyapguy" "UCc4IizbM0q_JySK3XUY0Drw")
|
||||
(my/rss-yt "Dylan Falconer" "UCZzs3Umh6sRiYS_IQIQDThw")
|
||||
(my/rss-yt "Gamefromscratch" "UCr-5TdGkKszdbboXXsFZJTQ")
|
||||
(my/rss-yt "Jonas Tyroller" "UC_p_9arduPuxM8DHTGIuSOg")
|
||||
(my/rss-yt "Miziziziz" "UCaoqVlqPTH78_xjTjTOMcmQ")
|
||||
(my/rss-yt "Penusbmic" "UCjU-rielI7RsX1hqsCQdfhw")
|
||||
(my/rss-yt "randy" "UCUmLRMERmJrmUtgnbFfknAg")
|
||||
(my/rss-yt "randy uncut" "UCgXdyySqz7qH-lDiVG-7KwA")
|
||||
(my/rss-yt "raylib" "UC8WIBkhYb5sBNqXO1mZ7WSQ")
|
||||
(my/rss-yt "Sebastian Lague" "UCmtyQOKKmrMVaKuRXz02jbQ")
|
||||
(my/rss-yt "Tantan" "UChl_NKOs1qqh_x7yJfaDpDw")
|
||||
(my/rss-yt "ThinMatrix" "UCUkRj4qoT1bsWpE_C8lZYoQ")
|
||||
(my/rss-yt "Brodie Robertson" "UCld68syR8Wi-GY_n4CaoJGA")
|
||||
(my/rss-yt "ETA PRIME" "UC_0CVCfC_3iuHqmyClu59Uw")
|
||||
(my/rss-yt "Benny Surge" "UCkih_7PNYICxAZi1omr2_Og")
|
||||
(my/rss-yt "bizlychannel" "UCMPGiQ8gwDXFYpwQhX6kK9A")
|
||||
(my/rss-yt "Daz Games" "UCDBCCMlFD-hArPbWv38FINA")
|
||||
(my/rss-yt "Deep Dive Dev" "UC1yGsLABIDAqLVtPnoHbpEA")
|
||||
(my/rss-yt "Flo Woelki" "UC18qytfIhR9cNEjUcgGLl3A")
|
||||
(my/rss-yt "Gohjoe" "UCac9YlOpTLy_wToRb5Bo-DQ")
|
||||
(my/rss-yt "Herbcode" "UC79nyXj9gujAj5CySiy2FAQ")
|
||||
(my/rss-yt "hoff._world" "UCaezB99bVg9xlMS6Jn_ka0A")
|
||||
(my/rss-yt "Inbound Shovel" "UCdYwjLVP-98bptdlQFO_5zQ")
|
||||
(my/rss-yt "Jimmy Oakes" "UChp08hcL-qAJD4LK51ZZZvw")
|
||||
(my/rss-yt "Juby Philosophy" "UCLrpO7U1lnmbRtVxji843-Q")
|
||||
(my/rss-yt "Lance Hedrick" "UCR2_8uHyWcTSV6iIw6BN4rg")
|
||||
(my/rss-yt "Mental Moshpit" "UC5a4hb7i2UAT6DxmGz72hdg")
|
||||
(my/rss-yt "NIGHTRIDE" "UCuYLDxZWv-aal88czKkFvKA")
|
||||
(my/rss-yt "Rockers Games" "UCeq6focWSVKJy5DR1JxDGyw")
|
||||
(my/rss-yt "Slax" "UCc0V8-3xYIT6aNOAreAjRcw")
|
||||
(my/rss-yt "StayAtHomeDev" "UCDshKIMtFjYreCzApleuV8w")
|
||||
(my/rss-yt "Turkey Tom" "UCDKJdFer1phQI95UinPZehw")
|
||||
(my/rss-yt "Zei" "UCywwEsnSmADUyhtSaq5dKNg")
|
||||
(my/rss-yt "Zip Tie Tech" "UCUpt_5O1vYpWAGg77iNMQXA"))
|
||||
(list 'news
|
||||
'("Hacker News" "https://hnrss.org/frontpage?points=100")))
|
||||
"Feeds by tag: each entry is (TAG FEED...), a feed is (NAME URL [CHANNEL-TAG]).
|
||||
The tag is what you filter on in elfeed, e.g. \"+youtube\". Each feed
|
||||
also gets its own channel tag, see `my/rss-channel-tag'.")
|
||||
|
||||
(defun my/rss-slug (name)
|
||||
"Tag symbol made from NAME, with spaces replaced by \"_\"."
|
||||
(intern (replace-regexp-in-string " +" "_" (string-trim name) t t)))
|
||||
|
||||
(defun my/rss-channel-tag (feed)
|
||||
"Channel tag for FEED, (NAME URL [TAG]): TAG if given, else NAME slugged."
|
||||
(or (nth 2 feed) (my/rss-slug (car feed))))
|
||||
|
||||
(defun my/rss-feeds ()
|
||||
"Elfeed feed list, (URL CATEGORY CHANNEL-TAG), from `my/rss-categories'."
|
||||
(mapcan (lambda (cat)
|
||||
(mapcar (lambda (feed)
|
||||
(list (cadr feed) (car cat) (my/rss-channel-tag feed)))
|
||||
(cdr cat)))
|
||||
my/rss-categories))
|
||||
|
||||
(defun my/rss-all-feeds ()
|
||||
"Every (NAME URL) in `my/rss-categories', across all tags."
|
||||
(mapcan (lambda (cat) (copy-sequence (cdr cat))) my/rss-categories))
|
||||
|
||||
(defun my/rss-apply-titles ()
|
||||
"Give each feed the name from `my/rss-categories' as its display title.
|
||||
YouTube playlist feeds all call themselves \"Videos\"; this overrides
|
||||
that, so the list shows the channel and \"=Name\" filters work. The
|
||||
title is stored as feed metadata, which fetching never overwrites."
|
||||
(dolist (feed (my/rss-all-feeds))
|
||||
(setf (elfeed-meta (elfeed-db-get-feed (cadr feed)) :title)
|
||||
(car feed))))
|
||||
|
||||
(defun my/rss-retag ()
|
||||
"Give already-fetched entries their feed's tags from `elfeed-feeds'.
|
||||
Elfeed tags entries only as they arrive, so this catches up entries
|
||||
fetched before a feed's tags changed. Safe to run any time."
|
||||
(interactive)
|
||||
(elfeed-db-ensure)
|
||||
(let ((tags-by-url (make-hash-table :test #'equal))
|
||||
(n 0))
|
||||
(dolist (f elfeed-feeds)
|
||||
(puthash (car f) (cdr f) tags-by-url))
|
||||
(maphash
|
||||
(lambda (_id entry)
|
||||
(let* ((tags (gethash (elfeed-entry-feed-id entry) tags-by-url))
|
||||
(missing (cl-set-difference tags (elfeed-entry-tags entry))))
|
||||
(when missing
|
||||
(apply #'elfeed-tag entry missing)
|
||||
(cl-incf n))))
|
||||
elfeed-db-entries)
|
||||
(when (or (> n 0) (called-interactively-p 'any))
|
||||
(message "rss: retagged %d entries" n))))
|
||||
|
||||
;;;; Playing videos
|
||||
|
||||
(defun my/rss-play (url &rest _)
|
||||
"Play URL in mpv. Its output goes to the *mpv* buffer."
|
||||
(message "mpv: starting %s (can take a few seconds)..." url)
|
||||
(set-process-sentinel
|
||||
(start-process "mpv" "*mpv*" "mpv" url)
|
||||
(lambda (proc _event)
|
||||
(when (and (eq (process-status proc) 'exit)
|
||||
(/= (process-exit-status proc) 0))
|
||||
(message "mpv failed (exit %d), see the *mpv* buffer"
|
||||
(process-exit-status proc))
|
||||
(display-buffer "*mpv*")))))
|
||||
|
||||
;; YouTube links go to mpv, everywhere in Emacs.
|
||||
(with-eval-after-load 'browse-url
|
||||
(add-to-list 'browse-url-handlers
|
||||
'("\\`https?://\\(?:www\\.\\|m\\.\\)?\\(?:youtube\\.com\\|youtu\\.be\\)/"
|
||||
. my/rss-play)))
|
||||
|
||||
;;;; Elfeed
|
||||
|
||||
(defvar my/rss-stagger 4
|
||||
"Seconds between feed fetches. YouTube answers with 404/500 when hit fast.")
|
||||
|
||||
(defun my/rss-fetch ()
|
||||
"Fetch every feed, one at a time, `my/rss-stagger' seconds apart.
|
||||
Run it again to fill in feeds that failed; entries are not duplicated."
|
||||
(interactive)
|
||||
(seq-do-indexed
|
||||
(lambda (feed i)
|
||||
(run-with-timer (* my/rss-stagger i) nil #'elfeed-update-feed (car feed)))
|
||||
elfeed-feeds)
|
||||
(message "rss: fetching %d feeds, about %ds"
|
||||
(length elfeed-feeds) (* my/rss-stagger (length elfeed-feeds))))
|
||||
|
||||
(defun my/rss-all-tags ()
|
||||
"Every tag name: the ones in `elfeed-feeds' plus any in the database."
|
||||
(delete-dups
|
||||
(mapcar #'symbol-name
|
||||
(append (mapcan (lambda (f) (copy-sequence (cdr f))) elfeed-feeds)
|
||||
(elfeed-db-get-all-tags)))))
|
||||
|
||||
(defun my/rss-filter-capf ()
|
||||
"Complete the +tag or -tag at point in the filter prompt."
|
||||
(when (looking-back "\\(?:^\\| \\)[+-]\\([^ ]*\\)" (line-beginning-position))
|
||||
(list (match-beginning 1) (match-end 1)
|
||||
(completion-table-case-fold (my/rss-all-tags))
|
||||
:exclusive 'no)))
|
||||
|
||||
(defvar my/rss-filter-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map (kbd "TAB") #'completion-at-point)
|
||||
map)
|
||||
"Extra keys for the filter prompt.")
|
||||
|
||||
(defun my/rss-filter ()
|
||||
"Elfeed's live filter, with TAB completing +tags and -tags."
|
||||
(interactive)
|
||||
(minibuffer-with-setup-hook
|
||||
(lambda ()
|
||||
(add-hook 'completion-at-point-functions #'my/rss-filter-capf nil t)
|
||||
(use-local-map (make-composed-keymap my/rss-filter-map
|
||||
(current-local-map))))
|
||||
(elfeed-search-live-filter)))
|
||||
|
||||
(defun my/rss-mark-all-read ()
|
||||
"Mark every entry the current filter lists as read.
|
||||
Works on elfeed's list directly, so it doesn't depend on the region or
|
||||
on Evil's visual state. Clear the filter first to mark everything."
|
||||
(interactive)
|
||||
(let ((n (length elfeed-search-entries)))
|
||||
(elfeed-untag elfeed-search-entries 'unread)
|
||||
(elfeed-search-update :force)
|
||||
(message "rss: marked %d entries read" n)))
|
||||
|
||||
(defun my/rss-channel ()
|
||||
"Pick a feed by name and show only its entries (read and unread).
|
||||
Filters on the feed URL, so it works whatever the feed calls itself.
|
||||
Press `s' and clear the filter to go back."
|
||||
(interactive)
|
||||
(let* ((feeds (my/rss-all-feeds))
|
||||
(name (completing-read "Channel: " feeds nil t))
|
||||
(url (cadr (assoc name feeds))))
|
||||
(elfeed-search-set-filter
|
||||
(concat "@6-months-ago =" (regexp-quote url)))))
|
||||
|
||||
;; Elfeed's buffers start in motion state: Evil movement, no editing keys.
|
||||
(evil-set-initial-state 'elfeed-search-mode 'motion)
|
||||
(evil-set-initial-state 'elfeed-show-mode 'motion)
|
||||
|
||||
(with-eval-after-load 'elfeed-search
|
||||
(evil-define-key 'motion elfeed-search-mode-map
|
||||
(kbd "RET") #'elfeed-search-show-entry
|
||||
"o" #'elfeed-search-browse-url ; plays via `browse-url-handlers', marks read
|
||||
"r" #'elfeed-search-untag-all-unread
|
||||
"u" #'elfeed-search-tag-all-unread
|
||||
"A" #'my/rss-mark-all-read
|
||||
"c" #'my/rss-channel
|
||||
"s" #'my/rss-filter
|
||||
"gr" #'my/rss-fetch
|
||||
"q" #'elfeed-search-quit-window))
|
||||
|
||||
(with-eval-after-load 'elfeed-show
|
||||
(evil-define-key 'motion elfeed-show-mode-map
|
||||
"o" #'elfeed-show-visit
|
||||
"q" #'elfeed-kill-buffer))
|
||||
|
||||
;; :rss opens elfeed; :rss get also fetches every feed now.
|
||||
(evil-define-command my/rss (args)
|
||||
"Open elfeed, or fetch all feeds too with `:rss get'."
|
||||
(interactive "<a>")
|
||||
(elfeed)
|
||||
(when (equal (string-trim (or args "")) "get")
|
||||
(my/rss-fetch)))
|
||||
|
||||
(evil-ex-define-cmd "rss" #'my/rss)
|
||||
|
||||
;;; rss.el ends here
|
||||
@@ -21,7 +21,6 @@ set -gx COLORTERM "truecolor"
|
||||
set -gx DEBUG 1
|
||||
set -gx GOPATH "$HOME/.go"
|
||||
set -gx GOCACHE "$HOME/.go/cache"
|
||||
set -gx GOROOT /usr/local/go
|
||||
set -gx OLS_BUILTIN_FOLDER "/home/jason/ThirdParty/ols/builtin"
|
||||
|
||||
# Direnv
|
||||
@@ -82,6 +81,10 @@ alias bat 'bat --theme="ansi" --paging=never'
|
||||
alias :q 'exit'
|
||||
alias files 'thunar .'
|
||||
alias fetch 'pfetch'
|
||||
# Map 'php' directly to FrankenPHP's bundled PHP CLI runtime
|
||||
alias php="frankenphp php-cli"
|
||||
# Optional: A shorthand to spin up your local dev server instantly using your Caddyfile
|
||||
alias phpserve="frankenphp php-server --config Caddyfile"
|
||||
|
||||
# Custom shortcuts
|
||||
alias reload 'source ~/.config/fish/config.fish'
|
||||
|
||||
+3
-2
@@ -151,9 +151,10 @@ if [ "$DO_INSTALL" = true ]; then
|
||||
# core utilities & CLI tools
|
||||
git fd jq fzf ripgrep tree direnv make
|
||||
bat unzip 7zip tar gzip bzip2 xz ark
|
||||
mpv xfce4-screenshooter xkill xwininfo
|
||||
xdotool wmctrl
|
||||
# build & dev tools
|
||||
emacs-x11 alacritty base-devel valgrind
|
||||
xfce4-screenshooter xkill xwininfo xdotool wmctrl
|
||||
emacs-x11 alacritty base-devel valgrind go
|
||||
)
|
||||
|
||||
MISSING_PACKAGES=()
|
||||
|
||||
Executable
+64
@@ -0,0 +1,64 @@
|
||||
#!/bin/bash
|
||||
# ---------------------------------------------------------------------------------
|
||||
# Steam install recipe
|
||||
# Target: Void Linux (x86_64 glibc only)
|
||||
# Enables nonfree + multilib repos, installs Steam, 32-bit runtime libs, GPU drivers
|
||||
# Usage: GPU=amd|nvidia|intel ./steam.sh (default: amd)
|
||||
# ---------------------------------------------------------------------------------
|
||||
set -e
|
||||
|
||||
GPU="${GPU:-amd}"
|
||||
|
||||
if [ "$(xbps-uhelper arch)" != "x86_64" ]; then
|
||||
echo "Steam requires x86_64 glibc. Aborting." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Enabling nonfree and multilib repositories..."
|
||||
sudo xbps-install -Sy void-repo-nonfree void-repo-multilib void-repo-multilib-nonfree
|
||||
sudo xbps-install -Sy # sync the newly added repos
|
||||
|
||||
echo "Installing Steam and 32-bit runtime libraries..."
|
||||
sudo xbps-install -y \
|
||||
steam \
|
||||
steam-udev-rules \
|
||||
libgcc-32bit \
|
||||
libstdc++-32bit \
|
||||
libdrm-32bit \
|
||||
libglvnd-32bit \
|
||||
mesa-dri \
|
||||
mesa-dri-32bit \
|
||||
vulkan-loader \
|
||||
vulkan-loader-32bit \
|
||||
alsa-lib-32bit \
|
||||
libpulseaudio-32bit
|
||||
|
||||
echo "Installing GPU drivers ($GPU)..."
|
||||
case "$GPU" in
|
||||
amd)
|
||||
sudo xbps-install -y \
|
||||
mesa-vulkan-radeon mesa-vulkan-radeon-32bit \
|
||||
mesa-vaapi
|
||||
;;
|
||||
nvidia)
|
||||
sudo xbps-install -y nvidia nvidia-libs nvidia-libs-32bit
|
||||
;;
|
||||
intel)
|
||||
sudo xbps-install -y \
|
||||
mesa-vulkan-intel mesa-vulkan-intel-32bit \
|
||||
intel-video-accel
|
||||
;;
|
||||
*)
|
||||
echo "Unknown GPU '$GPU' (amd|nvidia|intel)" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "Reloading udev rules..."
|
||||
sudo udevadm control --reload
|
||||
sudo udevadm trigger
|
||||
|
||||
echo ""
|
||||
echo "✓ Steam installed. Log out/in (or reboot) before first launch."
|
||||
echo ""
|
||||
|
||||
Reference in New Issue
Block a user