Skip to content

Commit ef0d500

Browse files
committed
Replace complex tree sitter helper
The helper was originally introduced to make the detection of a word at a given point more accurate (this is used for completion, hovering, etc) and fixes some issues with the tree sitter grammar. It turns out this is really not needed and introduces a bunch of issues. Related to #192
1 parent e441064 commit ef0d500

File tree

5 files changed

+33
-81
lines changed

5 files changed

+33
-81
lines changed

server/src/__tests__/analyzer.test.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,26 @@ describe('findSymbolsForFile', () => {
8787
describe('wordAtPoint', () => {
8888
it('returns current word at a given point', () => {
8989
analyzer.analyze(CURRENT_URI, FIXTURES.INSTALL)
90+
expect(analyzer.wordAtPoint(CURRENT_URI, 25, 0)).toEqual(null)
91+
expect(analyzer.wordAtPoint(CURRENT_URI, 25, 1)).toEqual(null)
92+
expect(analyzer.wordAtPoint(CURRENT_URI, 25, 2)).toEqual(null)
93+
expect(analyzer.wordAtPoint(CURRENT_URI, 25, 3)).toEqual(null)
94+
expect(analyzer.wordAtPoint(CURRENT_URI, 25, 4)).toEqual('rm')
9095
expect(analyzer.wordAtPoint(CURRENT_URI, 25, 5)).toEqual('rm')
96+
expect(analyzer.wordAtPoint(CURRENT_URI, 25, 6)).toEqual(null)
97+
expect(analyzer.wordAtPoint(CURRENT_URI, 25, 7)).toEqual('npm-install-')
9198

92-
// FIXME: grammar issue: else is not found
93-
// expect(analyzer.wordAtPoint(CURRENT_URI, 24, 5)).toEqual('else')
99+
expect(analyzer.wordAtPoint(CURRENT_URI, 24, 2)).toEqual('else')
100+
expect(analyzer.wordAtPoint(CURRENT_URI, 24, 3)).toEqual('else')
101+
expect(analyzer.wordAtPoint(CURRENT_URI, 24, 5)).toEqual('else')
102+
expect(analyzer.wordAtPoint(CURRENT_URI, 24, 7)).toEqual(null)
94103

95104
expect(analyzer.wordAtPoint(CURRENT_URI, 30, 1)).toEqual(null)
96105

106+
expect(analyzer.wordAtPoint(CURRENT_URI, 30, 2)).toEqual('ret')
97107
expect(analyzer.wordAtPoint(CURRENT_URI, 30, 3)).toEqual('ret')
98108
expect(analyzer.wordAtPoint(CURRENT_URI, 30, 4)).toEqual('ret')
99-
expect(analyzer.wordAtPoint(CURRENT_URI, 30, 5)).toEqual('ret')
109+
expect(analyzer.wordAtPoint(CURRENT_URI, 30, 5)).toEqual('=')
100110

101111
expect(analyzer.wordAtPoint(CURRENT_URI, 38, 5)).toEqual('configures')
102112
})

server/src/__tests__/server.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ describe('server', () => {
181181
{} as any,
182182
)
183183

184-
expect(result2).toMatchInlineSnapshot(`null`)
184+
expect(result2).toMatchInlineSnapshot(`Array []`)
185185
})
186186

187187
it('responds to onWorkspaceSymbol', async () => {
@@ -279,17 +279,17 @@ describe('server', () => {
279279
uri: FIXTURE_URI.INSTALL,
280280
},
281281
position: {
282-
// else
283-
line: 24,
284-
character: 5,
282+
// empty space
283+
line: 26,
284+
character: 0,
285285
},
286286
},
287287
{} as any,
288288
{} as any,
289289
)
290290

291291
// Entire list
292-
expect(result && 'length' in result && result.length > 50).toBe(true)
292+
expect(result && 'length' in result && result.length).toBeGreaterThanOrEqual(50)
293293
})
294294

295295
it('responds to onCompletion with empty list when word is a comment', async () => {

server/src/analyser.ts

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -371,32 +371,19 @@ export default class Analyzer {
371371
*/
372372
public wordAtPoint(uri: string, line: number, column: number): string | null {
373373
const document = this.uriToTreeSitterTrees[uri]
374-
const contents = this.uriToFileContent[uri]
375374

376375
if (!document.rootNode) {
377376
// Check for lacking rootNode (due to failed parse?)
378377
return null
379378
}
380379

381-
const point = { row: line, column }
382-
383-
const node = TreeSitterUtil.namedLeafDescendantForPosition(point, document.rootNode)
380+
const node = document.rootNode.descendantForPosition({ row: line, column })
384381

385-
if (!node) {
382+
if (!node || node.childCount > 0 || node.text.trim() === '') {
386383
return null
387384
}
388385

389-
const start = node.startIndex
390-
const end = node.endIndex
391-
const name = contents.slice(start, end)
392-
393-
// Hack. Might be a problem with the grammar.
394-
// TODO: Document this with a test case
395-
if (name.endsWith('=')) {
396-
return name.slice(0, name.length - 1)
397-
}
398-
399-
return name
386+
return node.text.trim()
400387
}
401388

402389
/**

server/src/server.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,9 +273,11 @@ export default class BashServer {
273273
): LSP.DocumentHighlight[] | null {
274274
const word = this.getWordAtPoint(params)
275275
this.logRequest({ request: 'onDocumentHighlight', params, word })
276+
276277
if (!word) {
277-
return null
278+
return []
278279
}
280+
279281
return this.analyzer
280282
.findOccurrences(params.textDocument.uri, word)
281283
.map(n => ({ range: n.range }))
@@ -291,7 +293,14 @@ export default class BashServer {
291293
}
292294

293295
private onCompletion(params: LSP.TextDocumentPositionParams): BashCompletionItem[] {
294-
const word = this.getWordAtPoint(params)
296+
const word = this.getWordAtPoint({
297+
...params,
298+
position: {
299+
line: params.position.line,
300+
// Go one character back to get completion on the current word
301+
character: Math.max(params.position.character - 1, 0),
302+
},
303+
})
295304
this.logRequest({ request: 'onCompletion', params, word })
296305

297306
const currentUri = params.textDocument.uri

server/src/util/tree-sitter.ts

Lines changed: 1 addition & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Range } from 'vscode-languageserver/lib/main'
2-
import { Point, SyntaxNode } from 'web-tree-sitter'
2+
import { SyntaxNode } from 'web-tree-sitter'
33

44
export function forEach(node: SyntaxNode, cb: (n: SyntaxNode) => void) {
55
cb(node)
@@ -52,57 +52,3 @@ export function findParent(
5252
}
5353
return null
5454
}
55-
56-
/**
57-
* Given a tree and a point, try to find the named leaf node that the point corresponds to.
58-
* This is a helper for wordAtPoint, useful in cases where the point occurs at the boundary of
59-
* a word so the normal behavior of "namedDescendantForPosition" does not find the desired leaf.
60-
* For example, if you do
61-
* > (new Parser()).setLanguage(bash).parse("echo 42").rootNode.descendantForIndex(4).text
62-
* then you get 'echo 42', not the leaf node for 'echo'.
63-
*
64-
* TODO: the need for this function might reveal a flaw in tree-sitter-bash.
65-
*/
66-
export function namedLeafDescendantForPosition(
67-
point: Point,
68-
rootNode: SyntaxNode,
69-
): SyntaxNode | null {
70-
const node = rootNode.namedDescendantForPosition(point)
71-
72-
if (node.childCount === 0) {
73-
return node
74-
} else {
75-
// The node wasn't a leaf. Try to figure out what word we should use.
76-
const nodeToUse = searchForLeafNode(point, node)
77-
if (nodeToUse) {
78-
return nodeToUse
79-
} else {
80-
return null
81-
}
82-
}
83-
}
84-
85-
function searchForLeafNode(point: Point, parent: SyntaxNode): SyntaxNode | null {
86-
let child = parent.firstNamedChild
87-
88-
while (child) {
89-
if (
90-
pointsEqual(child.startPosition, point) ||
91-
pointsEqual(child.endPosition, point)
92-
) {
93-
if (child.childCount === 0) {
94-
return child
95-
} else {
96-
return searchForLeafNode(point, child)
97-
}
98-
}
99-
100-
child = child.nextNamedSibling
101-
}
102-
103-
return null
104-
}
105-
106-
function pointsEqual(point1: Point, point2: Point) {
107-
return point1.row === point2.row && point1.column === point2.column
108-
}

0 commit comments

Comments
 (0)