Commit 7bdf4d4e8b44
Changed files (11)
dots
dots/config/raffi/scripts/denote-raffi
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+# List denote notes for raffi script filter.
+# Outputs Alfred Script Filter JSON format.
+# Usage: denote-raffi [query]
+set -euo pipefail
+
+query="${1:-}"
+DENOTE_DIR="${HOME}/desktop/org/denotes"
+
+if [[ ! -d "$DENOTE_DIR" ]]; then
+ jq -n '{"items": [{"title": "Denote directory not found", "subtitle": "'"$DENOTE_DIR"'", "arg": ""}]}'
+ exit 0
+fi
+
+items="[]"
+while IFS= read -r f; do
+ [[ -z "$f" ]] && continue
+ name=$(basename "$f")
+ # Extract title from denote filename: YYYYMMDDTHHMMSS--title__keywords.org
+ title=$(echo "$name" | sed -E 's/^[0-9]{8}T[0-9]{6}--//;s/__.*$//;s/\.org$//;s/-/ /g')
+ # Extract keywords
+ keywords=$(echo "$name" | sed -E 's/^.*__//;s/\.org$//;s/_/, /g')
+ if [[ "$keywords" == "$name" ]]; then
+ keywords=""
+ fi
+ subtitle="$keywords"
+ if [[ -n "$query" ]] && ! echo "$title $keywords" | grep -qi "$query"; then
+ continue
+ fi
+ items=$(jq --arg title "$title" --arg sub "$subtitle" --arg arg "$f" \
+ '. + [{"title": $title, "subtitle": $sub, "arg": $arg}]' <<< "$items")
+done < <(find "$DENOTE_DIR" -name '*.org' -type f | sort -r)
+
+if [[ "$items" == "[]" ]]; then
+ jq -n '{"items": [{"title": "No notes found", "subtitle": "No denote notes matching query", "arg": ""}]}'
+ exit 0
+fi
+
+jq -n --argjson items "$items" '{"items": $items}'
dots/config/raffi/scripts/emacs-recentf-raffi
@@ -0,0 +1,35 @@
+#!/usr/bin/env bash
+# List recent files from Emacs recentf for raffi script filter.
+# Outputs Alfred Script Filter JSON format.
+# Usage: emacs-recentf-raffi [query]
+# shellcheck disable=SC2016
+set -euo pipefail
+
+query="${1:-}"
+
+# Get recentf list from Emacs
+files=$(emacsclient --eval '(mapconcat (function identity) recentf-list "\n")' 2>/dev/null | tr -d '"' || true)
+
+if [[ -z "$files" ]]; then
+ jq -n '{"items": [{"title": "No recent files", "subtitle": "Emacs recentf is empty or Emacs is not running", "arg": ""}]}'
+ exit 0
+fi
+
+items="[]"
+while IFS= read -r f; do
+ [[ -z "$f" ]] && continue
+ # Skip tramp/remote paths
+ [[ "$f" == /ssh:* || "$f" == /sudo:* || "$f" == /scp:* ]] && continue
+ # Filter by query
+ if [[ -n "$query" ]] && ! echo "$f" | grep -qi "$query"; then
+ continue
+ fi
+ name=$(basename "$f")
+ dir=$(dirname "$f")
+ # Shorten home directory
+ dir="${dir/#"$HOME"/~}"
+ items=$(jq --arg title "$name" --arg sub "$dir" --arg arg "$f" \
+ '. + [{"title": $title, "subtitle": $sub, "arg": $arg}]' <<< "$items")
+done <<< "$files"
+
+jq -n --argjson items "$items" '{"items": $items}'
pkgs/my/scripts/bin/lazyworktree-raffi → dots/config/raffi/scripts/lazyworktree-raffi
File renamed without changes
dots/config/raffi/scripts/man-raffi
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+# Search man pages for raffi script filter.
+# Scans manpath directories directly (no apropos DB needed on NixOS).
+# Outputs Alfred Script Filter JSON format.
+# Usage: man-raffi [query]
+set -euo pipefail
+
+query="${*:-}"
+
+if [[ -z "$query" ]]; then
+ jq -n '{"items": [{"title": "Type to search man pages…", "subtitle": "Search manual pages", "arg": ""}]}'
+ exit 0
+fi
+
+# Convert spaces to wildcards so "git commit" matches "git-commit"
+pattern="${query// /*}"
+
+items="[]"
+count=0
+while IFS= read -r path; do
+ [[ -z "$path" ]] && continue
+ file=$(basename "$path")
+ # Strip compression extensions and extract name.section
+ name="${file%.gz}"
+ name="${name%.zst}"
+ name="${name%.bz2}"
+ name="${name%.xz}"
+ section="${name##*.}"
+ name="${name%.*}"
+ items=$(jq --arg title "${name}(${section})" --arg sub "$path" --arg arg "$name" \
+ '. + [{"title": $title, "subtitle": $sub, "arg": $arg}]' <<< "$items")
+ count=$((count + 1))
+ [[ $count -ge 30 ]] && break
+man_dirs=(/run/current-system/sw/share/man "/etc/profiles/per-user/${USER}/share/man")
+while IFS= read -r d; do
+ man_dirs+=("$d")
+done < <(manpath 2>/dev/null | tr ':' '\n')
+
+done < <(find -L "${man_dirs[@]}" -type f -iname "*${pattern}*" 2>/dev/null | sort -u)
+
+if [[ "$items" == "[]" ]]; then
+ jq -n --arg q "$query" '{"items": [{"title": "No results", "subtitle": "No man pages matching \"\($q)\"", "arg": ""}]}'
+ exit 0
+fi
+
+jq -n --argjson items "$items" '{"items": $items}'
dots/config/raffi/scripts/niri-windows-raffi
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+# List niri windows for raffi script filter (switch or kill).
+# Outputs Alfred Script Filter JSON format.
+# Usage: niri-windows-raffi [query]
+#
+# arg format: window id for use with niri msg action focus-window / close-window
+set -euo pipefail
+
+query="${1:-}"
+
+items="[]"
+while IFS=$'\t' read -r wid app_id title ws_id; do
+ [[ -z "$wid" ]] && continue
+ subtitle="${app_id} — workspace ${ws_id}"
+ if [[ -n "$query" ]] && ! echo "$title $app_id" | grep -qi "$query"; then
+ continue
+ fi
+ items=$(jq --arg title "$title" --arg sub "$subtitle" --arg arg "$wid" \
+ '. + [{"title": $title, "subtitle": $sub, "arg": $arg}]' <<< "$items")
+done < <(niri msg -j windows 2>/dev/null | jq -r '
+ .[] | [(.id | tostring), (.app_id // "unknown"), (.title // ""), (.workspace_id // 0 | tostring)] | @tsv
+')
+
+if [[ "$items" == "[]" ]]; then
+ jq -n '{"items": [{"title": "No windows found", "subtitle": "No open niri windows", "arg": ""}]}'
+ exit 0
+fi
+
+jq -n --argjson items "$items" '{"items": $items}'
dots/config/raffi/scripts/org-search-raffi
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+# Search org files for raffi script filter.
+# Outputs Alfred Script Filter JSON format.
+# Usage: org-search-raffi <query>
+set -euo pipefail
+
+query="${1:-}"
+ORG_DIR="${HOME}/desktop/org"
+
+if [[ -z "$query" ]]; then
+ jq -n '{"items": [{"title": "Type to search org files…", "subtitle": "Searches ~/desktop/org/", "arg": ""}]}'
+ exit 0
+fi
+
+items="[]"
+while IFS=: read -r file lineno content; do
+ [[ -z "$file" ]] && continue
+ relpath="${file/#"$ORG_DIR"\//}"
+ content_trimmed=$(echo "$content" | sed 's/^[[:space:]]*//' | head -c 100)
+ items=$(jq --arg title "$content_trimmed" --arg sub "$relpath:$lineno" --arg arg "${file}" \
+ '. + [{"title": $title, "subtitle": $sub, "arg": $arg}]' <<< "$items")
+done < <(rg --no-heading --line-number --max-count 30 -i "$query" "$ORG_DIR" --glob '*.org' 2>/dev/null | head -30)
+
+if [[ "$items" == "[]" ]]; then
+ jq -n --arg q "$query" '{"items": [{"title": "No results", "subtitle": "No matches for \"\($q)\" in org files", "arg": ""}]}'
+ exit 0
+fi
+
+jq -n --argjson items "$items" '{"items": $items}'
pkgs/my/scripts/bin/shpool-raffi → dots/config/raffi/scripts/shpool-raffi
File renamed without changes
dots/config/raffi/scripts/ssh-raffi
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+# List SSH hosts from ~/.ssh/config for raffi script filter.
+# Outputs Alfred Script Filter JSON format.
+# Usage: ssh-raffi [query]
+set -euo pipefail
+
+query="${1:-}"
+
+items="[]"
+while IFS= read -r host; do
+ [[ -z "$host" ]] && continue
+ # Skip wildcards, patterns, and git forges
+ [[ "$host" == *"*"* ]] && continue
+ [[ "$host" == *"/"* ]] && continue
+ echo "$host" | grep -qE '^(github\.com|gitlab\.com|codeberg\.org|git\.sr\.ht)$' && continue
+
+ if [[ -n "$query" ]] && ! echo "$host" | grep -qi "$query"; then
+ continue
+ fi
+ items=$(jq --arg h "$host" \
+ '. + [{"title": $h, "subtitle": "SSH to \($h) in Kitty", "arg": $h}]' <<< "$items")
+done < <(grep "^Host " ~/.ssh/config 2>/dev/null | awk '{print $2}' | sort -u)
+
+jq -n --argjson items "$items" '{"items": $items}'
pkgs/my/scripts/bin/uid-raffi → dots/config/raffi/scripts/uid-raffi
File renamed without changes
dots/config/raffi/raffi.yaml
@@ -127,6 +127,37 @@ toggle-color-scheme:
description: Toggle dark/light color scheme
icon: preferences-desktop-theme
+# Emacs integrations
+org-agenda:
+ description: Org Agenda
+ icon: emacs
+ script: |
+ emacsclient -c -a emacs --eval '(vde/agenda)'
+
+emacs-type:
+ description: Type & Paste (Emacs)
+ icon: emacs
+ script: |
+ emacsclient -c -a emacs --eval '(vde/type)'
+
+journal-entry:
+ description: Journal Entry
+ icon: emacs
+ script: |
+ emacsclient -n -c -F '((name . "capture") (width . 150) (height . 90) (vde/window-popup-frame . t))' -e '(org-capture nil "j")'
+
+mu4e:
+ description: Email (mu4e)
+ icon: mail-client
+ script: |
+ emacsclient -c -a emacs --eval '(mu4e)'
+
+magit:
+ description: Magit (Git)
+ icon: git
+ script: |
+ emacsclient -c -a emacs --eval '(magit-status)'
+
# Audio
pwvucontrol:
binary: pwvucontrol
@@ -169,17 +200,52 @@ addons:
icon: clock
- name: Worktrees
keyword: wt
- command: lazyworktree-raffi
+ command: ~/.config/raffi/scripts/lazyworktree-raffi
icon: folder-git
action: "kitty --title Worktrees --directory {value} lazyworktree"
- name: Shpool Sessions
keyword: sp
- command: shpool-raffi
+ command: ~/.config/raffi/scripts/shpool-raffi
icon: utilities-terminal
action: "kitty --title shpool:{value} ssh {value}"
+ - name: Open in Emacs
+ keyword: ed
+ command: ~/.config/raffi/scripts/emacs-recentf-raffi
+ icon: emacs
+ action: "emacsclient -c -a emacs {value}"
+ - name: Org Search
+ keyword: org
+ command: ~/.config/raffi/scripts/org-search-raffi
+ icon: emacs
+ action: "emacsclient -c -a emacs --eval '(find-file \"{value}\")'"
+ - name: Denote Notes
+ keyword: dn
+ command: ~/.config/raffi/scripts/denote-raffi
+ icon: emacs
+ action: "emacsclient -c -a emacs {value}"
+ - name: Kitty SSH
+ keyword: ssh
+ command: ~/.config/raffi/scripts/ssh-raffi
+ icon: utilities-terminal
+ action: "kitty --title 'SSH: {value}' ssh {value}"
+ - name: Man Pages
+ keyword: man
+ command: ~/.config/raffi/scripts/man-raffi
+ icon: help-contents
+ action: "kitty --title 'man {value}' sh -c 'man {value} | col -bx | bat -l man -p'"
+ - name: Window Switcher
+ keyword: win
+ command: ~/.config/raffi/scripts/niri-windows-raffi
+ icon: preferences-system-windows
+ action: "niri msg action focus-window --id {value}"
+ - name: Kill Window
+ keyword: kill
+ command: ~/.config/raffi/scripts/niri-windows-raffi
+ icon: window-close
+ action: "niri msg action close-window --id {value}"
- name: IDs & Timestamps
keyword: uid
- command: uid-raffi
+ command: ~/.config/raffi/scripts/uid-raffi
icon: clock
- name: GitHub Pull Requests
keyword: pr
dots/Makefile
@@ -100,7 +100,7 @@ opencode-plugin : ~/.config/opencode/plugin
lazygit : ~/.config/lazygit/config.yml
lazyworktree : ~/.config/lazyworktree/config.yaml
lazypr : ~/.config/lazypr/config.toml
-raffi : ~/.config/raffi/raffi.yaml
+raffi : ~/.config/raffi/raffi.yaml ~/.config/raffi/scripts
##@ GitHub