Compare commits

...

2 Commits

Author SHA1 Message Date
Piotr Osiewicz
8f44ff7d31 Cargo fmt 2025-03-31 15:31:27 +02:00
Piotr Osiewicz
e85ec8ffb7 chore: Prepare for Rust 2024
This is just a result of `cargo fix --edition`, without actually bumping the edition just yet.
2025-03-31 15:29:44 +02:00
320 changed files with 11821 additions and 10396 deletions

24
Cargo.lock generated
View File

@@ -1910,6 +1910,24 @@ name = "bindgen"
version = "0.70.1" version = "0.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f"
dependencies = [
"bitflags 2.9.0",
"cexpr",
"clang-sys",
"itertools 0.12.1",
"proc-macro2",
"quote",
"regex",
"rustc-hash 1.1.0",
"shlex",
"syn 2.0.100",
]
[[package]]
name = "bindgen"
version = "0.71.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.0",
"cexpr", "cexpr",
@@ -1920,7 +1938,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"regex", "regex",
"rustc-hash 1.1.0", "rustc-hash 2.1.1",
"shlex", "shlex",
"syn 2.0.100", "syn 2.0.100",
] ]
@@ -5848,7 +5866,7 @@ dependencies = [
"ashpd", "ashpd",
"async-task", "async-task",
"backtrace", "backtrace",
"bindgen 0.70.1", "bindgen 0.71.1",
"blade-graphics", "blade-graphics",
"blade-macros", "blade-macros",
"blade-util", "blade-util",
@@ -8220,7 +8238,7 @@ name = "media"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bindgen 0.70.1", "bindgen 0.71.1",
"core-foundation 0.10.0", "core-foundation 0.10.0",
"core-video", "core-video",
"ctor", "ctor",

View File

@@ -190,7 +190,7 @@ impl ActivityIndicator {
fn pending_language_server_work<'a>( fn pending_language_server_work<'a>(
&self, &self,
cx: &'a App, cx: &'a App,
) -> impl Iterator<Item = PendingWork<'a>> { ) -> impl Iterator<Item = PendingWork<'a>> + use<'a> {
self.project self.project
.read(cx) .read(cx)
.language_server_statuses(cx) .language_server_statuses(cx)

View File

@@ -89,14 +89,16 @@ impl AskPassSession {
buffer.clear(); buffer.clear();
} }
let prompt = String::from_utf8_lossy(&buffer); let prompt = String::from_utf8_lossy(&buffer);
if let Some(password) = delegate match delegate
.ask_password(prompt.to_string()) .ask_password(prompt.to_string())
.await .await
.context("failed to get askpass password") .context("failed to get askpass password")
.log_err() .log_err()
{ {
Some(password) => {
stream.write_all(password.as_bytes()).await.log_err(); stream.write_all(password.as_bytes()).await.log_err();
} else { }
_ => {
if let Some(kill_tx) = kill_tx.take() { if let Some(kill_tx) = kill_tx.take() {
kill_tx.send(()).log_err(); kill_tx.send(()).log_err();
} }
@@ -107,6 +109,7 @@ impl AskPassSession {
drop(stream); drop(stream);
} }
} }
}
drop(temp_dir) drop(temp_dir)
}); });

View File

@@ -741,20 +741,29 @@ impl AssistantPanel {
} }
}); });
if let Some(context_editor) = context_editor { match context_editor {
Some(InlineAssistTarget::Editor(context_editor, false)) Some(context_editor) => Some(InlineAssistTarget::Editor(context_editor, false)),
} else if let Some(workspace_editor) = workspace _ => {
match workspace
.active_item(cx) .active_item(cx)
.and_then(|item| item.act_as::<Editor>(cx)) .and_then(|item| item.act_as::<Editor>(cx))
{ {
Some(workspace_editor) => {
Some(InlineAssistTarget::Editor(workspace_editor, true)) Some(InlineAssistTarget::Editor(workspace_editor, true))
} else if let Some(terminal_view) = workspace }
_ => {
match workspace
.active_item(cx) .active_item(cx)
.and_then(|item| item.act_as::<TerminalView>(cx)) .and_then(|item| item.act_as::<TerminalView>(cx))
{ {
Some(terminal_view) => {
Some(InlineAssistTarget::Terminal(terminal_view)) Some(InlineAssistTarget::Terminal(terminal_view))
} else { }
None _ => None,
}
}
}
}
} }
} }

View File

@@ -250,9 +250,9 @@ impl InlineAssistant {
selection.end.column = snapshot selection.end.column = snapshot
.buffer_snapshot .buffer_snapshot
.line_len(MultiBufferRow(selection.end.row)); .line_len(MultiBufferRow(selection.end.row));
} else if let Some(fold) = } else {
snapshot.crease_for_buffer_row(MultiBufferRow(selection.end.row)) match snapshot.crease_for_buffer_row(MultiBufferRow(selection.end.row)) {
{ Some(fold) => {
selection.start = fold.range().start; selection.start = fold.range().start;
selection.end = fold.range().end; selection.end = fold.range().end;
if MultiBufferRow(selection.end.row) < snapshot.buffer_snapshot.max_row() { if MultiBufferRow(selection.end.row) < snapshot.buffer_snapshot.max_row() {
@@ -267,10 +267,9 @@ impl InlineAssistant {
if c.is_whitespace() { if c.is_whitespace() {
continue; continue;
} }
if snapshot if snapshot.language_at(selection.end).is_some_and(|language| {
.language_at(selection.end) language.config().brackets.is_closing_brace(c)
.is_some_and(|language| language.config().brackets.is_closing_brace(c)) }) {
{
selection.end.row += 1; selection.end.row += 1;
selection.end.column = snapshot selection.end.column = snapshot
.buffer_snapshot .buffer_snapshot
@@ -279,6 +278,9 @@ impl InlineAssistant {
} }
} }
} }
_ => {}
}
}
if let Some(prev_selection) = selections.last_mut() { if let Some(prev_selection) = selections.last_mut() {
if selection.start <= prev_selection.end { if selection.start <= prev_selection.end {
@@ -1031,7 +1033,8 @@ impl InlineAssistant {
let mut scroll_target_top; let mut scroll_target_top;
let mut scroll_target_bottom; let mut scroll_target_bottom;
if let Some(decorations) = assist.decorations.as_ref() { match assist.decorations.as_ref() {
Some(decorations) => {
scroll_target_top = editor scroll_target_top = editor
.row_for_block(decorations.prompt_block_id, cx) .row_for_block(decorations.prompt_block_id, cx)
.unwrap() .unwrap()
@@ -1040,7 +1043,8 @@ impl InlineAssistant {
.row_for_block(decorations.end_block_id, cx) .row_for_block(decorations.end_block_id, cx)
.unwrap() .unwrap()
.0 as f32; .0 as f32;
} else { }
_ => {
let snapshot = editor.snapshot(window, cx); let snapshot = editor.snapshot(window, cx);
let start_row = assist let start_row = assist
.range .range
@@ -1050,6 +1054,7 @@ impl InlineAssistant {
scroll_target_top = start_row.0 as f32; scroll_target_top = start_row.0 as f32;
scroll_target_bottom = scroll_target_top + 1.; scroll_target_bottom = scroll_target_top + 1.;
} }
}
scroll_target_top -= editor.vertical_scroll_margin() as f32; scroll_target_top -= editor.vertical_scroll_margin() as f32;
scroll_target_bottom += editor.vertical_scroll_margin() as f32; scroll_target_bottom += editor.vertical_scroll_margin() as f32;
@@ -1093,10 +1098,11 @@ impl InlineAssistant {
} }
pub fn start_assist(&mut self, assist_id: InlineAssistId, window: &mut Window, cx: &mut App) { pub fn start_assist(&mut self, assist_id: InlineAssistId, window: &mut Window, cx: &mut App) {
let assist = if let Some(assist) = self.assists.get_mut(&assist_id) { let assist = match self.assists.get_mut(&assist_id) {
assist Some(assist) => assist,
} else { _ => {
return; return;
}
}; };
let assist_group_id = assist.group_id; let assist_group_id = assist.group_id;
@@ -1128,10 +1134,11 @@ impl InlineAssistant {
} }
pub fn stop_assist(&mut self, assist_id: InlineAssistId, cx: &mut App) { pub fn stop_assist(&mut self, assist_id: InlineAssistId, cx: &mut App) {
let assist = if let Some(assist) = self.assists.get_mut(&assist_id) { let assist = match self.assists.get_mut(&assist_id) {
assist Some(assist) => assist,
} else { _ => {
return; return;
}
}; };
assist.codegen.update(cx, |codegen, cx| codegen.stop(cx)); assist.codegen.update(cx, |codegen, cx| codegen.stop(cx));
@@ -2184,7 +2191,7 @@ impl PromptEditor {
.into_any_element() .into_any_element()
} }
fn render_token_count(&self, cx: &mut Context<Self>) -> Option<impl IntoElement> { fn render_token_count(&self, cx: &mut Context<Self>) -> Option<impl IntoElement + use<>> {
let model = LanguageModelRegistry::read_global(cx).active_model()?; let model = LanguageModelRegistry::read_global(cx).active_model()?;
let token_counts = self.token_counts?; let token_counts = self.token_counts?;
let max_token_count = model.max_token_count(); let max_token_count = model.max_token_count();
@@ -2212,7 +2219,8 @@ impl PromptEditor {
.size(LabelSize::Small) .size(LabelSize::Small)
.color(Color::Muted), .color(Color::Muted),
); );
if let Some(workspace) = self.workspace.clone() { match self.workspace.clone() {
Some(workspace) => {
token_count = token_count token_count = token_count
.tooltip(move |window, cx| { .tooltip(move |window, cx| {
Tooltip::with_meta( Tooltip::with_meta(
@@ -2236,16 +2244,18 @@ impl PromptEditor {
}) })
.ok(); .ok();
}); });
} else { }
_ => {
token_count = token_count token_count = token_count
.cursor_default() .cursor_default()
.tooltip(Tooltip::text("Tokens used")); .tooltip(Tooltip::text("Tokens used"));
} }
}
Some(token_count) Some(token_count)
} }
fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement { fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement + use<> {
let settings = ThemeSettings::get_global(cx); let settings = ThemeSettings::get_global(cx);
let text_style = TextStyle { let text_style = TextStyle {
color: if self.editor.read(cx).read_only(cx) { color: if self.editor.read(cx).read_only(cx) {
@@ -2271,7 +2281,7 @@ impl PromptEditor {
) )
} }
fn render_rate_limit_notice(&self, cx: &mut Context<Self>) -> impl IntoElement { fn render_rate_limit_notice(&self, cx: &mut Context<Self>) -> impl IntoElement + use<> {
Popover::new().child( Popover::new().child(
v_flex() v_flex()
.occlude() .occlude()
@@ -2430,10 +2440,11 @@ impl InlineAssist {
InlineAssistant::update_global(cx, |this, cx| match event { InlineAssistant::update_global(cx, |this, cx| match event {
CodegenEvent::Undone => this.finish_assist(assist_id, false, window, cx), CodegenEvent::Undone => this.finish_assist(assist_id, false, window, cx),
CodegenEvent::Finished => { CodegenEvent::Finished => {
let assist = if let Some(assist) = this.assists.get(&assist_id) { let assist = match this.assists.get(&assist_id) {
assist Some(assist) => assist,
} else { _ => {
return; return;
}
}; };
if let CodegenStatus::Error(error) = codegen.read(cx).status(cx) { if let CodegenStatus::Error(error) = codegen.read(cx).status(cx) {
@@ -2865,7 +2876,8 @@ impl CodegenAlternative {
assistant_panel_context: Option<LanguageModelRequest>, assistant_panel_context: Option<LanguageModelRequest>,
cx: &App, cx: &App,
) -> BoxFuture<'static, Result<TokenCounts>> { ) -> BoxFuture<'static, Result<TokenCounts>> {
if let Some(model) = LanguageModelRegistry::read_global(cx).active_model() { match LanguageModelRegistry::read_global(cx).active_model() {
Some(model) => {
let request = self.build_request(user_prompt, assistant_panel_context.clone(), cx); let request = self.build_request(user_prompt, assistant_panel_context.clone(), cx);
match request { match request {
Ok(request) => { Ok(request) => {
@@ -2884,8 +2896,8 @@ impl CodegenAlternative {
} }
Err(error) => futures::future::ready(Err(error)).boxed(), Err(error) => futures::future::ready(Err(error)).boxed(),
} }
} else { }
future::ready(Err(anyhow!("no active model"))).boxed() _ => future::ready(Err(anyhow!("no active model"))).boxed(),
} }
} }
@@ -3221,11 +3233,14 @@ impl CodegenAlternative {
.update(cx, |this, cx| { .update(cx, |this, cx| {
this.message_id = message_id; this.message_id = message_id;
this.last_equal_ranges.clear(); this.last_equal_ranges.clear();
if let Err(error) = result { match result {
Err(error) => {
this.status = CodegenStatus::Error(error); this.status = CodegenStatus::Error(error);
} else { }
_ => {
this.status = CodegenStatus::Done; this.status = CodegenStatus::Done;
} }
}
this.elapsed_time = Some(elapsed_time); this.elapsed_time = Some(elapsed_time);
this.completion = Some(completion.lock().clone()); this.completion = Some(completion.lock().clone());
cx.emit(CodegenEvent::Finished); cx.emit(CodegenEvent::Finished);

View File

@@ -184,10 +184,11 @@ impl TerminalInlineAssistant {
} }
fn start_assist(&mut self, assist_id: TerminalInlineAssistId, cx: &mut App) { fn start_assist(&mut self, assist_id: TerminalInlineAssistId, cx: &mut App) {
let assist = if let Some(assist) = self.assists.get_mut(&assist_id) { let assist = match self.assists.get_mut(&assist_id) {
assist Some(assist) => assist,
} else { _ => {
return; return;
}
}; };
let Some(user_prompt) = assist let Some(user_prompt) = assist
@@ -222,10 +223,11 @@ impl TerminalInlineAssistant {
} }
fn stop_assist(&mut self, assist_id: TerminalInlineAssistId, cx: &mut App) { fn stop_assist(&mut self, assist_id: TerminalInlineAssistId, cx: &mut App) {
let assist = if let Some(assist) = self.assists.get_mut(&assist_id) { let assist = match self.assists.get_mut(&assist_id) {
assist Some(assist) => assist,
} else { _ => {
return; return;
}
}; };
assist.codegen.update(cx, |codegen, cx| codegen.stop(cx)); assist.codegen.update(cx, |codegen, cx| codegen.stop(cx));
@@ -436,10 +438,11 @@ impl TerminalInlineAssist {
window.subscribe(&codegen, cx, move |codegen, event, window, cx| { window.subscribe(&codegen, cx, move |codegen, event, window, cx| {
TerminalInlineAssistant::update_global(cx, |this, cx| match event { TerminalInlineAssistant::update_global(cx, |this, cx| match event {
CodegenEvent::Finished => { CodegenEvent::Finished => {
let assist = if let Some(assist) = this.assists.get(&assist_id) { let assist = match this.assists.get(&assist_id) {
assist Some(assist) => assist,
} else { _ => {
return; return;
}
}; };
if let CodegenStatus::Error(error) = &codegen.read(cx).status { if let CodegenStatus::Error(error) = &codegen.read(cx).status {
@@ -664,8 +667,8 @@ impl Render for PromptEditor {
}, },
gpui::Corner::TopRight, gpui::Corner::TopRight,
)) ))
.children( .children(match &self.codegen.read(cx).status {
if let CodegenStatus::Error(error) = &self.codegen.read(cx).status { CodegenStatus::Error(error) => {
let error_message = SharedString::from(error.to_string()); let error_message = SharedString::from(error.to_string());
Some( Some(
div() div()
@@ -677,10 +680,9 @@ impl Render for PromptEditor {
.color(Color::Error), .color(Color::Error),
), ),
) )
} else { }
None _ => None,
}, }),
),
) )
.child(div().flex_1().child(self.render_prompt_editor(cx))) .child(div().flex_1().child(self.render_prompt_editor(cx)))
.child( .child(
@@ -979,7 +981,7 @@ impl PromptEditor {
} }
} }
fn render_token_count(&self, cx: &mut Context<Self>) -> Option<impl IntoElement> { fn render_token_count(&self, cx: &mut Context<Self>) -> Option<impl IntoElement + use<>> {
let model = LanguageModelRegistry::read_global(cx).active_model()?; let model = LanguageModelRegistry::read_global(cx).active_model()?;
let token_count = self.token_count?; let token_count = self.token_count?;
let max_token_count = model.max_token_count(); let max_token_count = model.max_token_count();
@@ -1007,7 +1009,8 @@ impl PromptEditor {
.size(LabelSize::Small) .size(LabelSize::Small)
.color(Color::Muted), .color(Color::Muted),
); );
if let Some(workspace) = self.workspace.clone() { match self.workspace.clone() {
Some(workspace) => {
token_count = token_count token_count = token_count
.tooltip(|window, cx| { .tooltip(|window, cx| {
Tooltip::with_meta( Tooltip::with_meta(
@@ -1028,16 +1031,18 @@ impl PromptEditor {
}) })
.ok(); .ok();
}); });
} else { }
_ => {
token_count = token_count token_count = token_count
.cursor_default() .cursor_default()
.tooltip(Tooltip::text("Tokens Used by Inline Assistant")); .tooltip(Tooltip::text("Tokens Used by Inline Assistant"));
} }
}
Some(token_count) Some(token_count)
} }
fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement { fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement + use<> {
let settings = ThemeSettings::get_global(cx); let settings = ThemeSettings::get_global(cx);
let text_style = TextStyle { let text_style = TextStyle {
color: if self.editor.read(cx).read_only(cx) { color: if self.editor.read(cx).read_only(cx) {
@@ -1217,11 +1222,14 @@ impl Codegen {
let result = generate.await; let result = generate.await;
this.update(cx, |this, cx| { this.update(cx, |this, cx| {
if let Err(error) = result { match result {
Err(error) => {
this.status = CodegenStatus::Error(error); this.status = CodegenStatus::Error(error);
} else { }
_ => {
this.status = CodegenStatus::Done; this.status = CodegenStatus::Done;
} }
}
cx.emit(CodegenEvent::Finished); cx.emit(CodegenEvent::Finished);
cx.notify(); cx.notify();
}) })

View File

@@ -77,27 +77,36 @@ impl RenderedMessage {
} }
fn append_thinking(&mut self, text: &String, window: &Window, cx: &mut App) { fn append_thinking(&mut self, text: &String, window: &Window, cx: &mut App) {
if let Some(RenderedMessageSegment::Thinking { match self.segments.last_mut() {
Some(RenderedMessageSegment::Thinking {
content, content,
scroll_handle, scroll_handle,
}) = self.segments.last_mut() }) => {
{
content.update(cx, |markdown, cx| { content.update(cx, |markdown, cx| {
markdown.append(text, cx); markdown.append(text, cx);
}); });
scroll_handle.scroll_to_bottom(); scroll_handle.scroll_to_bottom();
} else { }
_ => {
self.segments.push(RenderedMessageSegment::Thinking { self.segments.push(RenderedMessageSegment::Thinking {
content: render_markdown(text.into(), self.language_registry.clone(), window, cx), content: render_markdown(
text.into(),
self.language_registry.clone(),
window,
cx,
),
scroll_handle: ScrollHandle::default(), scroll_handle: ScrollHandle::default(),
}); });
} }
} }
}
fn append_text(&mut self, text: &String, window: &Window, cx: &mut App) { fn append_text(&mut self, text: &String, window: &Window, cx: &mut App) {
if let Some(RenderedMessageSegment::Text(markdown)) = self.segments.last_mut() { match self.segments.last_mut() {
Some(RenderedMessageSegment::Text(markdown)) => {
markdown.update(cx, |markdown, cx| markdown.append(text, cx)); markdown.update(cx, |markdown, cx| markdown.append(text, cx));
} else { }
_ => {
self.segments self.segments
.push(RenderedMessageSegment::Text(render_markdown( .push(RenderedMessageSegment::Text(render_markdown(
SharedString::from(text), SharedString::from(text),
@@ -107,6 +116,7 @@ impl RenderedMessage {
))); )));
} }
} }
}
fn push_segment(&mut self, segment: &MessageSegment, window: &Window, cx: &mut App) { fn push_segment(&mut self, segment: &MessageSegment, window: &Window, cx: &mut App) {
let rendered_segment = match segment { let rendered_segment = match segment {
@@ -929,21 +939,18 @@ impl ActiveThread {
let message_content = let message_content =
v_flex() v_flex()
.gap_1p5() .gap_1p5()
.child( .child(match edit_message_editor.clone() {
if let Some(edit_message_editor) = edit_message_editor.clone() { Some(edit_message_editor) => div()
div()
.key_context("EditMessageEditor") .key_context("EditMessageEditor")
.on_action(cx.listener(Self::cancel_editing_message)) .on_action(cx.listener(Self::cancel_editing_message))
.on_action(cx.listener(Self::confirm_editing_message)) .on_action(cx.listener(Self::confirm_editing_message))
.min_h_6() .min_h_6()
.child(edit_message_editor) .child(edit_message_editor),
} else { _ => div()
div()
.min_h_6() .min_h_6()
.text_ui(cx) .text_ui(cx)
.child(self.render_message_content(message_id, rendered_message, cx)) .child(self.render_message_content(message_id, rendered_message, cx)),
}, })
)
.when_some(context, |parent, context| { .when_some(context, |parent, context| {
if !context.is_empty() { if !context.is_empty() {
parent.child(h_flex().flex_wrap().gap_1().children( parent.child(h_flex().flex_wrap().gap_1().children(
@@ -1204,7 +1211,7 @@ impl ActiveThread {
message_id: MessageId, message_id: MessageId,
rendered_message: &RenderedMessage, rendered_message: &RenderedMessage,
cx: &Context<Self>, cx: &Context<Self>,
) -> impl IntoElement { ) -> impl IntoElement + use<> {
let pending_thinking_segment_index = rendered_message let pending_thinking_segment_index = rendered_message
.segments .segments
.iter() .iter()
@@ -1259,7 +1266,7 @@ impl ActiveThread {
scroll_handle: &ScrollHandle, scroll_handle: &ScrollHandle,
pending: bool, pending: bool,
cx: &Context<Self>, cx: &Context<Self>,
) -> impl IntoElement { ) -> impl IntoElement + use<> {
let is_open = self let is_open = self
.expanded_thinking_segments .expanded_thinking_segments
.get(&(message_id, ix)) .get(&(message_id, ix))
@@ -1412,7 +1419,11 @@ impl ActiveThread {
) )
} }
fn render_tool_use(&self, tool_use: ToolUse, cx: &mut Context<Self>) -> impl IntoElement { fn render_tool_use(
&self,
tool_use: ToolUse,
cx: &mut Context<Self>,
) -> impl IntoElement + use<> {
let is_open = self let is_open = self
.expanded_tool_uses .expanded_tool_uses
.get(&tool_use.id) .get(&tool_use.id)
@@ -1822,7 +1833,7 @@ impl ActiveThread {
fn render_confirmations<'a>( fn render_confirmations<'a>(
&'a mut self, &'a mut self,
cx: &'a mut Context<Self>, cx: &'a mut Context<Self>,
) -> impl Iterator<Item = AnyElement> + 'a { ) -> impl Iterator<Item = AnyElement> + 'a + use<'a> {
let thread = self.thread.read(cx); let thread = self.thread.read(cx);
thread thread

View File

@@ -105,7 +105,7 @@ impl AssistantConfiguration {
&mut self, &mut self,
provider: &Arc<dyn LanguageModelProvider>, provider: &Arc<dyn LanguageModelProvider>,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> impl IntoElement { ) -> impl IntoElement + use<> {
let provider_id = provider.id().0.clone(); let provider_id = provider.id().0.clone();
let provider_name = provider.name().0.clone(); let provider_name = provider.name().0.clone();
let configuration_view = self let configuration_view = self
@@ -167,7 +167,10 @@ impl AssistantConfiguration {
) )
} }
fn render_context_servers_section(&mut self, cx: &mut Context<Self>) -> impl IntoElement { fn render_context_servers_section(
&mut self,
cx: &mut Context<Self>,
) -> impl IntoElement + use<> {
let context_servers = self.context_server_manager.read(cx).all_servers().clone(); let context_servers = self.context_server_manager.read(cx).all_servers().clone();
let tools_by_source = self.tools.tools_by_source(cx); let tools_by_source = self.tools.tools_by_source(cx);
let empty = Vec::new(); let empty = Vec::new();

View File

@@ -318,7 +318,7 @@ impl ManageProfilesModal {
mode: ChooseProfileMode, mode: ChooseProfileMode,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> impl IntoElement { ) -> impl IntoElement + use<> {
Navigable::new( Navigable::new(
div() div()
.track_focus(&self.focus_handle(cx)) .track_focus(&self.focus_handle(cx))
@@ -418,7 +418,7 @@ impl ManageProfilesModal {
mode: NewProfileMode, mode: NewProfileMode,
_window: &mut Window, _window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> impl IntoElement { ) -> impl IntoElement + use<> {
let settings = AssistantSettings::get_global(cx); let settings = AssistantSettings::get_global(cx);
let base_profile_name = mode.base_profile_id.as_ref().map(|base_profile_id| { let base_profile_name = mode.base_profile_id.as_ref().map(|base_profile_id| {
@@ -448,7 +448,7 @@ impl ManageProfilesModal {
mode: ViewProfileMode, mode: ViewProfileMode,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> impl IntoElement { ) -> impl IntoElement + use<> {
let settings = AssistantSettings::get_global(cx); let settings = AssistantSettings::get_global(cx);
let profile_name = settings let profile_name = settings

View File

@@ -48,11 +48,11 @@ impl AssistantDiff {
.items_of_type::<AssistantDiff>(cx) .items_of_type::<AssistantDiff>(cx)
.find(|diff| diff.read(cx).thread == thread) .find(|diff| diff.read(cx).thread == thread)
})?; })?;
if let Some(existing_diff) = existing_diff { match existing_diff {
workspace.update(cx, |workspace, cx| { Some(existing_diff) => workspace.update(cx, |workspace, cx| {
workspace.activate_item(&existing_diff, true, true, window, cx); workspace.activate_item(&existing_diff, true, true, window, cx);
}) }),
} else { _ => {
let assistant_diff = let assistant_diff =
cx.new(|cx| AssistantDiff::new(thread.clone(), workspace.clone(), window, cx)); cx.new(|cx| AssistantDiff::new(thread.clone(), workspace.clone(), window, cx));
workspace.update(cx, |workspace, cx| { workspace.update(cx, |workspace, cx| {
@@ -60,6 +60,7 @@ impl AssistantDiff {
}) })
} }
} }
}
pub fn new( pub fn new(
thread: Entity<Thread>, thread: Entity<Thread>,

View File

@@ -584,20 +584,14 @@ impl Focusable for AssistantPanel {
match self.active_view { match self.active_view {
ActiveView::Thread => self.message_editor.focus_handle(cx), ActiveView::Thread => self.message_editor.focus_handle(cx),
ActiveView::History => self.history.focus_handle(cx), ActiveView::History => self.history.focus_handle(cx),
ActiveView::PromptEditor => { ActiveView::PromptEditor => match self.context_editor.as_ref() {
if let Some(context_editor) = self.context_editor.as_ref() { Some(context_editor) => context_editor.focus_handle(cx),
context_editor.focus_handle(cx) _ => cx.focus_handle(),
} else { },
cx.focus_handle() ActiveView::Configuration => match self.configuration.as_ref() {
} Some(configuration) => configuration.focus_handle(cx),
} _ => cx.focus_handle(),
ActiveView::Configuration => { },
if let Some(configuration) = self.configuration.as_ref() {
configuration.focus_handle(cx)
} else {
cx.focus_handle()
}
}
} }
} }
} }
@@ -683,7 +677,11 @@ impl Panel for AssistantPanel {
} }
impl AssistantPanel { impl AssistantPanel {
fn render_toolbar(&self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { fn render_toolbar(
&self,
_window: &mut Window,
cx: &mut Context<Self>,
) -> impl IntoElement + use<> {
let thread = self.thread.read(cx); let thread = self.thread.read(cx);
let focus_handle = self.focus_handle(cx); let focus_handle = self.focus_handle(cx);
@@ -825,7 +823,7 @@ impl AssistantPanel {
&self, &self,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> impl IntoElement { ) -> impl IntoElement + use<> {
let recent_history = self let recent_history = self
.history_store .history_store
.update(cx, |this, cx| this.recent_entries(6, cx)); .update(cx, |this, cx| this.recent_entries(6, cx));

View File

@@ -676,11 +676,14 @@ impl CodegenAlternative {
.update(cx, |this, cx| { .update(cx, |this, cx| {
this.message_id = message_id; this.message_id = message_id;
this.last_equal_ranges.clear(); this.last_equal_ranges.clear();
if let Err(error) = result { match result {
Err(error) => {
this.status = CodegenStatus::Error(error); this.status = CodegenStatus::Error(error);
} else { }
_ => {
this.status = CodegenStatus::Done; this.status = CodegenStatus::Done;
} }
}
this.elapsed_time = Some(elapsed_time); this.elapsed_time = Some(elapsed_time);
this.completion = Some(completion.lock().clone()); this.completion = Some(completion.lock().clone());
if let Some(usage) = token_usage { if let Some(usage) = token_usage {

View File

@@ -581,15 +581,14 @@ impl CompletionProvider for ContextPickerCompletionProvider {
let line_start = Point::new(position.row, 0); let line_start = Point::new(position.row, 0);
let offset_to_line = buffer.point_to_offset(line_start); let offset_to_line = buffer.point_to_offset(line_start);
let mut lines = buffer.text_for_range(line_start..position).lines(); let mut lines = buffer.text_for_range(line_start..position).lines();
if let Some(line) = lines.next() { match lines.next() {
MentionCompletion::try_parse(line, offset_to_line) Some(line) => MentionCompletion::try_parse(line, offset_to_line)
.map(|completion| { .map(|completion| {
completion.source_range.start <= offset_to_line + position.column as usize completion.source_range.start <= offset_to_line + position.column as usize
&& completion.source_range.end >= offset_to_line + position.column as usize && completion.source_range.end >= offset_to_line + position.column as usize
}) })
.unwrap_or(false) .unwrap_or(false),
} else { _ => false,
false
} }
} }

View File

@@ -360,14 +360,17 @@ impl ContextStore {
remove_if_exists: bool, remove_if_exists: bool,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
if let Some(context_id) = self.includes_thread(&thread.read(cx).id()) { match self.includes_thread(&thread.read(cx).id()) {
Some(context_id) => {
if remove_if_exists { if remove_if_exists {
self.remove_context(context_id); self.remove_context(context_id);
} }
} else { }
_ => {
self.insert_thread(thread, cx); self.insert_thread(thread, cx);
} }
} }
}
fn insert_thread(&mut self, thread: Entity<Thread>, cx: &App) { fn insert_thread(&mut self, thread: Entity<Thread>, cx: &App) {
let id = self.next_context_id.post_inc(); let id = self.next_context_id.post_inc();
@@ -687,7 +690,7 @@ pub fn refresh_context_store_text(
context_store: Entity<ContextStore>, context_store: Entity<ContextStore>,
changed_buffers: &HashSet<Entity<Buffer>>, changed_buffers: &HashSet<Entity<Buffer>>,
cx: &App, cx: &App,
) -> impl Future<Output = Vec<ContextId>> { ) -> impl Future<Output = Vec<ContextId>> + use<> {
let mut tasks = Vec::new(); let mut tasks = Vec::new();
for context in &context_store.read(cx).context { for context in &context_store.read(cx).context {
@@ -756,8 +759,8 @@ fn refresh_file_text(
) -> Option<Task<()>> { ) -> Option<Task<()>> {
let id = file_context.id; let id = file_context.id;
let task = refresh_context_buffer(&file_context.context_buffer, cx); let task = refresh_context_buffer(&file_context.context_buffer, cx);
if let Some(task) = task { match task {
Some(cx.spawn(async move |cx| { Some(task) => Some(cx.spawn(async move |cx| {
let context_buffer = task.await; let context_buffer = task.await;
context_store context_store
.update(cx, |context_store, _| { .update(cx, |context_store, _| {
@@ -765,9 +768,8 @@ fn refresh_file_text(
context_store.replace_context(AssistantContext::File(new_file_context)); context_store.replace_context(AssistantContext::File(new_file_context));
}) })
.ok(); .ok();
})) })),
} else { _ => None,
None
} }
} }
@@ -780,14 +782,15 @@ fn refresh_directory_text(
let futures = directory_context let futures = directory_context
.context_buffers .context_buffers
.iter() .iter()
.map(|context_buffer| { .map(
if let Some(refresh_task) = refresh_context_buffer(context_buffer, cx) { |context_buffer| match refresh_context_buffer(context_buffer, cx) {
Some(refresh_task) => {
stale = true; stale = true;
future::Either::Left(refresh_task) future::Either::Left(refresh_task)
} else {
future::Either::Right(future::ready((*context_buffer).clone()))
} }
}) _ => future::Either::Right(future::ready((*context_buffer).clone())),
},
)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
if !stale { if !stale {
@@ -816,8 +819,8 @@ fn refresh_symbol_text(
) -> Option<Task<()>> { ) -> Option<Task<()>> {
let id = symbol_context.id; let id = symbol_context.id;
let task = refresh_context_symbol(&symbol_context.context_symbol, cx); let task = refresh_context_symbol(&symbol_context.context_symbol, cx);
if let Some(task) = task { match task {
Some(cx.spawn(async move |cx| { Some(task) => Some(cx.spawn(async move |cx| {
let context_symbol = task.await; let context_symbol = task.await;
context_store context_store
.update(cx, |context_store, _| { .update(cx, |context_store, _| {
@@ -825,9 +828,8 @@ fn refresh_symbol_text(
context_store.replace_context(AssistantContext::Symbol(new_symbol_context)); context_store.replace_context(AssistantContext::Symbol(new_symbol_context));
}) })
.ok(); .ok();
})) })),
} else { _ => None,
None
} }
} }
@@ -855,7 +857,7 @@ fn refresh_thread_text(
fn refresh_context_buffer( fn refresh_context_buffer(
context_buffer: &ContextBuffer, context_buffer: &ContextBuffer,
cx: &App, cx: &App,
) -> Option<impl Future<Output = ContextBuffer>> { ) -> Option<impl Future<Output = ContextBuffer> + use<>> {
let buffer = context_buffer.buffer.read(cx); let buffer = context_buffer.buffer.read(cx);
let path = buffer_path_log_err(buffer)?; let path = buffer_path_log_err(buffer)?;
if buffer.version.changed_since(&context_buffer.version) { if buffer.version.changed_since(&context_buffer.version) {
@@ -875,7 +877,7 @@ fn refresh_context_buffer(
fn refresh_context_symbol( fn refresh_context_symbol(
context_symbol: &ContextSymbol, context_symbol: &ContextSymbol,
cx: &App, cx: &App,
) -> Option<impl Future<Output = ContextSymbol>> { ) -> Option<impl Future<Output = ContextSymbol> + use<>> {
let buffer = context_symbol.buffer.read(cx); let buffer = context_symbol.buffer.read(cx);
let path = buffer_path_log_err(buffer)?; let path = buffer_path_log_err(buffer)?;
let project_path = buffer.project_path(cx)?; let project_path = buffer.project_path(cx)?;

View File

@@ -341,9 +341,9 @@ impl InlineAssistant {
selection.end.column = snapshot selection.end.column = snapshot
.buffer_snapshot .buffer_snapshot
.line_len(MultiBufferRow(selection.end.row)); .line_len(MultiBufferRow(selection.end.row));
} else if let Some(fold) = } else {
snapshot.crease_for_buffer_row(MultiBufferRow(selection.end.row)) match snapshot.crease_for_buffer_row(MultiBufferRow(selection.end.row)) {
{ Some(fold) => {
selection.start = fold.range().start; selection.start = fold.range().start;
selection.end = fold.range().end; selection.end = fold.range().end;
if MultiBufferRow(selection.end.row) < snapshot.buffer_snapshot.max_row() { if MultiBufferRow(selection.end.row) < snapshot.buffer_snapshot.max_row() {
@@ -358,10 +358,9 @@ impl InlineAssistant {
if c.is_whitespace() { if c.is_whitespace() {
continue; continue;
} }
if snapshot if snapshot.language_at(selection.end).is_some_and(|language| {
.language_at(selection.end) language.config().brackets.is_closing_brace(c)
.is_some_and(|language| language.config().brackets.is_closing_brace(c)) }) {
{
selection.end.row += 1; selection.end.row += 1;
selection.end.column = snapshot selection.end.column = snapshot
.buffer_snapshot .buffer_snapshot
@@ -370,6 +369,9 @@ impl InlineAssistant {
} }
} }
} }
_ => {}
}
}
if let Some(prev_selection) = selections.last_mut() { if let Some(prev_selection) = selections.last_mut() {
if selection.start <= prev_selection.end { if selection.start <= prev_selection.end {
@@ -1129,7 +1131,8 @@ impl InlineAssistant {
let mut scroll_target_top; let mut scroll_target_top;
let mut scroll_target_bottom; let mut scroll_target_bottom;
if let Some(decorations) = assist.decorations.as_ref() { match assist.decorations.as_ref() {
Some(decorations) => {
scroll_target_top = editor scroll_target_top = editor
.row_for_block(decorations.prompt_block_id, cx) .row_for_block(decorations.prompt_block_id, cx)
.unwrap() .unwrap()
@@ -1138,7 +1141,8 @@ impl InlineAssistant {
.row_for_block(decorations.end_block_id, cx) .row_for_block(decorations.end_block_id, cx)
.unwrap() .unwrap()
.0 as f32; .0 as f32;
} else { }
_ => {
let snapshot = editor.snapshot(window, cx); let snapshot = editor.snapshot(window, cx);
let start_row = assist let start_row = assist
.range .range
@@ -1148,6 +1152,7 @@ impl InlineAssistant {
scroll_target_top = start_row.0 as f32; scroll_target_top = start_row.0 as f32;
scroll_target_bottom = scroll_target_top + 1.; scroll_target_bottom = scroll_target_top + 1.;
} }
}
scroll_target_top -= editor.vertical_scroll_margin() as f32; scroll_target_top -= editor.vertical_scroll_margin() as f32;
scroll_target_bottom += editor.vertical_scroll_margin() as f32; scroll_target_bottom += editor.vertical_scroll_margin() as f32;
@@ -1191,10 +1196,11 @@ impl InlineAssistant {
} }
pub fn start_assist(&mut self, assist_id: InlineAssistId, window: &mut Window, cx: &mut App) { pub fn start_assist(&mut self, assist_id: InlineAssistId, window: &mut Window, cx: &mut App) {
let assist = if let Some(assist) = self.assists.get_mut(&assist_id) { let assist = match self.assists.get_mut(&assist_id) {
assist Some(assist) => assist,
} else { _ => {
return; return;
}
}; };
let assist_group_id = assist.group_id; let assist_group_id = assist.group_id;
@@ -1222,10 +1228,11 @@ impl InlineAssistant {
} }
pub fn stop_assist(&mut self, assist_id: InlineAssistId, cx: &mut App) { pub fn stop_assist(&mut self, assist_id: InlineAssistId, cx: &mut App) {
let assist = if let Some(assist) = self.assists.get_mut(&assist_id) { let assist = match self.assists.get_mut(&assist_id) {
assist Some(assist) => assist,
} else { _ => {
return; return;
}
}; };
assist.codegen.update(cx, |codegen, cx| codegen.stop(cx)); assist.codegen.update(cx, |codegen, cx| codegen.stop(cx));
@@ -1449,20 +1456,27 @@ impl InlineAssistant {
} }
}); });
if let Some(context_editor) = context_editor { match context_editor {
Some(InlineAssistTarget::Editor(context_editor)) Some(context_editor) => Some(InlineAssistTarget::Editor(context_editor)),
} else if let Some(workspace_editor) = workspace _ => {
match workspace
.active_item(cx) .active_item(cx)
.and_then(|item| item.act_as::<Editor>(cx)) .and_then(|item| item.act_as::<Editor>(cx))
{ {
Some(InlineAssistTarget::Editor(workspace_editor)) Some(workspace_editor) => Some(InlineAssistTarget::Editor(workspace_editor)),
} else if let Some(terminal_view) = workspace _ => {
match workspace
.active_item(cx) .active_item(cx)
.and_then(|item| item.act_as::<TerminalView>(cx)) .and_then(|item| item.act_as::<TerminalView>(cx))
{ {
Some(terminal_view) => {
Some(InlineAssistTarget::Terminal(terminal_view)) Some(InlineAssistTarget::Terminal(terminal_view))
} else { }
None _ => None,
}
}
}
}
} }
} }
} }
@@ -1654,10 +1668,11 @@ impl InlineAssist {
InlineAssistant::update_global(cx, |this, cx| match event { InlineAssistant::update_global(cx, |this, cx| match event {
CodegenEvent::Undone => this.finish_assist(assist_id, false, window, cx), CodegenEvent::Undone => this.finish_assist(assist_id, false, window, cx),
CodegenEvent::Finished => { CodegenEvent::Finished => {
let assist = if let Some(assist) = this.assists.get(&assist_id) { let assist = match this.assists.get(&assist_id) {
assist Some(assist) => assist,
} else { _ => {
return; return;
}
}; };
if let CodegenStatus::Error(error) = codegen.read(cx).status(cx) { if let CodegenStatus::Error(error) = codegen.read(cx).status(cx) {

View File

@@ -677,7 +677,7 @@ impl<T: 'static> PromptEditor<T> {
.into_any_element() .into_any_element()
} }
fn render_rate_limit_notice(&self, cx: &mut Context<Self>) -> impl IntoElement { fn render_rate_limit_notice(&self, cx: &mut Context<Self>) -> impl IntoElement + use<T> {
Popover::new().child( Popover::new().child(
v_flex() v_flex()
.occlude() .occlude()

View File

@@ -117,11 +117,14 @@ impl TerminalCodegen {
let result = generate.await; let result = generate.await;
this.update(cx, |this, cx| { this.update(cx, |this, cx| {
if let Err(error) = result { match result {
Err(error) => {
this.status = CodegenStatus::Error(error); this.status = CodegenStatus::Error(error);
} else { }
_ => {
this.status = CodegenStatus::Done; this.status = CodegenStatus::Done;
} }
}
cx.emit(CodegenEvent::Finished); cx.emit(CodegenEvent::Finished);
cx.notify(); cx.notify();
}) })

View File

@@ -164,10 +164,11 @@ impl TerminalInlineAssistant {
} }
fn start_assist(&mut self, assist_id: TerminalInlineAssistId, cx: &mut App) { fn start_assist(&mut self, assist_id: TerminalInlineAssistId, cx: &mut App) {
let assist = if let Some(assist) = self.assists.get_mut(&assist_id) { let assist = match self.assists.get_mut(&assist_id) {
assist Some(assist) => assist,
} else { _ => {
return; return;
}
}; };
let Some(user_prompt) = assist let Some(user_prompt) = assist
@@ -202,10 +203,11 @@ impl TerminalInlineAssistant {
} }
fn stop_assist(&mut self, assist_id: TerminalInlineAssistId, cx: &mut App) { fn stop_assist(&mut self, assist_id: TerminalInlineAssistId, cx: &mut App) {
let assist = if let Some(assist) = self.assists.get_mut(&assist_id) { let assist = match self.assists.get_mut(&assist_id) {
assist Some(assist) => assist,
} else { _ => {
return; return;
}
}; };
assist.codegen.update(cx, |codegen, cx| codegen.stop(cx)); assist.codegen.update(cx, |codegen, cx| codegen.stop(cx));
@@ -402,10 +404,11 @@ impl TerminalInlineAssist {
window.subscribe(&codegen, cx, move |codegen, event, window, cx| { window.subscribe(&codegen, cx, move |codegen, event, window, cx| {
TerminalInlineAssistant::update_global(cx, |this, cx| match event { TerminalInlineAssistant::update_global(cx, |this, cx| match event {
CodegenEvent::Finished => { CodegenEvent::Finished => {
let assist = if let Some(assist) = this.assists.get(&assist_id) { let assist = match this.assists.get(&assist_id) {
assist Some(assist) => assist,
} else { _ => {
return; return;
}
}; };
if let CodegenStatus::Error(error) = &codegen.read(cx).status { if let CodegenStatus::Error(error) = &codegen.read(cx).status {

View File

@@ -379,15 +379,18 @@ impl Thread {
cx.spawn(async move |this, cx| { cx.spawn(async move |this, cx| {
let result = restore.await; let result = restore.await;
this.update(cx, |this, cx| { this.update(cx, |this, cx| {
if let Err(err) = result.as_ref() { match result.as_ref() {
Err(err) => {
this.last_restore_checkpoint = Some(LastRestoreCheckpoint::Error { this.last_restore_checkpoint = Some(LastRestoreCheckpoint::Error {
message_id: checkpoint.message_id, message_id: checkpoint.message_id,
error: err.to_string(), error: err.to_string(),
}); });
} else { }
_ => {
this.truncate(checkpoint.message_id, cx); this.truncate(checkpoint.message_id, cx);
this.last_restore_checkpoint = None; this.last_restore_checkpoint = None;
} }
}
this.pending_checkpoint = None; this.pending_checkpoint = None;
cx.emit(ThreadEvent::CheckpointChanged); cx.emit(ThreadEvent::CheckpointChanged);
cx.notify(); cx.notify();
@@ -721,8 +724,8 @@ impl Thread {
}) })
.next(); .next();
if let Some((rel_rules_path, abs_rules_path)) = selected_rules_file { match selected_rules_file {
cx.spawn(async move |_| { Some((rel_rules_path, abs_rules_path)) => cx.spawn(async move |_| {
let rules_file_result = maybe!(async move { let rules_file_result = maybe!(async move {
let abs_rules_path = abs_rules_path?; let abs_rules_path = abs_rules_path?;
let text = fs.load(&abs_rules_path).await.with_context(|| { let text = fs.load(&abs_rules_path).await.with_context(|| {
@@ -751,16 +754,15 @@ impl Thread {
rules_file, rules_file,
}; };
(worktree_info, rules_file_error) (worktree_info, rules_file_error)
}) }),
} else { _ => Task::ready((
Task::ready((
WorktreeInfoForSystemPrompt { WorktreeInfoForSystemPrompt {
root_name, root_name,
abs_path, abs_path,
rules_file: None, rules_file: None,
}, },
None, None,
)) )),
} }
} }
@@ -1186,7 +1188,7 @@ impl Thread {
pub fn use_pending_tools( pub fn use_pending_tools(
&mut self, &mut self,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> impl IntoIterator<Item = PendingToolUse> { ) -> impl IntoIterator<Item = PendingToolUse> + use<> {
let request = self.to_completion_request(RequestKind::Chat, cx); let request = self.to_completion_request(RequestKind::Chat, cx);
let messages = Arc::new(request.messages); let messages = Arc::new(request.messages);
let pending_tool_uses = self let pending_tool_uses = self
@@ -1198,7 +1200,8 @@ impl Thread {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
for tool_use in pending_tool_uses.iter() { for tool_use in pending_tool_uses.iter() {
if let Some(tool) = self.tools.tool(&tool_use.name, cx) { match self.tools.tool(&tool_use.name, cx) {
Some(tool) => {
if tool.needs_confirmation() if tool.needs_confirmation()
&& !AssistantSettings::get_global(cx).always_allow_tool_actions && !AssistantSettings::get_global(cx).always_allow_tool_actions
{ {
@@ -1220,7 +1223,9 @@ impl Thread {
cx, cx,
); );
} }
} else if let Some(tool) = self.tools.tool(&tool_use.name, cx) { }
_ => match self.tools.tool(&tool_use.name, cx) {
Some(tool) => {
self.run_tool( self.run_tool(
tool_use.id.clone(), tool_use.id.clone(),
tool_use.ui_text.clone(), tool_use.ui_text.clone(),
@@ -1230,6 +1235,9 @@ impl Thread {
cx, cx,
); );
} }
_ => {}
},
}
} }
pending_tool_uses pending_tool_uses

View File

@@ -166,8 +166,8 @@ impl ToolUseState {
}; };
} }
if let Some(pending_tool_use) = self.pending_tool_uses_by_id.get(&tool_use.id) { match self.pending_tool_uses_by_id.get(&tool_use.id) {
match pending_tool_use.status { Some(pending_tool_use) => match pending_tool_use.status {
PendingToolUseStatus::Idle => ToolUseStatus::Pending, PendingToolUseStatus::Idle => ToolUseStatus::Pending,
PendingToolUseStatus::NeedsConfirmation { .. } => { PendingToolUseStatus::NeedsConfirmation { .. } => {
ToolUseStatus::NeedsConfirmation ToolUseStatus::NeedsConfirmation
@@ -176,17 +176,14 @@ impl ToolUseState {
PendingToolUseStatus::Error(ref err) => { PendingToolUseStatus::Error(ref err) => {
ToolUseStatus::Error(err.clone().into()) ToolUseStatus::Error(err.clone().into())
} }
} },
} else { _ => ToolUseStatus::Pending,
ToolUseStatus::Pending
} }
})(); })();
let (icon, needs_confirmation) = if let Some(tool) = self.tools.tool(&tool_use.name, cx) let (icon, needs_confirmation) = match self.tools.tool(&tool_use.name, cx) {
{ Some(tool) => (tool.icon(), tool.needs_confirmation()),
(tool.icon(), tool.needs_confirmation()) _ => (IconName::Cog, false),
} else {
(IconName::Cog, false)
}; };
tool_uses.push(ToolUse { tool_uses.push(ToolUse {
@@ -209,10 +206,9 @@ impl ToolUseState {
input: &serde_json::Value, input: &serde_json::Value,
cx: &App, cx: &App,
) -> SharedString { ) -> SharedString {
if let Some(tool) = self.tools.tool(tool_name, cx) { match self.tools.tool(tool_name, cx) {
tool.ui_text(input).into() Some(tool) => tool.ui_text(input).into(),
} else { _ => format!("Unknown tool {tool_name:?}").into(),
format!("Unknown tool {tool_name:?}").into()
} }
} }

View File

@@ -1877,16 +1877,19 @@ impl AssistantContext {
if let Some(mut pending_patch) = pending_patch { if let Some(mut pending_patch) = pending_patch {
let patch_start = pending_patch.range.start.to_offset(buffer); let patch_start = pending_patch.range.start.to_offset(buffer);
if let Some(message) = self.message_for_offset(patch_start, cx) { match self.message_for_offset(patch_start, cx) {
Some(message) => {
if message.anchor_range.end == text::Anchor::MAX { if message.anchor_range.end == text::Anchor::MAX {
pending_patch.range.end = text::Anchor::MAX; pending_patch.range.end = text::Anchor::MAX;
} else { } else {
let message_end = buffer.anchor_after(message.offset_range.end - 1); let message_end = buffer.anchor_after(message.offset_range.end - 1);
pending_patch.range.end = message_end; pending_patch.range.end = message_end;
} }
} else { }
_ => {
pending_patch.range.end = text::Anchor::MAX; pending_patch.range.end = text::Anchor::MAX;
} }
}
new_patches.push(pending_patch); new_patches.push(pending_patch);
} }
@@ -2453,7 +2456,7 @@ impl AssistantContext {
let result = stream_completion.await; let result = stream_completion.await;
this.update(cx, |this, cx| { this.update(cx, |this, cx| {
let error_message = if let Some(error) = result.as_ref().err() { let error_message = match result.as_ref().err() { Some(error) => {
if error.is::<PaymentRequiredError>() { if error.is::<PaymentRequiredError>() {
cx.emit(ContextEvent::ShowPaymentRequiredError); cx.emit(ContextEvent::ShowPaymentRequiredError);
this.update_metadata(assistant_message_id, cx, |metadata| { this.update_metadata(assistant_message_id, cx, |metadata| {
@@ -2481,12 +2484,12 @@ impl AssistantContext {
}); });
Some(error_message) Some(error_message)
} }
} else { } _ => {
this.update_metadata(assistant_message_id, cx, |metadata| { this.update_metadata(assistant_message_id, cx, |metadata| {
metadata.status = MessageStatus::Done; metadata.status = MessageStatus::Done;
}); });
None None
}; }};
let language_name = this let language_name = this
.buffer .buffer
@@ -2631,15 +2634,16 @@ impl AssistantContext {
} }
pub fn cancel_last_assist(&mut self, cx: &mut Context<Self>) -> bool { pub fn cancel_last_assist(&mut self, cx: &mut Context<Self>) -> bool {
if let Some(pending_completion) = self.pending_completions.pop() { match self.pending_completions.pop() {
Some(pending_completion) => {
self.update_metadata(pending_completion.assistant_message_id, cx, |metadata| { self.update_metadata(pending_completion.assistant_message_id, cx, |metadata| {
if metadata.status == MessageStatus::Pending { if metadata.status == MessageStatus::Pending {
metadata.status = MessageStatus::Canceled; metadata.status = MessageStatus::Canceled;
} }
}); });
true true
} else { }
false _ => false,
} }
} }
@@ -2799,7 +2803,8 @@ impl AssistantContext {
) -> (Option<MessageAnchor>, Option<MessageAnchor>) { ) -> (Option<MessageAnchor>, Option<MessageAnchor>) {
let start_message = self.message_for_offset(range.start, cx); let start_message = self.message_for_offset(range.start, cx);
let end_message = self.message_for_offset(range.end, cx); let end_message = self.message_for_offset(range.end, cx);
if let Some((start_message, end_message)) = start_message.zip(end_message) { match start_message.zip(end_message) {
Some((start_message, end_message)) => {
// Prevent splitting when range spans multiple messages. // Prevent splitting when range spans multiple messages.
if start_message.id != end_message.id { if start_message.id != end_message.id {
return (None, None); return (None, None);
@@ -2817,7 +2822,8 @@ impl AssistantContext {
{ {
if self.buffer.read(cx).chars_at(range.end).next() == Some('\n') { if self.buffer.read(cx).chars_at(range.end).next() == Some('\n') {
suffix_start = Some(range.end + 1); suffix_start = Some(range.end + 1);
} else if self.buffer.read(cx).reversed_chars_at(range.end).next() == Some('\n') { } else if self.buffer.read(cx).reversed_chars_at(range.end).next() == Some('\n')
{
suffix_start = Some(range.end); suffix_start = Some(range.end);
} }
} }
@@ -2912,8 +2918,8 @@ impl AssistantContext {
cx.emit(ContextEvent::MessagesEdited); cx.emit(ContextEvent::MessagesEdited);
} }
new_messages new_messages
} else { }
(None, None) _ => (None, None),
} }
} }

View File

@@ -403,10 +403,12 @@ impl ContextEditor {
if request_type == RequestType::SuggestEdits && !self.context.read(cx).contains_files(cx) { if request_type == RequestType::SuggestEdits && !self.context.read(cx).contains_files(cx) {
self.last_error = Some(AssistError::FileRequired); self.last_error = Some(AssistError::FileRequired);
cx.notify(); cx.notify();
} else if let Some(user_message) = self } else {
match self
.context .context
.update(cx, |context, cx| context.assist(request_type, cx)) .update(cx, |context, cx| context.assist(request_type, cx))
{ {
Some(user_message) => {
let new_selection = { let new_selection = {
let cursor = user_message let cursor = user_message
.start .start
@@ -414,13 +416,19 @@ impl ContextEditor {
cursor..cursor cursor..cursor
}; };
self.editor.update(cx, |editor, cx| { self.editor.update(cx, |editor, cx| {
editor.change_selections(Some(Autoscroll::fit()), window, cx, |selections| { editor.change_selections(
selections.select_ranges([new_selection]) Some(Autoscroll::fit()),
}); window,
cx,
|selections| selections.select_ranges([new_selection]),
);
}); });
// Avoid scrolling to the new cursor position so the assistant's output is stable. // Avoid scrolling to the new cursor position so the assistant's output is stable.
cx.defer_in(window, |this, _, _| this.scroll_position = None); cx.defer_in(window, |this, _, _| this.scroll_position = None);
} }
_ => {}
}
}
cx.notify(); cx.notify();
} }
@@ -817,10 +825,9 @@ impl ContextEditor {
} }
self.editor.update(cx, |editor, cx| { self.editor.update(cx, |editor, cx| {
if let Some(invoked_slash_command) = match self.context.read(cx).invoked_slash_command(&command_id) {
self.context.read(cx).invoked_slash_command(&command_id) Some(invoked_slash_command) => match invoked_slash_command.status {
{ InvokedSlashCommandStatus::Finished => {
if let InvokedSlashCommandStatus::Finished = invoked_slash_command.status {
let buffer = editor.buffer().read(cx).snapshot(cx); let buffer = editor.buffer().read(cx).snapshot(cx);
let (&excerpt_id, _buffer_id, _buffer_snapshot) = let (&excerpt_id, _buffer_id, _buffer_snapshot) =
buffer.as_singleton().unwrap(); buffer.as_singleton().unwrap();
@@ -839,10 +846,14 @@ impl ContextEditor {
); );
editor.remove_creases( editor.remove_creases(
HashSet::from_iter(self.invoked_slash_command_creases.remove(&command_id)), HashSet::from_iter(
self.invoked_slash_command_creases.remove(&command_id),
),
cx, cx,
); );
} else if let hash_map::Entry::Vacant(entry) = }
_ => {
if let hash_map::Entry::Vacant(entry) =
self.invoked_slash_command_creases.entry(command_id) self.invoked_slash_command_creases.entry(command_id)
{ {
let buffer = editor.buffer().read(cx).snapshot(cx); let buffer = editor.buffer().read(cx).snapshot(cx);
@@ -867,12 +878,15 @@ impl ContextEditor {
} else { } else {
cx.notify() cx.notify()
} }
} else { }
},
_ => {
editor.remove_creases( editor.remove_creases(
HashSet::from_iter(self.invoked_slash_command_creases.remove(&command_id)), HashSet::from_iter(self.invoked_slash_command_creases.remove(&command_id)),
cx, cx,
); );
cx.notify(); cx.notify();
}
}; };
}); });
} }
@@ -958,7 +972,8 @@ impl ContextEditor {
); );
let should_refold; let should_refold;
if let Some(state) = self.patches.get_mut(&range) { match self.patches.get_mut(&range) {
Some(state) => {
if let Some(editor_state) = &state.editor { if let Some(editor_state) = &state.editor {
if editor_state.opened_patch != patch { if editor_state.opened_patch != patch {
state.update_task = Some({ state.update_task = Some({
@@ -972,9 +987,10 @@ impl ContextEditor {
} }
} }
should_refold = should_refold = snapshot
snapshot.intersects_fold(patch_start.to_offset(&snapshot.buffer_snapshot)); .intersects_fold(patch_start.to_offset(&snapshot.buffer_snapshot));
} else { }
_ => {
let crease_id = editor.insert_creases([crease.clone()], cx)[0]; let crease_id = editor.insert_creases([crease.clone()], cx)[0];
self.patches.insert( self.patches.insert(
range.clone(), range.clone(),
@@ -987,6 +1003,7 @@ impl ContextEditor {
should_refold = true; should_refold = true;
} }
}
if should_refold { if should_refold {
editor.unfold_ranges(&[patch_start..patch_end], true, false, cx); editor.unfold_ranges(&[patch_start..patch_end], true, false, cx);
@@ -1175,20 +1192,24 @@ impl ContextEditor {
} }
} }
if let Some(editor) = editor { match editor {
Some(editor) => {
self.workspace self.workspace
.update(cx, |workspace, cx| { .update(cx, |workspace, cx| {
workspace.activate_item(&editor, true, false, window, cx); workspace.activate_item(&editor, true, false, window, cx);
}) })
.ok(); .ok();
} else { }
patch_state.update_task = Some(cx.spawn_in(window, async move |this, cx| { _ => {
patch_state.update_task =
Some(cx.spawn_in(window, async move |this, cx| {
Self::open_patch_editor(this, new_patch, cx).await.log_err(); Self::open_patch_editor(this, new_patch, cx).await.log_err();
})); }));
} }
} }
} }
} }
}
fn close_patch_editor( fn close_patch_editor(
&mut self, &mut self,
@@ -1282,7 +1303,8 @@ impl ContextEditor {
.collect(); .collect();
if let Some(state) = &mut patch_state.editor { if let Some(state) = &mut patch_state.editor {
if let Some(editor) = state.editor.upgrade() { match state.editor.upgrade() {
Some(editor) => {
editor.update(cx, |editor, cx| { editor.update(cx, |editor, cx| {
editor.set_title(patch.title.clone(), cx); editor.set_title(patch.title.clone(), cx);
editor.reset_locations(locations, window, cx); editor.reset_locations(locations, window, cx);
@@ -1290,10 +1312,12 @@ impl ContextEditor {
}); });
state.opened_patch = patch; state.opened_patch = patch;
} else { }
_ => {
patch_state.editor.take(); patch_state.editor.take();
} }
} }
}
patch_state.update_task.take(); patch_state.update_task.take();
Some(()) Some(())
@@ -1573,7 +1597,8 @@ impl ContextEditor {
let mut new_blocks = vec![]; let mut new_blocks = vec![];
let mut block_index_to_message = vec![]; let mut block_index_to_message = vec![];
for message in self.context.read(cx).messages(cx) { for message in self.context.read(cx).messages(cx) {
if let Some(_) = blocks_to_remove.remove(&message.id) { match blocks_to_remove.remove(&message.id) {
Some(_) => {
// This is an old message that we might modify. // This is an old message that we might modify.
let Some((meta, block_id)) = old_blocks.get_mut(&message.id) else { let Some((meta, block_id)) = old_blocks.get_mut(&message.id) else {
debug_assert!( debug_assert!(
@@ -1588,12 +1613,14 @@ impl ContextEditor {
blocks_to_replace.insert(*block_id, render_block(message_meta.clone())); blocks_to_replace.insert(*block_id, render_block(message_meta.clone()));
*meta = message_meta; *meta = message_meta;
} }
} else { }
_ => {
// This is a new message. // This is a new message.
new_blocks.push(create_block_properties(&message)); new_blocks.push(create_block_properties(&message));
block_index_to_message.push((message.id, MessageMetadata::from(&message))); block_index_to_message.push((message.id, MessageMetadata::from(&message)));
} }
} }
}
editor.replace_blocks(blocks_to_replace, None, cx); editor.replace_blocks(blocks_to_replace, None, cx);
editor.remove_blocks(blocks_to_remove.into_values().collect(), None, cx); editor.remove_blocks(blocks_to_remove.into_values().collect(), None, cx);
@@ -2321,10 +2348,14 @@ impl ContextEditor {
) )
.into_any_element(), .into_any_element(),
) )
} else if let Some(configuration_error) = configuration_error(cx) { } else {
match configuration_error(cx) {
Some(configuration_error) => {
let label = match configuration_error { let label = match configuration_error {
ConfigurationError::NoProvider => "No LLM provider selected.", ConfigurationError::NoProvider => "No LLM provider selected.",
ConfigurationError::ProviderNotAuthenticated => "LLM provider is not configured.", ConfigurationError::ProviderNotAuthenticated => {
"LLM provider is not configured."
}
ConfigurationError::ProviderPendingTermsAcceptance(_) => { ConfigurationError::ProviderPendingTermsAcceptance(_) => {
"LLM provider requires accepting the Terms of Service." "LLM provider requires accepting the Terms of Service."
} }
@@ -2357,18 +2388,27 @@ impl ContextEditor {
.on_click({ .on_click({
let focus_handle = self.focus_handle(cx).clone(); let focus_handle = self.focus_handle(cx).clone();
move |_event, window, cx| { move |_event, window, cx| {
focus_handle.dispatch_action(&ShowConfiguration, window, cx); focus_handle.dispatch_action(
&ShowConfiguration,
window,
cx,
);
} }
}), }),
) )
.into_any_element(), .into_any_element(),
) )
} else { }
None _ => None,
}
} }
} }
fn render_send_button(&self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { fn render_send_button(
&self,
window: &mut Window,
cx: &mut Context<Self>,
) -> impl IntoElement + use<> {
let focus_handle = self.focus_handle(cx).clone(); let focus_handle = self.focus_handle(cx).clone();
let (style, tooltip) = match token_state(&self.context, cx) { let (style, tooltip) = match token_state(&self.context, cx) {
@@ -2427,7 +2467,11 @@ impl ContextEditor {
}) })
} }
fn render_edit_button(&self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { fn render_edit_button(
&self,
window: &mut Window,
cx: &mut Context<Self>,
) -> impl IntoElement + use<> {
let focus_handle = self.focus_handle(cx).clone(); let focus_handle = self.focus_handle(cx).clone();
let (style, tooltip) = match token_state(&self.context, cx) { let (style, tooltip) = match token_state(&self.context, cx) {
@@ -2480,7 +2524,7 @@ impl ContextEditor {
}) })
} }
fn render_inject_context_menu(&self, cx: &mut Context<Self>) -> impl IntoElement { fn render_inject_context_menu(&self, cx: &mut Context<Self>) -> impl IntoElement + use<> {
slash_command_picker::SlashCommandSelector::new( slash_command_picker::SlashCommandSelector::new(
self.slash_commands.clone(), self.slash_commands.clone(),
cx.entity().downgrade(), cx.entity().downgrade(),
@@ -2499,7 +2543,7 @@ impl ContextEditor {
) )
} }
fn render_language_model_selector(&self, cx: &mut Context<Self>) -> impl IntoElement { fn render_language_model_selector(&self, cx: &mut Context<Self>) -> impl IntoElement + use<> {
let active_model = LanguageModelRegistry::read_global(cx).active_model(); let active_model = LanguageModelRegistry::read_global(cx).active_model();
let focus_handle = self.editor().focus_handle(cx).clone(); let focus_handle = self.editor().focus_handle(cx).clone();
let model_name = match active_model { let model_name = match active_model {
@@ -3283,12 +3327,9 @@ impl FollowableItem for ContextEditor {
Some(proto::view::Variant::ContextEditor( Some(proto::view::Variant::ContextEditor(
proto::view::ContextEditor { proto::view::ContextEditor {
context_id: context.id().to_proto(), context_id: context.id().to_proto(),
editor: if let Some(proto::view::Variant::Editor(proto)) = editor: match self.editor.read(cx).to_state_proto(window, cx) {
self.editor.read(cx).to_state_proto(window, cx) Some(proto::view::Variant::Editor(proto)) => Some(proto),
{ _ => None,
Some(proto)
} else {
None
}, },
}, },
)) ))
@@ -3413,7 +3454,7 @@ impl ContextEditorToolbarItem {
pub fn render_remaining_tokens( pub fn render_remaining_tokens(
context_editor: &Entity<ContextEditor>, context_editor: &Entity<ContextEditor>,
cx: &App, cx: &App,
) -> Option<impl IntoElement> { ) -> Option<impl IntoElement + use<>> {
let context = &context_editor.read(cx).context; let context = &context_editor.read(cx).context;
let (token_count_color, token_count, max_token_count, tooltip) = match token_state(context, cx)? let (token_count_color, token_count, max_token_count, tooltip) = match token_state(context, cx)?

View File

@@ -299,13 +299,12 @@ impl ContextStore {
} }
if is_shared { if is_shared {
self.contexts.retain_mut(|context| { self.contexts.retain_mut(|context| match context.upgrade() {
if let Some(strong_context) = context.upgrade() { Some(strong_context) => {
*context = ContextHandle::Strong(strong_context); *context = ContextHandle::Strong(strong_context);
true true
} else {
false
} }
_ => false,
}); });
let remote_id = self.project.read(cx).remote_id().unwrap(); let remote_id = self.project.read(cx).remote_id().unwrap();
self.client_subscription = self self.client_subscription = self
@@ -336,8 +335,8 @@ impl ContextStore {
self.synchronize_contexts(cx); self.synchronize_contexts(cx);
} }
project::Event::DisconnectedFromHost => { project::Event::DisconnectedFromHost => {
self.contexts.retain_mut(|context| { self.contexts.retain_mut(|context| match context.upgrade() {
if let Some(strong_context) = context.upgrade() { Some(strong_context) => {
*context = ContextHandle::Weak(context.downgrade()); *context = ContextHandle::Weak(context.downgrade());
strong_context.update(cx, |context, cx| { strong_context.update(cx, |context, cx| {
if context.replica_id() != ReplicaId::default() { if context.replica_id() != ReplicaId::default() {
@@ -345,9 +344,8 @@ impl ContextStore {
} }
}); });
true true
} else {
false
} }
_ => false,
}); });
self.host_contexts.clear(); self.host_contexts.clear();
cx.notify(); cx.notify();
@@ -422,13 +420,14 @@ impl ContextStore {
.await?; .await?;
context.update(cx, |context, cx| context.apply_ops(operations, cx))?; context.update(cx, |context, cx| context.apply_ops(operations, cx))?;
this.update(cx, |this, cx| { this.update(cx, |this, cx| {
if let Some(existing_context) = this.loaded_context_for_id(&context_id, cx) { match this.loaded_context_for_id(&context_id, cx) {
existing_context Some(existing_context) => existing_context,
} else { _ => {
this.register_context(&context, cx); this.register_context(&context, cx);
this.synchronize_contexts(cx); this.synchronize_contexts(cx);
context context
} }
}
}) })
}) })
} }
@@ -471,12 +470,13 @@ impl ContextStore {
) )
})?; })?;
this.update(cx, |this, cx| { this.update(cx, |this, cx| {
if let Some(existing_context) = this.loaded_context_for_path(&path, cx) { match this.loaded_context_for_path(&path, cx) {
existing_context Some(existing_context) => existing_context,
} else { _ => {
this.register_context(&context, cx); this.register_context(&context, cx);
context context
} }
}
}) })
}) })
} }
@@ -591,13 +591,14 @@ impl ContextStore {
.await?; .await?;
context.update(cx, |context, cx| context.apply_ops(operations, cx))?; context.update(cx, |context, cx| context.apply_ops(operations, cx))?;
this.update(cx, |this, cx| { this.update(cx, |this, cx| {
if let Some(existing_context) = this.loaded_context_for_id(&context_id, cx) { match this.loaded_context_for_id(&context_id, cx) {
existing_context Some(existing_context) => existing_context,
} else { _ => {
this.register_context(&context, cx); this.register_context(&context, cx);
this.synchronize_contexts(cx); this.synchronize_contexts(cx);
context context
} }
}
}) })
}) })
} }

View File

@@ -151,7 +151,8 @@ impl SlashCommandCompletionProvider {
let mut flag = self.cancel_flag.lock(); let mut flag = self.cancel_flag.lock();
flag.store(true, SeqCst); flag.store(true, SeqCst);
*flag = new_cancel_flag.clone(); *flag = new_cancel_flag.clone();
if let Some(command) = self.slash_commands.command(command_name, cx) { match self.slash_commands.command(command_name, cx) {
Some(command) => {
let completions = command.complete_argument( let completions = command.complete_argument(
arguments, arguments,
new_cancel_flag.clone(), new_cancel_flag.clone(),
@@ -169,11 +170,8 @@ impl SlashCommandCompletionProvider {
.await? .await?
.into_iter() .into_iter()
.map(|new_argument| { .map(|new_argument| {
let confirm = let confirm = editor.clone().zip(workspace.clone()).map(
editor |(editor, workspace)| {
.clone()
.zip(workspace.clone())
.map(|(editor, workspace)| {
Arc::new({ Arc::new({
let mut completed_arguments = arguments.clone(); let mut completed_arguments = arguments.clone();
if new_argument.replace_previous_arguments { if new_argument.replace_previous_arguments {
@@ -210,7 +208,8 @@ impl SlashCommandCompletionProvider {
} }
} }
}) as Arc<_> }) as Arc<_>
}); },
);
let mut new_text = new_argument.new_text.clone(); let mut new_text = new_argument.new_text.clone();
if new_argument.after_completion == AfterCompletion::Continue { if new_argument.after_completion == AfterCompletion::Continue {
@@ -234,8 +233,8 @@ impl SlashCommandCompletionProvider {
.collect(), .collect(),
)) ))
}) })
} else { }
Task::ready(Ok(Some(Vec::new()))) _ => Task::ready(Ok(Some(Vec::new()))),
} }
} }
} }
@@ -333,10 +332,9 @@ impl CompletionProvider for SlashCommandCompletionProvider {
let position = position.to_point(buffer); let position = position.to_point(buffer);
let line_start = Point::new(position.row, 0); let line_start = Point::new(position.row, 0);
let mut lines = buffer.text_for_range(line_start..position).lines(); let mut lines = buffer.text_for_range(line_start..position).lines();
if let Some(line) = lines.next() { match lines.next() {
SlashCommandLine::parse(line).is_some() Some(line) => SlashCommandLine::parse(line).is_some(),
} else { _ => false,
false
} }
} }

View File

@@ -105,8 +105,8 @@ impl JsonSchema for AssistantSettingsContent {
VersionedAssistantSettingsContent::schema_name() VersionedAssistantSettingsContent::schema_name()
} }
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> Schema { fn json_schema(r#gen: &mut schemars::r#gen::SchemaGenerator) -> Schema {
VersionedAssistantSettingsContent::json_schema(gen) VersionedAssistantSettingsContent::json_schema(r#gen)
} }
fn is_referenceable() -> bool { fn is_referenceable() -> bool {
@@ -416,7 +416,7 @@ pub struct LanguageModelSelection {
pub model: String, pub model: String,
} }
fn providers_schema(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema { fn providers_schema(_: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema {
schemars::schema::SchemaObject { schemars::schema::SchemaObject {
enum_values: Some(vec![ enum_values: Some(vec![
"anthropic".into(), "anthropic".into(),

View File

@@ -88,8 +88,8 @@ impl SlashCommand for ContextServerSlashCommand {
let server_id = self.server_id.clone(); let server_id = self.server_id.clone();
let prompt_name = self.prompt.name.clone(); let prompt_name = self.prompt.name.clone();
if let Some(server) = self.server_manager.read(cx).get_server(&server_id) { match self.server_manager.read(cx).get_server(&server_id) {
cx.foreground_executor().spawn(async move { Some(server) => cx.foreground_executor().spawn(async move {
let Some(protocol) = server.client() else { let Some(protocol) = server.client() else {
return Err(anyhow!("Context server not initialized")); return Err(anyhow!("Context server not initialized"));
}; };
@@ -118,9 +118,8 @@ impl SlashCommand for ContextServerSlashCommand {
}) })
.collect(); .collect();
Ok(completions) Ok(completions)
}) }),
} else { _ => Task::ready(Err(anyhow!("Context server not found"))),
Task::ready(Err(anyhow!("Context server not found")))
} }
} }
@@ -143,7 +142,8 @@ impl SlashCommand for ContextServerSlashCommand {
}; };
let manager = self.server_manager.read(cx); let manager = self.server_manager.read(cx);
if let Some(server) = manager.get_server(&server_id) { match manager.get_server(&server_id) {
Some(server) => {
cx.foreground_executor().spawn(async move { cx.foreground_executor().spawn(async move {
let Some(protocol) = server.client() else { let Some(protocol) = server.client() else {
return Err(anyhow!("Context server not initialized")); return Err(anyhow!("Context server not initialized"));
@@ -191,8 +191,8 @@ impl SlashCommand for ContextServerSlashCommand {
} }
.to_event_stream()) .to_event_stream())
}) })
} else { }
Task::ready(Err(anyhow!("Context server not found"))) _ => Task::ready(Err(anyhow!("Context server not found"))),
} }
} }
} }

View File

@@ -229,19 +229,20 @@ fn collect_diagnostics(
options: Options, options: Options,
cx: &mut App, cx: &mut App,
) -> Task<Result<Option<SlashCommandOutput>>> { ) -> Task<Result<Option<SlashCommandOutput>>> {
let error_source = if let Some(path_matcher) = &options.path_matcher { let error_source = match &options.path_matcher {
Some(path_matcher) => {
debug_assert_eq!(path_matcher.sources().len(), 1); debug_assert_eq!(path_matcher.sources().len(), 1);
Some(path_matcher.sources().first().cloned().unwrap_or_default()) Some(path_matcher.sources().first().cloned().unwrap_or_default())
} else { }
None _ => None,
}; };
let glob_is_exact_file_match = if let Some(path) = options let glob_is_exact_file_match = match options
.path_matcher .path_matcher
.as_ref() .as_ref()
.and_then(|pm| pm.sources().first()) .and_then(|pm| pm.sources().first())
{ {
PathBuf::try_from(path) Some(path) => PathBuf::try_from(path)
.ok() .ok()
.and_then(|path| { .and_then(|path| {
project.read(cx).worktrees(cx).find_map(|worktree| { project.read(cx).worktrees(cx).find_map(|worktree| {
@@ -251,9 +252,8 @@ fn collect_diagnostics(
worktree.absolutize(&relative_path).ok() worktree.absolutize(&relative_path).ok()
}) })
}) })
.is_some() .is_some(),
} else { _ => false,
false
}; };
let project_handle = project.downgrade(); let project_handle = project.downgrade();

View File

@@ -221,7 +221,7 @@ fn collect_files(
project: Entity<Project>, project: Entity<Project>,
glob_inputs: &[String], glob_inputs: &[String],
cx: &mut App, cx: &mut App,
) -> impl Stream<Item = Result<SlashCommandEvent>> { ) -> impl Stream<Item = Result<SlashCommandEvent>> + use<> {
let Ok(matchers) = glob_inputs let Ok(matchers) = glob_inputs
.into_iter() .into_iter()
.map(|glob_input| { .map(|glob_input| {
@@ -285,7 +285,8 @@ fn collect_files(
if entry.is_dir() { if entry.is_dir() {
// Auto-fold directories that contain no files // Auto-fold directories that contain no files
let mut child_entries = snapshot.child_entries(&entry.path); let mut child_entries = snapshot.child_entries(&entry.path);
if let Some(child) = child_entries.next() { match child_entries.next() {
Some(child) => {
if child_entries.next().is_none() && child.kind.is_dir() { if child_entries.next().is_none() && child.kind.is_dir() {
if is_top_level_directory { if is_top_level_directory {
is_top_level_directory = false; is_top_level_directory = false;
@@ -297,11 +298,13 @@ fn collect_files(
} }
continue; continue;
} }
} else { }
_ => {
// Skip empty directories // Skip empty directories
folded_directory_names_stack.clear(); folded_directory_names_stack.clear();
continue; continue;
} }
}
let prefix_paths = folded_directory_names_stack.drain(..).as_slice().join("/"); let prefix_paths = folded_directory_names_stack.drain(..).as_slice().join("/");
if prefix_paths.is_empty() { if prefix_paths.is_empty() {
let label = if is_top_level_directory { let label = if is_top_level_directory {

View File

@@ -218,12 +218,9 @@ async fn project_symbols(
for symbol in symbols for symbol in symbols
.iter() .iter()
.filter(|symbol| { .filter(|symbol| match &regex {
if let Some(regex) = &regex { Some(regex) => regex.is_match(&symbol.name),
regex.is_match(&symbol.name) _ => true,
} else {
true
}
}) })
.skip(offset as usize) .skip(offset as usize)
// Take 1 more than RESULTS_PER_PAGE so we can tell if there are more results. // Take 1 more than RESULTS_PER_PAGE so we can tell if there are more results.
@@ -316,13 +313,12 @@ async fn render_outline(
.collect(); .collect();
let lang_name = lang.name(); let lang_name = lang.name();
if let Some(lsp_adapter) = registry.lsp_adapters(&lang_name).first().cloned() { match registry.lsp_adapters(&lang_name).first().cloned() {
lsp_adapter Some(lsp_adapter) => lsp_adapter
.labels_for_symbols(&entries_for_labels, lang) .labels_for_symbols(&entries_for_labels, lang)
.await .await
.ok() .ok(),
} else { _ => None,
None
} }
} }
None => None, None => None,

View File

@@ -63,16 +63,16 @@ impl Tool for DiagnosticsTool {
} }
fn ui_text(&self, input: &serde_json::Value) -> String { fn ui_text(&self, input: &serde_json::Value) -> String {
if let Some(path) = serde_json::from_value::<DiagnosticsToolInput>(input.clone()) match serde_json::from_value::<DiagnosticsToolInput>(input.clone())
.ok() .ok()
.and_then(|input| match input.path { .and_then(|input| match input.path {
Some(path) if !path.is_empty() => Some(MarkdownString::inline_code(&path)), Some(path) if !path.is_empty() => Some(MarkdownString::inline_code(&path)),
_ => None, _ => None,
}) }) {
{ Some(path) => {
format!("Check diagnostics for {path}") format!("Check diagnostics for {path}")
} else { }
"Check project diagnostics".to_string() _ => "Check project diagnostics".to_string(),
} }
} }

View File

@@ -188,7 +188,7 @@ impl Tool for FindReplaceFileTool {
}) })
.await; .await;
if let Some(diff) = result { match result { Some(diff) => {
let edit_ids = buffer.update(cx, |buffer, cx| { let edit_ids = buffer.update(cx, |buffer, cx| {
buffer.finalize_last_transaction(); buffer.finalize_last_transaction();
buffer.apply_diff(diff, false, cx); buffer.apply_diff(diff, false, cx);
@@ -205,7 +205,7 @@ impl Tool for FindReplaceFileTool {
})?.await?; })?.await?;
Ok(format!("Edited {}", input.path.display())) Ok(format!("Edited {}", input.path.display()))
} else { } _ => {
let err = buffer.read_with(cx, |buffer, _cx| { let err = buffer.read_with(cx, |buffer, _cx| {
let file_exists = buffer let file_exists = buffer
.file() .file()
@@ -224,7 +224,7 @@ impl Tool for FindReplaceFileTool {
})?; })?;
Err(err) Err(err)
} }}
}) })
} }
} }

View File

@@ -35,7 +35,7 @@ impl SoundRegistry {
cx.set_global(GlobalSoundRegistry(SoundRegistry::new(source))); cx.set_global(GlobalSoundRegistry(SoundRegistry::new(source)));
} }
pub fn get(&self, name: &str) -> Result<impl Source<Item = f32>> { pub fn get(&self, name: &str) -> Result<impl Source<Item = f32> + use<>> {
if let Some(wav) = self.cache.lock().get(name) { if let Some(wav) = self.cache.lock().get(name) {
return Ok(wav.clone()); return Ok(wav.clone());
} }

View File

@@ -201,9 +201,11 @@ pub fn check(_: &Check, window: &mut Window, cx: &mut App) {
return; return;
} }
if let Some(updater) = AutoUpdater::get(cx) { match AutoUpdater::get(cx) {
Some(updater) => {
updater.update(cx, |updater, cx| updater.poll(cx)); updater.update(cx, |updater, cx| updater.poll(cx));
} else { }
_ => {
drop(window.prompt( drop(window.prompt(
gpui::PromptLevel::Info, gpui::PromptLevel::Info,
"Could not check for updates", "Could not check for updates",
@@ -212,6 +214,7 @@ pub fn check(_: &Check, window: &mut Window, cx: &mut App) {
cx, cx,
)); ));
} }
}
} }
pub fn view_release_notes(_: &ViewReleaseNotes, cx: &mut App) -> Option<()> { pub fn view_release_notes(_: &ViewReleaseNotes, cx: &mut App) -> Option<()> {

View File

@@ -110,8 +110,8 @@ impl Render for Breadcrumbs {
} }
} }
}) })
.tooltip(move |window, cx| { .tooltip(move |window, cx| match editor.upgrade() {
if let Some(editor) = editor.upgrade() { Some(editor) => {
let focus_handle = editor.read(cx).focus_handle(cx); let focus_handle = editor.read(cx).focus_handle(cx);
Tooltip::for_action_in( Tooltip::for_action_in(
"Show Symbol Outline", "Show Symbol Outline",
@@ -120,14 +120,13 @@ impl Render for Breadcrumbs {
window, window,
cx, cx,
) )
} else { }
Tooltip::for_action( _ => Tooltip::for_action(
"Show Symbol Outline", "Show Symbol Outline",
&zed_actions::outline::ToggleOutline, &zed_actions::outline::ToggleOutline,
window, window,
cx, cx,
) ),
}
}), }),
), ),
None => element None => element

View File

@@ -608,7 +608,8 @@ fn compute_hunks(
) -> SumTree<InternalDiffHunk> { ) -> SumTree<InternalDiffHunk> {
let mut tree = SumTree::new(&buffer); let mut tree = SumTree::new(&buffer);
if let Some((diff_base, diff_base_rope)) = diff_base { match diff_base {
Some((diff_base, diff_base_rope)) => {
let buffer_text = buffer.as_rope().to_string(); let buffer_text = buffer.as_rope().to_string();
let mut options = GitOptions::default(); let mut options = GitOptions::default();
@@ -649,7 +650,8 @@ fn compute_hunks(
tree.push(hunk, &buffer); tree.push(hunk, &buffer);
} }
} }
} else { }
_ => {
tree.push( tree.push(
InternalDiffHunk { InternalDiffHunk {
buffer_range: Anchor::MIN..Anchor::MAX, buffer_range: Anchor::MIN..Anchor::MAX,
@@ -658,6 +660,7 @@ fn compute_hunks(
&buffer, &buffer,
); );
} }
}
tree tree
} }
@@ -776,7 +779,7 @@ impl BufferDiff {
language: Option<Arc<Language>>, language: Option<Arc<Language>>,
language_registry: Option<Arc<LanguageRegistry>>, language_registry: Option<Arc<LanguageRegistry>>,
cx: &mut App, cx: &mut App,
) -> impl Future<Output = BufferDiffInner> { ) -> impl Future<Output = BufferDiffInner> + use<> {
let base_text_pair; let base_text_pair;
let base_text_exists; let base_text_exists;
let base_text_snapshot; let base_text_snapshot;
@@ -818,7 +821,7 @@ impl BufferDiff {
base_text: Option<Arc<String>>, base_text: Option<Arc<String>>,
base_text_snapshot: language::BufferSnapshot, base_text_snapshot: language::BufferSnapshot,
cx: &App, cx: &App,
) -> impl Future<Output = BufferDiffInner> { ) -> impl Future<Output = BufferDiffInner> + use<> {
let base_text_exists = base_text.is_some(); let base_text_exists = base_text.is_some();
let base_text_pair = base_text.map(|text| (text, base_text_snapshot.as_rope().clone())); let base_text_pair = base_text.map(|text| (text, base_text_snapshot.as_rope().clone()));
cx.background_spawn(async move { cx.background_spawn(async move {
@@ -2071,7 +2074,7 @@ mod tests {
) )
}); });
let working_copy = working_copy.read_with(cx, |working_copy, _| working_copy.snapshot()); let working_copy = working_copy.read_with(cx, |working_copy, _| working_copy.snapshot());
let mut index_text = if rng.gen() { let mut index_text = if rng.r#gen() {
Rope::from(head_text.as_str()) Rope::from(head_text.as_str())
} else { } else {
working_copy.as_rope().clone() working_copy.as_rope().clone()

View File

@@ -179,23 +179,21 @@ impl ActiveCall {
return Task::ready(Ok(())); return Task::ready(Ok(()));
} }
let room = if let Some(room) = self.room().cloned() { let room = match self.room().cloned() {
Some(Task::ready(Ok(room)).shared()) Some(room) => Some(Task::ready(Ok(room)).shared()),
} else { _ => self.pending_room_creation.clone(),
self.pending_room_creation.clone()
}; };
let invite = if let Some(room) = room { let invite = match room {
cx.spawn(async move |_, cx| { Some(room) => cx.spawn(async move |_, cx| {
let room = room.await.map_err(|err| anyhow!("{:?}", err))?; let room = room.await.map_err(|err| anyhow!("{:?}", err))?;
let initial_project_id = if let Some(initial_project) = initial_project { let initial_project_id = match initial_project {
Some( Some(initial_project) => Some(
room.update(cx, |room, cx| room.share_project(initial_project, cx))? room.update(cx, |room, cx| room.share_project(initial_project, cx))?
.await?, .await?,
) ),
} else { _ => None,
None
}; };
room.update(cx, move |room, cx| { room.update(cx, move |room, cx| {
@@ -204,8 +202,8 @@ impl ActiveCall {
.await?; .await?;
anyhow::Ok(()) anyhow::Ok(())
}) }),
} else { _ => {
let client = self.client.clone(); let client = self.client.clone();
let user_store = self.user_store.clone(); let user_store = self.user_store.clone();
let room = cx let room = cx
@@ -239,6 +237,7 @@ impl ActiveCall {
room.await.map_err(|err| anyhow!("{:?}", err))?; room.await.map_err(|err| anyhow!("{:?}", err))?;
anyhow::Ok(()) anyhow::Ok(())
}) })
}
}; };
cx.spawn(async move |this, cx| { cx.spawn(async move |this, cx| {
@@ -292,10 +291,11 @@ impl ActiveCall {
return Task::ready(Err(anyhow!("cannot join while on another call"))); return Task::ready(Err(anyhow!("cannot join while on another call")));
} }
let call = if let Some(call) = self.incoming_call.0.borrow_mut().take() { let call = match self.incoming_call.0.borrow_mut().take() {
call Some(call) => call,
} else { _ => {
return Task::ready(Err(anyhow!("no incoming call"))); return Task::ready(Err(anyhow!("no incoming call")));
}
}; };
if self.pending_room_creation.is_some() { if self.pending_room_creation.is_some() {
@@ -373,11 +373,12 @@ impl ActiveCall {
Audio::end_call(cx); Audio::end_call(cx);
let channel_id = self.channel_id(cx); let channel_id = self.channel_id(cx);
if let Some((room, _)) = self.room.take() { match self.room.take() {
Some((room, _)) => {
cx.emit(Event::RoomLeft { channel_id }); cx.emit(Event::RoomLeft { channel_id });
room.update(cx, |room, cx| room.leave(cx)) room.update(cx, |room, cx| room.leave(cx))
} else { }
Task::ready(Ok(())) _ => Task::ready(Ok(())),
} }
} }
@@ -386,11 +387,12 @@ impl ActiveCall {
project: Entity<Project>, project: Entity<Project>,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> Task<Result<u64>> { ) -> Task<Result<u64>> {
if let Some((room, _)) = self.room.as_ref() { match self.room.as_ref() {
Some((room, _)) => {
self.report_call_event("Project Shared", cx); self.report_call_event("Project Shared", cx);
room.update(cx, |room, cx| room.share_project(project, cx)) room.update(cx, |room, cx| room.share_project(project, cx))
} else { }
Task::ready(Err(anyhow!("no active call"))) _ => Task::ready(Err(anyhow!("no active call"))),
} }
} }
@@ -399,11 +401,12 @@ impl ActiveCall {
project: Entity<Project>, project: Entity<Project>,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> Result<()> { ) -> Result<()> {
if let Some((room, _)) = self.room.as_ref() { match self.room.as_ref() {
Some((room, _)) => {
self.report_call_event("Project Unshared", cx); self.report_call_event("Project Unshared", cx);
room.update(cx, |room, cx| room.unshare_project(project, cx)) room.update(cx, |room, cx| room.unshare_project(project, cx))
} else { }
Err(anyhow!("no active call")) _ => Err(anyhow!("no active call")),
} }
} }
@@ -430,7 +433,8 @@ impl ActiveCall {
Task::ready(Ok(())) Task::ready(Ok(()))
} else { } else {
cx.notify(); cx.notify();
if let Some(room) = room { match room {
Some(room) => {
if room.read(cx).status().is_offline() { if room.read(cx).status().is_offline() {
self.room = None; self.room = None;
Task::ready(Ok(())) Task::ready(Ok(()))
@@ -454,12 +458,14 @@ impl ActiveCall {
cx.emit(Event::RoomJoined { channel_id }); cx.emit(Event::RoomJoined { channel_id });
room.update(cx, |room, cx| room.set_location(location.as_ref(), cx)) room.update(cx, |room, cx| room.set_location(location.as_ref(), cx))
} }
} else { }
_ => {
self.room = None; self.room = None;
Task::ready(Ok(())) Task::ready(Ok(()))
} }
} }
} }
}
pub fn room(&self) -> Option<&Entity<Room>> { pub fn room(&self) -> Option<&Entity<Room>> {
self.room.as_ref().map(|(room, _)| room) self.room.as_ref().map(|(room, _)| room)

View File

@@ -96,10 +96,11 @@ impl Room {
} }
pub fn is_connected(&self, _: &App) -> bool { pub fn is_connected(&self, _: &App) -> bool {
if let Some(live_kit) = self.live_kit.as_ref() { match self.live_kit.as_ref() {
Some(live_kit) => {
live_kit.room.connection_state() == livekit::ConnectionState::Connected live_kit.room.connection_state() == livekit::ConnectionState::Connected
} else { }
false _ => false,
} }
} }
@@ -181,15 +182,16 @@ impl Room {
room room
})?; })?;
let initial_project_id = if let Some(initial_project) = initial_project { let initial_project_id = match initial_project {
Some(initial_project) => {
let initial_project_id = room let initial_project_id = room
.update(cx, |room, cx| { .update(cx, |room, cx| {
room.share_project(initial_project.clone(), cx) room.share_project(initial_project.clone(), cx)
})? })?
.await?; .await?;
Some(initial_project_id) Some(initial_project_id)
} else { }
None _ => None,
}; };
let did_join = room let did_join = room
@@ -243,7 +245,7 @@ impl Room {
} }
} }
fn app_will_quit(&mut self, cx: &mut Context<Self>) -> impl Future<Output = ()> { fn app_will_quit(&mut self, cx: &mut Context<Self>) -> impl Future<Output = ()> + use<> {
let task = if self.status.is_online() { let task = if self.status.is_online() {
let leave = self.leave_internal(cx); let leave = self.leave_internal(cx);
Some(cx.background_spawn(async move { Some(cx.background_spawn(async move {
@@ -665,7 +667,7 @@ impl Room {
Ok(()) Ok(())
} }
pub fn room_update_completed(&mut self) -> impl Future<Output = ()> { pub fn room_update_completed(&mut self) -> impl Future<Output = ()> + use<> {
let mut done_rx = self.room_update_completed_rx.clone(); let mut done_rx = self.room_update_completed_rx.clone();
async move { async move {
while let Some(result) = done_rx.next().await { while let Some(result) = done_rx.next().await {
@@ -728,13 +730,13 @@ impl Room {
} }
} }
this.joined_projects.retain(|project| { this.joined_projects
if let Some(project) = project.upgrade() { .retain(|project| match project.upgrade() {
Some(project) => {
project.update(cx, |project, cx| project.set_role(role, cx)); project.update(cx, |project, cx| project.set_role(role, cx));
true true
} else {
false
} }
_ => false,
}); });
} }
} else { } else {
@@ -778,19 +780,17 @@ impl Room {
} }
for unshared_project_id in old_projects.difference(&new_projects) { for unshared_project_id in old_projects.difference(&new_projects) {
this.joined_projects.retain(|project| { this.joined_projects
if let Some(project) = project.upgrade() { .retain(|project| match project.upgrade() {
project.update(cx, |project, cx| { Some(project) => project.update(cx, |project, cx| {
if project.remote_id() == Some(*unshared_project_id) { if project.remote_id() == Some(*unshared_project_id) {
project.disconnected_from_host(cx); project.disconnected_from_host(cx);
false false
} else { } else {
true true
} }
}) }),
} else { _ => false,
false
}
}); });
cx.emit(Event::RemoteProjectUnshared { cx.emit(Event::RemoteProjectUnshared {
project_id: *unshared_project_id, project_id: *unshared_project_id,
@@ -800,9 +800,8 @@ impl Room {
let role = participant.role(); let role = participant.role();
let location = ParticipantLocation::from_proto(participant.location) let location = ParticipantLocation::from_proto(participant.location)
.unwrap_or(ParticipantLocation::External); .unwrap_or(ParticipantLocation::External);
if let Some(remote_participant) = match this.remote_participants.get_mut(&participant.user_id) {
this.remote_participants.get_mut(&participant.user_id) Some(remote_participant) => {
{
remote_participant.peer_id = peer_id; remote_participant.peer_id = peer_id;
remote_participant.projects = participant.projects; remote_participant.projects = participant.projects;
remote_participant.participant_index = participant_index; remote_participant.participant_index = participant_index;
@@ -815,7 +814,8 @@ impl Room {
participant_id: peer_id, participant_id: peer_id,
}); });
} }
} else { }
_ => {
this.remote_participants.insert( this.remote_participants.insert(
participant.user_id, participant.user_id,
RemoteParticipant { RemoteParticipant {
@@ -856,6 +856,7 @@ impl Room {
} }
} }
} }
}
this.remote_participants.retain(|user_id, participant| { this.remote_participants.retain(|user_id, participant| {
if this.participant_user_ids.contains(user_id) { if this.participant_user_ids.contains(user_id) {
@@ -1141,12 +1142,10 @@ impl Room {
Project::in_room(id, client, user_store, language_registry, fs, cx.clone()).await?; Project::in_room(id, client, user_store, language_registry, fs, cx.clone()).await?;
this.update(cx, |this, cx| { this.update(cx, |this, cx| {
this.joined_projects.retain(|project| { this.joined_projects
if let Some(project) = project.upgrade() { .retain(|project| match project.upgrade() {
!project.read(cx).is_disconnected(cx) Some(project) => !project.read(cx).is_disconnected(cx),
} else { _ => false,
false
}
}); });
this.joined_projects.insert(project.downgrade()); this.joined_projects.insert(project.downgrade());
})?; })?;
@@ -1309,13 +1308,16 @@ impl Room {
return Task::ready(Err(anyhow!("room is offline"))); return Task::ready(Err(anyhow!("room is offline")));
} }
let (room, publish_id) = if let Some(live_kit) = self.live_kit.as_mut() { let (room, publish_id) = match self.live_kit.as_mut() {
Some(live_kit) => {
let publish_id = post_inc(&mut live_kit.next_publish_id); let publish_id = post_inc(&mut live_kit.next_publish_id);
live_kit.microphone_track = LocalTrack::Pending { publish_id }; live_kit.microphone_track = LocalTrack::Pending { publish_id };
cx.notify(); cx.notify();
(live_kit.room.clone(), publish_id) (live_kit.room.clone(), publish_id)
} else { }
_ => {
return Task::ready(Err(anyhow!("live-kit was not initialized"))); return Task::ready(Err(anyhow!("live-kit was not initialized")));
}
}; };
cx.spawn(async move |this, cx| { cx.spawn(async move |this, cx| {
@@ -1326,13 +1328,11 @@ impl Room {
.as_mut() .as_mut()
.ok_or_else(|| anyhow!("live-kit was not initialized"))?; .ok_or_else(|| anyhow!("live-kit was not initialized"))?;
let canceled = if let LocalTrack::Pending { let canceled = match &live_kit.microphone_track {
LocalTrack::Pending {
publish_id: cur_publish_id, publish_id: cur_publish_id,
} = &live_kit.microphone_track } => *cur_publish_id != publish_id,
{ _ => true,
*cur_publish_id != publish_id
} else {
true
}; };
match publication { match publication {
@@ -1376,13 +1376,16 @@ impl Room {
return Task::ready(Err(anyhow!("screen was already shared"))); return Task::ready(Err(anyhow!("screen was already shared")));
} }
let (participant, publish_id) = if let Some(live_kit) = self.live_kit.as_mut() { let (participant, publish_id) = match self.live_kit.as_mut() {
Some(live_kit) => {
let publish_id = post_inc(&mut live_kit.next_publish_id); let publish_id = post_inc(&mut live_kit.next_publish_id);
live_kit.screen_track = LocalTrack::Pending { publish_id }; live_kit.screen_track = LocalTrack::Pending { publish_id };
cx.notify(); cx.notify();
(live_kit.room.local_participant(), publish_id) (live_kit.room.local_participant(), publish_id)
} else { }
_ => {
return Task::ready(Err(anyhow!("live-kit was not initialized"))); return Task::ready(Err(anyhow!("live-kit was not initialized")));
}
}; };
let sources = cx.screen_capture_sources(); let sources = cx.screen_capture_sources();
@@ -1399,13 +1402,11 @@ impl Room {
.as_mut() .as_mut()
.ok_or_else(|| anyhow!("live-kit was not initialized"))?; .ok_or_else(|| anyhow!("live-kit was not initialized"))?;
let canceled = if let LocalTrack::Pending { let canceled = match &live_kit.screen_track {
LocalTrack::Pending {
publish_id: cur_publish_id, publish_id: cur_publish_id,
} = &live_kit.screen_track } => *cur_publish_id != publish_id,
{ _ => true,
*cur_publish_id != publish_id
} else {
true
}; };
match publication { match publication {

View File

@@ -183,7 +183,7 @@ impl ChannelChat {
let channel_id = self.channel_id; let channel_id = self.channel_id;
let pending_id = ChannelMessageId::Pending(post_inc(&mut self.next_pending_message_id)); let pending_id = ChannelMessageId::Pending(post_inc(&mut self.next_pending_message_id));
let nonce = self.rng.gen(); let nonce = self.rng.r#gen();
self.insert_messages( self.insert_messages(
SumTree::from_item( SumTree::from_item(
ChannelMessage { ChannelMessage {
@@ -257,7 +257,7 @@ impl ChannelChat {
cx, cx,
); );
let nonce: u128 = self.rng.gen(); let nonce: u128 = self.rng.r#gen();
let request = self.rpc.request(proto::UpdateChannelMessage { let request = self.rpc.request(proto::UpdateChannelMessage {
channel_id: self.channel_id.0, channel_id: self.channel_id.0,

View File

@@ -329,17 +329,16 @@ impl ChannelStore {
.request(proto::GetChannelMessagesById { message_ids }), .request(proto::GetChannelMessagesById { message_ids }),
) )
}; };
cx.spawn(async move |this, cx| { cx.spawn(async move |this, cx| match request {
if let Some(request) = request { Some(request) => {
let response = request.await?; let response = request.await?;
let this = this let this = this
.upgrade() .upgrade()
.ok_or_else(|| anyhow!("channel store dropped"))?; .ok_or_else(|| anyhow!("channel store dropped"))?;
let user_store = this.update(cx, |this, _| this.user_store.clone())?; let user_store = this.update(cx, |this, _| this.user_store.clone())?;
ChannelMessage::from_proto_vec(response.messages, &user_store, cx).await ChannelMessage::from_proto_vec(response.messages, &user_store, cx).await
} else {
Ok(Vec::new())
} }
_ => Ok(Vec::new()),
}) })
} }
@@ -465,14 +464,15 @@ impl ChannelStore {
let task = loop { let task = loop {
match get_map(self).entry(channel_id) { match get_map(self).entry(channel_id) {
hash_map::Entry::Occupied(e) => match e.get() { hash_map::Entry::Occupied(e) => match e.get() {
OpenEntityHandle::Open(entity) => { OpenEntityHandle::Open(entity) => match entity.upgrade() {
if let Some(entity) = entity.upgrade() { Some(entity) => {
break Task::ready(Ok(entity)).shared(); break Task::ready(Ok(entity)).shared();
} else { }
_ => {
get_map(self).remove(&channel_id); get_map(self).remove(&channel_id);
continue; continue;
} }
} },
OpenEntityHandle::Loading(task) => { OpenEntityHandle::Loading(task) => {
break task.clone(); break task.clone();
} }
@@ -824,7 +824,10 @@ impl ChannelStore {
}) })
} }
pub fn remove_channel(&self, channel_id: ChannelId) -> impl Future<Output = Result<()>> { pub fn remove_channel(
&self,
channel_id: ChannelId,
) -> impl Future<Output = Result<()>> + use<> {
let client = self.client.clone(); let client = self.client.clone();
async move { async move {
client client

View File

@@ -228,13 +228,16 @@ fn main() -> Result<()> {
paths.push(file.path().to_string_lossy().to_string()); paths.push(file.path().to_string_lossy().to_string());
let (file, _) = file.keep()?; let (file, _) = file.keep()?;
stdin_tmp_file = Some(file); stdin_tmp_file = Some(file);
} else if let Some(file) = anonymous_fd(path) { } else {
match anonymous_fd(path) {
Some(file) => {
let tmp_file = NamedTempFile::new()?; let tmp_file = NamedTempFile::new()?;
paths.push(tmp_file.path().to_string_lossy().to_string()); paths.push(tmp_file.path().to_string_lossy().to_string());
let (tmp_file, _) = tmp_file.keep()?; let (tmp_file, _) = tmp_file.keep()?;
anonymous_fd_tmp_files.push((file, tmp_file)); anonymous_fd_tmp_files.push((file, tmp_file));
} else { }
paths.push(parse_path_with_position(path)?) _ => paths.push(parse_path_with_position(path)?),
}
} }
} }
@@ -775,7 +778,7 @@ mod mac_os {
} }
impl Detect { impl Detect {
pub fn detect(path: Option<&Path>) -> anyhow::Result<impl InstalledApp> { pub fn detect(path: Option<&Path>) -> anyhow::Result<impl InstalledApp + use<>> {
let bundle_path = if let Some(bundle_path) = path { let bundle_path = if let Some(bundle_path) = path {
bundle_path bundle_path
.canonicalize() .canonicalize()

View File

@@ -618,10 +618,9 @@ impl Client {
} }
pub fn peer_id(&self) -> Option<PeerId> { pub fn peer_id(&self) -> Option<PeerId> {
if let Status::Connected { peer_id, .. } = &*self.status().borrow() { match &*self.status().borrow() {
Some(*peer_id) Status::Connected { peer_id, .. } => Some(*peer_id),
} else { _ => None,
None
} }
} }
@@ -1024,7 +1023,7 @@ impl Client {
&self, &self,
http: Arc<HttpClientWithUrl>, http: Arc<HttpClientWithUrl>,
release_channel: Option<ReleaseChannel>, release_channel: Option<ReleaseChannel>,
) -> impl Future<Output = Result<url::Url>> { ) -> impl Future<Output = Result<url::Url>> + use<> {
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
let url_override = self.rpc_url.read().clone(); let url_override = self.rpc_url.read().clone();
@@ -1429,10 +1428,9 @@ impl Client {
} }
fn connection_id(&self) -> Result<ConnectionId> { fn connection_id(&self) -> Result<ConnectionId> {
if let Status::Connected { connection_id, .. } = *self.status().borrow() { match *self.status().borrow() {
Ok(connection_id) Status::Connected { connection_id, .. } => Ok(connection_id),
} else { _ => Err(anyhow!("not connected")),
Err(anyhow!("not connected"))
} }
} }
@@ -1444,7 +1442,7 @@ impl Client {
pub fn request<T: RequestMessage>( pub fn request<T: RequestMessage>(
&self, &self,
request: T, request: T,
) -> impl Future<Output = Result<T::Response>> { ) -> impl Future<Output = Result<T::Response>> + use<T> {
self.request_envelope(request) self.request_envelope(request)
.map_ok(|envelope| envelope.payload) .map_ok(|envelope| envelope.payload)
} }
@@ -1452,7 +1450,8 @@ impl Client {
pub fn request_stream<T: RequestMessage>( pub fn request_stream<T: RequestMessage>(
&self, &self,
request: T, request: T,
) -> impl Future<Output = Result<impl Stream<Item = Result<T::Response>>>> { ) -> impl Future<Output = Result<impl Stream<Item = Result<T::Response>> + use<T>>> + use<T>
{
let client_id = self.id.load(Ordering::SeqCst); let client_id = self.id.load(Ordering::SeqCst);
log::debug!( log::debug!(
"rpc request start. client_id:{}. name:{}", "rpc request start. client_id:{}. name:{}",
@@ -1476,7 +1475,7 @@ impl Client {
pub fn request_envelope<T: RequestMessage>( pub fn request_envelope<T: RequestMessage>(
&self, &self,
request: T, request: T,
) -> impl Future<Output = Result<TypedEnvelope<T::Response>>> { ) -> impl Future<Output = Result<TypedEnvelope<T::Response>>> + use<T> {
let client_id = self.id(); let client_id = self.id();
log::debug!( log::debug!(
"rpc request start. client_id:{}. name:{}", "rpc request start. client_id:{}. name:{}",
@@ -1501,7 +1500,7 @@ impl Client {
&self, &self,
envelope: proto::Envelope, envelope: proto::Envelope,
request_type: &'static str, request_type: &'static str,
) -> impl Future<Output = Result<proto::Envelope>> { ) -> impl Future<Output = Result<proto::Envelope>> + use<> {
let client_id = self.id(); let client_id = self.id();
log::debug!( log::debug!(
"rpc request start. client_id:{}. name:{}", "rpc request start. client_id:{}. name:{}",
@@ -1528,12 +1527,13 @@ impl Client {
let type_name = message.payload_type_name(); let type_name = message.payload_type_name();
let original_sender_id = message.original_sender_id(); let original_sender_id = message.original_sender_id();
if let Some(future) = ProtoMessageHandlerSet::handle_message( match ProtoMessageHandlerSet::handle_message(
&self.handler_set, &self.handler_set,
message, message,
self.clone().into(), self.clone().into(),
cx.clone(), cx.clone(),
) { ) {
Some(future) => {
let client_id = self.id(); let client_id = self.id();
log::debug!( log::debug!(
"rpc message received. client_id:{}, sender_id:{:?}, type:{}", "rpc message received. client_id:{}, sender_id:{:?}, type:{}",
@@ -1561,13 +1561,15 @@ impl Client {
} }
}) })
.detach(); .detach();
} else { }
_ => {
log::info!("unhandled message {}", type_name); log::info!("unhandled message {}", type_name);
self.peer self.peer
.respond_with_unhandled_message(sender_id.into(), request_id, type_name) .respond_with_unhandled_message(sender_id.into(), request_id, type_name)
.log_err(); .log_err();
} }
} }
}
pub fn telemetry(&self) -> &Arc<Telemetry> { pub fn telemetry(&self) -> &Arc<Telemetry> {
&self.telemetry &self.telemetry

View File

@@ -273,7 +273,7 @@ impl Telemetry {
} }
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
fn shutdown_telemetry(self: &Arc<Self>) -> impl Future<Output = ()> { fn shutdown_telemetry(self: &Arc<Self>) -> impl Future<Output = ()> + use<> {
Task::ready(()) Task::ready(())
} }

View File

@@ -171,13 +171,15 @@ impl UserStore {
_maintain_contacts: cx.spawn(async move |this, cx| { _maintain_contacts: cx.spawn(async move |this, cx| {
let _subscriptions = rpc_subscriptions; let _subscriptions = rpc_subscriptions;
while let Some(message) = update_contacts_rx.next().await { while let Some(message) = update_contacts_rx.next().await {
if let Ok(task) = this.update(cx, |this, cx| this.update_contacts(message, cx)) match this.update(cx, |this, cx| this.update_contacts(message, cx)) {
{ Ok(task) => {
task.log_err().await; task.log_err().await;
} else { }
_ => {
break; break;
} }
} }
}
}), }),
_maintain_current_user: cx.spawn(async move |this, cx| { _maintain_current_user: cx.spawn(async move |this, cx| {
let mut status = client.status(); let mut status = client.status();
@@ -191,12 +193,13 @@ impl UserStore {
match status { match status {
Status::Connected { .. } => { Status::Connected { .. } => {
if let Some(user_id) = client.user_id() { if let Some(user_id) = client.user_id() {
let fetch_user = if let Ok(fetch_user) = let fetch_user = match this
this.update(cx, |this, cx| this.get_user(user_id, cx).log_err()) .update(cx, |this, cx| this.get_user(user_id, cx).log_err())
{ {
fetch_user Ok(fetch_user) => fetch_user,
} else { _ => {
break; break;
}
}; };
let fetch_private_user_info = let fetch_private_user_info =
client.request(proto::GetPrivateUserInfo {}).log_err(); client.request(proto::GetPrivateUserInfo {}).log_err();
@@ -581,7 +584,7 @@ impl UserStore {
}) })
} }
pub fn clear_contacts(&self) -> impl Future<Output = ()> { pub fn clear_contacts(&self) -> impl Future<Output = ()> + use<> {
let (tx, mut rx) = postage::barrier::channel(); let (tx, mut rx) = postage::barrier::channel();
self.update_contacts_tx self.update_contacts_tx
.unbounded_send(UpdateContacts::Clear(tx)) .unbounded_send(UpdateContacts::Clear(tx))
@@ -591,7 +594,7 @@ impl UserStore {
} }
} }
pub fn contact_updates_done(&self) -> impl Future<Output = ()> { pub fn contact_updates_done(&self) -> impl Future<Output = ()> + use<> {
let (tx, mut rx) = postage::barrier::channel(); let (tx, mut rx) = postage::barrier::channel();
self.update_contacts_tx self.update_contacts_tx
.unbounded_send(UpdateContacts::Wait(tx)) .unbounded_send(UpdateContacts::Wait(tx))
@@ -703,8 +706,8 @@ impl UserStore {
}; };
let client = self.client.clone(); let client = self.client.clone();
cx.spawn(async move |this, cx| { cx.spawn(async move |this, cx| match client.upgrade() {
if let Some(client) = client.upgrade() { Some(client) => {
let response = client let response = client
.request(proto::AcceptTermsOfService {}) .request(proto::AcceptTermsOfService {})
.await .await
@@ -714,9 +717,8 @@ impl UserStore {
this.set_current_user_accepted_tos_at(Some(response.accepted_tos_at)); this.set_current_user_accepted_tos_at(Some(response.accepted_tos_at));
cx.emit(Event::PrivateUserInfoUpdated); cx.emit(Event::PrivateUserInfoUpdated);
}) })
} else {
Err(anyhow!("client not found"))
} }
_ => Err(anyhow!("client not found")),
}) })
} }
@@ -732,15 +734,14 @@ impl UserStore {
cx: &Context<Self>, cx: &Context<Self>,
) -> Task<Result<Vec<Arc<User>>>> { ) -> Task<Result<Vec<Arc<User>>>> {
let client = self.client.clone(); let client = self.client.clone();
cx.spawn(async move |this, cx| { cx.spawn(async move |this, cx| match client.upgrade() {
if let Some(rpc) = client.upgrade() { Some(rpc) => {
let response = rpc.request(request).await.context("error loading users")?; let response = rpc.request(request).await.context("error loading users")?;
let users = response.users; let users = response.users;
this.update(cx, |this, _| this.insert(users)) this.update(cx, |this, _| this.insert(users))
} else {
Ok(Vec::new())
} }
_ => Ok(Vec::new()),
}) })
} }

View File

@@ -219,14 +219,17 @@ async fn create_access_token(
let mut impersonated_user_id = None; let mut impersonated_user_id = None;
if let Some(impersonate) = params.impersonate { if let Some(impersonate) = params.impersonate {
if user.admin { if user.admin {
if let Some(impersonated_user) = app.db.get_user_by_github_login(&impersonate).await? { match app.db.get_user_by_github_login(&impersonate).await? {
Some(impersonated_user) => {
impersonated_user_id = Some(impersonated_user.id); impersonated_user_id = Some(impersonated_user.id);
} else { }
_ => {
return Err(Error::http( return Err(Error::http(
StatusCode::UNPROCESSABLE_ENTITY, StatusCode::UNPROCESSABLE_ENTITY,
format!("user {impersonate} does not exist"), format!("user {impersonate} does not exist"),
)); ));
} }
}
} else { } else {
return Err(Error::http( return Err(Error::http(
StatusCode::UNAUTHORIZED, StatusCode::UNAUTHORIZED,

View File

@@ -103,8 +103,8 @@ async fn update_billing_preferences(
let max_monthly_llm_usage_spending_in_cents = let max_monthly_llm_usage_spending_in_cents =
body.max_monthly_llm_usage_spending_in_cents.max(0); body.max_monthly_llm_usage_spending_in_cents.max(0);
let billing_preferences = let billing_preferences = match app.db.get_billing_preferences(user.id).await? {
if let Some(_billing_preferences) = app.db.get_billing_preferences(user.id).await? { Some(_billing_preferences) => {
app.db app.db
.update_billing_preferences( .update_billing_preferences(
user.id, user.id,
@@ -115,7 +115,8 @@ async fn update_billing_preferences(
}, },
) )
.await? .await?
} else { }
_ => {
app.db app.db
.create_billing_preferences( .create_billing_preferences(
user.id, user.id,
@@ -124,6 +125,7 @@ async fn update_billing_preferences(
}, },
) )
.await? .await?
}
}; };
SnowflakeRow::new( SnowflakeRow::new(
@@ -624,11 +626,12 @@ async fn handle_customer_event(
return Ok(()); return Ok(());
}; };
if let Some(existing_customer) = app match app
.db .db
.get_billing_customer_by_stripe_customer_id(&customer.id) .get_billing_customer_by_stripe_customer_id(&customer.id)
.await? .await?
{ {
Some(existing_customer) => {
app.db app.db
.update_billing_customer( .update_billing_customer(
existing_customer.id, existing_customer.id,
@@ -639,7 +642,8 @@ async fn handle_customer_event(
}, },
) )
.await?; .await?;
} else { }
_ => {
app.db app.db
.create_billing_customer(&CreateBillingCustomerParams { .create_billing_customer(&CreateBillingCustomerParams {
user_id: user.id, user_id: user.id,
@@ -647,6 +651,7 @@ async fn handle_customer_event(
}) })
.await?; .await?;
} }
}
Ok(()) Ok(())
} }
@@ -689,11 +694,12 @@ async fn handle_customer_subscription_event(
.await?; .await?;
} }
if let Some(existing_subscription) = app match app
.db .db
.get_billing_subscription_by_stripe_subscription_id(&subscription.id) .get_billing_subscription_by_stripe_subscription_id(&subscription.id)
.await? .await?
{ {
Some(existing_subscription) => {
app.db app.db
.update_billing_subscription( .update_billing_subscription(
existing_subscription.id, existing_subscription.id,
@@ -716,7 +722,8 @@ async fn handle_customer_subscription_event(
}, },
) )
.await?; .await?;
} else { }
_ => {
// If the user already has an active billing subscription, ignore the // If the user already has an active billing subscription, ignore the
// event and return an `Ok` to signal that it was processed // event and return an `Ok` to signal that it was processed
// successfully. // successfully.
@@ -756,6 +763,7 @@ async fn handle_customer_subscription_event(
}) })
.await?; .await?;
} }
}
// When the user's subscription changes, we want to refresh their LLM tokens // When the user's subscription changes, we want to refresh their LLM tokens
// to either grant/revoke access. // to either grant/revoke access.

View File

@@ -47,10 +47,15 @@ impl IpsFile {
Some(panic_message) => format!("Panic `{}`", panic_message), Some(panic_message) => format!("Panic `{}`", panic_message),
None => "Crash `Abort trap: 6` (possible panic)".into(), None => "Crash `Abort trap: 6` (possible panic)".into(),
} }
} else if let Some(msg) = &self.body.exception.message {
format!("Exception `{}`", msg)
} else { } else {
match &self.body.exception.message {
Some(msg) => {
format!("Exception `{}`", msg)
}
_ => {
format!("Crash `{}`", self.body.termination.indicator) format!("Crash `{}`", self.body.termination.indicator)
}
}
}; };
if let Some(thread) = self.faulting_thread() { if let Some(thread) = self.faulting_thread() {
if let Some(queue) = thread.queue.as_ref() { if let Some(queue) = thread.queue.as_ref() {
@@ -81,10 +86,13 @@ impl IpsFile {
return None; return None;
} }
Some(format!("{:#}", rustc_demangle::demangle(name))) Some(format!("{:#}", rustc_demangle::demangle(name)))
} else if let Some(image) = self.body.used_images.get(frame.image_index) {
Some(image.name.clone().unwrap_or("<unknown-image>".into()))
} else { } else {
Some("<unknown>".into()) match self.body.used_images.get(frame.image_index) {
Some(image) => {
Some(image.name.clone().unwrap_or("<unknown-image>".into()))
}
_ => Some("<unknown>".into()),
}
} }
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();

View File

@@ -105,10 +105,11 @@ impl Database {
let mut accept_invite_result = None; let mut accept_invite_result = None;
if role.is_none() { if role.is_none() {
if let Some(invitation) = self match self
.pending_invite_for_channel(&channel, user_id, &tx) .pending_invite_for_channel(&channel, user_id, &tx)
.await? .await?
{ {
Some(invitation) => {
// note, this may be a parent channel // note, this may be a parent channel
role = Some(invitation.role); role = Some(invitation.role);
channel_member::Entity::update(channel_member::ActiveModel { channel_member::Entity::update(channel_member::ActiveModel {
@@ -126,7 +127,9 @@ impl Database {
debug_assert!( debug_assert!(
self.channel_role_for_user(&channel, user_id, &tx).await? == role self.channel_role_for_user(&channel, user_id, &tx).await? == role
); );
} else if channel.visibility == ChannelVisibility::Public { }
_ => {
if channel.visibility == ChannelVisibility::Public {
role = Some(ChannelRole::Guest); role = Some(ChannelRole::Guest);
channel_member::Entity::insert(channel_member::ActiveModel { channel_member::Entity::insert(channel_member::ActiveModel {
id: ActiveValue::NotSet, id: ActiveValue::NotSet,
@@ -148,6 +151,8 @@ impl Database {
); );
} }
} }
}
}
if role.is_none() || role == Some(ChannelRole::Banned) { if role.is_none() || role == Some(ChannelRole::Banned) {
Err(ErrorCode::Forbidden.anyhow())? Err(ErrorCode::Forbidden.anyhow())?

View File

@@ -101,15 +101,18 @@ impl Database {
} }
if let Some(wasm_api_version) = version.wasm_api_version.as_ref() { if let Some(wasm_api_version) = version.wasm_api_version.as_ref() {
if let Some(version) = SemanticVersion::from_str(wasm_api_version).log_err() { match SemanticVersion::from_str(wasm_api_version).log_err() {
Some(version) => {
if !constraints.wasm_api_versions.contains(&version) { if !constraints.wasm_api_versions.contains(&version) {
continue; continue;
} }
} else { }
_ => {
continue; continue;
} }
} }
} }
}
max_versions.insert(version.extension_id, (version, extension_version)); max_versions.insert(version.extension_id, (version, extension_version));
} }

View File

@@ -192,10 +192,11 @@ impl Database {
response: Option<bool>, response: Option<bool>,
tx: &DatabaseTransaction, tx: &DatabaseTransaction,
) -> Result<Option<(UserId, proto::Notification)>> { ) -> Result<Option<(UserId, proto::Notification)>> {
if let Some(id) = self match self
.find_notification(recipient_id, notification, tx) .find_notification(recipient_id, notification, tx)
.await? .await?
{ {
Some(id) => {
let row = notification::Entity::update(notification::ActiveModel { let row = notification::Entity::update(notification::ActiveModel {
id: ActiveValue::Unchanged(id), id: ActiveValue::Unchanged(id),
recipient_id: ActiveValue::Unchanged(recipient_id), recipient_id: ActiveValue::Unchanged(recipient_id),
@@ -212,8 +213,8 @@ impl Database {
Ok(model_to_proto(self, row) Ok(model_to_proto(self, row)
.map(|notification| (recipient_id, notification)) .map(|notification| (recipient_id, notification))
.ok()) .ok())
} else { }
Ok(None) _ => Ok(None),
} }
} }

View File

@@ -132,13 +132,15 @@ impl Database {
initial_channel_id: Option<ChannelId>, initial_channel_id: Option<ChannelId>,
tx: &DatabaseTransaction, tx: &DatabaseTransaction,
) -> Result<User> { ) -> Result<User> {
if let Some(existing_user) = self match self
.get_user_by_github_user_id_or_github_login(github_user_id, github_login, tx) .get_user_by_github_user_id_or_github_login(github_user_id, github_login, tx)
.await? .await?
{ {
Some(existing_user) => {
let mut existing_user = existing_user.into_active_model(); let mut existing_user = existing_user.into_active_model();
existing_user.github_login = ActiveValue::set(github_login.into()); existing_user.github_login = ActiveValue::set(github_login.into());
existing_user.github_user_created_at = ActiveValue::set(Some(github_user_created_at)); existing_user.github_user_created_at =
ActiveValue::set(Some(github_user_created_at));
if let Some(github_email) = github_email { if let Some(github_email) = github_email {
existing_user.email_address = ActiveValue::set(Some(github_email.into())); existing_user.email_address = ActiveValue::set(Some(github_email.into()));
@@ -149,7 +151,8 @@ impl Database {
} }
Ok(existing_user.update(tx).await?) Ok(existing_user.update(tx).await?)
} else { }
_ => {
let user = user::Entity::insert(user::ActiveModel { let user = user::Entity::insert(user::ActiveModel {
email_address: ActiveValue::set(github_email.map(|email| email.into())), email_address: ActiveValue::set(github_email.map(|email| email.into())),
name: ActiveValue::set(github_name.map(|name| name.into())), name: ActiveValue::set(github_name.map(|name| name.into())),
@@ -178,6 +181,7 @@ impl Database {
Ok(user) Ok(user)
} }
} }
}
/// Tries to retrieve a user, first by their GitHub user ID, and then by their GitHub login. /// Tries to retrieve a user, first by their GitHub user ID, and then by their GitHub login.
/// ///

View File

@@ -74,7 +74,7 @@ impl TestDb {
let mut rng = StdRng::from_entropy(); let mut rng = StdRng::from_entropy();
let url = format!( let url = format!(
"postgres://postgres@localhost/zed-test-{}", "postgres://postgres@localhost/zed-test-{}",
rng.gen::<u128>() rng.r#gen::<u128>()
); );
let runtime = tokio::runtime::Builder::new_current_thread() let runtime = tokio::runtime::Builder::new_current_thread()
.enable_io() .enable_io()

View File

@@ -101,11 +101,12 @@ async fn test_channel_buffers(db: &Arc<Database>) {
); );
buffer_b.apply_ops(buffer_response_b.operations.into_iter().map(|operation| { buffer_b.apply_ops(buffer_response_b.operations.into_iter().map(|operation| {
let operation = proto::deserialize_operation(operation).unwrap(); let operation = proto::deserialize_operation(operation).unwrap();
if let language::Operation::Buffer(operation) = operation { match operation {
operation language::Operation::Buffer(operation) => operation,
} else { _ => {
unreachable!() unreachable!()
} }
}
})); }));
assert_eq!(buffer_b.text(), "hello, cruel world"); assert_eq!(buffer_b.text(), "hello, cruel world");

View File

@@ -20,7 +20,8 @@ pub fn get_dotenv_vars(current_dir: impl AsRef<Path>) -> Result<Vec<(String, Str
pub fn load_dotenv() -> Result<()> { pub fn load_dotenv() -> Result<()> {
for (key, value) in get_dotenv_vars("./crates/collab")? { for (key, value) in get_dotenv_vars("./crates/collab")? {
std::env::set_var(key, value); // TODO: Audit that the environment access only happens in single-threaded code.
unsafe { std::env::set_var(key, value) };
} }
Ok(()) Ok(())
} }

View File

@@ -26,7 +26,7 @@ impl Executor {
} }
} }
pub fn sleep(&self, duration: Duration) -> impl Future<Output = ()> { pub fn sleep(&self, duration: Duration) -> impl Future<Output = ()> + use<> {
let this = self.clone(); let this = self.clone();
async move { async move {
match this { match this {

View File

@@ -26,7 +26,7 @@ impl TestLlmDb {
let mut rng = StdRng::from_entropy(); let mut rng = StdRng::from_entropy();
let url = format!( let url = format!(
"postgres://postgres@localhost/zed-llm-test-{}", "postgres://postgres@localhost/zed-llm-test-{}",
rng.gen::<u128>() rng.r#gen::<u128>()
); );
let runtime = tokio::runtime::Builder::new_current_thread() let runtime = tokio::runtime::Builder::new_current_thread()
.enable_io() .enable_io()

View File

@@ -716,7 +716,7 @@ impl Server {
system_id: Option<String>, system_id: Option<String>,
send_connection_id: Option<oneshot::Sender<ConnectionId>>, send_connection_id: Option<oneshot::Sender<ConnectionId>>,
executor: Executor, executor: Executor,
) -> impl Future<Output = ()> { ) -> impl Future<Output = ()> + use<> {
let this = self.clone(); let this = self.clone();
let span = info_span!("handle connection", %address, let span = info_span!("handle connection", %address,
connection_id=field::Empty, connection_id=field::Empty,
@@ -810,7 +810,7 @@ impl Server {
_ = foreground_message_handlers.next() => {} _ = foreground_message_handlers.next() => {}
next_message = next_message => { next_message = next_message => {
let (permit, message) = next_message; let (permit, message) = next_message;
if let Some(message) = message { match message { Some(message) => {
let type_name = message.payload_type_name(); let type_name = message.payload_type_name();
// note: we copy all the fields from the parent span so we can query them in the logs. // note: we copy all the fields from the parent span so we can query them in the logs.
// (https://github.com/tokio-rs/tracing/issues/2670). // (https://github.com/tokio-rs/tracing/issues/2670).
@@ -821,7 +821,7 @@ impl Server {
); );
principal.update_span(&span); principal.update_span(&span);
let span_enter = span.enter(); let span_enter = span.enter();
if let Some(handler) = this.handlers.get(&message.payload_type_id()) { match this.handlers.get(&message.payload_type_id()) { Some(handler) => {
let is_background = message.is_background(); let is_background = message.is_background();
let handle_message = (handler)(message, session.clone()); let handle_message = (handler)(message, session.clone());
drop(span_enter); drop(span_enter);
@@ -835,13 +835,13 @@ impl Server {
} else { } else {
foreground_message_handlers.push(handle_message); foreground_message_handlers.push(handle_message);
} }
} else { } _ => {
tracing::error!("no message handler"); tracing::error!("no message handler");
} }}
} else { } _ => {
tracing::info!("connection closed"); tracing::info!("connection closed");
break; break;
} }}
} }
} }
} }
@@ -1313,9 +1313,8 @@ async fn join_room(
.trace_err(); .trace_err();
} }
let live_kit_connection_info = if let Some(live_kit) = session.app_state.livekit_client.as_ref() let live_kit_connection_info = match session.app_state.livekit_client.as_ref() {
{ Some(live_kit) => live_kit
live_kit
.room_token( .room_token(
&joined_room.room.livekit_room, &joined_room.room.livekit_room,
&session.user_id().to_string(), &session.user_id().to_string(),
@@ -1325,9 +1324,8 @@ async fn join_room(
server_url: live_kit.url().into(), server_url: live_kit.url().into(),
token, token,
can_publish: true, can_publish: true,
}) }),
} else { _ => None,
None
}; };
response.send(proto::JoinRoomResponse { response.send(proto::JoinRoomResponse {
@@ -4393,7 +4391,8 @@ async fn leave_room_for_session(session: &Session, connection_id: ConnectionId)
let room; let room;
let channel; let channel;
if let Some(mut left_room) = session.db().await.leave_room(connection_id).await? { match session.db().await.leave_room(connection_id).await? {
Some(mut left_room) => {
contacts_to_update.insert(session.user_id()); contacts_to_update.insert(session.user_id());
for project in left_room.left_projects.values() { for project in left_room.left_projects.values() {
@@ -4408,9 +4407,11 @@ async fn leave_room_for_session(session: &Session, connection_id: ConnectionId)
channel = mem::take(&mut left_room.channel); channel = mem::take(&mut left_room.channel);
room_updated(&room, &session.peer); room_updated(&room, &session.peer);
} else { }
_ => {
return Ok(()); return Ok(());
} }
}
if let Some(channel) = channel { if let Some(channel) = channel {
channel_updated( channel_updated(

View File

@@ -130,9 +130,9 @@ impl StripeBilling {
} }
let mut state = self.state.write().await; let mut state = self.state.write().await;
let meter = if let Some(meter) = state.meters_by_event_name.get(meter_event_name) { let meter = match state.meters_by_event_name.get(meter_event_name) {
meter.clone() Some(meter) => meter.clone(),
} else { _ => {
let meter = StripeMeter::create( let meter = StripeMeter::create(
&self.client, &self.client,
StripeCreateMeterParams { StripeCreateMeterParams {
@@ -146,11 +146,12 @@ impl StripeBilling {
.meters_by_event_name .meters_by_event_name
.insert(meter_event_name.to_string(), meter.clone()); .insert(meter_event_name.to_string(), meter.clone());
meter meter
}
}; };
let price_id = if let Some(price_id) = state.price_ids_by_meter_id.get(&meter.id) { let price_id = match state.price_ids_by_meter_id.get(&meter.id) {
price_id.clone() Some(price_id) => price_id.clone(),
} else { _ => {
let price = stripe::Price::create( let price = stripe::Price::create(
&self.client, &self.client,
stripe::CreatePrice { stripe::CreatePrice {
@@ -198,6 +199,7 @@ impl StripeBilling {
.price_ids_by_meter_id .price_ids_by_meter_id
.insert(meter.id, price.id.clone()); .insert(meter.id, price.id.clone());
price.id price.id
}
}; };
Ok(StripeBillingPrice { Ok(StripeBillingPrice {

View File

@@ -5602,7 +5602,7 @@ async fn test_open_buffer_while_getting_definition_pointing_to_it(
let definitions; let definitions;
let buffer_b2; let buffer_b2;
if rng.gen() { if rng.r#gen() {
definitions = project_b.update(cx_b, |p, cx| p.definition(&buffer_b1, 23, cx)); definitions = project_b.update(cx_b, |p, cx| p.definition(&buffer_b1, 23, cx));
(buffer_b2, _) = project_b (buffer_b2, _) = project_b
.update(cx_b, |p, cx| { .update(cx_b, |p, cx| {

View File

@@ -216,7 +216,8 @@ impl RandomizedTest for ProjectCollaborationTest {
// Open a new project // Open a new project
0..=70 => { 0..=70 => {
// Open a remote project // Open a remote project
if let Some(room) = call.read_with(cx, |call, _| call.room().cloned()) { match call.read_with(cx, |call, _| call.room().cloned()) {
Some(room) => {
let existing_dev_server_project_ids = cx.read(|cx| { let existing_dev_server_project_ids = cx.read(|cx| {
client client
.dev_server_projects() .dev_server_projects()
@@ -229,7 +230,8 @@ impl RandomizedTest for ProjectCollaborationTest {
.values() .values()
.flat_map(|participant| { .flat_map(|participant| {
participant.projects.iter().filter_map(|project| { participant.projects.iter().filter_map(|project| {
if existing_dev_server_project_ids.contains(&project.id) if existing_dev_server_project_ids
.contains(&project.id)
{ {
None None
} else { } else {
@@ -251,12 +253,12 @@ impl RandomizedTest for ProjectCollaborationTest {
}; };
} }
} }
// Open a local project _ => {
else {
let first_root_name = plan.next_root_dir_name(); let first_root_name = plan.next_root_dir_name();
break ClientOperation::OpenLocalProject { first_root_name }; break ClientOperation::OpenLocalProject { first_root_name };
} }
} }
}
// Close a remote project // Close a remote project
71..=80 => { 71..=80 => {
@@ -279,7 +281,7 @@ impl RandomizedTest for ProjectCollaborationTest {
let project_root_name = root_name_for_project(&project, cx); let project_root_name = root_name_for_project(&project, cx);
let mut paths = client.fs().paths(false); let mut paths = client.fs().paths(false);
paths.remove(0); paths.remove(0);
let new_root_path = if paths.is_empty() || rng.gen() { let new_root_path = if paths.is_empty() || rng.r#gen() {
Path::new(path!("/")).join(plan.next_root_dir_name()) Path::new(path!("/")).join(plan.next_root_dir_name())
} else { } else {
paths.choose(rng).unwrap().clone() paths.choose(rng).unwrap().clone()
@@ -309,7 +311,7 @@ impl RandomizedTest for ProjectCollaborationTest {
.choose(rng) .choose(rng)
}); });
let Some(worktree) = worktree else { continue }; let Some(worktree) = worktree else { continue };
let is_dir = rng.gen::<bool>(); let is_dir = rng.r#gen::<bool>();
let mut full_path = let mut full_path =
worktree.read_with(cx, |w, _| PathBuf::from(w.root_name())); worktree.read_with(cx, |w, _| PathBuf::from(w.root_name()));
full_path.push(gen_file_name(rng)); full_path.push(gen_file_name(rng));
@@ -387,7 +389,7 @@ impl RandomizedTest for ProjectCollaborationTest {
language::Bias::Left, language::Bias::Left,
) )
}); });
let detach = rng.gen(); let detach = rng.r#gen();
break ClientOperation::RequestLspDataInBuffer { break ClientOperation::RequestLspDataInBuffer {
project_root_name, project_root_name,
full_path, full_path,
@@ -460,7 +462,7 @@ impl RandomizedTest for ProjectCollaborationTest {
// Create or update a file or directory // Create or update a file or directory
96.. => { 96.. => {
let is_dir = rng.gen::<bool>(); let is_dir = rng.r#gen::<bool>();
let content; let content;
let mut path; let mut path;
let dir_paths = client.fs().directories(false); let dir_paths = client.fs().directories(false);
@@ -1270,11 +1272,13 @@ impl RandomizedTest for ProjectCollaborationTest {
Some((client.user_id().unwrap(), project, cx)) Some((client.user_id().unwrap(), project, cx))
}); });
let (host_user_id, host_project, host_cx) = let (host_user_id, host_project, host_cx) = match host_project {
if let Some((host_user_id, host_project, host_cx)) = host_project { Some((host_user_id, host_project, host_cx)) => {
(host_user_id, host_project, host_cx) (host_user_id, host_project, host_cx)
} else { }
_ => {
continue; continue;
}
}; };
for guest_buffer in guest_buffers { for guest_buffer in guest_buffers {

View File

@@ -175,10 +175,9 @@ impl TestServer {
let clock = Arc::new(FakeSystemClock::new()); let clock = Arc::new(FakeSystemClock::new());
let http = FakeHttpClient::with_404_response(); let http = FakeHttpClient::with_404_response();
let user_id = if let Ok(Some(user)) = self.app_state.db.get_user_by_github_login(name).await let user_id = match self.app_state.db.get_user_by_github_login(name).await {
{ Ok(Some(user)) => user.id,
user.id _ => {
} else {
let github_user_id = self.next_github_user_id; let github_user_id = self.next_github_user_id;
self.next_github_user_id += 1; self.next_github_user_id += 1;
self.app_state self.app_state
@@ -195,6 +194,7 @@ impl TestServer {
.await .await
.expect("creating user failed") .expect("creating user failed")
.user_id .user_id
}
}; };
let client_name = name.to_string(); let client_name = name.to_string();
let mut client = cx.update(|cx| Client::new(clock, http.clone(), cx)); let mut client = cx.update(|cx| Client::new(clock, http.clone(), cx));
@@ -660,7 +660,7 @@ impl TestClient {
pub fn buffers_for_project<'a>( pub fn buffers_for_project<'a>(
&'a self, &'a self,
project: &Entity<Project>, project: &Entity<Project>,
) -> impl DerefMut<Target = HashSet<Entity<language::Buffer>>> + 'a { ) -> impl DerefMut<Target = HashSet<Entity<language::Buffer>>> + 'a + use<'a> {
RefMut::map(self.state.borrow_mut(), |state| { RefMut::map(self.state.borrow_mut(), |state| {
state.buffers.entry(project.clone()).or_default() state.buffers.entry(project.clone()).or_default()
}) })

View File

@@ -556,12 +556,9 @@ impl FollowableItem for ChannelView {
Some(proto::view::Variant::ChannelView( Some(proto::view::Variant::ChannelView(
proto::view::ChannelView { proto::view::ChannelView {
channel_id: channel_buffer.channel_id.0, channel_id: channel_buffer.channel_id.0,
editor: if let Some(proto::view::Variant::Editor(proto)) = editor: match self.editor.read(cx).to_state_proto(window, cx) {
self.editor.read(cx).to_state_proto(window, cx) Some(proto::view::Variant::Editor(proto)) => Some(proto),
{ _ => None,
Some(proto)
} else {
None
}, },
}, },
)) ))

View File

@@ -102,14 +102,11 @@ impl ChatPanel {
0, 0,
gpui::ListAlignment::Bottom, gpui::ListAlignment::Bottom,
px(1000.), px(1000.),
move |ix, window, cx| { move |ix, window, cx| match entity.upgrade() {
if let Some(entity) = entity.upgrade() { Some(entity) => entity.update(cx, |this: &mut Self, cx| {
entity.update(cx, |this: &mut Self, cx| {
this.render_message(ix, window, cx).into_any_element() this.render_message(ix, window, cx).into_any_element()
}) }),
} else { _ => div().into_any(),
div().into_any()
}
}, },
); );
@@ -200,15 +197,14 @@ impl ChatPanel {
cx: AsyncWindowContext, cx: AsyncWindowContext,
) -> Task<Result<Entity<Self>>> { ) -> Task<Result<Entity<Self>>> {
cx.spawn(async move |cx| { cx.spawn(async move |cx| {
let serialized_panel = if let Some(panel) = cx let serialized_panel = match cx
.background_spawn(async move { KEY_VALUE_STORE.read_kvp(CHAT_PANEL_KEY) }) .background_spawn(async move { KEY_VALUE_STORE.read_kvp(CHAT_PANEL_KEY) })
.await .await
.log_err() .log_err()
.flatten() .flatten()
{ {
Some(serde_json::from_str::<SerializedChatPanel>(&panel)?) Some(panel) => Some(serde_json::from_str::<SerializedChatPanel>(&panel)?),
} else { _ => None,
None
}; };
workspace.update_in(cx, |workspace, window, cx| { workspace.update_in(cx, |workspace, window, cx| {
@@ -314,7 +310,7 @@ impl ChatPanel {
message_id: Option<ChannelMessageId>, message_id: Option<ChannelMessageId>,
reply_to_message: &Option<ChannelMessage>, reply_to_message: &Option<ChannelMessage>,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> impl IntoElement { ) -> impl IntoElement + use<> {
let reply_to_message = match reply_to_message { let reply_to_message = match reply_to_message {
None => { None => {
return div().child( return div().child(
@@ -393,7 +389,7 @@ impl ChatPanel {
ix: usize, ix: usize,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> impl IntoElement { ) -> impl IntoElement + use<> {
let active_chat = &self.active_chat.as_ref().unwrap().0; let active_chat = &self.active_chat.as_ref().unwrap().0;
let (message, is_continuation_from_previous, is_admin) = let (message, is_continuation_from_previous, is_admin) =
active_chat.update(cx, |active_chat, cx| { active_chat.update(cx, |active_chat, cx| {
@@ -812,7 +808,8 @@ impl ChatPanel {
.message_editor .message_editor
.update(cx, |editor, cx| editor.take_message(window, cx)); .update(cx, |editor, cx| editor.take_message(window, cx));
if let Some(id) = self.message_editor.read(cx).edit_message_id() { match self.message_editor.read(cx).edit_message_id() {
Some(id) => {
self.message_editor.update(cx, |editor, _| { self.message_editor.update(cx, |editor, _| {
editor.clear_edit_message_id(); editor.clear_edit_message_id();
}); });
@@ -823,12 +820,19 @@ impl ChatPanel {
{ {
task.detach(); task.detach();
} }
} else if let Some(task) = chat }
_ => {
match chat
.update(cx, |chat, cx| chat.send_message(message, cx)) .update(cx, |chat, cx| chat.send_message(message, cx))
.log_err() .log_err()
{ {
Some(task) => {
task.detach(); task.detach();
} }
_ => {}
}
}
}
} }
} }

View File

@@ -244,12 +244,11 @@ impl CollabPanel {
0, 0,
gpui::ListAlignment::Top, gpui::ListAlignment::Top,
px(1000.), px(1000.),
move |ix, window, cx| { move |ix, window, cx| match entity.upgrade() {
if let Some(entity) = entity.upgrade() { Some(entity) => {
entity.update(cx, |this, cx| this.render_list_entry(ix, window, cx)) entity.update(cx, |this, cx| this.render_list_entry(ix, window, cx))
} else {
div().into_any()
} }
_ => div().into_any(),
}, },
); );
@@ -878,7 +877,7 @@ impl CollabPanel {
is_selected: bool, is_selected: bool,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> impl IntoElement { ) -> impl IntoElement + use<> {
let project_name: SharedString = if worktree_root_names.is_empty() { let project_name: SharedString = if worktree_root_names.is_empty() {
"untitled".to_string() "untitled".to_string()
} else { } else {
@@ -919,7 +918,7 @@ impl CollabPanel {
is_selected: bool, is_selected: bool,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> impl IntoElement { ) -> impl IntoElement + use<> {
let id = peer_id.map_or(usize::MAX, |id| id.as_u64() as usize); let id = peer_id.map_or(usize::MAX, |id| id.as_u64() as usize);
ListItem::new(("screen", id)) ListItem::new(("screen", id))
@@ -960,7 +959,7 @@ impl CollabPanel {
is_selected: bool, is_selected: bool,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> impl IntoElement { ) -> impl IntoElement + use<> {
let channel_store = self.channel_store.read(cx); let channel_store = self.channel_store.read(cx);
let has_channel_buffer_changed = channel_store.has_channel_buffer_changed(channel_id); let has_channel_buffer_changed = channel_store.has_channel_buffer_changed(channel_id);
ListItem::new("channel-notes") ListItem::new("channel-notes")
@@ -993,7 +992,7 @@ impl CollabPanel {
is_selected: bool, is_selected: bool,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> impl IntoElement { ) -> impl IntoElement + use<> {
let channel_store = self.channel_store.read(cx); let channel_store = self.channel_store.read(cx);
let has_messages_notification = channel_store.has_new_messages(channel_id); let has_messages_notification = channel_store.has_new_messages(channel_id);
ListItem::new("channel-chat") ListItem::new("channel-chat")
@@ -2278,7 +2277,7 @@ impl CollabPanel {
&self, &self,
editor: &Entity<Editor>, editor: &Entity<Editor>,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> impl IntoElement { ) -> impl IntoElement + use<> {
let settings = ThemeSettings::get_global(cx); let settings = ThemeSettings::get_global(cx);
let text_style = TextStyle { let text_style = TextStyle {
color: if editor.read(cx).read_only(cx) { color: if editor.read(cx).read_only(cx) {
@@ -2312,7 +2311,7 @@ impl CollabPanel {
is_selected: bool, is_selected: bool,
is_collapsed: bool, is_collapsed: bool,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> impl IntoElement { ) -> impl IntoElement + use<> {
let mut channel_link = None; let mut channel_link = None;
let mut channel_tooltip_text = None; let mut channel_tooltip_text = None;
let mut channel_icon = None; let mut channel_icon = None;
@@ -2411,7 +2410,7 @@ impl CollabPanel {
calling: bool, calling: bool,
is_selected: bool, is_selected: bool,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> impl IntoElement { ) -> impl IntoElement + use<> {
let online = contact.online; let online = contact.online;
let busy = contact.busy || calling; let busy = contact.busy || calling;
let github_login = SharedString::from(contact.user.github_login.clone()); let github_login = SharedString::from(contact.user.github_login.clone());
@@ -2492,7 +2491,7 @@ impl CollabPanel {
is_incoming: bool, is_incoming: bool,
is_selected: bool, is_selected: bool,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> impl IntoElement { ) -> impl IntoElement + use<> {
let github_login = SharedString::from(user.github_login.clone()); let github_login = SharedString::from(user.github_login.clone());
let user_id = user.id; let user_id = user.id;
let is_response_pending = self.user_store.read(cx).is_contact_request_pending(user); let is_response_pending = self.user_store.read(cx).is_contact_request_pending(user);
@@ -2605,7 +2604,7 @@ impl CollabPanel {
is_selected: bool, is_selected: bool,
ix: usize, ix: usize,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> impl IntoElement { ) -> impl IntoElement + use<> {
let channel_id = channel.id; let channel_id = channel.id;
let is_active = maybe!({ let is_active = maybe!({
@@ -2803,7 +2802,7 @@ impl CollabPanel {
depth: usize, depth: usize,
_window: &mut Window, _window: &mut Window,
_cx: &mut Context<Self>, _cx: &mut Context<Self>,
) -> impl IntoElement { ) -> impl IntoElement + use<> {
let item = ListItem::new("channel-editor") let item = ListItem::new("channel-editor")
.inset(false) .inset(false)
// Add one level of depth for the disclosure arrow. // Add one level of depth for the disclosure arrow.
@@ -2832,7 +2831,7 @@ fn render_tree_branch(
overdraw: bool, overdraw: bool,
window: &mut Window, window: &mut Window,
cx: &mut App, cx: &mut App,
) -> impl IntoElement { ) -> impl IntoElement + use<> {
let rem_size = window.rem_size(); let rem_size = window.rem_size();
let line_height = window.text_style().line_height_in_pixels(rem_size); let line_height = window.text_style().line_height_in_pixels(rem_size);
let width = rem_size * 1.5; let width = rem_size * 1.5;

View File

@@ -421,20 +421,17 @@ impl PickerDelegate for ChannelModalDelegate {
el.child(IconButton::new("ellipsis", IconName::Ellipsis)) el.child(IconButton::new("ellipsis", IconName::Ellipsis))
}) })
.when(is_me, |el| el.child(Label::new("You").color(Color::Muted))) .when(is_me, |el| el.child(Label::new("You").color(Color::Muted)))
.children( .children(match (&self.context_menu, selected) {
if let (Some((menu, _)), true) = (&self.context_menu, selected) { (Some((menu, _)), true) => Some(
Some(
deferred( deferred(
anchored() anchored()
.anchor(gpui::Corner::TopRight) .anchor(gpui::Corner::TopRight)
.child(menu.clone()), .child(menu.clone()),
) )
.with_priority(1), .with_priority(1),
)
} else {
None
},
), ),
_ => None,
}),
Mode::InviteMembers => match request_status { Mode::InviteMembers => match request_status {
Some(proto::channel_member::Kind::Invitee) => { Some(proto::channel_member::Kind::Invitee) => {
slot.children(Some(Label::new("Invited"))) slot.children(Some(Label::new("Invited")))

View File

@@ -182,15 +182,14 @@ impl NotificationPanel {
cx: AsyncWindowContext, cx: AsyncWindowContext,
) -> Task<Result<Entity<Self>>> { ) -> Task<Result<Entity<Self>>> {
cx.spawn(async move |cx| { cx.spawn(async move |cx| {
let serialized_panel = if let Some(panel) = cx let serialized_panel = match cx
.background_spawn(async move { KEY_VALUE_STORE.read_kvp(NOTIFICATION_PANEL_KEY) }) .background_spawn(async move { KEY_VALUE_STORE.read_kvp(NOTIFICATION_PANEL_KEY) })
.await .await
.log_err() .log_err()
.flatten() .flatten()
{ {
Some(serde_json::from_str::<SerializedNotificationPanel>(&panel)?) Some(panel) => Some(serde_json::from_str::<SerializedNotificationPanel>(&panel)?),
} else { _ => None,
None
}; };
workspace.update_in(cx, |workspace, window, cx| { workspace.update_in(cx, |workspace, window, cx| {
@@ -494,14 +493,15 @@ impl NotificationPanel {
if let Notification::ChannelMessageMention { channel_id, .. } = &notification { if let Notification::ChannelMessageMention { channel_id, .. } = &notification {
if let Some(workspace) = self.workspace.upgrade() { if let Some(workspace) = self.workspace.upgrade() {
return if let Some(panel) = workspace.read(cx).panel::<ChatPanel>(cx) { return match workspace.read(cx).panel::<ChatPanel>(cx) {
Some(panel) => {
let panel = panel.read(cx); let panel = panel.read(cx);
panel.is_scrolled_to_bottom() panel.is_scrolled_to_bottom()
&& panel && panel
.active_chat() .active_chat()
.map_or(false, |chat| chat.read(cx).channel_id.0 == *channel_id) .map_or(false, |chat| chat.read(cx).channel_id.0 == *channel_id)
} else { }
false _ => false,
}; };
} }
} }

View File

@@ -133,10 +133,9 @@ impl CommandPaletteInterceptor {
/// Intercepts the given query from the command palette. /// Intercepts the given query from the command palette.
pub fn intercept(&self, query: &str, cx: &App) -> Vec<CommandInterceptResult> { pub fn intercept(&self, query: &str, cx: &App) -> Vec<CommandInterceptResult> {
if let Some(handler) = self.0.as_ref() { match self.0.as_ref() {
(handler)(query, cx) Some(handler) => (handler)(query, cx),
} else { _ => Vec::new(),
Vec::new()
} }
} }

View File

@@ -158,7 +158,7 @@ pub fn components() -> AllComponents {
let data = COMPONENT_DATA.read(); let data = COMPONENT_DATA.read();
let mut all_components = AllComponents::new(); let mut all_components = AllComponents::new();
for (ref scope, name, description) in &data.components { for (scope, name, description) in &data.components {
let preview = data.previews.get(name).cloned(); let preview = data.previews.get(name).cloned();
let component_name = SharedString::new_static(name); let component_name = SharedString::new_static(name);
let id = ComponentId(name); let id = ComponentId(name);

View File

@@ -244,7 +244,7 @@ impl ComponentPreview {
ix: usize, ix: usize,
entry: &PreviewEntry, entry: &PreviewEntry,
cx: &Context<Self>, cx: &Context<Self>,
) -> impl IntoElement { ) -> impl IntoElement + use<> {
match entry { match entry {
PreviewEntry::Component(component_metadata) => { PreviewEntry::Component(component_metadata) => {
let id = component_metadata.id(); let id = component_metadata.id();
@@ -318,7 +318,7 @@ impl ComponentPreview {
title: SharedString, title: SharedString,
_window: &Window, _window: &Window,
_cx: &App, _cx: &App,
) -> impl IntoElement { ) -> impl IntoElement + use<> {
h_flex() h_flex()
.w_full() .w_full()
.h_10() .h_10()
@@ -332,7 +332,7 @@ impl ComponentPreview {
component: &ComponentMetadata, component: &ComponentMetadata,
window: &mut Window, window: &mut Window,
cx: &mut App, cx: &mut App,
) -> impl IntoElement { ) -> impl IntoElement + use<> {
let name = component.name(); let name = component.name();
let scope = component.scope(); let scope = component.scope();
@@ -379,7 +379,7 @@ impl ComponentPreview {
.into_any_element() .into_any_element()
} }
fn render_all_components(&self) -> impl IntoElement { fn render_all_components(&self) -> impl IntoElement + use<> {
v_flex() v_flex()
.id("component-list") .id("component-list")
.px_8() .px_8()
@@ -397,7 +397,7 @@ impl ComponentPreview {
component_id: &ComponentId, component_id: &ComponentId,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> impl IntoElement { ) -> impl IntoElement + use<> {
let component = self.component_map.get(&component_id); let component = self.component_map.get(&component_id);
if let Some(component) = component { if let Some(component) = component {

View File

@@ -62,10 +62,9 @@ pub struct Client {
pub struct ContextServerId(pub Arc<str>); pub struct ContextServerId(pub Arc<str>);
fn is_null_value<T: Serialize>(value: &T) -> bool { fn is_null_value<T: Serialize>(value: &T) -> bool {
if let Ok(Value::Null) = serde_json::to_value(value) { match serde_json::to_value(value) {
true Ok(Value::Null) => true,
} else { _ => false,
false
} }
} }
@@ -232,12 +231,19 @@ impl Client {
handler(Ok(message.to_string())); handler(Ok(message.to_string()));
} }
} }
} else if let Ok(notification) = serde_json::from_str::<AnyNotification>(&message) { } else {
match serde_json::from_str::<AnyNotification>(&message) {
Ok(notification) => {
let mut notification_handlers = notification_handlers.lock(); let mut notification_handlers = notification_handlers.lock();
if let Some(handler) = notification_handlers.get_mut(notification.method.as_str()) { if let Some(handler) =
notification_handlers.get_mut(notification.method.as_str())
{
handler(notification.params.unwrap_or(Value::Null), cx.clone()); handler(notification.params.unwrap_or(Value::Null), cx.clone());
} }
} }
_ => {}
}
}
} }
smol::future::yield_now().await; smol::future::yield_now().await;

View File

@@ -77,7 +77,8 @@ impl Tool for ContextServerTool {
_action_log: Entity<ActionLog>, _action_log: Entity<ActionLog>,
cx: &mut App, cx: &mut App,
) -> Task<Result<String>> { ) -> Task<Result<String>> {
if let Some(server) = self.server_manager.read(cx).get_server(&self.server_id) { match self.server_manager.read(cx).get_server(&self.server_id) {
Some(server) => {
let tool_name = self.tool.name.clone(); let tool_name = self.tool.name.clone();
let server_clone = server.clone(); let server_clone = server.clone();
let input_clone = input.clone(); let input_clone = input.clone();
@@ -87,10 +88,9 @@ impl Tool for ContextServerTool {
bail!("Context server not initialized"); bail!("Context server not initialized");
}; };
let arguments = if let serde_json::Value::Object(map) = input_clone { let arguments = match input_clone {
Some(map.into_iter().collect()) serde_json::Value::Object(map) => Some(map.into_iter().collect()),
} else { _ => None,
None
}; };
log::trace!( log::trace!(
@@ -116,8 +116,8 @@ impl Tool for ContextServerTool {
} }
Ok(result) Ok(result)
}) })
} else { }
Task::ready(Err(anyhow!("Context server not found"))) _ => Task::ready(Err(anyhow!("Context server not found"))),
} }
} }
} }

View File

@@ -2,7 +2,7 @@ use std::sync::Arc;
use collections::HashMap; use collections::HashMap;
use gpui::App; use gpui::App;
use schemars::gen::SchemaGenerator; use schemars::r#gen::SchemaGenerator;
use schemars::schema::{InstanceType, Schema, SchemaObject}; use schemars::schema::{InstanceType, Schema, SchemaObject};
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};

View File

@@ -348,7 +348,10 @@ impl Copilot {
this this
} }
fn shutdown_language_server(&mut self, _cx: &mut Context<Self>) -> impl Future<Output = ()> { fn shutdown_language_server(
&mut self,
_cx: &mut Context<Self>,
) -> impl Future<Output = ()> + use<> {
let shutdown = match mem::replace(&mut self.server, CopilotServer::Disabled) { let shutdown = match mem::replace(&mut self.server, CopilotServer::Disabled) {
CopilotServer::Running(server) => Some(Box::pin(async move { server.lsp.shutdown() })), CopilotServer::Running(server) => Some(Box::pin(async move { server.lsp.shutdown() })),
_ => None, _ => None,
@@ -553,8 +556,10 @@ impl Copilot {
} }
pub fn sign_in(&mut self, cx: &mut Context<Self>) -> Task<Result<()>> { pub fn sign_in(&mut self, cx: &mut Context<Self>) -> Task<Result<()>> {
if let CopilotServer::Running(server) = &mut self.server { match &mut self.server {
let task = match &server.sign_in_status { CopilotServer::Running(server) => {
let task =
match &server.sign_in_status {
SignInStatus::Authorized { .. } => Task::ready(Ok(())).shared(), SignInStatus::Authorized { .. } => Task::ready(Ok(())).shared(),
SignInStatus::SigningIn { task, .. } => { SignInStatus::SigningIn { task, .. } => {
cx.notify(); cx.notify();
@@ -564,7 +569,8 @@ impl Copilot {
let lsp = server.lsp.clone(); let lsp = server.lsp.clone();
let task = cx let task = cx
.spawn(async move |this, cx| { .spawn(async move |this, cx| {
let sign_in = async { let sign_in =
async {
let sign_in = lsp let sign_in = lsp
.request::<request::SignInInitiate>( .request::<request::SignInInitiate>(
request::SignInInitiateParams {}, request::SignInInitiateParams {},
@@ -629,12 +635,14 @@ impl Copilot {
}; };
cx.background_spawn(task.map_err(|err| anyhow!("{:?}", err))) cx.background_spawn(task.map_err(|err| anyhow!("{:?}", err)))
} else { }
_ => {
// If we're downloading, wait until download is finished // If we're downloading, wait until download is finished
// If we're in a stuck state, display to the user // If we're in a stuck state, display to the user
Task::ready(Err(anyhow!("copilot hasn't started yet"))) Task::ready(Err(anyhow!("copilot hasn't started yet")))
} }
} }
}
pub fn sign_out(&mut self, cx: &mut Context<Self>) -> Task<Result<()>> { pub fn sign_out(&mut self, cx: &mut Context<Self>) -> Task<Result<()>> {
self.update_sign_in_status(request::SignInStatus::NotSignedIn, cx); self.update_sign_in_status(request::SignInStatus::NotSignedIn, cx);
@@ -680,10 +688,9 @@ impl Copilot {
} }
pub fn language_server(&self) -> Option<&Arc<LanguageServer>> { pub fn language_server(&self) -> Option<&Arc<LanguageServer>> {
if let CopilotServer::Running(server) = &self.server { match &self.server {
Some(&server.lsp) CopilotServer::Running(server) => Some(&server.lsp),
} else { _ => None,
None
} }
} }

View File

@@ -1078,7 +1078,7 @@ mod tests {
cx: &mut EditorLspTestContext, cx: &mut EditorLspTestContext,
marked_string: &str, marked_string: &str,
completions: Vec<&'static str>, completions: Vec<&'static str>,
) -> impl Future<Output = ()> { ) -> impl Future<Output = ()> + use<> {
let complete_from_marker: TextRangeMarker = '|'.into(); let complete_from_marker: TextRangeMarker = '|'.into();
let replace_range_marker: TextRangeMarker = ('<', '>').into(); let replace_range_marker: TextRangeMarker = ('<', '>').into();
let (_, mut marked_ranges) = marked_text_ranges_by( let (_, mut marked_ranges) = marked_text_ranges_by(

View File

@@ -139,7 +139,10 @@ impl CopilotCodeVerification {
cx.notify(); cx.notify();
} }
fn render_device_code(data: &PromptUserDeviceFlow, cx: &mut Context<Self>) -> impl IntoElement { fn render_device_code(
data: &PromptUserDeviceFlow,
cx: &mut Context<Self>,
) -> impl IntoElement + use<> {
let copied = cx let copied = cx
.read_from_clipboard() .read_from_clipboard()
.map(|item| item.text().as_ref() == Some(&data.user_code)) .map(|item| item.text().as_ref() == Some(&data.user_code))
@@ -172,7 +175,7 @@ impl CopilotCodeVerification {
data: &PromptUserDeviceFlow, data: &PromptUserDeviceFlow,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> impl Element { ) -> impl Element + use<> {
let connect_button_label = if connect_clicked { let connect_button_label = if connect_clicked {
"Waiting for connection..." "Waiting for connection..."
} else { } else {
@@ -213,7 +216,7 @@ impl CopilotCodeVerification {
) )
} }
fn render_enabled_modal(cx: &mut Context<Self>) -> impl Element { fn render_enabled_modal(cx: &mut Context<Self>) -> impl Element + use<> {
v_flex() v_flex()
.gap_2() .gap_2()
.child(Headline::new("Copilot Enabled!").size(HeadlineSize::Large)) .child(Headline::new("Copilot Enabled!").size(HeadlineSize::Large))
@@ -227,7 +230,7 @@ impl CopilotCodeVerification {
) )
} }
fn render_unauthorized_modal(cx: &mut Context<Self>) -> impl Element { fn render_unauthorized_modal(cx: &mut Context<Self>) -> impl Element + use<> {
v_flex() v_flex()
.child(Headline::new("You must have an active GitHub Copilot subscription.").size(HeadlineSize::Large)) .child(Headline::new("You must have an active GitHub Copilot subscription.").size(HeadlineSize::Large))
@@ -246,7 +249,7 @@ impl CopilotCodeVerification {
) )
} }
fn render_loading(window: &mut Window, _: &mut Context<Self>) -> impl Element { fn render_loading(window: &mut Window, _: &mut Context<Self>) -> impl Element + use<> {
let loading_icon = svg() let loading_icon = svg()
.size_8() .size_8()
.path(IconName::ArrowCircle.path()) .path(IconName::ArrowCircle.path())

View File

@@ -222,13 +222,12 @@ impl TransportDelegate {
} }
pub(crate) async fn send_message(&self, message: Message) -> Result<()> { pub(crate) async fn send_message(&self, message: Message) -> Result<()> {
if let Some(server_tx) = self.server_tx.lock().await.as_ref() { match self.server_tx.lock().await.as_ref() {
server_tx Some(server_tx) => server_tx
.send(message) .send(message)
.await .await
.map_err(|e| anyhow!("Failed to send message: {}", e)) .map_err(|e| anyhow!("Failed to send message: {}", e)),
} else { _ => Err(anyhow!("Server tx already dropped")),
Err(anyhow!("Server tx already dropped"))
} }
} }
@@ -343,12 +342,15 @@ impl TransportDelegate {
match message { match message {
Ok(Message::Response(res)) => { Ok(Message::Response(res)) => {
if let Some(tx) = pending_requests.lock().await.remove(&res.request_seq) { match pending_requests.lock().await.remove(&res.request_seq) {
Some(tx) => {
if let Err(e) = tx.send(Self::process_response(res)) { if let Err(e) = tx.send(Self::process_response(res)) {
log::trace!("Did not send response `{:?}` for a cancelled", e); log::trace!("Did not send response `{:?}` for a cancelled", e);
} }
} else { }
_ => {
client_tx.send(Message::Response(res)).await?; client_tx.send(Message::Response(res)).await?;
}
}; };
} }
Ok(message) => { Ok(message) => {
@@ -816,18 +818,20 @@ impl FakeTransport {
.unwrap(); .unwrap();
writer.flush().await.unwrap(); writer.flush().await.unwrap();
} else { } else {
if let Some(handle) = request_handlers match request_handlers
.lock() .lock()
.await .await
.get_mut(request.command.as_str()) .get_mut(request.command.as_str())
{ {
Some(handle) => {
handle( handle(
request.seq, request.seq,
request.arguments.unwrap_or(json!({})), request.arguments.unwrap_or(json!({})),
stdout_writer.clone(), stdout_writer.clone(),
) )
.await; .await;
} else { }
_ => {
log::error!( log::error!(
"No request handler for {}", "No request handler for {}",
request.command request.command
@@ -835,6 +839,7 @@ impl FakeTransport {
} }
} }
} }
}
Message::Event(event) => { Message::Event(event) => {
let message = let message =
serde_json::to_string(&Message::Event(event)).unwrap(); serde_json::to_string(&Message::Event(event)).unwrap();
@@ -850,14 +855,20 @@ impl FakeTransport {
writer.flush().await.unwrap(); writer.flush().await.unwrap();
} }
Message::Response(response) => { Message::Response(response) => {
if let Some(handle) = response_handlers match response_handlers
.lock() .lock()
.await .await
.get(response.command.as_str()) .get(response.command.as_str())
{ {
Some(handle) => {
handle(response); handle(response);
} else { }
log::error!("No response handler for {}", response.command); _ => {
log::error!(
"No response handler for {}",
response.command
);
}
} }
} }
} }

View File

@@ -94,17 +94,16 @@ impl DebugAdapter for PythonDebugAdapter {
) )
.await; .await;
let python_path = if let Some(toolchain) = toolchain { let python_path = match toolchain {
Some(toolchain.path.to_string()) Some(toolchain) => Some(toolchain.path.to_string()),
} else { _ => BINARY_NAMES
BINARY_NAMES
.iter() .iter()
.filter_map(|cmd| { .filter_map(|cmd| {
delegate delegate
.which(OsStr::new(cmd)) .which(OsStr::new(cmd))
.map(|path| path.to_string_lossy().to_string()) .map(|path| path.to_string_lossy().to_string())
}) })
.find(|_| true) .find(|_| true),
}; };
Ok(DebugAdapterBinary { Ok(DebugAdapterBinary {

View File

@@ -112,7 +112,7 @@ pub async fn open_test_db<M: Migrator>(db_name: &str) -> ThreadSafeConnection<M>
/// Implements a basic DB wrapper for a given domain /// Implements a basic DB wrapper for a given domain
#[macro_export] #[macro_export]
macro_rules! define_connection { macro_rules! define_connection {
(pub static ref $id:ident: $t:ident<()> = $migrations:expr; $($global:ident)?) => { (pub static ref $id:ident: $t:ident<()> = $migrations:expr_2021; $($global:ident)?) => {
pub struct $t($crate::sqlez::thread_safe_connection::ThreadSafeConnection<$t>); pub struct $t($crate::sqlez::thread_safe_connection::ThreadSafeConnection<$t>);
impl ::std::ops::Deref for $t { impl ::std::ops::Deref for $t {
@@ -149,7 +149,7 @@ macro_rules! define_connection {
$t($crate::smol::block_on($crate::open_db(db_dir, scope))) $t($crate::smol::block_on($crate::open_db(db_dir, scope)))
}); });
}; };
(pub static ref $id:ident: $t:ident<$($d:ty),+> = $migrations:expr; $($global:ident)?) => { (pub static ref $id:ident: $t:ident<$($d:ty),+> = $migrations:expr_2021; $($global:ident)?) => {
pub struct $t($crate::sqlez::thread_safe_connection::ThreadSafeConnection<( $($d),+, $t )>); pub struct $t($crate::sqlez::thread_safe_connection::ThreadSafeConnection<( $($d),+, $t )>);
impl ::std::ops::Deref for $t { impl ::std::ops::Deref for $t {

View File

@@ -284,7 +284,7 @@ impl Render for InertState {
} }
impl InertState { impl InertState {
fn render_editor(editor: &Entity<Editor>, cx: &Context<Self>) -> impl IntoElement { fn render_editor(editor: &Entity<Editor>, cx: &Context<Self>) -> impl IntoElement + use<> {
let settings = ThemeSettings::get_global(cx); let settings = ThemeSettings::get_global(cx);
let text_style = TextStyle { let text_style = TextStyle {
color: cx.theme().colors().text, color: cx.theme().colors().text,

View File

@@ -153,7 +153,7 @@ impl Console {
}); });
} }
fn render_console(&self, cx: &Context<Self>) -> impl IntoElement { fn render_console(&self, cx: &Context<Self>) -> impl IntoElement + use<> {
let settings = ThemeSettings::get_global(cx); let settings = ThemeSettings::get_global(cx);
let text_style = TextStyle { let text_style = TextStyle {
color: if self.console.read(cx).read_only(cx) { color: if self.console.read(cx).read_only(cx) {
@@ -180,7 +180,7 @@ impl Console {
) )
} }
fn render_query_bar(&self, cx: &Context<Self>) -> impl IntoElement { fn render_query_bar(&self, cx: &Context<Self>) -> impl IntoElement + use<> {
let settings = ThemeSettings::get_global(cx); let settings = ThemeSettings::get_global(cx);
let text_style = TextStyle { let text_style = TextStyle {
color: if self.console.read(cx).read_only(cx) { color: if self.console.read(cx).read_only(cx) {

View File

@@ -807,14 +807,16 @@ impl VariableList {
) )
.when(!dap.value.is_empty(), |this| { .when(!dap.value.is_empty(), |this| {
this.child(div().w_full().id(variable.item_value_id()).map(|this| { this.child(div().w_full().id(variable.item_value_id()).map(|this| {
if let Some((_, editor)) = self match self
.edited_path .edited_path
.as_ref() .as_ref()
.filter(|(path, _)| path == &variable.path) .filter(|(path, _)| path == &variable.path)
{ {
Some((_, editor)) => {
this.child(div().size_full().px_2().child(editor.clone())) this.child(div().size_full().px_2().child(editor.clone()))
} else { }
this.text_color(cx.theme().colors().text_muted) _ => this
.text_color(cx.theme().colors().text_muted)
.when( .when(
!self.disabled !self.disabled
&& self && self
@@ -853,7 +855,7 @@ impl VariableList {
.when_some(variable_color, |this, color| { .when_some(variable_color, |this, color| {
this.color(Color::from(color)) this.color(Color::from(color))
}), }),
) ),
} }
})) }))
}), }),

View File

@@ -32,12 +32,9 @@ impl StartingState {
let _notify_parent = cx.spawn(async move |this, cx| { let _notify_parent = cx.spawn(async move |this, cx| {
let entity = task.await; let entity = task.await;
this.update(cx, |_, cx| { this.update(cx, |_, cx| match entity {
if let Ok(entity) = entity { Ok(entity) => cx.emit(StartingEvent::Finished(entity)),
cx.emit(StartingEvent::Finished(entity)) _ => cx.emit(StartingEvent::Failed),
} else {
cx.emit(StartingEvent::Failed)
}
}) })
.ok(); .ok();
}); });

View File

@@ -305,12 +305,14 @@ impl ProjectDiagnosticsEditor {
window: &mut Window, window: &mut Window,
cx: &mut Context<Workspace>, cx: &mut Context<Workspace>,
) { ) {
if let Some(existing) = workspace.item_of_type::<ProjectDiagnosticsEditor>(cx) { match workspace.item_of_type::<ProjectDiagnosticsEditor>(cx) {
Some(existing) => {
let is_active = workspace let is_active = workspace
.active_item(cx) .active_item(cx)
.is_some_and(|item| item.item_id() == existing.item_id()); .is_some_and(|item| item.item_id() == existing.item_id());
workspace.activate_item(&existing, true, !is_active, window, cx); workspace.activate_item(&existing, true, !is_active, window, cx);
} else { }
_ => {
let workspace_handle = cx.entity().downgrade(); let workspace_handle = cx.entity().downgrade();
let include_warnings = match cx.try_global::<IncludeWarnings>() { let include_warnings = match cx.try_global::<IncludeWarnings>() {
@@ -330,6 +332,7 @@ impl ProjectDiagnosticsEditor {
workspace.add_item_to_active_pane(Box::new(diagnostics), None, true, window, cx); workspace.add_item_to_active_pane(Box::new(diagnostics), None, true, window, cx);
} }
} }
}
fn toggle_warnings(&mut self, _: &ToggleWarnings, window: &mut Window, cx: &mut Context<Self>) { fn toggle_warnings(&mut self, _: &ToggleWarnings, window: &mut Window, cx: &mut Context<Self>) {
self.include_warnings = !self.include_warnings; self.include_warnings = !self.include_warnings;
@@ -472,7 +475,8 @@ impl ProjectDiagnosticsEditor {
} }
} }
if let Some((language_server_id, group)) = to_insert { match to_insert {
Some((language_server_id, group)) => {
let mut group_state = DiagnosticGroupState { let mut group_state = DiagnosticGroupState {
language_server_id, language_server_id,
primary_diagnostic: group.entries[group.primary_ix].clone(), primary_diagnostic: group.entries[group.primary_ix].clone(),
@@ -483,10 +487,11 @@ impl ProjectDiagnosticsEditor {
}; };
let mut pending_range: Option<(Range<Point>, Range<Point>, usize)> = None; let mut pending_range: Option<(Range<Point>, Range<Point>, usize)> = None;
let mut is_first_excerpt_for_group = true; let mut is_first_excerpt_for_group = true;
for (ix, entry) in group.entries.iter().map(Some).chain([None]).enumerate() { for (ix, entry) in group.entries.iter().map(Some).chain([None]).enumerate()
{
let resolved_entry = entry.map(|e| e.resolve::<Point>(&snapshot)); let resolved_entry = entry.map(|e| e.resolve::<Point>(&snapshot));
let expanded_range = if let Some(entry) = &resolved_entry { let expanded_range = match &resolved_entry {
Some( Some(entry) => Some(
context_range_for_entry( context_range_for_entry(
entry.range.clone(), entry.range.clone(),
context, context,
@@ -494,15 +499,15 @@ impl ProjectDiagnosticsEditor {
(**cx).clone(), (**cx).clone(),
) )
.await, .await,
) ),
} else { _ => None,
None
}; };
if let Some((range, context_range, start_ix)) = &mut pending_range { if let Some((range, context_range, start_ix)) = &mut pending_range {
if let Some(expanded_range) = expanded_range.clone() { if let Some(expanded_range) = expanded_range.clone() {
// If the entries are overlapping or next to each-other, merge them into one excerpt. // If the entries are overlapping or next to each-other, merge them into one excerpt.
if context_range.end.row + 1 >= expanded_range.start.row { if context_range.end.row + 1 >= expanded_range.start.row {
context_range.end = context_range.end.max(expanded_range.end); context_range.end =
context_range.end.max(expanded_range.end);
continue; continue;
} }
} }
@@ -546,7 +551,8 @@ impl ProjectDiagnosticsEditor {
for entry in &group.entries[*start_ix..ix] { for entry in &group.entries[*start_ix..ix] {
let mut diagnostic = entry.diagnostic.clone(); let mut diagnostic = entry.diagnostic.clone();
if diagnostic.is_primary { if diagnostic.is_primary {
group_state.primary_excerpt_ix = group_state.excerpts.len() - 1; group_state.primary_excerpt_ix =
group_state.excerpts.len() - 1;
diagnostic.message = diagnostic.message =
entry.diagnostic.message.split('\n').skip(1).collect(); entry.diagnostic.message.split('\n').skip(1).collect();
} }
@@ -558,9 +564,12 @@ impl ProjectDiagnosticsEditor {
excerpt_id, excerpt_id,
entry.range.start, entry.range.start,
)), )),
height: diagnostic.message.matches('\n').count() as u32 + 1, height: diagnostic.message.matches('\n').count() as u32
+ 1,
style: BlockStyle::Fixed, style: BlockStyle::Fixed,
render: diagnostic_block_renderer(diagnostic, None, true), render: diagnostic_block_renderer(
diagnostic, None, true,
),
priority: 0, priority: 0,
}); });
} }
@@ -581,12 +590,16 @@ impl ProjectDiagnosticsEditor {
.diagnostic_groups .diagnostic_groups
.push(group_state); .push(group_state);
})?; })?;
} else if let Some((_, group_state)) = to_remove { }
_ => match to_remove {
Some((_, group_state)) => {
excerpts.update(cx, |excerpts, cx| { excerpts.update(cx, |excerpts, cx| {
excerpts.remove_excerpts(group_state.excerpts.iter().copied(), cx) excerpts.remove_excerpts(group_state.excerpts.iter().copied(), cx)
})?; })?;
blocks_to_remove.extend(group_state.blocks.iter().copied()); blocks_to_remove.extend(group_state.blocks.iter().copied());
} else if let Some((_, group_state)) = to_keep { }
_ => match to_keep {
Some((_, group_state)) => {
prev_excerpt_id = *group_state.excerpts.last().unwrap(); prev_excerpt_id = *group_state.excerpts.last().unwrap();
first_excerpt_id.get_or_insert(prev_excerpt_id); first_excerpt_id.get_or_insert(prev_excerpt_id);
@@ -596,6 +609,10 @@ impl ProjectDiagnosticsEditor {
.push(group_state) .push(group_state)
})?; })?;
} }
_ => {}
},
},
}
} }
let excerpts_snapshot = excerpts.update(cx, |excerpts, cx| excerpts.snapshot(cx))?; let excerpts_snapshot = excerpts.update(cx, |excerpts, cx| excerpts.snapshot(cx))?;

View File

@@ -62,7 +62,8 @@ impl Render for DiagnosticIndicator {
.child(Label::new(warning_count.to_string()).size(LabelSize::Small)), .child(Label::new(warning_count.to_string()).size(LabelSize::Small)),
}; };
let status = if let Some(diagnostic) = &self.current_diagnostic { let status = match &self.current_diagnostic {
Some(diagnostic) => {
let message = diagnostic.message.split('\n').next().unwrap().to_string(); let message = diagnostic.message.split('\n').next().unwrap().to_string();
Some( Some(
Button::new("diagnostic_message", message) Button::new("diagnostic_message", message)
@@ -80,8 +81,8 @@ impl Render for DiagnosticIndicator {
})) }))
.into_any_element(), .into_any_element(),
) )
} else { }
None _ => None,
}; };
h_flex() h_flex()
@@ -187,15 +188,18 @@ impl StatusItemView for DiagnosticIndicator {
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
if let Some(editor) = active_pane_item.and_then(|item| item.downcast::<Editor>()) { match active_pane_item.and_then(|item| item.downcast::<Editor>()) {
Some(editor) => {
self.active_editor = Some(editor.downgrade()); self.active_editor = Some(editor.downgrade());
self._observe_active_editor = Some(cx.observe_in(&editor, window, Self::update)); self._observe_active_editor = Some(cx.observe_in(&editor, window, Self::update));
self.update(editor, window, cx); self.update(editor, window, cx);
} else { }
_ => {
self.active_editor = None; self.active_editor = None;
self.current_diagnostic = None; self.current_diagnostic = None;
self._observe_active_editor = None; self._observe_active_editor = None;
} }
}
cx.notify(); cx.notify();
} }
} }

View File

@@ -83,11 +83,12 @@ impl ToolbarItemView for ToolbarControls {
_: &mut Context<Self>, _: &mut Context<Self>,
) -> ToolbarItemLocation { ) -> ToolbarItemLocation {
if let Some(pane_item) = active_pane_item.as_ref() { if let Some(pane_item) = active_pane_item.as_ref() {
if let Some(editor) = pane_item.downcast::<ProjectDiagnosticsEditor>() { match pane_item.downcast::<ProjectDiagnosticsEditor>() {
Some(editor) => {
self.editor = Some(editor.downgrade()); self.editor = Some(editor.downgrade());
ToolbarItemLocation::PrimaryRight ToolbarItemLocation::PrimaryRight
} else { }
ToolbarItemLocation::Hidden _ => ToolbarItemLocation::Hidden,
} }
} else { } else {
ToolbarItemLocation::Hidden ToolbarItemLocation::Hidden

View File

@@ -21,11 +21,14 @@ fn main() -> Result<()> {
let preprocessor = let preprocessor =
ZedDocsPreprocessor::new().context("Failed to create ZedDocsPreprocessor")?; ZedDocsPreprocessor::new().context("Failed to create ZedDocsPreprocessor")?;
if let Some(sub_args) = matches.subcommand_matches("supports") { match matches.subcommand_matches("supports") {
Some(sub_args) => {
handle_supports(&preprocessor, sub_args); handle_supports(&preprocessor, sub_args);
} else { }
_ => {
handle_preprocessing(&preprocessor)?; handle_preprocessing(&preprocessor)?;
} }
}
Ok(()) Ok(())
} }

View File

@@ -735,11 +735,11 @@ impl CompletionsMenu {
let completion = &completions[mat.candidate_id]; let completion = &completions[mat.candidate_id];
let sort_key = completion.sort_key(); let sort_key = completion.sort_key();
let sort_text = let sort_text = match &completion.source {
if let CompletionSource::Lsp { lsp_completion, .. } = &completion.source { CompletionSource::Lsp { lsp_completion, .. } => {
lsp_completion.sort_text.as_deref() lsp_completion.sort_text.as_deref()
} else { }
None _ => None,
}; };
let score = Reverse(OrderedFloat(mat.score)); let score = Reverse(OrderedFloat(mat.score));

View File

@@ -49,7 +49,7 @@ impl<'a> CommitAvatar<'a> {
&'a self, &'a self,
window: &mut Window, window: &mut Window,
cx: &mut Context<CommitTooltip>, cx: &mut Context<CommitTooltip>,
) -> Option<impl IntoElement> { ) -> Option<impl IntoElement + use<>> {
let remote = self let remote = self
.commit .commit
.message .message

View File

@@ -226,26 +226,22 @@ impl DisplayMap {
.wrap_map .wrap_map
.update(cx, |map, cx| map.sync(snapshot, edits, cx)); .update(cx, |map, cx| map.sync(snapshot, edits, cx));
let mut block_map = self.block_map.write(snapshot, edits); let mut block_map = self.block_map.write(snapshot, edits);
let blocks = creases.into_iter().filter_map(|crease| { let blocks = creases.into_iter().filter_map(|crease| match crease {
if let Crease::Block { Crease::Block {
range, range,
block_height, block_height,
render_block, render_block,
block_style, block_style,
block_priority, block_priority,
.. ..
} = crease } => Some((
{
Some((
range, range,
render_block, render_block,
block_height, block_height,
block_style, block_style,
block_priority, block_priority,
)) )),
} else { _ => None,
None
}
}); });
block_map.insert( block_map.insert(
blocks blocks
@@ -954,10 +950,9 @@ impl DisplaySnapshot {
for chunk in self.highlighted_chunks(range, false, editor_style) { for chunk in self.highlighted_chunks(range, false, editor_style) {
line.push_str(chunk.text); line.push_str(chunk.text);
let text_style = if let Some(style) = chunk.style { let text_style = match chunk.style {
Cow::Owned(editor_style.text.clone().highlight(style)) Some(style) => Cow::Owned(editor_style.text.clone().highlight(style)),
} else { _ => Cow::Borrowed(&editor_style.text),
Cow::Borrowed(&editor_style.text)
}; };
runs.push(text_style.to_run(chunk.text.len())) runs.push(text_style.to_run(chunk.text.len()))
@@ -1186,11 +1181,11 @@ impl DisplaySnapshot {
pub fn crease_for_buffer_row(&self, buffer_row: MultiBufferRow) -> Option<Crease<Point>> { pub fn crease_for_buffer_row(&self, buffer_row: MultiBufferRow) -> Option<Crease<Point>> {
let start = MultiBufferPoint::new(buffer_row.0, self.buffer_snapshot.line_len(buffer_row)); let start = MultiBufferPoint::new(buffer_row.0, self.buffer_snapshot.line_len(buffer_row));
if let Some(crease) = self match self
.crease_snapshot .crease_snapshot
.query_row(buffer_row, &self.buffer_snapshot) .query_row(buffer_row, &self.buffer_snapshot)
{ {
match crease { Some(crease) => match crease {
Crease::Inline { Crease::Inline {
range, range,
placeholder, placeholder,
@@ -1219,8 +1214,9 @@ impl DisplaySnapshot {
block_priority: *block_priority, block_priority: *block_priority,
render_toggle: render_toggle.clone(), render_toggle: render_toggle.clone(),
}), }),
} },
} else if self.starts_indent(MultiBufferRow(start.row)) _ => {
if self.starts_indent(MultiBufferRow(start.row))
&& !self.is_line_folded(MultiBufferRow(start.row)) && !self.is_line_folded(MultiBufferRow(start.row))
{ {
let start_line_indent = self.line_indent_for_buffer_row(buffer_row); let start_line_indent = self.line_indent_for_buffer_row(buffer_row);
@@ -1267,6 +1263,8 @@ impl DisplaySnapshot {
None None
} }
} }
}
}
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
pub fn text_highlight_ranges<Tag: ?Sized + 'static>( pub fn text_highlight_ranges<Tag: ?Sized + 'static>(
@@ -1480,7 +1478,7 @@ pub mod tests {
}); });
let buffer = cx.update(|cx| { let buffer = cx.update(|cx| {
if rng.gen() { if rng.r#gen() {
let len = rng.gen_range(0..10); let len = rng.gen_range(0..10);
let text = util::RandomCharIter::new(&mut rng) let text = util::RandomCharIter::new(&mut rng)
.take(len) .take(len)
@@ -1542,7 +1540,7 @@ pub mod tests {
} }
30..=44 => { 30..=44 => {
map.update(cx, |map, cx| { map.update(cx, |map, cx| {
if rng.gen() || blocks.is_empty() { if rng.r#gen() || blocks.is_empty() {
let buffer = map.snapshot(cx).buffer_snapshot; let buffer = map.snapshot(cx).buffer_snapshot;
let block_properties = (0..rng.gen_range(1..=1)) let block_properties = (0..rng.gen_range(1..=1))
.map(|_| { .map(|_| {
@@ -1552,7 +1550,7 @@ pub mod tests {
Bias::Left, Bias::Left,
)); ));
let placement = if rng.gen() { let placement = if rng.r#gen() {
BlockPlacement::Above(position) BlockPlacement::Above(position)
} else { } else {
BlockPlacement::Below(position) BlockPlacement::Below(position)
@@ -1596,7 +1594,7 @@ pub mod tests {
}); });
} }
if rng.gen() && fold_count > 0 { if rng.r#gen() && fold_count > 0 {
log::info!("unfolding ranges: {:?}", ranges); log::info!("unfolding ranges: {:?}", ranges);
map.update(cx, |map, cx| { map.update(cx, |map, cx| {
map.unfold_intersecting(ranges, true, cx); map.unfold_intersecting(ranges, true, cx);

View File

@@ -1351,13 +1351,16 @@ impl BlockSnapshot {
{ {
break; break;
} }
if let Some(block) = &transform.block { match &transform.block {
Some(block) => {
cursor.next(&()); cursor.next(&());
return Some((start_row, block)); return Some((start_row, block));
} else { }
_ => {
cursor.next(&()); cursor.next(&());
} }
} }
}
None None
}) })
} }
@@ -1405,13 +1408,18 @@ impl BlockSnapshot {
cursor.seek(&wrap_row, Bias::Left, &()); cursor.seek(&wrap_row, Bias::Left, &());
while let Some(transform) = cursor.item() { while let Some(transform) = cursor.item() {
if let Some(block) = transform.block.as_ref() { match transform.block.as_ref() {
Some(block) => {
if block.id() == block_id { if block.id() == block_id {
return Some(block.clone()); return Some(block.clone());
} }
} else if *cursor.start() > wrap_row { }
_ => {
if *cursor.start() > wrap_row {
break; break;
} }
}
}
cursor.next(&()); cursor.next(&());
} }
@@ -1482,7 +1490,8 @@ impl BlockSnapshot {
pub(super) fn line_len(&self, row: BlockRow) -> u32 { pub(super) fn line_len(&self, row: BlockRow) -> u32 {
let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>(&()); let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>(&());
cursor.seek(&BlockRow(row.0), Bias::Right, &()); cursor.seek(&BlockRow(row.0), Bias::Right, &());
if let Some(transform) = cursor.item() { match cursor.item() {
Some(transform) => {
let (output_start, input_start) = cursor.start(); let (output_start, input_start) = cursor.start();
let overshoot = row.0 - output_start.0; let overshoot = row.0 - output_start.0;
if transform.block.is_some() { if transform.block.is_some() {
@@ -1490,12 +1499,16 @@ impl BlockSnapshot {
} else { } else {
self.wrap_snapshot.line_len(input_start.0 + overshoot) self.wrap_snapshot.line_len(input_start.0 + overshoot)
} }
} else if row.0 == 0 { }
_ => {
if row.0 == 0 {
0 0
} else { } else {
panic!("row out of range"); panic!("row out of range");
} }
} }
}
}
pub(super) fn is_block_line(&self, row: BlockRow) -> bool { pub(super) fn is_block_line(&self, row: BlockRow) -> bool {
let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>(&()); let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>(&());
@@ -1536,7 +1549,8 @@ impl BlockSnapshot {
let mut reversed = false; let mut reversed = false;
loop { loop {
if let Some(transform) = cursor.item() { match cursor.item() {
Some(transform) => {
let (output_start_row, input_start_row) = cursor.start(); let (output_start_row, input_start_row) = cursor.start();
let (output_end_row, input_end_row) = cursor.end(&()); let (output_end_row, input_end_row) = cursor.end(&());
let output_start = Point::new(output_start_row.0, 0); let output_start = Point::new(output_start_row.0, 0);
@@ -1576,7 +1590,9 @@ impl BlockSnapshot {
} else { } else {
cursor.next(&()); cursor.next(&());
} }
} else if reversed { }
_ => {
if reversed {
return self.max_point(); return self.max_point();
} else { } else {
reversed = true; reversed = true;
@@ -1585,11 +1601,14 @@ impl BlockSnapshot {
} }
} }
} }
}
}
pub fn to_block_point(&self, wrap_point: WrapPoint) -> BlockPoint { pub fn to_block_point(&self, wrap_point: WrapPoint) -> BlockPoint {
let mut cursor = self.transforms.cursor::<(WrapRow, BlockRow)>(&()); let mut cursor = self.transforms.cursor::<(WrapRow, BlockRow)>(&());
cursor.seek(&WrapRow(wrap_point.row()), Bias::Right, &()); cursor.seek(&WrapRow(wrap_point.row()), Bias::Right, &());
if let Some(transform) = cursor.item() { match cursor.item() {
Some(transform) => {
if transform.block.is_some() { if transform.block.is_some() {
BlockPoint::new(cursor.start().1 .0, 0) BlockPoint::new(cursor.start().1 .0, 0)
} else { } else {
@@ -1599,16 +1618,16 @@ impl BlockSnapshot {
let input_overshoot = wrap_point.0 - input_start; let input_overshoot = wrap_point.0 - input_start;
BlockPoint(output_start + input_overshoot) BlockPoint(output_start + input_overshoot)
} }
} else { }
self.max_point() _ => self.max_point(),
} }
} }
pub fn to_wrap_point(&self, block_point: BlockPoint, bias: Bias) -> WrapPoint { pub fn to_wrap_point(&self, block_point: BlockPoint, bias: Bias) -> WrapPoint {
let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>(&()); let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>(&());
cursor.seek(&BlockRow(block_point.row), Bias::Right, &()); cursor.seek(&BlockRow(block_point.row), Bias::Right, &());
if let Some(transform) = cursor.item() { match cursor.item() {
match transform.block.as_ref() { Some(transform) => match transform.block.as_ref() {
Some(block) => { Some(block) => {
if block.place_below() { if block.place_below() {
let wrap_row = cursor.start().1 .0 - 1; let wrap_row = cursor.start().1 .0 - 1;
@@ -1627,9 +1646,8 @@ impl BlockSnapshot {
let wrap_row = cursor.start().1 .0 + overshoot; let wrap_row = cursor.start().1 .0 + overshoot;
WrapPoint::new(wrap_row, block_point.column) WrapPoint::new(wrap_row, block_point.column)
} }
} },
} else { _ => self.wrap_snapshot.max_point(),
self.wrap_snapshot.max_point()
} }
} }
} }
@@ -1702,9 +1720,11 @@ impl<'a> Iterator for BlockChunks<'a> {
} }
if self.input_chunk.text.is_empty() { if self.input_chunk.text.is_empty() {
if let Some(input_chunk) = self.input_chunks.next() { match self.input_chunks.next() {
Some(input_chunk) => {
self.input_chunk = input_chunk; self.input_chunk = input_chunk;
} else { }
_ => {
if self.output_row < self.max_output_row { if self.output_row < self.max_output_row {
self.output_row += 1; self.output_row += 1;
self.advance(); self.advance();
@@ -1718,6 +1738,7 @@ impl<'a> Iterator for BlockChunks<'a> {
return None; return None;
} }
} }
}
let transform_end = self.transforms.end(&()).0 .0; let transform_end = self.transforms.end(&()).0 .0;
let (prefix_rows, prefix_bytes) = let (prefix_rows, prefix_bytes) =
@@ -1783,7 +1804,8 @@ impl Iterator for BlockRows<'_> {
} }
let transform = self.transforms.item()?; let transform = self.transforms.item()?;
if let Some(block) = transform.block.as_ref() { match transform.block.as_ref() {
Some(block) => {
if block.is_replacement() && self.transforms.start().0 == self.output_row { if block.is_replacement() && self.transforms.start().0 == self.output_row {
if matches!(block, Block::FoldedBuffer { .. }) { if matches!(block, Block::FoldedBuffer { .. }) {
Some(RowInfo::default()) Some(RowInfo::default())
@@ -1793,8 +1815,8 @@ impl Iterator for BlockRows<'_> {
} else { } else {
Some(RowInfo::default()) Some(RowInfo::default())
} }
} else { }
Some(self.input_rows.next().unwrap()) _ => Some(self.input_rows.next().unwrap()),
} }
} }
} }
@@ -2913,7 +2935,7 @@ mod tests {
log::info!("Wrap width: {:?}", wrap_width); log::info!("Wrap width: {:?}", wrap_width);
log::info!("Excerpt Header Height: {:?}", excerpt_header_height); log::info!("Excerpt Header Height: {:?}", excerpt_header_height);
let is_singleton = rng.gen(); let is_singleton = rng.r#gen();
let buffer = if is_singleton { let buffer = if is_singleton {
let len = rng.gen_range(0..10); let len = rng.gen_range(0..10);
let text = RandomCharIter::new(&mut rng).take(len).collect::<String>(); let text = RandomCharIter::new(&mut rng).take(len).collect::<String>();

View File

@@ -602,12 +602,14 @@ impl FoldSnapshot {
if let Some(transform) = cursor.item() { if let Some(transform) = cursor.item() {
let start_in_transform = range.start.0 - cursor.start().0 .0; let start_in_transform = range.start.0 - cursor.start().0 .0;
let end_in_transform = cmp::min(range.end, cursor.end(&()).0).0 - cursor.start().0 .0; let end_in_transform = cmp::min(range.end, cursor.end(&()).0).0 - cursor.start().0 .0;
if let Some(placeholder) = transform.placeholder.as_ref() { match transform.placeholder.as_ref() {
Some(placeholder) => {
summary = TextSummary::from( summary = TextSummary::from(
&placeholder.text &placeholder.text
[start_in_transform.column as usize..end_in_transform.column as usize], [start_in_transform.column as usize..end_in_transform.column as usize],
); );
} else { }
_ => {
let inlay_start = self let inlay_start = self
.inlay_snapshot .inlay_snapshot
.to_offset(InlayPoint(cursor.start().1 .0 + start_in_transform)); .to_offset(InlayPoint(cursor.start().1 .0 + start_in_transform));
@@ -619,6 +621,7 @@ impl FoldSnapshot {
.text_summary_for_range(inlay_start..inlay_end); .text_summary_for_range(inlay_start..inlay_end);
} }
} }
}
if range.end > cursor.end(&()).0 { if range.end > cursor.end(&()).0 {
cursor.next(&()); cursor.next(&());
@@ -627,10 +630,13 @@ impl FoldSnapshot {
.output; .output;
if let Some(transform) = cursor.item() { if let Some(transform) = cursor.item() {
let end_in_transform = range.end.0 - cursor.start().0 .0; let end_in_transform = range.end.0 - cursor.start().0 .0;
if let Some(placeholder) = transform.placeholder.as_ref() { match transform.placeholder.as_ref() {
summary += Some(placeholder) => {
TextSummary::from(&placeholder.text[..end_in_transform.column as usize]); summary += TextSummary::from(
} else { &placeholder.text[..end_in_transform.column as usize],
);
}
_ => {
let inlay_start = self.inlay_snapshot.to_offset(cursor.start().1); let inlay_start = self.inlay_snapshot.to_offset(cursor.start().1);
let inlay_end = self let inlay_end = self
.inlay_snapshot .inlay_snapshot
@@ -641,6 +647,7 @@ impl FoldSnapshot {
} }
} }
} }
}
summary summary
} }
@@ -822,7 +829,8 @@ impl FoldSnapshot {
pub fn clip_point(&self, point: FoldPoint, bias: Bias) -> FoldPoint { pub fn clip_point(&self, point: FoldPoint, bias: Bias) -> FoldPoint {
let mut cursor = self.transforms.cursor::<(FoldPoint, InlayPoint)>(&()); let mut cursor = self.transforms.cursor::<(FoldPoint, InlayPoint)>(&());
cursor.seek(&point, Bias::Right, &()); cursor.seek(&point, Bias::Right, &());
if let Some(transform) = cursor.item() { match cursor.item() {
Some(transform) => {
let transform_start = cursor.start().0 .0; let transform_start = cursor.start().0 .0;
if transform.placeholder.is_some() { if transform.placeholder.is_some() {
if point.0 == transform_start || matches!(bias, Bias::Left) { if point.0 == transform_start || matches!(bias, Bias::Left) {
@@ -836,8 +844,8 @@ impl FoldSnapshot {
let clipped_inlay_point = self.inlay_snapshot.clip_point(inlay_point, bias); let clipped_inlay_point = self.inlay_snapshot.clip_point(inlay_point, bias);
FoldPoint(cursor.start().0 .0 + (clipped_inlay_point - cursor.start().1).0) FoldPoint(cursor.start().0 .0 + (clipped_inlay_point - cursor.start().1).0)
} }
} else { }
FoldPoint(self.transforms.summary().output.lines) _ => FoldPoint(self.transforms.summary().output.lines),
} }
} }
} }
@@ -1616,7 +1624,7 @@ mod tests {
let len = rng.gen_range(0..10); let len = rng.gen_range(0..10);
let text = RandomCharIter::new(&mut rng).take(len).collect::<String>(); let text = RandomCharIter::new(&mut rng).take(len).collect::<String>();
let buffer = if rng.gen() { let buffer = if rng.r#gen() {
MultiBuffer::build_simple(&text, cx) MultiBuffer::build_simple(&text, cx)
} else { } else {
MultiBuffer::build_random(&mut rng, cx) MultiBuffer::build_random(&mut rng, cx)
@@ -1962,7 +1970,7 @@ mod tests {
let start = buffer.clip_offset(rng.gen_range(0..=end), Left); let start = buffer.clip_offset(rng.gen_range(0..=end), Left);
to_unfold.push(start..end); to_unfold.push(start..end);
} }
let inclusive = rng.gen(); let inclusive = rng.r#gen();
log::info!("unfolding {:?} (inclusive: {})", to_unfold, inclusive); log::info!("unfolding {:?} (inclusive: {})", to_unfold, inclusive);
let (mut writer, snapshot, edits) = self.write(inlay_snapshot, vec![]); let (mut writer, snapshot, edits) = self.write(inlay_snapshot, vec![]);
snapshot_edits.push((snapshot, edits)); snapshot_edits.push((snapshot, edits));

View File

@@ -610,9 +610,9 @@ impl InlayMap {
let mut to_insert = Vec::new(); let mut to_insert = Vec::new();
let snapshot = &mut self.snapshot; let snapshot = &mut self.snapshot;
for i in 0..rng.gen_range(1..=5) { for i in 0..rng.gen_range(1..=5) {
if self.inlays.is_empty() || rng.gen() { if self.inlays.is_empty() || rng.r#gen() {
let position = snapshot.buffer.random_byte_range(0, rng).start; let position = snapshot.buffer.random_byte_range(0, rng).start;
let bias = if rng.gen() { Bias::Left } else { Bias::Right }; let bias = if rng.r#gen() { Bias::Left } else { Bias::Right };
let len = if rng.gen_bool(0.01) { let len = if rng.gen_bool(0.01) {
0 0
} else { } else {
@@ -809,7 +809,8 @@ impl InlaySnapshot {
match cursor.item() { match cursor.item() {
Some(Transform::Isomorphic(transform)) => { Some(Transform::Isomorphic(transform)) => {
if cursor.start().0 == point { if cursor.start().0 == point {
if let Some(Transform::Inlay(inlay)) = cursor.prev_item() { match cursor.prev_item() {
Some(Transform::Inlay(inlay)) => {
if inlay.position.bias() == Bias::Left { if inlay.position.bias() == Bias::Left {
return point; return point;
} else if bias == Bias::Left { } else if bias == Bias::Left {
@@ -819,11 +820,14 @@ impl InlaySnapshot {
} else { } else {
point.0 += Point::new(0, 1); point.0 += Point::new(0, 1);
} }
} else { }
_ => {
return point; return point;
} }
}
} else if cursor.end(&()).0 == point { } else if cursor.end(&()).0 == point {
if let Some(Transform::Inlay(inlay)) = cursor.next_item() { match cursor.next_item() {
Some(Transform::Inlay(inlay)) => {
if inlay.position.bias() == Bias::Right { if inlay.position.bias() == Bias::Right {
return point; return point;
} else if bias == Bias::Right { } else if bias == Bias::Right {
@@ -834,9 +838,11 @@ impl InlaySnapshot {
} else { } else {
point.0.column -= 1; point.0.column -= 1;
} }
} else { }
_ => {
return point; return point;
} }
}
} else { } else {
let overshoot = point.0 - cursor.start().0 .0; let overshoot = point.0 - cursor.start().0 .0;
let buffer_point = cursor.start().1 + overshoot; let buffer_point = cursor.start().1 + overshoot;
@@ -1500,7 +1506,7 @@ mod tests {
.unwrap_or(10); .unwrap_or(10);
let len = rng.gen_range(0..30); let len = rng.gen_range(0..30);
let buffer = if rng.gen() { let buffer = if rng.r#gen() {
let text = util::RandomCharIter::new(&mut rng) let text = util::RandomCharIter::new(&mut rng)
.take(len) .take(len)
.collect::<String>(); .collect::<String>();
@@ -1709,7 +1715,8 @@ mod tests {
buffer_point buffer_point
); );
if let Some(ch) = buffer_chars.next() { match buffer_chars.next() {
Some(ch) => {
if ch == '\n' { if ch == '\n' {
buffer_point += Point::new(1, 0); buffer_point += Point::new(1, 0);
} else { } else {
@@ -1720,10 +1727,12 @@ mod tests {
let new_inlay_point = inlay_snapshot.to_inlay_point(buffer_point); let new_inlay_point = inlay_snapshot.to_inlay_point(buffer_point);
assert!(new_inlay_point > inlay_point); assert!(new_inlay_point > inlay_point);
inlay_point = new_inlay_point; inlay_point = new_inlay_point;
} else { }
_ => {
break; break;
} }
} }
}
let mut inlay_point = InlayPoint::default(); let mut inlay_point = InlayPoint::default();
let mut inlay_offset = InlayOffset::default(); let mut inlay_offset = InlayOffset::default();

View File

@@ -534,17 +534,20 @@ impl<'a> Iterator for TabChunks<'a> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.chunk.text.is_empty() { if self.chunk.text.is_empty() {
if let Some(chunk) = self.fold_chunks.next() { match self.fold_chunks.next() {
Some(chunk) => {
self.chunk = chunk; self.chunk = chunk;
if self.inside_leading_tab { if self.inside_leading_tab {
self.chunk.text = &self.chunk.text[1..]; self.chunk.text = &self.chunk.text[1..];
self.inside_leading_tab = false; self.inside_leading_tab = false;
self.input_column += 1; self.input_column += 1;
} }
} else { }
_ => {
return None; return None;
} }
} }
}
for (ix, c) in self.chunk.text.char_indices() { for (ix, c) in self.chunk.text.char_indices() {
match c { match c {
@@ -738,7 +741,7 @@ mod tests {
fn test_random_tabs(cx: &mut gpui::App, mut rng: StdRng) { fn test_random_tabs(cx: &mut gpui::App, mut rng: StdRng) {
let tab_size = NonZeroU32::new(rng.gen_range(1..=4)).unwrap(); let tab_size = NonZeroU32::new(rng.gen_range(1..=4)).unwrap();
let len = rng.gen_range(0..30); let len = rng.gen_range(0..30);
let buffer = if rng.gen() { let buffer = if rng.r#gen() {
let text = util::RandomCharIter::new(&mut rng) let text = util::RandomCharIter::new(&mut rng)
.take(len) .take(len)
.collect::<String>(); .collect::<String>();

View File

@@ -1207,7 +1207,7 @@ mod tests {
log::info!("Wrap width: {:?}", wrap_width); log::info!("Wrap width: {:?}", wrap_width);
let buffer = cx.update(|cx| { let buffer = cx.update(|cx| {
if rng.gen() { if rng.r#gen() {
MultiBuffer::build_random(&mut rng, cx) MultiBuffer::build_random(&mut rng, cx)
} else { } else {
let len = rng.gen_range(0..10); let len = rng.gen_range(0..10);

View File

@@ -1700,7 +1700,8 @@ impl Editor {
} }
} }
if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() { match self.buffer.read(cx).as_singleton() {
Some(singleton_buffer) => {
if let Some(extension) = singleton_buffer if let Some(extension) = singleton_buffer
.read(cx) .read(cx)
.file() .file()
@@ -1708,9 +1709,11 @@ impl Editor {
{ {
key_context.set("extension", extension.to_string()); key_context.set("extension", extension.to_string());
} }
} else { }
_ => {
key_context.add("multibuffer"); key_context.add("multibuffer");
} }
}
if has_active_edit_prediction { if has_active_edit_prediction {
if self.edit_prediction_in_conflict() { if self.edit_prediction_in_conflict() {
@@ -1901,14 +1904,13 @@ impl Editor {
pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot { pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
let git_blame_gutter_max_author_length = self let git_blame_gutter_max_author_length = self
.render_git_blame_gutter(cx) .render_git_blame_gutter(cx)
.then(|| { .then(|| match self.blame.as_ref() {
if let Some(blame) = self.blame.as_ref() { Some(blame) => {
let max_author_length = let max_author_length =
blame.update(cx, |blame, cx| blame.max_author_length(cx)); blame.update(cx, |blame, cx| blame.max_author_length(cx));
Some(max_author_length) Some(max_author_length)
} else {
None
} }
_ => None,
}) })
.flatten(); .flatten();
@@ -2791,7 +2793,9 @@ impl Editor {
if let Some(tail) = self.columnar_selection_tail.as_ref() { if let Some(tail) = self.columnar_selection_tail.as_ref() {
let tail = tail.to_display_point(&display_map); let tail = tail.to_display_point(&display_map);
self.select_columns(tail, position, goal_column, &display_map, window, cx); self.select_columns(tail, position, goal_column, &display_map, window, cx);
} else if let Some(mut pending) = self.selections.pending_anchor() { } else {
match self.selections.pending_anchor() {
Some(mut pending) => {
let buffer = self.buffer.read(cx).snapshot(cx); let buffer = self.buffer.read(cx).snapshot(cx);
let head; let head;
let tail; let tail;
@@ -2802,9 +2806,11 @@ impl Editor {
tail = pending.tail().to_point(&buffer); tail = pending.tail().to_point(&buffer);
} }
SelectMode::Word(original_range) => { SelectMode::Word(original_range) => {
let original_display_range = original_range.start.to_display_point(&display_map) let original_display_range =
original_range.start.to_display_point(&display_map)
..original_range.end.to_display_point(&display_map); ..original_range.end.to_display_point(&display_map);
let original_buffer_range = original_display_range.start.to_point(&display_map) let original_buffer_range =
original_display_range.start.to_point(&display_map)
..original_display_range.end.to_point(&display_map); ..original_display_range.end.to_point(&display_map);
if movement::is_inside_word(&display_map, position) if movement::is_inside_word(&display_map, position)
|| original_display_range.contains(&position) || original_display_range.contains(&position)
@@ -2826,7 +2832,8 @@ impl Editor {
} }
} }
SelectMode::Line(original_range) => { SelectMode::Line(original_range) => {
let original_range = original_range.to_point(&display_map.buffer_snapshot); let original_range =
original_range.to_point(&display_map.buffer_snapshot);
let position = display_map let position = display_map
.clip_point(position, Bias::Left) .clip_point(position, Bias::Left)
@@ -2867,10 +2874,13 @@ impl Editor {
self.change_selections(None, window, cx, |s| { self.change_selections(None, window, cx, |s| {
s.set_pending(pending, mode); s.set_pending(pending, mode);
}); });
} else { }
_ => {
log::error!("update_selection dispatched with no pending selection"); log::error!("update_selection dispatched with no pending selection");
return; return;
} }
}
}
self.apply_scroll_delta(scroll_delta, window, cx); self.apply_scroll_delta(scroll_delta, window, cx);
cx.notify(); cx.notify();
@@ -3492,9 +3502,8 @@ impl Editor {
let end = selection.end; let end = selection.end;
let selection_is_empty = start == end; let selection_is_empty = start == end;
let language_scope = buffer.language_scope_at(start); let language_scope = buffer.language_scope_at(start);
let (comment_delimiter, insert_extra_newline) = if let Some(language) = let (comment_delimiter, insert_extra_newline) = match &language_scope {
&language_scope Some(language) => {
{
let insert_extra_newline = let insert_extra_newline =
insert_extra_newline_brackets(&buffer, start..end, language) insert_extra_newline_brackets(&buffer, start..end, language)
|| insert_extra_newline_tree_sitter(&buffer, start..end); || insert_extra_newline_tree_sitter(&buffer, start..end);
@@ -3505,15 +3514,16 @@ impl Editor {
return None; return None;
} }
if !multi_buffer.language_settings(cx).extend_comment_on_newline { if !multi_buffer.language_settings(cx).extend_comment_on_newline
{
return None; return None;
} }
let delimiters = language.line_comment_prefixes(); let delimiters = language.line_comment_prefixes();
let max_len_of_delimiter = let max_len_of_delimiter =
delimiters.iter().map(|delimiter| delimiter.len()).max()?; delimiters.iter().map(|delimiter| delimiter.len()).max()?;
let (snapshot, range) = let (snapshot, range) = buffer
buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?; .buffer_line_for_row(MultiBufferRow(start_point.row))?;
let mut index_of_first_non_whitespace = 0; let mut index_of_first_non_whitespace = 0;
let comment_candidate = snapshot let comment_candidate = snapshot
@@ -3527,7 +3537,8 @@ impl Editor {
}) })
.take(max_len_of_delimiter) .take(max_len_of_delimiter)
.collect::<String>(); .collect::<String>();
let comment_prefix = delimiters.iter().find(|comment_prefix| { let comment_prefix =
delimiters.iter().find(|comment_prefix| {
comment_candidate.starts_with(comment_prefix.as_ref()) comment_candidate.starts_with(comment_prefix.as_ref())
})?; })?;
let cursor_is_placed_after_comment_marker = let cursor_is_placed_after_comment_marker =
@@ -3540,8 +3551,8 @@ impl Editor {
} }
}); });
(comment_delimiter, insert_extra_newline) (comment_delimiter, insert_extra_newline)
} else { }
(None, false) _ => (None, false),
}; };
let capacity_for_delimiter = comment_delimiter let capacity_for_delimiter = comment_delimiter
@@ -3810,16 +3821,15 @@ impl Editor {
return false; return false;
}; };
if let Some(completion_provider) = &self.completion_provider { match &self.completion_provider {
completion_provider.is_completion_trigger( Some(completion_provider) => completion_provider.is_completion_trigger(
&buffer, &buffer,
position.text_anchor, position.text_anchor,
text, text,
trigger_in_words, trigger_in_words,
cx, cx,
) ),
} else { _ => false,
false
} }
} }
@@ -4268,10 +4278,11 @@ impl Editor {
return; return;
} }
let (buffer, buffer_position) = let (buffer, buffer_position) =
if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) { match self.buffer.read(cx).text_anchor_for_position(position, cx) {
output Some(output) => output,
} else { _ => {
return; return;
}
}; };
let buffer_snapshot = buffer.read(cx).snapshot(); let buffer_snapshot = buffer.read(cx).snapshot();
let show_completion_documentation = buffer_snapshot let show_completion_documentation = buffer_snapshot
@@ -4499,11 +4510,12 @@ impl Editor {
#[cfg(feature = "test-support")] #[cfg(feature = "test-support")]
pub fn current_completions(&self) -> Option<Vec<project::Completion>> { pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
let menu = self.context_menu.borrow(); let menu = self.context_menu.borrow();
if let CodeContextMenu::Completions(menu) = menu.as_ref()? { match menu.as_ref()? {
CodeContextMenu::Completions(menu) => {
let completions = menu.completions.borrow(); let completions = menu.completions.borrow();
Some(completions.to_vec()) Some(completions.to_vec())
} else { }
None _ => None,
} }
} }
@@ -4536,11 +4548,11 @@ impl Editor {
) -> Option<Task<Result<()>>> { ) -> Option<Task<Result<()>>> {
use language::ToOffset as _; use language::ToOffset as _;
let completions_menu = let completions_menu = match self.hide_context_menu(window, cx)? {
if let CodeContextMenu::Completions(menu) = self.hide_context_menu(window, cx)? { CodeContextMenu::Completions(menu) => menu,
menu _ => {
} else {
return None; return None;
}
}; };
let candidate_id = { let candidate_id = {
@@ -4650,7 +4662,8 @@ impl Editor {
}); });
self.transact(window, cx, |this, window, cx| { self.transact(window, cx, |this, window, cx| {
if let Some(mut snippet) = snippet { match snippet {
Some(mut snippet) => {
snippet.text = text.to_string(); snippet.text = text.to_string();
for tabstop in snippet for tabstop in snippet
.tabstops .tabstops
@@ -4662,12 +4675,14 @@ impl Editor {
} }
this.insert_snippet(&ranges, snippet, window, cx).log_err(); this.insert_snippet(&ranges, snippet, window, cx).log_err();
} else { }
_ => {
this.buffer.update(cx, |buffer, cx| { this.buffer.update(cx, |buffer, cx| {
let edits = ranges.iter().map(|range| (range.clone(), text)); let edits = ranges.iter().map(|range| (range.clone(), text));
buffer.edit(edits, this.autoindent_mode.clone(), cx); buffer.edit(edits, this.autoindent_mode.clone(), cx);
}); });
} }
}
for (buffer, edits) in linked_edits { for (buffer, edits) in linked_edits {
buffer.update(cx, |buffer, cx| { buffer.update(cx, |buffer, cx| {
let snapshot = buffer.snapshot(); let snapshot = buffer.snapshot();
@@ -4818,7 +4833,7 @@ impl Editor {
&& code_actions && code_actions
.as_ref() .as_ref()
.map_or(true, |actions| actions.is_empty()); .map_or(true, |actions| actions.is_empty());
if let Ok(task) = editor.update_in(cx, |editor, window, cx| { match editor.update_in(cx, |editor, window, cx| {
*editor.context_menu.borrow_mut() = *editor.context_menu.borrow_mut() =
Some(CodeContextMenu::CodeActions(CodeActionsMenu { Some(CodeContextMenu::CodeActions(CodeActionsMenu {
buffer, buffer,
@@ -4843,9 +4858,8 @@ impl Editor {
cx.notify(); cx.notify();
Task::ready(Ok(())) Task::ready(Ok(()))
}) { }) {
task.await Ok(task) => task.await,
} else { _ => Ok(()),
Ok(())
} }
})) }))
} else { } else {
@@ -4869,11 +4883,11 @@ impl Editor {
) -> Option<Task<Result<()>>> { ) -> Option<Task<Result<()>>> {
self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction); self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
let actions_menu = let actions_menu = match self.hide_context_menu(window, cx)? {
if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? { CodeContextMenu::CodeActions(menu) => menu,
menu _ => {
} else {
return None; return None;
}
}; };
let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item); let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
@@ -4911,7 +4925,8 @@ impl Editor {
return Some(Task::ready(Ok(()))); return Some(Task::ready(Ok(())));
} }
if let Some(project) = self.project.as_ref() { match self.project.as_ref() {
Some(project) => {
project project
.update(cx, |project, cx| { .update(cx, |project, cx| {
project.start_debug_session( project.start_debug_session(
@@ -4921,8 +4936,8 @@ impl Editor {
}) })
.detach_and_log_err(cx); .detach_and_log_err(cx);
Some(Task::ready(Ok(()))) Some(Task::ready(Ok(())))
} else { }
Some(Task::ready(Ok(()))) _ => Some(Task::ready(Ok(()))),
} }
} }
} }
@@ -4967,7 +4982,8 @@ impl Editor {
// If the project transaction's edits are all contained within this editor, then // If the project transaction's edits are all contained within this editor, then
// avoid opening a new editor to display them. // avoid opening a new editor to display them.
if let Some((buffer, transaction)) = entries.first() { match entries.first() {
Some((buffer, transaction)) => {
if entries.len() == 1 { if entries.len() == 1 {
let excerpt = this.update(cx, |editor, cx| { let excerpt = this.update(cx, |editor, cx| {
editor editor
@@ -4993,9 +5009,11 @@ impl Editor {
} }
} }
} }
} else { }
_ => {
return Ok(()); return Ok(());
} }
}
let mut ranges_to_highlight = Vec::new(); let mut ranges_to_highlight = Vec::new();
let excerpt_buffer = cx.new(|cx| { let excerpt_buffer = cx.new(|cx| {
@@ -5166,16 +5184,15 @@ impl Editor {
.timer(Duration::from_millis(debounce)) .timer(Duration::from_millis(debounce))
.await; .await;
let highlights = if let Some(highlights) = cx let highlights = match cx
.update(|cx| { .update(|cx| {
provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx) provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
}) })
.ok() .ok()
.flatten() .flatten()
{ {
highlights.await.log_err() Some(highlights) => highlights.await.log_err(),
} else { _ => None,
None
}; };
if let Some(highlights) = highlights { if let Some(highlights) = highlights {
@@ -5489,12 +5506,11 @@ impl Editor {
pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool { pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
let cursor = self.selections.newest_anchor().head(); let cursor = self.selections.newest_anchor().head();
if let Some((buffer, cursor_position)) = match self.buffer.read(cx).text_anchor_for_position(cursor, cx) {
self.buffer.read(cx).text_anchor_for_position(cursor, cx) Some((buffer, cursor_position)) => {
{
self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx) self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
} else { }
false _ => false,
} }
} }
@@ -9930,13 +9946,13 @@ impl Editor {
self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction); self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) { if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
if let Some((selections, _)) = match self.selection_history.transaction(transaction_id).cloned() {
self.selection_history.transaction(transaction_id).cloned() Some((selections, _)) => {
{
self.change_selections(None, window, cx, |s| { self.change_selections(None, window, cx, |s| {
s.select_anchors(selections.to_vec()); s.select_anchors(selections.to_vec());
}); });
} else { }
_ => {
log::error!( log::error!(
"No entry in selection_history found for undo. \ "No entry in selection_history found for undo. \
This may correspond to a bug where undo does not update the selection. \ This may correspond to a bug where undo does not update the selection. \
@@ -9944,6 +9960,7 @@ impl Editor {
https://github.com/zed-industries/zed/issues/22692" https://github.com/zed-industries/zed/issues/22692"
); );
} }
}
self.request_autoscroll(Autoscroll::fit(), cx); self.request_autoscroll(Autoscroll::fit(), cx);
self.unmark_text(window, cx); self.unmark_text(window, cx);
self.refresh_inline_completion(true, false, window, cx); self.refresh_inline_completion(true, false, window, cx);
@@ -9960,13 +9977,13 @@ impl Editor {
self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction); self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) { if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
if let Some((_, Some(selections))) = match self.selection_history.transaction(transaction_id).cloned() {
self.selection_history.transaction(transaction_id).cloned() Some((_, Some(selections))) => {
{
self.change_selections(None, window, cx, |s| { self.change_selections(None, window, cx, |s| {
s.select_anchors(selections.to_vec()); s.select_anchors(selections.to_vec());
}); });
} else { }
_ => {
log::error!( log::error!(
"No entry in selection_history found for redo. \ "No entry in selection_history found for redo. \
This may correspond to a bug where undo does not update the selection. \ This may correspond to a bug where undo does not update the selection. \
@@ -9974,6 +9991,7 @@ impl Editor {
https://github.com/zed-industries/zed/issues/22692" https://github.com/zed-industries/zed/issues/22692"
); );
} }
}
self.request_autoscroll(Autoscroll::fit(), cx); self.request_autoscroll(Autoscroll::fit(), cx);
self.unmark_text(window, cx); self.unmark_text(window, cx);
self.refresh_inline_completion(true, false, window, cx); self.refresh_inline_completion(true, false, window, cx);
@@ -11377,7 +11395,8 @@ impl Editor {
let buffer = &display_map.buffer_snapshot; let buffer = &display_map.buffer_snapshot;
let mut selections = self.selections.all::<usize>(cx); let mut selections = self.selections.all::<usize>(cx);
if let Some(mut select_next_state) = self.select_next_state.take() { match self.select_next_state.take() {
Some(mut select_next_state) => {
let query = &select_next_state.query; let query = &select_next_state.query;
if !select_next_state.done { if !select_next_state.done {
let first_selection = selections.iter().min_by_key(|s| s.id).unwrap(); let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
@@ -11386,7 +11405,8 @@ impl Editor {
let bytes_after_last_selection = let bytes_after_last_selection =
buffer.bytes_in_range(last_selection.end..buffer.len()); buffer.bytes_in_range(last_selection.end..buffer.len());
let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start); let bytes_before_first_selection =
buffer.bytes_in_range(0..first_selection.start);
let query_matches = query let query_matches = query
.stream_find_iter(bytes_after_last_selection) .stream_find_iter(bytes_after_last_selection)
.map(|result| (last_selection.end, result)) .map(|result| (last_selection.end, result))
@@ -11433,7 +11453,8 @@ impl Editor {
} }
self.select_next_state = Some(select_next_state); self.select_next_state = Some(select_next_state);
} else { }
_ => {
let mut only_carets = true; let mut only_carets = true;
let mut same_text_selected = true; let mut same_text_selected = true;
let mut selected_text = None; let mut selected_text = None;
@@ -11519,6 +11540,7 @@ impl Editor {
)?; )?;
} }
} }
}
Ok(()) Ok(())
} }
@@ -11639,7 +11661,8 @@ impl Editor {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let buffer = &display_map.buffer_snapshot; let buffer = &display_map.buffer_snapshot;
let mut selections = self.selections.all::<usize>(cx); let mut selections = self.selections.all::<usize>(cx);
if let Some(mut select_prev_state) = self.select_prev_state.take() { match self.select_prev_state.take() {
Some(mut select_prev_state) => {
let query = &select_prev_state.query; let query = &select_prev_state.query;
if !select_prev_state.done { if !select_prev_state.done {
let first_selection = selections.iter().min_by_key(|s| s.id).unwrap(); let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
@@ -11688,7 +11711,8 @@ impl Editor {
} }
self.select_prev_state = Some(select_prev_state); self.select_prev_state = Some(select_prev_state);
} else { }
_ => {
let mut only_carets = true; let mut only_carets = true;
let mut same_text_selected = true; let mut same_text_selected = true;
let mut selected_text = None; let mut selected_text = None;
@@ -11762,13 +11786,17 @@ impl Editor {
}); });
} else if let Some(selected_text) = selected_text { } else if let Some(selected_text) = selected_text {
self.select_prev_state = Some(SelectNextState { self.select_prev_state = Some(SelectNextState {
query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?, query: AhoCorasick::new(&[selected_text
.chars()
.rev()
.collect::<String>()])?,
wordwise: false, wordwise: false,
done: false, done: false,
}); });
self.select_previous(action, window, cx)?; self.select_previous(action, window, cx)?;
} }
} }
}
Ok(()) Ok(())
} }
@@ -11873,12 +11901,13 @@ impl Editor {
let start_column = snapshot let start_column = snapshot
.indent_size_for_line(MultiBufferRow(selection.start.row)) .indent_size_for_line(MultiBufferRow(selection.start.row))
.len; .len;
let language = if let Some(language) = let language = match snapshot
snapshot.language_scope_at(Point::new(selection.start.row, start_column)) .language_scope_at(Point::new(selection.start.row, start_column))
{ {
language Some(language) => language,
} else { _ => {
continue; continue;
}
}; };
selection_edit_ranges.clear(); selection_edit_ranges.clear();
@@ -11969,11 +11998,12 @@ impl Editor {
(position..position, first_prefix.clone()) (position..position, first_prefix.clone())
})); }));
} }
} else if let Some((full_comment_prefix, comment_suffix)) = } else {
language.block_comment_delimiters() match language.block_comment_delimiters() {
{ Some((full_comment_prefix, comment_suffix)) => {
let comment_prefix = full_comment_prefix.trim_end_matches(' '); let comment_prefix = full_comment_prefix.trim_end_matches(' ');
let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..]; let comment_prefix_whitespace =
&full_comment_prefix[comment_prefix.len()..];
let prefix_range = comment_prefix_range( let prefix_range = comment_prefix_range(
snapshot.deref(), snapshot.deref(),
start_row, start_row,
@@ -11993,16 +12023,22 @@ impl Editor {
prefix_range.start..prefix_range.start, prefix_range.start..prefix_range.start,
full_comment_prefix.clone(), full_comment_prefix.clone(),
)); ));
edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone())); edits.push((
suffix_range.end..suffix_range.end,
comment_suffix.clone(),
));
suffixes_inserted.push((end_row, comment_suffix.len())); suffixes_inserted.push((end_row, comment_suffix.len()));
} else { } else {
edits.push((prefix_range, empty_str.clone())); edits.push((prefix_range, empty_str.clone()));
edits.push((suffix_range, empty_str.clone())); edits.push((suffix_range, empty_str.clone()));
} }
} else { }
_ => {
continue; continue;
} }
} }
}
}
drop(snapshot); drop(snapshot);
this.buffer.update(cx, |buffer, cx| { this.buffer.update(cx, |buffer, cx| {
@@ -13023,10 +13059,11 @@ impl Editor {
}; };
let head = self.selections.newest::<usize>(cx).head(); let head = self.selections.newest::<usize>(cx).head();
let buffer = self.buffer.read(cx); let buffer = self.buffer.read(cx);
let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) { let (buffer, head) = match buffer.text_anchor_for_position(head, cx) {
text_anchor Some(text_anchor) => text_anchor,
} else { _ => {
return Task::ready(Ok(Navigated::No)); return Task::ready(Ok(Navigated::No));
}
}; };
let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else { let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
@@ -13163,20 +13200,17 @@ impl Editor {
cx.open_url(&url); cx.open_url(&url);
Task::ready(Ok(TargetTaskResult::AlreadyNavigated)) Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
} }
HoverLink::File(path) => { HoverLink::File(path) => match self.workspace() {
if let Some(workspace) = self.workspace() { Some(workspace) => cx.spawn_in(window, async move |_, cx| {
cx.spawn_in(window, async move |_, cx| {
workspace workspace
.update_in(cx, |workspace, window, cx| { .update_in(cx, |workspace, window, cx| {
workspace.open_resolved_path(path, window, cx) workspace.open_resolved_path(path, window, cx)
})? })?
.await .await
.map(|_| TargetTaskResult::AlreadyNavigated) .map(|_| TargetTaskResult::AlreadyNavigated)
}) }),
} else { _ => Task::ready(Ok(TargetTaskResult::Location(None))),
Task::ready(Ok(TargetTaskResult::Location(None))) },
}
}
}; };
cx.spawn_in(window, async move |editor, cx| { cx.spawn_in(window, async move |editor, cx| {
let target = match target_task.await.context("target resolution task")? { let target = match target_task.await.context("target resolution task")? {
@@ -13572,10 +13606,9 @@ impl Editor {
drop(snapshot); drop(snapshot);
Some(cx.spawn_in(window, async move |this, cx| { Some(cx.spawn_in(window, async move |this, cx| {
let rename_range = if let Some(range) = prepare_rename.await? { let rename_range = match prepare_rename.await? {
Some(range) Some(range) => Some(range),
} else { _ => this.update(cx, |this, cx| {
this.update(cx, |this, cx| {
let buffer = this.buffer.read(cx).snapshot(cx); let buffer = this.buffer.read(cx).snapshot(cx);
let mut buffer_highlights = this let mut buffer_highlights = this
.document_highlights_for_position(selection.head(), &buffer) .document_highlights_for_position(selection.head(), &buffer)
@@ -13586,7 +13619,7 @@ impl Editor {
buffer_highlights buffer_highlights
.next() .next()
.map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor) .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
})? })?,
}; };
if let Some(rename_range) = rename_range { if let Some(rename_range) = rename_range {
this.update_in(cx, |this, window, cx| { this.update_in(cx, |this, window, cx| {
@@ -14321,22 +14354,26 @@ impl Editor {
now: Instant, now: Instant,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> Option<TransactionId> { ) -> Option<TransactionId> {
if let Some(transaction_id) = self match self
.buffer .buffer
.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx)) .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
{ {
if let Some((_, end_selections)) = Some(transaction_id) => {
self.selection_history.transaction_mut(transaction_id) match self.selection_history.transaction_mut(transaction_id) {
{ Some((_, end_selections)) => {
*end_selections = Some(self.selections.disjoint_anchors()); *end_selections = Some(self.selections.disjoint_anchors());
} else { }
log::error!("unexpectedly ended a transaction that wasn't started by this editor"); _ => {
log::error!(
"unexpectedly ended a transaction that wasn't started by this editor"
);
}
} }
cx.emit(EditorEvent::Edited { transaction_id }); cx.emit(EditorEvent::Edited { transaction_id });
Some(transaction_id) Some(transaction_id)
} else { }
None _ => None,
} }
} }
@@ -14454,13 +14491,13 @@ impl Editor {
let mut found = false; let mut found = false;
let mut row = range.start.row; let mut row = range.start.row;
while row <= range.end.row { while row <= range.end.row {
if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) match display_map.crease_for_buffer_row(MultiBufferRow(row)) {
{ Some(crease) => {
found = true; found = true;
row = crease.range().end.row + 1; row = crease.range().end.row + 1;
to_fold.push(crease); to_fold.push(crease);
} else { }
row += 1 _ => row += 1,
} }
} }
if found { if found {
@@ -15067,10 +15104,9 @@ impl Editor {
} }
} }
if let Some(project) = &self.project { match &self.project {
project.update(cx, |project, cx| project.save_buffers(buffers, cx)) Some(project) => project.update(cx, |project, cx| project.save_buffers(buffers, cx)),
} else { _ => Task::ready(Ok(())),
Task::ready(Ok(()))
} }
} }
@@ -15715,10 +15751,9 @@ impl Editor {
} }
pub fn project_path(&self, cx: &App) -> Option<ProjectPath> { pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
if let Some(buffer) = self.buffer.read(cx).as_singleton() { match self.buffer.read(cx).as_singleton() {
buffer.read(cx).project_path(cx) Some(buffer) => buffer.read(cx).project_path(cx),
} else { _ => None,
None
} }
} }
@@ -17401,13 +17436,15 @@ impl Editor {
fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) { fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
cx.emit(EditorEvent::Focused); cx.emit(EditorEvent::Focused);
if let Some(descendant) = self match self
.last_focused_descendant .last_focused_descendant
.take() .take()
.and_then(|descendant| descendant.upgrade()) .and_then(|descendant| descendant.upgrade())
{ {
Some(descendant) => {
window.focus(&descendant); window.focus(&descendant);
} else { }
_ => {
if let Some(blame) = self.blame.as_ref() { if let Some(blame) = self.blame.as_ref() {
blame.update(cx, GitBlame::focus) blame.update(cx, GitBlame::focus)
} }
@@ -17427,6 +17464,7 @@ impl Editor {
}); });
} }
} }
}
fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) { fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
cx.emit(EditorEvent::FocusedIn) cx.emit(EditorEvent::FocusedIn)
@@ -18700,7 +18738,7 @@ impl EditorSnapshot {
range: &'a Range<Anchor>, range: &'a Range<Anchor>,
collaboration_hub: &dyn CollaborationHub, collaboration_hub: &dyn CollaborationHub,
cx: &'a App, cx: &'a App,
) -> impl 'a + Iterator<Item = RemoteSelection> { ) -> impl 'a + Iterator<Item = RemoteSelection> + use<'a> {
let participant_names = collaboration_hub.user_names(cx); let participant_names = collaboration_hub.user_names(cx);
let participant_indices = collaboration_hub.user_participant_indices(cx); let participant_indices = collaboration_hub.user_participant_indices(cx);
let collaborators_by_peer_id = collaboration_hub.collaborators(cx); let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
@@ -18993,14 +19031,15 @@ impl EditorSnapshot {
cx: &mut App, cx: &mut App,
) -> Option<AnyElement> { ) -> Option<AnyElement> {
let folded = self.is_line_folded(buffer_row); let folded = self.is_line_folded(buffer_row);
if let Crease::Inline { render_trailer, .. } = self match self
.crease_snapshot .crease_snapshot
.query_row(buffer_row, &self.buffer_snapshot)? .query_row(buffer_row, &self.buffer_snapshot)?
{ {
Crease::Inline { render_trailer, .. } => {
let render_trailer = render_trailer.as_ref()?; let render_trailer = render_trailer.as_ref()?;
Some(render_trailer(buffer_row, folded, window, cx)) Some(render_trailer(buffer_row, folded, window, cx))
} else { }
None _ => None,
} }
} }
} }
@@ -19995,7 +20034,7 @@ impl BreakpointPromptEditor {
.log_err(); .log_err();
} }
fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement { fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement + use<> {
let settings = ThemeSettings::get_global(cx); let settings = ThemeSettings::get_global(cx);
let text_style = TextStyle { let text_style = TextStyle {
color: if self.prompt.read(cx).read_only(cx) { color: if self.prompt.read(cx).read_only(cx) {

View File

@@ -9526,16 +9526,18 @@ async fn test_word_completion(cx: &mut TestAppContext) {
cx.condition(|editor, _| editor.context_menu_visible()) cx.condition(|editor, _| editor.context_menu_visible())
.await; .await;
cx.update_editor(|editor, window, cx| { cx.update_editor(|editor, window, cx| {
if let Some(CodeContextMenu::Completions(menu)) = editor.context_menu.borrow_mut().as_ref() match editor.context_menu.borrow_mut().as_ref() {
{ Some(CodeContextMenu::Completions(menu)) => {
assert_eq!( assert_eq!(
completion_menu_entries(&menu), completion_menu_entries(&menu),
&["first", "last"], &["first", "last"],
"When LSP server is fast to reply, no fallback word completions are used" "When LSP server is fast to reply, no fallback word completions are used"
); );
} else { }
_ => {
panic!("expected completion menu to be open"); panic!("expected completion menu to be open");
} }
}
editor.cancel(&Cancel, window, cx); editor.cancel(&Cancel, window, cx);
}); });
cx.executor().run_until_parked(); cx.executor().run_until_parked();
@@ -9550,13 +9552,13 @@ async fn test_word_completion(cx: &mut TestAppContext) {
cx.condition(|editor, _| editor.context_menu_visible()) cx.condition(|editor, _| editor.context_menu_visible())
.await; .await;
cx.update_editor(|editor, _, _| { cx.update_editor(|editor, _, _| {
if let Some(CodeContextMenu::Completions(menu)) = editor.context_menu.borrow_mut().as_ref() match editor.context_menu.borrow_mut().as_ref()
{ { Some(CodeContextMenu::Completions(menu)) => {
assert_eq!(completion_menu_entries(&menu), &["one", "three", "two"], assert_eq!(completion_menu_entries(&menu), &["one", "three", "two"],
"When LSP server is slow, document words can be shown instead, if configured accordingly"); "When LSP server is slow, document words can be shown instead, if configured accordingly");
} else { } _ => {
panic!("expected completion menu to be open"); panic!("expected completion menu to be open");
} }}
}); });
} }
@@ -9609,16 +9611,16 @@ async fn test_word_completions_do_not_duplicate_lsp_ones(cx: &mut TestAppContext
cx.condition(|editor, _| editor.context_menu_visible()) cx.condition(|editor, _| editor.context_menu_visible())
.await; .await;
cx.update_editor(|editor, _, _| { cx.update_editor(|editor, _, _| {
if let Some(CodeContextMenu::Completions(menu)) = editor.context_menu.borrow_mut().as_ref() match editor.context_menu.borrow_mut().as_ref()
{ { Some(CodeContextMenu::Completions(menu)) => {
assert_eq!( assert_eq!(
completion_menu_entries(&menu), completion_menu_entries(&menu),
&["first", "last", "second"], &["first", "last", "second"],
"Word completions that has the same edit as the any of the LSP ones, should not be proposed" "Word completions that has the same edit as the any of the LSP ones, should not be proposed"
); );
} else { } _ => {
panic!("expected completion menu to be open"); panic!("expected completion menu to be open");
} }}
}); });
} }
@@ -9663,34 +9665,36 @@ async fn test_word_completions_continue_on_typing(cx: &mut TestAppContext) {
cx.executor().run_until_parked(); cx.executor().run_until_parked();
cx.condition(|editor, _| editor.context_menu_visible()) cx.condition(|editor, _| editor.context_menu_visible())
.await; .await;
cx.update_editor(|editor, _, _| { cx.update_editor(
if let Some(CodeContextMenu::Completions(menu)) = editor.context_menu.borrow_mut().as_ref() |editor, _, _| match editor.context_menu.borrow_mut().as_ref() {
{ Some(CodeContextMenu::Completions(menu)) => {
assert_eq!( assert_eq!(
completion_menu_entries(&menu), completion_menu_entries(&menu),
&["first", "last", "second"], &["first", "last", "second"],
"`ShowWordCompletions` action should show word completions" "`ShowWordCompletions` action should show word completions"
); );
} else { }
_ => {
panic!("expected completion menu to be open"); panic!("expected completion menu to be open");
} }
}); },
);
cx.simulate_keystroke("l"); cx.simulate_keystroke("l");
cx.executor().run_until_parked(); cx.executor().run_until_parked();
cx.condition(|editor, _| editor.context_menu_visible()) cx.condition(|editor, _| editor.context_menu_visible())
.await; .await;
cx.update_editor(|editor, _, _| { cx.update_editor(|editor, _, _| {
if let Some(CodeContextMenu::Completions(menu)) = editor.context_menu.borrow_mut().as_ref() match editor.context_menu.borrow_mut().as_ref()
{ { Some(CodeContextMenu::Completions(menu)) => {
assert_eq!( assert_eq!(
completion_menu_entries(&menu), completion_menu_entries(&menu),
&["last"], &["last"],
"After showing word completions, further editing should filter them and not query the LSP" "After showing word completions, further editing should filter them and not query the LSP"
); );
} else { } _ => {
panic!("expected completion menu to be open"); panic!("expected completion menu to be open");
} }}
}); });
} }
@@ -9719,16 +9723,16 @@ async fn test_word_completions_usually_skip_digits(cx: &mut TestAppContext) {
cx.condition(|editor, _| editor.context_menu_visible()) cx.condition(|editor, _| editor.context_menu_visible())
.await; .await;
cx.update_editor(|editor, window, cx| { cx.update_editor(|editor, window, cx| {
if let Some(CodeContextMenu::Completions(menu)) = editor.context_menu.borrow_mut().as_ref() match editor.context_menu.borrow_mut().as_ref()
{ { Some(CodeContextMenu::Completions(menu)) => {
assert_eq!( assert_eq!(
completion_menu_entries(&menu), completion_menu_entries(&menu),
&["let"], &["let"],
"With no digits in the completion query, no digits should be in the word completions" "With no digits in the completion query, no digits should be in the word completions"
); );
} else { } _ => {
panic!("expected completion menu to be open"); panic!("expected completion menu to be open");
} }}
editor.cancel(&Cancel, window, cx); editor.cancel(&Cancel, window, cx);
}); });
@@ -9745,13 +9749,13 @@ async fn test_word_completions_usually_skip_digits(cx: &mut TestAppContext) {
cx.condition(|editor, _| editor.context_menu_visible()) cx.condition(|editor, _| editor.context_menu_visible())
.await; .await;
cx.update_editor(|editor, _, _| { cx.update_editor(|editor, _, _| {
if let Some(CodeContextMenu::Completions(menu)) = editor.context_menu.borrow_mut().as_ref() match editor.context_menu.borrow_mut().as_ref()
{ { Some(CodeContextMenu::Completions(menu)) => {
assert_eq!(completion_menu_entries(&menu), &["33", "35f32"], "The digit is in the completion query, \ assert_eq!(completion_menu_entries(&menu), &["33", "35f32"], "The digit is in the completion query, \
return matching words with digits (`33`, `35f32`) but exclude query duplicates (`3`)"); return matching words with digits (`33`, `35f32`) but exclude query duplicates (`3`)");
} else { } _ => {
panic!("expected completion menu to be open"); panic!("expected completion menu to be open");
} }}
}); });
} }
@@ -9914,8 +9918,8 @@ async fn test_multiline_completion(cx: &mut TestAppContext) {
editor.update(cx, |editor, _| { editor.update(cx, |editor, _| {
assert!(editor.context_menu_visible()); assert!(editor.context_menu_visible());
if let Some(CodeContextMenu::Completions(menu)) = editor.context_menu.borrow_mut().as_ref() match editor.context_menu.borrow_mut().as_ref()
{ { Some(CodeContextMenu::Completions(menu)) => {
let completion_labels = menu let completion_labels = menu
.completions .completions
.borrow() .borrow()
@@ -9944,9 +9948,9 @@ async fn test_multiline_completion(cx: &mut TestAppContext) {
"Adjusted completion items should still keep their filter ranges for the entire label. Item: {completion:?}" "Adjusted completion items should still keep their filter ranges for the entire label. Item: {completion:?}"
); );
} }
} else { } _ => {
panic!("expected completion menu to be open"); panic!("expected completion menu to be open");
} }}
}); });
} }
@@ -9981,39 +9985,45 @@ async fn test_completion_page_up_down_keys(cx: &mut TestAppContext) {
cx.simulate_keystroke("."); cx.simulate_keystroke(".");
cx.executor().run_until_parked(); cx.executor().run_until_parked();
cx.update_editor(|editor, _, _| { cx.update_editor(
if let Some(CodeContextMenu::Completions(menu)) = editor.context_menu.borrow_mut().as_ref() |editor, _, _| match editor.context_menu.borrow_mut().as_ref() {
{ Some(CodeContextMenu::Completions(menu)) => {
assert_eq!(completion_menu_entries(&menu), &["first", "last"]); assert_eq!(completion_menu_entries(&menu), &["first", "last"]);
} else { }
_ => {
panic!("expected completion menu to be open"); panic!("expected completion menu to be open");
} }
}); },
);
cx.update_editor(|editor, window, cx| { cx.update_editor(|editor, window, cx| {
editor.move_page_down(&MovePageDown::default(), window, cx); editor.move_page_down(&MovePageDown::default(), window, cx);
if let Some(CodeContextMenu::Completions(menu)) = editor.context_menu.borrow_mut().as_ref() match editor.context_menu.borrow_mut().as_ref() {
{ Some(CodeContextMenu::Completions(menu)) => {
assert!( assert!(
menu.selected_item == 1, menu.selected_item == 1,
"expected PageDown to select the last item from the context menu" "expected PageDown to select the last item from the context menu"
); );
} else { }
_ => {
panic!("expected completion menu to stay open after PageDown"); panic!("expected completion menu to stay open after PageDown");
} }
}
}); });
cx.update_editor(|editor, window, cx| { cx.update_editor(|editor, window, cx| {
editor.move_page_up(&MovePageUp::default(), window, cx); editor.move_page_up(&MovePageUp::default(), window, cx);
if let Some(CodeContextMenu::Completions(menu)) = editor.context_menu.borrow_mut().as_ref() match editor.context_menu.borrow_mut().as_ref() {
{ Some(CodeContextMenu::Completions(menu)) => {
assert!( assert!(
menu.selected_item == 0, menu.selected_item == 0,
"expected PageUp to select the first item from the context menu" "expected PageUp to select the first item from the context menu"
); );
} else { }
_ => {
panic!("expected completion menu to stay open after PageUp"); panic!("expected completion menu to stay open after PageUp");
} }
}
}); });
} }
@@ -10074,17 +10084,19 @@ async fn test_completion_sort(cx: &mut TestAppContext) {
}); });
cx.executor().run_until_parked(); cx.executor().run_until_parked();
cx.update_editor(|editor, _, _| { cx.update_editor(
if let Some(CodeContextMenu::Completions(menu)) = editor.context_menu.borrow_mut().as_ref() |editor, _, _| match editor.context_menu.borrow_mut().as_ref() {
{ Some(CodeContextMenu::Completions(menu)) => {
assert_eq!( assert_eq!(
completion_menu_entries(&menu), completion_menu_entries(&menu),
&["r", "ret", "Range", "return"] &["r", "ret", "Range", "return"]
); );
} else { }
_ => {
panic!("expected completion menu to be open"); panic!("expected completion menu to be open");
} }
}); },
);
} }
#[gpui::test] #[gpui::test]
@@ -13056,42 +13068,48 @@ async fn test_completions_in_languages_with_extra_word_characters(cx: &mut TestA
// word character in the 'element' scope, which contains the cursor. // word character in the 'element' scope, which contains the cursor.
cx.simulate_keystroke("-"); cx.simulate_keystroke("-");
cx.executor().run_until_parked(); cx.executor().run_until_parked();
cx.update_editor(|editor, _, _| { cx.update_editor(
if let Some(CodeContextMenu::Completions(menu)) = editor.context_menu.borrow_mut().as_ref() |editor, _, _| match editor.context_menu.borrow_mut().as_ref() {
{ Some(CodeContextMenu::Completions(menu)) => {
assert_eq!( assert_eq!(
completion_menu_entries(&menu), completion_menu_entries(&menu),
&["bg-red", "bg-blue", "bg-yellow"] &["bg-red", "bg-blue", "bg-yellow"]
); );
} else { }
_ => {
panic!("expected completion menu to be open"); panic!("expected completion menu to be open");
} }
}); },
);
cx.simulate_keystroke("l"); cx.simulate_keystroke("l");
cx.executor().run_until_parked(); cx.executor().run_until_parked();
cx.update_editor(|editor, _, _| { cx.update_editor(
if let Some(CodeContextMenu::Completions(menu)) = editor.context_menu.borrow_mut().as_ref() |editor, _, _| match editor.context_menu.borrow_mut().as_ref() {
{ Some(CodeContextMenu::Completions(menu)) => {
assert_eq!(completion_menu_entries(&menu), &["bg-blue", "bg-yellow"]); assert_eq!(completion_menu_entries(&menu), &["bg-blue", "bg-yellow"]);
} else { }
_ => {
panic!("expected completion menu to be open"); panic!("expected completion menu to be open");
} }
}); },
);
// When filtering completions, consider the character after the '-' to // When filtering completions, consider the character after the '-' to
// be the start of a subword. // be the start of a subword.
cx.set_state(r#"<p class="yelˇ" />"#); cx.set_state(r#"<p class="yelˇ" />"#);
cx.simulate_keystroke("l"); cx.simulate_keystroke("l");
cx.executor().run_until_parked(); cx.executor().run_until_parked();
cx.update_editor(|editor, _, _| { cx.update_editor(
if let Some(CodeContextMenu::Completions(menu)) = editor.context_menu.borrow_mut().as_ref() |editor, _, _| match editor.context_menu.borrow_mut().as_ref() {
{ Some(CodeContextMenu::Completions(menu)) => {
assert_eq!(completion_menu_entries(&menu), &["bg-yellow"]); assert_eq!(completion_menu_entries(&menu), &["bg-yellow"]);
} else { }
_ => {
panic!("expected completion menu to be open"); panic!("expected completion menu to be open");
} }
}); },
);
} }
fn completion_menu_entries(menu: &CompletionsMenu) -> Vec<String> { fn completion_menu_entries(menu: &CompletionsMenu) -> Vec<String> {
@@ -18691,7 +18709,7 @@ fn assert_selection_ranges(marked_text: &str, editor: &mut Editor, cx: &mut Cont
pub fn handle_signature_help_request( pub fn handle_signature_help_request(
cx: &mut EditorLspTestContext, cx: &mut EditorLspTestContext,
mocked_response: lsp::SignatureHelp, mocked_response: lsp::SignatureHelp,
) -> impl Future<Output = ()> { ) -> impl Future<Output = ()> + use<> {
let mut request = let mut request =
cx.set_request_handler::<lsp::request::SignatureHelpRequest, _, _>(move |_, _, _| { cx.set_request_handler::<lsp::request::SignatureHelpRequest, _, _>(move |_, _, _| {
let mocked_response = mocked_response.clone(); let mocked_response = mocked_response.clone();
@@ -18711,7 +18729,7 @@ pub fn handle_completion_request(
marked_string: &str, marked_string: &str,
completions: Vec<&'static str>, completions: Vec<&'static str>,
counter: Arc<AtomicUsize>, counter: Arc<AtomicUsize>,
) -> impl Future<Output = ()> { ) -> impl Future<Output = ()> + use<> {
let complete_from_marker: TextRangeMarker = '|'.into(); let complete_from_marker: TextRangeMarker = '|'.into();
let replace_range_marker: TextRangeMarker = ('<', '>').into(); let replace_range_marker: TextRangeMarker = ('<', '>').into();
let (_, mut marked_ranges) = marked_text_ranges_by( let (_, mut marked_ranges) = marked_text_ranges_by(
@@ -18758,7 +18776,7 @@ pub fn handle_completion_request(
fn handle_resolve_completion_request( fn handle_resolve_completion_request(
cx: &mut EditorLspTestContext, cx: &mut EditorLspTestContext,
edits: Option<Vec<(&'static str, &'static str)>>, edits: Option<Vec<(&'static str, &'static str)>>,
) -> impl Future<Output = ()> { ) -> impl Future<Output = ()> + use<> {
let edits = edits.map(|edits| { let edits = edits.map(|edits| {
edits edits
.iter() .iter()

View File

@@ -432,69 +432,96 @@ impl EditorElement {
register_action(editor, window, Editor::expand_all_diff_hunks); register_action(editor, window, Editor::expand_all_diff_hunks);
register_action(editor, window, |editor, action, window, cx| { register_action(editor, window, |editor, action, window, cx| {
if let Some(task) = editor.format(action, window, cx) { match editor.format(action, window, cx) {
Some(task) => {
task.detach_and_notify_err(window, cx); task.detach_and_notify_err(window, cx);
} else { }
_ => {
cx.propagate(); cx.propagate();
} }
}
}); });
register_action(editor, window, |editor, action, window, cx| { register_action(editor, window, |editor, action, window, cx| {
if let Some(task) = editor.format_selections(action, window, cx) { match editor.format_selections(action, window, cx) {
Some(task) => {
task.detach_and_notify_err(window, cx); task.detach_and_notify_err(window, cx);
} else { }
_ => {
cx.propagate(); cx.propagate();
} }
}
}); });
register_action(editor, window, |editor, action, window, cx| { register_action(editor, window, |editor, action, window, cx| {
if let Some(task) = editor.organize_imports(action, window, cx) { match editor.organize_imports(action, window, cx) {
Some(task) => {
task.detach_and_notify_err(window, cx); task.detach_and_notify_err(window, cx);
} else { }
_ => {
cx.propagate(); cx.propagate();
} }
}
}); });
register_action(editor, window, Editor::restart_language_server); register_action(editor, window, Editor::restart_language_server);
register_action(editor, window, Editor::show_character_palette); register_action(editor, window, Editor::show_character_palette);
register_action(editor, window, |editor, action, window, cx| { register_action(editor, window, |editor, action, window, cx| {
if let Some(task) = editor.confirm_completion(action, window, cx) { match editor.confirm_completion(action, window, cx) {
Some(task) => {
task.detach_and_notify_err(window, cx); task.detach_and_notify_err(window, cx);
} else { }
_ => {
cx.propagate(); cx.propagate();
} }
}
}); });
register_action(editor, window, |editor, action, window, cx| { register_action(editor, window, |editor, action, window, cx| {
if let Some(task) = editor.compose_completion(action, window, cx) { match editor.compose_completion(action, window, cx) {
Some(task) => {
task.detach_and_notify_err(window, cx); task.detach_and_notify_err(window, cx);
} else { }
_ => {
cx.propagate(); cx.propagate();
} }
}
}); });
register_action(editor, window, |editor, action, window, cx| { register_action(editor, window, |editor, action, window, cx| {
if let Some(task) = editor.confirm_code_action(action, window, cx) { match editor.confirm_code_action(action, window, cx) {
Some(task) => {
task.detach_and_notify_err(window, cx); task.detach_and_notify_err(window, cx);
} else { }
_ => {
cx.propagate(); cx.propagate();
} }
}
}); });
register_action(editor, window, |editor, action, window, cx| { register_action(editor, window, |editor, action, window, cx| {
if let Some(task) = editor.rename(action, window, cx) { match editor.rename(action, window, cx) {
Some(task) => {
task.detach_and_notify_err(window, cx); task.detach_and_notify_err(window, cx);
} else { }
_ => {
cx.propagate(); cx.propagate();
} }
}
}); });
register_action(editor, window, |editor, action, window, cx| { register_action(editor, window, |editor, action, window, cx| {
if let Some(task) = editor.confirm_rename(action, window, cx) { match editor.confirm_rename(action, window, cx) {
Some(task) => {
task.detach_and_notify_err(window, cx); task.detach_and_notify_err(window, cx);
} else { }
_ => {
cx.propagate(); cx.propagate();
} }
}
}); });
register_action(editor, window, |editor, action, window, cx| { register_action(editor, window, |editor, action, window, cx| {
if let Some(task) = editor.find_all_references(action, window, cx) { match editor.find_all_references(action, window, cx) {
Some(task) => {
task.detach_and_log_err(cx); task.detach_and_log_err(cx);
} else { }
_ => {
cx.propagate(); cx.propagate();
} }
}
}); });
register_action(editor, window, Editor::show_signature_help); register_action(editor, window, Editor::show_signature_help);
register_action(editor, window, Editor::next_edit_prediction); register_action(editor, window, Editor::next_edit_prediction);
@@ -1097,10 +1124,12 @@ impl EditorElement {
selections.push((player, layouts)); selections.push((player, layouts));
} }
if let Some(collaboration_hub) = &editor.collaboration_hub { match &editor.collaboration_hub {
Some(collaboration_hub) => {
// When following someone, render the local selections in their color. // When following someone, render the local selections in their color.
if let Some(leader_id) = editor.leader_peer_id { if let Some(leader_id) = editor.leader_peer_id {
if let Some(collaborator) = collaboration_hub.collaborators(cx).get(&leader_id) if let Some(collaborator) =
collaboration_hub.collaborators(cx).get(&leader_id)
{ {
if let Some(participant_index) = collaboration_hub if let Some(participant_index) = collaboration_hub
.user_participant_indices(cx) .user_participant_indices(cx)
@@ -1154,7 +1183,9 @@ impl EditorElement {
} }
selections.extend(remote_selections.into_values()); selections.extend(remote_selections.into_values());
} else if !editor.is_focused(window) && editor.show_cursor_when_unfocused { }
_ => {
if !editor.is_focused(window) && editor.show_cursor_when_unfocused {
let layouts = snapshot let layouts = snapshot
.buffer_snapshot .buffer_snapshot
.selections_in_range(&(start_anchor..end_anchor), true) .selections_in_range(&(start_anchor..end_anchor), true)
@@ -1173,6 +1204,8 @@ impl EditorElement {
let player = editor.current_user_player_color(cx); let player = editor.current_user_player_color(cx);
selections.push((player, layouts)); selections.push((player, layouts));
} }
}
}
}); });
(selections, active_rows, newest_selection_head) (selections, active_rows, newest_selection_head)
} }
@@ -2056,20 +2089,17 @@ impl EditorElement {
cx: &mut App, cx: &mut App,
) -> Vec<AnyElement> { ) -> Vec<AnyElement> {
self.editor.update(cx, |editor, cx| { self.editor.update(cx, |editor, cx| {
let active_task_indicator_row = let active_task_indicator_row = match editor.context_menu.borrow().as_ref() {
if let Some(crate::CodeContextMenu::CodeActions(CodeActionsMenu { Some(crate::CodeContextMenu::CodeActions(CodeActionsMenu {
deployed_from_indicator, deployed_from_indicator,
actions, actions,
.. ..
})) = editor.context_menu.borrow().as_ref() })) => actions
{
actions
.tasks .tasks
.as_ref() .as_ref()
.map(|tasks| tasks.position.to_display_point(snapshot).row()) .map(|tasks| tasks.position.to_display_point(snapshot).row())
.or(*deployed_from_indicator) .or(*deployed_from_indicator),
} else { _ => None,
None
}; };
let offset_range_start = let offset_range_start =
@@ -4079,11 +4109,12 @@ impl EditorElement {
); );
let maybe_element = self.editor.update(cx, |editor, cx| { let maybe_element = self.editor.update(cx, |editor, cx| {
if let Some(popover) = editor.signature_help_state.popover_mut() { match editor.signature_help_state.popover_mut() {
Some(popover) => {
let element = popover.render(max_size, cx); let element = popover.render(max_size, cx);
Some(element) Some(element)
} else { }
None _ => None,
} }
}); });
if let Some(mut element) = maybe_element { if let Some(mut element) = maybe_element {
@@ -4189,7 +4220,11 @@ impl EditorElement {
None; None;
for (&new_row, &new_background) in &layout.highlighted_rows { for (&new_row, &new_background) in &layout.highlighted_rows {
match &mut current_paint { match &mut current_paint {
Some((current_background, current_range, mut edges)) => { &mut Some((
ref mut current_background,
ref mut current_range,
mut edges,
)) => {
let current_background = *current_background; let current_background = *current_background;
let new_range_started = current_background != new_background let new_range_started = current_background != new_background
|| current_range.end.next_row() != new_row; || current_range.end.next_row() != new_row;
@@ -4916,7 +4951,7 @@ impl EditorElement {
} }
editor.update(cx, |editor, cx| { editor.update(cx, |editor, cx| {
if let Some((scrollbar_layout, axis)) = event match event
.pressed_button .pressed_button
.filter(|button| *button == MouseButton::Left) .filter(|button| *button == MouseButton::Left)
.and(editor.scroll_manager.dragging_scrollbar_axis()) .and(editor.scroll_manager.dragging_scrollbar_axis())
@@ -4924,8 +4959,8 @@ impl EditorElement {
scrollbars_layout scrollbars_layout
.iter_scrollbars() .iter_scrollbars()
.find(|(_, a)| *a == axis) .find(|(_, a)| *a == axis)
}) }) {
{ Some((scrollbar_layout, axis)) => {
let ScrollbarLayout { let ScrollbarLayout {
hitbox, hitbox,
text_unit_size, text_unit_size,
@@ -4943,9 +4978,11 @@ impl EditorElement {
editor.set_scroll_position(position, window, cx); editor.set_scroll_position(position, window, cx);
} }
cx.stop_propagation(); cx.stop_propagation();
} else { }
_ => {
editor.scroll_manager.reset_scrollbar_dragging_state(cx); editor.scroll_manager.reset_scrollbar_dragging_state(cx);
} }
}
if scrollbars_layout.get_hovered_axis(window).is_some() { if scrollbars_layout.get_hovered_axis(window).is_some() {
editor.scroll_manager.show_scrollbars(window, cx); editor.scroll_manager.show_scrollbars(window, cx);
@@ -5655,13 +5692,12 @@ pub struct AcceptEditPredictionBinding(pub(crate) Option<gpui::KeyBinding>);
impl AcceptEditPredictionBinding { impl AcceptEditPredictionBinding {
pub fn keystroke(&self) -> Option<&Keystroke> { pub fn keystroke(&self) -> Option<&Keystroke> {
if let Some(binding) = self.0.as_ref() { match self.0.as_ref() {
match &binding.keystrokes() { Some(binding) => match &binding.keystrokes() {
[keystroke] => Some(keystroke), [keystroke] => Some(keystroke),
_ => None, _ => None,
} },
} else { _ => None,
None
} }
} }
} }
@@ -5949,7 +5985,8 @@ impl LineWithInvisibles {
is_tab: false, is_tab: false,
replacement: None, replacement: None,
}]) { }]) {
if let Some(replacement) = highlighted_chunk.replacement { match highlighted_chunk.replacement {
Some(replacement) => {
if !line.is_empty() { if !line.is_empty() {
let shaped_line = window let shaped_line = window
.text_system() .text_system()
@@ -6004,10 +6041,9 @@ impl LineWithInvisibles {
}); });
} }
ChunkReplacement::Str(x) => { ChunkReplacement::Str(x) => {
let text_style = if let Some(style) = highlighted_chunk.style { let text_style = match highlighted_chunk.style {
Cow::Owned(text_style.clone().highlight(style)) Some(style) => Cow::Owned(text_style.clone().highlight(style)),
} else { _ => Cow::Borrowed(text_style),
Cow::Borrowed(text_style)
}; };
let run = TextRun { let run = TextRun {
@@ -6029,7 +6065,8 @@ impl LineWithInvisibles {
fragments.push(LineFragment::Text(line_layout)) fragments.push(LineFragment::Text(line_layout))
} }
} }
} else { }
_ => {
for (ix, mut line_chunk) in highlighted_chunk.text.split('\n').enumerate() { for (ix, mut line_chunk) in highlighted_chunk.text.split('\n').enumerate() {
if ix > 0 { if ix > 0 {
let shaped_line = window let shaped_line = window
@@ -6058,10 +6095,9 @@ impl LineWithInvisibles {
} }
if !line_chunk.is_empty() && !line_exceeded_max_len { if !line_chunk.is_empty() && !line_exceeded_max_len {
let text_style = if let Some(style) = highlighted_chunk.style { let text_style = match highlighted_chunk.style {
Cow::Owned(text_style.clone().highlight(style)) Some(style) => Cow::Owned(text_style.clone().highlight(style)),
} else { _ => Cow::Borrowed(text_style),
Cow::Borrowed(text_style)
}; };
if line.len() + line_chunk.len() > max_line_len { if line.len() + line_chunk.len() > max_line_len {
@@ -6117,6 +6153,7 @@ impl LineWithInvisibles {
} }
} }
} }
}
layouts layouts
} }
@@ -8067,17 +8104,18 @@ impl PositionMap {
let x = position.x + (scroll_position.x * self.em_width); let x = position.x + (scroll_position.x * self.em_width);
let row = ((y / self.line_height) + scroll_position.y) as u32; let row = ((y / self.line_height) + scroll_position.y) as u32;
let (column, x_overshoot_after_line_end) = if let Some(line) = self let (column, x_overshoot_after_line_end) = match self
.line_layouts .line_layouts
.get(row as usize - scroll_position.y as usize) .get(row as usize - scroll_position.y as usize)
{ {
Some(line) => {
if let Some(ix) = line.index_for_x(x) { if let Some(ix) = line.index_for_x(x) {
(ix as u32, px(0.)) (ix as u32, px(0.))
} else { } else {
(line.len as u32, px(0.).max(x - line.width)) (line.len as u32, px(0.).max(x - line.width))
} }
} else { }
(0, x) _ => (0, x),
}; };
let mut exact_unclipped = DisplayPoint::new(DisplayRow(row), column); let mut exact_unclipped = DisplayPoint::new(DisplayRow(row), column);

View File

@@ -192,7 +192,7 @@ impl GitBlame {
&'a mut self, &'a mut self,
rows: &'a [RowInfo], rows: &'a [RowInfo],
cx: &App, cx: &App,
) -> impl 'a + Iterator<Item = Option<BlameEntry>> { ) -> impl 'a + Iterator<Item = Option<BlameEntry>> + use<'a> {
self.sync(cx); self.sync(cx);
let buffer_id = self.buffer_snapshot.remote_id(); let buffer_id = self.buffer_snapshot.remote_id();
@@ -480,15 +480,14 @@ async fn parse_commit_messages(
.and_then(|remote_url| parse_git_remote_url(provider_registry, remote_url)); .and_then(|remote_url| parse_git_remote_url(provider_registry, remote_url));
for (oid, message) in messages { for (oid, message) in messages {
let permalink = if let Some((provider, git_remote)) = parsed_remote_url.as_ref() { let permalink = match parsed_remote_url.as_ref() {
Some(provider.build_commit_permalink( Some((provider, git_remote)) => Some(provider.build_commit_permalink(
git_remote, git_remote,
git::BuildCommitPermalinkParams { git::BuildCommitPermalinkParams {
sha: oid.to_string().as_str(), sha: oid.to_string().as_str(),
}, },
)) )),
} else { _ => None,
None
}; };
let remote = parsed_remote_url let remote = parsed_remote_url

View File

@@ -472,11 +472,9 @@ pub fn show_link_definition(
_ => GotoDefinitionKind::Type, _ => GotoDefinitionKind::Type,
}; };
let (mut hovered_link_state, is_cached) = let (mut hovered_link_state, is_cached) = match editor.hovered_link_state.take() {
if let Some(existing) = editor.hovered_link_state.take() { Some(existing) => (existing, true),
(existing, true) _ => (
} else {
(
HoveredLinkState { HoveredLinkState {
last_trigger_point: trigger_point.clone(), last_trigger_point: trigger_point.clone(),
symbol_range: None, symbol_range: None,
@@ -485,7 +483,7 @@ pub fn show_link_definition(
task: None, task: None,
}, },
false, false,
) ),
}; };
if editor.pending_rename.is_some() { if editor.pending_rename.is_some() {
@@ -537,9 +535,9 @@ pub fn show_link_definition(
hovered_link_state.task = Some(cx.spawn_in(window, async move |this, cx| { hovered_link_state.task = Some(cx.spawn_in(window, async move |this, cx| {
async move { async move {
let result = match &trigger_point { let result = match &trigger_point {
TriggerPoint::Text(_) => { TriggerPoint::Text(_) => match find_url(&buffer, buffer_position, cx.clone()) {
if let Some((url_range, url)) = find_url(&buffer, buffer_position, cx.clone()) { Some((url_range, url)) => this
this.update(cx, |_, _| { .update(cx, |_, _| {
let range = maybe!({ let range = maybe!({
let start = let start =
snapshot.anchor_in_excerpt(excerpt_id, url_range.start)?; snapshot.anchor_in_excerpt(excerpt_id, url_range.start)?;
@@ -548,24 +546,31 @@ pub fn show_link_definition(
}); });
(range, vec![HoverLink::Url(url)]) (range, vec![HoverLink::Url(url)])
}) })
.ok() .ok(),
} else if let Some((filename_range, filename)) = _ => match find_file(&buffer, project.clone(), buffer_position, cx).await {
find_file(&buffer, project.clone(), buffer_position, cx).await Some((filename_range, filename)) => {
{
let range = maybe!({ let range = maybe!({
let start = let start =
snapshot.anchor_in_excerpt(excerpt_id, filename_range.start)?; snapshot.anchor_in_excerpt(excerpt_id, filename_range.start)?;
let end = snapshot.anchor_in_excerpt(excerpt_id, filename_range.end)?; let end =
snapshot.anchor_in_excerpt(excerpt_id, filename_range.end)?;
Some(RangeInEditor::Text(start..end)) Some(RangeInEditor::Text(start..end))
}); });
Some((range, vec![HoverLink::File(filename)])) Some((range, vec![HoverLink::File(filename)]))
} else if let Some(provider) = provider { }
_ => match provider {
Some(provider) => {
let task = cx.update(|_, cx| { let task = cx.update(|_, cx| {
provider.definitions(&buffer, buffer_position, preferred_kind, cx) provider.definitions(
&buffer,
buffer_position,
preferred_kind,
cx,
)
})?; })?;
if let Some(task) = task { match task {
task.await.ok().map(|definition_result| { Some(task) => task.await.ok().map(|definition_result| {
( (
definition_result.iter().find_map(|link| { definition_result.iter().find_map(|link| {
link.origin.as_ref().and_then(|origin| { link.origin.as_ref().and_then(|origin| {
@@ -573,21 +578,26 @@ pub fn show_link_definition(
excerpt_id, excerpt_id,
origin.range.start, origin.range.start,
)?; )?;
let end = snapshot let end = snapshot.anchor_in_excerpt(
.anchor_in_excerpt(excerpt_id, origin.range.end)?; excerpt_id,
origin.range.end,
)?;
Some(RangeInEditor::Text(start..end)) Some(RangeInEditor::Text(start..end))
}) })
}), }),
definition_result.into_iter().map(HoverLink::Text).collect(), definition_result
.into_iter()
.map(HoverLink::Text)
.collect(),
) )
}) }),
} else { _ => None,
None
}
} else {
None
} }
} }
_ => None,
},
},
},
TriggerPoint::InlayHint(highlight, lsp_location, server_id) => Some(( TriggerPoint::InlayHint(highlight, lsp_location, server_id) => Some((
Some(RangeInEditor::Inlay(highlight.clone())), Some(RangeInEditor::Inlay(highlight.clone())),
vec![HoverLink::InlayHint(lsp_location.clone(), *server_id)], vec![HoverLink::InlayHint(lsp_location.clone(), *server_id)],
@@ -606,7 +616,8 @@ pub fn show_link_definition(
.as_ref() .as_ref()
.and_then(|(symbol_range, _)| symbol_range.clone()); .and_then(|(symbol_range, _)| symbol_range.clone());
if let Some((symbol_range, definitions)) = result { match result {
Some((symbol_range, definitions)) => {
hovered_link_state.links = definitions; hovered_link_state.links = definitions;
let underline_hovered_link = !hovered_link_state.links.is_empty() let underline_hovered_link = !hovered_link_state.links.is_empty()
@@ -639,14 +650,24 @@ pub fn show_link_definition(
match highlight_range { match highlight_range {
RangeInEditor::Text(text_range) => editor RangeInEditor::Text(text_range) => editor
.highlight_text::<HoveredLinkState>(vec![text_range], style, cx), .highlight_text::<HoveredLinkState>(
vec![text_range],
style,
cx,
),
RangeInEditor::Inlay(highlight) => editor RangeInEditor::Inlay(highlight) => editor
.highlight_inlays::<HoveredLinkState>(vec![highlight], style, cx), .highlight_inlays::<HoveredLinkState>(
vec![highlight],
style,
cx,
),
} }
} }
} else { }
_ => {
editor.hide_hovered_link(cx); editor.hide_hovered_link(cx);
} }
}
})?; })?;
Ok::<_, anyhow::Error>(()) Ok::<_, anyhow::Error>(())

View File

@@ -289,7 +289,8 @@ fn show_hover(
// Find the entry with the most specific range // Find the entry with the most specific range
.min_by_key(|entry| entry.range.len()); .min_by_key(|entry| entry.range.len());
let diagnostic_popover = if let Some(local_diagnostic) = local_diagnostic { let diagnostic_popover = match local_diagnostic {
Some(local_diagnostic) => {
let text = match local_diagnostic.diagnostic.source { let text = match local_diagnostic.diagnostic.source {
Some(ref source) => { Some(ref source) => {
format!("{source}: {}", local_diagnostic.diagnostic.message) format!("{source}: {}", local_diagnostic.diagnostic.message)
@@ -348,7 +349,9 @@ fn show_hover(
}); });
let markdown_style = MarkdownStyle { let markdown_style = MarkdownStyle {
base_text_style, base_text_style,
selection_background_color: { cx.theme().players().local().selection }, selection_background_color: {
cx.theme().players().local().selection
},
link: TextStyleRefinement { link: TextStyleRefinement {
underline: Some(gpui::UnderlineStyle { underline: Some(gpui::UnderlineStyle {
thickness: px(1.), thickness: px(1.),
@@ -372,43 +375,48 @@ fn show_hover(
keyboard_grace: Rc::new(RefCell::new(ignore_timeout)), keyboard_grace: Rc::new(RefCell::new(ignore_timeout)),
anchor: Some(anchor), anchor: Some(anchor),
}) })
} else { }
None _ => None,
}; };
this.update(cx, |this, _| { this.update(cx, |this, _| {
this.hover_state.diagnostic_popover = diagnostic_popover; this.hover_state.diagnostic_popover = diagnostic_popover;
})?; })?;
let invisible_char = if let Some(invisible) = snapshot let invisible_char = match snapshot
.buffer_snapshot .buffer_snapshot
.chars_at(anchor) .chars_at(anchor)
.next() .next()
.filter(|&c| is_invisible(c)) .filter(|&c| is_invisible(c))
{ {
Some(invisible) => {
let after = snapshot.buffer_snapshot.anchor_after( let after = snapshot.buffer_snapshot.anchor_after(
anchor.to_offset(&snapshot.buffer_snapshot) + invisible.len_utf8(), anchor.to_offset(&snapshot.buffer_snapshot) + invisible.len_utf8(),
); );
Some((invisible, anchor..after)) Some((invisible, anchor..after))
} else if let Some(invisible) = snapshot }
_ => {
match snapshot
.buffer_snapshot .buffer_snapshot
.reversed_chars_at(anchor) .reversed_chars_at(anchor)
.next() .next()
.filter(|&c| is_invisible(c)) .filter(|&c| is_invisible(c))
{ {
Some(invisible) => {
let before = snapshot.buffer_snapshot.anchor_before( let before = snapshot.buffer_snapshot.anchor_before(
anchor.to_offset(&snapshot.buffer_snapshot) - invisible.len_utf8(), anchor.to_offset(&snapshot.buffer_snapshot) - invisible.len_utf8(),
); );
Some((invisible, before..anchor)) Some((invisible, before..anchor))
} else { }
None _ => None,
}
}
}; };
let hovers_response = if let Some(hover_request) = hover_request { let hovers_response = match hover_request {
hover_request.await Some(hover_request) => hover_request.await,
} else { _ => Vec::new(),
Vec::new()
}; };
let snapshot = this.update_in(cx, |this, window, cx| this.snapshot(window, cx))?; let snapshot = this.update_in(cx, |this, window, cx| this.snapshot(window, cx))?;
let mut hover_highlights = Vec::with_capacity(hovers_response.len()); let mut hover_highlights = Vec::with_capacity(hovers_response.len());
@@ -543,11 +551,12 @@ async fn parse_blocks(
language: Option<Arc<Language>>, language: Option<Arc<Language>>,
cx: &mut AsyncWindowContext, cx: &mut AsyncWindowContext,
) -> Option<Entity<Markdown>> { ) -> Option<Entity<Markdown>> {
let fallback_language_name = if let Some(ref l) = language { let fallback_language_name = match language {
Some(ref l) => {
let l = Arc::clone(l); let l = Arc::clone(l);
Some(l.lsp_id().clone()) Some(l.lsp_id().clone())
} else { }
None _ => None,
}; };
let combined_text = blocks let combined_text = blocks

View File

@@ -36,7 +36,8 @@ impl Editor {
cx: &mut Context<Editor>, cx: &mut Context<Editor>,
) -> Option<Vec<IndentGuide>> { ) -> Option<Vec<IndentGuide>> {
let show_indent_guides = self.should_show_indent_guides().unwrap_or_else(|| { let show_indent_guides = self.should_show_indent_guides().unwrap_or_else(|| {
if let Some(buffer) = self.buffer().read(cx).as_singleton() { match self.buffer().read(cx).as_singleton() {
Some(buffer) => {
language_settings( language_settings(
buffer.read(cx).language().map(|l| l.name()), buffer.read(cx).language().map(|l| l.name()),
buffer.read(cx).file(), buffer.read(cx).file(),
@@ -44,8 +45,8 @@ impl Editor {
) )
.indent_guides .indent_guides
.enabled .enabled
} else { }
true _ => true,
} }
}); });

Some files were not shown because too many files have changed in this diff Show More