From e140f70e3cc31f217c1ae01b30bd25dda954b1e6 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 22 Feb 2022 17:05:55 -0800 Subject: [PATCH] Show document highlights from the language server when moving the cursor --- crates/editor/src/editor.rs | 75 +++++++++++++ crates/project/src/lsp_command.rs | 144 ++++++++++++++++++++++++- crates/project/src/project.rs | 19 +++- crates/rpc/proto/zed.proto | 116 ++++++++++++-------- crates/rpc/src/proto.rs | 4 + crates/server/src/rpc.rs | 157 ++++++++++++++++++++++++++++ crates/theme/src/theme.rs | 4 + crates/zed/assets/themes/_base.toml | 2 + 8 files changed, 472 insertions(+), 49 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 7c745c0702..254f2ee415 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -442,6 +442,7 @@ pub struct Editor { next_completion_id: CompletionId, available_code_actions: Option<(ModelHandle, Arc<[CodeAction]>)>, code_actions_task: Option>, + document_highlights_task: Option>, pending_rename: Option, } @@ -903,6 +904,7 @@ impl Editor { next_completion_id: 0, available_code_actions: Default::default(), code_actions_task: Default::default(), + document_highlights_task: Default::default(), pending_rename: Default::default(), }; this.end_selection(cx); @@ -2295,6 +2297,76 @@ impl Editor { None } + fn refresh_document_highlights(&mut self, cx: &mut ViewContext) -> Option<()> { + let project = self.project.as_ref()?; + let buffer = self.buffer.read(cx); + let newest_selection = self.newest_anchor_selection().clone(); + let cursor_position = newest_selection.head(); + let (cursor_buffer, cursor_buffer_position) = + buffer.text_anchor_for_position(cursor_position.clone(), cx)?; + let (tail_buffer, _) = buffer.text_anchor_for_position(newest_selection.tail(), cx)?; + if cursor_buffer != tail_buffer { + return None; + } + + let highlights = project.update(cx, |project, cx| { + project.document_highlights(&cursor_buffer, cursor_buffer_position, cx) + }); + + enum DocumentHighlightRead {} + enum DocumentHighlightWrite {} + + self.document_highlights_task = Some(cx.spawn_weak(|this, mut cx| async move { + let highlights = highlights.log_err().await; + if let Some((this, highlights)) = this.upgrade(&cx).zip(highlights) { + this.update(&mut cx, |this, cx| { + let buffer_id = cursor_position.buffer_id; + let excerpt_id = cursor_position.excerpt_id.clone(); + let settings = (this.build_settings)(cx); + let buffer = this.buffer.read(cx); + if !buffer + .text_anchor_for_position(cursor_position, cx) + .map_or(false, |(buffer, _)| buffer == cursor_buffer) + { + return; + } + + let mut write_ranges = Vec::new(); + let mut read_ranges = Vec::new(); + for highlight in highlights { + let range = Anchor { + buffer_id, + excerpt_id: excerpt_id.clone(), + text_anchor: highlight.range.start, + }..Anchor { + buffer_id, + excerpt_id: excerpt_id.clone(), + text_anchor: highlight.range.end, + }; + if highlight.kind == lsp::DocumentHighlightKind::WRITE { + write_ranges.push(range); + } else { + read_ranges.push(range); + } + } + + this.highlight_ranges::( + read_ranges, + settings.style.document_highlight_read_background, + cx, + ); + this.highlight_ranges::( + write_ranges, + settings.style.document_highlight_write_background, + cx, + ); + cx.notify(); + }); + } + })); + None + } + pub fn render_code_actions_indicator(&self, cx: &mut ViewContext) -> Option { if self.available_code_actions.is_some() { enum Tag {} @@ -4840,6 +4912,7 @@ impl Editor { self.available_code_actions.take(); } self.refresh_code_actions(cx); + self.refresh_document_highlights(cx); self.pause_cursor_blinking(cx); cx.emit(Event::SelectionsChanged); @@ -5294,6 +5367,8 @@ impl EditorSettings { highlighted_line_background: Default::default(), diff_background_deleted: Default::default(), diff_background_inserted: Default::default(), + document_highlight_read_background: Default::default(), + document_highlight_write_background: Default::default(), line_number: Default::default(), line_number_active: Default::default(), selection: Default::default(), diff --git a/crates/project/src/lsp_command.rs b/crates/project/src/lsp_command.rs index 5e9f7c81ad..3b502fc8fa 100644 --- a/crates/project/src/lsp_command.rs +++ b/crates/project/src/lsp_command.rs @@ -1,4 +1,4 @@ -use crate::{Location, Project, ProjectTransaction}; +use crate::{DocumentHighlight, Location, Project, ProjectTransaction}; use anyhow::{anyhow, Result}; use async_trait::async_trait; use client::{proto, PeerId}; @@ -8,7 +8,8 @@ use language::{ proto::{deserialize_anchor, serialize_anchor}, range_from_lsp, Anchor, Bias, Buffer, PointUtf16, ToLspPosition, ToPointUtf16, }; -use std::{ops::Range, path::Path}; +use lsp::DocumentHighlightKind; +use std::{cmp::Reverse, ops::Range, path::Path}; #[async_trait(?Send)] pub(crate) trait LspCommand: 'static + Sized { @@ -70,6 +71,10 @@ pub(crate) struct GetReferences { pub position: PointUtf16, } +pub(crate) struct GetDocumentHighlights { + pub position: PointUtf16, +} + #[async_trait(?Send)] impl LspCommand for PrepareRename { type Response = Option>; @@ -598,3 +603,138 @@ impl LspCommand for GetReferences { message.buffer_id } } + +#[async_trait(?Send)] +impl LspCommand for GetDocumentHighlights { + type Response = Vec; + type LspRequest = lsp::request::DocumentHighlightRequest; + type ProtoRequest = proto::GetDocumentHighlights; + + fn to_lsp(&self, path: &Path, _: &AppContext) -> lsp::DocumentHighlightParams { + lsp::DocumentHighlightParams { + text_document_position_params: lsp::TextDocumentPositionParams { + text_document: lsp::TextDocumentIdentifier { + uri: lsp::Url::from_file_path(path).unwrap(), + }, + position: self.position.to_lsp_position(), + }, + work_done_progress_params: Default::default(), + partial_result_params: Default::default(), + } + } + + async fn response_from_lsp( + self, + lsp_highlights: Option>, + _: ModelHandle, + buffer: ModelHandle, + cx: AsyncAppContext, + ) -> Result> { + buffer.read_with(&cx, |buffer, _| { + let mut lsp_highlights = lsp_highlights.unwrap_or_default(); + lsp_highlights.sort_unstable_by_key(|h| (h.range.start, Reverse(h.range.end))); + Ok(lsp_highlights + .into_iter() + .map(|lsp_highlight| { + let start = buffer + .clip_point_utf16(point_from_lsp(lsp_highlight.range.start), Bias::Left); + let end = buffer + .clip_point_utf16(point_from_lsp(lsp_highlight.range.end), Bias::Left); + DocumentHighlight { + range: buffer.anchor_after(start)..buffer.anchor_before(end), + kind: lsp_highlight + .kind + .unwrap_or(lsp::DocumentHighlightKind::READ), + } + }) + .collect()) + }) + } + + fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDocumentHighlights { + proto::GetDocumentHighlights { + project_id, + buffer_id: buffer.remote_id(), + position: Some(language::proto::serialize_anchor( + &buffer.anchor_before(self.position), + )), + } + } + + fn from_proto( + message: proto::GetDocumentHighlights, + _: &mut Project, + buffer: &Buffer, + ) -> Result { + let position = message + .position + .and_then(deserialize_anchor) + .ok_or_else(|| anyhow!("invalid position"))?; + if !buffer.can_resolve(&position) { + Err(anyhow!("cannot resolve position"))?; + } + Ok(Self { + position: position.to_point_utf16(buffer), + }) + } + + fn response_to_proto( + response: Vec, + _: &mut Project, + _: PeerId, + _: &clock::Global, + _: &AppContext, + ) -> proto::GetDocumentHighlightsResponse { + let highlights = response + .into_iter() + .map(|highlight| proto::DocumentHighlight { + start: Some(serialize_anchor(&highlight.range.start)), + end: Some(serialize_anchor(&highlight.range.end)), + kind: match highlight.kind { + DocumentHighlightKind::TEXT => proto::document_highlight::Kind::Text.into(), + DocumentHighlightKind::WRITE => proto::document_highlight::Kind::Write.into(), + DocumentHighlightKind::READ => proto::document_highlight::Kind::Read.into(), + _ => proto::document_highlight::Kind::Text.into(), + }, + }) + .collect(); + proto::GetDocumentHighlightsResponse { highlights } + } + + async fn response_from_proto( + self, + message: proto::GetDocumentHighlightsResponse, + _: ModelHandle, + _: ModelHandle, + _: AsyncAppContext, + ) -> Result> { + Ok(message + .highlights + .into_iter() + .map(|highlight| { + let start = highlight + .start + .and_then(deserialize_anchor) + .ok_or_else(|| anyhow!("missing target start"))?; + let end = highlight + .end + .and_then(deserialize_anchor) + .ok_or_else(|| anyhow!("missing target end"))?; + let kind = match proto::document_highlight::Kind::from_i32(highlight.kind) { + Some(proto::document_highlight::Kind::Text) => DocumentHighlightKind::TEXT, + Some(proto::document_highlight::Kind::Read) => DocumentHighlightKind::READ, + Some(proto::document_highlight::Kind::Write) => DocumentHighlightKind::WRITE, + None => DocumentHighlightKind::TEXT, + }; + Ok(DocumentHighlight { + range: start..end, + kind, + }) + }) + .collect::>>()?) + } + + fn buffer_id_from_proto(message: &proto::GetDocumentHighlights) -> u64 { + message.buffer_id + } +} diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index aebabcd92e..4e67b11a59 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -18,7 +18,7 @@ use language::{ Diagnostic, DiagnosticEntry, File as _, Language, LanguageRegistry, Operation, PointUtf16, ToLspPosition, ToOffset, ToPointUtf16, Transaction, }; -use lsp::{DiagnosticSeverity, LanguageServer}; +use lsp::{DiagnosticSeverity, DocumentHighlightKind, LanguageServer}; use lsp_command::*; use postage::{broadcast, prelude::Stream, sink::Sink, watch}; use rand::prelude::*; @@ -123,6 +123,12 @@ pub struct Location { pub range: Range, } +#[derive(Debug)] +pub struct DocumentHighlight { + pub range: Range, + pub kind: DocumentHighlightKind, +} + #[derive(Clone, Debug)] pub struct Symbol { pub source_worktree_id: WorktreeId, @@ -202,6 +208,7 @@ impl Project { client.add_entity_request_handler(Self::handle_get_code_actions); client.add_entity_request_handler(Self::handle_get_completions); client.add_entity_request_handler(Self::handle_lsp_command::); + client.add_entity_request_handler(Self::handle_lsp_command::); client.add_entity_request_handler(Self::handle_lsp_command::); client.add_entity_request_handler(Self::handle_lsp_command::); client.add_entity_request_handler(Self::handle_lsp_command::); @@ -1269,6 +1276,16 @@ impl Project { self.request_lsp(buffer.clone(), GetReferences { position }, cx) } + pub fn document_highlights( + &self, + buffer: &ModelHandle, + position: T, + cx: &mut ModelContext, + ) -> Task>> { + let position = position.to_point_utf16(buffer.read(cx)); + self.request_lsp(buffer.clone(), GetDocumentHighlights { position }, cx) + } + pub fn symbols(&self, query: &str, cx: &mut ModelContext) -> Task>> { if self.is_local() { let mut language_servers = HashMap::default(); diff --git a/crates/rpc/proto/zed.proto b/crates/rpc/proto/zed.proto index 426ba93821..8e83b09963 100644 --- a/crates/rpc/proto/zed.proto +++ b/crates/rpc/proto/zed.proto @@ -25,57 +25,59 @@ message Envelope { GetDefinitionResponse get_definition_response = 19; GetReferences get_references = 20; GetReferencesResponse get_references_response = 21; - GetProjectSymbols get_project_symbols = 22; - GetProjectSymbolsResponse get_project_symbols_response = 23; - OpenBufferForSymbol open_buffer_for_symbol = 24; - OpenBufferForSymbolResponse open_buffer_for_symbol_response = 25; + GetDocumentHighlights get_document_highlights = 22; + GetDocumentHighlightsResponse get_document_highlights_response = 23; + GetProjectSymbols get_project_symbols = 24; + GetProjectSymbolsResponse get_project_symbols_response = 25; + OpenBufferForSymbol open_buffer_for_symbol = 26; + OpenBufferForSymbolResponse open_buffer_for_symbol_response = 27; - RegisterWorktree register_worktree = 26; - UnregisterWorktree unregister_worktree = 27; - ShareWorktree share_worktree = 28; - UpdateWorktree update_worktree = 29; - UpdateDiagnosticSummary update_diagnostic_summary = 30; - DiskBasedDiagnosticsUpdating disk_based_diagnostics_updating = 31; - DiskBasedDiagnosticsUpdated disk_based_diagnostics_updated = 32; + RegisterWorktree register_worktree = 28; + UnregisterWorktree unregister_worktree = 29; + ShareWorktree share_worktree = 30; + UpdateWorktree update_worktree = 31; + UpdateDiagnosticSummary update_diagnostic_summary = 32; + DiskBasedDiagnosticsUpdating disk_based_diagnostics_updating = 33; + DiskBasedDiagnosticsUpdated disk_based_diagnostics_updated = 34; - OpenBuffer open_buffer = 33; - OpenBufferResponse open_buffer_response = 34; - CloseBuffer close_buffer = 35; - UpdateBuffer update_buffer = 36; - UpdateBufferFile update_buffer_file = 37; - SaveBuffer save_buffer = 38; - BufferSaved buffer_saved = 39; - BufferReloaded buffer_reloaded = 40; - FormatBuffers format_buffers = 41; - FormatBuffersResponse format_buffers_response = 42; - GetCompletions get_completions = 43; - GetCompletionsResponse get_completions_response = 44; - ApplyCompletionAdditionalEdits apply_completion_additional_edits = 45; - ApplyCompletionAdditionalEditsResponse apply_completion_additional_edits_response = 46; - GetCodeActions get_code_actions = 47; - GetCodeActionsResponse get_code_actions_response = 48; - ApplyCodeAction apply_code_action = 49; - ApplyCodeActionResponse apply_code_action_response = 50; - PrepareRename prepare_rename = 51; - PrepareRenameResponse prepare_rename_response = 52; - PerformRename perform_rename = 53; - PerformRenameResponse perform_rename_response = 54; + OpenBuffer open_buffer = 35; + OpenBufferResponse open_buffer_response = 36; + CloseBuffer close_buffer = 37; + UpdateBuffer update_buffer = 38; + UpdateBufferFile update_buffer_file = 39; + SaveBuffer save_buffer = 40; + BufferSaved buffer_saved = 41; + BufferReloaded buffer_reloaded = 42; + FormatBuffers format_buffers = 43; + FormatBuffersResponse format_buffers_response = 44; + GetCompletions get_completions = 45; + GetCompletionsResponse get_completions_response = 46; + ApplyCompletionAdditionalEdits apply_completion_additional_edits = 47; + ApplyCompletionAdditionalEditsResponse apply_completion_additional_edits_response = 48; + GetCodeActions get_code_actions = 49; + GetCodeActionsResponse get_code_actions_response = 50; + ApplyCodeAction apply_code_action = 51; + ApplyCodeActionResponse apply_code_action_response = 52; + PrepareRename prepare_rename = 53; + PrepareRenameResponse prepare_rename_response = 54; + PerformRename perform_rename = 55; + PerformRenameResponse perform_rename_response = 56; - GetChannels get_channels = 55; - GetChannelsResponse get_channels_response = 56; - JoinChannel join_channel = 57; - JoinChannelResponse join_channel_response = 58; - LeaveChannel leave_channel = 59; - SendChannelMessage send_channel_message = 60; - SendChannelMessageResponse send_channel_message_response = 61; - ChannelMessageSent channel_message_sent = 62; - GetChannelMessages get_channel_messages = 63; - GetChannelMessagesResponse get_channel_messages_response = 64; + GetChannels get_channels = 57; + GetChannelsResponse get_channels_response = 58; + JoinChannel join_channel = 59; + JoinChannelResponse join_channel_response = 60; + LeaveChannel leave_channel = 61; + SendChannelMessage send_channel_message = 62; + SendChannelMessageResponse send_channel_message_response = 63; + ChannelMessageSent channel_message_sent = 64; + GetChannelMessages get_channel_messages = 65; + GetChannelMessagesResponse get_channel_messages_response = 66; - UpdateContacts update_contacts = 65; + UpdateContacts update_contacts = 67; - GetUsers get_users = 66; - GetUsersResponse get_users_response = 67; + GetUsers get_users = 68; + GetUsersResponse get_users_response = 69; } } @@ -181,12 +183,34 @@ message GetReferencesResponse { repeated Location locations = 1; } +message GetDocumentHighlights { + uint64 project_id = 1; + uint64 buffer_id = 2; + Anchor position = 3; + } + +message GetDocumentHighlightsResponse { + repeated DocumentHighlight highlights = 1; +} + message Location { Buffer buffer = 1; Anchor start = 2; Anchor end = 3; } +message DocumentHighlight { + Kind kind = 1; + Anchor start = 2; + Anchor end = 3; + + enum Kind { + Text = 0; + Read = 1; + Write = 2; + } +} + message GetProjectSymbols { uint64 project_id = 1; string query = 2; diff --git a/crates/rpc/src/proto.rs b/crates/rpc/src/proto.rs index 61c4585deb..b6d5c4b438 100644 --- a/crates/rpc/src/proto.rs +++ b/crates/rpc/src/proto.rs @@ -157,6 +157,8 @@ messages!( (GetCompletionsResponse, Foreground), (GetDefinition, Foreground), (GetDefinitionResponse, Foreground), + (GetDocumentHighlights, Foreground), + (GetDocumentHighlightsResponse, Foreground), (GetReferences, Foreground), (GetReferencesResponse, Foreground), (GetProjectSymbols, Background), @@ -210,6 +212,7 @@ request_messages!( (GetCodeActions, GetCodeActionsResponse), (GetCompletions, GetCompletionsResponse), (GetDefinition, GetDefinitionResponse), + (GetDocumentHighlights, GetDocumentHighlightsResponse), (GetReferences, GetReferencesResponse), (GetProjectSymbols, GetProjectSymbolsResponse), (GetUsers, GetUsersResponse), @@ -245,6 +248,7 @@ entity_messages!( GetCodeActions, GetCompletions, GetDefinition, + GetDocumentHighlights, GetReferences, GetProjectSymbols, JoinProject, diff --git a/crates/server/src/rpc.rs b/crates/server/src/rpc.rs index 39c2d8a20f..a767676fad 100644 --- a/crates/server/src/rpc.rs +++ b/crates/server/src/rpc.rs @@ -80,6 +80,7 @@ impl Server { .add_message_handler(Server::disk_based_diagnostics_updated) .add_request_handler(Server::get_definition) .add_request_handler(Server::get_references) + .add_request_handler(Server::get_document_highlights) .add_request_handler(Server::get_project_symbols) .add_request_handler(Server::open_buffer_for_symbol) .add_request_handler(Server::open_buffer) @@ -604,6 +605,20 @@ impl Server { .await?) } + async fn get_document_highlights( + self: Arc, + request: TypedEnvelope, + ) -> tide::Result { + let host_connection_id = self + .state() + .read_project(request.payload.project_id, request.sender_id)? + .host_connection_id; + Ok(self + .peer + .forward_request(request.sender_id, host_connection_id, request.payload) + .await?) + } + async fn get_project_symbols( self: Arc, request: TypedEnvelope, @@ -2855,6 +2870,148 @@ mod tests { }); } + #[gpui::test(iterations = 10)] + async fn test_document_highlights(mut cx_a: TestAppContext, mut cx_b: TestAppContext) { + cx_a.foreground().forbid_parking(); + let lang_registry = Arc::new(LanguageRegistry::new()); + let fs = FakeFs::new(cx_a.background()); + fs.insert_tree( + "/root-1", + json!({ + ".zed.toml": r#"collaborators = ["user_b"]"#, + "main.rs": "fn double(number: i32) -> i32 { number + number }", + }), + ) + .await; + + // Set up a fake language server. + let (language_server_config, mut fake_language_servers) = LanguageServerConfig::fake(); + lang_registry.add(Arc::new(Language::new( + LanguageConfig { + name: "Rust".into(), + path_suffixes: vec!["rs".to_string()], + language_server: Some(language_server_config), + ..Default::default() + }, + Some(tree_sitter_rust::language()), + ))); + + // Connect to a server as 2 clients. + let mut server = TestServer::start(cx_a.foreground(), cx_a.background()).await; + let client_a = server.create_client(&mut cx_a, "user_a").await; + let client_b = server.create_client(&mut cx_b, "user_b").await; + + // Share a project as client A + let project_a = cx_a.update(|cx| { + Project::local( + client_a.clone(), + client_a.user_store.clone(), + lang_registry.clone(), + fs.clone(), + cx, + ) + }); + let (worktree_a, _) = project_a + .update(&mut cx_a, |p, cx| { + p.find_or_create_local_worktree("/root-1", false, cx) + }) + .await + .unwrap(); + worktree_a + .read_with(&cx_a, |tree, _| tree.as_local().unwrap().scan_complete()) + .await; + let project_id = project_a.update(&mut cx_a, |p, _| p.next_remote_id()).await; + let worktree_id = worktree_a.read_with(&cx_a, |tree, _| tree.id()); + project_a + .update(&mut cx_a, |p, cx| p.share(cx)) + .await + .unwrap(); + + // Join the worktree as client B. + let project_b = Project::remote( + project_id, + client_b.clone(), + client_b.user_store.clone(), + lang_registry.clone(), + fs.clone(), + &mut cx_b.to_async(), + ) + .await + .unwrap(); + + // Open the file on client B. + let buffer_b = cx_b + .background() + .spawn(project_b.update(&mut cx_b, |p, cx| { + p.open_buffer((worktree_id, "main.rs"), cx) + })) + .await + .unwrap(); + + // Request document highlights as the guest. + let highlights = + project_b.update(&mut cx_b, |p, cx| p.document_highlights(&buffer_b, 34, cx)); + + let mut fake_language_server = fake_language_servers.next().await.unwrap(); + fake_language_server.handle_request::( + |params| { + assert_eq!( + params + .text_document_position_params + .text_document + .uri + .as_str(), + "file:///root-1/main.rs" + ); + assert_eq!( + params.text_document_position_params.position, + lsp::Position::new(0, 34) + ); + Some(vec![ + lsp::DocumentHighlight { + kind: Some(lsp::DocumentHighlightKind::WRITE), + range: lsp::Range::new( + lsp::Position::new(0, 10), + lsp::Position::new(0, 16), + ), + }, + lsp::DocumentHighlight { + kind: Some(lsp::DocumentHighlightKind::READ), + range: lsp::Range::new( + lsp::Position::new(0, 32), + lsp::Position::new(0, 38), + ), + }, + lsp::DocumentHighlight { + kind: Some(lsp::DocumentHighlightKind::READ), + range: lsp::Range::new( + lsp::Position::new(0, 41), + lsp::Position::new(0, 47), + ), + }, + ]) + }, + ); + + let highlights = highlights.await.unwrap(); + buffer_b.read_with(&cx_b, |buffer, _| { + let snapshot = buffer.snapshot(); + + let highlights = highlights + .into_iter() + .map(|highlight| (highlight.kind, highlight.range.to_offset(&snapshot))) + .collect::>(); + assert_eq!( + highlights, + &[ + (lsp::DocumentHighlightKind::WRITE, 10..16), + (lsp::DocumentHighlightKind::READ, 32..38), + (lsp::DocumentHighlightKind::READ, 41..47) + ] + ) + }); + } + #[gpui::test(iterations = 10)] async fn test_project_symbols(mut cx_a: TestAppContext, mut cx_b: TestAppContext) { cx_a.foreground().forbid_parking(); diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index a30dccb1a3..145996c6e9 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -279,6 +279,8 @@ pub struct EditorStyle { pub gutter_padding_factor: f32, pub active_line_background: Color, pub highlighted_line_background: Color, + pub document_highlight_read_background: Color, + pub document_highlight_write_background: Color, pub diff_background_deleted: Color, pub diff_background_inserted: Color, pub line_number: Color, @@ -386,6 +388,8 @@ impl InputEditorStyle { gutter_padding_factor: Default::default(), active_line_background: Default::default(), highlighted_line_background: Default::default(), + document_highlight_read_background: Default::default(), + document_highlight_write_background: Default::default(), diff_background_deleted: Default::default(), diff_background_inserted: Default::default(), line_number: Default::default(), diff --git a/crates/zed/assets/themes/_base.toml b/crates/zed/assets/themes/_base.toml index 5b9f822bf9..45448ae189 100644 --- a/crates/zed/assets/themes/_base.toml +++ b/crates/zed/assets/themes/_base.toml @@ -249,6 +249,8 @@ gutter_background = "$surface.1" gutter_padding_factor = 2.5 active_line_background = "$state.active_line" highlighted_line_background = "$state.highlighted_line" +document_highlight_read_background = "#99999920" +document_highlight_write_background = "#99999916" diff_background_deleted = "$state.deleted_line" diff_background_inserted = "$state.inserted_line" line_number = "$text.2.color"