Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/ide/src/lib.rs11
-rw-r--r--crates/ide/src/syntax_tree.rs338
-rw-r--r--crates/rust-analyzer/src/handlers/request.rs12
-rw-r--r--crates/rust-analyzer/src/lsp/ext.rs15
-rw-r--r--crates/rust-analyzer/src/main_loop.rs1
-rw-r--r--docs/dev/lsp-extensions.md2
-rw-r--r--editors/code/package.json20
-rw-r--r--editors/code/src/ast_inspector.ts216
-rw-r--r--editors/code/src/commands.ts85
-rw-r--r--editors/code/src/main.ts1
10 files changed, 1 insertions, 700 deletions
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 5cb77e6201..af9a7ce788 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -48,7 +48,6 @@ mod ssr;
mod static_index;
mod status;
mod syntax_highlighting;
-mod syntax_tree;
mod test_explorer;
mod typing;
mod view_crate_graph;
@@ -330,16 +329,6 @@ impl Analysis {
})
}
- /// Returns a syntax tree represented as `String`, for debug purposes.
- // FIXME: use a better name here.
- pub fn syntax_tree(
- &self,
- file_id: FileId,
- text_range: Option<TextRange>,
- ) -> Cancellable<String> {
- self.with_db(|db| syntax_tree::syntax_tree(db, file_id, text_range))
- }
-
pub fn view_syntax_tree(&self, file_id: FileId) -> Cancellable<String> {
self.with_db(|db| view_syntax_tree::view_syntax_tree(db, file_id))
}
diff --git a/crates/ide/src/syntax_tree.rs b/crates/ide/src/syntax_tree.rs
deleted file mode 100644
index 86c6676f92..0000000000
--- a/crates/ide/src/syntax_tree.rs
+++ /dev/null
@@ -1,338 +0,0 @@
-use hir::Semantics;
-use ide_db::{FileId, RootDatabase};
-use syntax::{
- AstNode, NodeOrToken, SourceFile, SyntaxKind::STRING, SyntaxToken, TextRange, TextSize,
-};
-
-// Feature: Show Debug Syntax Tree
-//
-// Shows the textual parse tree of the current file. It exists mostly for debugging
-// rust-analyzer itself.
-//
-// |===
-// | Editor | Action Name
-//
-// | VS Code | **rust-analyzer: Show Syntax Tree**
-// |===
-// image::https://user-images.githubusercontent.com/48062697/113065586-068bdb80-91b1-11eb-9507-fee67f9f45a0.gif[]
-pub(crate) fn syntax_tree(
- db: &RootDatabase,
- file_id: FileId,
- text_range: Option<TextRange>,
-) -> String {
- let sema = Semantics::new(db);
- let parse = sema.parse_guess_edition(file_id);
- if let Some(text_range) = text_range {
- let node = match parse.syntax().covering_element(text_range) {
- NodeOrToken::Node(node) => node,
- NodeOrToken::Token(token) => {
- if let Some(tree) = syntax_tree_for_string(&token, text_range) {
- return tree;
- }
- token.parent().unwrap()
- }
- };
-
- format!("{node:#?}")
- } else {
- format!("{:#?}", parse.syntax())
- }
-}
-
-/// Attempts parsing the selected contents of a string literal
-/// as rust syntax and returns its syntax tree
-fn syntax_tree_for_string(token: &SyntaxToken, text_range: TextRange) -> Option<String> {
- // When the range is inside a string
- // we'll attempt parsing it as rust syntax
- // to provide the syntax tree of the contents of the string
- match token.kind() {
- STRING => syntax_tree_for_token(token, text_range),
- _ => None,
- }
-}
-
-fn syntax_tree_for_token(node: &SyntaxToken, text_range: TextRange) -> Option<String> {
- // Range of the full node
- let node_range = node.text_range();
- let text = node.text().to_owned();
-
- // We start at some point inside the node
- // Either we have selected the whole string
- // or our selection is inside it
- let start = text_range.start() - node_range.start();
-
- // how many characters we have selected
- let len = text_range.len();
-
- let node_len = node_range.len();
-
- // We want to cap our length
- let len = len.min(node_len);
-
- // Ensure our slice is inside the actual string
- let end =
- if start + len < TextSize::of(&text) { start + len } else { TextSize::of(&text) - start };
-
- let text = &text[TextRange::new(start, end)];
-
- // Remove possible extra string quotes from the start
- // and the end of the string
- let text = text
- .trim_start_matches('r')
- .trim_start_matches('#')
- .trim_start_matches('"')
- .trim_end_matches('#')
- .trim_end_matches('"')
- .trim()
- // Remove custom markers
- .replace("$0", "");
-
- let parsed = SourceFile::parse(&text, span::Edition::CURRENT_FIXME);
-
- // If the "file" parsed without errors,
- // return its syntax
- if parsed.errors().is_empty() {
- return Some(format!("{:#?}", parsed.tree().syntax()));
- }
-
- None
-}
-
-#[cfg(test)]
-mod tests {
- use expect_test::expect;
-
- use crate::fixture;
-
- fn check(ra_fixture: &str, expect: expect_test::Expect) {
- let (analysis, file_id) = fixture::file(ra_fixture);
- let syn = analysis.syntax_tree(file_id, None).unwrap();
- expect.assert_eq(&syn)
- }
- fn check_range(ra_fixture: &str, expect: expect_test::Expect) {
- let (analysis, frange) = fixture::range(ra_fixture);
- let syn = analysis.syntax_tree(frange.file_id, Some(frange.range)).unwrap();
- expect.assert_eq(&syn)
- }
-
- #[test]
- fn test_syntax_tree_without_range() {
- // Basic syntax
- check(
- r#"fn foo() {}"#,
- expect![[r#"
- "#]],
- );
-
- check(
- r#"
-fn test() {
- assert!("
- fn foo() {
- }
- ", "");
-}"#,
- expect![[r#"
- [email protected] "\"\n fn foo() {\n ..."
- "#]],
- )
- }
-
- #[test]
- fn test_syntax_tree_with_range() {
- check_range(
- r#"$0fn foo() {}$0"#,
- expect![[r#"
- "#]],
- );
-
- check_range(
- r#"
-fn test() {
- $0assert!("
- fn foo() {
- }
- ", "");$0
-}"#,
- expect![[r#"
- [email protected] "\"\n fn foo() {\n ..."
- "#]],
- );
- }
-
- #[test]
- fn test_syntax_tree_inside_string() {
- check_range(
- r#"fn test() {
- assert!("
-$0fn foo() {
-}$0
-fn bar() {
-}
- ", "");
-}"#,
- expect![[r#"
- "#]],
- );
-
- // With a raw string
- check_range(
- r###"fn test() {
- assert!(r#"
-$0fn foo() {
-}$0
-fn bar() {
-}
- "#, "");
-}"###,
- expect![[r#"
- "#]],
- );
-
- // With a raw string
- check_range(
- r###"fn test() {
- assert!(r$0#"
-fn foo() {
-}
-fn bar() {
-}"$0#, "");
-}"###,
- expect![[r#"
- "#]],
- );
- }
-}
diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs
index 4644ebd44d..d01dc5fba1 100644
--- a/crates/rust-analyzer/src/handlers/request.rs
+++ b/crates/rust-analyzer/src/handlers/request.rs
@@ -136,18 +136,6 @@ pub(crate) fn handle_memory_usage(state: &mut GlobalState, _: ()) -> anyhow::Res
Ok(out)
}
-pub(crate) fn handle_syntax_tree(
- snap: GlobalStateSnapshot,
- params: lsp_ext::SyntaxTreeParams,
-) -> anyhow::Result<String> {
- let _p = tracing::info_span!("handle_syntax_tree").entered();
- let id = from_proto::file_id(&snap, &params.text_document.uri)?;
- let line_index = snap.file_line_index(id)?;
- let text_range = params.range.and_then(|r| from_proto::text_range(&line_index, r).ok());
- let res = snap.analysis.syntax_tree(id, text_range)?;
- Ok(res)
-}
-
pub(crate) fn handle_view_syntax_tree(
snap: GlobalStateSnapshot,
params: lsp_ext::ViewSyntaxTreeParams,
diff --git a/crates/rust-analyzer/src/lsp/ext.rs b/crates/rust-analyzer/src/lsp/ext.rs
index 48c2ff0a15..134de92fea 100644
--- a/crates/rust-analyzer/src/lsp/ext.rs
+++ b/crates/rust-analyzer/src/lsp/ext.rs
@@ -108,21 +108,6 @@ impl Request for RebuildProcMacros {
const METHOD: &'static str = "rust-analyzer/rebuildProcMacros";
}
-pub enum SyntaxTree {}
-
-impl Request for SyntaxTree {
- type Params = SyntaxTreeParams;
- type Result = String;
- const METHOD: &'static str = "rust-analyzer/syntaxTree";
-}
-
-#[derive(Deserialize, Serialize, Debug)]
-#[serde(rename_all = "camelCase")]
-pub struct SyntaxTreeParams {
- pub text_document: TextDocumentIdentifier,
- pub range: Option<Range>,
-}
-
pub enum ViewSyntaxTree {}
impl Request for ViewSyntaxTree {
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 325b0afc71..d6dc8b521f 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -1145,7 +1145,6 @@ impl GlobalState {
.on::<RETRY, lsp_ext::WorkspaceSymbol>(handlers::handle_workspace_symbol)
.on::<NO_RETRY, lsp_ext::Ssr>(handlers::handle_ssr)
.on::<NO_RETRY, lsp_ext::ViewRecursiveMemoryLayout>(handlers::handle_view_recursive_memory_layout)
- .on::<NO_RETRY, lsp_ext::SyntaxTree>(handlers::handle_syntax_tree)
.on::<NO_RETRY, lsp_ext::ViewSyntaxTree>(handlers::handle_view_syntax_tree)
.on::<NO_RETRY, lsp_ext::ViewHir>(handlers::handle_view_hir)
.on::<NO_RETRY, lsp_ext::ViewMir>(handlers::handle_view_mir)
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index 8cd0422773..a632fc6f5f 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@
<!---
-lsp/ext.rs hash: a85494375e528064
+lsp/ext.rs hash: 2d8604825c458288
If you need to change the above hash to make the test pass, please check if you
need to adjust this doc as well and ping this issue:
diff --git a/editors/code/package.json b/editors/code/package.json
index bbfe9c2a5c..6deb5bfd77 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -109,11 +109,6 @@
],
"commands": [
{
- "command": "rust-analyzer.syntaxTree",
- "title": "Show Syntax Tree",
- "category": "rust-analyzer (debug command)"
- },
- {
"command": "rust-analyzer.viewHir",
"title": "View Hir",
"category": "rust-analyzer (debug command)"
@@ -2969,17 +2964,6 @@
"pattern": "$rustc"
}
],
- "colors": [
- {
- "id": "rust_analyzer.syntaxTreeBorder",
- "description": "Color of the border displayed in the Rust source code for the selected syntax node (see \"Show Syntax Tree\" command)",
- "defaults": {
- "dark": "#ffffff",
- "light": "#b700ff",
- "highContrast": "#b700ff"
- }
- }
- ],
"semanticTokenTypes": [
{
"id": "angle",
@@ -3300,10 +3284,6 @@
"menus": {
"commandPalette": [
{
- "command": "rust-analyzer.syntaxTree",
- "when": "inRustProject"
- },
- {
"command": "rust-analyzer.viewHir",
"when": "inRustProject"
},
diff --git a/editors/code/src/ast_inspector.ts b/editors/code/src/ast_inspector.ts
deleted file mode 100644
index 35b705c477..0000000000
--- a/editors/code/src/ast_inspector.ts
+++ /dev/null
@@ -1,216 +0,0 @@
-import * as vscode from "vscode";
-
-import type { Ctx, Disposable } from "./ctx";
-import { type RustEditor, isRustEditor, unwrapUndefinable } from "./util";
-
-// FIXME: consider implementing this via the Tree View API?
-// https://code.visualstudio.com/api/extension-guides/tree-view
-export class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, Disposable {
- private readonly astDecorationType = vscode.window.createTextEditorDecorationType({
- borderColor: new vscode.ThemeColor("rust_analyzer.syntaxTreeBorder"),
- borderStyle: "solid",
- borderWidth: "2px",
- });
- private rustEditor: undefined | RustEditor;
-
- // Lazy rust token range -> syntax tree file range.
- private readonly rust2Ast = new Lazy(() => {
- const astEditor = this.findAstTextEditor();
- if (!this.rustEditor || !astEditor) return undefined;
-
- const buf: [vscode.Range, vscode.Range][] = [];
- for (let i = 0; i < astEditor.document.lineCount; ++i) {
- const astLine = astEditor.document.lineAt(i);
-
- // Heuristically look for nodes with quoted text (which are token nodes)
- const isTokenNode = astLine.text.lastIndexOf('"') >= 0;
- if (!isTokenNode) continue;
-
- const rustRange = this.parseRustTextRange(this.rustEditor.document, astLine.text);
- if (!rustRange) continue;
-
- buf.push([rustRange, this.findAstNodeRange(astLine)]);
- }
- return buf;
- });
-
- constructor(ctx: Ctx) {
- ctx.pushExtCleanup(
- vscode.languages.registerHoverProvider({ scheme: "rust-analyzer" }, this),
- );
- ctx.pushExtCleanup(vscode.languages.registerDefinitionProvider({ language: "rust" }, this));
- vscode.workspace.onDidCloseTextDocument(
- this.onDidCloseTextDocument,
- this,
- ctx.subscriptions,
- );
- vscode.workspace.onDidChangeTextDocument(
- this.onDidChangeTextDocument,
- this,
- ctx.subscriptions,
- );
- vscode.window.onDidChangeVisibleTextEditors(
- this.onDidChangeVisibleTextEditors,
- this,
- ctx.subscriptions,
- );
- }
- dispose() {
- this.setRustEditor(undefined);
- }
-
- private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
- if (
- this.rustEditor &&
- event.document.uri.toString() === this.rustEditor.document.uri.toString()
- ) {
- this.rust2Ast.reset();
- }
- }
-
- private onDidCloseTextDocument(doc: vscode.TextDocument) {
- if (this.rustEditor && doc.uri.toString() === this.rustEditor.document.uri.toString()) {
- this.setRustEditor(undefined);
- }
- }
-
- private onDidChangeVisibleTextEditors(editors: readonly vscode.TextEditor[]) {
- if (!this.findAstTextEditor()) {
- this.setRustEditor(undefined);
- return;
- }
- this.setRustEditor(editors.find(isRustEditor));
- }
-
- private findAstTextEditor(): undefined | vscode.TextEditor {
- return vscode.window.visibleTextEditors.find(
- (it) => it.document.uri.scheme === "rust-analyzer",
- );
- }
-
- private setRustEditor(newRustEditor: undefined | RustEditor) {
- if (this.rustEditor && this.rustEditor !== newRustEditor) {
- this.rustEditor.setDecorations(this.astDecorationType, []);
- this.rust2Ast.reset();
- }
- this.rustEditor = newRustEditor;
- }
-
- // additional positional params are omitted
- provideDefinition(
- doc: vscode.TextDocument,
- pos: vscode.Position,
- ): vscode.ProviderResult<vscode.DefinitionLink[]> {
- if (!this.rustEditor || doc.uri.toString() !== this.rustEditor.document.uri.toString()) {
- return;
- }
-
- const astEditor = this.findAstTextEditor();
- if (!astEditor) return;
-
- const rust2AstRanges = this.rust2Ast
- .get()
- ?.find(([rustRange, _]) => rustRange.contains(pos));
- if (!rust2AstRanges) return;
-
- const [rustFileRange, astFileRange] = rust2AstRanges;
-
- astEditor.revealRange(astFileRange);
- astEditor.selection = new vscode.Selection(astFileRange.start, astFileRange.end);
-
- return [
- {
- targetRange: astFileRange,
- targetUri: astEditor.document.uri,
- originSelectionRange: rustFileRange,
- targetSelectionRange: astFileRange,
- },
- ];
- }
-
- // additional positional params are omitted
- provideHover(
- doc: vscode.TextDocument,
- hoverPosition: vscode.Position,
- ): vscode.ProviderResult<vscode.Hover> {
- if (!this.rustEditor) return;
-
- const astFileLine = doc.lineAt(hoverPosition.line);
-
- const rustFileRange = this.parseRustTextRange(this.rustEditor.document, astFileLine.text);
- if (!rustFileRange) return;
-
- this.rustEditor.setDecorations(this.astDecorationType, [rustFileRange]);
- this.rustEditor.revealRange(rustFileRange);
-
- const rustSourceCode = this.rustEditor.document.getText(rustFileRange);
- const astFileRange = this.findAstNodeRange(astFileLine);
-
- return new vscode.Hover(["```rust\n" + rustSourceCode + "\n```"], astFileRange);
- }
-
- private findAstNodeRange(astLine: vscode.TextLine): vscode.Range {
- const lineOffset = astLine.range.start;
- const begin = lineOffset.translate(undefined, astLine.firstNonWhitespaceCharacterIndex);
- const end = lineOffset.translate(undefined, astLine.text.trimEnd().length);
- return new vscode.Range(begin, end);
- }
-
- private parseRustTextRange(
- doc: vscode.TextDocument,
- astLine: string,
- ): undefined | vscode.Range {
- const parsedRange = /(\d+)\.\.(\d+)/.exec(astLine);
- if (!parsedRange) return;
-
- const [begin, end] = parsedRange.slice(1).map((off) => this.positionAt(doc, +off));
- const actualBegin = unwrapUndefinable(begin);
- const actualEnd = unwrapUndefinable(end);
- return new vscode.Range(actualBegin, actualEnd);
- }
-
- // Memoize the last value, otherwise the CPU is at 100% single core
- // with quadratic lookups when we build rust2Ast cache
- cache?: { doc: vscode.TextDocument; offset: number; line: number };
-
- positionAt(doc: vscode.TextDocument, targetOffset: number): vscode.Position {
- if (doc.eol === vscode.EndOfLine.LF) {
- return doc.positionAt(targetOffset);
- }
-
- // Dirty workaround for crlf line endings
- // We are still in this prehistoric era of carriage returns here...
-
- let line = 0;
- let offset = 0;
-
- const cache = this.cache;
- if (cache?.doc === doc && cache.offset <= targetOffset) {
- ({ line, offset } = cache);
- }
-
- while (true) {
- const lineLenWithLf = doc.lineAt(line).text.length + 1;
- if (offset + lineLenWithLf > targetOffset) {
- this.cache = { doc, offset, line };
- return doc.positionAt(targetOffset + line);
- }
- offset += lineLenWithLf;
- line += 1;
- }
- }
-}
-
-class Lazy<T> {
- val: undefined | T;
-
- constructor(private readonly compute: () => undefined | T) {}
-
- get() {
- return this.val ?? (this.val = this.compute());
- }
-
- reset() {
- this.val = undefined;
- }
-}
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index a78696e186..f94c57eee8 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -15,7 +15,6 @@ import {
createTaskFromRunnable,
createCargoArgs,
} from "./run";
-import { AstInspector } from "./ast_inspector";
import {
isRustDocument,
isCargoRunnableArgs,
@@ -33,7 +32,6 @@ import type { DependencyId } from "./dependencies_provider";
import { log } from "./util";
import type { SyntaxElement } from "./syntax_tree_provider";
-export * from "./ast_inspector";
export * from "./run";
export function analyzerStatus(ctx: CtxInit): Cmd {
@@ -459,89 +457,6 @@ export function serverVersion(ctx: CtxInit): Cmd {
};
}
-// Opens the virtual file that will show the syntax tree
-//
-// The contents of the file come from the `TextDocumentContentProvider`
-export function syntaxTree(ctx: CtxInit): Cmd {
- const tdcp = new (class implements vscode.TextDocumentContentProvider {
- readonly uri = vscode.Uri.parse("rust-analyzer-syntax-tree://syntaxtree/tree.rast");
- readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
- constructor() {
- vscode.workspace.onDidChangeTextDocument(
- this.onDidChangeTextDocument,
- this,
- ctx.subscriptions,
- );
- vscode.window.onDidChangeActiveTextEditor(
- this.onDidChangeActiveTextEditor,
- this,
- ctx.subscriptions,
- );
- }
-
- private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
- if (isRustDocument(event.document)) {
- // We need to order this after language server updates, but there's no API for that.
- // Hence, good old sleep().
- void sleep(10).then(() => this.eventEmitter.fire(this.uri));
- }
- }
- private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {
- if (editor && isRustEditor(editor)) {
- this.eventEmitter.fire(this.uri);
- }
- }
-
- async provideTextDocumentContent(
- uri: vscode.Uri,
- ct: vscode.CancellationToken,
- ): Promise<string> {
- const rustEditor = ctx.activeRustEditor;
- if (!rustEditor) return "";
- const client = ctx.client;
-
- // When the range based query is enabled we take the range of the selection
- const range =
- uri.query === "range=true" && !rustEditor.selection.isEmpty
- ? client.code2ProtocolConverter.asRange(rustEditor.selection)
- : null;
-
- const params = { textDocument: { uri: rustEditor.document.uri.toString() }, range };
- return client.sendRequest(ra.syntaxTree, params, ct);
- }
-
- get onDidChange(): vscode.Event<vscode.Uri> {
- return this.eventEmitter.event;
- }
- })();
-
- ctx.pushExtCleanup(new AstInspector(ctx));
- ctx.pushExtCleanup(
- vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-syntax-tree", tdcp),
- );
- ctx.pushExtCleanup(
- vscode.languages.setLanguageConfiguration("ra_syntax_tree", {
- brackets: [["[", ")"]],
- }),
- );
-
- return async () => {
- const editor = vscode.window.activeTextEditor;
- const rangeEnabled = !!editor && !editor.selection.isEmpty;
-
- const uri = rangeEnabled ? vscode.Uri.parse(`${tdcp.uri.toString()}?range=true`) : tdcp.uri;
-
- const document = await vscode.workspace.openTextDocument(uri);
-
- tdcp.eventEmitter.fire(uri);
-
- void (await vscode.window.showTextDocument(document, {
- viewColumn: vscode.ViewColumn.Two,
- preserveFocus: true,
- }));
- };
-}
-
function viewHirOrMir(ctx: CtxInit, xir: "hir" | "mir"): Cmd {
const viewXir = xir === "hir" ? "viewHir" : "viewMir";
const requestType = xir === "hir" ? ra.viewHir : ra.viewMir;
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 989f66050c..59c131cb37 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -158,7 +158,6 @@ function createCommands(): Record<string, CommandFactory> {
matchingBrace: { enabled: commands.matchingBrace },
joinLines: { enabled: commands.joinLines },
parentModule: { enabled: commands.parentModule },
- syntaxTree: { enabled: commands.syntaxTree },
viewHir: { enabled: commands.viewHir },
viewMir: { enabled: commands.viewMir },
interpretFunction: { enabled: commands.interpretFunction },