mirror of
https://github.com/Xevion/dotfiles.git
synced 2026-01-31 02:24:11 -06:00
feat: add fzf abbreviation/alias search with Alt+A keybinding
This commit is contained in:
@@ -44,6 +44,12 @@ end
|
|||||||
# Load custom functions from ~/.config/fish/functions/
|
# Load custom functions from ~/.config/fish/functions/
|
||||||
# (Fish does this automatically, no explicit sourcing needed)
|
# (Fish does this automatically, no explicit sourcing needed)
|
||||||
|
|
||||||
|
# Custom keybindings
|
||||||
|
if functions -q fzf_search_abbr
|
||||||
|
bind \ea fzf_search_abbr # Alt+A: Search abbreviations/aliases
|
||||||
|
bind -M insert \ea fzf_search_abbr # Also bind in insert mode
|
||||||
|
end
|
||||||
|
|
||||||
# Load abbreviations
|
# Load abbreviations
|
||||||
if test -f ~/.config/fish/conf.d/abbr.fish
|
if test -f ~/.config/fish/conf.d/abbr.fish
|
||||||
source ~/.config/fish/conf.d/abbr.fish
|
source ~/.config/fish/conf.d/abbr.fish
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
function fzf_search_abbr --description "Search Fish abbreviations, aliases, and functions with fzf"
|
||||||
|
# Use the Bun script to collect items
|
||||||
|
# Output format: name\texpansion\ttype\tdisplay
|
||||||
|
set -l result (fzf-abbr-search.ts | fzf \
|
||||||
|
--ansi \
|
||||||
|
--height=50% \
|
||||||
|
--reverse \
|
||||||
|
--delimiter='\t' \
|
||||||
|
--with-nth=4 \
|
||||||
|
--nth=1,2 \
|
||||||
|
--prompt='Aliases/Abbrs > ' \
|
||||||
|
--preview='echo {2}' \
|
||||||
|
--preview-window=up:3:wrap \
|
||||||
|
--expect='tab' \
|
||||||
|
--header='Enter: insert name | Tab: insert expansion')
|
||||||
|
|
||||||
|
# Handle cancellation - just repaint and return
|
||||||
|
if test $status -ne 0 -o -z "$result"
|
||||||
|
commandline -f repaint
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# First line is the key pressed, second line is the selected item
|
||||||
|
set -l lines (string split \n $result)
|
||||||
|
set -l key $lines[1]
|
||||||
|
set -l selected $lines[2]
|
||||||
|
|
||||||
|
if test -n "$selected"
|
||||||
|
# Split by tab to get fields
|
||||||
|
set -l fields (string split \t $selected)
|
||||||
|
|
||||||
|
if test "$key" = "tab"
|
||||||
|
# Insert expansion (field 2)
|
||||||
|
commandline -i $fields[2]
|
||||||
|
else
|
||||||
|
# Insert name (field 1)
|
||||||
|
commandline -i $fields[1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
commandline -f repaint
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,196 @@
|
|||||||
|
#!/usr/bin/env bun
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fzf-abbr-search - Search shell abbreviations, aliases, and functions
|
||||||
|
* Output format: name\texpansion\ttype\tdisplay
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { $ } from "bun";
|
||||||
|
|
||||||
|
// ANSI color codes
|
||||||
|
const colors = {
|
||||||
|
name: "\x1b[36m", // Cyan
|
||||||
|
arrow: "\x1b[90m", // Gray
|
||||||
|
expansion: "\x1b[32m", // Green
|
||||||
|
type: "\x1b[33m", // Yellow
|
||||||
|
reset: "\x1b[0m",
|
||||||
|
};
|
||||||
|
|
||||||
|
interface Item {
|
||||||
|
name: string;
|
||||||
|
expansion: string;
|
||||||
|
type: "abbr" | "alias" | "func";
|
||||||
|
}
|
||||||
|
|
||||||
|
async function detectShell(): Promise<string> {
|
||||||
|
const shell = process.env.SHELL || "";
|
||||||
|
if (shell.includes("fish")) return "fish";
|
||||||
|
if (shell.includes("zsh")) return "zsh";
|
||||||
|
if (shell.includes("bash")) return "bash";
|
||||||
|
return "bash"; // default
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getAllFishItems(): Promise<Item[]> {
|
||||||
|
const items: Item[] = [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Combine all Fish queries into one script for efficiency
|
||||||
|
const script = `
|
||||||
|
# Output abbreviations
|
||||||
|
for line in (abbr --show)
|
||||||
|
echo "ABBR|$line"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Output aliases
|
||||||
|
for line in (alias)
|
||||||
|
echo "ALIAS|$line"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Output functions with descriptions
|
||||||
|
for func in (functions -n | string match -v '_*')
|
||||||
|
set -l desc (functions -D -v $func 2>/dev/null | tail -n1)
|
||||||
|
if test -n "$desc"
|
||||||
|
echo "FUNC|$func|$desc"
|
||||||
|
else
|
||||||
|
echo "FUNC|$func|$func"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
`;
|
||||||
|
|
||||||
|
const result = await $`fish -c ${script}`.quiet();
|
||||||
|
const lines = result.text().trim().split("\n");
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
if (!line) continue;
|
||||||
|
|
||||||
|
if (line.startsWith("ABBR|")) {
|
||||||
|
const abbrLine = line.slice(5);
|
||||||
|
const match = abbrLine.match(/^abbr -a -- (\S+) (.+)$/);
|
||||||
|
if (match) {
|
||||||
|
items.push({
|
||||||
|
name: match[1],
|
||||||
|
expansion: match[2].replace(/^'|'$/g, ""),
|
||||||
|
type: "abbr",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (line.startsWith("ALIAS|")) {
|
||||||
|
const aliasLine = line.slice(6);
|
||||||
|
const match = aliasLine.match(/^alias (\S+) (.+)$/);
|
||||||
|
if (match) {
|
||||||
|
items.push({
|
||||||
|
name: match[1],
|
||||||
|
expansion: match[2].replace(/^'|'$/g, ""),
|
||||||
|
type: "alias",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (line.startsWith("FUNC|")) {
|
||||||
|
const parts = line.slice(5).split("|", 2);
|
||||||
|
if (parts.length === 2) {
|
||||||
|
items.push({
|
||||||
|
name: parts[0],
|
||||||
|
expansion: parts[1],
|
||||||
|
type: "func",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Fish not available
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getBashZshAliases(): Promise<Item[]> {
|
||||||
|
const items: Item[] = [];
|
||||||
|
const shell = await detectShell();
|
||||||
|
|
||||||
|
if (shell === "fish") return []; // Already handled by getFishAliases
|
||||||
|
|
||||||
|
try {
|
||||||
|
const cmd = shell === "zsh" ? "zsh" : "bash";
|
||||||
|
const result = await $`${cmd} -i -c 'alias'`.quiet();
|
||||||
|
const lines = result.text().trim().split("\n");
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
// Format: alias name='expansion' or alias name=expansion
|
||||||
|
const match = line.match(/^alias (\S+)=['"]?(.+?)['"]?$/);
|
||||||
|
if (match) {
|
||||||
|
items.push({
|
||||||
|
name: match[1],
|
||||||
|
expansion: match[2],
|
||||||
|
type: "alias",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Shell not available or no aliases
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getBashZshFunctions(): Promise<Item[]> {
|
||||||
|
const items: Item[] = [];
|
||||||
|
const shell = await detectShell();
|
||||||
|
|
||||||
|
if (shell === "fish") return []; // Already handled by getFishFunctions
|
||||||
|
|
||||||
|
try {
|
||||||
|
const cmd = shell === "zsh" ? "zsh" : "bash";
|
||||||
|
// List all functions (excluding internal ones starting with _)
|
||||||
|
const result = await $`${cmd} -i -c 'declare -F'`.quiet();
|
||||||
|
const lines = result.text().trim().split("\n");
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
const match = line.match(/^declare -f (\S+)$/);
|
||||||
|
if (match && !match[1].startsWith("_")) {
|
||||||
|
items.push({
|
||||||
|
name: match[1],
|
||||||
|
expansion: match[1], // Functions just show their name
|
||||||
|
type: "func",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Shell not available
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function collectAllItems(): Promise<Item[]> {
|
||||||
|
const shell = await detectShell();
|
||||||
|
|
||||||
|
if (shell === "fish") {
|
||||||
|
return await getAllFishItems();
|
||||||
|
} else {
|
||||||
|
const [aliases, funcs] = await Promise.all([
|
||||||
|
getBashZshAliases(),
|
||||||
|
getBashZshFunctions(),
|
||||||
|
]);
|
||||||
|
return [...aliases, ...funcs];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatDisplay(item: Item): string {
|
||||||
|
const { name, expansion, type } = item;
|
||||||
|
return (
|
||||||
|
`${colors.name}${name}${colors.reset} ` +
|
||||||
|
`${colors.arrow}=>${colors.reset} ` +
|
||||||
|
`${colors.expansion}${expansion}${colors.reset} ` +
|
||||||
|
`${colors.type}(${type})${colors.reset}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const items = await collectAllItems();
|
||||||
|
|
||||||
|
// Output: name\texpansion\ttype\tdisplay
|
||||||
|
for (const item of items) {
|
||||||
|
const display = formatDisplay(item);
|
||||||
|
console.log(`${item.name}\t${item.expansion}\t${item.type}\t${display}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
Reference in New Issue
Block a user