From f551e50c16d189a724885ce5f208595a31af49cc Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 24 Feb 2020 17:17:05 +0100 Subject: [PATCH 01/28] When joining lines, unwrap trivial diverging blocks --- crates/ra_fmt/src/lib.rs | 36 +++++++++++++++++++++++++-------- crates/ra_ide/src/join_lines.rs | 25 +++++++++++++++++++++++ 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/crates/ra_fmt/src/lib.rs b/crates/ra_fmt/src/lib.rs index 4bca27b5c7..db27f9b839 100644 --- a/crates/ra_fmt/src/lib.rs +++ b/crates/ra_fmt/src/lib.rs @@ -43,15 +43,35 @@ pub fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr { pub fn extract_trivial_expression(block: &ast::BlockExpr) -> Option { let block = block.block()?; - let expr = block.expr()?; - let non_trivial_children = block.syntax().children().filter(|it| match it.kind() { - WHITESPACE | T!['{'] | T!['}'] => false, - _ => it != expr.syntax(), - }); - if non_trivial_children.count() > 0 { - return None; + let has_anything_else = |thing: &SyntaxNode| -> bool { + let mut non_trivial_children = + block.syntax().children_with_tokens().filter(|it| match it.kind() { + WHITESPACE | T!['{'] | T!['}'] => false, + _ => it.as_node() != Some(thing), + }); + non_trivial_children.next().is_some() + }; + + if let Some(expr) = block.expr() { + if has_anything_else(expr.syntax()) { + return None; + } + return Some(expr); + } else { + // Unwrap `{ continue; }` + let (stmt,) = block.statements().next_tuple()?; + if has_anything_else(stmt.syntax()) { + return None; + } + if let ast::Stmt::ExprStmt(expr_stmt) = stmt { + let expr = expr_stmt.expr()?; + match expr.syntax().kind() { + CONTINUE_EXPR | BREAK_EXPR | RETURN_EXPR => return Some(expr), + _ => (), + } + } } - Some(expr) + None } pub fn compute_ws(left: SyntaxKind, right: SyntaxKind) -> &'static str { diff --git a/crates/ra_ide/src/join_lines.rs b/crates/ra_ide/src/join_lines.rs index 01fb32b3df..7d70dab9c6 100644 --- a/crates/ra_ide/src/join_lines.rs +++ b/crates/ra_ide/src/join_lines.rs @@ -227,6 +227,31 @@ fn foo() { ); } + #[test] + fn test_join_lines_diverging_block() { + let before = r" + fn foo() { + loop { + match x { + 92 => <|>{ + continue; + } + } + } + } + "; + let after = r" + fn foo() { + loop { + match x { + 92 => <|>continue, + } + } + } + "; + check_join_lines(before, after); + } + #[test] fn join_lines_adds_comma_for_block_in_match_arm() { check_join_lines( From b4db089a6b79ae60dec9fcd0ba2d788a494c8d8f Mon Sep 17 00:00:00 2001 From: Veetaha Date: Mon, 24 Feb 2020 21:13:10 +0200 Subject: [PATCH 02/28] add error handling to fetchArtifactReleaseInfo(), throw Error when no artifact found --- .../fetch_artifact_release_info.ts | 56 ++++++++++++------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/editors/code/src/installation/fetch_artifact_release_info.ts b/editors/code/src/installation/fetch_artifact_release_info.ts index 1b6fc8d48c..5e201afb0a 100644 --- a/editors/code/src/installation/fetch_artifact_release_info.ts +++ b/editors/code/src/installation/fetch_artifact_release_info.ts @@ -4,41 +4,59 @@ import { log } from "../util"; const GITHUB_API_ENDPOINT_URL = "https://api.github.com"; - /** - * Fetches the release with `releaseTag` (or just latest release when not specified) - * from GitHub `repo` and returns metadata about `artifactFileName` shipped with - * this release or `null` if no such artifact was published. + * Fetches the release with `releaseTag` from GitHub `repo` and + * returns metadata about `artifactFileName` shipped with + * this release. + * + * @throws Error upon network failure or if no such repository, release, or artifact exists. */ export async function fetchArtifactReleaseInfo( - repo: GithubRepo, artifactFileName: string, releaseTag?: string -): Promise { + repo: GithubRepo, + artifactFileName: string, + releaseTag: string +): Promise { const repoOwner = encodeURIComponent(repo.owner); const repoName = encodeURIComponent(repo.name); - const apiEndpointPath = releaseTag - ? `/repos/${repoOwner}/${repoName}/releases/tags/${releaseTag}` - : `/repos/${repoOwner}/${repoName}/releases/latest`; + const apiEndpointPath = `/repos/${repoOwner}/${repoName}/releases/tags/${releaseTag}`; const requestUrl = GITHUB_API_ENDPOINT_URL + apiEndpointPath; - // We skip runtime type checks for simplicity (here we cast from `any` to `GithubRelease`) - log.debug("Issuing request for released artifacts metadata to", requestUrl); - // FIXME: handle non-ok response - const response: GithubRelease = await fetch(requestUrl, { - headers: { Accept: "application/vnd.github.v3+json" } - }) - .then(res => res.json()); + const response = await fetch(requestUrl, { headers: { Accept: "application/vnd.github.v3+json" } }); - const artifact = response.assets.find(artifact => artifact.name === artifactFileName); + if (!response.ok) { + log.error("Error fetching artifact release info", { + requestUrl, + releaseTag, + artifactFileName, + response: { + headers: response.headers, + status: response.status, + body: await response.text(), + } + }); - if (!artifact) return null; + throw new Error( + `Got response ${response.status} when trying to fetch ` + + `"${artifactFileName}" artifact release info for ${releaseTag} release` + ); + } + + // We skip runtime type checks for simplicity (here we cast from `any` to `GithubRelease`) + const release: GithubRelease = await response.json(); + + const artifact = release.assets.find(artifact => artifact.name === artifactFileName); + + if (!artifact) throw new Error( + `Artifact ${artifactFileName} was not found in ${release.name} release!` + ); return { - releaseName: response.name, + releaseName: release.name, downloadUrl: artifact.browser_download_url }; From af57251c311220c2f93a75a6105e6472ffc8ebaa Mon Sep 17 00:00:00 2001 From: Veetaha Date: Mon, 24 Feb 2020 21:23:48 +0200 Subject: [PATCH 03/28] vscode: remove type assertion --- editors/code/.eslintrc.js | 3 ++- editors/code/src/installation/server.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/editors/code/.eslintrc.js b/editors/code/.eslintrc.js index 16f18ab2c2..c6bf410f4b 100644 --- a/editors/code/.eslintrc.js +++ b/editors/code/.eslintrc.js @@ -32,6 +32,7 @@ module.exports = { "@typescript-eslint/semi": [ "error", "always" - ] + ], + "@typescript-eslint/no-unnecessary-type-assertion": "error" } }; diff --git a/editors/code/src/installation/server.ts b/editors/code/src/installation/server.ts index 9de257dd51..cb5e568448 100644 --- a/editors/code/src/installation/server.ts +++ b/editors/code/src/installation/server.ts @@ -63,7 +63,7 @@ export async function ensureServerBinary(source: null | BinarySource): Promise { try { - const releaseInfo = (await fetchArtifactReleaseInfo(source.repo, source.file, source.version))!; + const releaseInfo = await fetchArtifactReleaseInfo(source.repo, source.file, source.version); await downloadArtifact(releaseInfo, source.file, source.dir, "language server"); await setServerVersion(source.storage, releaseInfo.releaseName); From 6d15f89a4b1535ef489fa559f22d0275989f7357 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Mon, 24 Feb 2020 21:37:53 +0200 Subject: [PATCH 04/28] vscode: bump TypeScript version --- editors/code/package-lock.json | 6 +++--- editors/code/package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json index 76ef2aae43..0288a468e0 100644 --- a/editors/code/package-lock.json +++ b/editors/code/package-lock.json @@ -1575,9 +1575,9 @@ } }, "typescript": { - "version": "3.7.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.5.tgz", - "integrity": "sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==", + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.2.tgz", + "integrity": "sha512-EgOVgL/4xfVrCMbhYKUQTdF37SQn4Iw73H5BgCrF1Abdun7Kwy/QZsE/ssAy0y4LxBbvua3PIbFsbRczWWnDdQ==", "dev": true }, "typescript-formatter": { diff --git a/editors/code/package.json b/editors/code/package.json index 9ef6c69831..dff535fcd1 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -42,7 +42,7 @@ "eslint": "^6.8.0", "rollup": "^1.31.1", "tslib": "^1.10.0", - "typescript": "^3.7.5", + "typescript": "^3.8.2", "typescript-formatter": "^7.2.2", "vsce": "^1.73.0" }, From ed69482d90804c37d8ee60c63f0f51f20a6638f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 24 Feb 2020 22:36:57 +0200 Subject: [PATCH 05/28] Bump chalk and replace TypeFamily with Interner --- Cargo.lock | 12 +-- crates/ra_hir_ty/Cargo.toml | 6 +- crates/ra_hir_ty/src/traits.rs | 14 ++-- crates/ra_hir_ty/src/traits/chalk.rs | 107 +++++++++++++++------------ 4 files changed, 74 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 10564d4512..04023c6cd1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -129,7 +129,7 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "chalk-derive" version = "0.1.0" -source = "git+https://github.com/rust-lang/chalk.git?rev=af48f302a1f571b3ca418f7c5aa639a144a34f75#af48f302a1f571b3ca418f7c5aa639a144a34f75" +source = "git+https://github.com/rust-lang/chalk.git?rev=2939913fb7bb94ac2a6721087dc086be11410702#2939913fb7bb94ac2a6721087dc086be11410702" dependencies = [ "proc-macro2", "quote", @@ -139,7 +139,7 @@ dependencies = [ [[package]] name = "chalk-engine" version = "0.9.0" -source = "git+https://github.com/rust-lang/chalk.git?rev=af48f302a1f571b3ca418f7c5aa639a144a34f75#af48f302a1f571b3ca418f7c5aa639a144a34f75" +source = "git+https://github.com/rust-lang/chalk.git?rev=2939913fb7bb94ac2a6721087dc086be11410702#2939913fb7bb94ac2a6721087dc086be11410702" dependencies = [ "chalk-macros", "rustc-hash", @@ -148,7 +148,7 @@ dependencies = [ [[package]] name = "chalk-ir" version = "0.1.0" -source = "git+https://github.com/rust-lang/chalk.git?rev=af48f302a1f571b3ca418f7c5aa639a144a34f75#af48f302a1f571b3ca418f7c5aa639a144a34f75" +source = "git+https://github.com/rust-lang/chalk.git?rev=2939913fb7bb94ac2a6721087dc086be11410702#2939913fb7bb94ac2a6721087dc086be11410702" dependencies = [ "chalk-derive", "chalk-engine", @@ -159,7 +159,7 @@ dependencies = [ [[package]] name = "chalk-macros" version = "0.1.1" -source = "git+https://github.com/rust-lang/chalk.git?rev=af48f302a1f571b3ca418f7c5aa639a144a34f75#af48f302a1f571b3ca418f7c5aa639a144a34f75" +source = "git+https://github.com/rust-lang/chalk.git?rev=2939913fb7bb94ac2a6721087dc086be11410702#2939913fb7bb94ac2a6721087dc086be11410702" dependencies = [ "lazy_static", ] @@ -167,7 +167,7 @@ dependencies = [ [[package]] name = "chalk-rust-ir" version = "0.1.0" -source = "git+https://github.com/rust-lang/chalk.git?rev=af48f302a1f571b3ca418f7c5aa639a144a34f75#af48f302a1f571b3ca418f7c5aa639a144a34f75" +source = "git+https://github.com/rust-lang/chalk.git?rev=2939913fb7bb94ac2a6721087dc086be11410702#2939913fb7bb94ac2a6721087dc086be11410702" dependencies = [ "chalk-derive", "chalk-engine", @@ -178,7 +178,7 @@ dependencies = [ [[package]] name = "chalk-solve" version = "0.1.0" -source = "git+https://github.com/rust-lang/chalk.git?rev=af48f302a1f571b3ca418f7c5aa639a144a34f75#af48f302a1f571b3ca418f7c5aa639a144a34f75" +source = "git+https://github.com/rust-lang/chalk.git?rev=2939913fb7bb94ac2a6721087dc086be11410702#2939913fb7bb94ac2a6721087dc086be11410702" dependencies = [ "chalk-derive", "chalk-engine", diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml index 49cafc5395..99e2fe1bf1 100644 --- a/crates/ra_hir_ty/Cargo.toml +++ b/crates/ra_hir_ty/Cargo.toml @@ -21,9 +21,9 @@ ra_prof = { path = "../ra_prof" } ra_syntax = { path = "../ra_syntax" } test_utils = { path = "../test_utils" } -chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "af48f302a1f571b3ca418f7c5aa639a144a34f75" } -chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "af48f302a1f571b3ca418f7c5aa639a144a34f75" } -chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "af48f302a1f571b3ca418f7c5aa639a144a34f75" } +chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "2939913fb7bb94ac2a6721087dc086be11410702" } +chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "2939913fb7bb94ac2a6721087dc086be11410702" } +chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "2939913fb7bb94ac2a6721087dc086be11410702" } lalrpop-intern = "0.15.1" diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs index 2317fcac36..17aef94903 100644 --- a/crates/ra_hir_ty/src/traits.rs +++ b/crates/ra_hir_ty/src/traits.rs @@ -14,7 +14,7 @@ use crate::db::HirDatabase; use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; -use self::chalk::{from_chalk, ToChalk, TypeFamily}; +use self::chalk::{from_chalk, Interner, ToChalk}; pub(crate) mod chalk; mod builtin; @@ -22,7 +22,7 @@ mod builtin; #[derive(Debug, Clone)] pub struct TraitSolver { krate: CrateId, - inner: Arc>>, + inner: Arc>>, } /// We need eq for salsa @@ -38,8 +38,8 @@ impl TraitSolver { fn solve( &self, db: &impl HirDatabase, - goal: &chalk_ir::UCanonical>>, - ) -> Option> { + goal: &chalk_ir::UCanonical>>, + ) -> Option> { let context = ChalkContext { db, krate: self.krate }; log::debug!("solve goal: {:?}", goal); let mut solver = match self.inner.lock() { @@ -110,7 +110,7 @@ pub(crate) fn trait_solver_query( TraitSolver { krate, inner: Arc::new(Mutex::new(create_chalk_solver())) } } -fn create_chalk_solver() -> chalk_solve::Solver { +fn create_chalk_solver() -> chalk_solve::Solver { let solver_choice = chalk_solve::SolverChoice::SLG { max_size: CHALK_SOLVER_MAX_SIZE, expected_answers: None }; solver_choice.into_solver() @@ -242,9 +242,9 @@ pub(crate) fn trait_solve_query( fn solution_from_chalk( db: &impl HirDatabase, - solution: chalk_solve::Solution, + solution: chalk_solve::Solution, ) -> Solution { - let convert_subst = |subst: chalk_ir::Canonical>| { + let convert_subst = |subst: chalk_ir::Canonical>| { let value = subst .value .into_iter() diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index e1e430aeb0..5b6c1a62e0 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -3,7 +3,7 @@ use std::{fmt, sync::Arc}; use log::debug; -use chalk_ir::{cast::Cast, GoalData, Parameter, PlaceholderIndex, TypeName, UniverseIndex}; +use chalk_ir::{cast::Cast, Goal, GoalData, Parameter, PlaceholderIndex, TypeName, UniverseIndex}; use hir_def::{AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, TypeAliasId}; use ra_db::{ @@ -18,13 +18,14 @@ use crate::{ }; #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] -pub struct TypeFamily {} +pub struct Interner {} -impl chalk_ir::family::TypeFamily for TypeFamily { +impl chalk_ir::interner::Interner for Interner { type InternedType = Box>; type InternedLifetime = chalk_ir::LifetimeData; type InternedParameter = chalk_ir::ParameterData; type InternedGoal = Arc>; + type InternedGoals = Vec>; type InternedSubstitution = Vec>; type DefId = InternId; @@ -85,10 +86,18 @@ impl chalk_ir::family::TypeFamily for TypeFamily { Arc::new(goal) } + fn intern_goals(data: impl IntoIterator>) -> Self::InternedGoals { + data.into_iter().collect() + } + fn goal_data(goal: &Arc>) -> &GoalData { goal } + fn goals_data(goals: &Vec>) -> &[Goal] { + goals + } + fn intern_substitution( data: impl IntoIterator, E>>, ) -> Result>, E> { @@ -100,20 +109,20 @@ impl chalk_ir::family::TypeFamily for TypeFamily { } } -impl chalk_ir::family::HasTypeFamily for TypeFamily { - type TypeFamily = Self; +impl chalk_ir::interner::HasInterner for Interner { + type Interner = Self; } -pub type AssocTypeId = chalk_ir::AssocTypeId; -pub type AssociatedTyDatum = chalk_rust_ir::AssociatedTyDatum; -pub type TraitId = chalk_ir::TraitId; -pub type TraitDatum = chalk_rust_ir::TraitDatum; -pub type StructId = chalk_ir::StructId; -pub type StructDatum = chalk_rust_ir::StructDatum; -pub type ImplId = chalk_ir::ImplId; -pub type ImplDatum = chalk_rust_ir::ImplDatum; +pub type AssocTypeId = chalk_ir::AssocTypeId; +pub type AssociatedTyDatum = chalk_rust_ir::AssociatedTyDatum; +pub type TraitId = chalk_ir::TraitId; +pub type TraitDatum = chalk_rust_ir::TraitDatum; +pub type StructId = chalk_ir::StructId; +pub type StructDatum = chalk_rust_ir::StructDatum; +pub type ImplId = chalk_ir::ImplId; +pub type ImplDatum = chalk_rust_ir::ImplDatum; pub type AssociatedTyValueId = chalk_rust_ir::AssociatedTyValueId; -pub type AssociatedTyValue = chalk_rust_ir::AssociatedTyValue; +pub type AssociatedTyValue = chalk_rust_ir::AssociatedTyValue; pub(super) trait ToChalk { type Chalk; @@ -129,8 +138,8 @@ where } impl ToChalk for Ty { - type Chalk = chalk_ir::Ty; - fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty { + type Chalk = chalk_ir::Ty; + fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty { match self { Ty::Apply(apply_ty) => { let name = apply_ty.ctor.to_chalk(db); @@ -148,7 +157,7 @@ impl ToChalk for Ty { ui: UniverseIndex::ROOT, idx: interned_id.as_intern_id().as_usize(), } - .to_ty::() + .to_ty::() } Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx as usize).intern(), Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), @@ -169,7 +178,7 @@ impl ToChalk for Ty { } } } - fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self { + fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self { match chalk.data().clone() { chalk_ir::TyData::Apply(apply_ty) => match apply_ty.name { TypeName::Error => Ty::Unknown, @@ -205,13 +214,13 @@ impl ToChalk for Ty { } impl ToChalk for Substs { - type Chalk = chalk_ir::Substitution; + type Chalk = chalk_ir::Substitution; - fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Substitution { + fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Substitution { chalk_ir::Substitution::from(self.iter().map(|ty| ty.clone().to_chalk(db))) } - fn from_chalk(db: &impl HirDatabase, parameters: chalk_ir::Substitution) -> Substs { + fn from_chalk(db: &impl HirDatabase, parameters: chalk_ir::Substitution) -> Substs { let tys = parameters .into_iter() .map(|p| match p.ty() { @@ -224,15 +233,15 @@ impl ToChalk for Substs { } impl ToChalk for TraitRef { - type Chalk = chalk_ir::TraitRef; + type Chalk = chalk_ir::TraitRef; - fn to_chalk(self: TraitRef, db: &impl HirDatabase) -> chalk_ir::TraitRef { + fn to_chalk(self: TraitRef, db: &impl HirDatabase) -> chalk_ir::TraitRef { let trait_id = self.trait_.to_chalk(db); let substitution = self.substs.to_chalk(db); chalk_ir::TraitRef { trait_id, substitution } } - fn from_chalk(db: &impl HirDatabase, trait_ref: chalk_ir::TraitRef) -> Self { + fn from_chalk(db: &impl HirDatabase, trait_ref: chalk_ir::TraitRef) -> Self { let trait_ = from_chalk(db, trait_ref.trait_id); let substs = from_chalk(db, trait_ref.substitution); TraitRef { trait_, substs } @@ -252,9 +261,9 @@ impl ToChalk for hir_def::TraitId { } impl ToChalk for TypeCtor { - type Chalk = TypeName; + type Chalk = TypeName; - fn to_chalk(self, db: &impl HirDatabase) -> TypeName { + fn to_chalk(self, db: &impl HirDatabase) -> TypeName { match self { TypeCtor::AssociatedType(type_alias) => { let type_id = type_alias.to_chalk(db); @@ -268,7 +277,7 @@ impl ToChalk for TypeCtor { } } - fn from_chalk(db: &impl HirDatabase, type_name: TypeName) -> TypeCtor { + fn from_chalk(db: &impl HirDatabase, type_name: TypeName) -> TypeCtor { match type_name { TypeName::Struct(struct_id) => db.lookup_intern_type_ctor(struct_id.into()), TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)), @@ -317,9 +326,9 @@ impl ToChalk for AssocTyValue { } impl ToChalk for GenericPredicate { - type Chalk = chalk_ir::QuantifiedWhereClause; + type Chalk = chalk_ir::QuantifiedWhereClause; - fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::QuantifiedWhereClause { + fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::QuantifiedWhereClause { match self { GenericPredicate::Implemented(trait_ref) => { make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0) @@ -337,7 +346,7 @@ impl ToChalk for GenericPredicate { fn from_chalk( db: &impl HirDatabase, - where_clause: chalk_ir::QuantifiedWhereClause, + where_clause: chalk_ir::QuantifiedWhereClause, ) -> GenericPredicate { match where_clause.value { chalk_ir::WhereClause::Implemented(tr) => { @@ -353,9 +362,9 @@ impl ToChalk for GenericPredicate { } impl ToChalk for ProjectionTy { - type Chalk = chalk_ir::AliasTy; + type Chalk = chalk_ir::AliasTy; - fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::AliasTy { + fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::AliasTy { chalk_ir::AliasTy { associated_ty_id: self.associated_ty.to_chalk(db), substitution: self.parameters.to_chalk(db), @@ -364,7 +373,7 @@ impl ToChalk for ProjectionTy { fn from_chalk( db: &impl HirDatabase, - projection_ty: chalk_ir::AliasTy, + projection_ty: chalk_ir::AliasTy, ) -> ProjectionTy { ProjectionTy { associated_ty: from_chalk(db, projection_ty.associated_ty_id), @@ -374,28 +383,28 @@ impl ToChalk for ProjectionTy { } impl ToChalk for super::ProjectionPredicate { - type Chalk = chalk_ir::Normalize; + type Chalk = chalk_ir::Normalize; - fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Normalize { + fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Normalize { chalk_ir::Normalize { alias: self.projection_ty.to_chalk(db), ty: self.ty.to_chalk(db) } } - fn from_chalk(_db: &impl HirDatabase, _normalize: chalk_ir::Normalize) -> Self { + fn from_chalk(_db: &impl HirDatabase, _normalize: chalk_ir::Normalize) -> Self { unimplemented!() } } impl ToChalk for Obligation { - type Chalk = chalk_ir::DomainGoal; + type Chalk = chalk_ir::DomainGoal; - fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::DomainGoal { + fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::DomainGoal { match self { Obligation::Trait(tr) => tr.to_chalk(db).cast(), Obligation::Projection(pr) => pr.to_chalk(db).cast(), } } - fn from_chalk(_db: &impl HirDatabase, _goal: chalk_ir::DomainGoal) -> Self { + fn from_chalk(_db: &impl HirDatabase, _goal: chalk_ir::DomainGoal) -> Self { unimplemented!() } } @@ -418,16 +427,16 @@ where } impl ToChalk for Arc { - type Chalk = chalk_ir::Environment; + type Chalk = chalk_ir::Environment; - fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Environment { + fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Environment { let mut clauses = Vec::new(); for pred in &self.predicates { if pred.is_error() { // for env, we just ignore errors continue; } - let program_clause: chalk_ir::ProgramClause = + let program_clause: chalk_ir::ProgramClause = pred.clone().to_chalk(db).cast(); clauses.push(program_clause.into_from_env_clause()); } @@ -436,7 +445,7 @@ impl ToChalk for Arc { fn from_chalk( _db: &impl HirDatabase, - _env: chalk_ir::Environment, + _env: chalk_ir::Environment, ) -> Arc { unimplemented!() } @@ -444,7 +453,7 @@ impl ToChalk for Arc { impl ToChalk for super::InEnvironment where - T::Chalk: chalk_ir::family::HasTypeFamily, + T::Chalk: chalk_ir::interner::HasInterner, { type Chalk = chalk_ir::InEnvironment; @@ -522,7 +531,7 @@ fn convert_where_clauses( db: &impl HirDatabase, def: GenericDefId, substs: &Substs, -) -> Vec> { +) -> Vec> { let generic_predicates = db.generic_predicates(def); let mut result = Vec::with_capacity(generic_predicates.len()); for pred in generic_predicates.iter() { @@ -535,7 +544,7 @@ fn convert_where_clauses( result } -impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB> +impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB> where DB: HirDatabase, { @@ -554,7 +563,7 @@ where fn impls_for_trait( &self, trait_id: TraitId, - parameters: &[Parameter], + parameters: &[Parameter], ) -> Vec { debug!("impls_for_trait {:?}", trait_id); let trait_: hir_def::TraitId = from_chalk(self.db, trait_id); @@ -589,14 +598,14 @@ where fn associated_ty_value(&self, id: AssociatedTyValueId) -> Arc { self.db.associated_ty_value(self.krate, id) } - fn custom_clauses(&self) -> Vec> { + fn custom_clauses(&self) -> Vec> { vec![] } fn local_impls_to_coherence_check(&self, _trait_id: TraitId) -> Vec { // We don't do coherence checking (yet) unimplemented!() } - fn as_struct_id(&self, id: &TypeName) -> Option { + fn as_struct_id(&self, id: &TypeName) -> Option { match id { TypeName::Struct(struct_id) => Some(*struct_id), _ => None, From 39efb301ff7946592ac0d8a64749582daaa67b86 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Tue, 25 Feb 2020 00:48:44 +0200 Subject: [PATCH 06/28] vscode: create rust-analyzer-api.ts --- editors/code/src/rust-analyzer-api.ts | 117 ++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 editors/code/src/rust-analyzer-api.ts diff --git a/editors/code/src/rust-analyzer-api.ts b/editors/code/src/rust-analyzer-api.ts new file mode 100644 index 0000000000..d2738fef32 --- /dev/null +++ b/editors/code/src/rust-analyzer-api.ts @@ -0,0 +1,117 @@ +/** + * This file mirrors `crates/rust-analyzer/src/req.rs` declarations. + */ + +import { RequestType, TextDocumentIdentifier, Position, Range, TextDocumentPositionParams, Location, NotificationType, WorkspaceEdit } from "vscode-languageclient"; + +type Option = null | T; +type Vec = T[]; +type FxHashMap = Record; + +function request(method: string) { + return new RequestType(`rust-analyzer/${method}`); +} +function notification(method: string) { + return new NotificationType(method); +} + + +export const analyzerStatus = request("analyzerStatus"); + + +export const collectGarbage = request("collectGarbage"); + + +export interface SyntaxTreeParams { + textDocument: TextDocumentIdentifier; + range: Option; +} +export const syntaxTree = request("syntaxTree"); + + +export interface ExpandMacroParams { + textDocument: TextDocumentIdentifier; + position: Option; +} +export interface ExpandedMacro { + name: string; + expansion: string; +} +export const expandMacro = request>("expandMacro"); + + +export interface FindMatchingBraceParams { + textDocument: TextDocumentIdentifier; + offsets: Vec; +} +export const findMatchingBrace = request>("findMatchingBrace"); + + +export interface PublishDecorationsParams { + uri: string; + decorations: Vec; +} +export interface Decoration { + range: Range; + tag: string; + bindingHash: Option; +} +export const decorationsRequest = request>("decorationsRequest"); + + +export const parentModule = request>("parentModule"); + + +export interface JoinLinesParams { + textDocument: TextDocumentIdentifier; + range: Range; +} +export const joinLines = request("joinLines"); + + +export const onEnter = request>("onEnter"); + +export interface RunnablesParams { + textDocument: TextDocumentIdentifier; + position: Option; +} +export interface Runnable { + range: Range; + label: string; + bin: string; + args: Vec; + env: FxHashMap; + cwd: Option; +} +export const runnables = request>("runnables"); + + +export const enum InlayKind { + TypeHint = "TypeHint", + ParameterHint = "ParameterHint", +} +export interface InlayHint { + range: Range; + kind: InlayKind; + label: string; +} +export interface InlayHintsParams { + textDocument: TextDocumentIdentifier; +} +export const inlayHints = request>("inlayHints"); + + +export interface SsrParams { + arg: string; +} +export const ssr = request("ssr"); + + +export const publishDecorations = notification("publishDecorations"); + + +export interface SourceChange { + label: string; + workspaceEdit: WorkspaceEdit; + cursorPosition: Option; +} From 21ab13396672a4ad75b93bbb73af02d019ef918b Mon Sep 17 00:00:00 2001 From: Veetaha Date: Tue, 25 Feb 2020 00:49:19 +0200 Subject: [PATCH 07/28] vscode: migrate source_cnage.rs to rust-analyzer-api.rs --- editors/code/src/source_change.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/editors/code/src/source_change.ts b/editors/code/src/source_change.ts index a336269baa..399a150c65 100644 --- a/editors/code/src/source_change.ts +++ b/editors/code/src/source_change.ts @@ -1,15 +1,10 @@ import * as vscode from 'vscode'; import * as lc from 'vscode-languageclient'; +import * as ra from './rust-analyzer-api'; import { Ctx } from './ctx'; -export interface SourceChange { - label: string; - workspaceEdit: lc.WorkspaceEdit; - cursorPosition?: lc.TextDocumentPositionParams; -} - -export async function applySourceChange(ctx: Ctx, change: SourceChange) { +export async function applySourceChange(ctx: Ctx, change: ra.SourceChange) { const client = ctx.client; if (!client) return; From 8c4409b3bb6dcdc439c7ea98dfb89c0181969323 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Tue, 25 Feb 2020 00:49:54 +0200 Subject: [PATCH 08/28] vscode: migrate highlighting to rust-analyzer-api.ts --- editors/code/src/highlighting.ts | 58 +++++++++++--------------------- 1 file changed, 20 insertions(+), 38 deletions(-) diff --git a/editors/code/src/highlighting.ts b/editors/code/src/highlighting.ts index 77b4a1a68b..3e0cbdc561 100644 --- a/editors/code/src/highlighting.ts +++ b/editors/code/src/highlighting.ts @@ -1,5 +1,5 @@ import * as vscode from 'vscode'; -import * as lc from 'vscode-languageclient'; +import * as ra from './rust-analyzer-api'; import { ColorTheme, TextMateRuleSettings } from './color_theme'; @@ -8,29 +8,25 @@ import { sendRequestWithRetry } from './util'; export function activateHighlighting(ctx: Ctx) { const highlighter = new Highlighter(ctx); - const client = ctx.client; - if (client != null) { - client.onNotification( - 'rust-analyzer/publishDecorations', - (params: PublishDecorationsParams) => { - if (!ctx.config.highlightingOn) return; - const targetEditor = vscode.window.visibleTextEditors.find( - editor => { - const unescapedUri = unescape( - editor.document.uri.toString(), - ); - // Unescaped URI looks like: - // file:///c:/Workspace/ra-test/src/main.rs - return unescapedUri === params.uri; - }, + ctx.client.onNotification(ra.publishDecorations, params => { + if (!ctx.config.highlightingOn) return; + + const targetEditor = vscode.window.visibleTextEditors.find( + editor => { + const unescapedUri = unescape( + editor.document.uri.toString(), ); - if (!targetEditor) return; - - highlighter.setHighlights(targetEditor, params.decorations); + // Unescaped URI looks like: + // file:///c:/Workspace/ra-test/src/main.rs + return unescapedUri === params.uri; }, ); - } + if (!targetEditor) return; + + highlighter.setHighlights(targetEditor, params.decorations); + }); + vscode.workspace.onDidChangeConfiguration( _ => highlighter.removeHighlights(), @@ -45,13 +41,10 @@ export function activateHighlighting(ctx: Ctx) { const client = ctx.client; if (!client) return; - const params: lc.TextDocumentIdentifier = { - uri: editor.document.uri.toString(), - }; - const decorations = await sendRequestWithRetry( + const decorations = await sendRequestWithRetry( client, - 'rust-analyzer/decorationsRequest', - params, + ra.decorationsRequest, + { uri: editor.document.uri.toString() }, ); highlighter.setHighlights(editor, decorations); }, @@ -60,17 +53,6 @@ export function activateHighlighting(ctx: Ctx) { ); } -interface PublishDecorationsParams { - uri: string; - decorations: Decoration[]; -} - -interface Decoration { - range: lc.Range; - tag: string; - bindingHash?: string; -} - // Based on this HSL-based color generator: https://gist.github.com/bendc/76c48ce53299e6078a76 function fancify(seed: string, shade: 'light' | 'dark') { const random = randomU32Numbers(hashString(seed)); @@ -108,7 +90,7 @@ class Highlighter { this.decorations = null; } - public setHighlights(editor: vscode.TextEditor, highlights: Decoration[]) { + public setHighlights(editor: vscode.TextEditor, highlights: ra.Decoration[]) { const client = this.ctx.client; if (!client) return; // Initialize decorations if necessary From 603bc71a57ce386d78f1b1c842714ff0dbeeaf9c Mon Sep 17 00:00:00 2001 From: Veetaha Date: Tue, 25 Feb 2020 00:50:14 +0200 Subject: [PATCH 09/28] vscode: migrate analyzer_status to rust-analyzer-api.ts --- editors/code/src/commands/analyzer_status.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/editors/code/src/commands/analyzer_status.ts b/editors/code/src/commands/analyzer_status.ts index 6631e8db77..1c6ea399b1 100644 --- a/editors/code/src/commands/analyzer_status.ts +++ b/editors/code/src/commands/analyzer_status.ts @@ -1,5 +1,6 @@ import * as vscode from 'vscode'; +import * as ra from '../rust-analyzer-api'; import { Ctx, Cmd } from '../ctx'; // Shows status of rust-analyzer (for debugging) @@ -50,10 +51,7 @@ class TextDocumentContentProvider const client = this.ctx.client; if (!editor || !client) return ''; - return client.sendRequest( - 'rust-analyzer/analyzerStatus', - null, - ); + return client.sendRequest(ra.analyzerStatus, null); } get onDidChange(): vscode.Event { From 31d9932d18151bffe94e4137ac3b5d10df37641f Mon Sep 17 00:00:00 2001 From: Veetaha Date: Tue, 25 Feb 2020 00:50:36 +0200 Subject: [PATCH 10/28] vscode: migrate expand_macro to rust-analyzer-api.ts --- editors/code/src/commands/expand_macro.ts | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/editors/code/src/commands/expand_macro.ts b/editors/code/src/commands/expand_macro.ts index edec9bbc13..23f2ef1d5e 100644 --- a/editors/code/src/commands/expand_macro.ts +++ b/editors/code/src/commands/expand_macro.ts @@ -1,5 +1,5 @@ import * as vscode from 'vscode'; -import * as lc from 'vscode-languageclient'; +import * as ra from '../rust-analyzer-api'; import { Ctx, Cmd } from '../ctx'; @@ -26,12 +26,7 @@ export function expandMacro(ctx: Ctx): Cmd { }; } -interface ExpandedMacro { - name: string; - expansion: string; -} - -function codeFormat(expanded: ExpandedMacro): string { +function codeFormat(expanded: ra.ExpandedMacro): string { let result = `// Recursive expansion of ${expanded.name}! macro\n`; result += '// ' + '='.repeat(result.length - 3); result += '\n\n'; @@ -54,14 +49,11 @@ class TextDocumentContentProvider if (!editor || !client) return ''; const position = editor.selection.active; - const request: lc.TextDocumentPositionParams = { + + const expanded = await client.sendRequest(ra.expandMacro, { textDocument: { uri: editor.document.uri.toString() }, position, - }; - const expanded = await client.sendRequest( - 'rust-analyzer/expandMacro', - request, - ); + }); if (expanded == null) return 'Not available'; From c9a2fa1835a9b91d7e9332f7eceb8c899c727d32 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Tue, 25 Feb 2020 00:50:57 +0200 Subject: [PATCH 11/28] vscode: migrate collectGarbage to rust-analyzer-api.ts --- editors/code/src/commands/index.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/editors/code/src/commands/index.ts b/editors/code/src/commands/index.ts index 839245f487..bdb7fc3b03 100644 --- a/editors/code/src/commands/index.ts +++ b/editors/code/src/commands/index.ts @@ -1,5 +1,6 @@ import * as vscode from 'vscode'; import * as lc from 'vscode-languageclient'; +import * as ra from '../rust-analyzer-api'; import { Ctx, Cmd } from '../ctx'; import * as sourceChange from '../source_change'; @@ -16,9 +17,7 @@ export * from './ssr'; export * from './server_version'; export function collectGarbage(ctx: Ctx): Cmd { - return async () => { - await ctx.client?.sendRequest('rust-analyzer/collectGarbage', null); - }; + return async () => ctx.client.sendRequest(ra.collectGarbage, null); } export function showReferences(ctx: Ctx): Cmd { @@ -36,13 +35,13 @@ export function showReferences(ctx: Ctx): Cmd { } export function applySourceChange(ctx: Ctx): Cmd { - return async (change: sourceChange.SourceChange) => { + return async (change: ra.SourceChange) => { await sourceChange.applySourceChange(ctx, change); }; } export function selectAndApplySourceChange(ctx: Ctx): Cmd { - return async (changes: sourceChange.SourceChange[]) => { + return async (changes: ra.SourceChange[]) => { if (changes.length === 1) { await sourceChange.applySourceChange(ctx, changes[0]); } else if (changes.length > 0) { From 38d7945ec7d3522e09a105a92156d1aaf8651f46 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Tue, 25 Feb 2020 00:54:50 +0200 Subject: [PATCH 12/28] vscode: migrate join_lines to rust-analyzer-api.ts --- editors/code/src/commands/join_lines.ts | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/editors/code/src/commands/join_lines.ts b/editors/code/src/commands/join_lines.ts index 7b08c32550..de0614653d 100644 --- a/editors/code/src/commands/join_lines.ts +++ b/editors/code/src/commands/join_lines.ts @@ -1,7 +1,7 @@ -import * as lc from 'vscode-languageclient'; +import * as ra from '../rust-analyzer-api'; import { Ctx, Cmd } from '../ctx'; -import { applySourceChange, SourceChange } from '../source_change'; +import { applySourceChange } from '../source_change'; export function joinLines(ctx: Ctx): Cmd { return async () => { @@ -9,19 +9,10 @@ export function joinLines(ctx: Ctx): Cmd { const client = ctx.client; if (!editor || !client) return; - const request: JoinLinesParams = { + const change = await client.sendRequest(ra.joinLines, { range: client.code2ProtocolConverter.asRange(editor.selection), textDocument: { uri: editor.document.uri.toString() }, - }; - const change = await client.sendRequest( - 'rust-analyzer/joinLines', - request, - ); + }); await applySourceChange(ctx, change); }; } - -interface JoinLinesParams { - textDocument: lc.TextDocumentIdentifier; - range: lc.Range; -} From 56d1ff65324d59623e8483c7cbf03672611cbcdf Mon Sep 17 00:00:00 2001 From: Veetaha Date: Tue, 25 Feb 2020 00:55:13 +0200 Subject: [PATCH 13/28] vscode: migrate matching_brace to rust-analyzer-api.ts --- editors/code/src/commands/matching_brace.ts | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/editors/code/src/commands/matching_brace.ts b/editors/code/src/commands/matching_brace.ts index 7c58bb7e72..a60776e2d4 100644 --- a/editors/code/src/commands/matching_brace.ts +++ b/editors/code/src/commands/matching_brace.ts @@ -1,5 +1,5 @@ import * as vscode from 'vscode'; -import * as lc from 'vscode-languageclient'; +import * as ra from '../rust-analyzer-api'; import { Ctx, Cmd } from '../ctx'; @@ -9,16 +9,12 @@ export function matchingBrace(ctx: Ctx): Cmd { const client = ctx.client; if (!editor || !client) return; - const request: FindMatchingBraceParams = { + const response = await client.sendRequest(ra.findMatchingBrace, { textDocument: { uri: editor.document.uri.toString() }, offsets: editor.selections.map(s => client.code2ProtocolConverter.asPosition(s.active), ), - }; - const response = await client.sendRequest( - 'rust-analyzer/findMatchingBrace', - request, - ); + }); editor.selections = editor.selections.map((sel, idx) => { const active = client.protocol2CodeConverter.asPosition( response[idx], @@ -29,8 +25,3 @@ export function matchingBrace(ctx: Ctx): Cmd { editor.revealRange(editor.selection); }; } - -interface FindMatchingBraceParams { - textDocument: lc.TextDocumentIdentifier; - offsets: lc.Position[]; -} From 8c6581dcc3db0e79a075d22ab930cb58a31dfe3c Mon Sep 17 00:00:00 2001 From: Veetaha Date: Tue, 25 Feb 2020 00:55:48 +0200 Subject: [PATCH 14/28] vscode: migrate on_enter to rust-analyzer-api.ts --- editors/code/src/commands/on_enter.ts | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/editors/code/src/commands/on_enter.ts b/editors/code/src/commands/on_enter.ts index 27ae8ec232..285849db70 100644 --- a/editors/code/src/commands/on_enter.ts +++ b/editors/code/src/commands/on_enter.ts @@ -1,7 +1,7 @@ import * as vscode from 'vscode'; -import * as lc from 'vscode-languageclient'; +import * as ra from '../rust-analyzer-api'; -import { applySourceChange, SourceChange } from '../source_change'; +import { applySourceChange } from '../source_change'; import { Cmd, Ctx } from '../ctx'; async function handleKeypress(ctx: Ctx) { @@ -10,22 +10,15 @@ async function handleKeypress(ctx: Ctx) { if (!editor || !client) return false; - const request: lc.TextDocumentPositionParams = { + const change = await client.sendRequest(ra.onEnter, { textDocument: { uri: editor.document.uri.toString() }, position: client.code2ProtocolConverter.asPosition( editor.selection.active, ), - }; - const change = await client.sendRequest( - 'rust-analyzer/onEnter', - request, - ).catch( - (_error: any) => { - // FIXME: switch to the more modern (?) typed request infrastructure - // client.logFailedRequest(OnEnterRequest.type, error); - return Promise.resolve(null); - } - ); + }).catch(_error => { + // client.logFailedRequest(OnEnterRequest.type, error); + return null; + }); if (!change) return false; await applySourceChange(ctx, change); From d6a96a90f417d48e6391d2233abf752988c04f1a Mon Sep 17 00:00:00 2001 From: Veetaha Date: Tue, 25 Feb 2020 00:56:19 +0200 Subject: [PATCH 15/28] vscode: migrate parent_module to rust-analyzer-api.ts --- editors/code/src/commands/parent_module.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/editors/code/src/commands/parent_module.ts b/editors/code/src/commands/parent_module.ts index bf40b40218..8f78ddd71c 100644 --- a/editors/code/src/commands/parent_module.ts +++ b/editors/code/src/commands/parent_module.ts @@ -1,5 +1,5 @@ import * as vscode from 'vscode'; -import * as lc from 'vscode-languageclient'; +import * as ra from '../rust-analyzer-api'; import { Ctx, Cmd } from '../ctx'; @@ -9,16 +9,12 @@ export function parentModule(ctx: Ctx): Cmd { const client = ctx.client; if (!editor || !client) return; - const request: lc.TextDocumentPositionParams = { + const response = await client.sendRequest(ra.parentModule, { textDocument: { uri: editor.document.uri.toString() }, position: client.code2ProtocolConverter.asPosition( editor.selection.active, ), - }; - const response = await client.sendRequest( - 'rust-analyzer/parentModule', - request, - ); + }); const loc = response[0]; if (loc == null) return; From 8a8a4d08ef6c695cce04f5e306fad83cc9abddcd Mon Sep 17 00:00:00 2001 From: Veetaha Date: Tue, 25 Feb 2020 00:56:38 +0200 Subject: [PATCH 16/28] vscode: migrate runnables to rust-analyzer-api.ts --- editors/code/src/commands/runnables.ts | 29 +++++++------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts index 7919997ce3..06b5134668 100644 --- a/editors/code/src/commands/runnables.ts +++ b/editors/code/src/commands/runnables.ts @@ -1,5 +1,6 @@ import * as vscode from 'vscode'; import * as lc from 'vscode-languageclient'; +import * as ra from '../rust-analyzer-api'; import { Ctx, Cmd } from '../ctx'; @@ -14,16 +15,13 @@ export function run(ctx: Ctx): Cmd { const textDocument: lc.TextDocumentIdentifier = { uri: editor.document.uri.toString(), }; - const params: RunnablesParams = { + + const runnables = await client.sendRequest(ra.runnables, { textDocument, position: client.code2ProtocolConverter.asPosition( editor.selection.active, ), - }; - const runnables = await client.sendRequest( - 'rust-analyzer/runnables', - params, - ); + }); const items: RunnableQuickPick[] = []; if (prevRunnable) { items.push(prevRunnable); @@ -48,7 +46,7 @@ export function run(ctx: Ctx): Cmd { } export function runSingle(ctx: Ctx): Cmd { - return async (runnable: Runnable) => { + return async (runnable: ra.Runnable) => { const editor = ctx.activeRustEditor; if (!editor) return; @@ -64,26 +62,13 @@ export function runSingle(ctx: Ctx): Cmd { }; } -interface RunnablesParams { - textDocument: lc.TextDocumentIdentifier; - position?: lc.Position; -} - -interface Runnable { - label: string; - bin: string; - args: string[]; - env: { [index: string]: string }; - cwd?: string; -} - class RunnableQuickPick implements vscode.QuickPickItem { public label: string; public description?: string | undefined; public detail?: string | undefined; public picked?: boolean | undefined; - constructor(public runnable: Runnable) { + constructor(public runnable: ra.Runnable) { this.label = runnable.label; } } @@ -96,7 +81,7 @@ interface CargoTaskDefinition extends vscode.TaskDefinition { env?: { [key: string]: string }; } -function createTask(spec: Runnable): vscode.Task { +function createTask(spec: ra.Runnable): vscode.Task { const TASK_SOURCE = 'Rust'; const definition: CargoTaskDefinition = { type: 'cargo', From 9ea63d5a86b8217c25f0db49a535105b345ceae1 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Tue, 25 Feb 2020 00:56:57 +0200 Subject: [PATCH 17/28] vscode: migrate ssr to rust-analyzer-api.ts --- editors/code/src/commands/ssr.ts | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/editors/code/src/commands/ssr.ts b/editors/code/src/commands/ssr.ts index 9b814612aa..63c36ce806 100644 --- a/editors/code/src/commands/ssr.ts +++ b/editors/code/src/commands/ssr.ts @@ -1,6 +1,8 @@ -import { Ctx, Cmd } from '../ctx'; -import { applySourceChange, SourceChange } from '../source_change'; import * as vscode from 'vscode'; +import * as ra from "../rust-analyzer-api"; + +import { Ctx, Cmd } from '../ctx'; +import { applySourceChange } from '../source_change'; export function ssr(ctx: Ctx): Cmd { return async () => { @@ -21,16 +23,8 @@ export function ssr(ctx: Ctx): Cmd { if (!request) return; - const ssrRequest: SsrRequest = { arg: request }; - const change = await client.sendRequest( - 'rust-analyzer/ssr', - ssrRequest, - ); + const change = await client.sendRequest(ra.ssr, { arg: request },); await applySourceChange(ctx, change); }; } - -interface SsrRequest { - arg: string; -} From 8aea0ec511d141b5c53d419960c688b13bb6c061 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Tue, 25 Feb 2020 00:57:14 +0200 Subject: [PATCH 18/28] vscode: migrate syntax_tree to rust-analyzer-api.ts --- editors/code/src/commands/syntax_tree.ts | 27 ++++++------------------ 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/editors/code/src/commands/syntax_tree.ts b/editors/code/src/commands/syntax_tree.ts index 2887c96c80..7218bfb900 100644 --- a/editors/code/src/commands/syntax_tree.ts +++ b/editors/code/src/commands/syntax_tree.ts @@ -1,5 +1,5 @@ import * as vscode from 'vscode'; -import * as lc from 'vscode-languageclient'; +import * as ra from '../rust-analyzer-api'; import { Ctx, Cmd } from '../ctx'; @@ -61,13 +61,8 @@ function afterLs(f: () => void) { setTimeout(f, 10); } -interface SyntaxTreeParams { - textDocument: lc.TextDocumentIdentifier; - range?: lc.Range; -} -class TextDocumentContentProvider - implements vscode.TextDocumentContentProvider { +class TextDocumentContentProvider implements vscode.TextDocumentContentProvider { uri = vscode.Uri.parse('rust-analyzer://syntaxtree'); eventEmitter = new vscode.EventEmitter(); @@ -79,23 +74,15 @@ class TextDocumentContentProvider const client = this.ctx.client; if (!editor || !client) return ''; - let range: lc.Range | undefined; - // When the range based query is enabled we take the range of the selection - if (uri.query === 'range=true') { - range = editor.selection.isEmpty - ? undefined - : client.code2ProtocolConverter.asRange(editor.selection); - } + const range = uri.query === 'range=true' && !editor.selection.isEmpty + ? client.code2ProtocolConverter.asRange(editor.selection) + : null; - const request: SyntaxTreeParams = { + return client.sendRequest(ra.syntaxTree, { textDocument: { uri: editor.document.uri.toString() }, range, - }; - return client.sendRequest( - 'rust-analyzer/syntaxTree', - request, - ); + }); } get onDidChange(): vscode.Event { From c9230b88b4852faf1dac59e05fd4f4d8c1f0dfb0 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Tue, 25 Feb 2020 00:57:49 +0200 Subject: [PATCH 19/28] vscode: migrate inlay_hints to rust-analyzer-api.ts --- editors/code/src/inlay_hints.ts | 31 ++++++++----------------------- editors/code/src/util.ts | 16 ++++++++-------- 2 files changed, 16 insertions(+), 31 deletions(-) diff --git a/editors/code/src/inlay_hints.ts b/editors/code/src/inlay_hints.ts index 5f9229efbc..5951cf1b45 100644 --- a/editors/code/src/inlay_hints.ts +++ b/editors/code/src/inlay_hints.ts @@ -1,5 +1,5 @@ import * as vscode from 'vscode'; -import * as lc from 'vscode-languageclient'; +import * as ra from './rust-analyzer-api'; import { Ctx } from './ctx'; import { log, sendRequestWithRetry } from './util'; @@ -39,16 +39,6 @@ export function activateInlayHints(ctx: Ctx) { void hintsUpdater.setEnabled(ctx.config.displayInlayHints); } -interface InlayHintsParams { - textDocument: lc.TextDocumentIdentifier; -} - -interface InlayHint { - range: vscode.Range; - kind: "TypeHint" | "ParameterHint"; - label: string; -} - const typeHintDecorationType = vscode.window.createTextEditorDecorationType({ after: { color: new vscode.ThemeColor('rust_analyzer.inlayHint'), @@ -107,9 +97,9 @@ class HintsUpdater { if (newHints == null) return; const newTypeDecorations = newHints - .filter(hint => hint.kind === 'TypeHint') + .filter(hint => hint.kind === ra.InlayKind.TypeHint) .map(hint => ({ - range: hint.range, + range: this.ctx.client.protocol2CodeConverter.asRange(hint.range), renderOptions: { after: { contentText: `: ${hint.label}`, @@ -119,9 +109,9 @@ class HintsUpdater { this.setTypeDecorations(editor, newTypeDecorations); const newParameterDecorations = newHints - .filter(hint => hint.kind === 'ParameterHint') + .filter(hint => hint.kind === ra.InlayKind.ParameterHint) .map(hint => ({ - range: hint.range, + range: this.ctx.client.protocol2CodeConverter.asRange(hint.range), renderOptions: { before: { contentText: `${hint.label}: `, @@ -151,20 +141,15 @@ class HintsUpdater { ); } - private async queryHints(documentUri: string): Promise { + private async queryHints(documentUri: string): Promise { this.pending.get(documentUri)?.cancel(); const tokenSource = new vscode.CancellationTokenSource(); this.pending.set(documentUri, tokenSource); - const request: InlayHintsParams = { textDocument: { uri: documentUri } }; + const request = { textDocument: { uri: documentUri } }; - return sendRequestWithRetry( - this.ctx.client, - 'rust-analyzer/inlayHints', - request, - tokenSource.token - ) + return sendRequestWithRetry(this.ctx.client, ra.inlayHints, request, tokenSource.token) .catch(_ => null) .finally(() => { if (!tokenSource.token.isCancellationRequested) { diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts index 2f18f85a39..68c2a94d04 100644 --- a/editors/code/src/util.ts +++ b/editors/code/src/util.ts @@ -20,21 +20,21 @@ export const log = { } }; -export async function sendRequestWithRetry( +export async function sendRequestWithRetry( client: lc.LanguageClient, - method: string, - param: unknown, + reqType: lc.RequestType, + param: TParam, token?: vscode.CancellationToken, -): Promise { +): Promise { for (const delay of [2, 4, 6, 8, 10, null]) { try { return await (token - ? client.sendRequest(method, param, token) - : client.sendRequest(method, param) + ? client.sendRequest(reqType, param, token) + : client.sendRequest(reqType, param) ); } catch (error) { if (delay === null) { - log.error("LSP request timed out", { method, param, error }); + log.error("LSP request timed out", { method: reqType.method, param, error }); throw error; } @@ -43,7 +43,7 @@ export async function sendRequestWithRetry( } if (error.code !== lc.ErrorCodes.ContentModified) { - log.error("LSP request failed", { method, param, error }); + log.error("LSP request failed", { method: reqType.method, param, error }); throw error; } From 72e81dae71b8d2efbc418cba206b1988727766b7 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Tue, 25 Feb 2020 01:00:00 +0200 Subject: [PATCH 20/28] vscode: run fmt --- editors/code/src/commands/ssr.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editors/code/src/commands/ssr.ts b/editors/code/src/commands/ssr.ts index 63c36ce806..eee48c6935 100644 --- a/editors/code/src/commands/ssr.ts +++ b/editors/code/src/commands/ssr.ts @@ -23,7 +23,7 @@ export function ssr(ctx: Ctx): Cmd { if (!request) return; - const change = await client.sendRequest(ra.ssr, { arg: request },); + const change = await client.sendRequest(ra.ssr, { arg: request }); await applySourceChange(ctx, change); }; From 18b97d9d367d5fc1533c48157ebca7bb18b62e3c Mon Sep 17 00:00:00 2001 From: Veetaha Date: Tue, 25 Feb 2020 01:43:52 +0200 Subject: [PATCH 21/28] vscode: migrate rust-analyzer-api to import * as lc as per matklad and kjeremy --- editors/code/src/rust-analyzer-api.ts | 46 +++++++++++++-------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/editors/code/src/rust-analyzer-api.ts b/editors/code/src/rust-analyzer-api.ts index d2738fef32..c5a010e947 100644 --- a/editors/code/src/rust-analyzer-api.ts +++ b/editors/code/src/rust-analyzer-api.ts @@ -2,17 +2,17 @@ * This file mirrors `crates/rust-analyzer/src/req.rs` declarations. */ -import { RequestType, TextDocumentIdentifier, Position, Range, TextDocumentPositionParams, Location, NotificationType, WorkspaceEdit } from "vscode-languageclient"; +import * as lc from "vscode-languageclient"; type Option = null | T; type Vec = T[]; type FxHashMap = Record; function request(method: string) { - return new RequestType(`rust-analyzer/${method}`); + return new lc.RequestType(`rust-analyzer/${method}`); } function notification(method: string) { - return new NotificationType(method); + return new lc.NotificationType(method); } @@ -23,15 +23,15 @@ export const collectGarbage = request("collectGarbage"); export interface SyntaxTreeParams { - textDocument: TextDocumentIdentifier; - range: Option; + textDocument: lc.TextDocumentIdentifier; + range: Option; } export const syntaxTree = request("syntaxTree"); export interface ExpandMacroParams { - textDocument: TextDocumentIdentifier; - position: Option; + textDocument: lc.TextDocumentIdentifier; + position: Option; } export interface ExpandedMacro { name: string; @@ -41,10 +41,10 @@ export const expandMacro = request>("ex export interface FindMatchingBraceParams { - textDocument: TextDocumentIdentifier; - offsets: Vec; + textDocument: lc.TextDocumentIdentifier; + offsets: Vec; } -export const findMatchingBrace = request>("findMatchingBrace"); +export const findMatchingBrace = request>("findMatchingBrace"); export interface PublishDecorationsParams { @@ -52,31 +52,31 @@ export interface PublishDecorationsParams { decorations: Vec; } export interface Decoration { - range: Range; + range: lc.Range; tag: string; bindingHash: Option; } -export const decorationsRequest = request>("decorationsRequest"); +export const decorationsRequest = request>("decorationsRequest"); -export const parentModule = request>("parentModule"); +export const parentModule = request>("parentModule"); export interface JoinLinesParams { - textDocument: TextDocumentIdentifier; - range: Range; + textDocument: lc.TextDocumentIdentifier; + range: lc.Range; } export const joinLines = request("joinLines"); -export const onEnter = request>("onEnter"); +export const onEnter = request>("onEnter"); export interface RunnablesParams { - textDocument: TextDocumentIdentifier; - position: Option; + textDocument: lc.TextDocumentIdentifier; + position: Option; } export interface Runnable { - range: Range; + range: lc.Range; label: string; bin: string; args: Vec; @@ -91,12 +91,12 @@ export const enum InlayKind { ParameterHint = "ParameterHint", } export interface InlayHint { - range: Range; + range: lc.Range; kind: InlayKind; label: string; } export interface InlayHintsParams { - textDocument: TextDocumentIdentifier; + textDocument: lc.TextDocumentIdentifier; } export const inlayHints = request>("inlayHints"); @@ -112,6 +112,6 @@ export const publishDecorations = notification("publis export interface SourceChange { label: string; - workspaceEdit: WorkspaceEdit; - cursorPosition: Option; + workspaceEdit: lc.WorkspaceEdit; + cursorPosition: Option; } From 6ec4a7db42be5980f7a4b20f349cb10709dbf71b Mon Sep 17 00:00:00 2001 From: Veetaha Date: Tue, 25 Feb 2020 01:58:43 +0200 Subject: [PATCH 22/28] vscode: wrap non-single-line if body with curlies as per matklad --- .../code/src/installation/fetch_artifact_release_info.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/editors/code/src/installation/fetch_artifact_release_info.ts b/editors/code/src/installation/fetch_artifact_release_info.ts index 5e201afb0a..b1b5a3485c 100644 --- a/editors/code/src/installation/fetch_artifact_release_info.ts +++ b/editors/code/src/installation/fetch_artifact_release_info.ts @@ -51,9 +51,11 @@ export async function fetchArtifactReleaseInfo( const artifact = release.assets.find(artifact => artifact.name === artifactFileName); - if (!artifact) throw new Error( - `Artifact ${artifactFileName} was not found in ${release.name} release!` - ); + if (!artifact) { + throw new Error( + `Artifact ${artifactFileName} was not found in ${release.name} release!` + ); + } return { releaseName: release.name, From 9f0cfb7ad2120514ca8ffd21e08e3ddd0bfb34e9 Mon Sep 17 00:00:00 2001 From: kjeremy Date: Fri, 14 Feb 2020 17:56:28 -0500 Subject: [PATCH 23/28] Teach the server about Semantic Tokens proposed LSP --- crates/ra_ide/src/lib.rs | 2 +- crates/ra_ide/src/syntax_highlighting.rs | 42 ++++----- crates/rust-analyzer/src/caps.rs | 24 +++++- crates/rust-analyzer/src/conv.rs | 79 ++++++++++++++++- crates/rust-analyzer/src/lib.rs | 1 + crates/rust-analyzer/src/main_loop.rs | 1 + .../rust-analyzer/src/main_loop/handlers.rs | 28 +++++- crates/rust-analyzer/src/req.rs | 6 +- crates/rust-analyzer/src/semantic_tokens.rs | 86 +++++++++++++++++++ 9 files changed, 234 insertions(+), 35 deletions(-) create mode 100644 crates/rust-analyzer/src/semantic_tokens.rs diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index f86f98be73..82e10bc7e6 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs @@ -75,7 +75,7 @@ pub use crate::{ runnables::{Runnable, RunnableKind, TestId}, source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, ssr::SsrError, - syntax_highlighting::HighlightedRange, + syntax_highlighting::{tags, HighlightedRange}, }; pub use hir::Documentation; diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index d873f153ee..812229b4e0 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs @@ -17,32 +17,32 @@ use crate::{ }; pub mod tags { - pub(crate) const FIELD: &str = "field"; - pub(crate) const FUNCTION: &str = "function"; - pub(crate) const MODULE: &str = "module"; - pub(crate) const CONSTANT: &str = "constant"; - pub(crate) const MACRO: &str = "macro"; + pub const FIELD: &str = "field"; + pub const FUNCTION: &str = "function"; + pub const MODULE: &str = "module"; + pub const CONSTANT: &str = "constant"; + pub const MACRO: &str = "macro"; - pub(crate) const VARIABLE: &str = "variable"; - pub(crate) const VARIABLE_MUT: &str = "variable.mut"; + pub const VARIABLE: &str = "variable"; + pub const VARIABLE_MUT: &str = "variable.mut"; - pub(crate) const TYPE: &str = "type"; - pub(crate) const TYPE_BUILTIN: &str = "type.builtin"; - pub(crate) const TYPE_SELF: &str = "type.self"; - pub(crate) const TYPE_PARAM: &str = "type.param"; - pub(crate) const TYPE_LIFETIME: &str = "type.lifetime"; + pub const TYPE: &str = "type"; + pub const TYPE_BUILTIN: &str = "type.builtin"; + pub const TYPE_SELF: &str = "type.self"; + pub const TYPE_PARAM: &str = "type.param"; + pub const TYPE_LIFETIME: &str = "type.lifetime"; - pub(crate) const LITERAL_BYTE: &str = "literal.byte"; - pub(crate) const LITERAL_NUMERIC: &str = "literal.numeric"; - pub(crate) const LITERAL_CHAR: &str = "literal.char"; + pub const LITERAL_BYTE: &str = "literal.byte"; + pub const LITERAL_NUMERIC: &str = "literal.numeric"; + pub const LITERAL_CHAR: &str = "literal.char"; - pub(crate) const LITERAL_COMMENT: &str = "comment"; - pub(crate) const LITERAL_STRING: &str = "string"; - pub(crate) const LITERAL_ATTRIBUTE: &str = "attribute"; + pub const LITERAL_COMMENT: &str = "comment"; + pub const LITERAL_STRING: &str = "string"; + pub const LITERAL_ATTRIBUTE: &str = "attribute"; - pub(crate) const KEYWORD: &str = "keyword"; - pub(crate) const KEYWORD_UNSAFE: &str = "keyword.unsafe"; - pub(crate) const KEYWORD_CONTROL: &str = "keyword.control"; + pub const KEYWORD: &str = "keyword"; + pub const KEYWORD_UNSAFE: &str = "keyword.unsafe"; + pub const KEYWORD_CONTROL: &str = "keyword.control"; } #[derive(Debug)] diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs index c9fd645f1b..638987ee81 100644 --- a/crates/rust-analyzer/src/caps.rs +++ b/crates/rust-analyzer/src/caps.rs @@ -1,12 +1,15 @@ //! Advertizes the capabilities of the LSP Server. +use crate::semantic_tokens; + use lsp_types::{ CallHierarchyServerCapability, CodeActionProviderCapability, CodeLensOptions, CompletionOptions, DocumentOnTypeFormattingOptions, FoldingRangeProviderCapability, ImplementationProviderCapability, RenameOptions, RenameProviderCapability, SaveOptions, - SelectionRangeProviderCapability, ServerCapabilities, SignatureHelpOptions, - TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions, - TypeDefinitionProviderCapability, WorkDoneProgressOptions, + SelectionRangeProviderCapability, SemanticTokensDocumentProvider, SemanticTokensLegend, + SemanticTokensOptions, SemanticTokensServerCapabilities, ServerCapabilities, + SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, + TextDocumentSyncOptions, TypeDefinitionProviderCapability, WorkDoneProgressOptions, }; pub fn server_capabilities() -> ServerCapabilities { @@ -57,7 +60,20 @@ pub fn server_capabilities() -> ServerCapabilities { execute_command_provider: None, workspace: None, call_hierarchy_provider: Some(CallHierarchyServerCapability::Simple(true)), - semantic_tokens_provider: None, + semantic_tokens_provider: Some(SemanticTokensServerCapabilities::SemanticTokensOptions( + SemanticTokensOptions { + legend: SemanticTokensLegend { + token_types: semantic_tokens::supported_token_types().iter().cloned().collect(), + token_modifiers: semantic_tokens::supported_token_modifiers() + .iter() + .cloned() + .collect(), + }, + + document_provider: Some(SemanticTokensDocumentProvider::Bool(true)), + ..SemanticTokensOptions::default() + }, + )), experimental: Default::default(), } } diff --git a/crates/rust-analyzer/src/conv.rs b/crates/rust-analyzer/src/conv.rs index 90ef74056b..5fcb46b617 100644 --- a/crates/rust-analyzer/src/conv.rs +++ b/crates/rust-analyzer/src/conv.rs @@ -4,11 +4,12 @@ use lsp_types::{ self, CreateFile, DiagnosticSeverity, DocumentChangeOperation, DocumentChanges, Documentation, Location, LocationLink, MarkupContent, MarkupKind, Position, Range, RenameFile, ResourceOp, - SymbolKind, TextDocumentEdit, TextDocumentIdentifier, TextDocumentItem, - TextDocumentPositionParams, Url, VersionedTextDocumentIdentifier, WorkspaceEdit, + SemanticTokenModifier, SemanticTokenType, SymbolKind, TextDocumentEdit, TextDocumentIdentifier, + TextDocumentItem, TextDocumentPositionParams, Url, VersionedTextDocumentIdentifier, + WorkspaceEdit, }; use ra_ide::{ - translate_offset_with_edit, CompletionItem, CompletionItemKind, FileId, FilePosition, + tags, translate_offset_with_edit, CompletionItem, CompletionItemKind, FileId, FilePosition, FileRange, FileSystemEdit, Fold, FoldKind, InsertTextFormat, LineCol, LineIndex, NavigationTarget, RangeInfo, ReferenceAccess, Severity, SourceChange, SourceFileEdit, }; @@ -16,7 +17,7 @@ use ra_syntax::{SyntaxKind, TextRange, TextUnit}; use ra_text_edit::{AtomTextEdit, TextEdit}; use ra_vfs::LineEndings; -use crate::{req, world::WorldSnapshot, Result}; +use crate::{req, semantic_tokens, world::WorldSnapshot, Result}; pub trait Conv { type Output; @@ -302,6 +303,76 @@ impl ConvWith<&FoldConvCtx<'_>> for Fold { } } +impl Conv for &'static str { + type Output = (SemanticTokenType, Vec); + + fn conv(self) -> (SemanticTokenType, Vec) { + let token_type: SemanticTokenType = match self { + tags::FIELD => SemanticTokenType::MEMBER, + tags::FUNCTION => SemanticTokenType::FUNCTION, + tags::MODULE => SemanticTokenType::NAMESPACE, + tags::CONSTANT => { + return ( + SemanticTokenType::VARIABLE, + vec![SemanticTokenModifier::STATIC, SemanticTokenModifier::READONLY], + ) + } + tags::MACRO => SemanticTokenType::MACRO, + + tags::VARIABLE => { + return (SemanticTokenType::VARIABLE, vec![SemanticTokenModifier::READONLY]) + } + tags::VARIABLE_MUT => SemanticTokenType::VARIABLE, + + tags::TYPE => SemanticTokenType::TYPE, + tags::TYPE_BUILTIN => SemanticTokenType::TYPE, + tags::TYPE_SELF => { + return (SemanticTokenType::TYPE, vec![SemanticTokenModifier::REFERENCE]) + } + tags::TYPE_PARAM => SemanticTokenType::TYPE_PARAMETER, + tags::TYPE_LIFETIME => { + return (SemanticTokenType::LABEL, vec![SemanticTokenModifier::REFERENCE]) + } + + tags::LITERAL_BYTE => SemanticTokenType::NUMBER, + tags::LITERAL_NUMERIC => SemanticTokenType::NUMBER, + tags::LITERAL_CHAR => SemanticTokenType::NUMBER, + + tags::LITERAL_COMMENT => { + return (SemanticTokenType::COMMENT, vec![SemanticTokenModifier::DOCUMENTATION]) + } + + tags::LITERAL_STRING => SemanticTokenType::STRING, + tags::LITERAL_ATTRIBUTE => SemanticTokenType::KEYWORD, + + tags::KEYWORD => SemanticTokenType::KEYWORD, + tags::KEYWORD_UNSAFE => SemanticTokenType::KEYWORD, + tags::KEYWORD_CONTROL => SemanticTokenType::KEYWORD, + unknown => panic!("Unknown semantic token: {}", unknown), + }; + + (token_type, vec![]) + } +} + +impl Conv for (SemanticTokenType, Vec) { + type Output = (u32, u32); + + fn conv(self) -> Self::Output { + let token_index = + semantic_tokens::supported_token_types().iter().position(|it| *it == self.0).unwrap(); + let mut token_modifier_bitset = 0; + for modifier in self.1.iter() { + token_modifier_bitset |= semantic_tokens::supported_token_modifiers() + .iter() + .position(|it| it == modifier) + .unwrap(); + } + + (token_index as u32, token_modifier_bitset as u32) + } +} + impl, CTX> ConvWith for Option { type Output = Option; diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs index 0dae30e46e..a0f9688234 100644 --- a/crates/rust-analyzer/src/lib.rs +++ b/crates/rust-analyzer/src/lib.rs @@ -36,6 +36,7 @@ pub mod req; mod config; mod world; mod diagnostics; +mod semantic_tokens; use serde::de::DeserializeOwned; diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 98306986b2..6e9e604a65 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -528,6 +528,7 @@ fn on_request( .on::(handlers::handle_call_hierarchy_incoming)? .on::(handlers::handle_call_hierarchy_outgoing)? .on::(handlers::handle_ssr)? + .on::(handlers::handle_semantic_tokens)? .finish(); Ok(()) } diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index bb7bab3729..e13e7c95a2 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -16,8 +16,9 @@ use lsp_types::{ CodeAction, CodeActionOrCommand, CodeActionResponse, CodeLens, Command, CompletionItem, Diagnostic, DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, FoldingRangeParams, Hover, HoverContents, Location, MarkupContent, MarkupKind, Position, - PrepareRenameResponse, Range, RenameParams, SymbolInformation, TextDocumentIdentifier, - TextEdit, WorkspaceEdit, + PrepareRenameResponse, Range, RenameParams, SemanticTokenModifier, SemanticTokenType, + SemanticTokens, SemanticTokensParams, SemanticTokensResult, SymbolInformation, + TextDocumentIdentifier, TextEdit, WorkspaceEdit, }; use ra_ide::{ AssistId, FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, @@ -38,6 +39,7 @@ use crate::{ diagnostics::DiagnosticTask, from_json, req::{self, Decoration, InlayHint, InlayHintsParams, InlayKind}, + semantic_tokens::SemanticTokensBuilder, world::WorldSnapshot, LspError, Result, }; @@ -1068,3 +1070,25 @@ pub fn handle_call_hierarchy_outgoing( Ok(Some(res)) } + +pub fn handle_semantic_tokens( + world: WorldSnapshot, + params: SemanticTokensParams, +) -> Result> { + let _p = profile("handle_semantic_tokens"); + + let file_id = params.text_document.try_conv_with(&world)?; + let line_index = world.analysis().file_line_index(file_id)?; + + let mut builder = SemanticTokensBuilder::default(); + + for h in world.analysis().highlight(file_id)?.into_iter() { + let type_and_modifiers: (SemanticTokenType, Vec) = h.tag.conv(); + let (token_type, token_modifiers) = type_and_modifiers.conv(); + builder.push(h.range.conv_with(&line_index), token_type, token_modifiers); + } + + let tokens = SemanticTokens { data: builder.build(), ..Default::default() }; + + Ok(Some(tokens.into())) +} diff --git a/crates/rust-analyzer/src/req.rs b/crates/rust-analyzer/src/req.rs index 7ff7f60b31..3734899bc0 100644 --- a/crates/rust-analyzer/src/req.rs +++ b/crates/rust-analyzer/src/req.rs @@ -12,9 +12,9 @@ pub use lsp_types::{ DocumentSymbolResponse, FileSystemWatcher, Hover, InitializeResult, MessageType, PartialResultParams, ProgressParams, ProgressParamsValue, ProgressToken, PublishDiagnosticsParams, ReferenceParams, Registration, RegistrationParams, SelectionRange, - SelectionRangeParams, ServerCapabilities, ShowMessageParams, SignatureHelp, SymbolKind, - TextDocumentEdit, TextDocumentPositionParams, TextEdit, WorkDoneProgressParams, WorkspaceEdit, - WorkspaceSymbolParams, + SelectionRangeParams, SemanticTokensParams, SemanticTokensResult, ServerCapabilities, + ShowMessageParams, SignatureHelp, SymbolKind, TextDocumentEdit, TextDocumentPositionParams, + TextEdit, WorkDoneProgressParams, WorkspaceEdit, WorkspaceSymbolParams, }; pub enum AnalyzerStatus {} diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs new file mode 100644 index 0000000000..f76605aaa5 --- /dev/null +++ b/crates/rust-analyzer/src/semantic_tokens.rs @@ -0,0 +1,86 @@ +use lsp_types::{Range, SemanticToken, SemanticTokenModifier, SemanticTokenType}; + +const SUPPORTED_TYPES: &[SemanticTokenType] = &[ + SemanticTokenType::COMMENT, + SemanticTokenType::KEYWORD, + SemanticTokenType::STRING, + SemanticTokenType::NUMBER, + SemanticTokenType::REGEXP, + SemanticTokenType::OPERATOR, + SemanticTokenType::NAMESPACE, + SemanticTokenType::TYPE, + SemanticTokenType::STRUCT, + SemanticTokenType::CLASS, + SemanticTokenType::INTERFACE, + SemanticTokenType::ENUM, + SemanticTokenType::TYPE_PARAMETER, + SemanticTokenType::FUNCTION, + SemanticTokenType::MEMBER, + SemanticTokenType::PROPERTY, + SemanticTokenType::MACRO, + SemanticTokenType::VARIABLE, + SemanticTokenType::PARAMETER, + SemanticTokenType::LABEL, +]; + +const SUPPORTED_MODIFIERS: &[SemanticTokenModifier] = &[ + SemanticTokenModifier::DOCUMENTATION, + SemanticTokenModifier::DECLARATION, + SemanticTokenModifier::DEFINITION, + SemanticTokenModifier::REFERENCE, + SemanticTokenModifier::STATIC, + SemanticTokenModifier::ABSTRACT, + SemanticTokenModifier::DEPRECATED, + SemanticTokenModifier::ASYNC, + SemanticTokenModifier::VOLATILE, + SemanticTokenModifier::READONLY, +]; + +pub(crate) fn supported_token_types() -> &'static [SemanticTokenType] { + SUPPORTED_TYPES +} + +pub(crate) fn supported_token_modifiers() -> &'static [SemanticTokenModifier] { + SUPPORTED_MODIFIERS +} + +#[derive(Default)] +pub(crate) struct SemanticTokensBuilder { + prev_line: u32, + prev_char: u32, + data: Vec, +} + +impl SemanticTokensBuilder { + pub fn push(&mut self, range: Range, token_index: u32, modifier_bitset: u32) { + let mut push_line = range.start.line as u32; + let mut push_char = range.start.character as u32; + + if !self.data.is_empty() { + push_line -= self.prev_line; + if push_line == 0 { + push_char -= self.prev_char; + } + } + + // A token cannot be multiline + let token_len = range.end.character - range.start.character; + + let token = SemanticToken { + delta_line: push_line, + delta_start: push_char, + length: token_len as u32, + token_type: token_index, + token_modifiers_bitset: modifier_bitset, + }; + + self.data.push(token); + + self.prev_line = range.start.line as u32; + self.prev_char = range.start.character as u32; + } + + pub fn build(self) -> Vec { + self.data + } +} From 17ffdf9c27a6bb5cf5d30ad6a677390609fcf861 Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Mon, 24 Feb 2020 21:17:20 -0500 Subject: [PATCH 24/28] Add docs --- crates/rust-analyzer/src/semantic_tokens.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs index f76605aaa5..ad000a3ce2 100644 --- a/crates/rust-analyzer/src/semantic_tokens.rs +++ b/crates/rust-analyzer/src/semantic_tokens.rs @@ -1,3 +1,5 @@ +//! Semantic Tokens helpers + use lsp_types::{Range, SemanticToken, SemanticTokenModifier, SemanticTokenType}; const SUPPORTED_TYPES: &[SemanticTokenType] = &[ @@ -36,14 +38,19 @@ const SUPPORTED_MODIFIERS: &[SemanticTokenModifier] = &[ SemanticTokenModifier::READONLY, ]; +/// Token types that the server supports pub(crate) fn supported_token_types() -> &'static [SemanticTokenType] { SUPPORTED_TYPES } +/// Token modifiers that the server supports pub(crate) fn supported_token_modifiers() -> &'static [SemanticTokenModifier] { SUPPORTED_MODIFIERS } +/// Tokens are encoded relative to each other. +/// +/// This is a direct port of https://github.com/microsoft/vscode-languageserver-node/blob/f425af9de46a0187adb78ec8a46b9b2ce80c5412/server/src/sematicTokens.proposed.ts#L45 #[derive(Default)] pub(crate) struct SemanticTokensBuilder { prev_line: u32, @@ -52,6 +59,7 @@ pub(crate) struct SemanticTokensBuilder { } impl SemanticTokensBuilder { + /// Push a new token onto the builder pub fn push(&mut self, range: Range, token_index: u32, modifier_bitset: u32) { let mut push_line = range.start.line as u32; let mut push_char = range.start.character as u32; From 136151515abffabdedbe0087f8fc21a67c071dc6 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 25 Feb 2020 12:42:44 +0100 Subject: [PATCH 25/28] Replace generic with a concrete type --- crates/ra_assists/src/ast_transform.rs | 25 +++++++++++---------- crates/rust-analyzer/src/semantic_tokens.rs | 2 +- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/crates/ra_assists/src/ast_transform.rs b/crates/ra_assists/src/ast_transform.rs index 56b7588efb..c6d15af5fc 100644 --- a/crates/ra_assists/src/ast_transform.rs +++ b/crates/ra_assists/src/ast_transform.rs @@ -1,7 +1,8 @@ //! `AstTransformer`s are functions that replace nodes in an AST and can be easily combined. use rustc_hash::FxHashMap; -use hir::{db::HirDatabase, InFile, PathResolution}; +use hir::{InFile, PathResolution}; +use ra_ide_db::RootDatabase; use ra_syntax::ast::{self, AstNode}; pub trait AstTransform<'a> { @@ -33,18 +34,18 @@ impl<'a> AstTransform<'a> for NullTransformer { } } -pub struct SubstituteTypeParams<'a, DB: HirDatabase> { - db: &'a DB, +pub struct SubstituteTypeParams<'a> { + db: &'a RootDatabase, substs: FxHashMap, previous: Box + 'a>, } -impl<'a, DB: HirDatabase> SubstituteTypeParams<'a, DB> { +impl<'a> SubstituteTypeParams<'a> { pub fn for_trait_impl( - db: &'a DB, + db: &'a RootDatabase, trait_: hir::Trait, impl_block: ast::ImplBlock, - ) -> SubstituteTypeParams<'a, DB> { + ) -> SubstituteTypeParams<'a> { let substs = get_syntactic_substs(impl_block).unwrap_or_default(); let generic_def: hir::GenericDef = trait_.into(); let substs_by_param: FxHashMap<_, _> = generic_def @@ -95,7 +96,7 @@ impl<'a, DB: HirDatabase> SubstituteTypeParams<'a, DB> { } } -impl<'a, DB: HirDatabase> AstTransform<'a> for SubstituteTypeParams<'a, DB> { +impl<'a> AstTransform<'a> for SubstituteTypeParams<'a> { fn get_substitution( &self, node: InFile<&ra_syntax::SyntaxNode>, @@ -107,14 +108,14 @@ impl<'a, DB: HirDatabase> AstTransform<'a> for SubstituteTypeParams<'a, DB> { } } -pub struct QualifyPaths<'a, DB: HirDatabase> { - db: &'a DB, +pub struct QualifyPaths<'a> { + db: &'a RootDatabase, from: Option, previous: Box + 'a>, } -impl<'a, DB: HirDatabase> QualifyPaths<'a, DB> { - pub fn new(db: &'a DB, from: Option) -> Self { +impl<'a> QualifyPaths<'a> { + pub fn new(db: &'a RootDatabase, from: Option) -> Self { Self { db, from, previous: Box::new(NullTransformer) } } @@ -168,7 +169,7 @@ pub fn apply<'a, N: AstNode>(transformer: &dyn AstTransform<'a>, node: InFile N::cast(result).unwrap() } -impl<'a, DB: HirDatabase> AstTransform<'a> for QualifyPaths<'a, DB> { +impl<'a> AstTransform<'a> for QualifyPaths<'a> { fn get_substitution( &self, node: InFile<&ra_syntax::SyntaxNode>, diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs index ad000a3ce2..e6a8eb146f 100644 --- a/crates/rust-analyzer/src/semantic_tokens.rs +++ b/crates/rust-analyzer/src/semantic_tokens.rs @@ -49,7 +49,7 @@ pub(crate) fn supported_token_modifiers() -> &'static [SemanticTokenModifier] { } /// Tokens are encoded relative to each other. -/// +/// /// This is a direct port of https://github.com/microsoft/vscode-languageserver-node/blob/f425af9de46a0187adb78ec8a46b9b2ce80c5412/server/src/sematicTokens.proposed.ts#L45 #[derive(Default)] pub(crate) struct SemanticTokensBuilder { From 6542ab89ceb32d6ec108a28ad9d938d24762c029 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 25 Feb 2020 13:49:34 +0100 Subject: [PATCH 26/28] Simplify --- crates/ra_ide/src/call_hierarchy.rs | 20 ++++++------------- .../ra_ide/src/display/navigation_target.rs | 2 +- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/crates/ra_ide/src/call_hierarchy.rs b/crates/ra_ide/src/call_hierarchy.rs index f984f40ad7..51ac59a718 100644 --- a/crates/ra_ide/src/call_hierarchy.rs +++ b/crates/ra_ide/src/call_hierarchy.rs @@ -4,16 +4,11 @@ use indexmap::IndexMap; use hir::db::AstDatabase; use ra_ide_db::RootDatabase; -use ra_syntax::{ - ast::{self, DocCommentsOwner}, - match_ast, AstNode, TextRange, -}; +use ra_syntax::{ast, match_ast, AstNode, TextRange}; use crate::{ - call_info::FnCallNode, - display::{ShortLabel, ToNav}, - expand::descend_into_macros, - goto_definition, references, FilePosition, NavigationTarget, RangeInfo, + call_info::FnCallNode, display::ToNav, expand::descend_into_macros, goto_definition, + references, FilePosition, NavigationTarget, RangeInfo, }; #[derive(Debug, Clone)] @@ -49,6 +44,7 @@ pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Optio let refs = references::find_all_refs(db, position, None)?; let mut calls = CallLocations::default(); + let mut sb = hir::SourceBinder::new(db); for reference in refs.info.references() { let file_id = reference.file_range.file_id; @@ -62,12 +58,8 @@ pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Optio match_ast! { match node { ast::FnDef(it) => { - Some(NavigationTarget::from_named( - db, - token.with_value(&it), - it.doc_comment_text(), - it.short_label(), - )) + let def = sb.to_def(token.with_value(it))?; + Some(def.to_nav(sb.db)) }, _ => { None }, } diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs index b42cb477e3..c9d0058a62 100644 --- a/crates/ra_ide/src/display/navigation_target.rs +++ b/crates/ra_ide/src/display/navigation_target.rs @@ -125,7 +125,7 @@ impl NavigationTarget { } /// Allows `NavigationTarget` to be created from a `NameOwner` - pub(crate) fn from_named( + fn from_named( db: &RootDatabase, node: InFile<&dyn ast::NameOwner>, docs: Option, From 469011169bb2579ca8d7c16eefd2fe297136f976 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 25 Feb 2020 14:44:51 +0100 Subject: [PATCH 27/28] :arrow_up: rowan --- Cargo.lock | 4 ++-- crates/ra_syntax/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 04023c6cd1..e5400f5ebd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1308,9 +1308,9 @@ dependencies = [ [[package]] name = "rowan" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d03d4eff7a4e8dcc362e4c06bb2b1b33af4bcd64336c7f40a31a05850336b6c" +checksum = "1ea7cadf87a9d8432e85cb4eb86bd2e765ace60c24ef86e79084dcae5d1c5a19" dependencies = [ "rustc-hash", "smol_str", diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml index 7891628dcd..8efc6b368a 100644 --- a/crates/ra_syntax/Cargo.toml +++ b/crates/ra_syntax/Cargo.toml @@ -12,7 +12,7 @@ doctest = false [dependencies] itertools = "0.8.2" -rowan = "0.9.0" +rowan = "0.9.1" rustc_lexer = "0.1.0" rustc-hash = "1.1.0" arrayvec = "0.5.1" From d7da42bd402aedb167bfb33aec7ce61279716ff7 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 25 Feb 2020 14:59:13 +0100 Subject: [PATCH 28/28] Simplify --- crates/ra_ide/src/extend_selection.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/crates/ra_ide/src/extend_selection.rs b/crates/ra_ide/src/extend_selection.rs index 4757d8e22d..1e7d0621a6 100644 --- a/crates/ra_ide/src/extend_selection.rs +++ b/crates/ra_ide/src/extend_selection.rs @@ -145,25 +145,25 @@ fn extend_tokens_from_range( let src = db.parse_or_expand(expanded.file_id)?; let parent = shallowest_node(&find_covering_element(&src, expanded.value))?.parent()?; - let validate = |token: SyntaxToken| { + let validate = |token: &SyntaxToken| { let node = descend_into_macros(db, file_id, token.clone()); - if node.file_id == expanded.file_id + node.file_id == expanded.file_id && node.value.text_range().is_subrange(&parent.text_range()) - { - Some(token) - } else { - None - } }; // Find the first and last text range under expanded parent let first = successors(Some(first_token), |token| { - validate(skip_whitespace(token.prev_token()?, Direction::Prev)?) + let token = token.prev_token()?; + skip_whitespace(token, Direction::Prev) }) + .take_while(validate) .last()?; + let last = successors(Some(last_token), |token| { - validate(skip_whitespace(token.next_token()?, Direction::Next)?) + let token = token.next_token()?; + skip_whitespace(token, Direction::Next) }) + .take_while(validate) .last()?; let range = union_range(first.text_range(), last.text_range()); @@ -334,10 +334,12 @@ fn adj_comments(comment: &ast::Comment, dir: Direction) -> ast::Comment { #[cfg(test)] mod tests { - use super::*; - use crate::mock_analysis::single_file; use test_utils::extract_offset; + use crate::mock_analysis::single_file; + + use super::*; + fn do_check(before: &str, afters: &[&str]) { let (cursor, before) = extract_offset(before); let (analysis, file_id) = single_file(&before);