Skip to content

Commit c166b92

Browse files
committed
feat(refiner): add buffer info refiner for filtering by buffer properties
1 parent e9a3319 commit c166b92

File tree

2 files changed

+196
-0
lines changed

2 files changed

+196
-0
lines changed

builtin/refiner/buffer_info.ts

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
import * as fn from "@denops/std/function";
2+
import type { IdItem } from "@vim-fall/core/item";
3+
import { defineRefiner, type Refiner } from "../../refiner.ts";
4+
5+
type Detail = {
6+
bufnr: number;
7+
};
8+
9+
export type BufferInfoRefinerOptions = {
10+
/**
11+
* Filter by buffer modification status.
12+
*/
13+
modified?: boolean;
14+
15+
/**
16+
* Filter by buffer listed status.
17+
*/
18+
listed?: boolean;
19+
20+
/**
21+
* Filter by buffer loaded status.
22+
*/
23+
loaded?: boolean;
24+
25+
/**
26+
* Filter by buffer visibility (visible in any window).
27+
*/
28+
visible?: boolean;
29+
30+
/**
31+
* Filter by file types.
32+
* If provided, only buffers with these filetypes will pass.
33+
*/
34+
filetypes?: string[];
35+
36+
/**
37+
* Filter by buffer types.
38+
* Common values: "", "help", "quickfix", "terminal", "prompt", "popup", "nofile", "nowrite", "acwrite"
39+
*/
40+
buftypes?: string[];
41+
42+
/**
43+
* Whether to include unnamed buffers.
44+
* @default true
45+
*/
46+
includeUnnamed?: boolean;
47+
48+
/**
49+
* Whether to include special buffers (help, quickfix, etc).
50+
* @default true
51+
*/
52+
includeSpecial?: boolean;
53+
54+
/**
55+
* Minimum line count for the buffer.
56+
*/
57+
minLines?: number;
58+
59+
/**
60+
* Maximum line count for the buffer.
61+
*/
62+
maxLines?: number;
63+
};
64+
65+
/**
66+
* Creates a Refiner that filters items based on buffer information.
67+
*
68+
* This Refiner can filter buffers based on various criteria such as
69+
* modification status, visibility, file type, and buffer properties.
70+
*
71+
* @param options - Options to customize buffer filtering.
72+
* @returns A Refiner that filters items based on buffer information.
73+
*/
74+
export function bufferInfo(
75+
options: Readonly<BufferInfoRefinerOptions> = {},
76+
): Refiner<Detail> {
77+
const modified = options.modified;
78+
const listed = options.listed;
79+
const loaded = options.loaded;
80+
const visible = options.visible;
81+
const filetypes = options.filetypes;
82+
const buftypes = options.buftypes;
83+
const includeUnnamed = options.includeUnnamed ?? true;
84+
const includeSpecial = options.includeSpecial ?? true;
85+
const minLines = options.minLines;
86+
const maxLines = options.maxLines;
87+
88+
return defineRefiner(async function* (denops, { items }) {
89+
// Convert async iterable to array first
90+
const itemsArray: IdItem<Detail>[] = [];
91+
for await (const item of items) {
92+
itemsArray.push(item);
93+
}
94+
95+
// Get all buffer info at once for efficiency
96+
const allBufinfo = await fn.getbufinfo(denops);
97+
const bufInfoMap = new Map(
98+
allBufinfo.map((info) => [info.bufnr, info]),
99+
);
100+
101+
// Process items and filter
102+
const results = await Promise.all(
103+
itemsArray.map(async (item) => {
104+
const { bufnr } = item.detail;
105+
const bufinfo = bufInfoMap.get(bufnr);
106+
107+
if (!bufinfo) {
108+
return null;
109+
}
110+
111+
// Check modification status
112+
if (modified !== undefined && !!bufinfo.changed !== modified) {
113+
return null;
114+
}
115+
116+
// Check listed status
117+
if (listed !== undefined && !!bufinfo.listed !== listed) {
118+
return null;
119+
}
120+
121+
// Check loaded status
122+
if (loaded !== undefined && !!bufinfo.loaded !== loaded) {
123+
return null;
124+
}
125+
126+
// Check visibility
127+
if (visible !== undefined) {
128+
const isVisible = bufinfo.windows && bufinfo.windows.length > 0;
129+
if (visible !== isVisible) {
130+
return null;
131+
}
132+
}
133+
134+
// Check unnamed buffers
135+
if (!includeUnnamed && !bufinfo.name) {
136+
return null;
137+
}
138+
139+
// Check line count
140+
if (minLines !== undefined && bufinfo.linecount < minLines) {
141+
return null;
142+
}
143+
if (maxLines !== undefined && bufinfo.linecount > maxLines) {
144+
return null;
145+
}
146+
147+
// Check filetype
148+
if (filetypes && filetypes.length > 0) {
149+
const filetype = await denops.eval(
150+
`getbufvar(${bufnr}, "&filetype")`,
151+
) as string;
152+
if (!filetypes.includes(filetype)) {
153+
return null;
154+
}
155+
}
156+
157+
// Check buftype
158+
if (buftypes && buftypes.length > 0) {
159+
const buftype = await denops.eval(
160+
`getbufvar(${bufnr}, "&buftype")`,
161+
) as string;
162+
if (!buftypes.includes(buftype)) {
163+
return null;
164+
}
165+
}
166+
167+
// Check special buffers
168+
if (!includeSpecial) {
169+
const buftype = await denops.eval(
170+
`getbufvar(${bufnr}, "&buftype")`,
171+
) as string;
172+
if (buftype && buftype !== "") {
173+
return null;
174+
}
175+
176+
// Also check for help buffers
177+
const filetype = await denops.eval(
178+
`getbufvar(${bufnr}, "&filetype")`,
179+
) as string;
180+
if (filetype === "help") {
181+
return null;
182+
}
183+
}
184+
185+
return item;
186+
}),
187+
);
188+
189+
// Return only non-null items
190+
const filtered = results.filter((item): item is IdItem<Detail> =>
191+
item !== null
192+
);
193+
yield* filtered;
194+
});
195+
}

builtin/refiner/mod.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// This file is generated by gen-mod.ts
22
export * from "./absolute_path.ts";
3+
export * from "./buffer_info.ts";
34
export * from "./cwd.ts";
45
export * from "./exists.ts";
56
export * from "./file_info.ts";

0 commit comments

Comments
 (0)