Skip to content

Commit 1875608

Browse files
lambdalisueclaude
andcommitted
feat(source): add mapping source for listing key mappings
Implements a new source that lists all Vim key mappings across different modes. Shows mapping definitions, attributes (silent, noremap, etc.), and supports filtering by mode and buffer-local status. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 7a390c9 commit 1875608

File tree

2 files changed

+168
-0
lines changed

2 files changed

+168
-0
lines changed

builtin/source/mapping.ts

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
import * as fn from "@denops/std/function";
2+
3+
import { defineSource, type Source } from "../../source.ts";
4+
5+
type Detail = {
6+
/**
7+
* Mapping key/lhs
8+
*/
9+
lhs: string;
10+
11+
/**
12+
* Mapping value/rhs
13+
*/
14+
rhs: string;
15+
16+
/**
17+
* Mapping mode
18+
*/
19+
mode: string;
20+
21+
/**
22+
* Whether the mapping is buffer-local
23+
*/
24+
bufferLocal: boolean;
25+
26+
/**
27+
* Whether the mapping is silent
28+
*/
29+
silent: boolean;
30+
31+
/**
32+
* Whether the mapping is noremap
33+
*/
34+
noremap: boolean;
35+
36+
/**
37+
* Whether the mapping waits for more input
38+
*/
39+
nowait: boolean;
40+
41+
/**
42+
* Whether the mapping is an expression
43+
*/
44+
expr: boolean;
45+
};
46+
47+
export type MappingOptions = {
48+
/**
49+
* Which modes to include mappings from.
50+
* Default includes all common modes.
51+
* @default ["n", "i", "v", "x", "s", "o", "c", "t"]
52+
*/
53+
modes?: string[];
54+
55+
/**
56+
* Whether to include buffer-local mappings.
57+
* @default true
58+
*/
59+
includeBufferLocal?: boolean;
60+
61+
/**
62+
* Whether to include plugin mappings (mappings containing <Plug>).
63+
* @default false
64+
*/
65+
includePluginMappings?: boolean;
66+
};
67+
68+
/**
69+
* Creates a Source that generates items from Vim key mappings.
70+
*
71+
* This Source retrieves all key mappings from specified modes and
72+
* generates items for each one, showing their definitions and attributes.
73+
*
74+
* @param options - Options to customize mapping listing.
75+
* @returns A Source that generates items representing mappings.
76+
*/
77+
export function mapping(
78+
options: Readonly<MappingOptions> = {},
79+
): Source<Detail> {
80+
const modes = options.modes ?? ["n", "i", "v", "x", "s", "o", "c", "t"];
81+
const includeBufferLocal = options.includeBufferLocal ?? true;
82+
const includePluginMappings = options.includePluginMappings ?? false;
83+
84+
return defineSource(async function* (denops, _params, { signal }) {
85+
const items: Array<{
86+
id: number;
87+
value: string;
88+
detail: Detail;
89+
}> = [];
90+
91+
let id = 0;
92+
for (const mode of modes) {
93+
// Get mappings for this mode
94+
const mappingList = await fn.maplist(denops, mode) as MappingInfo[];
95+
signal?.throwIfAborted();
96+
97+
for (const mapping of mappingList) {
98+
// Skip buffer-local mappings if not included
99+
if (mapping.buffer && !includeBufferLocal) {
100+
continue;
101+
}
102+
103+
// Skip plugin mappings if not included
104+
if (!includePluginMappings && mapping.rhs.includes("<Plug>")) {
105+
continue;
106+
}
107+
108+
// Build attributes
109+
const attributes: string[] = [];
110+
if (mapping.silent) attributes.push("silent");
111+
if (mapping.noremap) attributes.push("noremap");
112+
if (mapping.nowait) attributes.push("nowait");
113+
if (mapping.expr) attributes.push("expr");
114+
if (mapping.buffer) attributes.push("buffer");
115+
116+
// Format mode indicator
117+
const modeIndicator = mode === "n" ? " " : `[${mode}]`;
118+
119+
// Format display value
120+
const attrStr = attributes.length > 0
121+
? ` (${attributes.join(", ")})`
122+
: "";
123+
const truncatedRhs = mapping.rhs.length > 50
124+
? mapping.rhs.substring(0, 47) + "..."
125+
: mapping.rhs;
126+
127+
items.push({
128+
id: id++,
129+
value: `${modeIndicator} ${mapping.lhs}${attrStr}${truncatedRhs}`,
130+
detail: {
131+
lhs: mapping.lhs,
132+
rhs: mapping.rhs,
133+
mode: mode,
134+
bufferLocal: mapping.buffer,
135+
silent: mapping.silent,
136+
noremap: mapping.noremap,
137+
nowait: mapping.nowait,
138+
expr: mapping.expr,
139+
},
140+
});
141+
}
142+
}
143+
144+
// Sort by mode and then by lhs
145+
items.sort((a, b) => {
146+
const modeCmp = a.detail.mode.localeCompare(b.detail.mode);
147+
if (modeCmp !== 0) return modeCmp;
148+
return a.detail.lhs.localeCompare(b.detail.lhs);
149+
});
150+
151+
yield* items;
152+
});
153+
}
154+
155+
type MappingInfo = {
156+
lhs: string;
157+
rhs: string;
158+
silent: boolean;
159+
noremap: boolean;
160+
nowait: boolean;
161+
expr: boolean;
162+
buffer: boolean;
163+
mode: string;
164+
sid: number;
165+
lnum: number;
166+
script: boolean;
167+
};

builtin/source/mod.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export * from "./jumplist.ts";
1010
export * from "./line.ts";
1111
export * from "./list.ts";
1212
export * from "./loclist.ts";
13+
export * from "./mapping.ts";
1314
export * from "./mark.ts";
1415
export * from "./noop.ts";
1516
export * from "./oldfiles.ts";

0 commit comments

Comments
 (0)