mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-16 07:03:57 +00:00
Move highlight configuration from protocol into the feature
This commit is contained in:
parent
afc8cfb4d1
commit
9a201873b8
8 changed files with 119 additions and 86 deletions
|
@ -98,7 +98,7 @@ pub use crate::{
|
|||
static_index::{StaticIndex, StaticIndexedFile, TokenId, TokenStaticData},
|
||||
syntax_highlighting::{
|
||||
tags::{Highlight, HlMod, HlMods, HlOperator, HlPunct, HlTag},
|
||||
HlRange,
|
||||
HighlightConfig, HlRange,
|
||||
},
|
||||
};
|
||||
pub use hir::{Documentation, Semantics};
|
||||
|
@ -517,8 +517,12 @@ impl Analysis {
|
|||
}
|
||||
|
||||
/// Computes syntax highlighting for the given file
|
||||
pub fn highlight(&self, file_id: FileId) -> Cancellable<Vec<HlRange>> {
|
||||
self.with_db(|db| syntax_highlighting::highlight(db, file_id, None, false))
|
||||
pub fn highlight(
|
||||
&self,
|
||||
highlight_config: HighlightConfig,
|
||||
file_id: FileId,
|
||||
) -> Cancellable<Vec<HlRange>> {
|
||||
self.with_db(|db| syntax_highlighting::highlight(db, highlight_config, file_id, None))
|
||||
}
|
||||
|
||||
/// Computes all ranges to highlight for a given item in a file.
|
||||
|
@ -533,9 +537,13 @@ impl Analysis {
|
|||
}
|
||||
|
||||
/// Computes syntax highlighting for the given file range.
|
||||
pub fn highlight_range(&self, frange: FileRange) -> Cancellable<Vec<HlRange>> {
|
||||
pub fn highlight_range(
|
||||
&self,
|
||||
highlight_config: HighlightConfig,
|
||||
frange: FileRange,
|
||||
) -> Cancellable<Vec<HlRange>> {
|
||||
self.with_db(|db| {
|
||||
syntax_highlighting::highlight(db, frange.file_id, Some(frange.range), false)
|
||||
syntax_highlighting::highlight(db, highlight_config, frange.file_id, Some(frange.range))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ mod html;
|
|||
mod tests;
|
||||
|
||||
use hir::{Name, Semantics};
|
||||
use ide_db::{FxHashMap, RootDatabase};
|
||||
use ide_db::{FxHashMap, RootDatabase, SymbolKind};
|
||||
use syntax::{
|
||||
ast, AstNode, AstToken, NodeOrToken, SyntaxKind::*, SyntaxNode, TextRange, WalkEvent, T,
|
||||
};
|
||||
|
@ -24,7 +24,7 @@ use crate::{
|
|||
escape::highlight_escape_string, format::highlight_format_string, highlights::Highlights,
|
||||
macro_::MacroHighlighter, tags::Highlight,
|
||||
},
|
||||
FileId, HlMod, HlTag,
|
||||
FileId, HlMod, HlOperator, HlPunct, HlTag,
|
||||
};
|
||||
|
||||
pub(crate) use html::highlight_as_html;
|
||||
|
@ -36,6 +36,16 @@ pub struct HlRange {
|
|||
pub binding_hash: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct HighlightConfig {
|
||||
pub strings: bool,
|
||||
pub punctuation: bool,
|
||||
pub specialize_punctuation: bool,
|
||||
pub specialize_operator: bool,
|
||||
pub operator: bool,
|
||||
pub syntactic_name_ref_highlighting: bool,
|
||||
}
|
||||
|
||||
// Feature: Semantic Syntax Highlighting
|
||||
//
|
||||
// rust-analyzer highlights the code semantically.
|
||||
|
@ -155,9 +165,9 @@ pub struct HlRange {
|
|||
// image::https://user-images.githubusercontent.com/48062697/113187625-f7f50100-9250-11eb-825e-91c58f236071.png[]
|
||||
pub(crate) fn highlight(
|
||||
db: &RootDatabase,
|
||||
config: HighlightConfig,
|
||||
file_id: FileId,
|
||||
range_to_highlight: Option<TextRange>,
|
||||
syntactic_name_ref_highlighting: bool,
|
||||
) -> Vec<HlRange> {
|
||||
let _p = profile::span("highlight");
|
||||
let sema = Semantics::new(db);
|
||||
|
@ -183,26 +193,18 @@ pub(crate) fn highlight(
|
|||
Some(it) => it.krate(),
|
||||
None => return hl.to_vec(),
|
||||
};
|
||||
traverse(
|
||||
&mut hl,
|
||||
&sema,
|
||||
file_id,
|
||||
&root,
|
||||
krate,
|
||||
range_to_highlight,
|
||||
syntactic_name_ref_highlighting,
|
||||
);
|
||||
traverse(&mut hl, &sema, config, file_id, &root, krate, range_to_highlight);
|
||||
hl.to_vec()
|
||||
}
|
||||
|
||||
fn traverse(
|
||||
hl: &mut Highlights,
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
config: HighlightConfig,
|
||||
file_id: FileId,
|
||||
root: &SyntaxNode,
|
||||
krate: hir::Crate,
|
||||
range_to_highlight: TextRange,
|
||||
syntactic_name_ref_highlighting: bool,
|
||||
) {
|
||||
let is_unlinked = sema.to_module_def(file_id).is_none();
|
||||
let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default();
|
||||
|
@ -325,7 +327,7 @@ fn traverse(
|
|||
Leave(NodeOrToken::Node(node)) => {
|
||||
// Doc comment highlighting injection, we do this when leaving the node
|
||||
// so that we overwrite the highlighting of the doc comment itself.
|
||||
inject::doc_comment(hl, sema, file_id, &node);
|
||||
inject::doc_comment(hl, sema, config, file_id, &node);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
@ -400,7 +402,8 @@ fn traverse(
|
|||
let string_to_highlight = ast::String::cast(descended_token.clone());
|
||||
if let Some((string, expanded_string)) = string.zip(string_to_highlight) {
|
||||
if string.is_raw() {
|
||||
if inject::ra_fixture(hl, sema, &string, &expanded_string).is_some() {
|
||||
if inject::ra_fixture(hl, sema, config, &string, &expanded_string).is_some()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -421,7 +424,7 @@ fn traverse(
|
|||
sema,
|
||||
krate,
|
||||
&mut bindings_shadow_count,
|
||||
syntactic_name_ref_highlighting,
|
||||
config.syntactic_name_ref_highlighting,
|
||||
name_like,
|
||||
),
|
||||
NodeOrToken::Token(token) => highlight::token(sema, token).zip(Some(None)),
|
||||
|
@ -439,6 +442,27 @@ fn traverse(
|
|||
// something unresolvable. FIXME: There should be a way to prevent that
|
||||
continue;
|
||||
}
|
||||
|
||||
// apply config filtering
|
||||
match &mut highlight.tag {
|
||||
HlTag::StringLiteral if !config.strings => continue,
|
||||
// If punctuation is disabled, make the macro bang part of the macro call again.
|
||||
tag @ HlTag::Punctuation(HlPunct::MacroBang)
|
||||
if !config.punctuation || !config.specialize_punctuation =>
|
||||
{
|
||||
*tag = HlTag::Symbol(SymbolKind::Macro);
|
||||
}
|
||||
HlTag::Punctuation(_) if !config.punctuation => continue,
|
||||
tag @ HlTag::Punctuation(_) if !config.specialize_punctuation => {
|
||||
*tag = HlTag::Punctuation(HlPunct::Other);
|
||||
}
|
||||
HlTag::Operator(_) if !config.operator && highlight.mods.is_empty() => continue,
|
||||
tag @ HlTag::Operator(_) if !config.specialize_operator => {
|
||||
*tag = HlTag::Operator(HlOperator::Other);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if inside_attribute {
|
||||
highlight |= HlMod::Attribute
|
||||
}
|
||||
|
|
|
@ -5,7 +5,10 @@ use oorandom::Rand32;
|
|||
use stdx::format_to;
|
||||
use syntax::AstNode;
|
||||
|
||||
use crate::{syntax_highlighting::highlight, FileId, RootDatabase};
|
||||
use crate::{
|
||||
syntax_highlighting::{highlight, HighlightConfig},
|
||||
FileId, RootDatabase,
|
||||
};
|
||||
|
||||
pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: bool) -> String {
|
||||
let parse = db.parse(file_id);
|
||||
|
@ -20,7 +23,19 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo
|
|||
)
|
||||
}
|
||||
|
||||
let hl_ranges = highlight(db, file_id, None, false);
|
||||
let hl_ranges = highlight(
|
||||
db,
|
||||
HighlightConfig {
|
||||
strings: true,
|
||||
punctuation: true,
|
||||
specialize_punctuation: true,
|
||||
specialize_operator: true,
|
||||
operator: true,
|
||||
syntactic_name_ref_highlighting: false,
|
||||
},
|
||||
file_id,
|
||||
None,
|
||||
);
|
||||
let text = parse.tree().syntax().to_string();
|
||||
let mut buf = String::new();
|
||||
buf.push_str(STYLE);
|
||||
|
|
|
@ -15,13 +15,14 @@ use syntax::{
|
|||
|
||||
use crate::{
|
||||
doc_links::{doc_attributes, extract_definitions_from_docs, resolve_doc_path_for_def},
|
||||
syntax_highlighting::{highlights::Highlights, injector::Injector},
|
||||
syntax_highlighting::{highlights::Highlights, injector::Injector, HighlightConfig},
|
||||
Analysis, HlMod, HlRange, HlTag, RootDatabase,
|
||||
};
|
||||
|
||||
pub(super) fn ra_fixture(
|
||||
hl: &mut Highlights,
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
config: HighlightConfig,
|
||||
literal: &ast::String,
|
||||
expanded: &ast::String,
|
||||
) -> Option<()> {
|
||||
|
@ -63,7 +64,13 @@ pub(super) fn ra_fixture(
|
|||
|
||||
let (analysis, tmp_file_id) = Analysis::from_single_file(inj.take_text());
|
||||
|
||||
for mut hl_range in analysis.highlight(tmp_file_id).unwrap() {
|
||||
for mut hl_range in analysis
|
||||
.highlight(
|
||||
HighlightConfig { syntactic_name_ref_highlighting: false, ..config },
|
||||
tmp_file_id,
|
||||
)
|
||||
.unwrap()
|
||||
{
|
||||
for range in inj.map_range_up(hl_range.range) {
|
||||
if let Some(range) = literal.map_range_up(range) {
|
||||
hl_range.range = range;
|
||||
|
@ -86,6 +93,7 @@ const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"];
|
|||
pub(super) fn doc_comment(
|
||||
hl: &mut Highlights,
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
config: HighlightConfig,
|
||||
src_file_id: FileId,
|
||||
node: &SyntaxNode,
|
||||
) {
|
||||
|
@ -206,7 +214,14 @@ pub(super) fn doc_comment(
|
|||
|
||||
let (analysis, tmp_file_id) = Analysis::from_single_file(inj.take_text());
|
||||
|
||||
if let Ok(ranges) = analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)) {
|
||||
if let Ok(ranges) = analysis.with_db(|db| {
|
||||
super::highlight(
|
||||
db,
|
||||
HighlightConfig { syntactic_name_ref_highlighting: true, ..config },
|
||||
tmp_file_id,
|
||||
None,
|
||||
)
|
||||
}) {
|
||||
for HlRange { range, highlight, binding_hash } in ranges {
|
||||
for range in inj.map_range_up(range) {
|
||||
hl.add(HlRange { range, highlight: highlight | HlMod::Injected, binding_hash });
|
||||
|
|
|
@ -4,7 +4,16 @@ use expect_test::{expect_file, ExpectFile};
|
|||
use ide_db::SymbolKind;
|
||||
use test_utils::{bench, bench_fixture, skip_slow_tests, AssertLinear};
|
||||
|
||||
use crate::{fixture, FileRange, HlTag, TextRange};
|
||||
use crate::{fixture, FileRange, HighlightConfig, HlTag, TextRange};
|
||||
|
||||
const HL_CONFIG: HighlightConfig = HighlightConfig {
|
||||
strings: true,
|
||||
punctuation: true,
|
||||
specialize_punctuation: true,
|
||||
specialize_operator: true,
|
||||
operator: true,
|
||||
syntactic_name_ref_highlighting: false,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn attributes() {
|
||||
|
@ -996,7 +1005,10 @@ struct Foo {
|
|||
|
||||
// The "x"
|
||||
let highlights = &analysis
|
||||
.highlight_range(FileRange { file_id, range: TextRange::at(45.into(), 1.into()) })
|
||||
.highlight_range(
|
||||
HL_CONFIG,
|
||||
FileRange { file_id, range: TextRange::at(45.into(), 1.into()) },
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(&highlights[0].highlight.to_string(), "field.declaration.public");
|
||||
|
@ -1011,7 +1023,7 @@ macro_rules! test {}
|
|||
}"#
|
||||
.trim(),
|
||||
);
|
||||
let _ = analysis.highlight(file_id).unwrap();
|
||||
let _ = analysis.highlight(HL_CONFIG, file_id).unwrap();
|
||||
}
|
||||
|
||||
/// Highlights the code given by the `ra_fixture` argument, renders the
|
||||
|
@ -1035,7 +1047,7 @@ fn benchmark_syntax_highlighting_long_struct() {
|
|||
let hash = {
|
||||
let _pt = bench("syntax highlighting long struct");
|
||||
analysis
|
||||
.highlight(file_id)
|
||||
.highlight(HL_CONFIG, file_id)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Struct))
|
||||
|
@ -1061,7 +1073,7 @@ fn syntax_highlighting_not_quadratic() {
|
|||
let time = Instant::now();
|
||||
|
||||
let hash = analysis
|
||||
.highlight(file_id)
|
||||
.highlight(HL_CONFIG, file_id)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Struct))
|
||||
|
@ -1086,7 +1098,7 @@ fn benchmark_syntax_highlighting_parser() {
|
|||
let hash = {
|
||||
let _pt = bench("syntax highlighting parser");
|
||||
analysis
|
||||
.highlight(file_id)
|
||||
.highlight(HL_CONFIG, file_id)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Function))
|
||||
|
|
|
@ -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},
|
||||
|
@ -543,15 +543,6 @@ impl HoverActionsConfig {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct HighlightingConfig {
|
||||
pub strings: bool,
|
||||
pub punctuation: bool,
|
||||
pub specialize_punctuation: bool,
|
||||
pub specialize_operator: bool,
|
||||
pub operator: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FilesConfig {
|
||||
pub watcher: FilesWatcher,
|
||||
|
@ -1200,8 +1191,8 @@ impl Config {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn highlighting_config(&self) -> HighlightingConfig {
|
||||
HighlightingConfig {
|
||||
pub fn highlighting_config(&self) -> HighlightConfig {
|
||||
HighlightConfig {
|
||||
strings: self.data.semanticHighlighting_strings_enable,
|
||||
punctuation: self.data.semanticHighlighting_punctuation_enable,
|
||||
specialize_punctuation: self
|
||||
|
@ -1209,6 +1200,7 @@ impl Config {
|
|||
.semanticHighlighting_punctuation_specialization_enable,
|
||||
operator: self.data.semanticHighlighting_operator_enable,
|
||||
specialize_operator: self.data.semanticHighlighting_operator_specialization_enable,
|
||||
syntactic_name_ref_highlighting: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 highlighting_config = snap.config.highlighting_config();
|
||||
let semantic_tokens =
|
||||
to_proto::semantic_tokens(&text, &line_index, highlights, highlighting_config);
|
||||
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_config();
|
||||
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_config();
|
||||
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()))
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ use vfs::AbsPath;
|
|||
|
||||
use crate::{
|
||||
cargo_target_spec::CargoTargetSpec,
|
||||
config::{CallInfoConfig, Config, HighlightingConfig},
|
||||
config::{CallInfoConfig, Config},
|
||||
global_state::GlobalStateSnapshot,
|
||||
line_index::{LineEndings, LineIndex, OffsetEncoding},
|
||||
lsp_ext,
|
||||
|
@ -517,42 +517,15 @@ pub(crate) fn semantic_tokens(
|
|||
text: &str,
|
||||
line_index: &LineIndex,
|
||||
highlights: Vec<HlRange>,
|
||||
config: HighlightingConfig,
|
||||
) -> lsp_types::SemanticTokens {
|
||||
let id = TOKEN_RESULT_COUNTER.fetch_add(1, Ordering::SeqCst).to_string();
|
||||
let mut builder = semantic_tokens::SemanticTokensBuilder::new(id);
|
||||
|
||||
for mut highlight_range in highlights {
|
||||
for highlight_range in highlights {
|
||||
if highlight_range.highlight.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// apply config filtering
|
||||
match &mut highlight_range.highlight.tag {
|
||||
HlTag::StringLiteral if !config.strings => continue,
|
||||
// If punctuation is disabled, make the macro bang part of the macro call again.
|
||||
tag @ HlTag::Punctuation(HlPunct::MacroBang)
|
||||
if !config.punctuation || !config.specialize_punctuation =>
|
||||
{
|
||||
*tag = HlTag::Symbol(SymbolKind::Macro);
|
||||
}
|
||||
HlTag::Punctuation(_)
|
||||
if !config.punctuation && highlight_range.highlight.mods.is_empty() =>
|
||||
{
|
||||
continue
|
||||
}
|
||||
tag @ HlTag::Punctuation(_) if !config.specialize_punctuation => {
|
||||
*tag = HlTag::Punctuation(HlPunct::Other);
|
||||
}
|
||||
HlTag::Operator(_) if !config.operator && highlight_range.highlight.mods.is_empty() => {
|
||||
continue
|
||||
}
|
||||
tag @ HlTag::Operator(_) if !config.specialize_operator => {
|
||||
*tag = HlTag::Operator(HlOperator::Other);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let (ty, mods) = semantic_token_type_and_modifiers(highlight_range.highlight);
|
||||
let token_index = semantic_tokens::type_index(ty);
|
||||
let modifier_bitset = mods.0;
|
||||
|
|
Loading…
Reference in a new issue