Skip to content

Commit ebc78db

Browse files
committed
Support reserved words
1 parent 845f7e2 commit ebc78db

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed

server/src/reservedWords.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import * as ShUtil from './util/sh'
2+
3+
// https://www.gnu.org/software/bash/manual/html_node/Reserved-Word-Index.html
4+
5+
export const LIST = [
6+
'!',
7+
'[[',
8+
']]',
9+
'{',
10+
'}',
11+
'case',
12+
'do',
13+
'done',
14+
'elif',
15+
'else',
16+
'esac',
17+
'fi',
18+
'for',
19+
'function',
20+
'if',
21+
'in',
22+
'select',
23+
'then',
24+
'time',
25+
'until',
26+
'while',
27+
]
28+
29+
const SET = new Set(LIST)
30+
31+
export function isReservedWord(word: string): boolean {
32+
return SET.has(word)
33+
}
34+
35+
export async function documentation(reservedWord: string): Promise<string> {
36+
try {
37+
const doc = await ShUtil.execShellScript(`help ${reservedWord}`)
38+
return doc || ''
39+
} catch (error) {
40+
return ''
41+
}
42+
}

server/src/server.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import * as Builtins from './builtins'
66
import * as config from './config'
77
import Executables from './executables'
88
import { initializeParser } from './parser'
9+
import * as ReservedWords from './reservedWords'
910

1011
/**
1112
* The BashServer glues together the separate components to implement
@@ -161,6 +162,12 @@ export default class BashServer {
161162
}))
162163
}
163164

165+
if (ReservedWords.isReservedWord(word)) {
166+
return ReservedWords.documentation(word).then(doc => ({
167+
contents: getMarkdownHoverItem(doc),
168+
}))
169+
}
170+
164171
if (this.executables.isExecutableOnPATH(word)) {
165172
return this.executables.documentation(word).then(doc => ({
166173
contents: getMarkdownHoverItem(doc),
@@ -203,6 +210,17 @@ export default class BashServer {
203210

204211
const symbolCompletions = this.analyzer.findSymbolCompletions(params.textDocument.uri)
205212

213+
// TODO: we could do some caching here...
214+
215+
const reservedWordsCompletions = ReservedWords.LIST.map(reservedWord => ({
216+
label: reservedWord,
217+
kind: LSP.SymbolKind.Interface, // ??
218+
data: {
219+
name: reservedWord,
220+
type: 'reservedWord',
221+
},
222+
}))
223+
206224
const programCompletions = this.executables.list().map((s: string) => {
207225
return {
208226
label: s,
@@ -225,6 +243,7 @@ export default class BashServer {
225243

226244
// TODO: we have duplicates here (e.g. echo is both a builtin AND have a man page)
227245
const allCompletions = [
246+
...reservedWordsCompletions,
228247
...symbolCompletions,
229248
...programCompletions,
230249
...builtinsCompletions,
@@ -269,6 +288,9 @@ export default class BashServer {
269288
} else if (type === 'builtin') {
270289
const doc = await Builtins.documentation(name)
271290
return getMarkdownCompletionItem(doc)
291+
} else if (type === 'reservedWord') {
292+
const doc = await ReservedWords.documentation(name)
293+
return getMarkdownCompletionItem(doc)
272294
} else {
273295
return item
274296
}

0 commit comments

Comments
 (0)