kakafarm.el (16062B)
1 ;;; kakafarm.el --- Various functions for my GNU Emacs configuration. -*- lexical-binding: t; -*- 2 3 ;; Copyright (C) 2024 Yuval Langer 4 5 ;; Author: Yuval Langer <yuval.langer@gmail.com> 6 ;; Version: 0.0.0 7 ;; Keywords: Personal, Auxiliary 8 ;; URL: https://codeberg.org/kakafarm/dotfiles/ 9 10 ;; This program is free software; you can redistribute it and/or modify 11 ;; it under the terms of the GNU General Public License as published by 12 ;; the Free Software Foundation, either version 3 of the License, or 13 ;; (at your option) any later version. 14 15 ;; This program is distributed in the hope that it will be useful, 16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 ;; GNU General Public License for more details. 19 20 ;; You should have received a copy of the GNU General Public License 21 ;; along with this program. If not, see <https://www.gnu.org/licenses/>. 22 23 ;;; Commentary: 24 25 ;; Do not expect any of these functions to remain stable. 26 ;; 27 ;; The functions are ordered in an alphabetic order. I do not know 28 ;; if it makes much sense, but so be it. 29 30 ;;; Code: 31 32 (require 'cl-lib) 33 34 ;;;###autoload 35 (defun kakafarm/advice-remove-all (function) 36 "Remove every advice function from FUNCTION." 37 (advice-mapc 38 (lambda (advice-function properties-alist) 39 (advice-remove function 40 advice-function)) 41 function)) 42 43 ;;;###autoload 44 (defun kakafarm/call-process-with-string-as-input (program &optional input-string &rest args) 45 (with-temp-buffer 46 (let ((our-output-buffer (current-buffer))) 47 (if input-string 48 (with-temp-buffer 49 (let ((our-input-buffer (current-buffer))) 50 (progn 51 (erase-buffer) 52 (insert input-string) 53 (apply 'call-process-region 54 (buffer-end -1) 55 (buffer-end 1) 56 program 57 nil 58 our-output-buffer 59 nil 60 args)))) 61 (apply 'call-process 62 program 63 nil 64 our-output-buffer 65 nil 66 args))) 67 (buffer-string))) 68 69 ;; (list (kakafarm/call-process-with-string-as-input "cat" 70 ;; "cat says moo") 71 ;; (kakafarm/call-process-with-string-as-input "echo" 72 ;; nil 73 ;; "-n" 74 ;; "echo echo echo")) 75 76 ;;;###autoload 77 (defun kakafarm/colorize-compilation () 78 "Colorize from `compilation-filter-start' to `point'. 79 80 Used to convert raw ANSI color codes into visually (sometimes dis-)pleasing colors. 81 82 From: 83 84 https://endlessparentheses.com/ansi-colors-in-the-compilation-buffer-output.html" 85 (let ((inhibit-read-only t)) 86 (ansi-color-apply-on-region compilation-filter-start 87 (point)))) 88 89 ;;;###autoload 90 (defun kakafarm/copy-elfeed-links () 91 (interactive) 92 93 (cl-letf* ((elfeed-entry-to-url-nl (lambda (entry) 94 (concat (elfeed-entry-link entry) "\n"))) 95 (all-urls-string (apply 'concat 96 (mapcar elfeed-entry-to-url-nl 97 (elfeed-search-selected))))) 98 (with-temp-buffer 99 (insert all-urls-string) 100 (kill-region (point-min) 101 (point-max))))) 102 103 ;;;###autoload 104 (defun kakafarm/drop-while (lst predp) 105 (named-let loop ((lst lst)) 106 (cond 107 (() 108 lst) 109 ((predp (car lst)) 110 (cdr lst)) 111 (t 112 (loop (cdr lst)))))) 113 114 ;;;###autoload 115 (defun kakafarm/easy-underscore (arg) 116 "Convert all inputs of semicolon to an underscore 117 If given ARG, then it will insert an actual semicolon. 118 119 from https://www.youtube.com/watch?v=6R-73hsL5wk" 120 (interactive "P") 121 (message (format "%s" arg)) 122 (if arg 123 (insert ";") 124 (insert "_"))) 125 126 ;;;###autoload 127 (defun kakafarm/elfeed-sort-feed-tags (a-feed) 128 (cond 129 ((stringp a-feed) 130 a-feed) 131 (t 132 (let* ((feed-url (car a-feed)) 133 (tags (cdr a-feed)) 134 (tags-as-strings (mapcar #'symbol-name 135 tags)) 136 (sorted-tags (sort tags-as-strings 137 #'string-lessp)) 138 (tags-as-symbols (mapcar #'intern sorted-tags))) 139 (cons feed-url tags-as-symbols))))) 140 141 ;;;###autoload 142 (defun kakafarm/elfeed-compare-feeds-urls (feed-a feed-b) 143 (string-lessp (car feed-a) 144 (car feed-b))) 145 146 ;;;###autoload 147 (defun kakafarm/elfeed-sort-feeds (feeds) 148 "Sort A-FEED, an `elfeed-feeds' list." 149 (sort (mapcar #'kakafarm/elfeed-sort-feed-tags 150 feeds) 151 #'kakafarm/elfeed-compare-feeds-urls)) 152 153 ;;;###autoload 154 (defun kakafarm/ffap-browse-urls () 155 "Open all visible URLs." 156 (interactive) 157 158 (let* ((urls (mapcar 'car (ffap-menu-rescan))) 159 (urls-newlined (mapcar (lambda (url) (concat url "\n")) 160 urls)) 161 (prompt (format "Open URLs? [y/n] 162 163 %s" 164 (apply 'concat 165 urls-newlined)))) 166 (when (y-or-n-p prompt) 167 (dolist (url urls) 168 (browse-url url))))) 169 170 ;;;###autoload 171 (defun kakafarm/kill-ring-save-unlines () 172 "Like `kill-ring-save', but also unlines and trims the newly killed stuff." 173 (interactive) 174 175 (kill-ring-save (point) (mark)) 176 177 (with-temp-buffer 178 (yank-pop) 179 (goto-char 1) 180 (replace-regexp "\n+" " ") 181 (let ((trimmed (string-trim (buffer-string)))) 182 (with-temp-buffer 183 (insert trimmed) 184 (kill-region (point-min) (point-max)))))) 185 186 ;;;###autoload 187 (defun kakafarm/list-all-http-or-https () 188 (interactive) 189 (dolist (url (let* ((list-of-lines 190 (split-string (substring-no-properties (buffer-string)) 191 "[ \n]"))) 192 (cl-reduce (lambda (accumulator line) 193 (if (string-match-p "https?://.+" 194 line) 195 (cons line accumulator) 196 accumulator)) 197 list-of-lines 198 :initial-value '()))) 199 (message "%s" url))) 200 201 ;;;###autoload 202 (defun kakafarm/org-roam-keyword-is-filetags-p (keyword-node) 203 (equal (org-element-property :key 204 keyword-node) 205 "FILETAGS")) 206 207 ;;;###autoload 208 (defun kakafarm/org-roam-filetags-keyword-is-publishable-p (filestags-keyword-node) 209 (seq-contains-p (split-string (org-element-property :value 210 filestags-keyword-node) 211 ":") 212 "publish")) 213 214 ;;;###autoload 215 (defun kakafarm/org-roam-publishable-node-p (org-filename) 216 (with-temp-buffer 217 (insert-file-contents org-filename) 218 (org-element-map 219 (org-element-parse-buffer) 220 'keyword 221 (lambda (keyword) 222 (and (kakafarm/org-roam-keyword-is-filetags-p keyword) 223 (kakafarm/org-roam-filetags-keyword-is-publishable-p keyword))) 224 nil 225 t))) 226 227 ;;;###autoload 228 (defun kakafarm/org-roam-sitemap (title list-of-org-links) 229 (message (format "kakafarm/org-roam-sitemap title: %S; list-of-links: %S\n" 230 title 231 list-of-org-links)) 232 ;; (let ((a-publishable-org-roam-node 233 ;; (seq-filter (lambda (org-link-list) 234 ;; (pcase org-link-list 235 ;; (`(,org-link) 236 ;; (with-temp-buffer 237 ;; (insert org-link) 238 ;; (org-element-map (org-element-parse-buffer) 'link 239 ;; (lambda (link) 240 ;; ;; Check if file linked is publishable. 241 ;; (kakafarm/org-roam-publishable-node-p 242 ;; (concat "~/mine/roam/" 243 ;; (org-element-property :path 244 ;; link)))) 245 ;; nil 246 ;; t))))) 247 ;; list-of-org-links))) 248 ;; (message "poop %S" a-publishable-org-roam-node)) 249 250 (concat 251 "# -*- encoding: utf-8 -*-\n" 252 "#+OPTIONS: ^:nil author:nil html-postamble:nil\n" 253 ;;"#SETUPFILE: ./simple_inline.theme\n" ; No theme yet. 254 "#+FILETAGS: publish\n" 255 "#+TITLE: " title "\n\n" 256 (org-list-to-org list-of-org-links) "\n" 257 258 ;; TODO: No sitemap SVG yet because it shows all the fucking 259 ;; files in the org-roam database. 260 ;; 261 ;;"file:sitemap.svg\n" 262 )) 263 264 ;;;###autoload 265 (defun kakafarm/org-roam-publication-wrapper (plist filename pubdir) 266 ;; (when (kakafarm/org-roam-publishable-node-p filename) 267 ;; nil) 268 ;;(org-roam-graph) ; How the fuck do I make this one not show every fucking node in the org-roam database?! 269 (org-html-publish-to-html plist 270 filename 271 pubdir) 272 (setq kakafarm/org-roam-project-publish-time 273 (cadr (current-time)))) 274 275 ;;;###autoload 276 (defun kakafarm/org-roam-custom-link-builder (node) 277 (let ((node-file (org-roam-node-file node))) 278 ;; (when (kakafarm/org-roam-publishable-node-p node-file) 279 ;; nil) 280 (message (format "kakafarm/org-roam-custom-link-builder: %S" node)) 281 (concat (file-name-base node-file) 282 ".html"))) 283 284 ;;;###autoload 285 (defun kakafarm/percent-read () 286 "Display percent read by current cursor location vs. total characters in file." 287 288 (interactive) 289 290 (message "%.2f%%" 291 (* 100 292 (/ (float (- (point) 1)) 293 (+ 1 (buffer-size)))))) 294 295 ;;;###autoload 296 (defun kakafarm/percent-read-point-min-max () 297 "Display percent read by current cursor location vs. place within (point-min) and (point-max)." 298 299 (interactive) 300 301 (let* ((our-location (point)) 302 (our-location-0-indexed (- our-location 1))) 303 (message "%.2f%%" 304 (* 100 305 (/ (float (- our-location-0-indexed 306 (point-min))) 307 (- (point-max) 308 (point-min))))))) 309 310 ;;;###autoload 311 (defun kakafarm/recenter-top-bottom (original-function &rest arguments) 312 "Move view such that point is 4 lines from the top of the frame when function is `recenter-top-bottom'." 313 314 (cond 315 ((null (car arguments)) 316 (apply original-function '(4))) 317 (t 318 (apply original-function arguments)))) 319 320 ;;;###autoload 321 (defun kakafarm/pulse-current-region (&rest _) 322 "Pulse the selected bit, either the marked region or if there's no 323 mark, the bit between mark and point... or something like 324 that... I don't even work here. 325 326 From Goparism (https://www.youtube.com/@goparism) 327 https://www.youtube.com/watch?v=oQ9JE9kRwG8 which is from the 328 user 0xMii on R***** which copied it from 329 who-knows-where-and-who." 330 (if mark-active 331 (pulse-momentary-highlight-region (region-beginning) 332 (region-end)) 333 (pulse-momentary-highlight-region (mark) 334 (point)))) 335 336 ;;;###autoload 337 (defun kakafarm/multi-vterm-weechat () 338 "Either start a weechat vterm buffer, or switch to it if it already exists." 339 340 (interactive) 341 342 (let* ((weechat-buffer-name "weechat") 343 (maybe-weechat-buffer (get-buffer weechat-buffer-name))) 344 (cond 345 ((multi-vterm-buffer-exist-p maybe-weechat-buffer) 346 (switch-to-buffer maybe-weechat-buffer)) 347 (t 348 (let ((vterm-shell (expand-file-name "~/bin/w"))) 349 (multi-vterm) 350 (rename-buffer weechat-buffer-name)))))) 351 352 ;;;###autoload 353 (defun kakafarm/sentence-end-double-nilify-for-read-only-buffers () 354 "Set `sentence-end-double-space' in read-only buffer to `nil'." 355 (when buffer-read-only 356 (setq-local sentence-end-double-space 357 nil))) 358 359 ;; Uploading README.html from README.org stuff. 360 ;;;###autoload 361 (defun kakafarm/srht-repo-id (repository-name) 362 "Returns the unique numerical I Dentification associated with 363 every sourcehut repository. 364 365 https://www.tomsdiner.org/blog/post_0003_sourcehut_readme_org_export.html" 366 367 (interactive "sRepo name: ") 368 (let* ((srht (netrc-machine (netrc-parse "~/.netrc.gpg") 369 "repo.git.sr.ht")) 370 (srht-token (netrc-get srht 371 "password")) 372 (our-response (with-temp-buffer 373 (call-process "curl" 374 nil 375 (list (current-buffer) nil) 376 nil 377 "--oauth2-bearer" srht-token 378 "-G" 379 "--data-urlencode" 380 (concat "query=query { me { repository(name: \"" 381 repository-name 382 "\") { id } } }") 383 "https://git.sr.ht/query") 384 (buffer-string))) 385 (repository-id (string-trim (kakafarm/call-process-with-string-as-input "jq" 386 our-response 387 ".data.me.repository.id")))) 388 (if (called-interactively-p) 389 (message "Repository ID: %S" repository-id) 390 repository-id))) 391 392 ;;;###autoload 393 (defun kakafarm/srht-set-readme (repository-id) 394 "Export the current file to HTML and set the result as README for 395 the sourcehut repo identified by ID. 396 397 https://www.tomsdiner.org/blog/post_0003_sourcehut_readme_org_export.html" 398 399 (interactive "sRepository ID: ") 400 (let* ((srht (netrc-machine (netrc-parse "~/.netrc.gpg") 401 "repo.git.sr.ht")) 402 (srht-token (netrc-get srht 403 "password")) 404 (readme.html (org-export-as (org-export-get-backend 'html) 405 nil 406 nil 407 t)) 408 (our-json-query (kakafarm/call-process-with-string-as-input 409 "jq" 410 readme.html 411 "-sR" 412 (concat " 413 { \"query\": \"mutation UpdateRepo($id: Int!, $readme: String!) { updateRepository(id: $id, input: { readme: $readme }) { id } }\", 414 \"variables\": { 415 \"id\": " repository-id ", 416 \"readme\": . 417 } 418 }")))) 419 (kakafarm/call-process-with-string-as-input "curl" 420 our-json-query 421 "--oauth2-bearer" srht-token 422 "-H" "Content-Type: application/json" 423 "-d@-" 424 "https://git.sr.ht/query"))) 425 426 ;;;###autoload 427 (defun kakafarm/take-while (lst predp) 428 (named-let loop ((lst lst) 429 (accumulator '())) 430 (cond 431 ((null lst) 432 (reverse accumulator)) 433 ((predp (car lst)) 434 (reverse accumulator)) 435 (t 436 (loop (cdr lst) 437 accumulator))))) 438 439 ;;;###autoload 440 (defun kakafarm/url-response-to-body (response) 441 (cdr (kakafarm/drop-while 442 (string-split response 443 "\n") 444 (lambda (line) 445 (not (string-blank-p line)))))) 446 447 ;;;###autoload 448 (defun kakafarm/yank-unlines () 449 "`yank' with each consecutive newlines converted to a single space, and trim both ends." 450 (interactive) 451 452 (insert 453 (string-trim 454 (with-temp-buffer 455 (yank) 456 (goto-char 1) 457 (replace-regexp "\n+" " ") 458 (buffer-string))))) 459 460 (provide 'kakafarm) 461 462 ;;; Local Variables: 463 ;;; read-symbol-shorthands: (("kf/" . "kakafarm/")) 464 ;;; End: 465 ;;; kakafarm.el ends here.