Skip to content

Commit f78f4a6

Browse files
committed
💥 Multiple matchers, sorters, renderers, and previewers
Switchable: - matcher - sorter - renderer Stackable: - previewer
1 parent 1081df8 commit f78f4a6

File tree

7 files changed

+114
-77
lines changed

7 files changed

+114
-77
lines changed

denops/@fall/builtin/action/submatch.ts

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ import { list } from "../source/list.ts";
99
import { type Action, defineAction } from "../../action.ts";
1010
import {
1111
type Derivable,
12+
type DerivableArray,
1213
type DerivableMap,
1314
derive,
15+
deriveArray,
1416
deriveMap,
1517
} from "../../util/derivable.ts";
1618
import { fzf } from "../matcher/fzf.ts";
@@ -20,38 +22,44 @@ import { regexp } from "../matcher/regexp.ts";
2022
type Options<T, A extends string> = {
2123
actions?: DerivableMap<Actions<T, A>>;
2224
defaultAction?: A;
23-
sorter?: Derivable<Sorter<T>> | null;
24-
renderer?: Derivable<Renderer<T>> | null;
25-
previewer?: Derivable<Previewer<T>> | null;
25+
sorters?: DerivableArray<Sorter<T>[]> | null;
26+
renderers?: DerivableArray<Renderer<T>[]> | null;
27+
previewers?: DerivableArray<Previewer<T>[]> | null;
2628
coordinator?: Derivable<Coordinator> | null;
2729
theme?: Derivable<Theme> | null;
2830
};
2931

3032
export function submatch<T, A extends string>(
31-
matcher: Derivable<Matcher<T>>,
33+
matchers: DerivableArray<[Matcher<T>, ...Matcher<T>[]]>,
3234
options: Options<T, A> = {},
3335
): Action<T> {
3436
return defineAction<T>(
3537
async (denops, { selectedItems, filteredItems, context }, { signal }) => {
3638
const params: ItemPickerParams<T, string> & GlobalConfig = {
3739
...context.pickerParams,
3840
source: list(selectedItems ?? filteredItems),
39-
matcher: derive(matcher),
41+
matchers: deriveArray(matchers),
4042
};
4143
if (options.actions) {
4244
params.actions = deriveMap(params.actions);
4345
}
4446
if (options.defaultAction) {
4547
params.defaultAction = options.defaultAction;
4648
}
47-
if (options.sorter !== undefined) {
48-
params.sorter = derive(options.sorter) ?? undefined;
49+
if (options.sorters !== undefined) {
50+
params.sorters = options.sorters
51+
? deriveArray(options.sorters)
52+
: undefined;
4953
}
50-
if (options.renderer !== undefined) {
51-
params.renderer = derive(options.renderer) ?? undefined;
54+
if (options.renderers !== undefined) {
55+
params.renderers = options.renderers
56+
? deriveArray(options.renderers)
57+
: undefined;
5258
}
53-
if (options.previewer !== undefined) {
54-
params.previewer = derive(options.previewer) ?? undefined;
59+
if (options.previewers !== undefined) {
60+
params.previewers = options.previewers
61+
? deriveArray(options.previewers)
62+
: undefined;
5563
}
5664
if (options.coordinator !== undefined) {
5765
params.coordinator = derive(options.coordinator) ??
@@ -80,7 +88,7 @@ export const defaultSubmatchActions: {
8088
"sub:substring": Action<unknown>;
8189
"sub:regexp": Action<unknown>;
8290
} = {
83-
"sub:fzf": submatch(fzf),
84-
"sub:substring": submatch(substring),
85-
"sub:regexp": submatch(regexp),
91+
"sub:fzf": submatch([fzf]),
92+
"sub:substring": submatch([substring]),
93+
"sub:regexp": submatch([regexp]),
8694
};

denops/@fall/config.ts

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ import type { Sorter } from "./sorter.ts";
99
import type { Renderer } from "./renderer.ts";
1010
import type { Previewer } from "./previewer.ts";
1111
import type { Action } from "./action.ts";
12-
import type { Derivable, DerivableMap } from "./util/derivable.ts";
12+
import type {
13+
Derivable,
14+
DerivableArray,
15+
DerivableMap,
16+
} from "./util/derivable.ts";
1317

1418
export type Actions<T, A extends string> =
1519
& Record<string, Action<T>>
@@ -18,21 +22,21 @@ export type Actions<T, A extends string> =
1822
export type ItemPickerParams<T, A extends string> = {
1923
name: string;
2024
source: Source<T>;
21-
matcher: Matcher<NoInfer<T>>;
2225
actions: Actions<T, NoInfer<A>>;
2326
defaultAction: A;
24-
sorter?: Sorter<NoInfer<T>>;
25-
renderer?: Renderer<NoInfer<T>>;
26-
previewer?: Previewer<NoInfer<T>>;
27+
matchers: [Matcher<NoInfer<T>>, ...Matcher<NoInfer<T>>[]];
28+
sorters?: Sorter<NoInfer<T>>[];
29+
renderers?: Renderer<NoInfer<T>>[];
30+
previewers?: Previewer<NoInfer<T>>[];
2731
coordinator?: Coordinator;
2832
theme?: Theme;
2933
};
3034

3135
export type ActionPickerParams = {
32-
matcher: Matcher<Action<unknown>>;
33-
sorter?: Sorter<Action<unknown>>;
34-
renderer?: Renderer<Action<unknown>>;
35-
previewer?: Previewer<Action<unknown>>;
36+
matchers: [Matcher<Action<unknown>>, ...Matcher<Action<unknown>>[]];
37+
sorters?: Sorter<Action<unknown>>[];
38+
renderers?: Renderer<Action<unknown>>[];
39+
previewers?: Previewer<Action<unknown>>[];
3640
coordinator?: Coordinator;
3741
theme?: Theme;
3842
};
@@ -49,12 +53,12 @@ export type DefineItemPickerFromSource = <T, A extends string>(
4953
name: string,
5054
source: Derivable<Source<T>>,
5155
params: {
52-
matcher: Derivable<Matcher<NoInfer<T>>>;
5356
actions: DerivableMap<Actions<NoInfer<T>, NoInfer<A>>>;
5457
defaultAction: A;
55-
sorter?: Derivable<Sorter<NoInfer<T>>>;
56-
renderer?: Derivable<Renderer<NoInfer<T>>>;
57-
previewer?: Derivable<Previewer<NoInfer<T>>>;
58+
matchers: DerivableArray<[Matcher<NoInfer<T>>, ...Matcher<NoInfer<T>>[]]>;
59+
sorters?: DerivableArray<Sorter<NoInfer<T>>[]>;
60+
renderers?: DerivableArray<Renderer<NoInfer<T>>[]>;
61+
previewers?: DerivableArray<Previewer<NoInfer<T>>[]>;
5862
coordinator?: Derivable<Coordinator>;
5963
theme?: Derivable<Theme>;
6064
},
@@ -69,9 +73,9 @@ export type DefineItemPickerFromCurator = <T, A extends string>(
6973
params: {
7074
actions: DerivableMap<Actions<NoInfer<T>, NoInfer<A>>>;
7175
defaultAction: A;
72-
sorter?: Derivable<Sorter<NoInfer<T>>>;
73-
renderer?: Derivable<Renderer<NoInfer<T>>>;
74-
previewer?: Derivable<Previewer<NoInfer<T>>>;
76+
sorters?: DerivableArray<Sorter<NoInfer<T>>[]>;
77+
renderers?: DerivableArray<Renderer<NoInfer<T>>[]>;
78+
previewers?: DerivableArray<Previewer<NoInfer<T>>[]>;
7579
coordinator?: Derivable<Coordinator>;
7680
theme?: Derivable<Theme>;
7781
},
@@ -82,10 +86,12 @@ export type DefineItemPickerFromCurator = <T, A extends string>(
8286
*/
8387
export type RefineActionPicker = (
8488
params: {
85-
matcher?: Derivable<Matcher<Action<unknown>>>;
86-
sorter?: Derivable<Sorter<Action<unknown>>>;
87-
renderer?: Derivable<Renderer<Action<unknown>>>;
88-
previewer?: Derivable<Previewer<Action<unknown>>>;
89+
matchers: DerivableArray<
90+
[Matcher<Action<unknown>>, ...Matcher<Action<unknown>>[]]
91+
>;
92+
sorters?: DerivableArray<Sorter<Action<unknown>>[]>;
93+
renderers?: DerivableArray<Renderer<Action<unknown>>[]>;
94+
previewers?: DerivableArray<Previewer<Action<unknown>>[]>;
8995
coordinator?: Derivable<Coordinator>;
9096
theme?: Derivable<Theme>;
9197
},

denops/fall/_assets/default.config.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export const main: Entrypoint = (
2828
builtin.modifier.relativePath,
2929
),
3030
{
31-
previewer: builtin.previewer.file,
31+
previewers: [builtin.previewer.file],
3232
actions: {
3333
...quickfixActions,
3434
...builtin.action.defaultOpenActions,
@@ -48,7 +48,7 @@ export const main: Entrypoint = (
4848
builtin.modifier.relativePath,
4949
),
5050
{
51-
previewer: builtin.previewer.file,
51+
previewers: [builtin.previewer.file],
5252
actions: {
5353
...quickfixActions,
5454
...builtin.action.defaultOpenActions,
@@ -68,7 +68,7 @@ export const main: Entrypoint = (
6868
builtin.modifier.relativePath,
6969
),
7070
{
71-
previewer: builtin.previewer.file,
71+
previewers: [builtin.previewer.file],
7272
actions: {
7373
...quickfixActions,
7474
...builtin.action.defaultOpenActions,
@@ -99,12 +99,12 @@ export const main: Entrypoint = (
9999
builtin.modifier.relativePath,
100100
),
101101
{
102-
matcher: builtin.matcher.fzf,
103-
renderer: composeRenderer(
102+
matchers: [builtin.matcher.fzf],
103+
renderers: [composeRenderer(
104104
builtin.renderer.smartPath,
105105
builtin.renderer.nerdfont,
106-
),
107-
previewer: builtin.previewer.file,
106+
)],
107+
previewers: [builtin.previewer.file],
108108
actions: {
109109
...quickfixActions,
110110
...builtin.action.defaultOpenActions,
@@ -118,8 +118,8 @@ export const main: Entrypoint = (
118118
);
119119

120120
defineItemPickerFromSource("line", builtin.source.line, {
121-
matcher: builtin.matcher.fzf,
122-
previewer: builtin.previewer.buffer,
121+
matchers: [builtin.matcher.fzf],
122+
previewers: [builtin.previewer.buffer],
123123
actions: {
124124
...quickfixActions,
125125
...builtin.action.defaultOpenActions,
@@ -135,8 +135,8 @@ export const main: Entrypoint = (
135135
"buffer",
136136
builtin.source.buffer({ filter: "bufloaded" }),
137137
{
138-
matcher: builtin.matcher.fzf,
139-
previewer: builtin.previewer.buffer,
138+
matchers: [builtin.matcher.fzf],
139+
previewers: [builtin.previewer.buffer],
140140
actions: {
141141
...quickfixActions,
142142
...builtin.action.defaultOpenActions,
@@ -150,8 +150,8 @@ export const main: Entrypoint = (
150150
);
151151

152152
defineItemPickerFromSource("help", builtin.source.helptag, {
153-
matcher: builtin.matcher.fzf,
154-
previewer: builtin.previewer.helptag,
153+
matchers: [builtin.matcher.fzf],
154+
previewers: [builtin.previewer.helptag],
155155
actions: {
156156
...builtin.action.defaultHelpActions,
157157
...builtin.action.defaultEchoActions,

denops/fall/config/action_picker.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ import { getGlobalConfig } from "./global_config.ts";
77

88
import { modern as modernLayout } from "../../@fall/builtin/coordinator/modern.ts";
99
import { fzf as fzfMatcher } from "../../@fall/builtin/matcher/fzf.ts";
10-
import { derive } from "../../@fall/util/derivable.ts";
10+
import { derive, deriveArray } from "../../@fall/util/derivable.ts";
1111

1212
const actionPickerParams: ActionPickerParams = {
13-
matcher: fzfMatcher(),
13+
matchers: [fzfMatcher()],
1414
coordinator: modernLayout({
1515
widthRatio: 0.4,
1616
heightRatio: 0.4,
@@ -27,17 +27,17 @@ export function getActionPickerParams(): Readonly<
2727
}
2828

2929
export const refineActionPicker: RefineActionPicker = (params) => {
30-
if (params.matcher) {
31-
actionPickerParams.matcher = derive(params.matcher);
30+
if (params.matchers) {
31+
actionPickerParams.matchers = deriveArray(params.matchers);
3232
}
33-
if (params.sorter) {
34-
actionPickerParams.sorter = derive(params.sorter);
33+
if (params.sorters) {
34+
actionPickerParams.sorters = deriveArray(params.sorters);
3535
}
36-
if (params.renderer) {
37-
actionPickerParams.renderer = derive(params.renderer);
36+
if (params.renderers) {
37+
actionPickerParams.renderers = deriveArray(params.renderers);
3838
}
39-
if (params.previewer) {
40-
actionPickerParams.previewer = derive(params.previewer);
39+
if (params.previewers) {
40+
actionPickerParams.previewers = deriveArray(params.previewers);
4141
}
4242
if (params.coordinator) {
4343
actionPickerParams.coordinator = derive(params.coordinator);

denops/fall/config/item_picker.ts

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import type {
99
GlobalConfig,
1010
ItemPickerParams,
1111
} from "../../@fall/config.ts";
12-
import { derive, deriveMap } from "../../@fall/util/derivable.ts";
12+
import { derive, deriveArray, deriveMap } from "../../@fall/util/derivable.ts";
1313
import { getGlobalConfig } from "./global_config.ts";
1414

1515
type Actions = ItemPickerParams<unknown, string>["actions"];
@@ -41,11 +41,16 @@ export const defineItemPickerFromSource: DefineItemPickerFromSource = (
4141
if (itemPickerParamsMap.has(name)) {
4242
throw new Error(`Item picker "${name}" is already defined.`);
4343
}
44-
const derivedParams = {
45-
...deriveMap(params),
44+
const derivedParams = omitUndefinedAttributes({
4645
actions: deriveMap(params.actions) as Actions,
4746
defaultAction: params.defaultAction,
48-
};
47+
matchers: deriveArray(params.matchers),
48+
sorters: params.sorters ? deriveArray(params.sorters) : undefined,
49+
renderers: params.renderers ? deriveArray(params.renderers) : undefined,
50+
previewers: params.previewers ? deriveArray(params.previewers) : undefined,
51+
coordinator: derive(params.coordinator),
52+
theme: derive(params.theme),
53+
});
4954
itemPickerParamsMap.set(name, {
5055
...derivedParams,
5156
name,
@@ -62,16 +67,20 @@ export const defineItemPickerFromCurator: DefineItemPickerFromCurator = (
6267
throw new Error(`Item picker "${name}" is already defined.`);
6368
}
6469
const source = new CuratorSourceMatcher(derive(curator));
65-
const derivedParams = {
66-
...deriveMap(params),
70+
const derivedParams = omitUndefinedAttributes({
6771
actions: deriveMap(params.actions) as Actions,
6872
defaultAction: params.defaultAction,
69-
};
73+
sorters: params.sorters ? deriveArray(params.sorters) : undefined,
74+
renderers: params.renderers ? deriveArray(params.renderers) : undefined,
75+
previewers: params.previewers ? deriveArray(params.previewers) : undefined,
76+
coordinator: derive(params.coordinator),
77+
theme: derive(params.theme),
78+
});
7079
itemPickerParamsMap.set(name, {
7180
...derivedParams,
7281
name,
7382
source,
74-
matcher: source,
83+
matchers: [source],
7584
});
7685
};
7786

@@ -107,3 +116,14 @@ class CuratorSourceMatcher<T> implements Source<T>, Matcher<T> {
107116
yield* this.#curator.curate(denops, curatorParams, options);
108117
}
109118
}
119+
120+
function omitUndefinedAttributes<
121+
M extends Record<PropertyKey, unknown>,
122+
R extends { [K in keyof M]: M[K] extends undefined ? never : M[K] },
123+
>(
124+
map: M,
125+
): R {
126+
return Object.fromEntries(
127+
Object.entries(map).filter(([, v]) => v !== undefined),
128+
) as R;
129+
}

denops/fall/main/picker.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,12 +181,12 @@ const isScreen = is.ObjectOf({
181181
const isParams = is.ObjectOf({
182182
name: is.String,
183183
source: is.Any,
184-
matcher: is.Any,
185184
actions: is.Any,
186185
defaultAction: is.String,
187-
sorter: as.Optional(is.Any),
188-
renderer: as.Optional(is.Any),
189-
previewer: as.Optional(is.Any),
186+
matchers: is.Any,
187+
sorters: as.Optional(is.Any),
188+
renderers: as.Optional(is.Any),
189+
previewers: as.Optional(is.Any),
190190
coordinator: is.Any,
191191
theme: is.Any,
192192
}) satisfies Predicate<ItemPickerParams<unknown, string> & GlobalConfig>;

0 commit comments

Comments
 (0)