⬆️ rust-analyzer
This commit is contained in:
@@ -93,6 +93,7 @@ fn try_main() -> Result<()> {
|
||||
flags::RustAnalyzerCmd::Ssr(cmd) => cmd.run()?,
|
||||
flags::RustAnalyzerCmd::Search(cmd) => cmd.run()?,
|
||||
flags::RustAnalyzerCmd::Lsif(cmd) => cmd.run()?,
|
||||
flags::RustAnalyzerCmd::Scip(cmd) => cmd.run()?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ mod analysis_stats;
|
||||
mod diagnostics;
|
||||
mod ssr;
|
||||
mod lsif;
|
||||
mod scip;
|
||||
|
||||
mod progress_report;
|
||||
|
||||
|
||||
@@ -112,6 +112,10 @@ xflags::xflags! {
|
||||
cmd lsif
|
||||
required path: PathBuf
|
||||
{}
|
||||
|
||||
cmd scip
|
||||
required path: PathBuf
|
||||
{}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,6 +144,7 @@ pub enum RustAnalyzerCmd {
|
||||
Search(Search),
|
||||
ProcMacro(ProcMacro),
|
||||
Lsif(Lsif),
|
||||
Scip(Scip),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -207,6 +212,11 @@ pub struct Lsif {
|
||||
pub path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Scip {
|
||||
pub path: PathBuf,
|
||||
}
|
||||
|
||||
impl RustAnalyzer {
|
||||
pub const HELP: &'static str = Self::HELP_;
|
||||
|
||||
|
||||
448
crates/rust-analyzer/src/cli/scip.rs
Normal file
448
crates/rust-analyzer/src/cli/scip.rs
Normal file
@@ -0,0 +1,448 @@
|
||||
//! SCIP generator
|
||||
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
use crate::line_index::{LineEndings, LineIndex, OffsetEncoding};
|
||||
use hir::Name;
|
||||
use ide::{
|
||||
LineCol, MonikerDescriptorKind, MonikerResult, StaticIndex, StaticIndexedFile, TextRange,
|
||||
TokenId,
|
||||
};
|
||||
use ide_db::LineIndexDatabase;
|
||||
use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace};
|
||||
use scip::types as scip_types;
|
||||
use std::env;
|
||||
|
||||
use crate::cli::{
|
||||
flags,
|
||||
load_cargo::{load_workspace, LoadCargoConfig},
|
||||
Result,
|
||||
};
|
||||
|
||||
impl flags::Scip {
|
||||
pub fn run(self) -> Result<()> {
|
||||
eprintln!("Generating SCIP start...");
|
||||
let now = Instant::now();
|
||||
let cargo_config = CargoConfig::default();
|
||||
|
||||
let no_progress = &|s| (eprintln!("rust-analyzer: Loading {}", s));
|
||||
let load_cargo_config = LoadCargoConfig {
|
||||
load_out_dirs_from_check: true,
|
||||
with_proc_macro: true,
|
||||
prefill_caches: true,
|
||||
};
|
||||
let path = vfs::AbsPathBuf::assert(env::current_dir()?.join(&self.path));
|
||||
let rootpath = path.normalize();
|
||||
let manifest = ProjectManifest::discover_single(&path)?;
|
||||
|
||||
let workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress)?;
|
||||
|
||||
let (host, vfs, _) = load_workspace(workspace, &load_cargo_config)?;
|
||||
let db = host.raw_database();
|
||||
let analysis = host.analysis();
|
||||
|
||||
let si = StaticIndex::compute(&analysis);
|
||||
|
||||
let mut index = scip_types::Index {
|
||||
metadata: Some(scip_types::Metadata {
|
||||
version: scip_types::ProtocolVersion::UnspecifiedProtocolVersion.into(),
|
||||
tool_info: Some(scip_types::ToolInfo {
|
||||
name: "rust-analyzer".to_owned(),
|
||||
version: "0.1".to_owned(),
|
||||
arguments: vec![],
|
||||
..Default::default()
|
||||
})
|
||||
.into(),
|
||||
project_root: format!(
|
||||
"file://{}",
|
||||
path.normalize()
|
||||
.as_os_str()
|
||||
.to_str()
|
||||
.ok_or(anyhow::anyhow!("Unable to normalize project_root path"))?
|
||||
.to_string()
|
||||
),
|
||||
text_document_encoding: scip_types::TextEncoding::UTF8.into(),
|
||||
..Default::default()
|
||||
})
|
||||
.into(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let mut symbols_emitted: HashSet<TokenId> = HashSet::default();
|
||||
let mut tokens_to_symbol: HashMap<TokenId, String> = HashMap::new();
|
||||
|
||||
for file in si.files {
|
||||
let mut local_count = 0;
|
||||
let mut new_local_symbol = || {
|
||||
let new_symbol = scip::types::Symbol::new_local(local_count);
|
||||
local_count += 1;
|
||||
|
||||
new_symbol
|
||||
};
|
||||
|
||||
let StaticIndexedFile { file_id, tokens, .. } = file;
|
||||
let relative_path = match get_relative_filepath(&vfs, &rootpath, file_id) {
|
||||
Some(relative_path) => relative_path,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let line_index = LineIndex {
|
||||
index: db.line_index(file_id),
|
||||
encoding: OffsetEncoding::Utf8,
|
||||
endings: LineEndings::Unix,
|
||||
};
|
||||
|
||||
let mut doc = scip_types::Document {
|
||||
relative_path,
|
||||
language: "rust".to_string(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
tokens.into_iter().for_each(|(range, id)| {
|
||||
let token = si.tokens.get(id).unwrap();
|
||||
|
||||
let mut occurrence = scip_types::Occurrence::default();
|
||||
occurrence.range = text_range_to_scip_range(&line_index, range);
|
||||
occurrence.symbol = match tokens_to_symbol.get(&id) {
|
||||
Some(symbol) => symbol.clone(),
|
||||
None => {
|
||||
let symbol = match &token.moniker {
|
||||
Some(moniker) => moniker_to_symbol(&moniker),
|
||||
None => new_local_symbol(),
|
||||
};
|
||||
|
||||
let symbol = scip::symbol::format_symbol(symbol);
|
||||
tokens_to_symbol.insert(id, symbol.clone());
|
||||
symbol
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(def) = token.definition {
|
||||
if def.range == range {
|
||||
occurrence.symbol_roles |= scip_types::SymbolRole::Definition as i32;
|
||||
}
|
||||
|
||||
if !symbols_emitted.contains(&id) {
|
||||
symbols_emitted.insert(id);
|
||||
|
||||
let mut symbol_info = scip_types::SymbolInformation::default();
|
||||
symbol_info.symbol = occurrence.symbol.clone();
|
||||
if let Some(hover) = &token.hover {
|
||||
if !hover.markup.as_str().is_empty() {
|
||||
symbol_info.documentation = vec![hover.markup.as_str().to_string()];
|
||||
}
|
||||
}
|
||||
|
||||
doc.symbols.push(symbol_info)
|
||||
}
|
||||
}
|
||||
|
||||
doc.occurrences.push(occurrence);
|
||||
});
|
||||
|
||||
if doc.occurrences.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
index.documents.push(doc);
|
||||
}
|
||||
|
||||
scip::write_message_to_file("index.scip", index)
|
||||
.map_err(|err| anyhow::anyhow!("Failed to write scip to file: {}", err))?;
|
||||
|
||||
eprintln!("Generating SCIP finished {:?}", now.elapsed());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_relative_filepath(
|
||||
vfs: &vfs::Vfs,
|
||||
rootpath: &vfs::AbsPathBuf,
|
||||
file_id: ide::FileId,
|
||||
) -> Option<String> {
|
||||
Some(vfs.file_path(file_id).as_path()?.strip_prefix(&rootpath)?.as_ref().to_str()?.to_string())
|
||||
}
|
||||
|
||||
// SCIP Ranges have a (very large) optimization that ranges if they are on the same line
|
||||
// only encode as a vector of [start_line, start_col, end_col].
|
||||
//
|
||||
// This transforms a line index into the optimized SCIP Range.
|
||||
fn text_range_to_scip_range(line_index: &LineIndex, range: TextRange) -> Vec<i32> {
|
||||
let LineCol { line: start_line, col: start_col } = line_index.index.line_col(range.start());
|
||||
let LineCol { line: end_line, col: end_col } = line_index.index.line_col(range.end());
|
||||
|
||||
if start_line == end_line {
|
||||
vec![start_line as i32, start_col as i32, end_col as i32]
|
||||
} else {
|
||||
vec![start_line as i32, start_col as i32, end_line as i32, end_col as i32]
|
||||
}
|
||||
}
|
||||
|
||||
fn new_descriptor_str(
|
||||
name: &str,
|
||||
suffix: scip_types::descriptor::Suffix,
|
||||
) -> scip_types::Descriptor {
|
||||
scip_types::Descriptor {
|
||||
name: name.to_string(),
|
||||
disambiguator: "".to_string(),
|
||||
suffix: suffix.into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn new_descriptor(name: Name, suffix: scip_types::descriptor::Suffix) -> scip_types::Descriptor {
|
||||
let mut name = name.to_string();
|
||||
if name.contains("'") {
|
||||
name = format!("`{}`", name);
|
||||
}
|
||||
|
||||
new_descriptor_str(name.as_str(), suffix)
|
||||
}
|
||||
|
||||
/// Loosely based on `def_to_moniker`
|
||||
///
|
||||
/// Only returns a Symbol when it's a non-local symbol.
|
||||
/// So if the visibility isn't outside of a document, then it will return None
|
||||
fn moniker_to_symbol(moniker: &MonikerResult) -> scip_types::Symbol {
|
||||
use scip_types::descriptor::Suffix::*;
|
||||
|
||||
let package_name = moniker.package_information.name.clone();
|
||||
let version = moniker.package_information.version.clone();
|
||||
let descriptors = moniker
|
||||
.identifier
|
||||
.description
|
||||
.iter()
|
||||
.map(|desc| {
|
||||
new_descriptor(
|
||||
desc.name.clone(),
|
||||
match desc.desc {
|
||||
MonikerDescriptorKind::Namespace => Namespace,
|
||||
MonikerDescriptorKind::Type => Type,
|
||||
MonikerDescriptorKind::Term => Term,
|
||||
MonikerDescriptorKind::Method => Method,
|
||||
MonikerDescriptorKind::TypeParameter => TypeParameter,
|
||||
MonikerDescriptorKind::Parameter => Parameter,
|
||||
MonikerDescriptorKind::Macro => Macro,
|
||||
MonikerDescriptorKind::Meta => Meta,
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
scip_types::Symbol {
|
||||
scheme: "rust-analyzer".into(),
|
||||
package: Some(scip_types::Package {
|
||||
manager: "cargo".to_string(),
|
||||
name: package_name,
|
||||
version,
|
||||
..Default::default()
|
||||
})
|
||||
.into(),
|
||||
descriptors,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use hir::Semantics;
|
||||
use ide::{AnalysisHost, FilePosition};
|
||||
use ide_db::defs::IdentClass;
|
||||
use ide_db::{base_db::fixture::ChangeFixture, helpers::pick_best_token};
|
||||
use scip::symbol::format_symbol;
|
||||
use syntax::SyntaxKind::*;
|
||||
use syntax::{AstNode, T};
|
||||
|
||||
fn position(ra_fixture: &str) -> (AnalysisHost, FilePosition) {
|
||||
let mut host = AnalysisHost::default();
|
||||
let change_fixture = ChangeFixture::parse(ra_fixture);
|
||||
host.raw_database_mut().apply_change(change_fixture.change);
|
||||
let (file_id, range_or_offset) =
|
||||
change_fixture.file_position.expect("expected a marker ($0)");
|
||||
let offset = range_or_offset.expect_offset();
|
||||
(host, FilePosition { file_id, offset })
|
||||
}
|
||||
|
||||
/// If expected == "", then assert that there are no symbols (this is basically local symbol)
|
||||
#[track_caller]
|
||||
fn check_symbol(ra_fixture: &str, expected: &str) {
|
||||
let (host, position) = position(ra_fixture);
|
||||
|
||||
let FilePosition { file_id, offset } = position;
|
||||
|
||||
let db = host.raw_database();
|
||||
let sema = &Semantics::new(db);
|
||||
let file = sema.parse(file_id).syntax().clone();
|
||||
let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
|
||||
IDENT
|
||||
| INT_NUMBER
|
||||
| LIFETIME_IDENT
|
||||
| T![self]
|
||||
| T![super]
|
||||
| T![crate]
|
||||
| T![Self]
|
||||
| COMMENT => 2,
|
||||
kind if kind.is_trivia() => 0,
|
||||
_ => 1,
|
||||
})
|
||||
.expect("OK OK");
|
||||
|
||||
let navs = sema
|
||||
.descend_into_macros(original_token.clone())
|
||||
.into_iter()
|
||||
.filter_map(|token| {
|
||||
IdentClass::classify_token(sema, &token).map(IdentClass::definitions).map(|it| {
|
||||
it.into_iter().flat_map(|def| {
|
||||
let module = def.module(db).unwrap();
|
||||
let current_crate = module.krate();
|
||||
|
||||
match MonikerResult::from_def(sema.db, def, current_crate) {
|
||||
Some(moniker_result) => Some(moniker_to_symbol(&moniker_result)),
|
||||
None => None,
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if expected == "" {
|
||||
assert_eq!(0, navs.len(), "must have no symbols {:?}", navs);
|
||||
return;
|
||||
}
|
||||
|
||||
assert_eq!(1, navs.len(), "must have one symbol {:?}", navs);
|
||||
|
||||
let res = navs.get(0).unwrap();
|
||||
let formatted = format_symbol(res.clone());
|
||||
assert_eq!(formatted, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic() {
|
||||
check_symbol(
|
||||
r#"
|
||||
//- /lib.rs crate:main deps:foo
|
||||
use foo::example_mod::func;
|
||||
fn main() {
|
||||
func$0();
|
||||
}
|
||||
//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
|
||||
pub mod example_mod {
|
||||
pub fn func() {}
|
||||
}
|
||||
"#,
|
||||
"rust-analyzer cargo foo 0.1.0 example_mod/func().",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn symbol_for_trait() {
|
||||
check_symbol(
|
||||
r#"
|
||||
//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
|
||||
pub mod module {
|
||||
pub trait MyTrait {
|
||||
pub fn func$0() {}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
"rust-analyzer cargo foo 0.1.0 module/MyTrait#func().",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn symbol_for_trait_constant() {
|
||||
check_symbol(
|
||||
r#"
|
||||
//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
|
||||
pub mod module {
|
||||
pub trait MyTrait {
|
||||
const MY_CONST$0: u8;
|
||||
}
|
||||
}
|
||||
"#,
|
||||
"rust-analyzer cargo foo 0.1.0 module/MyTrait#MY_CONST.",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn symbol_for_trait_type() {
|
||||
check_symbol(
|
||||
r#"
|
||||
//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
|
||||
pub mod module {
|
||||
pub trait MyTrait {
|
||||
type MyType$0;
|
||||
}
|
||||
}
|
||||
"#,
|
||||
// "foo::module::MyTrait::MyType",
|
||||
"rust-analyzer cargo foo 0.1.0 module/MyTrait#[MyType]",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn symbol_for_trait_impl_function() {
|
||||
check_symbol(
|
||||
r#"
|
||||
//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
|
||||
pub mod module {
|
||||
pub trait MyTrait {
|
||||
pub fn func() {}
|
||||
}
|
||||
|
||||
struct MyStruct {}
|
||||
|
||||
impl MyTrait for MyStruct {
|
||||
pub fn func$0() {}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
// "foo::module::MyStruct::MyTrait::func",
|
||||
"rust-analyzer cargo foo 0.1.0 module/MyStruct#MyTrait#func().",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn symbol_for_field() {
|
||||
check_symbol(
|
||||
r#"
|
||||
//- /lib.rs crate:main deps:foo
|
||||
use foo::St;
|
||||
fn main() {
|
||||
let x = St { a$0: 2 };
|
||||
}
|
||||
//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
|
||||
pub struct St {
|
||||
pub a: i32,
|
||||
}
|
||||
"#,
|
||||
"rust-analyzer cargo foo 0.1.0 St#a.",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn local_symbol_for_local() {
|
||||
check_symbol(
|
||||
r#"
|
||||
//- /lib.rs crate:main deps:foo
|
||||
use foo::module::func;
|
||||
fn main() {
|
||||
func();
|
||||
}
|
||||
//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
|
||||
pub mod module {
|
||||
pub fn func() {
|
||||
let x$0 = 2;
|
||||
}
|
||||
}
|
||||
"#,
|
||||
"",
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,8 @@ use std::{ffi::OsString, fmt, iter, path::PathBuf};
|
||||
use flycheck::FlycheckConfig;
|
||||
use ide::{
|
||||
AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode,
|
||||
HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayHintsConfig, JoinLinesConfig,
|
||||
Snippet, SnippetScope,
|
||||
HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayHintsConfig,
|
||||
JoinLinesConfig, Snippet, SnippetScope,
|
||||
};
|
||||
use ide_db::{
|
||||
imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
|
||||
@@ -385,6 +385,34 @@ config_data! {
|
||||
/// available on a nightly build.
|
||||
rustfmt_rangeFormatting_enable: bool = "false",
|
||||
|
||||
/// Inject additional highlighting into doc comments.
|
||||
///
|
||||
/// When enabled, rust-analyzer will highlight rust source in doc comments as well as intra
|
||||
/// doc links.
|
||||
semanticHighlighting_doc_comment_inject_enable: bool = "true",
|
||||
/// Use semantic tokens for operators.
|
||||
///
|
||||
/// When disabled, rust-analyzer will emit semantic tokens only for operator tokens when
|
||||
/// they are tagged with modifiers.
|
||||
semanticHighlighting_operator_enable: bool = "true",
|
||||
/// Use specialized semantic tokens for operators.
|
||||
///
|
||||
/// When enabled, rust-analyzer will emit special token types for operator tokens instead
|
||||
/// of the generic `operator` token type.
|
||||
semanticHighlighting_operator_specialization_enable: bool = "false",
|
||||
/// Use semantic tokens for punctuations.
|
||||
///
|
||||
/// When disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when
|
||||
/// they are tagged with modifiers or have a special role.
|
||||
semanticHighlighting_punctuation_enable: bool = "false",
|
||||
/// When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro
|
||||
/// calls.
|
||||
semanticHighlighting_punctuation_separate_macro_bang: bool = "false",
|
||||
/// Use specialized semantic tokens for punctuations.
|
||||
///
|
||||
/// When enabled, rust-analyzer will emit special token types for punctuation tokens instead
|
||||
/// of the generic `punctuation` token type.
|
||||
semanticHighlighting_punctuation_specialization_enable: bool = "false",
|
||||
/// Use semantic tokens for strings.
|
||||
///
|
||||
/// In some editors (e.g. vscode) semantic tokens override other highlighting grammars.
|
||||
@@ -1171,8 +1199,19 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn highlighting_strings(&self) -> bool {
|
||||
self.data.semanticHighlighting_strings_enable
|
||||
pub fn highlighting_config(&self) -> HighlightConfig {
|
||||
HighlightConfig {
|
||||
strings: self.data.semanticHighlighting_strings_enable,
|
||||
punctuation: self.data.semanticHighlighting_punctuation_enable,
|
||||
specialize_punctuation: self
|
||||
.data
|
||||
.semanticHighlighting_punctuation_specialization_enable,
|
||||
macro_bang: self.data.semanticHighlighting_punctuation_separate_macro_bang,
|
||||
operator: self.data.semanticHighlighting_operator_enable,
|
||||
specialize_operator: self.data.semanticHighlighting_operator_specialization_enable,
|
||||
inject_doc_comment: self.data.semanticHighlighting_doc_comment_inject_enable,
|
||||
syntactic_name_ref_highlighting: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hover(&self) -> HoverConfig {
|
||||
|
||||
@@ -4,11 +4,12 @@ pub(crate) mod to_proto;
|
||||
use std::{mem, sync::Arc};
|
||||
|
||||
use ide::FileId;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use ide_db::FxHashMap;
|
||||
use stdx::hash::{NoHashHashMap, NoHashHashSet};
|
||||
|
||||
use crate::lsp_ext;
|
||||
|
||||
pub(crate) type CheckFixes = Arc<FxHashMap<usize, FxHashMap<FileId, Vec<Fix>>>>;
|
||||
pub(crate) type CheckFixes = Arc<NoHashHashMap<usize, NoHashHashMap<FileId, Vec<Fix>>>>;
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct DiagnosticsMapConfig {
|
||||
@@ -19,12 +20,12 @@ pub struct DiagnosticsMapConfig {
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub(crate) struct DiagnosticCollection {
|
||||
// FIXME: should be FxHashMap<FileId, Vec<ra_id::Diagnostic>>
|
||||
pub(crate) native: FxHashMap<FileId, Vec<lsp_types::Diagnostic>>,
|
||||
// FIXME: should be NoHashHashMap<FileId, Vec<ra_id::Diagnostic>>
|
||||
pub(crate) native: NoHashHashMap<FileId, Vec<lsp_types::Diagnostic>>,
|
||||
// FIXME: should be Vec<flycheck::Diagnostic>
|
||||
pub(crate) check: FxHashMap<usize, FxHashMap<FileId, Vec<lsp_types::Diagnostic>>>,
|
||||
pub(crate) check: NoHashHashMap<usize, NoHashHashMap<FileId, Vec<lsp_types::Diagnostic>>>,
|
||||
pub(crate) check_fixes: CheckFixes,
|
||||
changes: FxHashSet<FileId>,
|
||||
changes: NoHashHashSet<FileId>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -105,7 +106,7 @@ impl DiagnosticCollection {
|
||||
native.chain(check)
|
||||
}
|
||||
|
||||
pub(crate) fn take_changes(&mut self) -> Option<FxHashSet<FileId>> {
|
||||
pub(crate) fn take_changes(&mut self) -> Option<NoHashHashSet<FileId>> {
|
||||
if self.changes.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ use parking_lot::{Mutex, RwLock};
|
||||
use proc_macro_api::ProcMacroServer;
|
||||
use project_model::{CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts};
|
||||
use rustc_hash::FxHashMap;
|
||||
use stdx::hash::NoHashHashMap;
|
||||
use vfs::AnchoredPathBuf;
|
||||
|
||||
use crate::{
|
||||
@@ -67,7 +68,7 @@ pub(crate) struct GlobalState {
|
||||
pub(crate) flycheck_sender: Sender<flycheck::Message>,
|
||||
pub(crate) flycheck_receiver: Receiver<flycheck::Message>,
|
||||
|
||||
pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
|
||||
pub(crate) vfs: Arc<RwLock<(vfs::Vfs, NoHashHashMap<FileId, LineEndings>)>>,
|
||||
pub(crate) vfs_config_version: u32,
|
||||
pub(crate) vfs_progress_config_version: u32,
|
||||
pub(crate) vfs_progress_n_total: usize,
|
||||
@@ -113,7 +114,7 @@ pub(crate) struct GlobalStateSnapshot {
|
||||
pub(crate) check_fixes: CheckFixes,
|
||||
mem_docs: MemDocs,
|
||||
pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
|
||||
vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
|
||||
vfs: Arc<RwLock<(vfs::Vfs, NoHashHashMap<FileId, LineEndings>)>>,
|
||||
pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
|
||||
}
|
||||
|
||||
@@ -157,7 +158,7 @@ impl GlobalState {
|
||||
flycheck_sender,
|
||||
flycheck_receiver,
|
||||
|
||||
vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))),
|
||||
vfs: Arc::new(RwLock::new((vfs::Vfs::default(), NoHashHashMap::default()))),
|
||||
vfs_config_version: 0,
|
||||
vfs_progress_config_version: 0,
|
||||
vfs_progress_n_total: 0,
|
||||
|
||||
@@ -1504,10 +1504,8 @@ pub(crate) fn handle_semantic_tokens_full(
|
||||
let text = snap.analysis.file_text(file_id)?;
|
||||
let line_index = snap.file_line_index(file_id)?;
|
||||
|
||||
let highlights = snap.analysis.highlight(file_id)?;
|
||||
let highlight_strings = snap.config.highlighting_strings();
|
||||
let semantic_tokens =
|
||||
to_proto::semantic_tokens(&text, &line_index, highlights, highlight_strings);
|
||||
let highlights = snap.analysis.highlight(snap.config.highlighting_config(), file_id)?;
|
||||
let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
|
||||
|
||||
// Unconditionally cache the tokens
|
||||
snap.semantic_tokens_cache.lock().insert(params.text_document.uri, semantic_tokens.clone());
|
||||
@@ -1525,10 +1523,8 @@ pub(crate) fn handle_semantic_tokens_full_delta(
|
||||
let text = snap.analysis.file_text(file_id)?;
|
||||
let line_index = snap.file_line_index(file_id)?;
|
||||
|
||||
let highlights = snap.analysis.highlight(file_id)?;
|
||||
let highlight_strings = snap.config.highlighting_strings();
|
||||
let semantic_tokens =
|
||||
to_proto::semantic_tokens(&text, &line_index, highlights, highlight_strings);
|
||||
let highlights = snap.analysis.highlight(snap.config.highlighting_config(), file_id)?;
|
||||
let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
|
||||
|
||||
let mut cache = snap.semantic_tokens_cache.lock();
|
||||
let cached_tokens = cache.entry(params.text_document.uri).or_default();
|
||||
@@ -1556,10 +1552,8 @@ pub(crate) fn handle_semantic_tokens_range(
|
||||
let text = snap.analysis.file_text(frange.file_id)?;
|
||||
let line_index = snap.file_line_index(frange.file_id)?;
|
||||
|
||||
let highlights = snap.analysis.highlight_range(frange)?;
|
||||
let highlight_strings = snap.config.highlighting_strings();
|
||||
let semantic_tokens =
|
||||
to_proto::semantic_tokens(&text, &line_index, highlights, highlight_strings);
|
||||
let highlights = snap.analysis.highlight_range(snap.config.highlighting_config(), frange)?;
|
||||
let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
|
||||
Ok(Some(semantic_tokens.into()))
|
||||
}
|
||||
|
||||
|
||||
@@ -328,8 +328,33 @@ impl GlobalState {
|
||||
}
|
||||
|
||||
let uri = file_id_to_url(&self.vfs.read().0, file_id);
|
||||
let diagnostics =
|
||||
let mut diagnostics =
|
||||
self.diagnostics.diagnostics_for(file_id).cloned().collect::<Vec<_>>();
|
||||
|
||||
// VSCode assumes diagnostic messages to be non-empty strings, so we need to patch
|
||||
// empty diagnostics. Neither the docs of VSCode nor the LSP spec say whether
|
||||
// diagnostic messages are actually allowed to be empty or not and patching this
|
||||
// in the VSCode client does not work as the assertion happens in the protocol
|
||||
// conversion. So this hack is here to stay, and will be considered a hack
|
||||
// until the LSP decides to state that empty messages are allowed.
|
||||
|
||||
// See https://github.com/rust-lang/rust-analyzer/issues/11404
|
||||
// See https://github.com/rust-lang/rust-analyzer/issues/13130
|
||||
let patch_empty = |message: &mut String| {
|
||||
if message.is_empty() {
|
||||
*message = " ".to_string();
|
||||
}
|
||||
};
|
||||
|
||||
for d in &mut diagnostics {
|
||||
patch_empty(&mut d.message);
|
||||
if let Some(dri) = &mut d.related_information {
|
||||
for dri in dri {
|
||||
patch_empty(&mut dri.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let version = from_proto::vfs_path(&uri)
|
||||
.map(|path| self.mem_docs.get(&path).map(|it| it.version))
|
||||
.unwrap_or_default();
|
||||
@@ -529,6 +554,13 @@ impl GlobalState {
|
||||
}
|
||||
flycheck::Progress::DidCheckCrate(target) => (Progress::Report, Some(target)),
|
||||
flycheck::Progress::DidCancel => (Progress::End, None),
|
||||
flycheck::Progress::DidFailToRestart(err) => {
|
||||
self.show_and_log_error(
|
||||
"cargo check failed".to_string(),
|
||||
Some(err.to_string()),
|
||||
);
|
||||
return;
|
||||
}
|
||||
flycheck::Progress::DidFinish(result) => {
|
||||
if let Err(err) = result {
|
||||
self.show_and_log_error(
|
||||
|
||||
@@ -8,107 +8,130 @@ use lsp_types::{
|
||||
};
|
||||
|
||||
macro_rules! define_semantic_token_types {
|
||||
($(($ident:ident, $string:literal)),*$(,)?) => {
|
||||
$(pub(crate) const $ident: SemanticTokenType = SemanticTokenType::new($string);)*
|
||||
(
|
||||
standard {
|
||||
$($standard:ident),*$(,)?
|
||||
}
|
||||
custom {
|
||||
$(($custom:ident, $string:literal)),*$(,)?
|
||||
}
|
||||
|
||||
) => {
|
||||
$(pub(crate) const $standard: SemanticTokenType = SemanticTokenType::$standard;)*
|
||||
$(pub(crate) const $custom: SemanticTokenType = SemanticTokenType::new($string);)*
|
||||
|
||||
pub(crate) 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::ENUM_MEMBER,
|
||||
SemanticTokenType::TYPE_PARAMETER,
|
||||
SemanticTokenType::FUNCTION,
|
||||
SemanticTokenType::METHOD,
|
||||
SemanticTokenType::PROPERTY,
|
||||
SemanticTokenType::MACRO,
|
||||
SemanticTokenType::VARIABLE,
|
||||
SemanticTokenType::PARAMETER,
|
||||
$($ident),*
|
||||
$(SemanticTokenType::$standard,)*
|
||||
$($custom),*
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
define_semantic_token_types![
|
||||
(ANGLE, "angle"),
|
||||
(ARITHMETIC, "arithmetic"),
|
||||
(ATTRIBUTE, "attribute"),
|
||||
(ATTRIBUTE_BRACKET, "attributeBracket"),
|
||||
(BITWISE, "bitwise"),
|
||||
(BOOLEAN, "boolean"),
|
||||
(BRACE, "brace"),
|
||||
(BRACKET, "bracket"),
|
||||
(BUILTIN_ATTRIBUTE, "builtinAttribute"),
|
||||
(BUILTIN_TYPE, "builtinType"),
|
||||
(CHAR, "character"),
|
||||
(COLON, "colon"),
|
||||
(COMMA, "comma"),
|
||||
(COMPARISON, "comparison"),
|
||||
(CONST_PARAMETER, "constParameter"),
|
||||
(DERIVE, "derive"),
|
||||
(DERIVE_HELPER, "deriveHelper"),
|
||||
(DOT, "dot"),
|
||||
(ESCAPE_SEQUENCE, "escapeSequence"),
|
||||
(FORMAT_SPECIFIER, "formatSpecifier"),
|
||||
(GENERIC, "generic"),
|
||||
(LABEL, "label"),
|
||||
(LIFETIME, "lifetime"),
|
||||
(LOGICAL, "logical"),
|
||||
(MACRO_BANG, "macroBang"),
|
||||
(OPERATOR, "operator"),
|
||||
(PARENTHESIS, "parenthesis"),
|
||||
(PUNCTUATION, "punctuation"),
|
||||
(SELF_KEYWORD, "selfKeyword"),
|
||||
(SELF_TYPE_KEYWORD, "selfTypeKeyword"),
|
||||
(SEMICOLON, "semicolon"),
|
||||
(TYPE_ALIAS, "typeAlias"),
|
||||
(TOOL_MODULE, "toolModule"),
|
||||
(UNION, "union"),
|
||||
(UNRESOLVED_REFERENCE, "unresolvedReference"),
|
||||
standard {
|
||||
COMMENT,
|
||||
DECORATOR,
|
||||
ENUM_MEMBER,
|
||||
ENUM,
|
||||
FUNCTION,
|
||||
INTERFACE,
|
||||
KEYWORD,
|
||||
MACRO,
|
||||
METHOD,
|
||||
NAMESPACE,
|
||||
NUMBER,
|
||||
OPERATOR,
|
||||
PARAMETER,
|
||||
PROPERTY,
|
||||
STRING,
|
||||
STRUCT,
|
||||
TYPE_PARAMETER,
|
||||
VARIABLE,
|
||||
}
|
||||
|
||||
custom {
|
||||
(ANGLE, "angle"),
|
||||
(ARITHMETIC, "arithmetic"),
|
||||
(ATTRIBUTE, "attribute"),
|
||||
(ATTRIBUTE_BRACKET, "attributeBracket"),
|
||||
(BITWISE, "bitwise"),
|
||||
(BOOLEAN, "boolean"),
|
||||
(BRACE, "brace"),
|
||||
(BRACKET, "bracket"),
|
||||
(BUILTIN_ATTRIBUTE, "builtinAttribute"),
|
||||
(BUILTIN_TYPE, "builtinType"),
|
||||
(CHAR, "character"),
|
||||
(COLON, "colon"),
|
||||
(COMMA, "comma"),
|
||||
(COMPARISON, "comparison"),
|
||||
(CONST_PARAMETER, "constParameter"),
|
||||
(DERIVE, "derive"),
|
||||
(DERIVE_HELPER, "deriveHelper"),
|
||||
(DOT, "dot"),
|
||||
(ESCAPE_SEQUENCE, "escapeSequence"),
|
||||
(FORMAT_SPECIFIER, "formatSpecifier"),
|
||||
(GENERIC, "generic"),
|
||||
(LABEL, "label"),
|
||||
(LIFETIME, "lifetime"),
|
||||
(LOGICAL, "logical"),
|
||||
(MACRO_BANG, "macroBang"),
|
||||
(PARENTHESIS, "parenthesis"),
|
||||
(PUNCTUATION, "punctuation"),
|
||||
(SELF_KEYWORD, "selfKeyword"),
|
||||
(SELF_TYPE_KEYWORD, "selfTypeKeyword"),
|
||||
(SEMICOLON, "semicolon"),
|
||||
(TYPE_ALIAS, "typeAlias"),
|
||||
(TOOL_MODULE, "toolModule"),
|
||||
(UNION, "union"),
|
||||
(UNRESOLVED_REFERENCE, "unresolvedReference"),
|
||||
}
|
||||
];
|
||||
|
||||
macro_rules! define_semantic_token_modifiers {
|
||||
($(($ident:ident, $string:literal)),*$(,)?) => {
|
||||
$(pub(crate) const $ident: SemanticTokenModifier = SemanticTokenModifier::new($string);)*
|
||||
(
|
||||
standard {
|
||||
$($standard:ident),*$(,)?
|
||||
}
|
||||
custom {
|
||||
$(($custom:ident, $string:literal)),*$(,)?
|
||||
}
|
||||
|
||||
) => {
|
||||
|
||||
$(pub(crate) const $standard: SemanticTokenModifier = SemanticTokenModifier::$standard;)*
|
||||
$(pub(crate) const $custom: SemanticTokenModifier = SemanticTokenModifier::new($string);)*
|
||||
|
||||
pub(crate) const SUPPORTED_MODIFIERS: &[SemanticTokenModifier] = &[
|
||||
SemanticTokenModifier::DOCUMENTATION,
|
||||
SemanticTokenModifier::DECLARATION,
|
||||
SemanticTokenModifier::DEFINITION,
|
||||
SemanticTokenModifier::STATIC,
|
||||
SemanticTokenModifier::ABSTRACT,
|
||||
SemanticTokenModifier::DEPRECATED,
|
||||
SemanticTokenModifier::READONLY,
|
||||
SemanticTokenModifier::DEFAULT_LIBRARY,
|
||||
$($ident),*
|
||||
$(SemanticTokenModifier::$standard,)*
|
||||
$($custom),*
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
define_semantic_token_modifiers![
|
||||
(ASYNC, "async"),
|
||||
(ATTRIBUTE_MODIFIER, "attribute"),
|
||||
(CALLABLE, "callable"),
|
||||
(CONSTANT, "constant"),
|
||||
(CONSUMING, "consuming"),
|
||||
(CONTROL_FLOW, "controlFlow"),
|
||||
(CRATE_ROOT, "crateRoot"),
|
||||
(INJECTED, "injected"),
|
||||
(INTRA_DOC_LINK, "intraDocLink"),
|
||||
(LIBRARY, "library"),
|
||||
(MUTABLE, "mutable"),
|
||||
(PUBLIC, "public"),
|
||||
(REFERENCE, "reference"),
|
||||
(TRAIT_MODIFIER, "trait"),
|
||||
(UNSAFE, "unsafe"),
|
||||
standard {
|
||||
DOCUMENTATION,
|
||||
DECLARATION,
|
||||
STATIC,
|
||||
DEFAULT_LIBRARY,
|
||||
}
|
||||
custom {
|
||||
(ASYNC, "async"),
|
||||
(ATTRIBUTE_MODIFIER, "attribute"),
|
||||
(CALLABLE, "callable"),
|
||||
(CONSTANT, "constant"),
|
||||
(CONSUMING, "consuming"),
|
||||
(CONTROL_FLOW, "controlFlow"),
|
||||
(CRATE_ROOT, "crateRoot"),
|
||||
(INJECTED, "injected"),
|
||||
(INTRA_DOC_LINK, "intraDocLink"),
|
||||
(LIBRARY, "library"),
|
||||
(MUTABLE, "mutable"),
|
||||
(PUBLIC, "public"),
|
||||
(REFERENCE, "reference"),
|
||||
(TRAIT_MODIFIER, "trait"),
|
||||
(UNSAFE, "unsafe"),
|
||||
}
|
||||
];
|
||||
|
||||
#[derive(Default)]
|
||||
|
||||
@@ -517,7 +517,6 @@ pub(crate) fn semantic_tokens(
|
||||
text: &str,
|
||||
line_index: &LineIndex,
|
||||
highlights: Vec<HlRange>,
|
||||
highlight_strings: bool,
|
||||
) -> lsp_types::SemanticTokens {
|
||||
let id = TOKEN_RESULT_COUNTER.fetch_add(1, Ordering::SeqCst).to_string();
|
||||
let mut builder = semantic_tokens::SemanticTokensBuilder::new(id);
|
||||
@@ -526,10 +525,8 @@ pub(crate) fn semantic_tokens(
|
||||
if highlight_range.highlight.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let (ty, mods) = semantic_token_type_and_modifiers(highlight_range.highlight);
|
||||
if !highlight_strings && ty == lsp_types::SemanticTokenType::STRING {
|
||||
continue;
|
||||
}
|
||||
let token_index = semantic_tokens::type_index(ty);
|
||||
let modifier_bitset = mods.0;
|
||||
|
||||
@@ -561,55 +558,55 @@ fn semantic_token_type_and_modifiers(
|
||||
let mut mods = semantic_tokens::ModifierSet::default();
|
||||
let type_ = match highlight.tag {
|
||||
HlTag::Symbol(symbol) => match symbol {
|
||||
SymbolKind::Attribute => semantic_tokens::ATTRIBUTE,
|
||||
SymbolKind::Attribute => semantic_tokens::DECORATOR,
|
||||
SymbolKind::Derive => semantic_tokens::DERIVE,
|
||||
SymbolKind::DeriveHelper => semantic_tokens::DERIVE_HELPER,
|
||||
SymbolKind::Module => lsp_types::SemanticTokenType::NAMESPACE,
|
||||
SymbolKind::Module => semantic_tokens::NAMESPACE,
|
||||
SymbolKind::Impl => semantic_tokens::TYPE_ALIAS,
|
||||
SymbolKind::Field => lsp_types::SemanticTokenType::PROPERTY,
|
||||
SymbolKind::TypeParam => lsp_types::SemanticTokenType::TYPE_PARAMETER,
|
||||
SymbolKind::Field => semantic_tokens::PROPERTY,
|
||||
SymbolKind::TypeParam => semantic_tokens::TYPE_PARAMETER,
|
||||
SymbolKind::ConstParam => semantic_tokens::CONST_PARAMETER,
|
||||
SymbolKind::LifetimeParam => semantic_tokens::LIFETIME,
|
||||
SymbolKind::Label => semantic_tokens::LABEL,
|
||||
SymbolKind::ValueParam => lsp_types::SemanticTokenType::PARAMETER,
|
||||
SymbolKind::ValueParam => semantic_tokens::PARAMETER,
|
||||
SymbolKind::SelfParam => semantic_tokens::SELF_KEYWORD,
|
||||
SymbolKind::SelfType => semantic_tokens::SELF_TYPE_KEYWORD,
|
||||
SymbolKind::Local => lsp_types::SemanticTokenType::VARIABLE,
|
||||
SymbolKind::Local => semantic_tokens::VARIABLE,
|
||||
SymbolKind::Function => {
|
||||
if highlight.mods.contains(HlMod::Associated) {
|
||||
lsp_types::SemanticTokenType::METHOD
|
||||
semantic_tokens::METHOD
|
||||
} else {
|
||||
lsp_types::SemanticTokenType::FUNCTION
|
||||
semantic_tokens::FUNCTION
|
||||
}
|
||||
}
|
||||
SymbolKind::Const => {
|
||||
mods |= semantic_tokens::CONSTANT;
|
||||
mods |= lsp_types::SemanticTokenModifier::STATIC;
|
||||
lsp_types::SemanticTokenType::VARIABLE
|
||||
mods |= semantic_tokens::STATIC;
|
||||
semantic_tokens::VARIABLE
|
||||
}
|
||||
SymbolKind::Static => {
|
||||
mods |= lsp_types::SemanticTokenModifier::STATIC;
|
||||
lsp_types::SemanticTokenType::VARIABLE
|
||||
mods |= semantic_tokens::STATIC;
|
||||
semantic_tokens::VARIABLE
|
||||
}
|
||||
SymbolKind::Struct => lsp_types::SemanticTokenType::STRUCT,
|
||||
SymbolKind::Enum => lsp_types::SemanticTokenType::ENUM,
|
||||
SymbolKind::Variant => lsp_types::SemanticTokenType::ENUM_MEMBER,
|
||||
SymbolKind::Struct => semantic_tokens::STRUCT,
|
||||
SymbolKind::Enum => semantic_tokens::ENUM,
|
||||
SymbolKind::Variant => semantic_tokens::ENUM_MEMBER,
|
||||
SymbolKind::Union => semantic_tokens::UNION,
|
||||
SymbolKind::TypeAlias => semantic_tokens::TYPE_ALIAS,
|
||||
SymbolKind::Trait => lsp_types::SemanticTokenType::INTERFACE,
|
||||
SymbolKind::Macro => lsp_types::SemanticTokenType::MACRO,
|
||||
SymbolKind::Trait => semantic_tokens::INTERFACE,
|
||||
SymbolKind::Macro => semantic_tokens::MACRO,
|
||||
SymbolKind::BuiltinAttr => semantic_tokens::BUILTIN_ATTRIBUTE,
|
||||
SymbolKind::ToolModule => semantic_tokens::TOOL_MODULE,
|
||||
},
|
||||
HlTag::AttributeBracket => semantic_tokens::ATTRIBUTE_BRACKET,
|
||||
HlTag::BoolLiteral => semantic_tokens::BOOLEAN,
|
||||
HlTag::BuiltinType => semantic_tokens::BUILTIN_TYPE,
|
||||
HlTag::ByteLiteral | HlTag::NumericLiteral => lsp_types::SemanticTokenType::NUMBER,
|
||||
HlTag::ByteLiteral | HlTag::NumericLiteral => semantic_tokens::NUMBER,
|
||||
HlTag::CharLiteral => semantic_tokens::CHAR,
|
||||
HlTag::Comment => lsp_types::SemanticTokenType::COMMENT,
|
||||
HlTag::Comment => semantic_tokens::COMMENT,
|
||||
HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE,
|
||||
HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER,
|
||||
HlTag::Keyword => lsp_types::SemanticTokenType::KEYWORD,
|
||||
HlTag::Keyword => semantic_tokens::KEYWORD,
|
||||
HlTag::None => semantic_tokens::GENERIC,
|
||||
HlTag::Operator(op) => match op {
|
||||
HlOperator::Bitwise => semantic_tokens::BITWISE,
|
||||
@@ -618,7 +615,7 @@ fn semantic_token_type_and_modifiers(
|
||||
HlOperator::Comparison => semantic_tokens::COMPARISON,
|
||||
HlOperator::Other => semantic_tokens::OPERATOR,
|
||||
},
|
||||
HlTag::StringLiteral => lsp_types::SemanticTokenType::STRING,
|
||||
HlTag::StringLiteral => semantic_tokens::STRING,
|
||||
HlTag::UnresolvedReference => semantic_tokens::UNRESOLVED_REFERENCE,
|
||||
HlTag::Punctuation(punct) => match punct {
|
||||
HlPunct::Bracket => semantic_tokens::BRACKET,
|
||||
@@ -643,16 +640,16 @@ fn semantic_token_type_and_modifiers(
|
||||
HlMod::Consuming => semantic_tokens::CONSUMING,
|
||||
HlMod::ControlFlow => semantic_tokens::CONTROL_FLOW,
|
||||
HlMod::CrateRoot => semantic_tokens::CRATE_ROOT,
|
||||
HlMod::DefaultLibrary => lsp_types::SemanticTokenModifier::DEFAULT_LIBRARY,
|
||||
HlMod::Definition => lsp_types::SemanticTokenModifier::DECLARATION,
|
||||
HlMod::Documentation => lsp_types::SemanticTokenModifier::DOCUMENTATION,
|
||||
HlMod::DefaultLibrary => semantic_tokens::DEFAULT_LIBRARY,
|
||||
HlMod::Definition => semantic_tokens::DECLARATION,
|
||||
HlMod::Documentation => semantic_tokens::DOCUMENTATION,
|
||||
HlMod::Injected => semantic_tokens::INJECTED,
|
||||
HlMod::IntraDocLink => semantic_tokens::INTRA_DOC_LINK,
|
||||
HlMod::Library => semantic_tokens::LIBRARY,
|
||||
HlMod::Mutable => semantic_tokens::MUTABLE,
|
||||
HlMod::Public => semantic_tokens::PUBLIC,
|
||||
HlMod::Reference => semantic_tokens::REFERENCE,
|
||||
HlMod::Static => lsp_types::SemanticTokenModifier::STATIC,
|
||||
HlMod::Static => semantic_tokens::STATIC,
|
||||
HlMod::Trait => semantic_tokens::TRAIT_MODIFIER,
|
||||
HlMod::Unsafe => semantic_tokens::UNSAFE,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user