Fix some issues with branch buffers (#18945)
* `Open Excerpts` command always opens the locations in the base buffer * LSP features like document-highlights, go-to-def, and inlay hints work correctly in branch buffers * Other LSP features like completions, code actions, and rename are disabled in branch buffers Release Notes: - N/A
This commit is contained in:
parent
cae548a50d
commit
53cc82b132
13 changed files with 554 additions and 267 deletions
|
@ -1,4 +1,4 @@
|
|||
use crate::{Editor, EditorEvent};
|
||||
use crate::{Editor, EditorEvent, SemanticsProvider};
|
||||
use collections::HashSet;
|
||||
use futures::{channel::mpsc, future::join_all};
|
||||
use gpui::{AppContext, EventEmitter, FocusableView, Model, Render, Subscription, Task, View};
|
||||
|
@ -6,7 +6,7 @@ use language::{Buffer, BufferEvent, Capability};
|
|||
use multi_buffer::{ExcerptRange, MultiBuffer};
|
||||
use project::Project;
|
||||
use smol::stream::StreamExt;
|
||||
use std::{any::TypeId, ops::Range, time::Duration};
|
||||
use std::{any::TypeId, ops::Range, rc::Rc, time::Duration};
|
||||
use text::ToOffset;
|
||||
use ui::prelude::*;
|
||||
use workspace::{
|
||||
|
@ -35,6 +35,12 @@ struct RecalculateDiff {
|
|||
debounce: bool,
|
||||
}
|
||||
|
||||
/// A provider of code semantics for branch buffers.
|
||||
///
|
||||
/// Requests in edited regions will return nothing, but requests in unchanged
|
||||
/// regions will be translated into the base buffer's coordinates.
|
||||
struct BranchBufferSemanticsProvider(Rc<dyn SemanticsProvider>);
|
||||
|
||||
impl ProposedChangesEditor {
|
||||
pub fn new<T: ToOffset>(
|
||||
buffers: Vec<ProposedChangesBuffer<T>>,
|
||||
|
@ -66,6 +72,13 @@ impl ProposedChangesEditor {
|
|||
editor: cx.new_view(|cx| {
|
||||
let mut editor = Editor::for_multibuffer(multibuffer.clone(), project, true, cx);
|
||||
editor.set_expand_all_diff_hunks();
|
||||
editor.set_completion_provider(None);
|
||||
editor.clear_code_action_providers();
|
||||
editor.set_semantics_provider(
|
||||
editor
|
||||
.semantics_provider()
|
||||
.map(|provider| Rc::new(BranchBufferSemanticsProvider(provider)) as _),
|
||||
);
|
||||
editor
|
||||
}),
|
||||
recalculate_diffs_tx,
|
||||
|
@ -76,7 +89,7 @@ impl ProposedChangesEditor {
|
|||
|
||||
while recalculate_diff.debounce {
|
||||
cx.background_executor()
|
||||
.timer(Duration::from_millis(250))
|
||||
.timer(Duration::from_millis(50))
|
||||
.await;
|
||||
let mut had_further_changes = false;
|
||||
while let Ok(next_recalculate_diff) = recalculate_diffs_rx.try_next() {
|
||||
|
@ -245,3 +258,103 @@ impl ToolbarItemView for ProposedChangesEditorToolbar {
|
|||
self.get_toolbar_item_location()
|
||||
}
|
||||
}
|
||||
|
||||
impl BranchBufferSemanticsProvider {
|
||||
fn to_base(
|
||||
&self,
|
||||
buffer: &Model<Buffer>,
|
||||
positions: &[text::Anchor],
|
||||
cx: &AppContext,
|
||||
) -> Option<Model<Buffer>> {
|
||||
let base_buffer = buffer.read(cx).diff_base_buffer()?;
|
||||
let version = base_buffer.read(cx).version();
|
||||
if positions
|
||||
.iter()
|
||||
.any(|position| !version.observed(position.timestamp))
|
||||
{
|
||||
return None;
|
||||
}
|
||||
Some(base_buffer)
|
||||
}
|
||||
}
|
||||
|
||||
impl SemanticsProvider for BranchBufferSemanticsProvider {
|
||||
fn hover(
|
||||
&self,
|
||||
buffer: &Model<Buffer>,
|
||||
position: text::Anchor,
|
||||
cx: &mut AppContext,
|
||||
) -> Option<Task<Vec<project::Hover>>> {
|
||||
let buffer = self.to_base(buffer, &[position], cx)?;
|
||||
self.0.hover(&buffer, position, cx)
|
||||
}
|
||||
|
||||
fn inlay_hints(
|
||||
&self,
|
||||
buffer: Model<Buffer>,
|
||||
range: Range<text::Anchor>,
|
||||
cx: &mut AppContext,
|
||||
) -> Option<Task<anyhow::Result<Vec<project::InlayHint>>>> {
|
||||
let buffer = self.to_base(&buffer, &[range.start, range.end], cx)?;
|
||||
self.0.inlay_hints(buffer, range, cx)
|
||||
}
|
||||
|
||||
fn resolve_inlay_hint(
|
||||
&self,
|
||||
hint: project::InlayHint,
|
||||
buffer: Model<Buffer>,
|
||||
server_id: lsp::LanguageServerId,
|
||||
cx: &mut AppContext,
|
||||
) -> Option<Task<anyhow::Result<project::InlayHint>>> {
|
||||
let buffer = self.to_base(&buffer, &[], cx)?;
|
||||
self.0.resolve_inlay_hint(hint, buffer, server_id, cx)
|
||||
}
|
||||
|
||||
fn supports_inlay_hints(&self, buffer: &Model<Buffer>, cx: &AppContext) -> bool {
|
||||
if let Some(buffer) = self.to_base(&buffer, &[], cx) {
|
||||
self.0.supports_inlay_hints(&buffer, cx)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn document_highlights(
|
||||
&self,
|
||||
buffer: &Model<Buffer>,
|
||||
position: text::Anchor,
|
||||
cx: &mut AppContext,
|
||||
) -> Option<Task<gpui::Result<Vec<project::DocumentHighlight>>>> {
|
||||
let buffer = self.to_base(&buffer, &[position], cx)?;
|
||||
self.0.document_highlights(&buffer, position, cx)
|
||||
}
|
||||
|
||||
fn definitions(
|
||||
&self,
|
||||
buffer: &Model<Buffer>,
|
||||
position: text::Anchor,
|
||||
kind: crate::GotoDefinitionKind,
|
||||
cx: &mut AppContext,
|
||||
) -> Option<Task<gpui::Result<Vec<project::LocationLink>>>> {
|
||||
let buffer = self.to_base(&buffer, &[position], cx)?;
|
||||
self.0.definitions(&buffer, position, kind, cx)
|
||||
}
|
||||
|
||||
fn range_for_rename(
|
||||
&self,
|
||||
_: &Model<Buffer>,
|
||||
_: text::Anchor,
|
||||
_: &mut AppContext,
|
||||
) -> Option<Task<gpui::Result<Option<Range<text::Anchor>>>>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn perform_rename(
|
||||
&self,
|
||||
_: &Model<Buffer>,
|
||||
_: text::Anchor,
|
||||
_: String,
|
||||
_: &mut AppContext,
|
||||
) -> Option<Task<gpui::Result<project::ProjectTransaction>>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue