Skip to content

Commit 3dfff09

Browse files
committed
Make symbol completions unique
1 parent 075c521 commit 3dfff09

File tree

5 files changed

+176
-12
lines changed

5 files changed

+176
-12
lines changed

server/src/__tests__/__snapshots__/analyzer.test.ts.snap

+133
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,139 @@ Array [
107107
]
108108
`;
109109

110+
exports[`findSymbolCompletions return a list of symbols 1`] = `
111+
Array [
112+
Object {
113+
"data": Object {
114+
"name": "ret",
115+
"type": "function",
116+
},
117+
"kind": undefined,
118+
"label": "ret",
119+
},
120+
Object {
121+
"data": Object {
122+
"name": "configures",
123+
"type": "function",
124+
},
125+
"kind": undefined,
126+
"label": "configures",
127+
},
128+
Object {
129+
"data": Object {
130+
"name": "npm_config_loglevel",
131+
"type": "function",
132+
},
133+
"kind": undefined,
134+
"label": "npm_config_loglevel",
135+
},
136+
Object {
137+
"data": Object {
138+
"name": "node",
139+
"type": "function",
140+
},
141+
"kind": undefined,
142+
"label": "node",
143+
},
144+
Object {
145+
"data": Object {
146+
"name": "TMP",
147+
"type": "function",
148+
},
149+
"kind": undefined,
150+
"label": "TMP",
151+
},
152+
Object {
153+
"data": Object {
154+
"name": "BACK",
155+
"type": "function",
156+
},
157+
"kind": undefined,
158+
"label": "BACK",
159+
},
160+
Object {
161+
"data": Object {
162+
"name": "tar",
163+
"type": "function",
164+
},
165+
"kind": undefined,
166+
"label": "tar",
167+
},
168+
Object {
169+
"data": Object {
170+
"name": "MAKE",
171+
"type": "function",
172+
},
173+
"kind": undefined,
174+
"label": "MAKE",
175+
},
176+
Object {
177+
"data": Object {
178+
"name": "make",
179+
"type": "function",
180+
},
181+
"kind": undefined,
182+
"label": "make",
183+
},
184+
Object {
185+
"data": Object {
186+
"name": "clean",
187+
"type": "function",
188+
},
189+
"kind": undefined,
190+
"label": "clean",
191+
},
192+
Object {
193+
"data": Object {
194+
"name": "node_version",
195+
"type": "function",
196+
},
197+
"kind": undefined,
198+
"label": "node_version",
199+
},
200+
Object {
201+
"data": Object {
202+
"name": "t",
203+
"type": "function",
204+
},
205+
"kind": undefined,
206+
"label": "t",
207+
},
208+
Object {
209+
"data": Object {
210+
"name": "url",
211+
"type": "function",
212+
},
213+
"kind": undefined,
214+
"label": "url",
215+
},
216+
Object {
217+
"data": Object {
218+
"name": "ver",
219+
"type": "function",
220+
},
221+
"kind": undefined,
222+
"label": "ver",
223+
},
224+
Object {
225+
"data": Object {
226+
"name": "isnpm10",
227+
"type": "function",
228+
},
229+
"kind": undefined,
230+
"label": "isnpm10",
231+
},
232+
Object {
233+
"data": Object {
234+
"name": "NODE",
235+
"type": "function",
236+
},
237+
"kind": undefined,
238+
"label": "NODE",
239+
},
240+
]
241+
`;
242+
110243
exports[`findSymbols returns a list of SymbolInformation if uri is found 1`] = `
111244
Array [
112245
Object {

server/src/__tests__/analyzer.test.ts

+6
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,9 @@ describe('wordAtPoint', () => {
6767
// expect(analyzer.wordAtPoint(CURRENT_URI, 24, 4)).toEqual('else')
6868
})
6969
})
70+
71+
describe('findSymbolCompletions', () => {
72+
it('return a list of symbols', () => {
73+
expect(analyzer.findSymbolCompletions(CURRENT_URI)).toMatchSnapshot()
74+
})
75+
})

server/src/analyser.ts

+19
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { Document } from 'tree-sitter'
77
import * as bash from 'tree-sitter-bash'
88
import * as LSP from 'vscode-languageserver'
99

10+
import { uniqueBasedOnHash } from './util/array'
1011
import * as TreeSitterUtil from './util/tree-sitter'
1112

1213
type Kinds = { [type: string]: LSP.SymbolKind }
@@ -137,6 +138,24 @@ export default class Analyzer {
137138
return ds
138139
}
139140

141+
/**
142+
* Find unique symbol completions for the given file.
143+
*/
144+
public findSymbolCompletions(uri: string): LSP.CompletionItem[] {
145+
const hashFunction = ({ name, kind }) => `${name}${kind}`
146+
147+
return uniqueBasedOnHash(this.findSymbols(uri), hashFunction).map(
148+
(symbol: LSP.SymbolInformation) => ({
149+
label: symbol.name,
150+
kind: symbol.kind,
151+
data: {
152+
name: symbol.name,
153+
type: 'function',
154+
},
155+
}),
156+
)
157+
}
158+
140159
/**
141160
* Analyze the given document, cache the tree-sitter AST, and iterate over the
142161
* tree to find declarations.

server/src/server.ts

+1-12
Original file line numberDiff line numberDiff line change
@@ -146,18 +146,7 @@ export default class BashServer {
146146
this.connection.console.log(
147147
`Asked for completions at ${pos.position.line}:${pos.position.character}`,
148148
)
149-
const symbols = this.analyzer.findSymbols(pos.textDocument.uri)
150-
151-
const symbolCompletions = symbols.map((s: LSP.SymbolInformation) => {
152-
return {
153-
label: s.name,
154-
kind: s.kind,
155-
data: {
156-
name: s.name,
157-
type: 'function',
158-
},
159-
}
160-
})
149+
const symbolCompletions = this.analyzer.findSymbolCompletions(pos.textDocument.uri)
161150

162151
const programCompletions = this.executables.list().map((s: string) => {
163152
return {

server/src/util/array.ts

+17
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,20 @@ export function flatten<A>(xs: A[][]): A[] {
1212
export function uniq<A>(a: A[]): A[] {
1313
return Array.from(new Set(a))
1414
}
15+
16+
/**
17+
* Removed all duplicates from the list based on the hash function.
18+
*/
19+
export function uniqueBasedOnHash<A>(list: A[], elementToHash: (a: A) => string): A[] {
20+
const hashSet = new Set()
21+
22+
return list.reduce((accumulator, currentValue) => {
23+
const hash = elementToHash(currentValue)
24+
if (hashSet.has(hash)) {
25+
return accumulator
26+
}
27+
hashSet.add(hash)
28+
29+
return [...accumulator, currentValue]
30+
}, [])
31+
}

0 commit comments

Comments
 (0)