Skip to content

Commit 45eefdc

Browse files
authored
Add selection range handler (#213)
* Add selection range handler
1 parent 9fdd0e4 commit 45eefdc

File tree

6 files changed

+113
-18
lines changed

6 files changed

+113
-18
lines changed

README.md

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -56,19 +56,20 @@ Or use local versions from your `node_modules` directory, if you want to do that
5656

5757
Supports Elm 0.19
5858

59-
| Feature | Description |
60-
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
61-
| Diagnostics | Provided via `elm`, `elm-test` and `elm-analyse` |
62-
| Formatting | Provided via `elm-format` and postprocessed to only return a diff of changes. This way it should not be as intrusive as running `elm-format` normal |
63-
| codeLenses | Currently only shows if a type alias, custom type or function is exposed from that module |
64-
| completions | Show completions for the current file and snippets |
65-
| definitions | Enables you to jump to the definition of a type alias, module, custom type or function |
66-
| documentSymbols | Identifies all symbols in a document. |
67-
| folding | Let's you fold the code on certain Elm constructs |
68-
| hover | Shows type annotations and documentation for a type alias, module, custom type or function |
69-
| references | Lists all references to a type alias, module, custom type or function |
70-
| rename | Enables you to rename a type alias, module, custom type or function |
71-
| workspaceSymbols | Identifies all symbols in the current workspace |
59+
| Feature | Description |
60+
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
61+
| diagnostics | Provided via `elm`, `elm-test` and `elm-analyse` |
62+
| formatting | Provided via `elm-format` and post-processed to only return a diff of changes. This way it should not be as intrusive as running `elm-format` normal |
63+
| codeLenses | Currently only shows if a type alias, custom type or function is exposed from that module |
64+
| completions | Show completions for the current file and snippets |
65+
| definitions | Enables you to jump to the definition of a type alias, module, custom type or function |
66+
| documentSymbols | Identifies all symbols in a document. |
67+
| folding | Let's you fold the code on certain Elm constructs |
68+
| hover | Shows type annotations and documentation for a type alias, module, custom type or function |
69+
| references | Lists all references to a type alias, module, custom type or function |
70+
| rename | Enables you to rename a type alias, module, custom type or function |
71+
| workspaceSymbols | Identifies all symbols in the current workspace |
72+
| selectionRange | Enables navigation by selectionRange (extend selection for e.g.) |
7273

7374
## Server Settings
7475

src/capabilityCalculator.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export class CapabilityCalculator {
3939
hoverProvider: true,
4040
referencesProvider: true,
4141
renameProvider: true,
42+
selectionRangeProvider: true,
4243
textDocumentSync: TextDocumentSyncKind.Full,
4344
workspaceSymbolProvider: true,
4445
};

src/position.ts renamed to src/positionUtil.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { Position as VSPosition } from "vscode-languageserver";
22
import { Point as TSPosition } from "web-tree-sitter";
33

4-
export class Position {
5-
public static FROM_VS_POSITION(position: VSPosition): Position {
6-
return new Position(position.line, position.character);
4+
export class PositionUtil {
5+
public static FROM_VS_POSITION(position: VSPosition): PositionUtil {
6+
return new PositionUtil(position.line, position.character);
77
}
88

9-
public static FROM_TS_POSITION(position: TSPosition): Position {
10-
return new Position(position.row, position.column);
9+
public static FROM_TS_POSITION(position: TSPosition): PositionUtil {
10+
return new PositionUtil(position.row, position.column);
1111
}
1212

1313
private row: number;

src/providers/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export * from "./diagnostics/elmAnalyseDiagnostics";
88
export * from "./diagnostics/elmMakeDiagnostics";
99
export * from "./documentFormatingProvider";
1010
export * from "./documentSymbolProvider";
11+
export * from "./selectionRangeProvider";
1112
export * from "./foldingProvider";
1213
export * from "./hoverProvider";
1314
export * from "./referencesProvider";
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import {
2+
SelectionRange,
3+
SelectionRangeParams,
4+
IConnection,
5+
Range,
6+
Position,
7+
} from "vscode-languageserver";
8+
import { URI } from "vscode-uri";
9+
import { SyntaxNode, Tree } from "web-tree-sitter";
10+
import { ElmWorkspace } from "../elmWorkspace";
11+
import { ElmWorkspaceMatcher } from "../util/elmWorkspaceMatcher";
12+
import { TreeUtils } from "../util/treeUtils";
13+
import { PositionUtil } from "../positionUtil";
14+
15+
export class SelectionRangeProvider {
16+
constructor(private connection: IConnection, elmWorkspaces: ElmWorkspace[]) {
17+
connection.onSelectionRanges(
18+
new ElmWorkspaceMatcher(elmWorkspaces, (param: SelectionRangeParams) =>
19+
URI.parse(param.textDocument.uri),
20+
).handlerForWorkspace(this.handleSelectionRangeRequest),
21+
);
22+
}
23+
24+
private handleSelectionRangeRequest = async (
25+
params: SelectionRangeParams,
26+
elmWorkspace: ElmWorkspace,
27+
): Promise<SelectionRange[] | null> => {
28+
this.connection.console.info(`Selection Ranges were requested`);
29+
30+
const ret: SelectionRange[] = [];
31+
32+
const forest = elmWorkspace.getForest();
33+
const tree: Tree | undefined = forest.getTree(params.textDocument.uri);
34+
35+
if (tree) {
36+
params.positions.forEach((position: Position) => {
37+
const nodeAtPosition = TreeUtils.getNamedDescendantForPosition(
38+
tree.rootNode,
39+
position,
40+
);
41+
42+
const newRange = {
43+
start: PositionUtil.FROM_TS_POSITION(
44+
nodeAtPosition.startPosition,
45+
).toVSPosition(),
46+
end: PositionUtil.FROM_TS_POSITION(
47+
nodeAtPosition.endPosition,
48+
).toVSPosition(),
49+
};
50+
51+
ret.push({
52+
range: newRange,
53+
parent: this.getParentNode(nodeAtPosition, newRange),
54+
});
55+
});
56+
}
57+
58+
return ret ? ret : null;
59+
};
60+
61+
private getParentNode(
62+
node: SyntaxNode,
63+
previousRange: Range,
64+
): SelectionRange | undefined {
65+
if (node.parent) {
66+
const newRange = {
67+
start: PositionUtil.FROM_TS_POSITION(
68+
node.parent.startPosition,
69+
).toVSPosition(),
70+
end: PositionUtil.FROM_TS_POSITION(
71+
node.parent.endPosition,
72+
).toVSPosition(),
73+
};
74+
if (
75+
previousRange.start.line === newRange.start.line &&
76+
previousRange.start.character === newRange.start.character &&
77+
previousRange.end.line === newRange.end.line &&
78+
previousRange.end.character === newRange.end.character
79+
) {
80+
// Skip ranges that match
81+
return this.getParentNode(node.parent, previousRange);
82+
} else {
83+
return {
84+
range: newRange,
85+
parent: this.getParentNode(node.parent, newRange),
86+
};
87+
}
88+
}
89+
}
90+
}

src/server.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
ReferencesProvider,
2626
RenameProvider,
2727
WorkspaceSymbolProvider,
28+
SelectionRangeProvider,
2829
} from "./providers";
2930
import { DocumentEvents } from "./util/documentEvents";
3031
import { Settings } from "./util/settings";
@@ -189,6 +190,7 @@ export class Server implements ILanguageServer {
189190
new DocumentSymbolProvider(this.connection, this.elmWorkspaces);
190191
new WorkspaceSymbolProvider(this.connection, this.elmWorkspaces);
191192
new CodeLensProvider(this.connection, this.elmWorkspaces);
193+
new SelectionRangeProvider(this.connection, this.elmWorkspaces);
192194
new RenameProvider(this.connection, this.elmWorkspaces);
193195
}
194196

0 commit comments

Comments
 (0)