Compare commits
13 Commits
fix-git-ht
...
v0.168.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
14b2cd06a7 | ||
|
|
5d35ba34e8 | ||
|
|
b1b8fc02b8 | ||
|
|
a8ef5aa87c | ||
|
|
e9f548639c | ||
|
|
37a019ec7a | ||
|
|
46f0a6860d | ||
|
|
74c82e1e1a | ||
|
|
da62407ef0 | ||
|
|
7d92b14e85 | ||
|
|
03c261566b | ||
|
|
b800ff51c0 | ||
|
|
56f288e635 |
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -16204,7 +16204,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zed"
|
||||
version = "0.168.0"
|
||||
version = "0.168.2"
|
||||
dependencies = [
|
||||
"activity_indicator",
|
||||
"anyhow",
|
||||
|
||||
@@ -993,7 +993,10 @@ pub(crate) struct FocusedBlock {
|
||||
|
||||
#[derive(Clone)]
|
||||
enum JumpData {
|
||||
MultiBufferRow(MultiBufferRow),
|
||||
MultiBufferRow {
|
||||
row: MultiBufferRow,
|
||||
line_offset_from_top: u32,
|
||||
},
|
||||
MultiBufferPoint {
|
||||
excerpt_id: ExcerptId,
|
||||
position: Point,
|
||||
@@ -12487,7 +12490,10 @@ impl Editor {
|
||||
);
|
||||
}
|
||||
}
|
||||
Some(JumpData::MultiBufferRow(row)) => {
|
||||
Some(JumpData::MultiBufferRow {
|
||||
row,
|
||||
line_offset_from_top,
|
||||
}) => {
|
||||
let point = MultiBufferPoint::new(row.0, 0);
|
||||
if let Some((buffer, buffer_point, _)) =
|
||||
self.buffer.read(cx).point_to_buffer_point(point, cx)
|
||||
@@ -12495,7 +12501,7 @@ impl Editor {
|
||||
let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
|
||||
new_selections_by_buffer
|
||||
.entry(buffer)
|
||||
.or_insert((Vec::new(), None))
|
||||
.or_insert((Vec::new(), Some(*line_offset_from_top)))
|
||||
.0
|
||||
.push(buffer_offset..buffer_offset)
|
||||
}
|
||||
|
||||
@@ -599,8 +599,15 @@ impl EditorElement {
|
||||
.row;
|
||||
if let Some((_, Some(hitbox))) = line_numbers.get(&MultiBufferRow(multi_buffer_row)) {
|
||||
if hitbox.contains(&event.position) {
|
||||
let scroll_position_row =
|
||||
position_map.scroll_pixel_position.y / position_map.line_height;
|
||||
let line_offset_from_top = display_row - scroll_position_row as u32;
|
||||
|
||||
editor.open_excerpts_common(
|
||||
Some(JumpData::MultiBufferRow(MultiBufferRow(multi_buffer_row))),
|
||||
Some(JumpData::MultiBufferRow {
|
||||
row: MultiBufferRow(multi_buffer_row),
|
||||
line_offset_from_top,
|
||||
}),
|
||||
modifiers.alt,
|
||||
cx,
|
||||
);
|
||||
@@ -2959,7 +2966,12 @@ impl EditorElement {
|
||||
selected_buffer_ids: &Vec<BufferId>,
|
||||
cx: &mut WindowContext,
|
||||
) -> AnyElement {
|
||||
let jump_data = header_jump_data(snapshot, DisplayRow(0), FILE_HEADER_HEIGHT, excerpt);
|
||||
let jump_data = header_jump_data(
|
||||
snapshot,
|
||||
DisplayRow(scroll_position as u32),
|
||||
FILE_HEADER_HEIGHT + MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
|
||||
excerpt,
|
||||
);
|
||||
|
||||
let editor_bg_color = cx.theme().colors().editor_background;
|
||||
|
||||
@@ -5096,13 +5108,12 @@ fn header_jump_data(
|
||||
let offset_from_excerpt_start = if jump_anchor == excerpt_start {
|
||||
0
|
||||
} else {
|
||||
let excerpt_start_row = language::ToPoint::to_point(&jump_anchor, buffer).row;
|
||||
let excerpt_start_row = language::ToPoint::to_point(&excerpt_start, buffer).row;
|
||||
jump_position.row - excerpt_start_row
|
||||
};
|
||||
|
||||
let line_offset_from_top = block_row_start.0
|
||||
+ height
|
||||
+ offset_from_excerpt_start.saturating_sub(
|
||||
let line_offset_from_top = (block_row_start.0 + height + offset_from_excerpt_start)
|
||||
.saturating_sub(
|
||||
snapshot
|
||||
.scroll_anchor
|
||||
.scroll_position(&snapshot.display_snapshot)
|
||||
|
||||
@@ -33,9 +33,9 @@ use util::ResultExt;
|
||||
|
||||
use crate::{
|
||||
current_platform, hash, init_app_menus, Action, ActionRegistry, Any, AnyView, AnyWindowHandle,
|
||||
Asset, AssetSource, BackgroundExecutor, ClipboardItem, Context, DispatchPhase, DisplayId,
|
||||
Entity, EventEmitter, FocusHandle, FocusId, ForegroundExecutor, Global, KeyBinding, Keymap,
|
||||
Keystroke, LayoutId, Menu, MenuItem, OwnedMenu, PathPromptOptions, Pixels, Platform,
|
||||
Asset, AssetSource, BackgroundExecutor, Bounds, ClipboardItem, Context, DispatchPhase,
|
||||
DisplayId, Entity, EventEmitter, FocusHandle, FocusId, ForegroundExecutor, Global, KeyBinding,
|
||||
Keymap, Keystroke, LayoutId, Menu, MenuItem, OwnedMenu, PathPromptOptions, Pixels, Platform,
|
||||
PlatformDisplay, Point, PromptBuilder, PromptHandle, PromptLevel, Render,
|
||||
RenderablePromptHandle, Reservation, ScreenCaptureSource, SharedString, SubscriberSet,
|
||||
Subscription, SvgRenderer, Task, TextSystem, View, ViewContext, Window, WindowAppearance,
|
||||
@@ -1612,6 +1612,12 @@ pub struct AnyTooltip {
|
||||
|
||||
/// The absolute position of the mouse when the tooltip was deployed.
|
||||
pub mouse_position: Point<Pixels>,
|
||||
|
||||
/// Whether the tooltitp can be hovered or not.
|
||||
pub hoverable: bool,
|
||||
|
||||
/// Bounds of the element that triggered the tooltip appearance.
|
||||
pub origin_bounds: Bounds<Pixels>,
|
||||
}
|
||||
|
||||
/// A keystroke event, and potentially the associated action
|
||||
|
||||
@@ -1923,6 +1923,7 @@ impl Interactivity {
|
||||
cx.on_mouse_event({
|
||||
let active_tooltip = active_tooltip.clone();
|
||||
let hitbox = hitbox.clone();
|
||||
let source_bounds = hitbox.bounds;
|
||||
let tooltip_id = self.tooltip_id;
|
||||
move |_: &MouseMoveEvent, phase, cx| {
|
||||
let is_hovered =
|
||||
@@ -1952,6 +1953,8 @@ impl Interactivity {
|
||||
tooltip: Some(AnyTooltip {
|
||||
view: build_tooltip(cx),
|
||||
mouse_position: cx.mouse_position(),
|
||||
hoverable: tooltip_is_hoverable,
|
||||
origin_bounds: source_bounds,
|
||||
}),
|
||||
_task: None,
|
||||
});
|
||||
|
||||
@@ -675,6 +675,7 @@ impl Element for InteractiveText {
|
||||
|
||||
if let Some(tooltip_builder) = self.tooltip_builder.clone() {
|
||||
let hitbox = hitbox.clone();
|
||||
let source_bounds = hitbox.bounds;
|
||||
let active_tooltip = interactive_state.active_tooltip.clone();
|
||||
let pending_mouse_down = interactive_state.mouse_down_index.clone();
|
||||
let text_layout = text_layout.clone();
|
||||
@@ -708,6 +709,8 @@ impl Element for InteractiveText {
|
||||
tooltip: Some(AnyTooltip {
|
||||
view: tooltip,
|
||||
mouse_position: cx.mouse_position(),
|
||||
hoverable: true,
|
||||
origin_bounds: source_bounds,
|
||||
}),
|
||||
_task: None,
|
||||
}
|
||||
|
||||
@@ -1586,6 +1586,19 @@ impl<'a> WindowContext<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// Element's parent can get hidden (e.g. via the `visible_on_hover` method),
|
||||
// and element's `paint` won't be called (ergo, mouse listeners also won't be active) to detect that the tooltip has to be removed.
|
||||
// Ensure it's not stuck around in such cases.
|
||||
let invalidate_tooltip = !tooltip_request
|
||||
.tooltip
|
||||
.origin_bounds
|
||||
.contains(&self.mouse_position())
|
||||
&& (!tooltip_request.tooltip.hoverable
|
||||
|| !tooltip_bounds.contains(&self.mouse_position()));
|
||||
if invalidate_tooltip {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.with_absolute_element_offset(tooltip_bounds.origin, |cx| element.prepaint(cx));
|
||||
|
||||
self.window.tooltip_bounds = Some(TooltipBounds {
|
||||
|
||||
@@ -2,8 +2,8 @@ use std::sync::Arc;
|
||||
|
||||
use feature_flags::ZedPro;
|
||||
use gpui::{
|
||||
Action, AnyElement, AppContext, DismissEvent, EventEmitter, FocusHandle, FocusableView, Task,
|
||||
View, WeakView,
|
||||
Action, AnyElement, AppContext, DismissEvent, EventEmitter, FocusHandle, FocusableView, Model,
|
||||
Subscription, Task, View, WeakView,
|
||||
};
|
||||
use language_model::{LanguageModel, LanguageModelAvailability, LanguageModelRegistry};
|
||||
use picker::{Picker, PickerDelegate};
|
||||
@@ -17,6 +17,10 @@ type OnModelChanged = Arc<dyn Fn(Arc<dyn LanguageModel>, &AppContext) + 'static>
|
||||
|
||||
pub struct LanguageModelSelector {
|
||||
picker: View<Picker<LanguageModelPickerDelegate>>,
|
||||
/// The task used to update the picker's matches when there is a change to
|
||||
/// the language model registry.
|
||||
update_matches_task: Option<Task<()>>,
|
||||
_subscriptions: Vec<Subscription>,
|
||||
}
|
||||
|
||||
impl LanguageModelSelector {
|
||||
@@ -26,7 +30,51 @@ impl LanguageModelSelector {
|
||||
) -> Self {
|
||||
let on_model_changed = Arc::new(on_model_changed);
|
||||
|
||||
let all_models = LanguageModelRegistry::global(cx)
|
||||
let all_models = Self::all_models(cx);
|
||||
let delegate = LanguageModelPickerDelegate {
|
||||
language_model_selector: cx.view().downgrade(),
|
||||
on_model_changed: on_model_changed.clone(),
|
||||
all_models: all_models.clone(),
|
||||
filtered_models: all_models,
|
||||
selected_index: 0,
|
||||
};
|
||||
|
||||
let picker =
|
||||
cx.new_view(|cx| Picker::uniform_list(delegate, cx).max_height(Some(rems(20.).into())));
|
||||
|
||||
LanguageModelSelector {
|
||||
picker,
|
||||
update_matches_task: None,
|
||||
_subscriptions: vec![cx.subscribe(
|
||||
&LanguageModelRegistry::global(cx),
|
||||
Self::handle_language_model_registry_event,
|
||||
)],
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_language_model_registry_event(
|
||||
&mut self,
|
||||
_registry: Model<LanguageModelRegistry>,
|
||||
event: &language_model::Event,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
match event {
|
||||
language_model::Event::ProviderStateChanged
|
||||
| language_model::Event::AddedProvider(_)
|
||||
| language_model::Event::RemovedProvider(_) => {
|
||||
let task = self.picker.update(cx, |this, cx| {
|
||||
let query = this.query(cx);
|
||||
this.delegate.all_models = Self::all_models(cx);
|
||||
this.delegate.update_matches(query, cx)
|
||||
});
|
||||
self.update_matches_task = Some(task);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn all_models(cx: &AppContext) -> Vec<ModelInfo> {
|
||||
LanguageModelRegistry::global(cx)
|
||||
.read(cx)
|
||||
.providers()
|
||||
.iter()
|
||||
@@ -44,20 +92,7 @@ impl LanguageModelSelector {
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let delegate = LanguageModelPickerDelegate {
|
||||
language_model_selector: cx.view().downgrade(),
|
||||
on_model_changed: on_model_changed.clone(),
|
||||
all_models: all_models.clone(),
|
||||
filtered_models: all_models,
|
||||
selected_index: 0,
|
||||
};
|
||||
|
||||
let picker =
|
||||
cx.new_view(|cx| Picker::uniform_list(delegate, cx).max_height(Some(rems(20.).into())));
|
||||
|
||||
LanguageModelSelector { picker }
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,25 +187,25 @@ impl PickerDelegate for LanguageModelPickerDelegate {
|
||||
|
||||
let llm_registry = LanguageModelRegistry::global(cx);
|
||||
|
||||
let configured_models: Vec<_> = llm_registry
|
||||
let configured_providers = llm_registry
|
||||
.read(cx)
|
||||
.providers()
|
||||
.iter()
|
||||
.filter(|provider| provider.is_authenticated(cx))
|
||||
.map(|provider| provider.id())
|
||||
.collect();
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
let filtered_models = cx
|
||||
.background_executor()
|
||||
.spawn(async move {
|
||||
let displayed_models = if configured_models.is_empty() {
|
||||
let displayed_models = if configured_providers.is_empty() {
|
||||
all_models
|
||||
} else {
|
||||
all_models
|
||||
.into_iter()
|
||||
.filter(|model_info| {
|
||||
configured_models.contains(&model_info.model.provider_id())
|
||||
configured_providers.contains(&model_info.model.provider_id())
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
@@ -253,49 +253,51 @@ impl LspAdapter for RustLspAdapter {
|
||||
.as_ref()
|
||||
.and_then(|detail| detail.detail.as_ref())
|
||||
.or(completion.detail.as_ref())
|
||||
.map(ToOwned::to_owned);
|
||||
.map(|detail| detail.trim());
|
||||
let function_signature = completion
|
||||
.label_details
|
||||
.as_ref()
|
||||
.and_then(|detail| detail.description.as_ref())
|
||||
.or(completion.detail.as_ref())
|
||||
.map(ToOwned::to_owned);
|
||||
match completion.kind {
|
||||
Some(lsp::CompletionItemKind::FIELD) if detail.is_some() => {
|
||||
.and_then(|detail| detail.description.as_deref())
|
||||
.or(completion.detail.as_deref());
|
||||
match (detail, completion.kind) {
|
||||
(Some(detail), Some(lsp::CompletionItemKind::FIELD)) => {
|
||||
let name = &completion.label;
|
||||
let text = format!("{}: {}", name, detail.unwrap());
|
||||
let source = Rope::from(format!("struct S {{ {} }}", text).as_str());
|
||||
let runs = language.highlight_text(&source, 11..11 + text.len());
|
||||
let text = format!("{name}: {detail}");
|
||||
let prefix = "struct S { ";
|
||||
let source = Rope::from(format!("{prefix}{text} }}"));
|
||||
let runs =
|
||||
language.highlight_text(&source, prefix.len()..prefix.len() + text.len());
|
||||
return Some(CodeLabel {
|
||||
text,
|
||||
runs,
|
||||
filter_range: 0..name.len(),
|
||||
});
|
||||
}
|
||||
Some(lsp::CompletionItemKind::CONSTANT | lsp::CompletionItemKind::VARIABLE)
|
||||
if detail.is_some()
|
||||
&& completion.insert_text_format != Some(lsp::InsertTextFormat::SNIPPET) =>
|
||||
{
|
||||
(
|
||||
Some(detail),
|
||||
Some(lsp::CompletionItemKind::CONSTANT | lsp::CompletionItemKind::VARIABLE),
|
||||
) if completion.insert_text_format != Some(lsp::InsertTextFormat::SNIPPET) => {
|
||||
let name = &completion.label;
|
||||
let text = format!(
|
||||
"{}: {}",
|
||||
name,
|
||||
completion.detail.as_ref().or(detail.as_ref()).unwrap()
|
||||
completion.detail.as_deref().unwrap_or(detail)
|
||||
);
|
||||
let source = Rope::from(format!("let {} = ();", text).as_str());
|
||||
let runs = language.highlight_text(&source, 4..4 + text.len());
|
||||
let prefix = "let ";
|
||||
let source = Rope::from(format!("{prefix}{text} = ();"));
|
||||
let runs =
|
||||
language.highlight_text(&source, prefix.len()..prefix.len() + text.len());
|
||||
return Some(CodeLabel {
|
||||
text,
|
||||
runs,
|
||||
filter_range: 0..name.len(),
|
||||
});
|
||||
}
|
||||
Some(lsp::CompletionItemKind::FUNCTION | lsp::CompletionItemKind::METHOD)
|
||||
if detail.is_some() =>
|
||||
{
|
||||
(
|
||||
Some(detail),
|
||||
Some(lsp::CompletionItemKind::FUNCTION | lsp::CompletionItemKind::METHOD),
|
||||
) => {
|
||||
static REGEX: LazyLock<Regex> = LazyLock::new(|| Regex::new("\\(…?\\)").unwrap());
|
||||
|
||||
let detail = detail.unwrap();
|
||||
const FUNCTION_PREFIXES: [&str; 6] = [
|
||||
"async fn",
|
||||
"async unsafe fn",
|
||||
@@ -315,10 +317,11 @@ impl LspAdapter for RustLspAdapter {
|
||||
// fn keyword should be followed by opening parenthesis.
|
||||
if let Some((prefix, suffix)) = fn_keyword {
|
||||
let mut text = REGEX.replace(&completion.label, suffix).to_string();
|
||||
let source = Rope::from(format!("{prefix} {} {{}}", text).as_str());
|
||||
let source = Rope::from(format!("{prefix} {text} {{}}"));
|
||||
let run_start = prefix.len() + 1;
|
||||
let runs = language.highlight_text(&source, run_start..run_start + text.len());
|
||||
if detail.starts_with(" (") {
|
||||
if detail.starts_with("(") {
|
||||
text.push(' ');
|
||||
text.push_str(&detail);
|
||||
}
|
||||
|
||||
@@ -342,7 +345,7 @@ impl LspAdapter for RustLspAdapter {
|
||||
});
|
||||
}
|
||||
}
|
||||
Some(kind) => {
|
||||
(_, Some(kind)) => {
|
||||
let highlight_name = match kind {
|
||||
lsp::CompletionItemKind::STRUCT
|
||||
| lsp::CompletionItemKind::INTERFACE
|
||||
@@ -356,9 +359,9 @@ impl LspAdapter for RustLspAdapter {
|
||||
};
|
||||
|
||||
let mut label = completion.label.clone();
|
||||
if let Some(detail) = detail.filter(|detail| detail.starts_with(" (")) {
|
||||
use std::fmt::Write;
|
||||
write!(label, "{detail}").ok()?;
|
||||
if let Some(detail) = detail.filter(|detail| detail.starts_with("(")) {
|
||||
label.push(' ');
|
||||
label.push_str(detail);
|
||||
}
|
||||
let mut label = CodeLabel::plain(label, None);
|
||||
if let Some(highlight_name) = highlight_name {
|
||||
@@ -883,7 +886,7 @@ mod tests {
|
||||
kind: Some(lsp::CompletionItemKind::FUNCTION),
|
||||
label: "hello(…)".to_string(),
|
||||
label_details: Some(CompletionItemLabelDetails {
|
||||
detail: Some(" (use crate::foo)".into()),
|
||||
detail: Some("(use crate::foo)".into()),
|
||||
description: Some("fn(&mut Option<T>) -> Vec<T>".to_string())
|
||||
}),
|
||||
..Default::default()
|
||||
|
||||
@@ -4447,18 +4447,27 @@ impl Panel for OutlinePanel {
|
||||
.update(&mut cx, |outline_panel, cx| {
|
||||
let old_active = outline_panel.active;
|
||||
outline_panel.active = active;
|
||||
if active && old_active != active {
|
||||
if let Some((active_item, active_editor)) = outline_panel
|
||||
.workspace
|
||||
.upgrade()
|
||||
.and_then(|workspace| workspace_active_editor(workspace.read(cx), cx))
|
||||
{
|
||||
if outline_panel.should_replace_active_item(active_item.as_ref()) {
|
||||
outline_panel.replace_active_editor(active_item, active_editor, cx);
|
||||
} else {
|
||||
outline_panel.update_fs_entries(active_editor, None, cx)
|
||||
if old_active != active {
|
||||
if active {
|
||||
if let Some((active_item, active_editor)) =
|
||||
outline_panel.workspace.upgrade().and_then(|workspace| {
|
||||
workspace_active_editor(workspace.read(cx), cx)
|
||||
})
|
||||
{
|
||||
if outline_panel.should_replace_active_item(active_item.as_ref()) {
|
||||
outline_panel.replace_active_editor(
|
||||
active_item,
|
||||
active_editor,
|
||||
cx,
|
||||
);
|
||||
} else {
|
||||
outline_panel.update_fs_entries(active_editor, None, cx)
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else if !outline_panel.pinned {
|
||||
}
|
||||
|
||||
if !outline_panel.pinned {
|
||||
outline_panel.clear_previous(cx);
|
||||
}
|
||||
}
|
||||
@@ -4605,9 +4614,11 @@ fn subscribe_for_editor_events(
|
||||
cx: &mut ViewContext<OutlinePanel>,
|
||||
) -> Subscription {
|
||||
let debounce = Some(UPDATE_DEBOUNCE);
|
||||
cx.subscribe(
|
||||
editor,
|
||||
move |outline_panel, editor, e: &EditorEvent, cx| match e {
|
||||
cx.subscribe(editor, move |outline_panel, editor, e: &EditorEvent, cx| {
|
||||
if !outline_panel.active {
|
||||
return;
|
||||
}
|
||||
match e {
|
||||
EditorEvent::SelectionsChanged { local: true } => {
|
||||
outline_panel.reveal_entry_for_selection(editor, cx);
|
||||
cx.notify();
|
||||
@@ -4712,8 +4723,8 @@ fn subscribe_for_editor_events(
|
||||
outline_panel.update_non_fs_items(cx);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn empty_icon() -> AnyElement {
|
||||
|
||||
@@ -5586,13 +5586,13 @@ impl LspStore {
|
||||
<R::LspRequest as lsp::request::Request>::Result: Send,
|
||||
<R::LspRequest as lsp::request::Request>::Params: Send,
|
||||
{
|
||||
debug_assert!(self.upstream_client().is_none());
|
||||
let Some(local) = self.as_local() else {
|
||||
return Task::ready(Vec::new());
|
||||
};
|
||||
|
||||
let snapshot = buffer.read(cx).snapshot();
|
||||
let scope = position.and_then(|position| snapshot.language_scope_at(position));
|
||||
let server_ids = self
|
||||
.as_local()
|
||||
.unwrap()
|
||||
let server_ids = local
|
||||
.language_servers_for_buffer(buffer.read(cx), cx)
|
||||
.filter(|(adapter, _)| {
|
||||
scope
|
||||
|
||||
@@ -514,13 +514,15 @@ fn text_object(
|
||||
|
||||
let excerpt = snapshot.excerpt_containing(offset..offset)?;
|
||||
let buffer = excerpt.buffer();
|
||||
let offset = excerpt.map_offset_to_buffer(offset);
|
||||
|
||||
let mut matches: Vec<Range<usize>> = buffer
|
||||
.text_object_ranges(offset..offset, TreeSitterOptions::default())
|
||||
.filter_map(|(r, m)| if m == target { Some(r) } else { None })
|
||||
.collect();
|
||||
matches.sort_by_key(|r| (r.end - r.start));
|
||||
if let Some(range) = matches.first() {
|
||||
if let Some(buffer_range) = matches.first() {
|
||||
let range = excerpt.map_range_from_buffer(buffer_range.clone());
|
||||
return Some(range.start.to_display_point(map)..range.end.to_display_point(map));
|
||||
}
|
||||
|
||||
@@ -537,12 +539,14 @@ fn text_object(
|
||||
.filter_map(|(r, m)| if m == target { Some(r) } else { None })
|
||||
.collect();
|
||||
matches.sort_by_key(|r| r.start);
|
||||
if let Some(range) = matches.first() {
|
||||
if !range.is_empty() {
|
||||
if let Some(buffer_range) = matches.first() {
|
||||
if !buffer_range.is_empty() {
|
||||
let range = excerpt.map_range_from_buffer(buffer_range.clone());
|
||||
return Some(range.start.to_display_point(map)..range.end.to_display_point(map));
|
||||
}
|
||||
}
|
||||
return Some(around_range.start.to_display_point(map)..around_range.end.to_display_point(map));
|
||||
let buffer_range = excerpt.map_range_from_buffer(around_range.clone());
|
||||
return Some(buffer_range.start.to_display_point(map)..buffer_range.end.to_display_point(map));
|
||||
}
|
||||
|
||||
fn argument(
|
||||
|
||||
@@ -170,6 +170,7 @@ impl From<&dyn PanelHandle> for AnyView {
|
||||
pub struct Dock {
|
||||
position: DockPosition,
|
||||
panel_entries: Vec<PanelEntry>,
|
||||
workspace: WeakView<Workspace>,
|
||||
is_open: bool,
|
||||
active_panel_index: Option<usize>,
|
||||
focus_handle: FocusHandle,
|
||||
@@ -236,6 +237,7 @@ impl Dock {
|
||||
});
|
||||
Self {
|
||||
position,
|
||||
workspace: workspace.downgrade(),
|
||||
panel_entries: Default::default(),
|
||||
active_panel_index: None,
|
||||
is_open: false,
|
||||
@@ -337,6 +339,9 @@ impl Dock {
|
||||
self.is_open = open;
|
||||
if let Some(active_panel) = self.active_panel_entry() {
|
||||
active_panel.panel.set_active(open, cx);
|
||||
if !open {
|
||||
self.active_panel_index = None;
|
||||
}
|
||||
}
|
||||
|
||||
cx.notify();
|
||||
@@ -354,6 +359,11 @@ impl Dock {
|
||||
}
|
||||
}
|
||||
|
||||
self.workspace
|
||||
.update(cx, |workspace, cx| {
|
||||
workspace.serialize_workspace(cx);
|
||||
})
|
||||
.ok();
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
@@ -484,7 +494,8 @@ impl Dock {
|
||||
},
|
||||
);
|
||||
|
||||
if !self.restore_state(cx) && panel.read(cx).starts_open(cx) {
|
||||
self.restore_state(cx);
|
||||
if panel.read(cx).starts_open(cx) {
|
||||
self.activate_panel(index, cx);
|
||||
self.set_open(true, cx);
|
||||
}
|
||||
@@ -652,9 +663,14 @@ impl Render for Dock {
|
||||
)
|
||||
.on_mouse_up(
|
||||
MouseButton::Left,
|
||||
cx.listener(|v, e: &MouseUpEvent, cx| {
|
||||
cx.listener(|dock, e: &MouseUpEvent, cx| {
|
||||
if e.click_count == 2 {
|
||||
v.resize_active_panel(None, cx);
|
||||
dock.resize_active_panel(None, cx);
|
||||
dock.workspace
|
||||
.update(cx, |workspace, cx| {
|
||||
workspace.serialize_workspace(cx);
|
||||
})
|
||||
.ok();
|
||||
cx.stop_propagation();
|
||||
}
|
||||
}),
|
||||
|
||||
@@ -743,6 +743,7 @@ pub struct Workspace {
|
||||
weak_self: WeakView<Self>,
|
||||
workspace_actions: Vec<Box<dyn Fn(Div, &mut ViewContext<Self>) -> Div>>,
|
||||
zoomed: Option<AnyWeakView>,
|
||||
previous_dock_drag_coordinates: Option<Point<Pixels>>,
|
||||
zoomed_position: Option<DockPosition>,
|
||||
center: PaneGroup,
|
||||
left_dock: View<Dock>,
|
||||
@@ -1020,18 +1021,6 @@ impl Workspace {
|
||||
|
||||
ThemeSettings::reload_current_theme(cx);
|
||||
}),
|
||||
cx.observe(&left_dock, |this, _, cx| {
|
||||
this.serialize_workspace(cx);
|
||||
cx.notify();
|
||||
}),
|
||||
cx.observe(&bottom_dock, |this, _, cx| {
|
||||
this.serialize_workspace(cx);
|
||||
cx.notify();
|
||||
}),
|
||||
cx.observe(&right_dock, |this, _, cx| {
|
||||
this.serialize_workspace(cx);
|
||||
cx.notify();
|
||||
}),
|
||||
cx.on_release(|this, window, cx| {
|
||||
this.app_state.workspace_store.update(cx, |store, _| {
|
||||
let window = window.downcast::<Self>().unwrap();
|
||||
@@ -1047,6 +1036,7 @@ impl Workspace {
|
||||
weak_self: weak_handle.clone(),
|
||||
zoomed: None,
|
||||
zoomed_position: None,
|
||||
previous_dock_drag_coordinates: None,
|
||||
center: PaneGroup::new(center_pane.clone()),
|
||||
panes: vec![center_pane.clone()],
|
||||
panes_by_item: Default::default(),
|
||||
@@ -3068,6 +3058,7 @@ impl Workspace {
|
||||
event: &pane::Event,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
let mut serialize_workspace = true;
|
||||
match event {
|
||||
pane::Event::AddItem { item } => {
|
||||
item.added_to_pane(self, pane, cx);
|
||||
@@ -3078,10 +3069,14 @@ impl Workspace {
|
||||
pane::Event::Split(direction) => {
|
||||
self.split_and_clone(pane, *direction, cx);
|
||||
}
|
||||
pane::Event::JoinIntoNext => self.join_pane_into_next(pane, cx),
|
||||
pane::Event::JoinAll => self.join_all_panes(cx),
|
||||
pane::Event::JoinIntoNext => {
|
||||
self.join_pane_into_next(pane, cx);
|
||||
}
|
||||
pane::Event::JoinAll => {
|
||||
self.join_all_panes(cx);
|
||||
}
|
||||
pane::Event::Remove { focus_on_pane } => {
|
||||
self.remove_pane(pane, focus_on_pane.clone(), cx)
|
||||
self.remove_pane(pane, focus_on_pane.clone(), cx);
|
||||
}
|
||||
pane::Event::ActivateItem { local } => {
|
||||
cx.on_next_frame(|_, cx| {
|
||||
@@ -3099,16 +3094,20 @@ impl Workspace {
|
||||
self.update_active_view_for_followers(cx);
|
||||
}
|
||||
}
|
||||
pane::Event::UserSavedItem { item, save_intent } => cx.emit(Event::UserSavedItem {
|
||||
pane: pane.downgrade(),
|
||||
item: item.boxed_clone(),
|
||||
save_intent: *save_intent,
|
||||
}),
|
||||
pane::Event::UserSavedItem { item, save_intent } => {
|
||||
cx.emit(Event::UserSavedItem {
|
||||
pane: pane.downgrade(),
|
||||
item: item.boxed_clone(),
|
||||
save_intent: *save_intent,
|
||||
});
|
||||
serialize_workspace = false;
|
||||
}
|
||||
pane::Event::ChangeItemTitle => {
|
||||
if pane == self.active_pane {
|
||||
self.active_item_path_changed(cx);
|
||||
}
|
||||
self.update_window_edited(cx);
|
||||
serialize_workspace = false;
|
||||
}
|
||||
pane::Event::RemoveItem { .. } => {}
|
||||
pane::Event::RemovedItem { item_id } => {
|
||||
@@ -3147,7 +3146,9 @@ impl Workspace {
|
||||
}
|
||||
}
|
||||
|
||||
self.serialize_workspace(cx);
|
||||
if serialize_workspace {
|
||||
self.serialize_workspace(cx);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unfollow_in_pane(
|
||||
@@ -4908,32 +4909,39 @@ impl Render for Workspace {
|
||||
})
|
||||
.when(self.zoomed.is_none(), |this| {
|
||||
this.on_drag_move(cx.listener(
|
||||
|workspace, e: &DragMoveEvent<DraggedDock>, cx| {
|
||||
match e.drag(cx).0 {
|
||||
DockPosition::Left => {
|
||||
resize_left_dock(
|
||||
e.event.position.x
|
||||
- workspace.bounds.left(),
|
||||
workspace,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
DockPosition::Right => {
|
||||
resize_right_dock(
|
||||
workspace.bounds.right()
|
||||
- e.event.position.x,
|
||||
workspace,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
DockPosition::Bottom => {
|
||||
resize_bottom_dock(
|
||||
workspace.bounds.bottom()
|
||||
- e.event.position.y,
|
||||
workspace,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
move |workspace, e: &DragMoveEvent<DraggedDock>, cx| {
|
||||
if workspace.previous_dock_drag_coordinates
|
||||
!= Some(e.event.position)
|
||||
{
|
||||
workspace.previous_dock_drag_coordinates =
|
||||
Some(e.event.position);
|
||||
match e.drag(cx).0 {
|
||||
DockPosition::Left => {
|
||||
resize_left_dock(
|
||||
e.event.position.x
|
||||
- workspace.bounds.left(),
|
||||
workspace,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
DockPosition::Right => {
|
||||
resize_right_dock(
|
||||
workspace.bounds.right()
|
||||
- e.event.position.x,
|
||||
workspace,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
DockPosition::Bottom => {
|
||||
resize_bottom_dock(
|
||||
workspace.bounds.bottom()
|
||||
- e.event.position.y,
|
||||
workspace,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
};
|
||||
workspace.serialize_workspace(cx);
|
||||
}
|
||||
},
|
||||
))
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
description = "The fast, collaborative code editor."
|
||||
edition = "2021"
|
||||
name = "zed"
|
||||
version = "0.168.0"
|
||||
version = "0.168.2"
|
||||
publish = false
|
||||
license = "GPL-3.0-or-later"
|
||||
authors = ["Zed Team <hi@zed.dev>"]
|
||||
|
||||
@@ -1 +1 @@
|
||||
dev
|
||||
stable
|
||||
@@ -20,6 +20,7 @@ use command_palette_hooks::CommandPaletteFilter;
|
||||
use editor::ProposedChangesEditorToolbar;
|
||||
use editor::{scroll::Autoscroll, Editor, MultiBuffer};
|
||||
use feature_flags::FeatureFlagAppExt;
|
||||
use futures::FutureExt;
|
||||
use futures::{channel::mpsc, select_biased, StreamExt};
|
||||
use gpui::{
|
||||
actions, point, px, AppContext, AsyncAppContext, Context, FocusableView, MenuItem,
|
||||
@@ -348,7 +349,16 @@ fn initialize_panels(prompt_builder: Arc<PromptBuilder>, cx: &mut ViewContext<Wo
|
||||
workspace.add_panel(assistant_panel, cx)
|
||||
})?;
|
||||
|
||||
let git_ui_enabled = git_ui_feature_flag.await;
|
||||
let git_ui_enabled = {
|
||||
let mut git_ui_feature_flag = git_ui_feature_flag.fuse();
|
||||
let mut timeout =
|
||||
FutureExt::fuse(smol::Timer::after(std::time::Duration::from_secs(5)));
|
||||
|
||||
select_biased! {
|
||||
is_git_ui_enabled = git_ui_feature_flag => is_git_ui_enabled,
|
||||
_ = timeout => false,
|
||||
}
|
||||
};
|
||||
let git_panel = if git_ui_enabled {
|
||||
Some(git_ui::git_panel::GitPanel::load(workspace_handle.clone(), cx.clone()).await?)
|
||||
} else {
|
||||
@@ -363,7 +373,14 @@ fn initialize_panels(prompt_builder: Arc<PromptBuilder>, cx: &mut ViewContext<Wo
|
||||
let is_assistant2_enabled = if cfg!(test) {
|
||||
false
|
||||
} else {
|
||||
assistant2_feature_flag.await
|
||||
let mut assistant2_feature_flag = assistant2_feature_flag.fuse();
|
||||
let mut timeout =
|
||||
FutureExt::fuse(smol::Timer::after(std::time::Duration::from_secs(5)));
|
||||
|
||||
select_biased! {
|
||||
is_assistant2_enabled = assistant2_feature_flag => is_assistant2_enabled,
|
||||
_ = timeout => false,
|
||||
}
|
||||
};
|
||||
let assistant2_panel = if is_assistant2_enabled {
|
||||
Some(assistant2::AssistantPanel::load(workspace_handle.clone(), cx.clone()).await?)
|
||||
|
||||
Reference in New Issue
Block a user