Remove old syntax highlighting

This commit is contained in:
Aleksey Kladov 2020-04-02 09:52:27 +02:00
parent f696df379a
commit 309fc70155
9 changed files with 3 additions and 359 deletions

View file

@ -16,7 +16,6 @@ use serde::Deserialize;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Config { pub struct Config {
pub client_caps: ClientCapsConfig, pub client_caps: ClientCapsConfig,
pub publish_decorations: bool,
pub publish_diagnostics: bool, pub publish_diagnostics: bool,
pub notifications: NotificationsConfig, pub notifications: NotificationsConfig,
pub inlay_hints: InlayHintsConfig, pub inlay_hints: InlayHintsConfig,
@ -60,7 +59,6 @@ pub struct ClientCapsConfig {
impl Default for Config { impl Default for Config {
fn default() -> Self { fn default() -> Self {
Config { Config {
publish_decorations: false,
publish_diagnostics: true, publish_diagnostics: true,
notifications: NotificationsConfig { notifications: NotificationsConfig {
workspace_loaded: true, workspace_loaded: true,
@ -105,7 +103,6 @@ impl Config {
*self = Default::default(); *self = Default::default();
self.client_caps = client_caps; self.client_caps = client_caps;
set(value, "/publishDecorations", &mut self.publish_decorations);
set(value, "/excludeGlobs", &mut self.exclude_globs); set(value, "/excludeGlobs", &mut self.exclude_globs);
set(value, "/useClientWatching", &mut self.use_client_watching); set(value, "/useClientWatching", &mut self.use_client_watching);
set(value, "/lruCapacity", &mut self.lru_capacity); set(value, "/lruCapacity", &mut self.lru_capacity);

View file

@ -250,9 +250,7 @@ impl fmt::Debug for Event {
} }
} }
Event::Task(Task::Notify(not)) => { Event::Task(Task::Notify(not)) => {
if notification_is::<req::PublishDecorations>(not) if notification_is::<req::PublishDiagnostics>(not) {
|| notification_is::<req::PublishDiagnostics>(not)
{
return debug_verbose_not(not, f); return debug_verbose_not(not, f);
} }
} }
@ -427,7 +425,6 @@ fn loop_turn(
update_file_notifications_on_threadpool( update_file_notifications_on_threadpool(
pool, pool,
world_state.snapshot(), world_state.snapshot(),
world_state.config.publish_decorations,
task_sender.clone(), task_sender.clone(),
loop_state.subscriptions.subscriptions(), loop_state.subscriptions.subscriptions(),
) )
@ -508,7 +505,6 @@ fn on_request(
.on::<req::GotoTypeDefinition>(handlers::handle_goto_type_definition)? .on::<req::GotoTypeDefinition>(handlers::handle_goto_type_definition)?
.on::<req::ParentModule>(handlers::handle_parent_module)? .on::<req::ParentModule>(handlers::handle_parent_module)?
.on::<req::Runnables>(handlers::handle_runnables)? .on::<req::Runnables>(handlers::handle_runnables)?
.on::<req::DecorationsRequest>(handlers::handle_decorations)?
.on::<req::Completion>(handlers::handle_completion)? .on::<req::Completion>(handlers::handle_completion)?
.on::<req::CodeActionRequest>(handlers::handle_code_action)? .on::<req::CodeActionRequest>(handlers::handle_code_action)?
.on::<req::CodeLensRequest>(handlers::handle_code_lens)? .on::<req::CodeLensRequest>(handlers::handle_code_lens)?
@ -884,7 +880,6 @@ where
fn update_file_notifications_on_threadpool( fn update_file_notifications_on_threadpool(
pool: &ThreadPool, pool: &ThreadPool,
world: WorldSnapshot, world: WorldSnapshot,
publish_decorations: bool,
task_sender: Sender<Task>, task_sender: Sender<Task>,
subscriptions: Vec<FileId>, subscriptions: Vec<FileId>,
) { ) {
@ -904,19 +899,6 @@ fn update_file_notifications_on_threadpool(
} }
} }
} }
if publish_decorations {
match handlers::publish_decorations(&world, file_id) {
Err(e) => {
if !is_canceled(&e) {
log::error!("failed to compute decorations: {:?}", e);
}
}
Ok(params) => {
let not = notification_new::<req::PublishDecorations>(params);
task_sender.send(Task::Notify(not)).unwrap();
}
}
}
} }
}); });
} }

View file

@ -38,7 +38,7 @@ use crate::{
}, },
diagnostics::DiagnosticTask, diagnostics::DiagnosticTask,
from_json, from_json,
req::{self, Decoration, InlayHint, InlayHintsParams}, req::{self, InlayHint, InlayHintsParams},
semantic_tokens::SemanticTokensBuilder, semantic_tokens::SemanticTokensBuilder,
world::WorldSnapshot, world::WorldSnapshot,
LspError, Result, LspError, Result,
@ -389,15 +389,6 @@ pub fn handle_runnables(
Ok(res) Ok(res)
} }
pub fn handle_decorations(
world: WorldSnapshot,
params: TextDocumentIdentifier,
) -> Result<Vec<Decoration>> {
let _p = profile("handle_decorations");
let file_id = params.try_conv_with(&world)?;
highlight(&world, file_id)
}
pub fn handle_completion( pub fn handle_completion(
world: WorldSnapshot, world: WorldSnapshot,
params: req::CompletionParams, params: req::CompletionParams,
@ -970,15 +961,6 @@ pub fn publish_diagnostics(world: &WorldSnapshot, file_id: FileId) -> Result<Dia
Ok(DiagnosticTask::SetNative(file_id, diagnostics)) Ok(DiagnosticTask::SetNative(file_id, diagnostics))
} }
pub fn publish_decorations(
world: &WorldSnapshot,
file_id: FileId,
) -> Result<req::PublishDecorationsParams> {
let _p = profile("publish_decorations");
let uri = world.file_id_to_uri(file_id)?;
Ok(req::PublishDecorationsParams { uri, decorations: highlight(&world, file_id)? })
}
fn to_lsp_runnable( fn to_lsp_runnable(
world: &WorldSnapshot, world: &WorldSnapshot,
file_id: FileId, file_id: FileId,
@ -1008,21 +990,6 @@ fn to_lsp_runnable(
}) })
} }
fn highlight(world: &WorldSnapshot, file_id: FileId) -> Result<Vec<Decoration>> {
let line_index = world.analysis().file_line_index(file_id)?;
let res = world
.analysis()
.highlight(file_id)?
.into_iter()
.map(|h| Decoration {
range: h.range.conv_with(&line_index),
tag: h.highlight.to_string(),
binding_hash: h.binding_hash.map(|x| x.to_string()),
})
.collect();
Ok(res)
}
pub fn handle_inlay_hints( pub fn handle_inlay_hints(
world: WorldSnapshot, world: WorldSnapshot,
params: InlayHintsParams, params: InlayHintsParams,

View file

@ -1,6 +1,6 @@
//! Defines `rust-analyzer` specific custom messages. //! Defines `rust-analyzer` specific custom messages.
use lsp_types::{Location, Position, Range, TextDocumentIdentifier, Url}; use lsp_types::{Location, Position, Range, TextDocumentIdentifier};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -86,36 +86,6 @@ pub struct FindMatchingBraceParams {
pub offsets: Vec<Position>, pub offsets: Vec<Position>,
} }
pub enum DecorationsRequest {}
impl Request for DecorationsRequest {
type Params = TextDocumentIdentifier;
type Result = Vec<Decoration>;
const METHOD: &'static str = "rust-analyzer/decorationsRequest";
}
pub enum PublishDecorations {}
impl Notification for PublishDecorations {
type Params = PublishDecorationsParams;
const METHOD: &'static str = "rust-analyzer/publishDecorations";
}
#[derive(Deserialize, Serialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct PublishDecorationsParams {
pub uri: Url,
pub decorations: Vec<Decoration>,
}
#[derive(Deserialize, Serialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Decoration {
pub range: Range,
pub tag: String,
pub binding_hash: Option<String>,
}
pub enum ParentModule {} pub enum ParentModule {}
impl Request for ParentModule { impl Request for ParentModule {

View file

@ -182,16 +182,6 @@
"default": false, "default": false,
"description": "Use proposed semantic tokens API for syntax highlighting" "description": "Use proposed semantic tokens API for syntax highlighting"
}, },
"rust-analyzer.highlightingOn": {
"type": "boolean",
"default": false,
"description": "Highlight Rust code (overrides built-in syntax highlighting)"
},
"rust-analyzer.rainbowHighlightingOn": {
"type": "boolean",
"default": false,
"description": "When highlighting Rust code, use a unique color per identifier"
},
"rust-analyzer.featureFlags": { "rust-analyzer.featureFlags": {
"type": "object", "type": "object",
"default": {}, "default": {},

View file

@ -7,7 +7,6 @@ import { SemanticTokensFeature, DocumentSemanticsTokensSignature } from 'vscode-
export function configToServerOptions(config: Config) { export function configToServerOptions(config: Config) {
return { return {
publishDecorations: !config.highlightingSemanticTokens,
lruCapacity: config.lruCapacity, lruCapacity: config.lruCapacity,
inlayHintsType: config.inlayHints.typeHints, inlayHintsType: config.inlayHints.typeHints,

View file

@ -71,8 +71,6 @@ export class Config {
get channel() { return this.cfg.get<UpdatesChannel>("updates.channel")!; } get channel() { return this.cfg.get<UpdatesChannel>("updates.channel")!; }
get askBeforeDownload() { return this.cfg.get<boolean>("updates.askBeforeDownload")!; } get askBeforeDownload() { return this.cfg.get<boolean>("updates.askBeforeDownload")!; }
get highlightingSemanticTokens() { return this.cfg.get<boolean>("highlighting.semanticTokens")!; } get highlightingSemanticTokens() { return this.cfg.get<boolean>("highlighting.semanticTokens")!; }
get highlightingOn() { return this.cfg.get<boolean>("highlightingOn")!; }
get rainbowHighlightingOn() { return this.cfg.get<boolean>("rainbowHighlightingOn")!; }
get lruCapacity() { return this.cfg.get<null | number>("lruCapacity")!; } get lruCapacity() { return this.cfg.get<null | number>("lruCapacity")!; }
get excludeGlobs() { return this.cfg.get<string[]>("excludeGlobs")!; } get excludeGlobs() { return this.cfg.get<string[]>("excludeGlobs")!; }
get useClientWatching() { return this.cfg.get<boolean>("useClientWatching")!; } get useClientWatching() { return this.cfg.get<boolean>("useClientWatching")!; }

View file

@ -1,255 +0,0 @@
import * as vscode from 'vscode';
import * as ra from './rust-analyzer-api';
import { ColorTheme, TextMateRuleSettings } from './color_theme';
import { Ctx } from './ctx';
import { sendRequestWithRetry, isRustDocument } from './util';
export function activateHighlighting(ctx: Ctx) {
const highlighter = new Highlighter(ctx);
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(),
);
// 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(),
null,
ctx.subscriptions,
);
vscode.window.onDidChangeActiveTextEditor(
async (editor: vscode.TextEditor | undefined) => {
if (!editor || !isRustDocument(editor.document)) return;
if (!ctx.config.highlightingOn) return;
const client = ctx.client;
if (!client) return;
const decorations = await sendRequestWithRetry(
client,
ra.decorationsRequest,
{ uri: editor.document.uri.toString() },
);
highlighter.setHighlights(editor, decorations);
},
null,
ctx.subscriptions,
);
}
// 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));
const randomInt = (min: number, max: number) => {
return Math.abs(random()) % (max - min + 1) + min;
};
const h = randomInt(0, 360);
const s = randomInt(42, 98);
const l = shade === 'light' ? randomInt(15, 40) : randomInt(40, 90);
return `hsl(${h},${s}%,${l}%)`;
}
class Highlighter {
private ctx: Ctx;
private decorations: Map<
string,
vscode.TextEditorDecorationType
> | null = null;
constructor(ctx: Ctx) {
this.ctx = ctx;
}
public removeHighlights() {
if (this.decorations == null) {
return;
}
// Decorations are removed when the object is disposed
for (const decoration of this.decorations.values()) {
decoration.dispose();
}
this.decorations = null;
}
public setHighlights(editor: vscode.TextEditor, highlights: ra.Decoration[]) {
const client = this.ctx.client;
if (!client) return;
// Initialize decorations if necessary
//
// Note: decoration objects need to be kept around so we can dispose them
// if the user disables syntax highlighting
if (this.decorations == null) {
this.decorations = initDecorations();
}
const byTag: Map<string, vscode.Range[]> = new Map();
const colorfulIdents: Map<
string,
[vscode.Range[], boolean]
> = new Map();
const rainbowTime = this.ctx.config.rainbowHighlightingOn;
for (const tag of this.decorations.keys()) {
byTag.set(tag, []);
}
for (const d of highlights) {
if (!byTag.get(d.tag)) {
continue;
}
if (rainbowTime && d.bindingHash) {
if (!colorfulIdents.has(d.bindingHash)) {
const mut = d.tag.endsWith('.mut');
colorfulIdents.set(d.bindingHash, [[], mut]);
}
colorfulIdents
.get(d.bindingHash)![0]
.push(
client.protocol2CodeConverter.asRange(d.range),
);
} else {
byTag
.get(d.tag)!
.push(
client.protocol2CodeConverter.asRange(d.range),
);
}
}
for (const tag of byTag.keys()) {
const dec = this.decorations.get(
tag,
) as vscode.TextEditorDecorationType;
const ranges = byTag.get(tag)!;
editor.setDecorations(dec, ranges);
}
for (const [hash, [ranges, mut]] of colorfulIdents.entries()) {
const textDecoration = mut ? 'underline' : undefined;
const dec = vscode.window.createTextEditorDecorationType({
light: { color: fancify(hash, 'light'), textDecoration },
dark: { color: fancify(hash, 'dark'), textDecoration },
});
editor.setDecorations(dec, ranges);
}
}
}
function initDecorations(): Map<string, vscode.TextEditorDecorationType> {
const theme = ColorTheme.load();
const res = new Map();
TAG_TO_SCOPES.forEach((scopes, tag) => {
// We are going to axe this soon, so don't try to detect unknown tags.
// Users should switch to the new semantic tokens implementation.
if (!scopes) return;
const rule = theme.lookup(scopes);
const decor = createDecorationFromTextmate(rule);
res.set(tag, decor);
});
return res;
}
function createDecorationFromTextmate(
themeStyle: TextMateRuleSettings,
): vscode.TextEditorDecorationType {
const decorationOptions: vscode.DecorationRenderOptions = {};
decorationOptions.rangeBehavior = vscode.DecorationRangeBehavior.OpenOpen;
if (themeStyle.foreground) {
decorationOptions.color = themeStyle.foreground;
}
if (themeStyle.background) {
decorationOptions.backgroundColor = themeStyle.background;
}
if (themeStyle.fontStyle) {
const parts: string[] = themeStyle.fontStyle.split(' ');
parts.forEach(part => {
switch (part) {
case 'italic':
decorationOptions.fontStyle = 'italic';
break;
case 'bold':
decorationOptions.fontWeight = 'bold';
break;
case 'underline':
decorationOptions.textDecoration = 'underline';
break;
default:
break;
}
});
}
return vscode.window.createTextEditorDecorationType(decorationOptions);
}
// sync with tags from `syntax_highlighting.rs`.
const TAG_TO_SCOPES = new Map<string, string[]>([
["field", ["entity.name.field"]],
["function", ["entity.name.function"]],
["module", ["entity.name.module"]],
["constant", ["entity.name.constant"]],
["macro", ["entity.name.macro"]],
["variable", ["variable"]],
["variable.mutable", ["variable", "meta.mutable"]],
["type", ["entity.name.type"]],
["type.builtin", ["entity.name.type", "support.type.primitive"]],
["type.self", ["entity.name.type.parameter.self"]],
["type.param", ["entity.name.type.parameter", "entity.name.type.param.rust"]],
["type.lifetime", ["entity.name.type.lifetime", "entity.name.lifetime.rust"]],
["literal.byte", ["constant.character.byte"]],
["literal.char", ["constant.character.rust"]],
["numeric_literal", ["constant.numeric"]],
["comment", ["comment"]],
["string_literal", ["string.quoted"]],
["attribute", ["meta.attribute.rust"]],
["keyword", ["keyword"]],
["keyword.unsafe", ["keyword.other.unsafe"]],
["keyword.control", ["keyword.control"]],
]);
function randomU32Numbers(seed: number) {
let random = seed | 0;
return () => {
random ^= random << 13;
random ^= random >> 17;
random ^= random << 5;
random |= 0;
return random;
};
}
function hashString(str: string): number {
let res = 0;
for (let i = 0; i < str.length; ++i) {
const c = str.codePointAt(i)!;
res = (res * 31 + c) & ~0;
}
return res;
}

View file

@ -7,7 +7,6 @@ import * as commands from './commands';
import { activateInlayHints } from './inlay_hints'; import { activateInlayHints } from './inlay_hints';
import { activateStatusDisplay } from './status_display'; import { activateStatusDisplay } from './status_display';
import { Ctx } from './ctx'; import { Ctx } from './ctx';
import { activateHighlighting } from './highlighting';
import { Config, NIGHTLY_TAG } from './config'; import { Config, NIGHTLY_TAG } from './config';
import { log, assert } from './util'; import { log, assert } from './util';
import { PersistentState } from './persistent_state'; import { PersistentState } from './persistent_state';
@ -97,9 +96,6 @@ export async function activate(context: vscode.ExtensionContext) {
activateStatusDisplay(ctx); activateStatusDisplay(ctx);
if (!ctx.config.highlightingSemanticTokens) {
activateHighlighting(ctx);
}
activateInlayHints(ctx); activateInlayHints(ctx);
vscode.workspace.onDidChangeConfiguration( vscode.workspace.onDidChangeConfiguration(