Skip to content

Commit 2608e1c

Browse files
authored
Merge pull request #3 from vim-fall/v1
v0.1
2 parents 71a559f + 8594cb1 commit 2608e1c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+4020
-1
lines changed

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,27 @@ Plug 'lambdalisue/fall.vim'
2929

3030
[vim-plug]: https://github.com/junegunn/vim-plug
3131

32+
## Usage
33+
34+
Use `:Fall` command to open the fuzzy finder. The command accepts the following
35+
arguments:
36+
37+
```
38+
:Fall {source} {source_args}...
39+
```
40+
41+
For example, if you'd like to use `file` source, you can use the following
42+
43+
```
44+
:Fall file
45+
```
46+
47+
Or `line` source with `README.md` as an argument
48+
49+
```
50+
:Fall line README.md
51+
```
52+
3253
## Similar Projects
3354

3455
- [ddu.vim](https://github.com/Shougo/ddu.vim)<br>A highly customizable and

autoload/fall.vim

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
function! fall#start(name, args, options) abort
2+
call denops#plugin#wait_async(
3+
\ 'fall',
4+
\ { -> denops#notify('fall', 'start', [a:name, a:args, a:options]) },
5+
\)
6+
endfunction
7+
8+
function! fall#command(cmdargs) abort
9+
let l:args = split(a:cmdargs, ' ', v:true)
10+
const l:name = remove(l:args, 0)
11+
call fall#start(l:name, l:args, {})
12+
endfunction
13+
14+
function! fall#action(name) abort
15+
call denops#plugin#wait_async(
16+
\ 'fall',
17+
\ { -> denops#notify('fall', 'dispatch', ['action-invoke', a:name]) },
18+
\)
19+
endfunction

autoload/fall/internal/mapping.vim

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
let s:saved_maps = []
2+
3+
function! fall#internal#mapping#store() abort
4+
if !empty(s:saved_maps)
5+
return
6+
endif
7+
let s:saved_maps = map(maplist(), { _, m -> m.mode == 'c' })
8+
endfunction
9+
10+
function! fall#internal#mapping#restore() abort
11+
for l:m in s:saved_maps
12+
try
13+
call mapset(l:m)
14+
catch
15+
endtry
16+
endfor
17+
endfunction
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import type { Action } from "https://deno.land/x/fall_core@v0.3.0/mod.ts";
2+
import { batch } from "https://deno.land/x/denops_std@v6.3.0/batch/mod.ts";
3+
import { assert, is } from "https://deno.land/x/unknownutil@v3.16.3/mod.ts";
4+
5+
const isOptions = is.StrictOf(is.PartialOf(is.ObjectOf({})));
6+
7+
export function getAction(
8+
options: Record<string, unknown>,
9+
): Action {
10+
assert(options, isOptions);
11+
return {
12+
invoke: async (denops, { cursorItem, selectedItems }) => {
13+
const items = selectedItems.length > 0
14+
? selectedItems
15+
: cursorItem
16+
? [cursorItem]
17+
: [];
18+
const content = items.map((item) => JSON.stringify(item));
19+
await batch(denops, async (denops) => {
20+
for (const line of content) {
21+
await denops.cmd(`echomsg ${line}`);
22+
}
23+
});
24+
// Keep picker running
25+
return true;
26+
},
27+
};
28+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import type { Action } from "https://deno.land/x/fall_core@v0.3.0/mod.ts";
2+
import * as buffer from "https://deno.land/x/denops_std@v6.3.0/buffer/mod.ts";
3+
import * as fn from "https://deno.land/x/denops_std@v6.3.0/function/mod.ts";
4+
import { assert, is } from "https://deno.land/x/unknownutil@v3.16.3/mod.ts";
5+
6+
const isOptions = is.StrictOf(is.PartialOf(is.ObjectOf({
7+
bang: is.Boolean,
8+
mods: is.String,
9+
cmdarg: is.String,
10+
opener: is.String,
11+
splitter: is.String,
12+
})));
13+
14+
const isPathDetail = is.ObjectOf({
15+
path: is.String,
16+
line: is.OptionalOf(is.Number),
17+
column: is.OptionalOf(is.Number),
18+
});
19+
20+
export function getAction(
21+
options: Record<string, unknown>,
22+
): Action {
23+
assert(options, isOptions);
24+
const bang = options.bang ?? false;
25+
const mods = options.mods ?? "";
26+
const cmdarg = options.cmdarg ?? "";
27+
const firstOpener = options.opener ?? "edit";
28+
const splitter = options.splitter ?? firstOpener;
29+
return {
30+
invoke: async (denops, { cursorItem, selectedItems }) => {
31+
const items = selectedItems.length > 0
32+
? selectedItems
33+
: cursorItem
34+
? [cursorItem]
35+
: [];
36+
let opener = firstOpener;
37+
for (const item of items) {
38+
if (!isPathDetail(item.detail)) {
39+
continue;
40+
}
41+
try {
42+
const info = await buffer.open(denops, item.detail.path, {
43+
bang,
44+
mods,
45+
cmdarg,
46+
opener,
47+
});
48+
opener = splitter;
49+
if (item.detail.line || item.detail.column) {
50+
const line = item.detail.line ?? 1;
51+
const column = item.detail.column ?? 1;
52+
await fn.win_execute(
53+
denops,
54+
info.winid,
55+
`silent! call cursor(${line}, ${column})`,
56+
);
57+
}
58+
} catch (err) {
59+
// Fail silently
60+
console.debug(
61+
`[fall] (action/open) Failed to open ${item.detail.path}:`,
62+
err,
63+
);
64+
}
65+
}
66+
return false;
67+
},
68+
};
69+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import type { Action } from "https://deno.land/x/fall_core@v0.3.0/mod.ts";
2+
import * as fn from "https://deno.land/x/denops_std@v6.3.0/function/mod.ts";
3+
import { assert, is } from "https://deno.land/x/unknownutil@v3.16.3/mod.ts";
4+
5+
const isOptions = is.StrictOf(is.PartialOf(is.ObjectOf({
6+
what: is.PartialOf(is.ObjectOf({
7+
context: is.Unknown,
8+
id: is.Number,
9+
idx: is.UnionOf([is.Number, is.String]),
10+
nr: is.Number,
11+
title: is.String,
12+
})),
13+
action: is.LiteralOneOf(["a", "r", "f", " "] as const),
14+
target: is.LiteralOneOf(
15+
[
16+
"selected-or-cursor",
17+
"selected-or-processed",
18+
] as const,
19+
),
20+
})));
21+
22+
const isPathDetail = is.ObjectOf({
23+
path: is.String,
24+
line: is.OptionalOf(is.Number),
25+
column: is.OptionalOf(is.Number),
26+
});
27+
28+
function isDefined<T>(value: T | undefined): value is T {
29+
return value !== undefined;
30+
}
31+
32+
export function getAction(
33+
options: Record<string, unknown>,
34+
): Action {
35+
assert(options, isOptions);
36+
const what = options.what ?? {};
37+
const action = options.action ?? " ";
38+
const target = options.target ?? "selected-or-cursor";
39+
return {
40+
invoke: async (denops, { cursorItem, selectedItems, processedItems }) => {
41+
const source = selectedItems.length > 0
42+
? selectedItems
43+
: target === "selected-or-cursor"
44+
? cursorItem ? [cursorItem] : []
45+
: processedItems;
46+
const items = source
47+
.map((item) => {
48+
if (isPathDetail(item.detail)) {
49+
return {
50+
filename: item.detail.path,
51+
lnum: item.detail.line,
52+
col: item.detail.column,
53+
};
54+
}
55+
return undefined;
56+
})
57+
.filter(isDefined);
58+
try {
59+
await fn.setqflist(denops, [], action, {
60+
...what,
61+
items,
62+
});
63+
} catch (err) {
64+
// Fail silently
65+
console.debug(
66+
`[fall] (action/quickfix) Failed to set quickfix list:`,
67+
err,
68+
);
69+
}
70+
return false;
71+
},
72+
};
73+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import type { Previewer } from "https://deno.land/x/fall_core@v0.3.0/mod.ts";
2+
import { batch } from "https://deno.land/x/denops_std@v6.3.0/batch/mod.ts";
3+
import * as fn from "https://deno.land/x/denops_std@v6.3.0/function/mod.ts";
4+
import { basename } from "https://deno.land/std@0.218.2/path/basename.ts";
5+
import { assert, is } from "https://deno.land/x/unknownutil@v3.16.3/mod.ts";
6+
7+
const isOptions = is.StrictOf(is.PartialOf(is.ObjectOf({})));
8+
9+
const isPathDetail = is.ObjectOf({
10+
path: is.String,
11+
line: is.OptionalOf(is.Number),
12+
column: is.OptionalOf(is.Number),
13+
});
14+
15+
export function getPreviewer(
16+
options: Record<string, unknown>,
17+
): Previewer {
18+
assert(options, isOptions);
19+
return {
20+
preview: async (denops, item, { winid }) => {
21+
if (!isPathDetail(item.detail)) {
22+
// No preview is available
23+
return;
24+
}
25+
const { line = 1, column = 1 } = item.detail;
26+
const path = await fn.fnameescape(denops, item.detail.path);
27+
await batch(denops, async (denops) => {
28+
await fn.win_execute(
29+
denops,
30+
winid,
31+
`setlocal modifiable`,
32+
);
33+
await fn.win_execute(
34+
denops,
35+
winid,
36+
`silent! 0,$delete _`,
37+
);
38+
await fn.win_execute(
39+
denops,
40+
winid,
41+
`silent! 0read ${path}`,
42+
);
43+
await fn.win_execute(
44+
denops,
45+
winid,
46+
`silent! $delete _`,
47+
);
48+
await fn.win_execute(
49+
denops,
50+
winid,
51+
`silent! 0file`,
52+
);
53+
await fn.win_execute(
54+
denops,
55+
winid,
56+
`silent! syntax clear`,
57+
);
58+
await fn.win_execute(
59+
denops,
60+
winid,
61+
`silent! file fall://preview/${basename(path)}`,
62+
);
63+
await fn.win_execute(
64+
denops,
65+
winid,
66+
`silent! doautocmd <nomodeline> BufRead`,
67+
);
68+
await fn.win_execute(
69+
denops,
70+
winid,
71+
`setlocal nomodifiable`,
72+
);
73+
await fn.win_execute(denops, winid, `normal! ${line}G${column}|`);
74+
});
75+
},
76+
};
77+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import type {
2+
Processor,
3+
ProcessorItem,
4+
} from "https://deno.land/x/fall_core@v0.3.0/mod.ts";
5+
import { assert, is } from "https://deno.land/x/unknownutil@v3.16.3/mod.ts";
6+
7+
const isOptions = is.StrictOf(is.PartialOf(is.ObjectOf({
8+
reverse: is.Boolean,
9+
})));
10+
11+
export function getProcessor(
12+
options: Record<string, unknown>,
13+
): Processor {
14+
assert(options, isOptions);
15+
const alpha = options.reverse ? -1 : 1;
16+
return {
17+
getStream: (_denops) => {
18+
const items: ProcessorItem[] = [];
19+
return new TransformStream({
20+
transform(chunk) {
21+
items.push(chunk);
22+
},
23+
flush(controller) {
24+
items.sort((a, b) => {
25+
return a.value.localeCompare(b.value) * alpha;
26+
});
27+
items.forEach((item) => controller.enqueue(item));
28+
},
29+
});
30+
},
31+
};
32+
}

0 commit comments

Comments
 (0)