chore: Prepare for Rust edition bump to 2024 (without autofix) (#27791)

Successor to #27779 - in this PR I've applied changes manually, without
futzing with if let lifetimes at all.

Release Notes:

- N/A
This commit is contained in:
Piotr Osiewicz 2025-03-31 20:10:36 +02:00 committed by GitHub
parent d51aa2ffb0
commit 0729d24d77
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
162 changed files with 2333 additions and 1937 deletions

443
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1412,7 +1412,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)

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

View file

@ -687,7 +687,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 {
@ -855,7 +855,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 +875,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

@ -1192,7 +1192,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

View file

@ -3413,7 +3413,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

@ -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

@ -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| {
@ -782,7 +782,12 @@ mod test {
assert_eq!(result.sections[6].label, "summercamp"); assert_eq!(result.sections[6].label, "summercamp");
assert_eq!(result.sections[7].label, separator!("zed/assets/themes")); assert_eq!(result.sections[7].label, separator!("zed/assets/themes"));
assert_eq!(result.text, separator!("zed/assets/themes\n```zed/assets/themes/LICENSE\n1\n```\n\nsummercamp\n```zed/assets/themes/summercamp/LICENSE\n1\n```\n\nsubdir\n```zed/assets/themes/summercamp/subdir/LICENSE\n1\n```\n\nsubsubdir\n```zed/assets/themes/summercamp/subdir/subsubdir/LICENSE\n3\n```\n\n")); assert_eq!(
result.text,
separator!(
"zed/assets/themes\n```zed/assets/themes/LICENSE\n1\n```\n\nsummercamp\n```zed/assets/themes/summercamp/LICENSE\n1\n```\n\nsubdir\n```zed/assets/themes/summercamp/subdir/LICENSE\n1\n```\n\nsubsubdir\n```zed/assets/themes/summercamp/subdir/subsubdir/LICENSE\n3\n```\n\n"
)
);
// Ensure that the project lasts until after the last await // Ensure that the project lasts until after the last await
drop(project); drop(project);

View file

@ -81,7 +81,9 @@ impl Tool for BashTool {
}; };
if worktrees.next().is_some() { if worktrees.next().is_some() {
return Task::ready(Err(anyhow!("'.' is ambiguous in multi-root workspaces. Please specify a root directory explicitly."))); return Task::ready(Err(anyhow!(
"'.' is ambiguous in multi-root workspaces. Please specify a root directory explicitly."
)));
} }
only_worktree.read(cx).abs_path() only_worktree.read(cx).abs_path()

View file

@ -526,7 +526,8 @@ impl EditToolRequest {
} }
} }
write!(&mut output, write!(
&mut output,
"The SEARCH section must exactly match an existing block of lines including all white \ "The SEARCH section must exactly match an existing block of lines including all white \
space, comments, indentation, docstrings, etc." space, comments, indentation, docstrings, etc."
)?; )?;
@ -545,7 +546,8 @@ impl EditToolRequest {
} }
if has_errors { if has_errors {
writeln!(&mut output, writeln!(
&mut output,
"\n\nYou can fix errors by running the tool again. You can include instructions, \ "\n\nYou can fix errors by running the tool again. You can include instructions, \
but errors are part of the conversation so you don't need to repeat them.", but errors are part of the conversation so you don't need to repeat them.",
)?; )?;

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

@ -32,7 +32,7 @@ impl AwsConnector for AwsHttpConnector {
let req = match request.try_into_http1x() { let req = match request.try_into_http1x() {
Ok(req) => req, Ok(req) => req,
Err(err) => { Err(err) => {
return HttpConnectorFuture::ready(Err(ConnectorError::other(err.into(), None))) return HttpConnectorFuture::ready(Err(ConnectorError::other(err.into(), None)));
} }
}; };

View file

@ -433,79 +433,82 @@ impl BufferDiffInner {
let max_point = buffer.max_point(); let max_point = buffer.max_point();
let mut summaries = buffer.summaries_for_anchors_with_payload::<Point, _, _>(anchor_iter); let mut summaries = buffer.summaries_for_anchors_with_payload::<Point, _, _>(anchor_iter);
iter::from_fn(move || loop { iter::from_fn(move || {
let (start_point, (start_anchor, start_base)) = summaries.next()?; loop {
let (mut end_point, (mut end_anchor, end_base)) = summaries.next()?; let (start_point, (start_anchor, start_base)) = summaries.next()?;
let (mut end_point, (mut end_anchor, end_base)) = summaries.next()?;
if !start_anchor.is_valid(buffer) { if !start_anchor.is_valid(buffer) {
continue; continue;
}
if end_point.column > 0 && end_point < max_point {
end_point.row += 1;
end_point.column = 0;
end_anchor = buffer.anchor_before(end_point);
}
let mut secondary_status = DiffHunkSecondaryStatus::NoSecondaryHunk;
let mut has_pending = false;
if start_anchor
.cmp(&pending_hunks_cursor.start().buffer_range.start, buffer)
.is_gt()
{
pending_hunks_cursor.seek_forward(&start_anchor, Bias::Left, buffer);
}
if let Some(pending_hunk) = pending_hunks_cursor.item() {
let mut pending_range = pending_hunk.buffer_range.to_point(buffer);
if pending_range.end.column > 0 {
pending_range.end.row += 1;
pending_range.end.column = 0;
} }
if pending_range == (start_point..end_point) { if end_point.column > 0 && end_point < max_point {
if !buffer.has_edits_since_in_range( end_point.row += 1;
&pending_hunk.buffer_version, end_point.column = 0;
start_anchor..end_anchor, end_anchor = buffer.anchor_before(end_point);
) {
has_pending = true;
secondary_status = pending_hunk.new_status;
}
} }
}
if let (Some(secondary_cursor), false) = (secondary_cursor.as_mut(), has_pending) { let mut secondary_status = DiffHunkSecondaryStatus::NoSecondaryHunk;
let mut has_pending = false;
if start_anchor if start_anchor
.cmp(&secondary_cursor.start().buffer_range.start, buffer) .cmp(&pending_hunks_cursor.start().buffer_range.start, buffer)
.is_gt() .is_gt()
{ {
secondary_cursor.seek_forward(&start_anchor, Bias::Left, buffer); pending_hunks_cursor.seek_forward(&start_anchor, Bias::Left, buffer);
} }
if let Some(secondary_hunk) = secondary_cursor.item() { if let Some(pending_hunk) = pending_hunks_cursor.item() {
let mut secondary_range = secondary_hunk.buffer_range.to_point(buffer); let mut pending_range = pending_hunk.buffer_range.to_point(buffer);
if secondary_range.end.column > 0 { if pending_range.end.column > 0 {
secondary_range.end.row += 1; pending_range.end.row += 1;
secondary_range.end.column = 0; pending_range.end.column = 0;
} }
if secondary_range.is_empty() && secondary_hunk.diff_base_byte_range.is_empty()
if pending_range == (start_point..end_point) {
if !buffer.has_edits_since_in_range(
&pending_hunk.buffer_version,
start_anchor..end_anchor,
) {
has_pending = true;
secondary_status = pending_hunk.new_status;
}
}
}
if let (Some(secondary_cursor), false) = (secondary_cursor.as_mut(), has_pending) {
if start_anchor
.cmp(&secondary_cursor.start().buffer_range.start, buffer)
.is_gt()
{ {
// ignore secondary_cursor.seek_forward(&start_anchor, Bias::Left, buffer);
} else if secondary_range == (start_point..end_point) { }
secondary_status = DiffHunkSecondaryStatus::HasSecondaryHunk;
} else if secondary_range.start <= end_point { if let Some(secondary_hunk) = secondary_cursor.item() {
secondary_status = DiffHunkSecondaryStatus::OverlapsWithSecondaryHunk; let mut secondary_range = secondary_hunk.buffer_range.to_point(buffer);
if secondary_range.end.column > 0 {
secondary_range.end.row += 1;
secondary_range.end.column = 0;
}
if secondary_range.is_empty()
&& secondary_hunk.diff_base_byte_range.is_empty()
{
// ignore
} else if secondary_range == (start_point..end_point) {
secondary_status = DiffHunkSecondaryStatus::HasSecondaryHunk;
} else if secondary_range.start <= end_point {
secondary_status = DiffHunkSecondaryStatus::OverlapsWithSecondaryHunk;
}
} }
} }
}
return Some(DiffHunk { return Some(DiffHunk {
range: start_point..end_point, range: start_point..end_point,
diff_base_byte_range: start_base..end_base, diff_base_byte_range: start_base..end_base,
buffer_range: start_anchor..end_anchor, buffer_range: start_anchor..end_anchor,
secondary_status, secondary_status,
}); });
}
}) })
} }
@ -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

@ -243,7 +243,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 +665,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 {

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

@ -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

@ -465,7 +465,7 @@ mod linux {
match fork::fork() { match fork::fork() {
Ok(Fork::Parent(_)) => Ok(()), Ok(Fork::Parent(_)) => Ok(()),
Ok(Fork::Child) => { Ok(Fork::Child) => {
std::env::set_var(FORCE_CLI_MODE_ENV_VAR_NAME, ""); unsafe { std::env::set_var(FORCE_CLI_MODE_ENV_VAR_NAME, "") };
if let Err(_) = fork::setsid() { if let Err(_) = fork::setsid() {
eprintln!("failed to setsid: {}", std::io::Error::last_os_error()); eprintln!("failed to setsid: {}", std::io::Error::last_os_error());
process::exit(1); process::exit(1);
@ -521,7 +521,7 @@ mod flatpak {
paths.push(extra_path.into()); paths.push(extra_path.into());
} }
env::set_var("LD_LIBRARY_PATH", env::join_paths(paths).unwrap()); unsafe { env::set_var("LD_LIBRARY_PATH", env::join_paths(paths).unwrap()) };
} }
/// Restarts outside of the sandbox if currently running within it /// Restarts outside of the sandbox if currently running within it
@ -562,7 +562,9 @@ mod flatpak {
{ {
if args.zed.is_none() { if args.zed.is_none() {
args.zed = Some("/app/libexec/zed-editor".into()); args.zed = Some("/app/libexec/zed-editor".into());
env::set_var("ZED_UPDATE_EXPLANATION", "Please use flatpak to update zed"); unsafe {
env::set_var("ZED_UPDATE_EXPLANATION", "Please use flatpak to update zed")
};
} }
} }
args args

View file

@ -817,7 +817,7 @@ impl Client {
| Status::Reauthenticating { .. } | Status::Reauthenticating { .. }
| Status::ReconnectionError { .. } => false, | Status::ReconnectionError { .. } => false,
Status::Connected { .. } | Status::Connecting { .. } | Status::Reconnecting { .. } => { Status::Connected { .. } | Status::Connecting { .. } | Status::Reconnecting { .. } => {
return Ok(()) return Ok(());
} }
Status::UpgradeRequired => return Err(EstablishConnectionError::UpgradeRequired)?, Status::UpgradeRequired => return Err(EstablishConnectionError::UpgradeRequired)?,
}; };
@ -1024,7 +1024,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();
@ -1444,7 +1444,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)
} }
@ -1476,7 +1476,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 +1501,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:{}",

View file

@ -273,14 +273,14 @@ 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(())
} }
// Skip calling this function in tests. // Skip calling this function in tests.
// TestAppContext ends up calling this function on shutdown and it panics when trying to find the TelemetrySettings // TestAppContext ends up calling this function on shutdown and it panics when trying to find the TelemetrySettings
#[cfg(not(any(test, feature = "test-support")))] #[cfg(not(any(test, feature = "test-support")))]
fn shutdown_telemetry(self: &Arc<Self>) -> impl Future<Output = ()> { fn shutdown_telemetry(self: &Arc<Self>) -> impl Future<Output = ()> + use<> {
telemetry::event!("App Closed"); telemetry::event!("App Closed");
// TODO: close final edit period and make sure it's sent // TODO: close final edit period and make sure it's sent
Task::ready(()) Task::ready(())

View file

@ -581,7 +581,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))

View file

@ -534,7 +534,9 @@ async fn poll_stripe_events(
if event_pages.page.has_more { if event_pages.page.has_more {
if pages_of_already_processed_events >= NUMBER_OF_ALREADY_PROCESSED_PAGES_BEFORE_WE_STOP if pages_of_already_processed_events >= NUMBER_OF_ALREADY_PROCESSED_PAGES_BEFORE_WE_STOP
{ {
log::info!("Stripe events: stopping, saw {pages_of_already_processed_events} pages of already-processed events"); log::info!(
"Stripe events: stopping, saw {pages_of_already_processed_events} pages of already-processed events"
);
break; break;
} else { } else {
log::info!("Stripe events: retrieving next page"); log::info!("Stripe events: retrieving next page");

View file

@ -853,7 +853,7 @@ fn db_status_to_proto(
_ => { _ => {
return Err(anyhow!( return Err(anyhow!(
"Unexpected combination of status fields: {entry:?}" "Unexpected combination of status fields: {entry:?}"
)) ));
} }
}; };
Ok(proto::StatusEntry { Ok(proto::StatusEntry {

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

@ -20,7 +20,7 @@ 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); 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

@ -193,7 +193,9 @@ mod tests {
.to_vec(); .to_vec();
assert_eq!( assert_eq!(
String::from_utf8(response_body).unwrap(), String::from_utf8(response_body).unwrap(),
format!("access to {provider:?} models is not available in your region ({country_code})") format!(
"access to {provider:?} models is not available in your region ({country_code})"
)
); );
} }
} }

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

@ -724,7 +724,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,

View file

@ -5103,7 +5103,9 @@ async fn test_project_search(
results.entry(buffer).or_insert(ranges); results.entry(buffer).or_insert(ranges);
} }
SearchResult::LimitReached => { SearchResult::LimitReached => {
panic!("Unexpectedly reached search limit in tests. If you do want to assert limit-reached, change this panic call.") panic!(
"Unexpectedly reached search limit in tests. If you do want to assert limit-reached, change this panic call."
)
} }
}; };
} }
@ -5602,7 +5604,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

@ -279,7 +279,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 +309,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 +387,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 +460,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);
@ -1315,7 +1315,9 @@ impl RandomizedTest for ProjectCollaborationTest {
match (host_file, guest_file) { match (host_file, guest_file) {
(Some(host_file), Some(guest_file)) => { (Some(host_file), Some(guest_file)) => {
assert_eq!(guest_file.path(), host_file.path()); assert_eq!(guest_file.path(), host_file.path());
assert_eq!(guest_file.disk_state(), host_file.disk_state(), assert_eq!(
guest_file.disk_state(),
host_file.disk_state(),
"guest {} disk_state does not match host {} for path {:?} in project {}", "guest {} disk_state does not match host {} for path {:?} in project {}",
guest_user_id, guest_user_id,
host_user_id, host_user_id,
@ -1347,52 +1349,54 @@ impl RandomizedTest for ProjectCollaborationTest {
.base_text_string() .base_text_string()
}); });
assert_eq!( assert_eq!(
guest_diff_base, host_diff_base, guest_diff_base, host_diff_base,
"guest {} diff base does not match host's for path {path:?} in project {project_id}", "guest {} diff base does not match host's for path {path:?} in project {project_id}",
client.username client.username
); );
let host_saved_version = let host_saved_version =
host_buffer.read_with(host_cx, |b, _| b.saved_version().clone()); host_buffer.read_with(host_cx, |b, _| b.saved_version().clone());
let guest_saved_version = let guest_saved_version =
guest_buffer.read_with(client_cx, |b, _| b.saved_version().clone()); guest_buffer.read_with(client_cx, |b, _| b.saved_version().clone());
assert_eq!( assert_eq!(
guest_saved_version, host_saved_version, guest_saved_version, host_saved_version,
"guest {} saved version does not match host's for path {path:?} in project {project_id}", "guest {} saved version does not match host's for path {path:?} in project {project_id}",
client.username client.username
); );
let host_is_dirty = host_buffer.read_with(host_cx, |b, _| b.is_dirty()); let host_is_dirty = host_buffer.read_with(host_cx, |b, _| b.is_dirty());
let guest_is_dirty = guest_buffer.read_with(client_cx, |b, _| b.is_dirty()); let guest_is_dirty = guest_buffer.read_with(client_cx, |b, _| b.is_dirty());
assert_eq!( assert_eq!(
guest_is_dirty, host_is_dirty, guest_is_dirty, host_is_dirty,
"guest {} dirty state does not match host's for path {path:?} in project {project_id}", "guest {} dirty state does not match host's for path {path:?} in project {project_id}",
client.username client.username
); );
let host_saved_mtime = host_buffer.read_with(host_cx, |b, _| b.saved_mtime()); let host_saved_mtime = host_buffer.read_with(host_cx, |b, _| b.saved_mtime());
let guest_saved_mtime = let guest_saved_mtime =
guest_buffer.read_with(client_cx, |b, _| b.saved_mtime()); guest_buffer.read_with(client_cx, |b, _| b.saved_mtime());
assert_eq!( assert_eq!(
guest_saved_mtime, host_saved_mtime, guest_saved_mtime, host_saved_mtime,
"guest {} saved mtime does not match host's for path {path:?} in project {project_id}", "guest {} saved mtime does not match host's for path {path:?} in project {project_id}",
client.username client.username
); );
let host_is_dirty = host_buffer.read_with(host_cx, |b, _| b.is_dirty()); let host_is_dirty = host_buffer.read_with(host_cx, |b, _| b.is_dirty());
let guest_is_dirty = guest_buffer.read_with(client_cx, |b, _| b.is_dirty()); let guest_is_dirty = guest_buffer.read_with(client_cx, |b, _| b.is_dirty());
assert_eq!(guest_is_dirty, host_is_dirty, assert_eq!(
"guest {} dirty status does not match host's for path {path:?} in project {project_id}", guest_is_dirty, host_is_dirty,
client.username "guest {} dirty status does not match host's for path {path:?} in project {project_id}",
); client.username
);
let host_has_conflict = host_buffer.read_with(host_cx, |b, _| b.has_conflict()); let host_has_conflict = host_buffer.read_with(host_cx, |b, _| b.has_conflict());
let guest_has_conflict = let guest_has_conflict =
guest_buffer.read_with(client_cx, |b, _| b.has_conflict()); guest_buffer.read_with(client_cx, |b, _| b.has_conflict());
assert_eq!(guest_has_conflict, host_has_conflict, assert_eq!(
"guest {} conflict status does not match host's for path {path:?} in project {project_id}", guest_has_conflict, host_has_conflict,
client.username "guest {} conflict status does not match host's for path {path:?} in project {project_id}",
); client.username
);
} }
} }
} }

View file

@ -332,7 +332,7 @@ impl ChatPanel {
.color(Color::Muted), .color(Color::Muted),
) )
}), }),
) );
} }
Some(val) => val, Some(val) => val,
}; };

View file

@ -46,7 +46,7 @@ fn normalize_query(input: &str) -> String {
match (last_char, char) { match (last_char, char) {
(Some(':'), ':') => continue, (Some(':'), ':') => continue,
(Some(last_char), char) if last_char.is_whitespace() && char.is_whitespace() => { (Some(last_char), char) if last_char.is_whitespace() && char.is_whitespace() => {
continue continue;
} }
_ => { _ => {
last_char = Some(char); last_char = Some(char);

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();

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,

View file

@ -296,7 +296,9 @@ impl DebugPanel {
match event { match event {
dap_store::DapStoreEvent::DebugClientStarted(session_id) => { dap_store::DapStoreEvent::DebugClientStarted(session_id) => {
let Some(session) = dap_store.read(cx).session_by_id(session_id) else { let Some(session) = dap_store.read(cx).session_by_id(session_id) else {
return log::error!("Couldn't get session with id: {session_id:?} from DebugClientStarted event"); return log::error!(
"Couldn't get session with id: {session_id:?} from DebugClientStarted event"
);
}; };
let Some(project) = self.project.upgrade() else { let Some(project) = self.project.upgrade() else {

View file

@ -437,7 +437,9 @@ impl VariableList {
}); });
if res.is_none() { if res.is_none() {
log::error!("Couldn't confirm variable edit because variable doesn't have a leaf name or a parent reference id"); log::error!(
"Couldn't confirm variable edit because variable doesn't have a leaf name or a parent reference id"
);
} }
} }

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

@ -1464,7 +1464,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)
@ -1526,7 +1526,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(|_| {
@ -1536,7 +1536,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)
@ -1580,7 +1580,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

@ -1370,7 +1370,7 @@ impl BlockSnapshot {
while let Some(transform) = cursor.item() { while let Some(transform) = cursor.item() {
match &transform.block { match &transform.block {
Some(Block::ExcerptBoundary { excerpt, .. }) => { Some(Block::ExcerptBoundary { excerpt, .. }) => {
return Some(StickyHeaderExcerpt { excerpt }) return Some(StickyHeaderExcerpt { excerpt });
} }
Some(block) if block.is_buffer_header() => return None, Some(block) if block.is_buffer_header() => return None,
_ => { _ => {
@ -2913,7 +2913,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>();
@ -3077,7 +3077,9 @@ mod tests {
let fold = !unfolded_buffers.is_empty() && rng.gen_bool(0.5); let fold = !unfolded_buffers.is_empty() && rng.gen_bool(0.5);
let unfold = !folded_buffers.is_empty() && rng.gen_bool(0.5); let unfold = !folded_buffers.is_empty() && rng.gen_bool(0.5);
if !fold && !unfold { if !fold && !unfold {
log::info!("Noop fold/unfold operation. Unfolded buffers: {unfolded_count}, folded buffers: {folded_count}"); log::info!(
"Noop fold/unfold operation. Unfolded buffers: {unfolded_count}, folded buffers: {folded_count}"
);
continue; continue;
} }

View file

@ -1616,7 +1616,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 +1962,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 {
@ -1500,7 +1500,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>();

View file

@ -738,7 +738,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

@ -2428,7 +2428,11 @@ impl Editor {
background_executor.timer(SERIALIZATION_THROTTLE_TIME).await; background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
DB.save_editor_folds(editor_id, workspace_id, db_folds) DB.save_editor_folds(editor_id, workspace_id, db_folds)
.await .await
.with_context(|| format!("persisting editor folds for editor {editor_id}, workspace {workspace_id:?}")) .with_context(|| {
format!(
"persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
)
})
.log_err(); .log_err();
}); });
} }
@ -6200,7 +6204,9 @@ impl Editor {
fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) { fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
if self.tasks.insert(key, value).is_some() { if self.tasks.insert(key, value).is_some() {
// This case should hopefully be rare, but just in case... // This case should hopefully be rare, but just in case...
log::error!("multiple different run targets found on a single line, only the last target will be rendered") log::error!(
"multiple different run targets found on a single line, only the last target will be rendered"
)
} }
} }

View file

@ -7985,7 +7985,9 @@ async fn test_multibuffer_format_during_save(cx: &mut TestAppContext) {
assert!(cx.read(|cx| !multi_buffer_editor.is_dirty(cx))); assert!(cx.read(|cx| !multi_buffer_editor.is_dirty(cx)));
assert_eq!( assert_eq!(
multi_buffer_editor.update(cx, |editor, cx| editor.text(cx)), multi_buffer_editor.update(cx, |editor, cx| editor.text(cx)),
uri!("a|o[file:///a/main.rs formatted]bbbb\ncccc\n\nffff\ngggg\n\njjjj\n\nlll[file:///a/other.rs formatted]mmmm\nnnnn|four|five|six|\nr\n\nuuuu\n\nvvvv\nwwww\nxxxx\n\n{{{{\n||||\n\n\u{7f}\u{7f}\u{7f}\u{7f}"), uri!(
"a|o[file:///a/main.rs formatted]bbbb\ncccc\n\nffff\ngggg\n\njjjj\n\nlll[file:///a/other.rs formatted]mmmm\nnnnn|four|five|six|\nr\n\nuuuu\n\nvvvv\nwwww\nxxxx\n\n{{{{\n||||\n\n\u{7f}\u{7f}\u{7f}\u{7f}"
),
); );
buffer_1.update(cx, |buffer, _| { buffer_1.update(cx, |buffer, _| {
assert!(!buffer.is_dirty()); assert!(!buffer.is_dirty());
@ -18669,7 +18671,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();

View file

@ -4190,8 +4190,7 @@ 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((current_background, ref mut current_range, mut edges)) => {
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;
if new_range_started { if new_range_started {
@ -8793,8 +8792,10 @@ mod tests {
px(500.0), px(500.0),
show_line_numbers, show_line_numbers,
); );
assert!(invisibles.is_empty(), assert!(
"For editor mode {editor_mode_without_invisibles:?} no invisibles was expected but got {invisibles:?}"); invisibles.is_empty(),
"For editor mode {editor_mode_without_invisibles:?} no invisibles was expected but got {invisibles:?}"
);
} }
} }
} }
@ -8872,7 +8873,9 @@ mod tests {
(Invisible::Whitespace { .. }, Invisible::Whitespace { .. }) (Invisible::Whitespace { .. }, Invisible::Whitespace { .. })
| (Invisible::Tab { .. }, Invisible::Tab { .. }) => {} | (Invisible::Tab { .. }, Invisible::Tab { .. }) => {}
_ => { _ => {
panic!("At index {i}, expected invisible {expected_invisible:?} does not match actual {actual_invisible:?} by kind. Actual invisibles: {actual_invisibles:?}") panic!(
"At index {i}, expected invisible {expected_invisible:?} does not match actual {actual_invisible:?} by kind. Actual invisibles: {actual_invisibles:?}"
)
} }
}, },
None => { None => {

View file

@ -26,8 +26,7 @@ use wit_component::ComponentEncoder;
/// Once Rust 1.78 is released, there will be a `wasm32-wasip2` target available, so we will /// Once Rust 1.78 is released, there will be a `wasm32-wasip2` target available, so we will
/// not need the adapter anymore. /// not need the adapter anymore.
const RUST_TARGET: &str = "wasm32-wasip1"; const RUST_TARGET: &str = "wasm32-wasip1";
const WASI_ADAPTER_URL: &str = const WASI_ADAPTER_URL: &str = "https://github.com/bytecodealliance/wasmtime/releases/download/v18.0.2/wasi_snapshot_preview1.reactor.wasm";
"https://github.com/bytecodealliance/wasmtime/releases/download/v18.0.2/wasi_snapshot_preview1.reactor.wasm";
/// Compiling Tree-sitter parsers from C to WASM requires Clang 17, and a WASM build of libc /// Compiling Tree-sitter parsers from C to WASM requires Clang 17, and a WASM build of libc
/// and clang's runtime library. The `wasi-sdk` provides these binaries. /// and clang's runtime library. The `wasi-sdk` provides these binaries.
@ -100,7 +99,9 @@ impl ExtensionBuilder {
for (grammar_name, grammar_metadata) in &extension_manifest.grammars { for (grammar_name, grammar_metadata) in &extension_manifest.grammars {
let snake_cased_grammar_name = grammar_name.to_case(Case::Snake); let snake_cased_grammar_name = grammar_name.to_case(Case::Snake);
if grammar_name.as_ref() != snake_cased_grammar_name.as_str() { if grammar_name.as_ref() != snake_cased_grammar_name.as_str() {
bail!("grammar name '{grammar_name}' must be written in snake_case: {snake_cased_grammar_name}"); bail!(
"grammar name '{grammar_name}' must be written in snake_case: {snake_cased_grammar_name}"
);
} }
log::info!( log::info!(

View file

@ -19,7 +19,7 @@ path = "src/extension_api.rs"
[dependencies] [dependencies]
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
wit-bindgen = "0.22" wit-bindgen = "0.41"
[package.metadata.component] [package.metadata.component]
target = { path = "wit" } target = { path = "wit" }

View file

@ -185,7 +185,7 @@ pub trait Extension: Send + Sync {
#[macro_export] #[macro_export]
macro_rules! register_extension { macro_rules! register_extension {
($extension_type:ty) => { ($extension_type:ty) => {
#[export_name = "init-extension"] #[unsafe(export_name = "init-extension")]
pub extern "C" fn __init_extension() { pub extern "C" fn __init_extension() {
std::env::set_current_dir(std::env::var("PWD").unwrap()).unwrap(); std::env::set_current_dir(std::env::var("PWD").unwrap()).unwrap();
zed_extension_api::register_extension(|| { zed_extension_api::register_extension(|| {

View file

@ -398,7 +398,7 @@ impl ExtensionStore {
&mut self, &mut self,
modified_extension: Option<Arc<str>>, modified_extension: Option<Arc<str>>,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> impl Future<Output = ()> { ) -> impl Future<Output = ()> + use<> {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
self.reload_complete_senders.push(tx); self.reload_complete_senders.push(tx);
self.reload_tx self.reload_tx

View file

@ -839,64 +839,64 @@ async fn test_query_history(cx: &mut gpui::TestAppContext) {
let history_after_third = let history_after_third =
open_close_queried_buffer("sec", 1, "second.rs", &workspace, cx).await; open_close_queried_buffer("sec", 1, "second.rs", &workspace, cx).await;
assert_eq!( assert_eq!(
history_after_third, history_after_third,
vec![ vec![
FoundPath::new( FoundPath::new(
ProjectPath { ProjectPath {
worktree_id, worktree_id,
path: Arc::from(Path::new("test/third.rs")), path: Arc::from(Path::new("test/third.rs")),
}, },
Some(PathBuf::from(path!("/src/test/third.rs"))) Some(PathBuf::from(path!("/src/test/third.rs")))
), ),
FoundPath::new( FoundPath::new(
ProjectPath { ProjectPath {
worktree_id, worktree_id,
path: Arc::from(Path::new("test/second.rs")), path: Arc::from(Path::new("test/second.rs")),
}, },
Some(PathBuf::from(path!("/src/test/second.rs"))) Some(PathBuf::from(path!("/src/test/second.rs")))
), ),
FoundPath::new( FoundPath::new(
ProjectPath { ProjectPath {
worktree_id, worktree_id,
path: Arc::from(Path::new("test/first.rs")), path: Arc::from(Path::new("test/first.rs")),
}, },
Some(PathBuf::from(path!("/src/test/first.rs"))) Some(PathBuf::from(path!("/src/test/first.rs")))
), ),
], ],
"Should show 1st, 2nd and 3rd opened items in the history when opening the 2nd item again. \ "Should show 1st, 2nd and 3rd opened items in the history when opening the 2nd item again. \
3rd item should be the first in the history, as the last opened." 3rd item should be the first in the history, as the last opened."
); );
let history_after_second_again = let history_after_second_again =
open_close_queried_buffer("thi", 1, "third.rs", &workspace, cx).await; open_close_queried_buffer("thi", 1, "third.rs", &workspace, cx).await;
assert_eq!( assert_eq!(
history_after_second_again, history_after_second_again,
vec![ vec![
FoundPath::new( FoundPath::new(
ProjectPath { ProjectPath {
worktree_id, worktree_id,
path: Arc::from(Path::new("test/second.rs")), path: Arc::from(Path::new("test/second.rs")),
}, },
Some(PathBuf::from(path!("/src/test/second.rs"))) Some(PathBuf::from(path!("/src/test/second.rs")))
), ),
FoundPath::new( FoundPath::new(
ProjectPath { ProjectPath {
worktree_id, worktree_id,
path: Arc::from(Path::new("test/third.rs")), path: Arc::from(Path::new("test/third.rs")),
}, },
Some(PathBuf::from(path!("/src/test/third.rs"))) Some(PathBuf::from(path!("/src/test/third.rs")))
), ),
FoundPath::new( FoundPath::new(
ProjectPath { ProjectPath {
worktree_id, worktree_id,
path: Arc::from(Path::new("test/first.rs")), path: Arc::from(Path::new("test/first.rs")),
}, },
Some(PathBuf::from(path!("/src/test/first.rs"))) Some(PathBuf::from(path!("/src/test/first.rs")))
), ),
], ],
"Should show 1st, 2nd and 3rd opened items in the history when opening the 3rd item again. \ "Should show 1st, 2nd and 3rd opened items in the history when opening the 3rd item again. \
2nd item, as the last opened, 3rd item should go next as it was opened right before." 2nd item, as the last opened, 3rd item should go next as it was opened right before."
); );
} }
#[gpui::test] #[gpui::test]
@ -1656,15 +1656,15 @@ async fn test_nonexistent_history_items_not_shown(cx: &mut gpui::TestAppContext)
cx.simulate_input("rs"); cx.simulate_input("rs");
picker.update(cx, |picker, _| { picker.update(cx, |picker, _| {
assert_eq!( assert_eq!(
collect_search_matches(picker).history, collect_search_matches(picker).history,
vec![ vec![
PathBuf::from("test/first.rs"), PathBuf::from("test/first.rs"),
PathBuf::from("test/third.rs"), PathBuf::from("test/third.rs"),
], ],
"Should have all opened files in the history, except the ones that do not exist on disk" "Should have all opened files in the history, except the ones that do not exist on disk"
); );
}); });
} }
#[gpui::test] #[gpui::test]

View file

@ -430,7 +430,7 @@ impl Fs for RealFs {
unsafe { unsafe {
unsafe fn ns_string(string: &str) -> id { unsafe fn ns_string(string: &str) -> id {
NSString::alloc(nil).init_str(string).autorelease() unsafe { NSString::alloc(nil).init_str(string).autorelease() }
} }
let url: id = msg_send![class!(NSURL), fileURLWithPath: ns_string(path.to_string_lossy().as_ref())]; let url: id = msg_send![class!(NSURL), fileURLWithPath: ns_string(path.to_string_lossy().as_ref())];
@ -591,7 +591,7 @@ impl Fs for RealFs {
(io::ErrorKind::NotFound, _) => Ok(None), (io::ErrorKind::NotFound, _) => Ok(None),
(io::ErrorKind::Other, Some(libc::ENOTDIR)) => Ok(None), (io::ErrorKind::Other, Some(libc::ENOTDIR)) => Ok(None),
_ => Err(anyhow::Error::new(err)), _ => Err(anyhow::Error::new(err)),
} };
} }
}; };

View file

@ -365,7 +365,7 @@ impl std::fmt::Display for StreamFlags {
} }
#[link(name = "CoreServices", kind = "framework")] #[link(name = "CoreServices", kind = "framework")]
extern "C" { unsafe extern "C" {
pub fn FSEventsGetCurrentEventId() -> u64; pub fn FSEventsGetCurrentEventId() -> u64;
} }

View file

@ -1548,7 +1548,7 @@ impl GitPanel {
&mut self, &mut self,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> impl Future<Output = Result<bool, anyhow::Error>> { ) -> impl Future<Output = Result<bool, anyhow::Error>> + use<> {
let repo = self.active_repository.clone(); let repo = self.active_repository.clone();
let mut cx = window.to_async(cx); let mut cx = window.to_async(cx);
@ -2007,7 +2007,7 @@ impl GitPanel {
&mut self, &mut self,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> impl Future<Output = anyhow::Result<Option<Remote>>> { ) -> impl Future<Output = anyhow::Result<Option<Remote>>> + use<> {
let repo = self.active_repository.clone(); let repo = self.active_repository.clone();
let workspace = self.workspace.clone(); let workspace = self.workspace.clone();
let mut cx = window.to_async(cx); let mut cx = window.to_async(cx);

View file

@ -226,7 +226,7 @@ embed-resource = "3.0"
naga.workspace = true naga.workspace = true
[target.'cfg(target_os = "macos")'.build-dependencies] [target.'cfg(target_os = "macos")'.build-dependencies]
bindgen = "0.70.0" bindgen = "0.71"
cbindgen = { version = "0.28.0", default-features = false } cbindgen = { version = "0.28.0", default-features = false }
naga.workspace = true naga.workspace = true

View file

@ -68,7 +68,7 @@ pub trait Action: 'static + Send {
/// Optional JSON schema for the action's input data. /// Optional JSON schema for the action's input data.
fn action_json_schema( fn action_json_schema(
_: &mut schemars::gen::SchemaGenerator, _: &mut schemars::r#gen::SchemaGenerator,
) -> Option<schemars::schema::Schema> ) -> Option<schemars::schema::Schema>
where where
Self: Sized, Self: Sized,
@ -167,7 +167,7 @@ impl Default for ActionRegistry {
struct ActionData { struct ActionData {
pub build: ActionBuilder, pub build: ActionBuilder,
pub json_schema: fn(&mut schemars::gen::SchemaGenerator) -> Option<schemars::schema::Schema>, pub json_schema: fn(&mut schemars::r#gen::SchemaGenerator) -> Option<schemars::schema::Schema>,
} }
/// This type must be public so that our macros can build it in other crates. /// This type must be public so that our macros can build it in other crates.
@ -183,7 +183,7 @@ pub struct MacroActionData {
pub aliases: &'static [&'static str], pub aliases: &'static [&'static str],
pub type_id: TypeId, pub type_id: TypeId,
pub build: ActionBuilder, pub build: ActionBuilder,
pub json_schema: fn(&mut schemars::gen::SchemaGenerator) -> Option<schemars::schema::Schema>, pub json_schema: fn(&mut schemars::r#gen::SchemaGenerator) -> Option<schemars::schema::Schema>,
} }
inventory::collect!(MacroActionBuilder); inventory::collect!(MacroActionBuilder);
@ -271,7 +271,7 @@ impl ActionRegistry {
pub fn action_schemas( pub fn action_schemas(
&self, &self,
generator: &mut schemars::gen::SchemaGenerator, generator: &mut schemars::r#gen::SchemaGenerator,
) -> Vec<(SharedString, Option<schemars::schema::Schema>)> { ) -> Vec<(SharedString, Option<schemars::schema::Schema>)> {
// Use the order from all_names so that the resulting schema has sensible order. // Use the order from all_names so that the resulting schema has sensible order.
self.all_names self.all_names
@ -310,7 +310,7 @@ macro_rules! actions {
Ok(Box::new(Self)) Ok(Box::new(Self))
}, },
fn action_json_schema( fn action_json_schema(
_: &mut gpui::private::schemars::gen::SchemaGenerator, _: &mut gpui::private::schemars::r#gen::SchemaGenerator,
) -> Option<gpui::private::schemars::schema::Schema> { ) -> Option<gpui::private::schemars::schema::Schema> {
None None
} }
@ -347,7 +347,7 @@ macro_rules! action_as {
Ok(Box::new(Self)) Ok(Box::new(Self))
}, },
fn action_json_schema( fn action_json_schema(
generator: &mut gpui::private::schemars::gen::SchemaGenerator, generator: &mut gpui::private::schemars::r#gen::SchemaGenerator,
) -> Option<gpui::private::schemars::schema::Schema> { ) -> Option<gpui::private::schemars::schema::Schema> {
None None
} }
@ -381,7 +381,7 @@ macro_rules! action_with_deprecated_aliases {
}, },
fn action_json_schema( fn action_json_schema(
generator: &mut gpui::private::schemars::gen::SchemaGenerator, generator: &mut gpui::private::schemars::r#gen::SchemaGenerator,
) -> Option<gpui::private::schemars::schema::Schema> { ) -> Option<gpui::private::schemars::schema::Schema> {
None None
}, },
@ -412,7 +412,7 @@ macro_rules! impl_action_with_deprecated_aliases {
}, },
fn action_json_schema( fn action_json_schema(
generator: &mut gpui::private::schemars::gen::SchemaGenerator, generator: &mut gpui::private::schemars::r#gen::SchemaGenerator,
) -> Option<gpui::private::schemars::schema::Schema> { ) -> Option<gpui::private::schemars::schema::Schema> {
Some(<Self as gpui::private::schemars::JsonSchema>::json_schema( Some(<Self as gpui::private::schemars::JsonSchema>::json_schema(
generator, generator,
@ -446,7 +446,7 @@ macro_rules! impl_actions {
Ok(std::boxed::Box::new(gpui::private::serde_json::from_value::<Self>(value)?)) Ok(std::boxed::Box::new(gpui::private::serde_json::from_value::<Self>(value)?))
}, },
fn action_json_schema( fn action_json_schema(
generator: &mut gpui::private::schemars::gen::SchemaGenerator, generator: &mut gpui::private::schemars::r#gen::SchemaGenerator,
) -> Option<gpui::private::schemars::schema::Schema> { ) -> Option<gpui::private::schemars::schema::Schema> {
Some(<Self as gpui::private::schemars::JsonSchema>::json_schema( Some(<Self as gpui::private::schemars::JsonSchema>::json_schema(
generator, generator,
@ -479,7 +479,7 @@ macro_rules! impl_internal_actions {
))) )))
}, },
fn action_json_schema( fn action_json_schema(
generator: &mut gpui::private::schemars::gen::SchemaGenerator, generator: &mut gpui::private::schemars::r#gen::SchemaGenerator,
) -> Option<gpui::private::schemars::schema::Schema> { ) -> Option<gpui::private::schemars::schema::Schema> {
None None
} }
@ -509,7 +509,7 @@ macro_rules! impl_action_as {
)) ))
}, },
fn action_json_schema( fn action_json_schema(
generator: &mut gpui::private::schemars::gen::SchemaGenerator, generator: &mut gpui::private::schemars::r#gen::SchemaGenerator,
) -> Option<gpui::private::schemars::schema::Schema> { ) -> Option<gpui::private::schemars::schema::Schema> {
Some(<Self as gpui::private::schemars::JsonSchema>::json_schema( Some(<Self as gpui::private::schemars::JsonSchema>::json_schema(
generator, generator,

View file

@ -1347,7 +1347,7 @@ impl App {
/// Get all non-internal actions that have been registered, along with their schemas. /// Get all non-internal actions that have been registered, along with their schemas.
pub fn action_schemas( pub fn action_schemas(
&self, &self,
generator: &mut schemars::gen::SchemaGenerator, generator: &mut schemars::r#gen::SchemaGenerator,
) -> Vec<(SharedString, Option<schemars::schema::Schema>)> { ) -> Vec<(SharedString, Option<schemars::schema::Schema>)> {
self.actions.action_schemas(generator) self.actions.action_schemas(generator)
} }

View file

@ -234,11 +234,11 @@ impl AsyncApp {
} }
/// Run something using this entity and cx, when the returned struct is dropped /// Run something using this entity and cx, when the returned struct is dropped
pub fn on_drop<T: 'static>( pub fn on_drop<T: 'static, Callback: FnOnce(&mut T, &mut Context<T>) + 'static>(
&self, &self,
entity: &WeakEntity<T>, entity: &WeakEntity<T>,
f: impl FnOnce(&mut T, &mut Context<T>) + 'static, f: Callback,
) -> util::Deferred<impl FnOnce()> { ) -> util::Deferred<impl FnOnce() + use<T, Callback>> {
let entity = entity.clone(); let entity = entity.clone();
let mut cx = self.clone(); let mut cx = self.clone();
util::defer(move || { util::defer(move || {

View file

@ -448,7 +448,10 @@ impl TestAppContext {
} }
/// Returns a stream of notifications whenever the Entity is updated. /// Returns a stream of notifications whenever the Entity is updated.
pub fn notifications<T: 'static>(&mut self, entity: &Entity<T>) -> impl Stream<Item = ()> { pub fn notifications<T: 'static>(
&mut self,
entity: &Entity<T>,
) -> impl Stream<Item = ()> + use<T> {
let (tx, rx) = futures::channel::mpsc::unbounded(); let (tx, rx) = futures::channel::mpsc::unbounded();
self.update(|cx| { self.update(|cx| {
cx.observe(entity, { cx.observe(entity, {

View file

@ -66,11 +66,15 @@ impl Arena {
where where
F: FnOnce() -> T, F: FnOnce() -> T,
{ {
ptr::write(ptr, f()); unsafe {
ptr::write(ptr, f());
}
} }
unsafe fn drop<T>(ptr: *mut u8) { unsafe fn drop<T>(ptr: *mut u8) {
std::ptr::drop_in_place(ptr.cast::<T>()); unsafe {
std::ptr::drop_in_place(ptr.cast::<T>());
}
} }
unsafe { unsafe {

View file

@ -196,12 +196,12 @@ impl BackgroundExecutor {
} }
#[cfg(not(any(test, feature = "test-support")))] #[cfg(not(any(test, feature = "test-support")))]
pub(crate) fn block_internal<R>( pub(crate) fn block_internal<Fut: Future>(
&self, &self,
_background_only: bool, _background_only: bool,
future: impl Future<Output = R>, future: Fut,
timeout: Option<Duration>, timeout: Option<Duration>,
) -> Result<R, impl Future<Output = R>> { ) -> Result<Fut::Output, impl Future<Output = Fut::Output> + use<Fut>> {
use std::time::Instant; use std::time::Instant;
let mut future = Box::pin(future); let mut future = Box::pin(future);
@ -234,12 +234,12 @@ impl BackgroundExecutor {
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
#[track_caller] #[track_caller]
pub(crate) fn block_internal<R>( pub(crate) fn block_internal<Fut: Future>(
&self, &self,
background_only: bool, background_only: bool,
future: impl Future<Output = R>, future: Fut,
timeout: Option<Duration>, timeout: Option<Duration>,
) -> Result<R, impl Future<Output = R>> { ) -> Result<Fut::Output, impl Future<Output = Fut::Output> + use<Fut>> {
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;
let mut future = Box::pin(future); let mut future = Box::pin(future);
@ -291,8 +291,8 @@ impl BackgroundExecutor {
waiting_message = format!("\n waiting on: {}\n", waiting_hint); waiting_message = format!("\n waiting on: {}\n", waiting_hint);
} }
panic!( panic!(
"parked with nothing left to run{waiting_message}{backtrace_message}", "parked with nothing left to run{waiting_message}{backtrace_message}",
) )
} }
self.dispatcher.park(None); self.dispatcher.park(None);
} }
@ -303,11 +303,11 @@ impl BackgroundExecutor {
/// Block the current thread until the given future resolves /// Block the current thread until the given future resolves
/// or `duration` has elapsed. /// or `duration` has elapsed.
pub fn block_with_timeout<R>( pub fn block_with_timeout<Fut: Future>(
&self, &self,
duration: Duration, duration: Duration,
future: impl Future<Output = R>, future: Fut,
) -> Result<R, impl Future<Output = R>> { ) -> Result<Fut::Output, impl Future<Output = Fut::Output> + use<Fut>> {
self.block_internal(true, future, Some(duration)) self.block_internal(true, future, Some(duration))
} }
@ -365,7 +365,7 @@ impl BackgroundExecutor {
/// in tests, run an arbitrary number of tasks (determined by the SEED environment variable) /// in tests, run an arbitrary number of tasks (determined by the SEED environment variable)
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
pub fn simulate_random_delay(&self) -> impl Future<Output = ()> { pub fn simulate_random_delay(&self) -> impl Future<Output = ()> + use<> {
self.dispatcher.as_test().unwrap().simulate_random_delay() self.dispatcher.as_test().unwrap().simulate_random_delay()
} }

View file

@ -438,14 +438,8 @@ mod tests {
actions!( actions!(
test, test,
[ [
A, A, B, C, D, E, F, G, // Don't wrap, test the trailing comma
B, ]
C,
D,
E,
F,
G, // Don't wrap, test the trailing comma
]
); );
} }
} }

View file

@ -398,8 +398,12 @@ impl BladeRenderer {
log::error!("GPU hung"); log::error!("GPU hung");
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
if self.gpu.device_information().driver_name == "radv" { if self.gpu.device_information().driver_name == "radv" {
log::error!("there's a known bug with amdgpu/radv, try setting ZED_PATH_SAMPLE_COUNT=0 as a workaround"); log::error!(
log::error!("if that helps you're running into https://github.com/zed-industries/zed/issues/26143"); "there's a known bug with amdgpu/radv, try setting ZED_PATH_SAMPLE_COUNT=0 as a workaround"
);
log::error!(
"if that helps you're running into https://github.com/zed-industries/zed/issues/26143"
);
} }
log::error!( log::error!(
"your device information is: {:?}", "your device information is: {:?}",

View file

@ -632,7 +632,7 @@ pub(super) fn get_xkb_compose_state(cx: &xkb::Context) -> Option<xkb::compose::S
#[cfg(any(feature = "wayland", feature = "x11"))] #[cfg(any(feature = "wayland", feature = "x11"))]
pub(super) unsafe fn read_fd(mut fd: filedescriptor::FileDescriptor) -> Result<Vec<u8>> { pub(super) unsafe fn read_fd(mut fd: filedescriptor::FileDescriptor) -> Result<Vec<u8>> {
let mut file = File::from_raw_fd(fd.as_raw_fd()); let mut file = unsafe { File::from_raw_fd(fd.as_raw_fd()) };
let mut buffer = Vec::new(); let mut buffer = Vec::new();
file.read_to_end(&mut buffer)?; file.read_to_end(&mut buffer)?;
Ok(buffer) Ok(buffer)

View file

@ -256,7 +256,7 @@ impl Clipboard {
} }
Ok(n) => written += n, Ok(n) => written += n,
Err(err) if err.kind() == ErrorKind::WouldBlock => { Err(err) if err.kind() == ErrorKind::WouldBlock => {
break Ok(PostAction::Continue) break Ok(PostAction::Continue);
} }
Err(_) => break Ok(PostAction::Remove), Err(_) => break Ok(PostAction::Remove),
} }

View file

@ -186,12 +186,15 @@ fn find_visuals(xcb: &XCBConnection, screen_index: usize) -> VisualSet {
colormap: 0, colormap: 0,
depth: depth_info.depth, depth: depth_info.depth,
}; };
log::debug!("Visual id: {}, class: {:?}, depth: {}, bits_per_value: {}, masks: 0x{:x} 0x{:x} 0x{:x}", log::debug!(
"Visual id: {}, class: {:?}, depth: {}, bits_per_value: {}, masks: 0x{:x} 0x{:x} 0x{:x}",
visual_type.visual_id, visual_type.visual_id,
visual_type.class, visual_type.class,
depth_info.depth, depth_info.depth,
visual_type.bits_per_rgb_value, visual_type.bits_per_rgb_value,
visual_type.red_mask, visual_type.green_mask, visual_type.blue_mask, visual_type.red_mask,
visual_type.green_mask,
visual_type.blue_mask,
); );
if ( if (
@ -409,15 +412,27 @@ impl X11WindowState {
let mut bounds = params.bounds.to_device_pixels(scale_factor); let mut bounds = params.bounds.to_device_pixels(scale_factor);
if bounds.size.width.0 == 0 || bounds.size.height.0 == 0 { if bounds.size.width.0 == 0 || bounds.size.height.0 == 0 {
log::warn!("Window bounds contain a zero value. height={}, width={}. Falling back to defaults.", bounds.size.height.0, bounds.size.width.0); log::warn!(
"Window bounds contain a zero value. height={}, width={}. Falling back to defaults.",
bounds.size.height.0,
bounds.size.width.0
);
bounds.size.width = 800.into(); bounds.size.width = 800.into();
bounds.size.height = 600.into(); bounds.size.height = 600.into();
} }
check_reply( check_reply(
|| { || {
format!("X11 CreateWindow failed. depth: {}, x_window: {}, visual_set.root: {}, bounds.origin.x.0: {}, bounds.origin.y.0: {}, bounds.size.width.0: {}, bounds.size.height.0: {}", format!(
visual.depth, x_window, visual_set.root, bounds.origin.x.0 + 2, bounds.origin.y.0, bounds.size.width.0, bounds.size.height.0) "X11 CreateWindow failed. depth: {}, x_window: {}, visual_set.root: {}, bounds.origin.x.0: {}, bounds.origin.y.0: {}, bounds.size.width.0: {}, bounds.size.height.0: {}",
visual.depth,
x_window,
visual_set.root,
bounds.origin.x.0 + 2,
bounds.origin.y.0,
bounds.size.width.0,
bounds.size.height.0
)
}, },
xcb.create_window( xcb.create_window(
visual.depth, visual.depth,

View file

@ -74,11 +74,13 @@ trait NSStringExt {
impl NSStringExt for id { impl NSStringExt for id {
unsafe fn to_str(&self) -> &str { unsafe fn to_str(&self) -> &str {
let cstr = self.UTF8String(); unsafe {
if cstr.is_null() { let cstr = self.UTF8String();
"" if cstr.is_null() {
} else { ""
CStr::from_ptr(cstr as *mut c_char).to_str().unwrap() } else {
CStr::from_ptr(cstr as *mut c_char).to_str().unwrap()
}
} }
} }
} }
@ -134,7 +136,7 @@ unsafe impl objc::Encode for NSRange {
} }
unsafe fn ns_string(string: &str) -> id { unsafe fn ns_string(string: &str) -> id {
NSString::alloc(nil).init_str(string).autorelease() unsafe { NSString::alloc(nil).init_str(string).autorelease() }
} }
impl From<NSSize> for Size<Pixels> { impl From<NSSize> for Size<Pixels> {

View file

@ -65,7 +65,7 @@ impl MacDisplay {
} }
#[link(name = "ApplicationServices", kind = "framework")] #[link(name = "ApplicationServices", kind = "framework")]
extern "C" { unsafe extern "C" {
fn CGDisplayCreateUUIDFromDisplayID(display: CGDirectDisplayID) -> CFUUIDRef; fn CGDisplayCreateUUIDFromDisplayID(display: CGDirectDisplayID) -> CFUUIDRef;
} }

View file

@ -30,9 +30,11 @@ impl DisplayLink {
_flags_out: *mut i64, _flags_out: *mut i64,
frame_requests: *mut c_void, frame_requests: *mut c_void,
) -> i32 { ) -> i32 {
let frame_requests = frame_requests as dispatch_source_t; unsafe {
dispatch_source_merge_data(frame_requests, 1); let frame_requests = frame_requests as dispatch_source_t;
0 dispatch_source_merge_data(frame_requests, 1);
0
}
} }
unsafe { unsafe {
@ -202,7 +204,7 @@ mod sys {
#[link(name = "CoreFoundation", kind = "framework")] #[link(name = "CoreFoundation", kind = "framework")]
#[link(name = "CoreVideo", kind = "framework")] #[link(name = "CoreVideo", kind = "framework")]
#[allow(improper_ctypes, unknown_lints, clippy::duplicated_attributes)] #[allow(improper_ctypes, unknown_lints, clippy::duplicated_attributes)]
extern "C" { unsafe extern "C" {
pub fn CVDisplayLinkCreateWithActiveCGDisplays( pub fn CVDisplayLinkCreateWithActiveCGDisplays(
display_link_out: *mut *mut CVDisplayLink, display_link_out: *mut *mut CVDisplayLink,
) -> i32; ) -> i32;
@ -228,40 +230,46 @@ mod sys {
callback: CVDisplayLinkOutputCallback, callback: CVDisplayLinkOutputCallback,
user_info: *mut c_void, user_info: *mut c_void,
) -> Result<Self> { ) -> Result<Self> {
let mut display_link: *mut CVDisplayLink = 0 as _; unsafe {
let mut display_link: *mut CVDisplayLink = 0 as _;
let code = CVDisplayLinkCreateWithActiveCGDisplays(&mut display_link); let code = CVDisplayLinkCreateWithActiveCGDisplays(&mut display_link);
anyhow::ensure!(code == 0, "could not create display link, code: {}", code); anyhow::ensure!(code == 0, "could not create display link, code: {}", code);
let mut display_link = DisplayLink::from_ptr(display_link); let mut display_link = DisplayLink::from_ptr(display_link);
let code = CVDisplayLinkSetOutputCallback(&mut display_link, callback, user_info); let code = CVDisplayLinkSetOutputCallback(&mut display_link, callback, user_info);
anyhow::ensure!(code == 0, "could not set output callback, code: {}", code); anyhow::ensure!(code == 0, "could not set output callback, code: {}", code);
let code = CVDisplayLinkSetCurrentCGDisplay(&mut display_link, display_id); let code = CVDisplayLinkSetCurrentCGDisplay(&mut display_link, display_id);
anyhow::ensure!( anyhow::ensure!(
code == 0, code == 0,
"could not assign display to display link, code: {}", "could not assign display to display link, code: {}",
code code
); );
Ok(display_link) Ok(display_link)
}
} }
} }
impl DisplayLinkRef { impl DisplayLinkRef {
/// Apple docs: [CVDisplayLinkStart](https://developer.apple.com/documentation/corevideo/1457193-cvdisplaylinkstart?language=objc) /// Apple docs: [CVDisplayLinkStart](https://developer.apple.com/documentation/corevideo/1457193-cvdisplaylinkstart?language=objc)
pub unsafe fn start(&mut self) -> Result<()> { pub unsafe fn start(&mut self) -> Result<()> {
let code = CVDisplayLinkStart(self); unsafe {
anyhow::ensure!(code == 0, "could not start display link, code: {}", code); let code = CVDisplayLinkStart(self);
Ok(()) anyhow::ensure!(code == 0, "could not start display link, code: {}", code);
Ok(())
}
} }
/// Apple docs: [CVDisplayLinkStop](https://developer.apple.com/documentation/corevideo/1457281-cvdisplaylinkstop?language=objc) /// Apple docs: [CVDisplayLinkStop](https://developer.apple.com/documentation/corevideo/1457281-cvdisplaylinkstop?language=objc)
pub unsafe fn stop(&mut self) -> Result<()> { pub unsafe fn stop(&mut self) -> Result<()> {
let code = CVDisplayLinkStop(self); unsafe {
anyhow::ensure!(code == 0, "could not stop display link, code: {}", code); let code = CVDisplayLinkStop(self);
Ok(()) anyhow::ensure!(code == 0, "could not stop display link, code: {}", code);
Ok(())
}
} }
} }
} }

View file

@ -80,19 +80,21 @@ pub fn key_to_native(key: &str) -> Cow<str> {
} }
unsafe fn read_modifiers(native_event: id) -> Modifiers { unsafe fn read_modifiers(native_event: id) -> Modifiers {
let modifiers = native_event.modifierFlags(); unsafe {
let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); let modifiers = native_event.modifierFlags();
let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask);
let shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask);
let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); let shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask);
let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask); let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask);
let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask);
Modifiers { Modifiers {
control, control,
alt, alt,
shift, shift,
platform: command, platform: command,
function, function,
}
} }
} }
@ -101,344 +103,351 @@ impl PlatformInput {
native_event: id, native_event: id,
window_height: Option<Pixels>, window_height: Option<Pixels>,
) -> Option<Self> { ) -> Option<Self> {
let event_type = native_event.eventType(); unsafe {
let event_type = native_event.eventType();
// Filter out event types that aren't in the NSEventType enum. // Filter out event types that aren't in the NSEventType enum.
// See https://github.com/servo/cocoa-rs/issues/155#issuecomment-323482792 for details. // See https://github.com/servo/cocoa-rs/issues/155#issuecomment-323482792 for details.
match event_type as u64 { match event_type as u64 {
0 | 21 | 32 | 33 | 35 | 36 | 37 => { 0 | 21 | 32 | 33 | 35 | 36 | 37 => {
return None; return None;
}
_ => {}
} }
_ => {}
}
match event_type { match event_type {
NSEventType::NSFlagsChanged => Some(Self::ModifiersChanged(ModifiersChangedEvent { NSEventType::NSFlagsChanged => {
modifiers: read_modifiers(native_event), Some(Self::ModifiersChanged(ModifiersChangedEvent {
})),
NSEventType::NSKeyDown => Some(Self::KeyDown(KeyDownEvent {
keystroke: parse_keystroke(native_event),
is_held: native_event.isARepeat() == YES,
})),
NSEventType::NSKeyUp => Some(Self::KeyUp(KeyUpEvent {
keystroke: parse_keystroke(native_event),
})),
NSEventType::NSLeftMouseDown
| NSEventType::NSRightMouseDown
| NSEventType::NSOtherMouseDown => {
let button = match native_event.buttonNumber() {
0 => MouseButton::Left,
1 => MouseButton::Right,
2 => MouseButton::Middle,
3 => MouseButton::Navigate(NavigationDirection::Back),
4 => MouseButton::Navigate(NavigationDirection::Forward),
// Other mouse buttons aren't tracked currently
_ => return None,
};
window_height.map(|window_height| {
Self::MouseDown(MouseDownEvent {
button,
position: point(
px(native_event.locationInWindow().x as f32),
// MacOS screen coordinates are relative to bottom left
window_height - px(native_event.locationInWindow().y as f32),
),
modifiers: read_modifiers(native_event), modifiers: read_modifiers(native_event),
click_count: native_event.clickCount() as usize, }))
first_mouse: false, }
}) NSEventType::NSKeyDown => Some(Self::KeyDown(KeyDownEvent {
}) keystroke: parse_keystroke(native_event),
} is_held: native_event.isARepeat() == YES,
NSEventType::NSLeftMouseUp })),
| NSEventType::NSRightMouseUp NSEventType::NSKeyUp => Some(Self::KeyUp(KeyUpEvent {
| NSEventType::NSOtherMouseUp => { keystroke: parse_keystroke(native_event),
let button = match native_event.buttonNumber() { })),
0 => MouseButton::Left, NSEventType::NSLeftMouseDown
1 => MouseButton::Right, | NSEventType::NSRightMouseDown
2 => MouseButton::Middle, | NSEventType::NSOtherMouseDown => {
3 => MouseButton::Navigate(NavigationDirection::Back), let button = match native_event.buttonNumber() {
4 => MouseButton::Navigate(NavigationDirection::Forward), 0 => MouseButton::Left,
// Other mouse buttons aren't tracked currently 1 => MouseButton::Right,
_ => return None, 2 => MouseButton::Middle,
}; 3 => MouseButton::Navigate(NavigationDirection::Back),
4 => MouseButton::Navigate(NavigationDirection::Forward),
window_height.map(|window_height| { // Other mouse buttons aren't tracked currently
Self::MouseUp(MouseUpEvent {
button,
position: point(
px(native_event.locationInWindow().x as f32),
window_height - px(native_event.locationInWindow().y as f32),
),
modifiers: read_modifiers(native_event),
click_count: native_event.clickCount() as usize,
})
})
}
// Some mice (like Logitech MX Master) send navigation buttons as swipe events
NSEventType::NSEventTypeSwipe => {
let navigation_direction = match native_event.phase() {
NSEventPhase::NSEventPhaseEnded => match native_event.deltaX() {
x if x > 0.0 => Some(NavigationDirection::Back),
x if x < 0.0 => Some(NavigationDirection::Forward),
_ => return None, _ => return None,
}, };
_ => return None, window_height.map(|window_height| {
};
match navigation_direction {
Some(direction) => window_height.map(|window_height| {
Self::MouseDown(MouseDownEvent { Self::MouseDown(MouseDownEvent {
button: MouseButton::Navigate(direction), button,
position: point(
px(native_event.locationInWindow().x as f32),
// MacOS screen coordinates are relative to bottom left
window_height - px(native_event.locationInWindow().y as f32),
),
modifiers: read_modifiers(native_event),
click_count: native_event.clickCount() as usize,
first_mouse: false,
})
})
}
NSEventType::NSLeftMouseUp
| NSEventType::NSRightMouseUp
| NSEventType::NSOtherMouseUp => {
let button = match native_event.buttonNumber() {
0 => MouseButton::Left,
1 => MouseButton::Right,
2 => MouseButton::Middle,
3 => MouseButton::Navigate(NavigationDirection::Back),
4 => MouseButton::Navigate(NavigationDirection::Forward),
// Other mouse buttons aren't tracked currently
_ => return None,
};
window_height.map(|window_height| {
Self::MouseUp(MouseUpEvent {
button,
position: point( position: point(
px(native_event.locationInWindow().x as f32), px(native_event.locationInWindow().x as f32),
window_height - px(native_event.locationInWindow().y as f32), window_height - px(native_event.locationInWindow().y as f32),
), ),
modifiers: read_modifiers(native_event), modifiers: read_modifiers(native_event),
click_count: 1, click_count: native_event.clickCount() as usize,
first_mouse: false,
}) })
}), })
_ => None,
} }
} // Some mice (like Logitech MX Master) send navigation buttons as swipe events
NSEventType::NSScrollWheel => window_height.map(|window_height| { NSEventType::NSEventTypeSwipe => {
let phase = match native_event.phase() { let navigation_direction = match native_event.phase() {
NSEventPhase::NSEventPhaseMayBegin | NSEventPhase::NSEventPhaseBegan => { NSEventPhase::NSEventPhaseEnded => match native_event.deltaX() {
TouchPhase::Started x if x > 0.0 => Some(NavigationDirection::Back),
x if x < 0.0 => Some(NavigationDirection::Forward),
_ => return None,
},
_ => return None,
};
match navigation_direction {
Some(direction) => window_height.map(|window_height| {
Self::MouseDown(MouseDownEvent {
button: MouseButton::Navigate(direction),
position: point(
px(native_event.locationInWindow().x as f32),
window_height - px(native_event.locationInWindow().y as f32),
),
modifiers: read_modifiers(native_event),
click_count: 1,
first_mouse: false,
})
}),
_ => None,
} }
NSEventPhase::NSEventPhaseEnded => TouchPhase::Ended, }
_ => TouchPhase::Moved, NSEventType::NSScrollWheel => window_height.map(|window_height| {
}; let phase = match native_event.phase() {
NSEventPhase::NSEventPhaseMayBegin | NSEventPhase::NSEventPhaseBegan => {
TouchPhase::Started
}
NSEventPhase::NSEventPhaseEnded => TouchPhase::Ended,
_ => TouchPhase::Moved,
};
let raw_data = point( let raw_data = point(
native_event.scrollingDeltaX() as f32, native_event.scrollingDeltaX() as f32,
native_event.scrollingDeltaY() as f32, native_event.scrollingDeltaY() as f32,
); );
let delta = if native_event.hasPreciseScrollingDeltas() == YES { let delta = if native_event.hasPreciseScrollingDeltas() == YES {
ScrollDelta::Pixels(raw_data.map(px)) ScrollDelta::Pixels(raw_data.map(px))
} else { } else {
ScrollDelta::Lines(raw_data) ScrollDelta::Lines(raw_data)
}; };
Self::ScrollWheel(ScrollWheelEvent { Self::ScrollWheel(ScrollWheelEvent {
position: point(
px(native_event.locationInWindow().x as f32),
window_height - px(native_event.locationInWindow().y as f32),
),
delta,
touch_phase: phase,
modifiers: read_modifiers(native_event),
})
}),
NSEventType::NSLeftMouseDragged
| NSEventType::NSRightMouseDragged
| NSEventType::NSOtherMouseDragged => {
let pressed_button = match native_event.buttonNumber() {
0 => MouseButton::Left,
1 => MouseButton::Right,
2 => MouseButton::Middle,
3 => MouseButton::Navigate(NavigationDirection::Back),
4 => MouseButton::Navigate(NavigationDirection::Forward),
// Other mouse buttons aren't tracked currently
_ => return None,
};
window_height.map(|window_height| {
Self::MouseMove(MouseMoveEvent {
pressed_button: Some(pressed_button),
position: point( position: point(
px(native_event.locationInWindow().x as f32), px(native_event.locationInWindow().x as f32),
window_height - px(native_event.locationInWindow().y as f32), window_height - px(native_event.locationInWindow().y as f32),
), ),
delta,
touch_phase: phase,
modifiers: read_modifiers(native_event), modifiers: read_modifiers(native_event),
}) })
}) }),
} NSEventType::NSLeftMouseDragged
NSEventType::NSMouseMoved => window_height.map(|window_height| { | NSEventType::NSRightMouseDragged
Self::MouseMove(MouseMoveEvent { | NSEventType::NSOtherMouseDragged => {
position: point( let pressed_button = match native_event.buttonNumber() {
px(native_event.locationInWindow().x as f32), 0 => MouseButton::Left,
window_height - px(native_event.locationInWindow().y as f32), 1 => MouseButton::Right,
), 2 => MouseButton::Middle,
pressed_button: None, 3 => MouseButton::Navigate(NavigationDirection::Back),
modifiers: read_modifiers(native_event), 4 => MouseButton::Navigate(NavigationDirection::Forward),
}) // Other mouse buttons aren't tracked currently
}), _ => return None,
NSEventType::NSMouseExited => window_height.map(|window_height| { };
Self::MouseExited(MouseExitEvent {
position: point(
px(native_event.locationInWindow().x as f32),
window_height - px(native_event.locationInWindow().y as f32),
),
pressed_button: None, window_height.map(|window_height| {
modifiers: read_modifiers(native_event), Self::MouseMove(MouseMoveEvent {
}) pressed_button: Some(pressed_button),
}), position: point(
_ => None, px(native_event.locationInWindow().x as f32),
window_height - px(native_event.locationInWindow().y as f32),
),
modifiers: read_modifiers(native_event),
})
})
}
NSEventType::NSMouseMoved => window_height.map(|window_height| {
Self::MouseMove(MouseMoveEvent {
position: point(
px(native_event.locationInWindow().x as f32),
window_height - px(native_event.locationInWindow().y as f32),
),
pressed_button: None,
modifiers: read_modifiers(native_event),
})
}),
NSEventType::NSMouseExited => window_height.map(|window_height| {
Self::MouseExited(MouseExitEvent {
position: point(
px(native_event.locationInWindow().x as f32),
window_height - px(native_event.locationInWindow().y as f32),
),
pressed_button: None,
modifiers: read_modifiers(native_event),
})
}),
_ => None,
}
} }
} }
} }
unsafe fn parse_keystroke(native_event: id) -> Keystroke { unsafe fn parse_keystroke(native_event: id) -> Keystroke {
use cocoa::appkit::*; unsafe {
use cocoa::appkit::*;
let mut characters = native_event let mut characters = native_event
.charactersIgnoringModifiers() .charactersIgnoringModifiers()
.to_str() .to_str()
.to_string(); .to_string();
let mut key_char = None; let mut key_char = None;
let first_char = characters.chars().next().map(|ch| ch as u16); let first_char = characters.chars().next().map(|ch| ch as u16);
let modifiers = native_event.modifierFlags(); let modifiers = native_event.modifierFlags();
let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask);
let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask);
let mut shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); let mut shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask);
let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask);
let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask) let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask)
&& first_char.map_or(true, |ch| { && first_char.map_or(true, |ch| {
!(NSUpArrowFunctionKey..=NSModeSwitchFunctionKey).contains(&ch) !(NSUpArrowFunctionKey..=NSModeSwitchFunctionKey).contains(&ch)
}); });
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
let key = match first_char { let key = match first_char {
Some(SPACE_KEY) => { Some(SPACE_KEY) => {
key_char = Some(" ".to_string()); key_char = Some(" ".to_string());
"space".to_string() "space".to_string()
}
Some(TAB_KEY) => {
key_char = Some("\t".to_string());
"tab".to_string()
}
Some(ENTER_KEY) | Some(NUMPAD_ENTER_KEY) => {
key_char = Some("\n".to_string());
"enter".to_string()
}
Some(BACKSPACE_KEY) => "backspace".to_string(),
Some(ESCAPE_KEY) => "escape".to_string(),
Some(SHIFT_TAB_KEY) => "tab".to_string(),
Some(NSUpArrowFunctionKey) => "up".to_string(),
Some(NSDownArrowFunctionKey) => "down".to_string(),
Some(NSLeftArrowFunctionKey) => "left".to_string(),
Some(NSRightArrowFunctionKey) => "right".to_string(),
Some(NSPageUpFunctionKey) => "pageup".to_string(),
Some(NSPageDownFunctionKey) => "pagedown".to_string(),
Some(NSHomeFunctionKey) => "home".to_string(),
Some(NSEndFunctionKey) => "end".to_string(),
Some(NSDeleteFunctionKey) => "delete".to_string(),
// Observed Insert==NSHelpFunctionKey not NSInsertFunctionKey.
Some(NSHelpFunctionKey) => "insert".to_string(),
Some(NSF1FunctionKey) => "f1".to_string(),
Some(NSF2FunctionKey) => "f2".to_string(),
Some(NSF3FunctionKey) => "f3".to_string(),
Some(NSF4FunctionKey) => "f4".to_string(),
Some(NSF5FunctionKey) => "f5".to_string(),
Some(NSF6FunctionKey) => "f6".to_string(),
Some(NSF7FunctionKey) => "f7".to_string(),
Some(NSF8FunctionKey) => "f8".to_string(),
Some(NSF9FunctionKey) => "f9".to_string(),
Some(NSF10FunctionKey) => "f10".to_string(),
Some(NSF11FunctionKey) => "f11".to_string(),
Some(NSF12FunctionKey) => "f12".to_string(),
Some(NSF13FunctionKey) => "f13".to_string(),
Some(NSF14FunctionKey) => "f14".to_string(),
Some(NSF15FunctionKey) => "f15".to_string(),
Some(NSF16FunctionKey) => "f16".to_string(),
Some(NSF17FunctionKey) => "f17".to_string(),
Some(NSF18FunctionKey) => "f18".to_string(),
Some(NSF19FunctionKey) => "f19".to_string(),
Some(NSF20FunctionKey) => "f20".to_string(),
Some(NSF21FunctionKey) => "f21".to_string(),
Some(NSF22FunctionKey) => "f22".to_string(),
Some(NSF23FunctionKey) => "f23".to_string(),
Some(NSF24FunctionKey) => "f24".to_string(),
Some(NSF25FunctionKey) => "f25".to_string(),
Some(NSF26FunctionKey) => "f26".to_string(),
Some(NSF27FunctionKey) => "f27".to_string(),
Some(NSF28FunctionKey) => "f28".to_string(),
Some(NSF29FunctionKey) => "f29".to_string(),
Some(NSF30FunctionKey) => "f30".to_string(),
Some(NSF31FunctionKey) => "f31".to_string(),
Some(NSF32FunctionKey) => "f32".to_string(),
Some(NSF33FunctionKey) => "f33".to_string(),
Some(NSF34FunctionKey) => "f34".to_string(),
Some(NSF35FunctionKey) => "f35".to_string(),
_ => {
// Cases to test when modifying this:
//
// qwerty key | none | cmd | cmd-shift
// * Armenian s | ս | cmd-s | cmd-shift-s (layout is non-ASCII, so we use cmd layout)
// * Dvorak+QWERTY s | o | cmd-s | cmd-shift-s (layout switches on cmd)
// * Ukrainian+QWERTY s | с | cmd-s | cmd-shift-s (macOS reports cmd-s instead of cmd-S)
// * Czech 7 | ý | cmd-ý | cmd-7 (layout has shifted numbers)
// * Norwegian 7 | 7 | cmd-7 | cmd-/ (macOS reports cmd-shift-7 instead of cmd-/)
// * Russian 7 | 7 | cmd-7 | cmd-& (shift-7 is . but when cmd is down, should use cmd layout)
// * German QWERTZ ; | ö | cmd-ö | cmd-Ö (Zed's shift special case only applies to a-z)
//
let mut chars_ignoring_modifiers =
chars_for_modified_key(native_event.keyCode(), NO_MOD);
let mut chars_with_shift = chars_for_modified_key(native_event.keyCode(), SHIFT_MOD);
let always_use_cmd_layout = always_use_command_layout();
// Handle Dvorak+QWERTY / Russian / Armenian
if command || always_use_cmd_layout {
let chars_with_cmd = chars_for_modified_key(native_event.keyCode(), CMD_MOD);
let chars_with_both =
chars_for_modified_key(native_event.keyCode(), CMD_MOD | SHIFT_MOD);
// We don't do this in the case that the shifted command key generates
// the same character as the unshifted command key (Norwegian, e.g.)
if chars_with_both != chars_with_cmd {
chars_with_shift = chars_with_both;
// Handle edge-case where cmd-shift-s reports cmd-s instead of
// cmd-shift-s (Ukrainian, etc.)
} else if chars_with_cmd.to_ascii_uppercase() != chars_with_cmd {
chars_with_shift = chars_with_cmd.to_ascii_uppercase();
}
chars_ignoring_modifiers = chars_with_cmd;
} }
Some(TAB_KEY) => {
if !control && !command && !function { key_char = Some("\t".to_string());
let mut mods = NO_MOD; "tab".to_string()
if shift {
mods |= SHIFT_MOD;
}
if alt {
mods |= OPTION_MOD;
}
key_char = Some(chars_for_modified_key(native_event.keyCode(), mods));
} }
Some(ENTER_KEY) | Some(NUMPAD_ENTER_KEY) => {
key_char = Some("\n".to_string());
"enter".to_string()
}
Some(BACKSPACE_KEY) => "backspace".to_string(),
Some(ESCAPE_KEY) => "escape".to_string(),
Some(SHIFT_TAB_KEY) => "tab".to_string(),
Some(NSUpArrowFunctionKey) => "up".to_string(),
Some(NSDownArrowFunctionKey) => "down".to_string(),
Some(NSLeftArrowFunctionKey) => "left".to_string(),
Some(NSRightArrowFunctionKey) => "right".to_string(),
Some(NSPageUpFunctionKey) => "pageup".to_string(),
Some(NSPageDownFunctionKey) => "pagedown".to_string(),
Some(NSHomeFunctionKey) => "home".to_string(),
Some(NSEndFunctionKey) => "end".to_string(),
Some(NSDeleteFunctionKey) => "delete".to_string(),
// Observed Insert==NSHelpFunctionKey not NSInsertFunctionKey.
Some(NSHelpFunctionKey) => "insert".to_string(),
Some(NSF1FunctionKey) => "f1".to_string(),
Some(NSF2FunctionKey) => "f2".to_string(),
Some(NSF3FunctionKey) => "f3".to_string(),
Some(NSF4FunctionKey) => "f4".to_string(),
Some(NSF5FunctionKey) => "f5".to_string(),
Some(NSF6FunctionKey) => "f6".to_string(),
Some(NSF7FunctionKey) => "f7".to_string(),
Some(NSF8FunctionKey) => "f8".to_string(),
Some(NSF9FunctionKey) => "f9".to_string(),
Some(NSF10FunctionKey) => "f10".to_string(),
Some(NSF11FunctionKey) => "f11".to_string(),
Some(NSF12FunctionKey) => "f12".to_string(),
Some(NSF13FunctionKey) => "f13".to_string(),
Some(NSF14FunctionKey) => "f14".to_string(),
Some(NSF15FunctionKey) => "f15".to_string(),
Some(NSF16FunctionKey) => "f16".to_string(),
Some(NSF17FunctionKey) => "f17".to_string(),
Some(NSF18FunctionKey) => "f18".to_string(),
Some(NSF19FunctionKey) => "f19".to_string(),
Some(NSF20FunctionKey) => "f20".to_string(),
Some(NSF21FunctionKey) => "f21".to_string(),
Some(NSF22FunctionKey) => "f22".to_string(),
Some(NSF23FunctionKey) => "f23".to_string(),
Some(NSF24FunctionKey) => "f24".to_string(),
Some(NSF25FunctionKey) => "f25".to_string(),
Some(NSF26FunctionKey) => "f26".to_string(),
Some(NSF27FunctionKey) => "f27".to_string(),
Some(NSF28FunctionKey) => "f28".to_string(),
Some(NSF29FunctionKey) => "f29".to_string(),
Some(NSF30FunctionKey) => "f30".to_string(),
Some(NSF31FunctionKey) => "f31".to_string(),
Some(NSF32FunctionKey) => "f32".to_string(),
Some(NSF33FunctionKey) => "f33".to_string(),
Some(NSF34FunctionKey) => "f34".to_string(),
Some(NSF35FunctionKey) => "f35".to_string(),
_ => {
// Cases to test when modifying this:
//
// qwerty key | none | cmd | cmd-shift
// * Armenian s | ս | cmd-s | cmd-shift-s (layout is non-ASCII, so we use cmd layout)
// * Dvorak+QWERTY s | o | cmd-s | cmd-shift-s (layout switches on cmd)
// * Ukrainian+QWERTY s | с | cmd-s | cmd-shift-s (macOS reports cmd-s instead of cmd-S)
// * Czech 7 | ý | cmd-ý | cmd-7 (layout has shifted numbers)
// * Norwegian 7 | 7 | cmd-7 | cmd-/ (macOS reports cmd-shift-7 instead of cmd-/)
// * Russian 7 | 7 | cmd-7 | cmd-& (shift-7 is . but when cmd is down, should use cmd layout)
// * German QWERTZ ; | ö | cmd-ö | cmd-Ö (Zed's shift special case only applies to a-z)
//
let mut chars_ignoring_modifiers =
chars_for_modified_key(native_event.keyCode(), NO_MOD);
let mut chars_with_shift =
chars_for_modified_key(native_event.keyCode(), SHIFT_MOD);
let always_use_cmd_layout = always_use_command_layout();
let mut key = if shift // Handle Dvorak+QWERTY / Russian / Armenian
&& chars_ignoring_modifiers if command || always_use_cmd_layout {
.chars() let chars_with_cmd = chars_for_modified_key(native_event.keyCode(), CMD_MOD);
.all(|c| c.is_ascii_lowercase()) let chars_with_both =
{ chars_for_modified_key(native_event.keyCode(), CMD_MOD | SHIFT_MOD);
chars_ignoring_modifiers
} else if shift {
shift = false;
chars_with_shift
} else {
chars_ignoring_modifiers
};
key // We don't do this in the case that the shifted command key generates
// the same character as the unshifted command key (Norwegian, e.g.)
if chars_with_both != chars_with_cmd {
chars_with_shift = chars_with_both;
// Handle edge-case where cmd-shift-s reports cmd-s instead of
// cmd-shift-s (Ukrainian, etc.)
} else if chars_with_cmd.to_ascii_uppercase() != chars_with_cmd {
chars_with_shift = chars_with_cmd.to_ascii_uppercase();
}
chars_ignoring_modifiers = chars_with_cmd;
}
if !control && !command && !function {
let mut mods = NO_MOD;
if shift {
mods |= SHIFT_MOD;
}
if alt {
mods |= OPTION_MOD;
}
key_char = Some(chars_for_modified_key(native_event.keyCode(), mods));
}
let mut key = if shift
&& chars_ignoring_modifiers
.chars()
.all(|c| c.is_ascii_lowercase())
{
chars_ignoring_modifiers
} else if shift {
shift = false;
chars_with_shift
} else {
chars_ignoring_modifiers
};
key
}
};
Keystroke {
modifiers: Modifiers {
control,
alt,
shift,
platform: command,
function,
},
key,
key_char,
} }
};
Keystroke {
modifiers: Modifiers {
control,
alt,
shift,
platform: command,
function,
},
key,
key_char,
} }
} }

View file

@ -471,7 +471,8 @@ impl MetalRenderer {
if !ok { if !ok {
command_encoder.end_encoding(); command_encoder.end_encoding();
return Err(anyhow!("scene too large: {} paths, {} shadows, {} quads, {} underlines, {} mono, {} poly, {} surfaces", return Err(anyhow!(
"scene too large: {} paths, {} shadows, {} quads, {} underlines, {} mono, {} poly, {} surfaces",
scene.paths.len(), scene.paths.len(),
scene.shadows.len(), scene.shadows.len(),
scene.quads.len(), scene.quads.len(),

View file

@ -132,7 +132,7 @@ fn append_system_fallbacks(fallback_array: CFMutableArrayRef, font_ref: CTFontRe
} }
#[link(name = "CoreText", kind = "framework")] #[link(name = "CoreText", kind = "framework")]
extern "C" { unsafe extern "C" {
static kCTFontOpenTypeFeatureTag: CFStringRef; static kCTFontOpenTypeFeatureTag: CFStringRef;
static kCTFontOpenTypeFeatureValue: CFStringRef; static kCTFontOpenTypeFeatureValue: CFStringRef;

View file

@ -68,79 +68,82 @@ static mut APP_DELEGATE_CLASS: *const Class = ptr::null();
#[ctor] #[ctor]
unsafe fn build_classes() { unsafe fn build_classes() {
APP_CLASS = { unsafe {
let mut decl = ClassDecl::new("GPUIApplication", class!(NSApplication)).unwrap(); APP_CLASS = {
decl.add_ivar::<*mut c_void>(MAC_PLATFORM_IVAR); let mut decl = ClassDecl::new("GPUIApplication", class!(NSApplication)).unwrap();
decl.register() decl.add_ivar::<*mut c_void>(MAC_PLATFORM_IVAR);
decl.register()
}
}; };
unsafe {
APP_DELEGATE_CLASS = unsafe {
let mut decl = ClassDecl::new("GPUIApplicationDelegate", class!(NSResponder)).unwrap();
decl.add_ivar::<*mut c_void>(MAC_PLATFORM_IVAR);
decl.add_method(
sel!(applicationDidFinishLaunching:),
did_finish_launching as extern "C" fn(&mut Object, Sel, id),
);
decl.add_method(
sel!(applicationShouldHandleReopen:hasVisibleWindows:),
should_handle_reopen as extern "C" fn(&mut Object, Sel, id, bool),
);
decl.add_method(
sel!(applicationWillTerminate:),
will_terminate as extern "C" fn(&mut Object, Sel, id),
);
decl.add_method(
sel!(handleGPUIMenuItem:),
handle_menu_item as extern "C" fn(&mut Object, Sel, id),
);
// Add menu item handlers so that OS save panels have the correct key commands
decl.add_method(
sel!(cut:),
handle_menu_item as extern "C" fn(&mut Object, Sel, id),
);
decl.add_method(
sel!(copy:),
handle_menu_item as extern "C" fn(&mut Object, Sel, id),
);
decl.add_method(
sel!(paste:),
handle_menu_item as extern "C" fn(&mut Object, Sel, id),
);
decl.add_method(
sel!(selectAll:),
handle_menu_item as extern "C" fn(&mut Object, Sel, id),
);
decl.add_method(
sel!(undo:),
handle_menu_item as extern "C" fn(&mut Object, Sel, id),
);
decl.add_method(
sel!(redo:),
handle_menu_item as extern "C" fn(&mut Object, Sel, id),
);
decl.add_method(
sel!(validateMenuItem:),
validate_menu_item as extern "C" fn(&mut Object, Sel, id) -> bool,
);
decl.add_method(
sel!(menuWillOpen:),
menu_will_open as extern "C" fn(&mut Object, Sel, id),
);
decl.add_method(
sel!(applicationDockMenu:),
handle_dock_menu as extern "C" fn(&mut Object, Sel, id) -> id,
);
decl.add_method(
sel!(application:openURLs:),
open_urls as extern "C" fn(&mut Object, Sel, id, id),
);
APP_DELEGATE_CLASS = { decl.add_method(
let mut decl = ClassDecl::new("GPUIApplicationDelegate", class!(NSResponder)).unwrap(); sel!(onKeyboardLayoutChange:),
decl.add_ivar::<*mut c_void>(MAC_PLATFORM_IVAR); on_keyboard_layout_change as extern "C" fn(&mut Object, Sel, id),
decl.add_method( );
sel!(applicationDidFinishLaunching:),
did_finish_launching as extern "C" fn(&mut Object, Sel, id),
);
decl.add_method(
sel!(applicationShouldHandleReopen:hasVisibleWindows:),
should_handle_reopen as extern "C" fn(&mut Object, Sel, id, bool),
);
decl.add_method(
sel!(applicationWillTerminate:),
will_terminate as extern "C" fn(&mut Object, Sel, id),
);
decl.add_method(
sel!(handleGPUIMenuItem:),
handle_menu_item as extern "C" fn(&mut Object, Sel, id),
);
// Add menu item handlers so that OS save panels have the correct key commands
decl.add_method(
sel!(cut:),
handle_menu_item as extern "C" fn(&mut Object, Sel, id),
);
decl.add_method(
sel!(copy:),
handle_menu_item as extern "C" fn(&mut Object, Sel, id),
);
decl.add_method(
sel!(paste:),
handle_menu_item as extern "C" fn(&mut Object, Sel, id),
);
decl.add_method(
sel!(selectAll:),
handle_menu_item as extern "C" fn(&mut Object, Sel, id),
);
decl.add_method(
sel!(undo:),
handle_menu_item as extern "C" fn(&mut Object, Sel, id),
);
decl.add_method(
sel!(redo:),
handle_menu_item as extern "C" fn(&mut Object, Sel, id),
);
decl.add_method(
sel!(validateMenuItem:),
validate_menu_item as extern "C" fn(&mut Object, Sel, id) -> bool,
);
decl.add_method(
sel!(menuWillOpen:),
menu_will_open as extern "C" fn(&mut Object, Sel, id),
);
decl.add_method(
sel!(applicationDockMenu:),
handle_dock_menu as extern "C" fn(&mut Object, Sel, id) -> id,
);
decl.add_method(
sel!(application:openURLs:),
open_urls as extern "C" fn(&mut Object, Sel, id, id),
);
decl.add_method( decl.register()
sel!(onKeyboardLayoutChange:), }
on_keyboard_layout_change as extern "C" fn(&mut Object, Sel, id),
);
decl.register()
} }
} }
@ -206,14 +209,16 @@ impl MacPlatform {
} }
unsafe fn read_from_pasteboard(&self, pasteboard: *mut Object, kind: id) -> Option<&[u8]> { unsafe fn read_from_pasteboard(&self, pasteboard: *mut Object, kind: id) -> Option<&[u8]> {
let data = pasteboard.dataForType(kind); unsafe {
if data == nil { let data = pasteboard.dataForType(kind);
None if data == nil {
} else { None
Some(slice::from_raw_parts( } else {
data.bytes() as *mut u8, Some(slice::from_raw_parts(
data.length() as usize, data.bytes() as *mut u8,
)) data.length() as usize,
))
}
} }
} }
@ -224,36 +229,38 @@ impl MacPlatform {
actions: &mut Vec<Box<dyn Action>>, actions: &mut Vec<Box<dyn Action>>,
keymap: &Keymap, keymap: &Keymap,
) -> id { ) -> id {
let application_menu = NSMenu::new(nil).autorelease(); unsafe {
application_menu.setDelegate_(delegate); let application_menu = NSMenu::new(nil).autorelease();
application_menu.setDelegate_(delegate);
for menu_config in menus { for menu_config in menus {
let menu = NSMenu::new(nil).autorelease(); let menu = NSMenu::new(nil).autorelease();
let menu_title = ns_string(&menu_config.name); let menu_title = ns_string(&menu_config.name);
menu.setTitle_(menu_title); menu.setTitle_(menu_title);
menu.setDelegate_(delegate); menu.setDelegate_(delegate);
for item_config in menu_config.items { for item_config in menu_config.items {
menu.addItem_(Self::create_menu_item( menu.addItem_(Self::create_menu_item(
item_config, item_config,
delegate, delegate,
actions, actions,
keymap, keymap,
)); ));
}
let menu_item = NSMenuItem::new(nil).autorelease();
menu_item.setTitle_(menu_title);
menu_item.setSubmenu_(menu);
application_menu.addItem_(menu_item);
if menu_config.name == "Window" {
let app: id = msg_send![APP_CLASS, sharedApplication];
app.setWindowsMenu_(menu);
}
} }
let menu_item = NSMenuItem::new(nil).autorelease(); application_menu
menu_item.setTitle_(menu_title);
menu_item.setSubmenu_(menu);
application_menu.addItem_(menu_item);
if menu_config.name == "Window" {
let app: id = msg_send![APP_CLASS, sharedApplication];
app.setWindowsMenu_(menu);
}
} }
application_menu
} }
unsafe fn create_dock_menu( unsafe fn create_dock_menu(
@ -263,18 +270,20 @@ impl MacPlatform {
actions: &mut Vec<Box<dyn Action>>, actions: &mut Vec<Box<dyn Action>>,
keymap: &Keymap, keymap: &Keymap,
) -> id { ) -> id {
let dock_menu = NSMenu::new(nil); unsafe {
dock_menu.setDelegate_(delegate); let dock_menu = NSMenu::new(nil);
for item_config in menu_items { dock_menu.setDelegate_(delegate);
dock_menu.addItem_(Self::create_menu_item( for item_config in menu_items {
item_config, dock_menu.addItem_(Self::create_menu_item(
delegate, item_config,
actions, delegate,
keymap, actions,
)); keymap,
} ));
}
dock_menu dock_menu
}
} }
unsafe fn create_menu_item( unsafe fn create_menu_item(
@ -283,70 +292,80 @@ impl MacPlatform {
actions: &mut Vec<Box<dyn Action>>, actions: &mut Vec<Box<dyn Action>>,
keymap: &Keymap, keymap: &Keymap,
) -> id { ) -> id {
match item { unsafe {
MenuItem::Separator => NSMenuItem::separatorItem(nil), match item {
MenuItem::Action { MenuItem::Separator => NSMenuItem::separatorItem(nil),
name, MenuItem::Action {
action, name,
os_action, action,
} => { os_action,
let keystrokes = crate::Keymap::binding_to_display_from_bindings_iterator( } => {
keymap.bindings_for_action(action.as_ref()), let keystrokes = crate::Keymap::binding_to_display_from_bindings_iterator(
) keymap.bindings_for_action(action.as_ref()),
.map(|binding| binding.keystrokes()); )
.map(|binding| binding.keystrokes());
let selector = match os_action { let selector = match os_action {
Some(crate::OsAction::Cut) => selector("cut:"), Some(crate::OsAction::Cut) => selector("cut:"),
Some(crate::OsAction::Copy) => selector("copy:"), Some(crate::OsAction::Copy) => selector("copy:"),
Some(crate::OsAction::Paste) => selector("paste:"), Some(crate::OsAction::Paste) => selector("paste:"),
Some(crate::OsAction::SelectAll) => selector("selectAll:"), Some(crate::OsAction::SelectAll) => selector("selectAll:"),
// "undo:" and "redo:" are always disabled in our case, as // "undo:" and "redo:" are always disabled in our case, as
// we don't have a NSTextView/NSTextField to enable them on. // we don't have a NSTextView/NSTextField to enable them on.
Some(crate::OsAction::Undo) => selector("handleGPUIMenuItem:"), Some(crate::OsAction::Undo) => selector("handleGPUIMenuItem:"),
Some(crate::OsAction::Redo) => selector("handleGPUIMenuItem:"), Some(crate::OsAction::Redo) => selector("handleGPUIMenuItem:"),
None => selector("handleGPUIMenuItem:"), None => selector("handleGPUIMenuItem:"),
}; };
let item; let item;
if let Some(keystrokes) = keystrokes { if let Some(keystrokes) = keystrokes {
if keystrokes.len() == 1 { if keystrokes.len() == 1 {
let keystroke = &keystrokes[0]; let keystroke = &keystrokes[0];
let mut mask = NSEventModifierFlags::empty(); let mut mask = NSEventModifierFlags::empty();
for (modifier, flag) in &[ for (modifier, flag) in &[
( (
keystroke.modifiers.platform, keystroke.modifiers.platform,
NSEventModifierFlags::NSCommandKeyMask, NSEventModifierFlags::NSCommandKeyMask,
), ),
( (
keystroke.modifiers.control, keystroke.modifiers.control,
NSEventModifierFlags::NSControlKeyMask, NSEventModifierFlags::NSControlKeyMask,
), ),
( (
keystroke.modifiers.alt, keystroke.modifiers.alt,
NSEventModifierFlags::NSAlternateKeyMask, NSEventModifierFlags::NSAlternateKeyMask,
), ),
( (
keystroke.modifiers.shift, keystroke.modifiers.shift,
NSEventModifierFlags::NSShiftKeyMask, NSEventModifierFlags::NSShiftKeyMask,
), ),
] { ] {
if *modifier { if *modifier {
mask |= *flag; mask |= *flag;
}
} }
}
item = NSMenuItem::alloc(nil) item = NSMenuItem::alloc(nil)
.initWithTitle_action_keyEquivalent_( .initWithTitle_action_keyEquivalent_(
ns_string(&name), ns_string(&name),
selector, selector,
ns_string(key_to_native(&keystroke.key).as_ref()), ns_string(key_to_native(&keystroke.key).as_ref()),
) )
.autorelease(); .autorelease();
if MacPlatform::os_version().unwrap() >= SemanticVersion::new(12, 0, 0) { if MacPlatform::os_version().unwrap() >= SemanticVersion::new(12, 0, 0)
let _: () = {
msg_send![item, setAllowsAutomaticKeyEquivalentLocalization: NO]; let _: () = msg_send![item, setAllowsAutomaticKeyEquivalentLocalization: NO];
}
item.setKeyEquivalentModifierMask_(mask);
} else {
item = NSMenuItem::alloc(nil)
.initWithTitle_action_keyEquivalent_(
ns_string(&name),
selector,
ns_string(""),
)
.autorelease();
} }
item.setKeyEquivalentModifierMask_(mask);
} else { } else {
item = NSMenuItem::alloc(nil) item = NSMenuItem::alloc(nil)
.initWithTitle_action_keyEquivalent_( .initWithTitle_action_keyEquivalent_(
@ -356,36 +375,28 @@ impl MacPlatform {
) )
.autorelease(); .autorelease();
} }
} else {
item = NSMenuItem::alloc(nil)
.initWithTitle_action_keyEquivalent_(
ns_string(&name),
selector,
ns_string(""),
)
.autorelease();
}
let tag = actions.len() as NSInteger; let tag = actions.len() as NSInteger;
let _: () = msg_send![item, setTag: tag]; let _: () = msg_send![item, setTag: tag];
actions.push(action); actions.push(action);
item item
}
MenuItem::Submenu(Menu { name, items }) => {
let item = NSMenuItem::new(nil).autorelease();
let submenu = NSMenu::new(nil).autorelease();
submenu.setDelegate_(delegate);
for item in items {
submenu.addItem_(Self::create_menu_item(item, delegate, actions, keymap));
}
item.setSubmenu_(submenu);
item.setTitle_(ns_string(&name));
if name == "Services" {
let app: id = msg_send![APP_CLASS, sharedApplication];
app.setServicesMenu_(item);
} }
MenuItem::Submenu(Menu { name, items }) => {
let item = NSMenuItem::new(nil).autorelease();
let submenu = NSMenu::new(nil).autorelease();
submenu.setDelegate_(delegate);
for item in items {
submenu.addItem_(Self::create_menu_item(item, delegate, actions, keymap));
}
item.setSubmenu_(submenu);
item.setTitle_(ns_string(&name));
if name == "Services" {
let app: id = msg_send![APP_CLASS, sharedApplication];
app.setServicesMenu_(item);
}
item item
}
} }
} }
} }
@ -460,8 +471,10 @@ impl Platform for MacPlatform {
} }
unsafe extern "C" fn quit(_: *mut c_void) { unsafe extern "C" fn quit(_: *mut c_void) {
let app = NSApplication::sharedApplication(nil); unsafe {
let _: () = msg_send![app, terminate: nil]; let app = NSApplication::sharedApplication(nil);
let _: () = msg_send![app, terminate: nil];
}
} }
} }
@ -1180,75 +1193,81 @@ impl MacPlatform {
state: &MacPlatformState, state: &MacPlatformState,
text_bytes: &[u8], text_bytes: &[u8],
) -> ClipboardItem { ) -> ClipboardItem {
let text = String::from_utf8_lossy(text_bytes).to_string(); unsafe {
let metadata = self let text = String::from_utf8_lossy(text_bytes).to_string();
.read_from_pasteboard(state.pasteboard, state.text_hash_pasteboard_type) let metadata = self
.and_then(|hash_bytes| { .read_from_pasteboard(state.pasteboard, state.text_hash_pasteboard_type)
let hash_bytes = hash_bytes.try_into().ok()?; .and_then(|hash_bytes| {
let hash = u64::from_be_bytes(hash_bytes); let hash_bytes = hash_bytes.try_into().ok()?;
let metadata = let hash = u64::from_be_bytes(hash_bytes);
self.read_from_pasteboard(state.pasteboard, state.metadata_pasteboard_type)?; let metadata = self
.read_from_pasteboard(state.pasteboard, state.metadata_pasteboard_type)?;
if hash == ClipboardString::text_hash(&text) { if hash == ClipboardString::text_hash(&text) {
String::from_utf8(metadata.to_vec()).ok() String::from_utf8(metadata.to_vec()).ok()
} else { } else {
None None
} }
}); });
ClipboardItem { ClipboardItem {
entries: vec![ClipboardEntry::String(ClipboardString { text, metadata })], entries: vec![ClipboardEntry::String(ClipboardString { text, metadata })],
}
} }
} }
unsafe fn write_plaintext_to_clipboard(&self, string: &ClipboardString) { unsafe fn write_plaintext_to_clipboard(&self, string: &ClipboardString) {
let state = self.0.lock(); unsafe {
state.pasteboard.clearContents(); let state = self.0.lock();
state.pasteboard.clearContents();
let text_bytes = NSData::dataWithBytes_length_( let text_bytes = NSData::dataWithBytes_length_(
nil,
string.text.as_ptr() as *const c_void,
string.text.len() as u64,
);
state
.pasteboard
.setData_forType(text_bytes, NSPasteboardTypeString);
if let Some(metadata) = string.metadata.as_ref() {
let hash_bytes = ClipboardString::text_hash(&string.text).to_be_bytes();
let hash_bytes = NSData::dataWithBytes_length_(
nil, nil,
hash_bytes.as_ptr() as *const c_void, string.text.as_ptr() as *const c_void,
hash_bytes.len() as u64, string.text.len() as u64,
); );
state state
.pasteboard .pasteboard
.setData_forType(hash_bytes, state.text_hash_pasteboard_type); .setData_forType(text_bytes, NSPasteboardTypeString);
let metadata_bytes = NSData::dataWithBytes_length_( if let Some(metadata) = string.metadata.as_ref() {
nil, let hash_bytes = ClipboardString::text_hash(&string.text).to_be_bytes();
metadata.as_ptr() as *const c_void, let hash_bytes = NSData::dataWithBytes_length_(
metadata.len() as u64, nil,
); hash_bytes.as_ptr() as *const c_void,
state hash_bytes.len() as u64,
.pasteboard );
.setData_forType(metadata_bytes, state.metadata_pasteboard_type); state
.pasteboard
.setData_forType(hash_bytes, state.text_hash_pasteboard_type);
let metadata_bytes = NSData::dataWithBytes_length_(
nil,
metadata.as_ptr() as *const c_void,
metadata.len() as u64,
);
state
.pasteboard
.setData_forType(metadata_bytes, state.metadata_pasteboard_type);
}
} }
} }
unsafe fn write_image_to_clipboard(&self, image: &Image) { unsafe fn write_image_to_clipboard(&self, image: &Image) {
let state = self.0.lock(); unsafe {
state.pasteboard.clearContents(); let state = self.0.lock();
state.pasteboard.clearContents();
let bytes = NSData::dataWithBytes_length_( let bytes = NSData::dataWithBytes_length_(
nil, nil,
image.bytes.as_ptr() as *const c_void, image.bytes.as_ptr() as *const c_void,
image.bytes.len() as u64, image.bytes.len() as u64,
); );
state state
.pasteboard .pasteboard
.setData_forType(bytes, Into::<UTType>::into(image.format).inner_mut()); .setData_forType(bytes, Into::<UTType>::into(image.format).inner_mut());
}
} }
} }
@ -1280,15 +1299,17 @@ fn try_clipboard_image(pasteboard: id, format: ImageFormat) -> Option<ClipboardI
unsafe fn path_from_objc(path: id) -> PathBuf { unsafe fn path_from_objc(path: id) -> PathBuf {
let len = msg_send![path, lengthOfBytesUsingEncoding: NSUTF8StringEncoding]; let len = msg_send![path, lengthOfBytesUsingEncoding: NSUTF8StringEncoding];
let bytes = path.UTF8String() as *const u8; let bytes = unsafe { path.UTF8String() as *const u8 };
let path = str::from_utf8(slice::from_raw_parts(bytes, len)).unwrap(); let path = str::from_utf8(unsafe { slice::from_raw_parts(bytes, len) }).unwrap();
PathBuf::from(path) PathBuf::from(path)
} }
unsafe fn get_mac_platform(object: &mut Object) -> &MacPlatform { unsafe fn get_mac_platform(object: &mut Object) -> &MacPlatform {
let platform_ptr: *mut c_void = *object.get_ivar(MAC_PLATFORM_IVAR); unsafe {
assert!(!platform_ptr.is_null()); let platform_ptr: *mut c_void = *object.get_ivar(MAC_PLATFORM_IVAR);
&*(platform_ptr as *const MacPlatform) assert!(!platform_ptr.is_null());
&*(platform_ptr as *const MacPlatform)
}
} }
extern "C" fn did_finish_launching(this: &mut Object, _: Sel, _: id) { extern "C" fn did_finish_launching(this: &mut Object, _: Sel, _: id) {
@ -1438,25 +1459,24 @@ extern "C" fn handle_dock_menu(this: &mut Object, _: Sel, _: id) -> id {
} }
unsafe fn ns_string(string: &str) -> id { unsafe fn ns_string(string: &str) -> id {
NSString::alloc(nil).init_str(string).autorelease() unsafe { NSString::alloc(nil).init_str(string).autorelease() }
} }
unsafe fn ns_url_to_path(url: id) -> Result<PathBuf> { unsafe fn ns_url_to_path(url: id) -> Result<PathBuf> {
let path: *mut c_char = msg_send![url, fileSystemRepresentation]; let path: *mut c_char = msg_send![url, fileSystemRepresentation];
if path.is_null() { if path.is_null() {
Err(anyhow!( Err(anyhow!("url is not a file path: {}", unsafe {
"url is not a file path: {}",
CStr::from_ptr(url.absoluteString().UTF8String()).to_string_lossy() CStr::from_ptr(url.absoluteString().UTF8String()).to_string_lossy()
)) }))
} else { } else {
Ok(PathBuf::from(OsStr::from_bytes( Ok(PathBuf::from(OsStr::from_bytes(unsafe {
CStr::from_ptr(path).to_bytes(), CStr::from_ptr(path).to_bytes()
))) })))
} }
} }
#[link(name = "Carbon", kind = "framework")] #[link(name = "Carbon", kind = "framework")]
extern "C" { unsafe extern "C" {
pub(super) fn TISCopyCurrentKeyboardLayoutInputSource() -> *mut Object; pub(super) fn TISCopyCurrentKeyboardLayoutInputSource() -> *mut Object;
pub(super) fn TISGetInputSourceProperty( pub(super) fn TISGetInputSourceProperty(
inputSource: *mut Object, inputSource: *mut Object,
@ -1485,7 +1505,7 @@ mod security {
use super::*; use super::*;
#[link(name = "Security", kind = "framework")] #[link(name = "Security", kind = "framework")]
extern "C" { unsafe extern "C" {
pub static kSecClass: CFStringRef; pub static kSecClass: CFStringRef;
pub static kSecClassInternetPassword: CFStringRef; pub static kSecClassInternetPassword: CFStringRef;
pub static kSecAttrServer: CFStringRef; pub static kSecAttrServer: CFStringRef;

View file

@ -37,7 +37,7 @@ pub struct MacScreenCaptureStream {
} }
#[link(name = "ScreenCaptureKit", kind = "framework")] #[link(name = "ScreenCaptureKit", kind = "framework")]
extern "C" {} unsafe extern "C" {}
static mut DELEGATE_CLASS: *const Class = ptr::null(); static mut DELEGATE_CLASS: *const Class = ptr::null();
static mut OUTPUT_CLASS: *const Class = ptr::null(); static mut OUTPUT_CLASS: *const Class = ptr::null();
@ -200,28 +200,31 @@ pub(crate) fn get_sources() -> oneshot::Receiver<Result<Vec<Box<dyn ScreenCaptur
#[ctor] #[ctor]
unsafe fn build_classes() { unsafe fn build_classes() {
let mut decl = ClassDecl::new("GPUIStreamDelegate", class!(NSObject)).unwrap(); let mut decl = ClassDecl::new("GPUIStreamDelegate", class!(NSObject)).unwrap();
decl.add_method( unsafe {
sel!(outputVideoEffectDidStartForStream:), decl.add_method(
output_video_effect_did_start_for_stream as extern "C" fn(&Object, Sel, id), sel!(outputVideoEffectDidStartForStream:),
); output_video_effect_did_start_for_stream as extern "C" fn(&Object, Sel, id),
decl.add_method( );
sel!(outputVideoEffectDidStopForStream:), decl.add_method(
output_video_effect_did_stop_for_stream as extern "C" fn(&Object, Sel, id), sel!(outputVideoEffectDidStopForStream:),
); output_video_effect_did_stop_for_stream as extern "C" fn(&Object, Sel, id),
decl.add_method( );
sel!(stream:didStopWithError:), decl.add_method(
stream_did_stop_with_error as extern "C" fn(&Object, Sel, id, id), sel!(stream:didStopWithError:),
); stream_did_stop_with_error as extern "C" fn(&Object, Sel, id, id),
DELEGATE_CLASS = decl.register(); );
DELEGATE_CLASS = decl.register();
let mut decl = ClassDecl::new("GPUIStreamOutput", class!(NSObject)).unwrap(); let mut decl = ClassDecl::new("GPUIStreamOutput", class!(NSObject)).unwrap();
decl.add_method( decl.add_method(
sel!(stream:didOutputSampleBuffer:ofType:), sel!(stream:didOutputSampleBuffer:ofType:),
stream_did_output_sample_buffer_of_type as extern "C" fn(&Object, Sel, id, id, NSInteger), stream_did_output_sample_buffer_of_type
); as extern "C" fn(&Object, Sel, id, id, NSInteger),
decl.add_ivar::<*mut c_void>(FRAME_CALLBACK_IVAR); );
decl.add_ivar::<*mut c_void>(FRAME_CALLBACK_IVAR);
OUTPUT_CLASS = decl.register(); OUTPUT_CLASS = decl.register();
}
} }
extern "C" fn output_video_effect_did_start_for_stream(_this: &Object, _: Sel, _stream: id) {} extern "C" fn output_video_effect_did_start_for_stream(_this: &Object, _: Sel, _stream: id) {}

View file

@ -664,9 +664,11 @@ mod lenient_font_attributes {
} }
unsafe fn wrap_under_get_rule(reference: CFStringRef) -> CFString { unsafe fn wrap_under_get_rule(reference: CFStringRef) -> CFString {
assert!(!reference.is_null(), "Attempted to create a NULL object."); unsafe {
let reference = CFRetain(reference as *const ::std::os::raw::c_void) as CFStringRef; assert!(!reference.is_null(), "Attempted to create a NULL object.");
TCFType::wrap_under_create_rule(reference) let reference = CFRetain(reference as *const ::std::os::raw::c_void) as CFStringRef;
TCFType::wrap_under_create_rule(reference)
}
} }
} }

View file

@ -80,7 +80,7 @@ const NSDragOperationNone: NSDragOperation = 0;
const NSDragOperationCopy: NSDragOperation = 1; const NSDragOperationCopy: NSDragOperation = 1;
#[link(name = "CoreGraphics", kind = "framework")] #[link(name = "CoreGraphics", kind = "framework")]
extern "C" { unsafe extern "C" {
// Widely used private APIs; Apple uses them for their Terminal.app. // Widely used private APIs; Apple uses them for their Terminal.app.
fn CGSMainConnectionID() -> id; fn CGSMainConnectionID() -> id;
fn CGSSetWindowBackgroundBlurRadius( fn CGSSetWindowBackgroundBlurRadius(
@ -92,152 +92,155 @@ extern "C" {
#[ctor] #[ctor]
unsafe fn build_classes() { unsafe fn build_classes() {
WINDOW_CLASS = build_window_class("GPUIWindow", class!(NSWindow)); unsafe {
PANEL_CLASS = build_window_class("GPUIPanel", class!(NSPanel)); WINDOW_CLASS = build_window_class("GPUIWindow", class!(NSWindow));
VIEW_CLASS = { PANEL_CLASS = build_window_class("GPUIPanel", class!(NSPanel));
let mut decl = ClassDecl::new("GPUIView", class!(NSView)).unwrap(); VIEW_CLASS = {
decl.add_ivar::<*mut c_void>(WINDOW_STATE_IVAR); let mut decl = ClassDecl::new("GPUIView", class!(NSView)).unwrap();
decl.add_ivar::<*mut c_void>(WINDOW_STATE_IVAR);
unsafe {
decl.add_method(sel!(dealloc), dealloc_view as extern "C" fn(&Object, Sel));
decl.add_method(sel!(dealloc), dealloc_view as extern "C" fn(&Object, Sel)); decl.add_method(
sel!(performKeyEquivalent:),
handle_key_equivalent as extern "C" fn(&Object, Sel, id) -> BOOL,
);
decl.add_method(
sel!(keyDown:),
handle_key_down as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(keyUp:),
handle_key_up as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(mouseDown:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(mouseUp:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(rightMouseDown:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(rightMouseUp:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(otherMouseDown:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(otherMouseUp:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(mouseMoved:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(mouseExited:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(mouseDragged:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(scrollWheel:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(swipeWithEvent:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(flagsChanged:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method( decl.add_method(
sel!(performKeyEquivalent:), sel!(makeBackingLayer),
handle_key_equivalent as extern "C" fn(&Object, Sel, id) -> BOOL, make_backing_layer as extern "C" fn(&Object, Sel) -> id,
); );
decl.add_method(
sel!(keyDown:),
handle_key_down as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(keyUp:),
handle_key_up as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(mouseDown:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(mouseUp:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(rightMouseDown:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(rightMouseUp:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(otherMouseDown:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(otherMouseUp:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(mouseMoved:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(mouseExited:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(mouseDragged:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(scrollWheel:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(swipeWithEvent:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(flagsChanged:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method( decl.add_protocol(Protocol::get("CALayerDelegate").unwrap());
sel!(makeBackingLayer), decl.add_method(
make_backing_layer as extern "C" fn(&Object, Sel) -> id, sel!(viewDidChangeBackingProperties),
); view_did_change_backing_properties as extern "C" fn(&Object, Sel),
);
decl.add_method(
sel!(setFrameSize:),
set_frame_size as extern "C" fn(&Object, Sel, NSSize),
);
decl.add_method(
sel!(displayLayer:),
display_layer as extern "C" fn(&Object, Sel, id),
);
decl.add_protocol(Protocol::get("CALayerDelegate").unwrap()); decl.add_protocol(Protocol::get("NSTextInputClient").unwrap());
decl.add_method( decl.add_method(
sel!(viewDidChangeBackingProperties), sel!(validAttributesForMarkedText),
view_did_change_backing_properties as extern "C" fn(&Object, Sel), valid_attributes_for_marked_text as extern "C" fn(&Object, Sel) -> id,
); );
decl.add_method( decl.add_method(
sel!(setFrameSize:), sel!(hasMarkedText),
set_frame_size as extern "C" fn(&Object, Sel, NSSize), has_marked_text as extern "C" fn(&Object, Sel) -> BOOL,
); );
decl.add_method( decl.add_method(
sel!(displayLayer:), sel!(markedRange),
display_layer as extern "C" fn(&Object, Sel, id), marked_range as extern "C" fn(&Object, Sel) -> NSRange,
); );
decl.add_method(
sel!(selectedRange),
selected_range as extern "C" fn(&Object, Sel) -> NSRange,
);
decl.add_method(
sel!(firstRectForCharacterRange:actualRange:),
first_rect_for_character_range
as extern "C" fn(&Object, Sel, NSRange, id) -> NSRect,
);
decl.add_method(
sel!(insertText:replacementRange:),
insert_text as extern "C" fn(&Object, Sel, id, NSRange),
);
decl.add_method(
sel!(setMarkedText:selectedRange:replacementRange:),
set_marked_text as extern "C" fn(&Object, Sel, id, NSRange, NSRange),
);
decl.add_method(sel!(unmarkText), unmark_text as extern "C" fn(&Object, Sel));
decl.add_method(
sel!(attributedSubstringForProposedRange:actualRange:),
attributed_substring_for_proposed_range
as extern "C" fn(&Object, Sel, NSRange, *mut c_void) -> id,
);
decl.add_method(
sel!(viewDidChangeEffectiveAppearance),
view_did_change_effective_appearance as extern "C" fn(&Object, Sel),
);
decl.add_protocol(Protocol::get("NSTextInputClient").unwrap()); // Suppress beep on keystrokes with modifier keys.
decl.add_method( decl.add_method(
sel!(validAttributesForMarkedText), sel!(doCommandBySelector:),
valid_attributes_for_marked_text as extern "C" fn(&Object, Sel) -> id, do_command_by_selector as extern "C" fn(&Object, Sel, Sel),
); );
decl.add_method(
sel!(hasMarkedText),
has_marked_text as extern "C" fn(&Object, Sel) -> BOOL,
);
decl.add_method(
sel!(markedRange),
marked_range as extern "C" fn(&Object, Sel) -> NSRange,
);
decl.add_method(
sel!(selectedRange),
selected_range as extern "C" fn(&Object, Sel) -> NSRange,
);
decl.add_method(
sel!(firstRectForCharacterRange:actualRange:),
first_rect_for_character_range as extern "C" fn(&Object, Sel, NSRange, id) -> NSRect,
);
decl.add_method(
sel!(insertText:replacementRange:),
insert_text as extern "C" fn(&Object, Sel, id, NSRange),
);
decl.add_method(
sel!(setMarkedText:selectedRange:replacementRange:),
set_marked_text as extern "C" fn(&Object, Sel, id, NSRange, NSRange),
);
decl.add_method(sel!(unmarkText), unmark_text as extern "C" fn(&Object, Sel));
decl.add_method(
sel!(attributedSubstringForProposedRange:actualRange:),
attributed_substring_for_proposed_range
as extern "C" fn(&Object, Sel, NSRange, *mut c_void) -> id,
);
decl.add_method(
sel!(viewDidChangeEffectiveAppearance),
view_did_change_effective_appearance as extern "C" fn(&Object, Sel),
);
// Suppress beep on keystrokes with modifier keys. decl.add_method(
decl.add_method( sel!(acceptsFirstMouse:),
sel!(doCommandBySelector:), accepts_first_mouse as extern "C" fn(&Object, Sel, id) -> BOOL,
do_command_by_selector as extern "C" fn(&Object, Sel, Sel), );
);
decl.add_method( decl.add_method(
sel!(acceptsFirstMouse:), sel!(characterIndexForPoint:),
accepts_first_mouse as extern "C" fn(&Object, Sel, id) -> BOOL, character_index_for_point as extern "C" fn(&Object, Sel, NSPoint) -> u64,
); );
}
decl.add_method( decl.register()
sel!(characterIndexForPoint:), };
character_index_for_point as extern "C" fn(&Object, Sel, NSPoint) -> u64, }
);
decl.register()
};
} }
pub(crate) fn convert_mouse_position(position: NSPoint, window_height: Pixels) -> Point<Pixels> { pub(crate) fn convert_mouse_position(position: NSPoint, window_height: Pixels) -> Point<Pixels> {
@ -249,78 +252,81 @@ pub(crate) fn convert_mouse_position(position: NSPoint, window_height: Pixels) -
} }
unsafe fn build_window_class(name: &'static str, superclass: &Class) -> *const Class { unsafe fn build_window_class(name: &'static str, superclass: &Class) -> *const Class {
let mut decl = ClassDecl::new(name, superclass).unwrap(); unsafe {
decl.add_ivar::<*mut c_void>(WINDOW_STATE_IVAR); let mut decl = ClassDecl::new(name, superclass).unwrap();
decl.add_method(sel!(dealloc), dealloc_window as extern "C" fn(&Object, Sel)); decl.add_ivar::<*mut c_void>(WINDOW_STATE_IVAR);
decl.add_method( decl.add_method(sel!(dealloc), dealloc_window as extern "C" fn(&Object, Sel));
sel!(canBecomeMainWindow),
yes as extern "C" fn(&Object, Sel) -> BOOL,
);
decl.add_method(
sel!(canBecomeKeyWindow),
yes as extern "C" fn(&Object, Sel) -> BOOL,
);
decl.add_method(
sel!(windowDidResize:),
window_did_resize as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(windowDidChangeOcclusionState:),
window_did_change_occlusion_state as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(windowWillEnterFullScreen:),
window_will_enter_fullscreen as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(windowWillExitFullScreen:),
window_will_exit_fullscreen as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(windowDidMove:),
window_did_move as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(windowDidChangeScreen:),
window_did_change_screen as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(windowDidBecomeKey:),
window_did_change_key_status as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(windowDidResignKey:),
window_did_change_key_status as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(windowShouldClose:),
window_should_close as extern "C" fn(&Object, Sel, id) -> BOOL,
);
decl.add_method(sel!(close), close_window as extern "C" fn(&Object, Sel)); decl.add_method(
sel!(canBecomeMainWindow),
yes as extern "C" fn(&Object, Sel) -> BOOL,
);
decl.add_method(
sel!(canBecomeKeyWindow),
yes as extern "C" fn(&Object, Sel) -> BOOL,
);
decl.add_method(
sel!(windowDidResize:),
window_did_resize as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(windowDidChangeOcclusionState:),
window_did_change_occlusion_state as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(windowWillEnterFullScreen:),
window_will_enter_fullscreen as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(windowWillExitFullScreen:),
window_will_exit_fullscreen as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(windowDidMove:),
window_did_move as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(windowDidChangeScreen:),
window_did_change_screen as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(windowDidBecomeKey:),
window_did_change_key_status as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(windowDidResignKey:),
window_did_change_key_status as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(windowShouldClose:),
window_should_close as extern "C" fn(&Object, Sel, id) -> BOOL,
);
decl.add_method( decl.add_method(sel!(close), close_window as extern "C" fn(&Object, Sel));
sel!(draggingEntered:),
dragging_entered as extern "C" fn(&Object, Sel, id) -> NSDragOperation,
);
decl.add_method(
sel!(draggingUpdated:),
dragging_updated as extern "C" fn(&Object, Sel, id) -> NSDragOperation,
);
decl.add_method(
sel!(draggingExited:),
dragging_exited as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(performDragOperation:),
perform_drag_operation as extern "C" fn(&Object, Sel, id) -> BOOL,
);
decl.add_method(
sel!(concludeDragOperation:),
conclude_drag_operation as extern "C" fn(&Object, Sel, id),
);
decl.register() decl.add_method(
sel!(draggingEntered:),
dragging_entered as extern "C" fn(&Object, Sel, id) -> NSDragOperation,
);
decl.add_method(
sel!(draggingUpdated:),
dragging_updated as extern "C" fn(&Object, Sel, id) -> NSDragOperation,
);
decl.add_method(
sel!(draggingExited:),
dragging_exited as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(performDragOperation:),
perform_drag_operation as extern "C" fn(&Object, Sel, id) -> BOOL,
);
decl.add_method(
sel!(concludeDragOperation:),
conclude_drag_operation as extern "C" fn(&Object, Sel, id),
);
decl.register()
}
} }
struct MacWindowState { struct MacWindowState {
@ -913,7 +919,7 @@ impl PlatformWindow for MacWindow {
.iter() .iter()
.enumerate() .enumerate()
.rev() .rev()
.find(|(_, &label)| label != "Cancel") .find(|(_, label)| **label != "Cancel")
.filter(|&(label_index, _)| label_index > 0); .filter(|&(label_index, _)| label_index > 0);
unsafe { unsafe {
@ -1200,16 +1206,20 @@ fn get_scale_factor(native_window: id) -> f32 {
} }
unsafe fn get_window_state(object: &Object) -> Arc<Mutex<MacWindowState>> { unsafe fn get_window_state(object: &Object) -> Arc<Mutex<MacWindowState>> {
let raw: *mut c_void = *object.get_ivar(WINDOW_STATE_IVAR); unsafe {
let rc1 = Arc::from_raw(raw as *mut Mutex<MacWindowState>); let raw: *mut c_void = *object.get_ivar(WINDOW_STATE_IVAR);
let rc2 = rc1.clone(); let rc1 = Arc::from_raw(raw as *mut Mutex<MacWindowState>);
mem::forget(rc1); let rc2 = rc1.clone();
rc2 mem::forget(rc1);
rc2
}
} }
unsafe fn drop_window_state(object: &Object) { unsafe fn drop_window_state(object: &Object) {
let raw: *mut c_void = *object.get_ivar(WINDOW_STATE_IVAR); unsafe {
Arc::from_raw(raw as *mut Mutex<MacWindowState>); let raw: *mut c_void = *object.get_ivar(WINDOW_STATE_IVAR);
Arc::from_raw(raw as *mut Mutex<MacWindowState>);
}
} }
extern "C" fn yes(_: &Object, _: Sel) -> BOOL { extern "C" fn yes(_: &Object, _: Sel) -> BOOL {
@ -2069,9 +2079,11 @@ where
} }
unsafe fn display_id_for_screen(screen: id) -> CGDirectDisplayID { unsafe fn display_id_for_screen(screen: id) -> CGDirectDisplayID {
let device_description = NSScreen::deviceDescription(screen); unsafe {
let screen_number_key: id = NSString::alloc(nil).init_str("NSScreenNumber"); let device_description = NSScreen::deviceDescription(screen);
let screen_number = device_description.objectForKey_(screen_number_key); let screen_number_key: id = NSString::alloc(nil).init_str("NSScreenNumber");
let screen_number: NSUInteger = msg_send![screen_number, unsignedIntegerValue]; let screen_number = device_description.objectForKey_(screen_number_key);
screen_number as CGDirectDisplayID let screen_number: NSUInteger = msg_send![screen_number, unsignedIntegerValue];
screen_number as CGDirectDisplayID
}
} }

View file

@ -10,26 +10,28 @@ use std::ffi::CStr;
impl WindowAppearance { impl WindowAppearance {
pub(crate) unsafe fn from_native(appearance: id) -> Self { pub(crate) unsafe fn from_native(appearance: id) -> Self {
let name: id = msg_send![appearance, name]; let name: id = msg_send![appearance, name];
if name == NSAppearanceNameVibrantLight { unsafe {
Self::VibrantLight if name == NSAppearanceNameVibrantLight {
} else if name == NSAppearanceNameVibrantDark { Self::VibrantLight
Self::VibrantDark } else if name == NSAppearanceNameVibrantDark {
} else if name == NSAppearanceNameAqua { Self::VibrantDark
Self::Light } else if name == NSAppearanceNameAqua {
} else if name == NSAppearanceNameDarkAqua { Self::Light
Self::Dark } else if name == NSAppearanceNameDarkAqua {
} else { Self::Dark
println!( } else {
"unknown appearance: {:?}", println!(
CStr::from_ptr(name.UTF8String()) "unknown appearance: {:?}",
); CStr::from_ptr(name.UTF8String())
Self::Light );
Self::Light
}
} }
} }
} }
#[link(name = "AppKit", kind = "framework")] #[link(name = "AppKit", kind = "framework")]
extern "C" { unsafe extern "C" {
pub static NSAppearanceNameAqua: id; pub static NSAppearanceNameAqua: id;
pub static NSAppearanceNameDarkAqua: id; pub static NSAppearanceNameDarkAqua: id;
} }

View file

@ -89,7 +89,7 @@ impl TestDispatcher {
self.state.lock().time = new_now; self.state.lock().time = new_now;
} }
pub fn simulate_random_delay(&self) -> impl 'static + Send + Future<Output = ()> { pub fn simulate_random_delay(&self) -> impl 'static + Send + Future<Output = ()> + use<> {
struct YieldNow { struct YieldNow {
pub(crate) count: usize, pub(crate) count: usize,
} }

View file

@ -333,7 +333,7 @@ impl DirectWriteState {
&self, &self,
font_features: &FontFeatures, font_features: &FontFeatures,
) -> Result<IDWriteTypography> { ) -> Result<IDWriteTypography> {
let direct_write_features = self.components.factory.CreateTypography()?; let direct_write_features = unsafe { self.components.factory.CreateTypography()? };
apply_font_features(&direct_write_features, font_features)?; apply_font_features(&direct_write_features, font_features)?;
Ok(direct_write_features) Ok(direct_write_features)
} }
@ -352,28 +352,32 @@ impl DirectWriteState {
} else { } else {
&self.custom_font_collection &self.custom_font_collection
}; };
let fontset = collection.GetFontSet().log_err()?; let fontset = unsafe { collection.GetFontSet().log_err()? };
let font = fontset let font = unsafe {
.GetMatchingFonts( fontset
&HSTRING::from(family_name), .GetMatchingFonts(
font_weight.into(), &HSTRING::from(family_name),
DWRITE_FONT_STRETCH_NORMAL, font_weight.into(),
font_style.into(), DWRITE_FONT_STRETCH_NORMAL,
) font_style.into(),
.log_err()?; )
let total_number = font.GetFontCount(); .log_err()?
};
let total_number = unsafe { font.GetFontCount() };
for index in 0..total_number { for index in 0..total_number {
let Some(font_face_ref) = font.GetFontFaceReference(index).log_err() else { let Some(font_face_ref) = (unsafe { font.GetFontFaceReference(index).log_err() })
else {
continue; continue;
}; };
let Some(font_face) = font_face_ref.CreateFontFace().log_err() else { let Some(font_face) = (unsafe { font_face_ref.CreateFontFace().log_err() }) else {
continue; continue;
}; };
let Some(identifier) = get_font_identifier(&font_face, &self.components.locale) else { let Some(identifier) = get_font_identifier(&font_face, &self.components.locale) else {
continue; continue;
}; };
let is_emoji = font_face.IsColorFont().as_bool(); let is_emoji = unsafe { font_face.IsColorFont().as_bool() };
let Some(direct_write_features) = self.generate_font_features(font_features).log_err() let Some(direct_write_features) =
(unsafe { self.generate_font_features(font_features).log_err() })
else { else {
continue; continue;
}; };
@ -396,14 +400,14 @@ impl DirectWriteState {
} }
unsafe fn update_system_font_collection(&mut self) { unsafe fn update_system_font_collection(&mut self) {
let mut collection = std::mem::zeroed(); let mut collection = unsafe { std::mem::zeroed() };
if self if unsafe {
.components self.components
.factory .factory
.GetSystemFontCollection(false, &mut collection, true) .GetSystemFontCollection(false, &mut collection, true)
.log_err() .log_err()
.is_some() .is_some()
{ } {
self.system_font_collection = collection.unwrap(); self.system_font_collection = collection.unwrap();
} }
} }
@ -461,35 +465,37 @@ impl DirectWriteState {
fallbacks: Option<&FontFallbacks>, fallbacks: Option<&FontFallbacks>,
) -> Option<FontId> { ) -> Option<FontId> {
// try to find target font in custom font collection first // try to find target font in custom font collection first
self.get_font_id_from_font_collection( unsafe {
family_name,
weight,
style,
features,
fallbacks,
false,
)
.or_else(|| {
self.get_font_id_from_font_collection( self.get_font_id_from_font_collection(
family_name, family_name,
weight, weight,
style, style,
features, features,
fallbacks, fallbacks,
true, false,
) )
}) .or_else(|| {
.or_else(|| { self.get_font_id_from_font_collection(
self.update_system_font_collection(); family_name,
self.get_font_id_from_font_collection( weight,
family_name, style,
weight, features,
style, fallbacks,
features, true,
fallbacks, )
true, })
) .or_else(|| {
}) self.update_system_font_collection();
self.get_font_id_from_font_collection(
family_name,
weight,
style,
features,
fallbacks,
true,
)
})
}
} }
fn layout_line( fn layout_line(

View file

@ -27,8 +27,8 @@ impl JsonSchema for SharedString {
String::schema_name() String::schema_name()
} }
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema { fn json_schema(r#gen: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema {
String::json_schema(gen) String::json_schema(r#gen)
} }
} }

View file

@ -45,7 +45,7 @@ where
&self, &self,
emitter_key: EmitterKey, emitter_key: EmitterKey,
callback: Callback, callback: Callback,
) -> (Subscription, impl FnOnce()) { ) -> (Subscription, impl FnOnce() + use<EmitterKey, Callback>) {
let active = Rc::new(Cell::new(false)); let active = Rc::new(Cell::new(false));
let mut lock = self.0.lock(); let mut lock = self.0.lock();
let subscriber_id = post_inc(&mut lock.next_subscriber_id); let subscriber_id = post_inc(&mut lock.next_subscriber_id);
@ -88,7 +88,10 @@ where
(subscription, move || active.set(true)) (subscription, move || active.set(true))
} }
pub fn remove(&self, emitter: &EmitterKey) -> impl IntoIterator<Item = Callback> { pub fn remove(
&self,
emitter: &EmitterKey,
) -> impl IntoIterator<Item = Callback> + use<EmitterKey, Callback> {
let subscribers = self.0.lock().subscribers.remove(emitter); let subscribers = self.0.lock().subscribers.remove(emitter);
subscribers subscribers
.unwrap_or_default() .unwrap_or_default()

View file

@ -133,7 +133,7 @@ impl schemars::JsonSchema for FontFeatures {
"FontFeatures".into() "FontFeatures".into()
} }
fn json_schema(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema { fn json_schema(_: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema {
let mut schema = SchemaObject::default(); let mut schema = SchemaObject::default();
schema.instance_type = Some(schemars::schema::SingleOrVec::Single(Box::new( schema.instance_type = Some(schemars::schema::SingleOrVec::Single(Box::new(
InstanceType::Object, InstanceType::Object,

View file

@ -936,7 +936,7 @@ impl Window {
pub(crate) fn new_focus_listener( pub(crate) fn new_focus_listener(
&self, &self,
value: AnyWindowFocusListener, value: AnyWindowFocusListener,
) -> (Subscription, impl FnOnce()) { ) -> (Subscription, impl FnOnce() + use<>) {
self.focus_listeners.insert((), value) self.focus_listeners.insert((), value)
} }
} }
@ -3719,11 +3719,11 @@ impl Window {
} }
/// Returns a generic handler that invokes the given handler with the view and context associated with the given view handle. /// Returns a generic handler that invokes the given handler with the view and context associated with the given view handle.
pub fn handler_for<V: Render>( pub fn handler_for<V: Render, Callback: Fn(&mut V, &mut Window, &mut Context<V>) + 'static>(
&self, &self,
view: &Entity<V>, view: &Entity<V>,
f: impl Fn(&mut V, &mut Window, &mut Context<V>) + 'static, f: Callback,
) -> impl Fn(&mut Window, &mut App) { ) -> impl Fn(&mut Window, &mut App) + use<V, Callback> {
let view = view.downgrade(); let view = view.downgrade();
move |window: &mut Window, cx: &mut App| { move |window: &mut Window, cx: &mut App| {
view.update(cx, |view, cx| f(view, window, cx)).ok(); view.update(cx, |view, cx| f(view, window, cx)).ok();

View file

@ -17,7 +17,7 @@ pub fn derive_app_context(input: TokenStream) -> TokenStream {
let type_name = &ast.ident; let type_name = &ast.ident;
let (impl_generics, type_generics, where_clause) = ast.generics.split_for_impl(); let (impl_generics, type_generics, where_clause) = ast.generics.split_for_impl();
let gen = quote! { let r#gen = quote! {
impl #impl_generics gpui::AppContext for #type_name #type_generics impl #impl_generics gpui::AppContext for #type_name #type_generics
#where_clause #where_clause
{ {
@ -98,5 +98,5 @@ pub fn derive_app_context(input: TokenStream) -> TokenStream {
} }
}; };
gen.into() r#gen.into()
} }

View file

@ -7,7 +7,7 @@ pub fn derive_into_element(input: TokenStream) -> TokenStream {
let type_name = &ast.ident; let type_name = &ast.ident;
let (impl_generics, type_generics, where_clause) = ast.generics.split_for_impl(); let (impl_generics, type_generics, where_clause) = ast.generics.split_for_impl();
let gen = quote! { let r#gen = quote! {
impl #impl_generics gpui::IntoElement for #type_name #type_generics impl #impl_generics gpui::IntoElement for #type_name #type_generics
#where_clause #where_clause
{ {
@ -19,5 +19,5 @@ pub fn derive_into_element(input: TokenStream) -> TokenStream {
} }
}; };
gen.into() r#gen.into()
} }

View file

@ -7,7 +7,7 @@ pub fn derive_render(input: TokenStream) -> TokenStream {
let type_name = &ast.ident; let type_name = &ast.ident;
let (impl_generics, type_generics, where_clause) = ast.generics.split_for_impl(); let (impl_generics, type_generics, where_clause) = ast.generics.split_for_impl();
let gen = quote! { let r#gen = quote! {
impl #impl_generics gpui::Render for #type_name #type_generics impl #impl_generics gpui::Render for #type_name #type_generics
#where_clause #where_clause
{ {
@ -17,5 +17,5 @@ pub fn derive_render(input: TokenStream) -> TokenStream {
} }
}; };
gen.into() r#gen.into()
} }

View file

@ -24,7 +24,7 @@ pub fn derive_visual_context(input: TokenStream) -> TokenStream {
let type_name = &ast.ident; let type_name = &ast.ident;
let (impl_generics, type_generics, where_clause) = ast.generics.split_for_impl(); let (impl_generics, type_generics, where_clause) = ast.generics.split_for_impl();
let gen = quote! { let r#gen = quote! {
impl #impl_generics gpui::VisualContext for #type_name #type_generics impl #impl_generics gpui::VisualContext for #type_name #type_generics
#where_clause #where_clause
{ {
@ -67,5 +67,5 @@ pub fn derive_visual_context(input: TokenStream) -> TokenStream {
} }
}; };
gen.into() r#gen.into()
} }

View file

@ -1292,27 +1292,27 @@ fn border_prefixes() -> Vec<BorderStylePrefix> {
quote! { border_widths.bottom }, quote! { border_widths.bottom },
quote! { border_widths.left }, quote! { border_widths.left },
], ],
doc_string_prefix: "Sets the border width of the element. [Docs](https://tailwindcss.com/docs/border-width)" doc_string_prefix: "Sets the border width of the element. [Docs](https://tailwindcss.com/docs/border-width)",
}, },
BorderStylePrefix { BorderStylePrefix {
prefix: "border_t", prefix: "border_t",
fields: vec![quote! { border_widths.top }], fields: vec![quote! { border_widths.top }],
doc_string_prefix: "Sets the border width of the top side of the element. [Docs](https://tailwindcss.com/docs/border-width#individual-sides)" doc_string_prefix: "Sets the border width of the top side of the element. [Docs](https://tailwindcss.com/docs/border-width#individual-sides)",
}, },
BorderStylePrefix { BorderStylePrefix {
prefix: "border_b", prefix: "border_b",
fields: vec![quote! { border_widths.bottom }], fields: vec![quote! { border_widths.bottom }],
doc_string_prefix: "Sets the border width of the bottom side of the element. [Docs](https://tailwindcss.com/docs/border-width#individual-sides)" doc_string_prefix: "Sets the border width of the bottom side of the element. [Docs](https://tailwindcss.com/docs/border-width#individual-sides)",
}, },
BorderStylePrefix { BorderStylePrefix {
prefix: "border_r", prefix: "border_r",
fields: vec![quote! { border_widths.right }], fields: vec![quote! { border_widths.right }],
doc_string_prefix: "Sets the border width of the right side of the element. [Docs](https://tailwindcss.com/docs/border-width#individual-sides)" doc_string_prefix: "Sets the border width of the right side of the element. [Docs](https://tailwindcss.com/docs/border-width#individual-sides)",
}, },
BorderStylePrefix { BorderStylePrefix {
prefix: "border_l", prefix: "border_l",
fields: vec![quote! { border_widths.left }], fields: vec![quote! { border_widths.left }],
doc_string_prefix: "Sets the border width of the left side of the element. [Docs](https://tailwindcss.com/docs/border-width#individual-sides)" doc_string_prefix: "Sets the border width of the left side of the element. [Docs](https://tailwindcss.com/docs/border-width#individual-sides)",
}, },
BorderStylePrefix { BorderStylePrefix {
prefix: "border_x", prefix: "border_x",
@ -1320,7 +1320,7 @@ fn border_prefixes() -> Vec<BorderStylePrefix> {
quote! { border_widths.left }, quote! { border_widths.left },
quote! { border_widths.right }, quote! { border_widths.right },
], ],
doc_string_prefix: "Sets the border width of the vertical sides of the element. [Docs](https://tailwindcss.com/docs/border-width#horizontal-and-vertical-sides)" doc_string_prefix: "Sets the border width of the vertical sides of the element. [Docs](https://tailwindcss.com/docs/border-width#horizontal-and-vertical-sides)",
}, },
BorderStylePrefix { BorderStylePrefix {
prefix: "border_y", prefix: "border_y",
@ -1328,7 +1328,7 @@ fn border_prefixes() -> Vec<BorderStylePrefix> {
quote! { border_widths.top }, quote! { border_widths.top },
quote! { border_widths.bottom }, quote! { border_widths.bottom },
], ],
doc_string_prefix: "Sets the border width of the horizontal sides of the element. [Docs](https://tailwindcss.com/docs/border-width#horizontal-and-vertical-sides)" doc_string_prefix: "Sets the border width of the horizontal sides of the element. [Docs](https://tailwindcss.com/docs/border-width#horizontal-and-vertical-sides)",
}, },
] ]
} }

View file

@ -441,7 +441,9 @@ mod persistence {
.collect::<Vec<&str>>() .collect::<Vec<&str>>()
.join(", "); .join(", ");
let query = format!("DELETE FROM image_viewers WHERE workspace_id = ? AND item_id NOT IN ({placeholders})"); let query = format!(
"DELETE FROM image_viewers WHERE workspace_id = ? AND item_id NOT IN ({placeholders})"
);
self.write(move |conn| { self.write(move |conn| {
let mut statement = Statement::prepare(conn, query)?; let mut statement = Statement::prepare(conn, query)?;

View file

@ -989,7 +989,7 @@ impl Buffer {
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 = BufferSnapshot> { ) -> impl Future<Output = BufferSnapshot> + use<> {
let entity_id = cx.reserve_entity::<Self>().entity_id(); let entity_id = cx.reserve_entity::<Self>().entity_id();
let buffer_id = entity_id.as_non_zero_u64().into(); let buffer_id = entity_id.as_non_zero_u64().into();
async move { async move {
@ -1587,7 +1587,9 @@ impl Buffer {
} }
} }
fn compute_autoindents(&self) -> Option<impl Future<Output = BTreeMap<u32, IndentSize>>> { fn compute_autoindents(
&self,
) -> Option<impl Future<Output = BTreeMap<u32, IndentSize>> + use<>> {
let max_rows_between_yields = 100; let max_rows_between_yields = 100;
let snapshot = self.snapshot(); let snapshot = self.snapshot();
if snapshot.syntax.is_empty() || self.autoindent_requests.is_empty() { if snapshot.syntax.is_empty() || self.autoindent_requests.is_empty() {
@ -2082,23 +2084,26 @@ impl Buffer {
} }
/// Waits for the buffer to receive operations with the given timestamps. /// Waits for the buffer to receive operations with the given timestamps.
pub fn wait_for_edits( pub fn wait_for_edits<It: IntoIterator<Item = clock::Lamport>>(
&mut self, &mut self,
edit_ids: impl IntoIterator<Item = clock::Lamport>, edit_ids: It,
) -> impl Future<Output = Result<()>> { ) -> impl Future<Output = Result<()>> + use<It> {
self.text.wait_for_edits(edit_ids) self.text.wait_for_edits(edit_ids)
} }
/// Waits for the buffer to receive the operations necessary for resolving the given anchors. /// Waits for the buffer to receive the operations necessary for resolving the given anchors.
pub fn wait_for_anchors( pub fn wait_for_anchors<It: IntoIterator<Item = Anchor>>(
&mut self, &mut self,
anchors: impl IntoIterator<Item = Anchor>, anchors: It,
) -> impl 'static + Future<Output = Result<()>> { ) -> impl 'static + Future<Output = Result<()>> + use<It> {
self.text.wait_for_anchors(anchors) self.text.wait_for_anchors(anchors)
} }
/// Waits for the buffer to receive operations up to the given version. /// Waits for the buffer to receive operations up to the given version.
pub fn wait_for_version(&mut self, version: clock::Global) -> impl Future<Output = Result<()>> { pub fn wait_for_version(
&mut self,
version: clock::Global,
) -> impl Future<Output = Result<()>> + use<> {
self.text.wait_for_version(version) self.text.wait_for_version(version)
} }
@ -3916,91 +3921,93 @@ impl BufferSnapshot {
.map(|grammar| grammar.runnable_config.as_ref()) .map(|grammar| grammar.runnable_config.as_ref())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
iter::from_fn(move || loop { iter::from_fn(move || {
let mat = syntax_matches.peek()?; loop {
let mat = syntax_matches.peek()?;
let test_range = test_configs[mat.grammar_index].and_then(|test_configs| { let test_range = test_configs[mat.grammar_index].and_then(|test_configs| {
let mut run_range = None; let mut run_range = None;
let full_range = mat.captures.iter().fold( let full_range = mat.captures.iter().fold(
Range { Range {
start: usize::MAX, start: usize::MAX,
end: 0, end: 0,
}, },
|mut acc, next| { |mut acc, next| {
let byte_range = next.node.byte_range(); let byte_range = next.node.byte_range();
if acc.start > byte_range.start { if acc.start > byte_range.start {
acc.start = byte_range.start; acc.start = byte_range.start;
} }
if acc.end < byte_range.end { if acc.end < byte_range.end {
acc.end = byte_range.end; acc.end = byte_range.end;
} }
acc acc
}, },
); );
if full_range.start > full_range.end { if full_range.start > full_range.end {
// We did not find a full spanning range of this match. // We did not find a full spanning range of this match.
return None; return None;
}
let extra_captures: SmallVec<[_; 1]> =
SmallVec::from_iter(mat.captures.iter().filter_map(|capture| {
test_configs
.extra_captures
.get(capture.index as usize)
.cloned()
.and_then(|tag_name| match tag_name {
RunnableCapture::Named(name) => {
Some((capture.node.byte_range(), name))
}
RunnableCapture::Run => {
let _ = run_range.insert(capture.node.byte_range());
None
}
})
}));
let run_range = run_range?;
let tags = test_configs
.query
.property_settings(mat.pattern_index)
.iter()
.filter_map(|property| {
if *property.key == *"tag" {
property
.value
.as_ref()
.map(|value| RunnableTag(value.to_string().into()))
} else {
None
}
})
.collect();
let extra_captures = extra_captures
.into_iter()
.map(|(range, name)| {
(
name.to_string(),
self.text_for_range(range.clone()).collect::<String>(),
)
})
.collect();
// All tags should have the same range.
Some(RunnableRange {
run_range,
full_range,
runnable: Runnable {
tags,
language: mat.language,
buffer: self.remote_id(),
},
extra_captures,
buffer_id: self.remote_id(),
})
});
syntax_matches.advance();
if test_range.is_some() {
// It's fine for us to short-circuit on .peek()? returning None. We don't want to return None from this iter if we
// had a capture that did not contain a run marker, hence we'll just loop around for the next capture.
return test_range;
} }
let extra_captures: SmallVec<[_; 1]> =
SmallVec::from_iter(mat.captures.iter().filter_map(|capture| {
test_configs
.extra_captures
.get(capture.index as usize)
.cloned()
.and_then(|tag_name| match tag_name {
RunnableCapture::Named(name) => {
Some((capture.node.byte_range(), name))
}
RunnableCapture::Run => {
let _ = run_range.insert(capture.node.byte_range());
None
}
})
}));
let run_range = run_range?;
let tags = test_configs
.query
.property_settings(mat.pattern_index)
.iter()
.filter_map(|property| {
if *property.key == *"tag" {
property
.value
.as_ref()
.map(|value| RunnableTag(value.to_string().into()))
} else {
None
}
})
.collect();
let extra_captures = extra_captures
.into_iter()
.map(|(range, name)| {
(
name.to_string(),
self.text_for_range(range.clone()).collect::<String>(),
)
})
.collect();
// All tags should have the same range.
Some(RunnableRange {
run_range,
full_range,
runnable: Runnable {
tags,
language: mat.language,
buffer: self.remote_id(),
},
extra_captures,
buffer_id: self.remote_id(),
})
});
syntax_matches.advance();
if test_range.is_some() {
// It's fine for us to short-circuit on .peek()? returning None. We don't want to return None from this iter if we
// had a capture that did not contain a run marker, hence we'll just loop around for the next capture.
return test_range;
} }
}) })
} }
@ -4352,7 +4359,10 @@ impl<'a> BufferChunks<'a> {
} else { } else {
// We cannot obtain new highlights for a language-aware buffer iterator, as we don't have a buffer snapshot. // We cannot obtain new highlights for a language-aware buffer iterator, as we don't have a buffer snapshot.
// Seeking such BufferChunks is not supported. // Seeking such BufferChunks is not supported.
debug_assert!(false, "Attempted to seek on a language-aware buffer iterator without associated buffer snapshot"); debug_assert!(
false,
"Attempted to seek on a language-aware buffer iterator without associated buffer snapshot"
);
} }
highlights.captures.set_byte_range(self.range.clone()); highlights.captures.set_byte_range(self.range.clone());

View file

@ -38,7 +38,7 @@ pub use manifest::{ManifestName, ManifestProvider, ManifestQuery};
use parking_lot::Mutex; use parking_lot::Mutex;
use regex::Regex; use regex::Regex;
use schemars::{ use schemars::{
gen::SchemaGenerator, r#gen::SchemaGenerator,
schema::{InstanceType, Schema, SchemaObject}, schema::{InstanceType, Schema, SchemaObject},
JsonSchema, JsonSchema,
}; };
@ -598,7 +598,9 @@ pub trait LspAdapter: 'static + Send + Sync {
/// Should not be called unless the callee is sure that /// Should not be called unless the callee is sure that
/// `Self::is_primary_zed_json_schema_adapter` returns `true` /// `Self::is_primary_zed_json_schema_adapter` returns `true`
async fn clear_zed_json_schema_cache(&self) { async fn clear_zed_json_schema_cache(&self) {
unreachable!("Not implemented for this adapter. This method should only be called on the default JSON language server adapter"); unreachable!(
"Not implemented for this adapter. This method should only be called on the default JSON language server adapter"
);
} }
} }
@ -931,8 +933,8 @@ impl BracketPairConfig {
} }
} }
fn bracket_pair_config_json_schema(gen: &mut SchemaGenerator) -> Schema { fn bracket_pair_config_json_schema(r#gen: &mut SchemaGenerator) -> Schema {
Option::<Vec<BracketPairContent>>::json_schema(gen) Option::<Vec<BracketPairContent>>::json_schema(r#gen)
} }
#[derive(Deserialize, JsonSchema)] #[derive(Deserialize, JsonSchema)]
@ -1532,7 +1534,9 @@ impl Language {
.scope_opt_in_language_servers .scope_opt_in_language_servers
.contains(server_name) .contains(server_name)
{ {
util::debug_panic!("Server {server_name:?} has been opted-in by scope {name:?} but has not been marked as an opt-in server"); util::debug_panic!(
"Server {server_name:?} has been opted-in by scope {name:?} but has not been marked as an opt-in server"
);
} }
} }

View file

@ -597,7 +597,7 @@ impl LanguageRegistry {
pub fn language_for_name( pub fn language_for_name(
self: &Arc<Self>, self: &Arc<Self>,
name: &str, name: &str,
) -> impl Future<Output = Result<Arc<Language>>> { ) -> impl Future<Output = Result<Arc<Language>>> + use<> {
let name = UniCase::new(name); let name = UniCase::new(name);
let rx = self.get_or_load_language(|language_name, _| { let rx = self.get_or_load_language(|language_name, _| {
if UniCase::new(&language_name.0) == name { if UniCase::new(&language_name.0) == name {

View file

@ -1300,7 +1300,7 @@ impl settings::Settings for AllLanguageSettings {
} }
fn json_schema( fn json_schema(
generator: &mut schemars::gen::SchemaGenerator, generator: &mut schemars::r#gen::SchemaGenerator,
params: &settings::SettingsJsonSchemaParams, params: &settings::SettingsJsonSchemaParams,
_: &App, _: &App,
) -> schemars::schema::RootSchema { ) -> schemars::schema::RootSchema {

View file

@ -153,14 +153,14 @@ fn test_syntax_map_layers_for_range(cx: &mut App) {
syntax_map.reparse(language.clone(), &buffer); syntax_map.reparse(language.clone(), &buffer);
assert_layers_for_range( assert_layers_for_range(
&syntax_map, &syntax_map,
&buffer, &buffer,
Point::new(2, 14)..Point::new(2, 16), Point::new(2, 14)..Point::new(2, 16),
&[ &[
"...(function_item ...", "...(function_item ...",
"...(tuple_expression (call_expression ... arguments: (arguments (reference_expression value: (array_expression...", "...(tuple_expression (call_expression ... arguments: (arguments (reference_expression value: (array_expression...",
], ],
); );
// Put the vec! macro back, adding back the syntactic layer. // Put the vec! macro back, adding back the syntactic layer.
buffer.undo(); buffer.undo();
@ -207,15 +207,15 @@ fn test_dynamic_language_injection(cx: &mut App) {
syntax_map.reparse(markdown.clone(), &buffer); syntax_map.reparse(markdown.clone(), &buffer);
syntax_map.reparse(markdown_inline.clone(), &buffer); syntax_map.reparse(markdown_inline.clone(), &buffer);
assert_layers_for_range( assert_layers_for_range(
&syntax_map, &syntax_map,
&buffer, &buffer,
Point::new(3, 0)..Point::new(3, 0), Point::new(3, 0)..Point::new(3, 0),
&[ &[
"(document (section (paragraph (inline)) (fenced_code_block (fenced_code_block_delimiter) (info_string (language)) (block_continuation) (code_fence_content (block_continuation)) (fenced_code_block_delimiter))))", "(document (section (paragraph (inline)) (fenced_code_block (fenced_code_block_delimiter) (info_string (language)) (block_continuation) (code_fence_content (block_continuation)) (fenced_code_block_delimiter))))",
"(inline (code_span (code_span_delimiter) (code_span_delimiter)))", "(inline (code_span (code_span_delimiter) (code_span_delimiter)))",
"...(function_item name: (identifier) parameters: (parameters) body: (block)...", "...(function_item name: (identifier) parameters: (parameters) body: (block)...",
], ],
); );
// Replace `rs` with a path to ending in `.rb` in code block. // Replace `rs` with a path to ending in `.rb` in code block.
let macro_name_range = range_for_text(&buffer, "rs"); let macro_name_range = range_for_text(&buffer, "rs");
@ -224,15 +224,15 @@ fn test_dynamic_language_injection(cx: &mut App) {
syntax_map.reparse(markdown.clone(), &buffer); syntax_map.reparse(markdown.clone(), &buffer);
syntax_map.reparse(markdown_inline.clone(), &buffer); syntax_map.reparse(markdown_inline.clone(), &buffer);
assert_layers_for_range( assert_layers_for_range(
&syntax_map, &syntax_map,
&buffer, &buffer,
Point::new(3, 0)..Point::new(3, 0), Point::new(3, 0)..Point::new(3, 0),
&[ &[
"(document (section (paragraph (inline)) (fenced_code_block (fenced_code_block_delimiter) (info_string (language)) (block_continuation) (code_fence_content (block_continuation)) (fenced_code_block_delimiter))))", "(document (section (paragraph (inline)) (fenced_code_block (fenced_code_block_delimiter) (info_string (language)) (block_continuation) (code_fence_content (block_continuation)) (fenced_code_block_delimiter))))",
"(inline (code_span (code_span_delimiter) (code_span_delimiter)))", "(inline (code_span (code_span_delimiter) (code_span_delimiter)))",
"...(call method: (identifier) arguments: (argument_list (call method: (identifier) arguments: (argument_list) block: (block)...", "...(call method: (identifier) arguments: (argument_list (call method: (identifier) arguments: (argument_list) block: (block)...",
], ],
); );
// Replace Ruby with a language that hasn't been loaded yet. // Replace Ruby with a language that hasn't been loaded yet.
let macro_name_range = range_for_text(&buffer, "foo/bar/baz.rb"); let macro_name_range = range_for_text(&buffer, "foo/bar/baz.rb");
@ -241,29 +241,29 @@ fn test_dynamic_language_injection(cx: &mut App) {
syntax_map.reparse(markdown.clone(), &buffer); syntax_map.reparse(markdown.clone(), &buffer);
syntax_map.reparse(markdown_inline.clone(), &buffer); syntax_map.reparse(markdown_inline.clone(), &buffer);
assert_layers_for_range( assert_layers_for_range(
&syntax_map, &syntax_map,
&buffer, &buffer,
Point::new(3, 0)..Point::new(3, 0), Point::new(3, 0)..Point::new(3, 0),
&[ &[
"(document (section (paragraph (inline)) (fenced_code_block (fenced_code_block_delimiter) (info_string (language)) (block_continuation) (code_fence_content (block_continuation)) (fenced_code_block_delimiter))))", "(document (section (paragraph (inline)) (fenced_code_block (fenced_code_block_delimiter) (info_string (language)) (block_continuation) (code_fence_content (block_continuation)) (fenced_code_block_delimiter))))",
"(inline (code_span (code_span_delimiter) (code_span_delimiter)))", "(inline (code_span (code_span_delimiter) (code_span_delimiter)))",
], ],
); );
assert!(syntax_map.contains_unknown_injections()); assert!(syntax_map.contains_unknown_injections());
registry.add(Arc::new(html_lang())); registry.add(Arc::new(html_lang()));
syntax_map.reparse(markdown.clone(), &buffer); syntax_map.reparse(markdown.clone(), &buffer);
syntax_map.reparse(markdown_inline.clone(), &buffer); syntax_map.reparse(markdown_inline.clone(), &buffer);
assert_layers_for_range( assert_layers_for_range(
&syntax_map, &syntax_map,
&buffer, &buffer,
Point::new(3, 0)..Point::new(3, 0), Point::new(3, 0)..Point::new(3, 0),
&[ &[
"(document (section (paragraph (inline)) (fenced_code_block (fenced_code_block_delimiter) (info_string (language)) (block_continuation) (code_fence_content (block_continuation)) (fenced_code_block_delimiter))))", "(document (section (paragraph (inline)) (fenced_code_block (fenced_code_block_delimiter) (info_string (language)) (block_continuation) (code_fence_content (block_continuation)) (fenced_code_block_delimiter))))",
"(inline (code_span (code_span_delimiter) (code_span_delimiter)))", "(inline (code_span (code_span_delimiter) (code_span_delimiter)))",
"(document (text))", "(document (text))",
], ],
); );
assert!(!syntax_map.contains_unknown_injections()); assert!(!syntax_map.contains_unknown_injections());
} }

View file

@ -52,7 +52,7 @@ impl RateLimiter {
pub fn stream<'a, Fut, T>( pub fn stream<'a, Fut, T>(
&self, &self,
future: Fut, future: Fut,
) -> impl 'a + Future<Output = Result<impl Stream<Item = T::Item>>> ) -> impl 'a + Future<Output = Result<impl Stream<Item = T::Item> + use<Fut, T>>>
where where
Fut: 'a + Future<Output = Result<T>>, Fut: 'a + Future<Output = Result<T>>,
T: Stream, T: Stream,

View file

@ -125,11 +125,21 @@ impl LanguageModelProvider for CopilotChatLanguageModelProvider {
let err = match copilot.read(cx).status() { let err = match copilot.read(cx).status() {
Status::Authorized => return Task::ready(Ok(())), Status::Authorized => return Task::ready(Ok(())),
Status::Disabled => anyhow!("Copilot must be enabled for Copilot Chat to work. Please enable Copilot and try again."), Status::Disabled => anyhow!(
Status::Error(err) => anyhow!(format!("Received the following error while signing into Copilot: {err}")), "Copilot must be enabled for Copilot Chat to work. Please enable Copilot and try again."
Status::Starting { task: _ } => anyhow!("Copilot is still starting, please wait for Copilot to start then try again"), ),
Status::Unauthorized => anyhow!("Unable to authorize with Copilot. Please make sure that you have an active Copilot and Copilot Chat subscription."), Status::Error(err) => anyhow!(format!(
Status::SignedOut {..} => anyhow!("You have signed out of Copilot. Please sign in to Copilot and try again."), "Received the following error while signing into Copilot: {err}"
)),
Status::Starting { task: _ } => anyhow!(
"Copilot is still starting, please wait for Copilot to start then try again"
),
Status::Unauthorized => anyhow!(
"Unable to authorize with Copilot. Please make sure that you have an active Copilot and Copilot Chat subscription."
),
Status::SignedOut { .. } => {
anyhow!("You have signed out of Copilot. Please sign in to Copilot and try again.")
}
Status::SigningIn { prompt: _ } => anyhow!("Still signing into Copilot..."), Status::SigningIn { prompt: _ } => anyhow!("Still signing into Copilot..."),
}; };
@ -398,8 +408,7 @@ impl Render for ConfigurationView {
.child(svg().size_8().path(IconName::CopilotError.path())) .child(svg().size_8().path(IconName::CopilotError.path()))
} }
_ => { _ => {
const LABEL: &str = const LABEL: &str = "To use Zed's assistant with GitHub Copilot, you need to be logged in to GitHub. Note that your GitHub account must have an active Copilot Chat subscription.";
"To use Zed's assistant with GitHub Copilot, you need to be logged in to GitHub. Note that your GitHub account must have an active Copilot Chat subscription.";
v_flex().gap_6().child(Label::new(LABEL)).child( v_flex().gap_6().child(Label::new(LABEL)).child(
v_flex() v_flex()
.gap_2() .gap_2()

View file

@ -2,8 +2,7 @@ use anyhow::{anyhow, Context as _, Result};
use collections::BTreeMap; use collections::BTreeMap;
use credentials_provider::CredentialsProvider; use credentials_provider::CredentialsProvider;
use editor::{Editor, EditorElement, EditorStyle}; use editor::{Editor, EditorElement, EditorStyle};
use futures::Stream; use futures::{future::BoxFuture, FutureExt, Stream, StreamExt};
use futures::{future::BoxFuture, FutureExt, StreamExt};
use google_ai::{FunctionDeclaration, GenerateContentResponse, Part, UsageMetadata}; use google_ai::{FunctionDeclaration, GenerateContentResponse, Part, UsageMetadata};
use gpui::{ use gpui::{
AnyView, App, AsyncApp, Context, Entity, FontStyle, Subscription, Task, TextStyle, WhiteSpace, AnyView, App, AsyncApp, Context, Entity, FontStyle, Subscription, Task, TextStyle, WhiteSpace,

View file

@ -415,8 +415,7 @@ impl Render for ConfigurationView {
let is_authenticated = self.state.read(cx).is_authenticated(); let is_authenticated = self.state.read(cx).is_authenticated();
let lmstudio_intro = "Run local LLMs like Llama, Phi, and Qwen."; let lmstudio_intro = "Run local LLMs like Llama, Phi, and Qwen.";
let lmstudio_reqs = let lmstudio_reqs = "To use LM Studio as a provider for Zed assistant, it needs to be running with at least one model downloaded.";
"To use LM Studio as a provider for Zed assistant, it needs to be running with at least one model downloaded.";
let inline_code_bg = cx.theme().colors().editor_foreground.opacity(0.05); let inline_code_bg = cx.theme().colors().editor_foreground.opacity(0.05);

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