Skip to content

Commit bafb016

Browse files
committed
Support builtins documentation and completions
1 parent d8035cc commit bafb016

File tree

4 files changed

+113
-1
lines changed

4 files changed

+113
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`documentation returns documentation string an known builtin 1`] = `
4+
"exit: exit [n]
5+
Exit the shell with a status of N. If N is omitted, the exit status
6+
is that of the last command executed.
7+
"
8+
`;

server/src/__tests__/builtins.test.ts

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import * as Builtins from '../builtins'
2+
3+
describe('documentation', () => {
4+
it('returns an error string an unknown builtin', async () => {
5+
const result = await Builtins.documentation('foobar')
6+
expect(result).toEqual('No help page for foobar')
7+
})
8+
9+
it('returns documentation string an known builtin', async () => {
10+
const result = await Builtins.documentation('exit')
11+
expect(result).toMatchSnapshot()
12+
})
13+
})

server/src/builtins.ts

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import * as ShUtil from './util/sh'
2+
3+
export const LIST = [
4+
'.',
5+
':',
6+
'[',
7+
'alias',
8+
'bg',
9+
'bind',
10+
'break',
11+
'builtin',
12+
'caller',
13+
'cd',
14+
'command',
15+
'compgen',
16+
'complete',
17+
'continue',
18+
'declare',
19+
'dirs',
20+
'disown',
21+
'echo',
22+
'enable',
23+
'eval',
24+
'exec',
25+
'exit',
26+
'export',
27+
'false',
28+
'fc',
29+
'fg',
30+
'getopts',
31+
'hash',
32+
'help',
33+
'history',
34+
'jobs',
35+
'kill',
36+
'let',
37+
'local',
38+
'logout',
39+
'popd',
40+
'printf',
41+
'pushd',
42+
'pwd',
43+
'read',
44+
'readonly',
45+
'return',
46+
'set',
47+
'shift',
48+
'shopt',
49+
'source',
50+
'suspend',
51+
'test',
52+
'times',
53+
'trap',
54+
'true',
55+
'type',
56+
'typeset',
57+
'ulimit',
58+
'umask',
59+
'unalias',
60+
'unset',
61+
'wait',
62+
]
63+
64+
export async function documentation(builtin: string): Promise<string> {
65+
const errorMessage = `No help page for ${builtin}`
66+
try {
67+
const doc = await ShUtil.execShellScript(`help ${builtin}`)
68+
return doc || errorMessage
69+
} catch (error) {
70+
return errorMessage
71+
}
72+
}

server/src/server.ts

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as LSP from 'vscode-languageserver'
22

33
import Analyzer from './analyser'
4+
import * as Builtins from './builtins'
45
import Executables from './executables'
56

67
/**
@@ -159,10 +160,20 @@ export default class BashServer {
159160
}
160161
})
161162

162-
return symbolCompletions.concat(programCompletions)
163+
const builtinsCompletions = Builtins.LIST.map(builtin => ({
164+
label: builtin,
165+
kind: LSP.SymbolKind.Method, // ??
166+
data: {
167+
name: builtin,
168+
type: 'builtin',
169+
},
170+
}))
171+
172+
return [...symbolCompletions, ...programCompletions, ...builtinsCompletions]
163173
}
164174

165175
private onCompletionResolve(item: LSP.CompletionItem): Promise<LSP.CompletionItem> {
176+
// TODO: async await would be nice I guess
166177
if (item.data.type === 'executable') {
167178
return this.executables
168179
.documentation(item.data.name)
@@ -171,6 +182,14 @@ export default class BashServer {
171182
detail: doc,
172183
}))
173184
.catch(() => item)
185+
} else if (item.data.type === 'builtin') {
186+
//
187+
return Builtins.documentation(item.data.name)
188+
.then(doc => ({
189+
...item,
190+
detail: doc,
191+
}))
192+
.catch(() => item)
174193
} else {
175194
return Promise.resolve(item)
176195
}

0 commit comments

Comments
 (0)