Skip to content

Commit deab430

Browse files
lambdalisueclaude
andcommitted
feat: add autocmd source for vim autocmds
Implements a new source that lists all defined vim autocmds with their events, patterns, and commands. Supports filtering by event and group, and can include or exclude buffer-local autocmds. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 6ae2408 commit deab430

File tree

1 file changed

+176
-0
lines changed

1 file changed

+176
-0
lines changed

builtin/source/autocmd.ts

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
import { defineSource, type Source } from "../../source.ts";
2+
3+
type Detail = {
4+
/**
5+
* Autocmd event name
6+
*/
7+
event: string;
8+
9+
/**
10+
* Autocmd group name (if any)
11+
*/
12+
group?: string;
13+
14+
/**
15+
* Pattern the autocmd matches
16+
*/
17+
pattern: string;
18+
19+
/**
20+
* Command to execute
21+
*/
22+
command: string;
23+
24+
/**
25+
* Whether it's a buffer-local autocmd
26+
*/
27+
bufferLocal: boolean;
28+
29+
/**
30+
* Additional autocmd flags/attributes
31+
*/
32+
flags: string[];
33+
};
34+
35+
export type AutocmdOptions = {
36+
/**
37+
* Filter by specific event(s).
38+
*/
39+
events?: string[];
40+
41+
/**
42+
* Filter by autocmd group.
43+
*/
44+
group?: string;
45+
46+
/**
47+
* Whether to include buffer-local autocmds.
48+
* @default true
49+
*/
50+
includeBufferLocal?: boolean;
51+
52+
/**
53+
* Whether to show detailed command (full command vs truncated).
54+
* @default false
55+
*/
56+
showFullCommand?: boolean;
57+
};
58+
59+
/**
60+
* Creates a Source that generates items from Vim autocmds.
61+
*
62+
* This Source retrieves all defined autocmds and generates items
63+
* for each one, showing their events, patterns, and commands.
64+
*
65+
* @param options - Options to customize autocmd listing.
66+
* @returns A Source that generates items representing autocmds.
67+
*/
68+
export function autocmd(
69+
options: Readonly<AutocmdOptions> = {},
70+
): Source<Detail> {
71+
const filterEvents = options.events;
72+
const filterGroup = options.group;
73+
const includeBufferLocal = options.includeBufferLocal ?? true;
74+
const showFullCommand = options.showFullCommand ?? false;
75+
76+
return defineSource(async function* (denops, _params, { signal }) {
77+
// Get autocmd output
78+
const autocmdCmd = filterGroup ? `:autocmd ${filterGroup}` : ":autocmd";
79+
const output = await denops.call("execute", autocmdCmd) as string;
80+
signal?.throwIfAborted();
81+
82+
// Parse autocmd output
83+
const lines = output.trim().split("\n");
84+
const items: Array<{
85+
id: number;
86+
value: string;
87+
detail: Detail;
88+
}> = [];
89+
90+
let id = 0;
91+
let currentGroup = "";
92+
let currentEvent = "";
93+
94+
for (const line of lines) {
95+
const trimmed = line.trim();
96+
if (!trimmed) continue;
97+
98+
// Check for group header
99+
const groupMatch = trimmed.match(/^--- Autocommands ---$/);
100+
if (groupMatch) {
101+
currentGroup = "";
102+
continue;
103+
}
104+
105+
// Check for named group header
106+
const namedGroupMatch = trimmed.match(
107+
/^(\w+)\s+Autocommands for "(.+)"$/,
108+
);
109+
if (namedGroupMatch) {
110+
currentGroup = namedGroupMatch[1];
111+
continue;
112+
}
113+
114+
// Check for event header
115+
const eventMatch = trimmed.match(/^(\w+)$/);
116+
if (eventMatch && !trimmed.includes(" ")) {
117+
currentEvent = eventMatch[1];
118+
continue;
119+
}
120+
121+
// Parse autocmd line
122+
// Format: " pattern command"
123+
const cmdMatch = trimmed.match(/^\s*(\S+)\s+(.+)$/);
124+
if (cmdMatch && currentEvent) {
125+
const [, pattern, command] = cmdMatch;
126+
127+
// Filter by event if specified
128+
if (filterEvents && !filterEvents.includes(currentEvent)) {
129+
continue;
130+
}
131+
132+
// Parse flags from pattern
133+
const flags: string[] = [];
134+
let bufferLocal = false;
135+
let cleanPattern = pattern;
136+
137+
// Check for buffer-local indicator
138+
if (pattern.startsWith("<buffer>")) {
139+
bufferLocal = true;
140+
cleanPattern = pattern.replace("<buffer>", "").trim();
141+
flags.push("buffer");
142+
}
143+
144+
// Skip buffer-local if not included
145+
if (bufferLocal && !includeBufferLocal) {
146+
continue;
147+
}
148+
149+
// Format display value
150+
const groupStr = currentGroup ? `[${currentGroup}] ` : "";
151+
const bufferStr = bufferLocal ? " <buffer>" : "";
152+
const truncatedCmd = showFullCommand || command.length <= 50
153+
? command
154+
: command.substring(0, 47) + "...";
155+
156+
const value =
157+
`${groupStr}${currentEvent} ${cleanPattern}${bufferStr}${truncatedCmd}`;
158+
159+
items.push({
160+
id: id++,
161+
value,
162+
detail: {
163+
event: currentEvent,
164+
group: currentGroup || undefined,
165+
pattern: cleanPattern,
166+
command,
167+
bufferLocal,
168+
flags,
169+
},
170+
});
171+
}
172+
}
173+
174+
yield* items;
175+
});
176+
}

0 commit comments

Comments
 (0)