Skip to content

Commit 2986b4b

Browse files
authored
Merge pull request #40 from lambdalisue/add-components
Add `statusline` and `tabline` component functions
2 parents 84f517e + b7dc5c2 commit 2986b4b

File tree

9 files changed

+276
-1
lines changed

9 files changed

+276
-1
lines changed

autoload/gin/component/branch.vim

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
function! gin#component#branch#ascii(...) abort
2+
try
3+
let cwd = a:0 ? a:1 : ''
4+
return denops#request('gin', 'component:branch:ascii', [cwd])
5+
catch
6+
return ""
7+
endtry
8+
endfunction
9+
10+
function! gin#component#branch#unicode(...) abort
11+
try
12+
let cwd = a:0 ? a:1 : ''
13+
return denops#request('gin', 'component:branch:unicode', [cwd])
14+
catch
15+
return ""
16+
endtry
17+
endfunction

autoload/gin/component/traffic.vim

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
function! gin#component#traffic#ascii(...) abort
2+
try
3+
let cwd = a:0 ? a:1 : ''
4+
return denops#request('gin', 'component:traffic:ascii', [cwd])
5+
catch
6+
return ""
7+
endtry
8+
endfunction
9+
10+
function! gin#component#traffic#unicode(...) abort
11+
try
12+
let cwd = a:0 ? a:1 : ''
13+
return denops#request('gin', 'component:traffic:unicode', [cwd])
14+
catch
15+
return ""
16+
endtry
17+
endfunction

autoload/gin/component/worktree.vim

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
function! gin#component#worktree#full(...) abort
2+
try
3+
let cwd = a:0 ? a:1 : ''
4+
return denops#request('gin', 'component:worktree:full', [cwd])
5+
catch
6+
return ""
7+
endtry
8+
endfunction
9+
10+
function! gin#component#worktree#name(...) abort
11+
try
12+
let cwd = a:0 ? a:1 : ''
13+
return denops#request('gin', 'component:worktree:name', [cwd])
14+
catch
15+
return ""
16+
endtry
17+
endfunction

denops/gin/component/branch.ts

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { Cache, Denops, unknownutil } from "../deps.ts";
2+
import { decodeUtf8 } from "../util/text.ts";
3+
import { getWorktree } from "../util/worktree.ts";
4+
import { execute } from "../git/process.ts";
5+
6+
type Data = [string, string];
7+
8+
const cache = new Cache<string, Data>(100);
9+
10+
async function getData(
11+
denops: Denops,
12+
worktree: string,
13+
): Promise<Data> {
14+
if (cache.has("data")) {
15+
return cache.get("data");
16+
}
17+
const cwd = worktree || await getWorktree(denops);
18+
const result = await getBranches(cwd);
19+
cache.set("data", result);
20+
return result;
21+
}
22+
23+
async function getBranches(
24+
cwd: string,
25+
): Promise<Data> {
26+
const stdout = await execute([
27+
"rev-parse",
28+
"--abbrev-ref",
29+
"--symbolic-full-name",
30+
"HEAD",
31+
"@{u}",
32+
], {
33+
noOptionalLocks: true,
34+
cwd,
35+
});
36+
const [branch, upstream] = decodeUtf8(stdout).split("\n");
37+
return [branch, upstream];
38+
}
39+
40+
export function main(denops: Denops): void {
41+
denops.dispatcher = {
42+
...denops.dispatcher,
43+
"component:branch:ascii": async (worktree) => {
44+
unknownutil.assertString(worktree);
45+
const [branch, upstream] = await getData(denops, worktree);
46+
if (branch && upstream) {
47+
return `${branch} -> ${upstream}`;
48+
}
49+
return branch;
50+
},
51+
"component:branch:unicode": async (worktree) => {
52+
unknownutil.assertString(worktree);
53+
const [branch, upstream] = await getData(denops, worktree);
54+
if (branch && upstream) {
55+
return `${branch}${upstream}`;
56+
}
57+
return branch;
58+
},
59+
};
60+
}

denops/gin/component/traffic.ts

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { Cache, Denops, unknownutil } from "../deps.ts";
2+
import { decodeUtf8 } from "../util/text.ts";
3+
import { getWorktree } from "../util/worktree.ts";
4+
import { execute } from "../git/process.ts";
5+
6+
type Data = [number, number];
7+
8+
const cache = new Cache<string, Data>(100);
9+
10+
async function getData(
11+
denops: Denops,
12+
worktree: string,
13+
): Promise<Data> {
14+
if (cache.has("data")) {
15+
return cache.get("data");
16+
}
17+
const cwd = worktree || await getWorktree(denops);
18+
const result = await Promise.all([
19+
getAhead(cwd),
20+
getBehind(cwd),
21+
]);
22+
cache.set("data", result);
23+
return result;
24+
}
25+
26+
async function getAhead(cwd: string): Promise<number> {
27+
const stdout = await execute([
28+
"rev-list",
29+
"--count",
30+
"@{u}..HEAD",
31+
], {
32+
noOptionalLocks: true,
33+
cwd,
34+
});
35+
return Number(decodeUtf8(stdout));
36+
}
37+
38+
async function getBehind(cwd: string): Promise<number> {
39+
const stdout = await execute([
40+
"rev-list",
41+
"--count",
42+
"HEAD..@{u}",
43+
], {
44+
noOptionalLocks: true,
45+
cwd,
46+
});
47+
return Number(decodeUtf8(stdout));
48+
}
49+
50+
export function main(denops: Denops): void {
51+
denops.dispatcher = {
52+
...denops.dispatcher,
53+
"component:traffic:ascii": async (worktree) => {
54+
unknownutil.assertString(worktree);
55+
const [ahead, behind] = await getData(denops, worktree);
56+
let component = "";
57+
if (ahead) {
58+
component += `^${ahead}`;
59+
}
60+
if (behind) {
61+
component += `v${behind}`;
62+
}
63+
return component;
64+
},
65+
"component:traffic:unicode": async (worktree) => {
66+
unknownutil.assertString(worktree);
67+
const [ahead, behind] = await getData(denops, worktree);
68+
let component = "";
69+
if (ahead) {
70+
component += `↑${ahead}`;
71+
}
72+
if (behind) {
73+
component += `↓${behind}`;
74+
}
75+
return component;
76+
},
77+
};
78+
}

denops/gin/component/worktree.ts

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { Cache, Denops, path, unknownutil } from "../deps.ts";
2+
import { getWorktree } from "../util/worktree.ts";
3+
import { find } from "../git/finder.ts";
4+
5+
type Data = string;
6+
7+
const cache = new Cache<string, Data>(100);
8+
9+
async function getData(
10+
denops: Denops,
11+
worktree: string,
12+
): Promise<Data> {
13+
if (cache.has("data")) {
14+
return cache.get("data");
15+
}
16+
const cwd = worktree || await getWorktree(denops);
17+
const result = await find(cwd);
18+
cache.set("data", result);
19+
return result;
20+
}
21+
22+
export function main(denops: Denops): void {
23+
denops.dispatcher = {
24+
...denops.dispatcher,
25+
"component:worktree:full": async (worktree) => {
26+
unknownutil.assertString(worktree);
27+
const fullpath = await getData(denops, worktree);
28+
return fullpath;
29+
},
30+
"component:worktree:name": async (worktree) => {
31+
unknownutil.assertString(worktree);
32+
const fullpath = await getData(denops, worktree);
33+
return path.basename(fullpath);
34+
},
35+
};
36+
}

denops/gin/main.ts

+8
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ import { main as mainEdit } from "./feat/edit/main.ts";
1212
import { main as mainPatch } from "./feat/patch/main.ts";
1313
import { main as mainStatus } from "./feat/status/main.ts";
1414

15+
import { main as mainComponentBranch } from "./component/branch.ts";
16+
import { main as mainComponentTraffic } from "./component/traffic.ts";
17+
import { main as mainComponentWorktree } from "./component/worktree.ts";
18+
1519
export function main(denops: Denops): void {
1620
mainAction(denops);
1721
mainBare(denops);
@@ -24,4 +28,8 @@ export function main(denops: Denops): void {
2428
mainEdit(denops);
2529
mainPatch(denops);
2630
mainStatus(denops);
31+
32+
mainComponentBranch(denops);
33+
mainComponentTraffic(denops);
34+
mainComponentWorktree(denops);
2735
}

denops/gin/util/worktree.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { expand } from "../util/cmd.ts";
1313
import { Opts } from "../util/args.ts";
1414
import { find } from "../git/finder.ts";
1515

16-
async function getWorktree(denops: Denops): Promise<string> {
16+
export async function getWorktree(denops: Denops): Promise<string> {
1717
const [cwd, filename, verbose] = await batch.gather(
1818
denops,
1919
async (denops) => {

doc/gin.txt

+42
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ INTERFACE |gin-interface|
1616
COMMANDS |gin-commands|
1717
VARIABLES |gin-variables|
1818
FUNCTIONS |gin-functions|
19+
COMPONENTS |gin-components|
1920
MAPPINGS |gin-mappings|
2021
ACTIONS |gin-actions|
2122

@@ -347,6 +348,47 @@ gin#action#list_actions()
347348
gin#action#gather_candidates({range})
348349
Gather and return candidates of the current buffer in {range}.
349350

351+
-----------------------------------------------------------------------------
352+
COMPONENTS *gin-components*
353+
354+
Components are |Function| that return a string for |statusline| and |tabline|.
355+
The function will never throw errors and fail silently.
356+
Note that the result of function is cached shortly to keep performance.
357+
If no {worktree} is specified or an empty string, gin tries to find one like
358+
++worktree option explained in |gin-command-options|.
359+
>
360+
set statusline+=\ %{gin#component#worktree#name()}
361+
set statusline+=\ (%{gin#component#branch#ascii()})
362+
set statusline+=\ [%{gin#component#traffic#ascii()}]
363+
<
364+
Because |statusline| and/or |tabline| is not rendered on |BufEnter|, the
365+
following configuration is recommended for fast update.
366+
>
367+
augroup gin_component_fast_update
368+
autocmd!
369+
autocmd BufEnter * ++nested redrawstatusline
370+
" Or if you prefer tabline, use below
371+
"autocmd BufEnter * ++nested redrawtabline
372+
augroup END
373+
<
374+
*gin#component#branch#ascii()*
375+
*gin#component#branch#unicode()*
376+
gin#component#branch#ascii([{worktree}])
377+
gin#component#branch#unicode([{worktree}])
378+
Return an indicator string of a current and upstream branches.
379+
380+
*gin#component#traffic#ascii()*
381+
*gin#component#traffic#unicode()*
382+
gin#component#traffic#ascii([{worktree}])
383+
gin#component#traffic#unicode([{worktree}])
384+
Return an indicator string of the number of ahead and behind commits.
385+
386+
*gin#component#worktree#full()*
387+
*gin#component#worktree#name()*
388+
gin#component#worktree#full([{worktree}])
389+
gin#component#worktree#name([{worktree}])
390+
Return an indicator string of the current worktree.
391+
350392
-----------------------------------------------------------------------------
351393
MAPPINGS *gin-mappings*
352394

0 commit comments

Comments
 (0)