diff options
-rw-r--r-- | .cargo/config | 1 | ||||
-rw-r--r-- | CONTRIBUTING.md | 88 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated.rs | 3 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated.rs.tera | 5 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar.ron | 5 | ||||
-rw-r--r-- | crates/ra_syntax/src/syntax_kinds/generated.rs | 3 | ||||
-rw-r--r-- | crates/ra_syntax/src/syntax_kinds/generated.rs.tera | 5 | ||||
-rw-r--r-- | editors/code/package.json | 2 | ||||
-rw-r--r-- | editors/code/src/extension.ts | 47 |
9 files changed, 112 insertions, 47 deletions
diff --git a/.cargo/config b/.cargo/config index 767045bdb..ac7470c7e 100644 --- a/.cargo/config +++ b/.cargo/config | |||
@@ -1,4 +1,5 @@ | |||
1 | [alias] | 1 | [alias] |
2 | # Automatically generates the ast and syntax kinds files | ||
2 | gen-kinds = "run --package tools -- gen-kinds" | 3 | gen-kinds = "run --package tools -- gen-kinds" |
3 | gen-tests = "run --package tools -- gen-tests" | 4 | gen-tests = "run --package tools -- gen-tests" |
4 | install-code = "run --package tools -- install-code" | 5 | install-code = "run --package tools -- install-code" |
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 41954c02e..c952078cf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md | |||
@@ -1,38 +1,58 @@ | |||
1 | The project is in its early stages: contributions are welcome and | 1 | The project is in its early stages: contributions are welcome and would be |
2 | would be **very** helpful, but the project is not *yet* optimized for | 2 | **very** helpful, but the project is not _yet_ optimized for contribution. |
3 | contribution. Moreover, it is doubly experimental, so there's no | 3 | Moreover, it is doubly experimental, so there's no guarantee that any work here |
4 | guarantee that any work here would reach production. That said, here | 4 | would reach production. That said, here are some areas where contributions would |
5 | are some areas where contributions would be **especially** welcome: | 5 | be **especially** welcome: |
6 | 6 | ||
7 | 7 | - Designing internal data structures: RFC only outlines the constraints, it's an | |
8 | * Designing internal data structures: RFC only outlines the | 8 | open question how to satisfy them in the optimal way. See `ARCHITECTURE.md` |
9 | constraints, it's an open question how to satisfy them in the | 9 | for current design questions. |
10 | optimal way. See `ARCHITECTURE.md` for current design questions. | 10 | |
11 | 11 | - Porting libsyntax parser to rust-analyzer: currently rust-analyzer parses only | |
12 | * Porting libsyntax parser to rust-analyzer: currently rust-analyzer parses | 12 | a tiny subset of Rust. This should be fixed by porting parsing functions from |
13 | only a tiny subset of Rust. This should be fixed by porting parsing | 13 | libsyntax one by one. Take a look at the [libsyntax parser] for "what to port" |
14 | functions from libsyntax one by one. Take a look at the | 14 | and at the [Kotlin parser] for "how to port". |
15 | [libsyntax parser](https://github.com/rust-lang/rust/blob/6b99adeb11313197f409b4f7c4083c2ceca8a4fe/src/libsyntax/parse/parser.rs) | 15 | |
16 | for "what to port" and at the | 16 | - Writing validators: by design, rust-analyzer is very lax about the input. For |
17 | [Kotlin parser](https://github.com/JetBrains/kotlin/blob/4d951de616b20feca92f3e9cc9679b2de9e65195/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinParsing.java) | 17 | example, the lexer happily accepts unclosed strings. The idea is that there |
18 | for "how to port". | 18 | should be a higher level visitor, which walks the syntax tree after parsing |
19 | 19 | and produces all the warnings. Alas, there's no such visitor yet :( Would you | |
20 | * Writing validators: by design, rust-analyzer is very lax about the | 20 | like to write one? :) |
21 | input. For example, the lexer happily accepts unclosed strings. The | 21 | |
22 | idea is that there should be a higher level visitor, which walks the | 22 | - Creating tests: it would be tremendously helpful to read each of libsyntax and |
23 | syntax tree after parsing and produces all the warnings. Alas, | 23 | rust-analyzer parser functions and crate a small separate test cases to cover |
24 | there's no such visitor yet :( Would you like to write one? :) | 24 | each and every edge case. |
25 | 25 | ||
26 | * Creating tests: it would be tremendously helpful to read each of | 26 | - Building stuff with rust-analyzer: it would be really cool to compile |
27 | libsyntax and rust-analyzer parser functions and crate a small separate | 27 | rust-analyzer to WASM and add _client side_ syntax validation to rust |
28 | test cases to cover each and every edge case. | ||
29 | |||
30 | * Building stuff with rust-analyzer: it would be really cool to compile | ||
31 | rust-analyzer to WASM and add *client side* syntax validation to rust | ||
32 | playground! | 28 | playground! |
33 | 29 | ||
34 | |||
35 | Do take a look at the issue tracker. | 30 | Do take a look at the issue tracker. |
36 | 31 | ||
37 | If you don't know where to start, or have *any* questions or suggestions, | 32 | If you don't know where to start, or have _any_ questions or suggestions, don't |
38 | don't hesitate to chat at [Gitter](https://gitter.im/libsyntax2/Lobby)! | 33 | hesitate to chat at [Gitter]! |
34 | |||
35 | # Code generation | ||
36 | |||
37 | Some of the components of this repository are generated through automatic | ||
38 | processes. These are outlined below: | ||
39 | |||
40 | - `gen-kinds`: The kinds of tokens are reused in several places, so a generator | ||
41 | is used. This process uses [tera] to generate, using data in [grammar.ron], | ||
42 | the files: | ||
43 | - [ast/generated.rs][ast generated] in `ra_syntax` based on | ||
44 | [ast/generated.tera.rs][ast source] | ||
45 | - [syntax_kinds/generated.rs][syntax_kinds generated] in `ra_syntax` based on | ||
46 | [syntax_kinds/generated.tera.rs][syntax_kinds source] | ||
47 | |||
48 | [libsyntax parser]: | ||
49 | https://github.com/rust-lang/rust/blob/6b99adeb11313197f409b4f7c4083c2ceca8a4fe/src/libsyntax/parse/parser.rs | ||
50 | [kotlin parser]: | ||
51 | https://github.com/JetBrains/kotlin/blob/4d951de616b20feca92f3e9cc9679b2de9e65195/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinParsing.java | ||
52 | [gitter]: https://gitter.im/libsyntax2/Lobby | ||
53 | [tera]: https://tera.netlify.com/ | ||
54 | [grammar.ron]: ./crates/ra_syntax/src/grammar.ron | ||
55 | [ast generated]: ./crates/ra_syntax/src/ast/generated.rs | ||
56 | [ast source]: ./crates/ra_syntax/src/ast/generated.tera.rs | ||
57 | [syntax_kinds generated]: ./crates/ra_syntax/src/syntax_kinds/generated.rs | ||
58 | [syntax_kinds source]: ./crates/ra_syntax/src/syntax_kinds/generated.tera.rs | ||
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index c945c094a..2db6dff1b 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -1,3 +1,6 @@ | |||
1 | // This file is automatically generated based on the file `./generated.rs.tera` when `cargo gen-kinds` is run | ||
2 | // Do not edit manually | ||
3 | |||
1 | use { | 4 | use { |
2 | ast, | 5 | ast, |
3 | SyntaxNodeRef, AstNode, | 6 | SyntaxNodeRef, AstNode, |
diff --git a/crates/ra_syntax/src/ast/generated.rs.tera b/crates/ra_syntax/src/ast/generated.rs.tera index a72e9b732..ceb2cd7e2 100644 --- a/crates/ra_syntax/src/ast/generated.rs.tera +++ b/crates/ra_syntax/src/ast/generated.rs.tera | |||
@@ -1,3 +1,8 @@ | |||
1 | {# THIS File is not automatically generated: | ||
2 | the below applies to the result of this template | ||
3 | #}// This file is automatically generated based on the file `./generated.rs.tera` when `cargo gen-kinds` is run | ||
4 | // Do not edit manually | ||
5 | |||
1 | use { | 6 | use { |
2 | ast, | 7 | ast, |
3 | SyntaxNodeRef, AstNode, | 8 | SyntaxNodeRef, AstNode, |
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 77ae4c7db..4b990fd8d 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -1,3 +1,5 @@ | |||
1 | // Stores definitions which must be used in multiple places | ||
2 | // See `cargo gen-kinds` (defined in crates/tools/src/main.rs) | ||
1 | Grammar( | 3 | Grammar( |
2 | single_byte_tokens: [ | 4 | single_byte_tokens: [ |
3 | [";", "SEMI"], | 5 | [";", "SEMI"], |
@@ -23,8 +25,9 @@ Grammar( | |||
23 | ["^", "CARET"], | 25 | ["^", "CARET"], |
24 | ["%", "PERCENT"], | 26 | ["%", "PERCENT"], |
25 | ], | 27 | ], |
28 | // TODO: Confirm surmision: the tokens which cannot be recorded in a single UTF-8 byte | ||
26 | multi_byte_tokens: [ | 29 | multi_byte_tokens: [ |
27 | [".", "DOT"], | 30 | [".", "DOT"], // Note: DOT is here because <TODO: REASON> |
28 | ["..", "DOTDOT"], | 31 | ["..", "DOTDOT"], |
29 | ["...", "DOTDOTDOT"], | 32 | ["...", "DOTDOTDOT"], |
30 | ["..=", "DOTDOTEQ"], | 33 | ["..=", "DOTDOTEQ"], |
diff --git a/crates/ra_syntax/src/syntax_kinds/generated.rs b/crates/ra_syntax/src/syntax_kinds/generated.rs index 7882bded9..11e9150bb 100644 --- a/crates/ra_syntax/src/syntax_kinds/generated.rs +++ b/crates/ra_syntax/src/syntax_kinds/generated.rs | |||
@@ -1,3 +1,6 @@ | |||
1 | // This file is automatically generated based on the file `./generated.rs.tera` when `cargo gen-kinds` is run | ||
2 | // Do not edit manually | ||
3 | |||
1 | #![allow(bad_style, missing_docs, unreachable_pub)] | 4 | #![allow(bad_style, missing_docs, unreachable_pub)] |
2 | #![cfg_attr(rustfmt, rustfmt_skip)] | 5 | #![cfg_attr(rustfmt, rustfmt_skip)] |
3 | use super::SyntaxInfo; | 6 | use super::SyntaxInfo; |
diff --git a/crates/ra_syntax/src/syntax_kinds/generated.rs.tera b/crates/ra_syntax/src/syntax_kinds/generated.rs.tera index 90618721a..018564b8a 100644 --- a/crates/ra_syntax/src/syntax_kinds/generated.rs.tera +++ b/crates/ra_syntax/src/syntax_kinds/generated.rs.tera | |||
@@ -1,3 +1,8 @@ | |||
1 | {# THIS File is not automatically generated: | ||
2 | the below applies to the result of this template | ||
3 | #}// This file is automatically generated based on the file `./generated.rs.tera` when `cargo gen-kinds` is run | ||
4 | // Do not edit manually | ||
5 | |||
1 | #![allow(bad_style, missing_docs, unreachable_pub)] | 6 | #![allow(bad_style, missing_docs, unreachable_pub)] |
2 | #![cfg_attr(rustfmt, rustfmt_skip)] | 7 | #![cfg_attr(rustfmt, rustfmt_skip)] |
3 | use super::SyntaxInfo; | 8 | use super::SyntaxInfo; |
diff --git a/editors/code/package.json b/editors/code/package.json index 305d6eaf1..9f05fe91a 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -111,7 +111,7 @@ | |||
111 | ], | 111 | ], |
112 | "configuration": { | 112 | "configuration": { |
113 | "type": "object", | 113 | "type": "object", |
114 | "title": "Rust Analyzer configuration", | 114 | "title": "Rust Analyzer", |
115 | "properties": { | 115 | "properties": { |
116 | "ra-lsp.highlightingOn": { | 116 | "ra-lsp.highlightingOn": { |
117 | "type": "boolean", | 117 | "type": "boolean", |
diff --git a/editors/code/src/extension.ts b/editors/code/src/extension.ts index dc1792e94..fde6a480d 100644 --- a/editors/code/src/extension.ts +++ b/editors/code/src/extension.ts | |||
@@ -11,10 +11,22 @@ let uris = { | |||
11 | let highlightingOn = true; | 11 | let highlightingOn = true; |
12 | 12 | ||
13 | export function activate(context: vscode.ExtensionContext) { | 13 | export function activate(context: vscode.ExtensionContext) { |
14 | let config = vscode.workspace.getConfiguration('ra-lsp'); | 14 | let applyHighlightingOn = () => { |
15 | if (config.has('highlightingOn')) { | 15 | let config = vscode.workspace.getConfiguration('ra-lsp'); |
16 | highlightingOn = config.get('highlightingOn') as boolean; | 16 | if (config.has('highlightingOn')) { |
17 | } | 17 | highlightingOn = config.get('highlightingOn') as boolean; |
18 | }; | ||
19 | |||
20 | if (!highlightingOn) { | ||
21 | removeHighlights(); | ||
22 | } | ||
23 | }; | ||
24 | |||
25 | // Apply the highlightingOn config now and whenever the config changes | ||
26 | applyHighlightingOn(); | ||
27 | vscode.workspace.onDidChangeConfiguration(_ => { | ||
28 | applyHighlightingOn(); | ||
29 | }); | ||
18 | 30 | ||
19 | let textDocumentContentProvider = new TextDocumentContentProvider() | 31 | let textDocumentContentProvider = new TextDocumentContentProvider() |
20 | let dispose = (disposable: vscode.Disposable) => { | 32 | let dispose = (disposable: vscode.Disposable) => { |
@@ -130,7 +142,7 @@ export function activate(context: vscode.ExtensionContext) { | |||
130 | }) | 142 | }) |
131 | }, null, context.subscriptions) | 143 | }, null, context.subscriptions) |
132 | vscode.window.onDidChangeActiveTextEditor(async (editor) => { | 144 | vscode.window.onDidChangeActiveTextEditor(async (editor) => { |
133 | if (!editor || editor.document.languageId != 'rust') return | 145 | if (!highlightingOn || !editor || editor.document.languageId != 'rust') return |
134 | let params: lc.TextDocumentIdentifier = { | 146 | let params: lc.TextDocumentIdentifier = { |
135 | uri: editor.document.uri.toString() | 147 | uri: editor.document.uri.toString() |
136 | } | 148 | } |
@@ -179,7 +191,7 @@ function startServer() { | |||
179 | let editor = vscode.window.visibleTextEditors.find( | 191 | let editor = vscode.window.visibleTextEditors.find( |
180 | (editor) => editor.document.uri.toString() == params.uri | 192 | (editor) => editor.document.uri.toString() == params.uri |
181 | ) | 193 | ) |
182 | if (editor == null) return; | 194 | if (!highlightingOn || !editor) return; |
183 | setHighlights( | 195 | setHighlights( |
184 | editor, | 196 | editor, |
185 | params.decorations, | 197 | params.decorations, |
@@ -213,10 +225,11 @@ class TextDocumentContentProvider implements vscode.TextDocumentContentProvider | |||
213 | } | 225 | } |
214 | } | 226 | } |
215 | 227 | ||
228 | let decorations: { [index: string]: vscode.TextEditorDecorationType } = {}; | ||
216 | 229 | ||
217 | const decorations: { [index: string]: vscode.TextEditorDecorationType } = (() => { | 230 | function initDecorations() { |
218 | const decor = (obj: any) => vscode.window.createTextEditorDecorationType({ color: obj }) | 231 | const decor = (obj: any) => vscode.window.createTextEditorDecorationType({ color: obj }) |
219 | return { | 232 | decorations = { |
220 | background: decor("#3F3F3F"), | 233 | background: decor("#3F3F3F"), |
221 | error: vscode.window.createTextEditorDecorationType({ | 234 | error: vscode.window.createTextEditorDecorationType({ |
222 | borderColor: "red", | 235 | borderColor: "red", |
@@ -232,14 +245,26 @@ const decorations: { [index: string]: vscode.TextEditorDecorationType } = (() => | |||
232 | attribute: decor("#BFEBBF"), | 245 | attribute: decor("#BFEBBF"), |
233 | literal: decor("#DFAF8F"), | 246 | literal: decor("#DFAF8F"), |
234 | } | 247 | } |
235 | })() | 248 | } |
249 | |||
250 | function removeHighlights() { | ||
251 | for (let tag in decorations) { | ||
252 | decorations[tag].dispose(); | ||
253 | } | ||
254 | |||
255 | decorations = {}; | ||
256 | } | ||
236 | 257 | ||
237 | function setHighlights( | 258 | function setHighlights( |
238 | editor: vscode.TextEditor, | 259 | editor: vscode.TextEditor, |
239 | highlights: Array<Decoration> | 260 | highlights: Array<Decoration> |
240 | ) { | 261 | ) { |
241 | if (!highlightingOn) { | 262 | // Initialize decorations if necessary |
242 | return; | 263 | // |
264 | // Note: decoration objects need to be kept around so we can dispose them | ||
265 | // if the user disables syntax highlighting | ||
266 | if (Object.keys(decorations).length === 0) { | ||
267 | initDecorations(); | ||
243 | } | 268 | } |
244 | 269 | ||
245 | let byTag: Map<string, vscode.Range[]> = new Map() | 270 | let byTag: Map<string, vscode.Range[]> = new Map() |