#+TITLE:Doomed Chicken
This is another attempt at making a decent Emacs configuration for the chicken I am. Having multiple files with a poor consistence or a directed goal always bit me in the back relatively quickly. So this time, I'll try to write something documenting my process to warn my future me about my current configuration mishaps.
Because I'm trying to make this setup my daily driver for personal programming and writing, I'm going to list here the programming/writing languages I might use in the future with that setup, so expect this configuration to be revolving around this list:
Markdown
I heard I could manage my packages.el file directly from here. So why not
doing it?
First, the header so Doom shouldn't byte-compile this file. It'd make the
updates harder due to requiring a manual doom build invocation for every
change done. I'm directly stealing it from the example provided by Doom Emacs.
;; -*- no-byte-compile: t; -*- ;;; .doom.d/packages.el
(package! doom-nano-modeline
:recipe (:host github
:repo "ronisbr/doom-nano-modeline"))
It's rather solid for a terminal emulator. Too bad it doesn't seem to work on Windows. (Actually I haven't tried so hard, I just don't always have the time to find a way to compile it)
(package! vterm :ignore (eq system-type 'windows-nt))
Making graphs is fun and GraphViz, might it be a bit limited in terms of ease of access, is still quite solid for basic stuff.
(package! graphviz-dot-mode :ignore (not (executable-find "dot")))
Python X allows me to have a notebook-ish workflow. More about this in its configuration section
(package! python-x :ignore (not (executable-find "python")))
Not having emacs be stuck when doing heavier stuff seems great. Let's use that.
(package! ob-async)
On some computers I have Iosevka installed and using both Iosevka Extended and the regular version is neat.
(package! mixed-pitch)
I love using box drawing characters, so using them when possible is cool. Also it makes me use emacs as a drawing tool as it helps avoiding looking up charmap for the right character all the time.
Note that with evil, digraphs are back.
(package! ascii-art-to-unicode)
Experimenting with that package. I might need to fork it in the future to add the latest P8 additions.
(package! pico8-mode :recipe (:host github :repo "Kaali/pico8-mode"))
(package! powershell.el :ignore (not (eq system-type 'windows-nt)) :recipe (:host github :repo "jschaf/powershell.el"))
(package! wikinfo :recipe (:host github :repo "progfolio/wikinfo")) (package! wikinforg :recipe (:host github :repo "progfolio/wikinforg"))
(package! w3m)
I'd like to write math stuff (notably on the computer rendering topic). Why not having something that automatically displays the inline previews?
What remains is adding a way to detect the needed executables in the PATH.
(package! org-fragtog)
(package! valign :recipe (:host github :repo "casouri/valign" :branch "master"))
For workplace-local modifications
(package! work :recipe (:local-repo "lisp/work"))
I had issues before dealing with specific patterns at configuration time. At this moment, I don't have all the packages nor do I want to deal with them manually. So I'm reinventing the wheel at some places to make the configuration easier to use.
I haven't found one bundled with emacs yet. I'm using a homebrew filter function
directly taken from a cookbook page here so I can skip requiring cl or seq
at launch.
(defun chicken/filter (condp lst)
(delq nil
(mapcar (lambda (x) (and (funcall condp x) x)) lst)))
Because why not? I'm planning to use that around launch to toggle between two themes but I worry about the actual boot time impact.
Currently untangled because it doesn't serve any use for now.
(defun chicken/uses-dark-mode-p()
(let ((windows-get-mode-command "powershell \"Get-ItemPropertyValue -Path HKCU:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize -Name SystemUsesLightTheme\""))
(cond
((eq system-type 'windows-nt)
(string= "0\n" (shell-command-to-string windows-get-mode-command)))
(t (message "Ok")))))
Based on a code found here. It's not really used here yet, but it could be useful to diagnose long configuration setting in my configuration.
(defmacro chicken/measure-time-m (&rest body)
"Measure the time it takes to evaluate BODY."
`(let ((time (current-time)))
,@body
(message "%.06f" (float-time (time-since time)))))
(use-package! doom-nano-modeline
:config
(doom-nano-modeline-mode 1)
(global-hide-mode-line-mode 1)
(setq default-frame-alist
(append (list
'(min-height . 1)
'(height . 45)
'(min-width . 1)
'(width . 81)
'(vertical-scroll-bars . nil)
'(internal-border-width . 16)
'(left-fringe . 1)
'(right-fringe . 1)
'(tool-bar-lines . 0)
'(menu-bar-lines . 0)))))
It's 2024, my Emacs config needs a small refresh, so I'll be using rougier's NANO theme for a while.
(after! doom-themes (load-theme 'doom-nano-dark t))
The other basic configuration I usually do first too is setting a font. PragmataPro has been my newest typographic friend as it's really good for what it's made for: displaying text in a flexible yet consistent way. Wait, I just described fonts. Yet, Pragmata is neicely designed and made in a way I'm still discovering little details after weeks of daily usage, like properly managing combining characters like F⃣.. I really like those small touches and of course the mighty ligatures.
On the other hand, I don't always want to install all the fonts everywhere, so let's build first a font selector so I can gracefully fallback on other fonts when needed.
(defun chicken/select-first-available-font (fonts-to-select)
(let ((available-fonts (font-family-list)))
(car (chicken/filter (lambda (elt) (member elt available-fonts)) fonts-to-select))))
Now the font proper selection
(let ((base-size 14)
(code-font (chicken/select-first-available-font
'("PragmataPro Mono Liga"
"PragmataPro Liga"
"PragmataPro"
"Iosevka Custom"
"Iosevka"
"Iosevka SS08"
"InputMonoCompressed"
"Cascadia Code PL"
"Cascadia Code"
"Consolas"
"Courrier New")))
(variable-font (chicken/select-first-available-font
'("Iosevka Extended"
"Iosevka SS08 Extended"
"InputSansCompressed"
"Segoe UI")))
(symbol-font (chicken/select-first-available-font
'("PragmataPro Liga"
"PragmataPro"
"Segoe Color Emoji"
"InputMonoCompressed"
"Iosevka Custom"
"Iosevka SS08"
"Iosevka"
"Segoe UI")))
(serif-font (chicken/select-first-available-font
'("Iosevka Slab"
"InputSerifCompressed"
"Courrier New"
"Courrier New"))))
(setq doom-font
(font-spec :family code-font :size base-size)
doom-variable-pitch-font
(font-spec :family variable-font :size base-size)
doom-symbol-font
(font-spec :family symbol-font :size base-size)
doom-big-font
(font-spec :family code-font :size (* base-size 2))
doom-serif-font
(font-spec :family serif-font :size base-size)))
A note about the serif font: I can't set the styling set for a given font on
emacs, so I can't use Pragmata for the serif font. I'm currently having issues
with fixed-pitch-serif as it doesn't properly load the doom-font, so I am
resorting to use a custom serif font, Iosevka Slab, from the Iosevka forge, my
other favorite programming font. Actually, they blend well together, even if
Iosevka Slab feels ever so slightly too thick against Pragmata.
PragmataPro's ligatures have been enabled within init.el though the
pretty-code layer and it's optional specialization for this font. No more
setting is to be done for this font. Yet I wonder if I want to determine how to
add specific replacements (like lambda → λ ).
Gruvbox-light doesn't need a font as think as its dark alternative.
I need to factorize the way I select the fonts so I can use them here too.
(custom-set-faces! '(line-number :slant italic) '(org-default :inherit default :family "Iosevka Extended Slab") '(org-quote :inherit default :family "Iosevka Extended Slab") '(org-code :inherit default :family "PragmataPro Mono Liga") '(org-block :inherit default :family "PragmataPro Mono Liga"))
(after! ligatures (setq +ligatures-extras-in-modes '(org-mode rustic-mode)))
I'm trying to slightly tweak the modeline to show some info like the word count and forcing the usage of icons for situations where I use emacs in daemon mode, which occured quite often on Windows with Spacemacs, due to the latter's increased boot time.
I'm disabling the font icons when one of the fonts (here GitHub's) isn't present so I can directly fallback on the unicode symbols. Allows me to tone down the visual noise.
(after! doom-modeline
(if (member "github-octicons" (font-family-list))
(progn
(setq doom-modeline-icon t)
(setq doom-modeline-major-mode-icon t))
(progn
(setq doom-modeline-icon nil)
(setq doom-modeline-unicode-fallback t)))
(setq doom-modeline-height 16))
Python-x allows me to have the same cell-based workflow than on Jupter or
Spyder. I'd like also to use similar separators to what I currently use (# %%).
(after! python-x (python-x-setup) (setq python-section-delimiter "# %%"))
I have usually two locations for my own note repository. On Windows, I like to put it in a folder located in the root folder of a hard drive while on Linux, I prefer having it at the root of my home folder. This prevents having spaces in the base folder path.
Right now, the Windows' version is relatively bare, I only have setups where I
use C: or D: as drives to store my notes folder, directly on the root, but
maybe in the future I'd like to move it, so I should plan to support future
configurations later.
Using the use-package configuration scope instead of after! because org
expands some configured variable at initialization (for instance the capture
file locations are derived from the org directory), so the after! hook won't
update those variables.
(let ((base-folder-name "Notes"))
(when (eq system-type 'windows-nt)
;; HACK I usually have two disk drives
(if (file-directory-p (concat "C:/" base-folder-name))
(setq org-directory (concat "C:/" base-folder-name))
(setq org-directory (concat "D:/" base-folder-name))))
(when (eq system-type 'gnu/linux)
;; TODO Factorize with let
(let ((notes-folder (concat
(file-name-as-directory (getenv "HOME"))
base-folder-name)))
(if (file-directory-p notes-folder)
(setq org-directory notes-folder)
(message "Can't find the org note folder.")))))
Instead of having a global attachment dir, I'm going to use multiple folders as I have multiple org base folders
(after! org (setq org-attach-id-dir ".attach/"))
Emacs 27 adds a face attribute that allows a line background to extend past the
last character. org-block has this disabled in doom-gruvbox(-light). Let's add
it back. This is mostly visible in the scratch buffer where the background is
using a different background color.
Also tweaking the ellipsis character to actually use an ellipsis character and disabling the line numbers.
(after! org (setq org-ellipsis "…") (custom-set-faces! '(org-block :extend t)) (add-hook 'org-mode-hook (lambda () (setq-local display-line-numbers nil))))
I kinda like this feature and want it back on C-k on Org. Evil-org put its own mapping at this place so I have to hijack this key after its configuration.
(after! evil-org
(map! :map evil-org-mode-map
:i "C-k" 'evil-insert-digraph))
(after! org
(custom-set-faces!
'(org-table :inherit fixed-pitch)
'(org-table-header :inherit fixed-pitch)
'(org-brain-wires :inherit fixed-pitch)))
I'd like to track when I finish tasks. I'm not feeling that adding a note each time I close an item might be the best thing as I'd get tired of the prompt really quickly. I'll reserve this to manual additions.
(after! org (setq org-log-done 'time))
Here will be located a routine to determine which folder we want to write the default brain(s) down. A small fix to avoid org-brain's key bindings be overwritten by evil.
(after! org-brain (evil-set-initial-state 'org-brain-visualize-mode 'emacs) (custom-set-faces! `(org-brain-child :inherit fixed-pitch :foreground ,(doom-color 'blue)) `(org-brain-parent :inherit fixed-pitch :foreground ,(doom-color 'dark-blue)) `(org-brain-wires :inherit fixed-pitch :weight light :foreground ,(doom-color 'base5))) )
Working icon display with all-the-icons to have a small icon before various
kind of resource links.
(after! org-brain
(defun org-brain-insert-resource-icon (link)
"Insert an icon, based on content of org-mode LINK."
(let ((starts_with_http (string-prefix-p "http" link)))
(insert (format "%s "
(cond
;; File extensions
;; TODO use string-suffix-p everywhere or string-match?
;; The latter might give wrong results on filenames with
;; multiple extensions.
;;
;; TODO Propertize works here. Color everything?
;; (propertize (all-the-icons-faicon "file-code-o") 'face '(:foreground "red") )
((string-suffix-p ".pdf" link)
(all-the-icons-octicon "file-pdf"))
((string-match "shadertoy\\.com" link)
(all-the-icons-fileicon "vertex-shader"))
((string-match "\\.cpp" link)
(all-the-icons-alltheicon "cplusplus"))
((string-match "\\.cs" link)
(all-the-icons-alltheicon "csharp"))
((string-match "\\.java" link)
(all-the-icons-alltheicon "java"))
((string-match "\\.lua" link)
(all-the-icons-fileicon "lua"))
((string-match "\\.xml" link)
(all-the-icons-faicon "file-code-o"))
((string-match "\\.xaml" link)
(all-the-icons-faicon "file-code-o"))
;; [TODO] This will break http file links to header files.
;; Use instead a more clever regex match
((and (string-match "\\.h" link)
(not starts_with_http))
(all-the-icons-alltheicon "cplusplus-line"))
((string-match "\\.hpp" link)
(all-the-icons-alltheicon "cplusplus-line"))
;; URL
(starts_with_http (cond
((string-match "wikipedia\\.org" link)
(all-the-icons-faicon "wikipedia-w"))
((string-match "app\\.nuclino\\.com" link)
(all-the-icons-fileicon "brain"))
((string-match "github\\.com" link)
(all-the-icons-octicon "mark-github"))
((string-match "vimeo\\.com" link)
(all-the-icons-faicon "vimeo"))
((string-match "youtube\\.com" link)
(all-the-icons-faicon "youtube"))
((string-match "bitbucket\\.org" link)
(all-the-icons-faicon "bitbucket"))
((string-match "stackoverflow\\.com" link)
(all-the-icons-faicon "stack-overflow"))
((string-match "twitter\\.com" link)
(all-the-icons-faicon "twitter"))
((string-match "reddit\\.com" link)
(all-the-icons-faicon "reddit"))
(t (all-the-icons-faicon "globe"))))
((string-prefix-p "brain:" link)
(all-the-icons-fileicon "brain"))
(t (all-the-icons-icon-for-file link)))))))
(add-hook 'org-brain-after-resource-button-functions #'org-brain-insert-resource-icon))
This snippet, slightly edited from the code available on org-brain's repository page uses ascii-art-to-unicode to draw the inheritance diagram with box drawing characters.
(after! (ascii-art-to-unicode org-brain)
(defface aa2u-face '((t (:inherit fixed-pitch :weight light)) )
"Face for aa2u box drawing characters")
(advice-add #'aa2u-1c :filter-return
(lambda (str) (propertize str 'face 'aa2u-face)))
(defun aa2u-org-brain-buffer ()
(let ((inhibit-read-only t))
(make-local-variable 'face-remapping-alist)
(add-to-list 'face-remapping-alist
'(aa2u-face . org-brain-wires))
(ignore-errors (aa2u (point-min) (point-max)))))
(add-hook 'org-brain-after-visualize-hook #'aa2u-org-brain-buffer))
(map! (:when (featurep! :lang org +brain)
(:map org-mode-map
:localleader
:desc "brain" "B" nil
:desc "Get Id" "Bi" #'org-brain-get-id
:desc "Ensure ids" "BI" #'org-brain-ensure-ids-in-buffer
:desc "Visualize" "Bv" #'org-brain-visualize
)))
Here's some keybindings vaguely inspired from my experience with Spacemacs.
(map! :mode org-mode
:localleader
;; Narrow
:desc "narrow" "mN" nil
:desc "Narrow to subtree" "mNs" #'org-narrow-to-subtree
:desc "Toggle subtree narrowing" "mNt" #'org-toggle-narrow-to-subtree
:desc "Narrow to element" "mNe" #'org-narrow-to-element
:desc "Narrow to element" "mNb" #'org-narrow-to-block
:desc "Widen" "mNw" #'widen)
(map! :map org-mode-map (:when (featurep! :lang org +brain) :localleader (:prefix ("B" . "brain") :desc "Get Id" "i" #'org-brain-get-id :desc "Ensure ids" "I" #'org-brain-ensure-ids-in-buffer :desc "Visualize" "v" #'org-brain-visualize )))
#+end_src
(after! org
(setq calendar-week-start-day 1
calendar-day-name-array ["Dimanche" "Lundi" "Mardi" "Mercredi"
"Jeudi" "Vendredi" "Samedi"]
calendar-month-name-array ["Janvier" "Février" "Mars" "Avril" "Mai"
"Juin" "Juillet" "Août" "Septembre"
"Octobre" "Novembre" "Décembre"]))
(after! org
(setq chicken/dreamlog-file (concat org-directory "/Dreamlog.org"))
(setq
org-capture-templates
'(("b" "Brain" plain #'org-brain-goto-end "* %i%?" :empty-lines 1)
("d" "Dreamlog" entry
(file+olp+datetree chicken/dreamlog-file))
("t" "Personal todo" entry
(file+headline +org-capture-todo-file "Inbox")
"* [ ] %?\n%i\n%a" :prepend t)
("n" "Personal notes" entry
(file+headline +org-capture-notes-file "Inbox")
"* %u %?\n%i\n%a" :prepend t)
("p" "Templates for projects")
("pt" "Project-local todo" entry
(file+headline +org-capture-project-todo-file "Inbox")
"* TODO %?\n%i\n%a" :prepend t)
("pn" "Project-local notes" entry
(file+headline +org-capture-project-notes-file "Inbox")
"* %U %?\n%i\n%a" :prepend t)
("pc" "Project-local changelog" entry
(file+headline +org-capture-project-changelog-file "Unreleased")
"* %U %?\n%i\n%a" :prepend t)
("o" "Centralized templates for projects")
("ot" "Project todo" entry #'+org-capture-central-project-todo-file
"* TODO %?\n %i\n %a" :heading "Tasks" :prepend nil)
("on" "Project notes" entry #'+org-capture-central-project-notes-file
"* %U %?\n %i\n %a" :heading "Notes" :prepend t)
("oc" "Project changelog" entry #'+org-capture-central-project-changelog-file
"* %U %?\n %i\n %a" :heading "Changelog" :prepend t))))
(use-package! wikinfo :after org) (use-package! wikinforg :after wikinfo)
Yay $\LaTeX$!
(use-package! org-fragtog
:after org
:config
(add-hook 'org-mode-hook #'org-fragtog-mode)
(add-hook 'org-mode-hook (lambda() (
;;((plist-put org-format-latex-options :scale 1.0))
))))
Valign is an org-mode plugin that overlays tables to draw them with non-character borders. Looks cleaner with it. Need to figure the boot and performance impact.
(use-package! valign :after org :config (setq valign-fancy-bar t) (add-hook 'org-mode-hook #'valign-mode))
Using that pico-8 mode for Emacs might be fun. It even includes an overlay to display the GFX and label as pictures in the code. Fancy!
I want it to work with gruvbox's colors, so let's tweak the non-lua face to be toned down but in Gruv's palette. Base4 seems to works well in both dark and light mode.
Mimicking Pico's decision to make tabs as short as spaces due to small screen space.
(use-package! pico8-mode
:after lua
:config
(add-hook 'pico8-mode-hook
(lambda ()
(setq indent-tabs-mode t)
(setq tab-width 2))))
(after! pico8-mode (custom-set-faces! `(pico8--non-lua-overlay :weight light :foreground ,(doom-color 'base4))))
I have a blog. I want to use emacs as my platform to type bits and bobs on it.
Org mode is awesome, that's a fact. Minus the fact that I have to deal with a few weirds things around the UI, I love each instant I handle notes or todos with that mode. I tried to look into making org my blog framework/builder but I couldn't do the jump for many reasons, the most important ones were about having to do the templates for org, another one being having to convert Markdown blog posts. I switched to Hugo and extracted my blog files from the v3's database into markdown files.
Now I'll just enjoy the blog writing from a Hugo-powered blog git repo. The v4 is out for a few weeks now and I feel content with the workflow I'm having with it right now. But we can do better.
(defun chicken/run-hugo-in-project ()
(interactive)
(let ((default-directory (projectile-project-root)))
(start-process "Hugo" "+hugo+" "hugo" "serve" "-D")))
Hugo has a few utilities, notably listing draft posts. I wrote a while ago a function to list drafts and feed them to helm. Doom Emacs seems to use ivy as file browser, so I had to rewrite one to feed Ivy with my draft list. Here's how it works. First we have a function that calls Hugo's draft listing based on the project's directory.
(defun chicken/list-hugo-drafts ()
"Fetches the current drafts in a hugo project when available.
Assumes the current project is a Hugo one."
(let* ((root (projectile-project-root))
(stdout
(with-temp-buffer
(call-process "hugo" nil t nil "-s" root "list" "drafts")
(buffer-string)))
(lines (string-lines stdout))
(entries (cdr lines)) ; Remove Hugo's table header
(filenames (mapcar #'(lambda (str) (car (string-split str ","))) entries)))
filenames))
Then I have an interactive function I can call that will process the list given
by list-hugo-drafts and either opens the file or does nothing if the user
cancels the search. Something to note here is how I have to rebuild the whole
path based on the project's root. If the user was in another folder, which can
happen for instance when opening another file, the action callback would have
tried to open the selected file relatively to the current folder instead of the
project folder. There is also a check to detect first the presence of a config
file before attmepting to invoke hugo to give a sensible message.
(defun chicken/hugo-goto-draft ()
"Opens an ivy-powered search helper to quickly jump on a draft
if the current project is the root of a Hugo-powered site."
(interactive)
(if (file-exists-p! "config.toml" (projectile-project-root))
(ivy-read "Open a draft: " (chicken/list-hugo-drafts)
:require-match t
:history 'chicken/hugo-goto-history
:action (lambda (file)
(with-ivy-window
(when file
(let*
((root (projectile-project-root))
(full-file (concat root file)))
(find-file full-file)))))
:unwind #'counsel-delete-process
:caller 'chicken/hugo-goto-draft)
(message "The current project doesn't have a config.toml in the root directory.")))
I like GIFs, that's a fact. But neither your bandwidth nor your CPU will appreciate them. It's past 2020 and GIFs are one of the most known ways to share a small video but it is one of the heaviest way one could do on the internet. Why keep continuing using it, except for pixel perfect (256) colors when most of the time a little encoding will lose little details but a lot of filesize?
I have a recipe to convert GIFs (and anything video related) into webm or mp4 with the help of FFMPEG, here it is.
# base ffmpeg -i input-file.mp4 -c:v libvpx -crf 10 -b:v 1M -c:a libvorbis output-file.webm # This worked not so badly on voxathrone gif # --- # auto-alt-ref is needed because the webm format will throw a tantrum due to # transparency in the gif. ffmpeg -i .\collision_benchmark.gif -c:v libvpx -crf 10 -auto-alt-ref 0 -b:v 1M -an .\collision_benchmark.webm
It might be nice to have some functions in emacs to convert a picture when working on a post. I'm still randomly trying to figure what I need, but here what I have for now:
Detect when working on a post to automatically filter the compatible pictures
{{< video >}} template
so I can extract the link to the file and locate the file.content folder.Of course, an automatic script could help too, but I think this is kind of situation where I prefer handling myself the conversion as I might still need GIFs in some situations.
I somehow found out how to make a first usable function that allows me to
quickly find a gif in any post and convert it. There is no smarter filtering or
a way to ask for quality parameters, but it's already usable as is.
Looking back to the earlier comment block, we can figure an argument listing
which will be apply'd to the process creation routine
(defun chicken/mp4-command (in-file out-file)
"Returns a list composed of my default command to make MP4 out
of gifs."
(list "ffmpeg" "-i" in-file
"-crf" "10"
"-pix_fmt" "yuv420p"
"-y"
out-file))
(defun chicken/webm-command (in-file out-file)
"Returns a list composed of my default command to make WEBM out
of gifs. This one was found by experiment. The ~auto-alt-ref~
argument was found required because ffmpeg would fail with GIFs
with alpgha channels otherwise."
(list "ffmpeg" "-i" in-file
"-c:v" "libvpx"
"-crf" "10"
"-b:v" "1M"
"-auto-alt-ref" "0"
"-c:a" "libvorbis"
"-y"
out-file))
Given a path to a .gif file, it's relatively easy to derive the location of the video files and to run the processes with the precedent part. It's good to note that currently there is no way to guess the result value nor the errors except by checking the processes' buffers. This is something to work on but for now, it'll do. I don't know if the ivy window wrapper is pertinent as the processes run in their own buffer.
(defun chicken/process-gif(file)
"Given a .gif file, calls ffmpeg twice to convert once in a
webm and once in a mp4."
(with-ivy-window
(when file
(let* ((default-directory (projectile-project-root))
(input-file file)
(noext-file (file-name-sans-extension file))
(mp4-file (concat noext-file ".mp4"))
(webm-file (concat noext-file ".webm"))
(mp4-command-line (chicken/mp4-command input-file mp4-file))
(webm-command-line (chicken/webm-command input-file webm-file))
(mp4-process-args (-concat '("ffmpeg") '("*chicken/convert-mp4*") mp4-command-line))
(webm-process-args (-concat '("ffmpeg") '("*chicken/convert-webm*") webm-command-line)))
(start-process "pwd" "*pwd*" "pwd")
(apply 'start-process mp4-process-args)
(apply 'start-process webm-process-args)))))
Then comes the counsel-powered wrapper. I haven't made it as resilient as the
draft lister, but for now it just wraps over one of counsel's built-in file
listers to filter it and only keep the .gif located in the content folder.
Simple but rather effective.
(defun chicken/counsel-filter-gif(regex candidates)
"Wraps counsel--find-file-matcher to filter files to only keep
gifs located in the content subfolder."
(let ((filtered
(remove-if-not
(lambda (file) (and (s-ends-with-p ".gif" file t)
(s-starts-with-p "content" file t)))
candidates)))
(counsel--find-file-matcher regex filtered)))
;;;###autoload
(defun chicken/convert-post-gif()
"Askes the user for a gif located in the content folder to
convert it automatically into mp4 and webm."
(interactive)
(ivy-read "The GAME:" (counsel--find-return-list
counsel-file-jump-args)
:matcher #'chicken/counsel-filter-gif
:require-match t
:history 'chicken/convert-post-gif-history
:action #'chicken/process-gif
:unwind #'counsel-delete-process
:caller 'chicken/convert-post-gif))
I would like to make a shortcut to launch the conversion function to quickly get things done. I need to find a proper wrapper for that and to read more Doom Emacs' documentation to figure how and where to scope the mapping.
(map! (:when
(functionp 'chicken/search-everything))
:leader
:desc "Everything" "sE" #'chicken/search-everything)
Convert this snippet to use lexical binding instead of lexical-let (link to manual)
;; Note, I could build the list by concating the character's unicode name and itself.
;; The variable that'll contain the character maps. A alist binding a symbol to
;; an alist of name <-> symbols. Sadly, I couldn't figure how to avoid having
;; character names to be strings. So the mapping will be a bit less readable for
;; now.
(setq chicken/unicode-helper-map '(
(misc . (("link" . )))))
(defun chicken/get-character-map (id)
(cdr (assoc* id chicken/unicode-helper-map)))
(defun chicken/get-character-from-map (character-map-id)
"""Wrapper over a simple ivy-read call to automatically select
the proper character map to list."""
(let* ((map (chicken/get-character-map character-map-id))
(entry (ivy-read
"Prompt:"
map
:require-match t)))
(message (symbol-name (cdr (assoc entry map))))))
(defun chicken/insert-user-character (id)
"""Another level of wrapper. This one should be pretty much
useable as-is as an user-editable replacement of insert-char
after giving an argument."""
(insert-char
(string-to-char
(chicken/get-character-from-map id))))
(defun chicken/create-user-character-inserter (id)
(lexical-let ((inner-id id))
#'(lambda () (interactive) (chicken/insert-user-character inner-id))))
(map! (:when (boundp 'lexical-let)
:leader ; Use leader key from now on
:desc "Misc character insert" "iM" (chicken/create-user-character-inserter 'misc)))
Windows' emoji panel is great but not convenient enough when focusing on the keyboard. Let's add a mapping to quickly insert various kaomojis.
(map! :leader
:desc "Kaomoji" "iK" nil
:desc "Shrug" "iKs" (lambda ()(interactive) (insert "¯\\_(ツ)_/¯"))
:desc "Shrug (clip)" "iKS" (lambda ()(interactive) (kill-new "¯\\_(ツ)_/¯")))
I have further questions adressed to myself regarding the mental sanity behind such feature.
(map! :leader
:desc "View" "v" nil
:desc "Narrow to region" "vr" #'narrow-to-region
:desc "Narrow to defun" "vd" #'narrow-to-defun
:desc "Narrow to page" "vp" #'narrow-to-page
:desc "Widen" "vw" #'widen)
(defun command-line-ediff (switch)
(let ((file1 (pop command-line-args-left))
(file2 (pop command-line-args-left)))
(ediff file1 file2)))
(defun command-line-ediff-merge (switch)
(let ((file1 (pop command-line-args-left))
(file2 (pop command-line-args-left))
(ancestor (pop command-line-args-left)))
(ediff-merge-files-with-ancestor file1 file2 ancestor)))
(add-to-list 'command-switch-alist '("ediff" . command-line-ediff))
(add-to-list 'command-switch-alist '("ediff-merge" . command-line-ediff-merge))
As both an exercise and a way to quickly get the proper mode for newly created buffer, I created a small quick mode selector.
(setq chicken/quick-mode-modes '(("Org" . org-mode)
("Emacs" . emacs-lisp-mode)
("Lua" . lua-mode)))
(defun chicken/quick-mode-set()
(interactive)
(ivy-read
"Select a mode"
chicken/quick-mode-modes
:require-match t
:action (lambda (selection)
(with-ivy-window
(when selection
(funcall (cdr selection)))))))
(map! :leader
:desc "Chicken" "M" nil
:desc "Quick mode select" "Mm" #'chicken/quick-mode-set)
Everything is a very useful tool for Windows that indexes all the available in the system and provides a insanely fast search popup to directly find the file you want based on either globbing or regexes. On Windows, I just can't live without it. It also provides a command line utility designed to search on a console but also works very well as part of a scripting toolbox.
Inspired by a friend's desire to use it on his own Emacs setup, I wrote a small
function based on Ivy to let me jump on any file with the command line version.
First, the function that will feed ivy-read. It assumes es.exe is in your
PATH.
(when (eq system-type 'windows-nt)
(defun chicken/counsel-es-function (str)
(or (ivy-more-chars)
(progn
(counsel--async-command
(format "es.exe %s" str))
'("" "working...")))))
Then the search function. It is defined when the executable es.exe can be
found in your PATH environment variable. The function is largely inspired by
Ivy's own examples.
(when (and
(eq system-type 'windows-nt)
(executable-find "es.exe")
(featurep! :completion ivy))
(defun chicken/search-everything ()
"Call the \"es\" shell command.
INITIAL-INPUT can be given as the initial minibuffer input."
(interactive)
(ivy-read "Everything: " #'chicken/counsel-es-function
:dynamic-collection t
:require-match t
:history 'chicken/search-everything-history
:action (lambda (file)
(with-ivy-window
(when file
(find-file file))))
:unwind #'counsel-delete-process
:caller 'chicken/search-everything )))
Finally, let's set up a shortcut to directly search a file globally with that
tool. I'm going to map it on <leader> s E, as I hope it won't be used in the
near future by Doom Emacs' default configuration. The mapping makes sure that
you have the executable available by checking if the function to be called is
available.
(map! (:when
(functionp 'chicken/search-everything)
:leader
:desc "Everything" "sE" #'chicken/search-everything))
According to Doom Emacs' FAQ, the Evil mode considers the underscore as a word delimiter because that's the default Emacs behiavour, not following vim's own motion. To fix this, there is the possibility of changing the underscore's entry in the syntax table:
(modify-syntax-entry ?_ "w")
But again, the FAQ suggests using hooks to limit the tweak to specific modes.
(defun chicken/alter-underscore-entry() (modify-syntax-entry ?_ "w")) (add-hook! (python-mode pico8-mode lua-mode markdown-mode) #'chicken/alter-underscore-entry)
(use-package! work)