One big cleanup pass of clippy lints

Co-authored-by: Mikayla <mikayla@zed.dev>
This commit is contained in:
ForLoveOfCats 2022-08-10 17:39:24 -04:00 committed by K Simmons
parent e7540d2833
commit 8ba2f77148
138 changed files with 1328 additions and 1366 deletions

6
.cargo/config.toml Normal file
View File

@ -0,0 +1,6 @@
[target.'cfg(all())']
rustflags = [
"-Aclippy::reversed_empty_ranges",
"-Aclippy::missing_safety_doc",
"-Aclippy::let_unit_value",
]

View File

@ -15,9 +15,9 @@ use workspace::{ItemHandle, StatusItemView, Workspace};
actions!(lsp_status, [ShowErrorMessage]); actions!(lsp_status, [ShowErrorMessage]);
const DOWNLOAD_ICON: &'static str = "icons/download_12.svg"; const DOWNLOAD_ICON: &str = "icons/download_12.svg";
const WARNING_ICON: &'static str = "icons/triangle_exclamation_12.svg"; const WARNING_ICON: &str = "icons/triangle_exclamation_12.svg";
const DONE_ICON: &'static str = "icons/circle_check_12.svg"; const DONE_ICON: &str = "icons/circle_check_12.svg";
pub enum Event { pub enum Event {
ShowError { lsp_name: Arc<str>, error: String }, ShowError { lsp_name: Arc<str>, error: String },
@ -76,7 +76,7 @@ impl ActivityIndicator {
cx.subscribe(&this, move |workspace, _, event, cx| match event { cx.subscribe(&this, move |workspace, _, event, cx| match event {
Event::ShowError { lsp_name, error } => { Event::ShowError { lsp_name, error } => {
if let Some(buffer) = project if let Some(buffer) = project
.update(cx, |project, cx| project.create_buffer(&error, None, cx)) .update(cx, |project, cx| project.create_buffer(error, None, cx))
.log_err() .log_err()
{ {
buffer.update(cx, |buffer, cx| { buffer.update(cx, |buffer, cx| {

View File

@ -13,8 +13,7 @@ use std::{env, ffi::OsString, path::PathBuf, sync::Arc, time::Duration};
use update_notification::UpdateNotification; use update_notification::UpdateNotification;
use workspace::Workspace; use workspace::Workspace;
const SHOULD_SHOW_UPDATE_NOTIFICATION_KEY: &'static str = const SHOULD_SHOW_UPDATE_NOTIFICATION_KEY: &str = "auto-updater-should-show-updated-notification";
"auto-updater-should-show-updated-notification";
const POLL_INTERVAL: Duration = Duration::from_secs(60 * 60); const POLL_INTERVAL: Duration = Duration::from_secs(60 * 60);
lazy_static! { lazy_static! {
@ -61,7 +60,7 @@ pub fn init(
server_url: String, server_url: String,
cx: &mut MutableAppContext, cx: &mut MutableAppContext,
) { ) {
if let Some(version) = ZED_APP_VERSION.clone().or(cx.platform().app_version().ok()) { if let Some(version) = (*ZED_APP_VERSION).or_else(|| cx.platform().app_version().ok()) {
let auto_updater = cx.add_model(|cx| { let auto_updater = cx.add_model(|cx| {
let updater = AutoUpdater::new(version, db.clone(), http_client, server_url.clone()); let updater = AutoUpdater::new(version, db.clone(), http_client, server_url.clone());
updater.start_polling(cx).detach(); updater.start_polling(cx).detach();

View File

@ -70,7 +70,7 @@ impl ChatPanel {
let theme = &cx.global::<Settings>().theme.chat_panel.channel_select; let theme = &cx.global::<Settings>().theme.chat_panel.channel_select;
SelectStyle { SelectStyle {
header: theme.header.container, header: theme.header.container,
menu: theme.menu.clone(), menu: theme.menu,
} }
}) })
}); });
@ -91,7 +91,7 @@ impl ChatPanel {
let _observe_status = cx.spawn_weak(|this, mut cx| { let _observe_status = cx.spawn_weak(|this, mut cx| {
let mut status = rpc.status(); let mut status = rpc.status();
async move { async move {
while let Some(_) = status.recv().await { while (status.recv().await).is_some() {
if let Some(this) = this.upgrade(&cx) { if let Some(this) = this.upgrade(&cx) {
this.update(&mut cx, |_, cx| cx.notify()); this.update(&mut cx, |_, cx| cx.notify());
} else { } else {

View File

@ -145,7 +145,7 @@ impl ChannelList {
} }
pub fn available_channels(&self) -> Option<&[ChannelDetails]> { pub fn available_channels(&self) -> Option<&[ChannelDetails]> {
self.available_channels.as_ref().map(Vec::as_slice) self.available_channels.as_deref()
} }
pub fn get_channel( pub fn get_channel(
@ -601,8 +601,8 @@ mod tests {
let user_id = 5; let user_id = 5;
let http_client = FakeHttpClient::with_404_response(); let http_client = FakeHttpClient::with_404_response();
let mut client = Client::new(http_client.clone()); let client = Client::new(http_client.clone());
let server = FakeServer::for_client(user_id, &mut client, &cx).await; let server = FakeServer::for_client(user_id, &client, cx).await;
Channel::init(&client); Channel::init(&client);
let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http_client, cx)); let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http_client, cx));
@ -623,7 +623,7 @@ mod tests {
}, },
) )
.await; .await;
channel_list.next_notification(&cx).await; channel_list.next_notification(cx).await;
channel_list.read_with(cx, |list, _| { channel_list.read_with(cx, |list, _| {
assert_eq!( assert_eq!(
list.available_channels().unwrap(), list.available_channels().unwrap(),
@ -701,7 +701,7 @@ mod tests {
.await; .await;
assert_eq!( assert_eq!(
channel.next_event(&cx).await, channel.next_event(cx).await,
ChannelEvent::MessagesUpdated { ChannelEvent::MessagesUpdated {
old_range: 0..0, old_range: 0..0,
new_count: 2, new_count: 2,
@ -749,7 +749,7 @@ mod tests {
.await; .await;
assert_eq!( assert_eq!(
channel.next_event(&cx).await, channel.next_event(cx).await,
ChannelEvent::MessagesUpdated { ChannelEvent::MessagesUpdated {
old_range: 2..2, old_range: 2..2,
new_count: 1, new_count: 1,
@ -798,7 +798,7 @@ mod tests {
.await; .await;
assert_eq!( assert_eq!(
channel.next_event(&cx).await, channel.next_event(cx).await,
ChannelEvent::MessagesUpdated { ChannelEvent::MessagesUpdated {
old_range: 0..0, old_range: 0..0,
new_count: 2, new_count: 2,

View File

@ -41,13 +41,13 @@ pub use user::*;
lazy_static! { lazy_static! {
pub static ref ZED_SERVER_URL: String = pub static ref ZED_SERVER_URL: String =
std::env::var("ZED_SERVER_URL").unwrap_or("https://zed.dev".to_string()); std::env::var("ZED_SERVER_URL").unwrap_or_else(|_| "https://zed.dev".to_string());
pub static ref IMPERSONATE_LOGIN: Option<String> = std::env::var("ZED_IMPERSONATE") pub static ref IMPERSONATE_LOGIN: Option<String> = std::env::var("ZED_IMPERSONATE")
.ok() .ok()
.and_then(|s| if s.is_empty() { None } else { Some(s) }); .and_then(|s| if s.is_empty() { None } else { Some(s) });
} }
pub const ZED_SECRET_CLIENT_TOKEN: &'static str = "618033988749894"; pub const ZED_SECRET_CLIENT_TOKEN: &str = "618033988749894";
actions!(client, [Authenticate]); actions!(client, [Authenticate]);
@ -65,10 +65,13 @@ pub struct Client {
http: Arc<dyn HttpClient>, http: Arc<dyn HttpClient>,
state: RwLock<ClientState>, state: RwLock<ClientState>,
#[allow(clippy::type_complexity)]
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
authenticate: RwLock< authenticate: RwLock<
Option<Box<dyn 'static + Send + Sync + Fn(&AsyncAppContext) -> Task<Result<Credentials>>>>, Option<Box<dyn 'static + Send + Sync + Fn(&AsyncAppContext) -> Task<Result<Credentials>>>>,
>, >,
#[allow(clippy::type_complexity)]
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
establish_connection: RwLock< establish_connection: RwLock<
Option< Option<
@ -149,6 +152,7 @@ struct ClientState {
entities_by_type_and_remote_id: HashMap<(TypeId, u64), AnyWeakEntityHandle>, entities_by_type_and_remote_id: HashMap<(TypeId, u64), AnyWeakEntityHandle>,
models_by_message_type: HashMap<TypeId, AnyWeakModelHandle>, models_by_message_type: HashMap<TypeId, AnyWeakModelHandle>,
entity_types_by_message_type: HashMap<TypeId, TypeId>, entity_types_by_message_type: HashMap<TypeId, TypeId>,
#[allow(clippy::type_complexity)]
message_handlers: HashMap< message_handlers: HashMap<
TypeId, TypeId,
Arc< Arc<
@ -596,7 +600,7 @@ impl Client {
let mut status_rx = self.status(); let mut status_rx = self.status();
let _ = status_rx.next().await; let _ = status_rx.next().await;
futures::select_biased! { futures::select_biased! {
authenticate = self.authenticate(&cx).fuse() => { authenticate = self.authenticate(cx).fuse() => {
match authenticate { match authenticate {
Ok(creds) => credentials = Some(creds), Ok(creds) => credentials = Some(creds),
Err(err) => { Err(err) => {
@ -819,7 +823,7 @@ impl Client {
.get("Location") .get("Location")
.ok_or_else(|| anyhow!("missing location header in /rpc response"))? .ok_or_else(|| anyhow!("missing location header in /rpc response"))?
.to_str() .to_str()
.map_err(|error| EstablishConnectionError::other(error))? .map_err(EstablishConnectionError::other)?
.to_string(); .to_string();
} }
// Until we switch the zed.dev domain to point to the new Next.js app, there // Until we switch the zed.dev domain to point to the new Next.js app, there
@ -1051,7 +1055,7 @@ fn write_credentials_to_keychain(credentials: &Credentials, cx: &AsyncAppContext
) )
} }
const WORKTREE_URL_PREFIX: &'static str = "zed://worktrees/"; const WORKTREE_URL_PREFIX: &str = "zed://worktrees/";
pub fn encode_worktree_url(id: u64, access_token: &str) -> String { pub fn encode_worktree_url(id: u64, access_token: &str) -> String {
format!("{}{}/{}", WORKTREE_URL_PREFIX, id, access_token) format!("{}{}/{}", WORKTREE_URL_PREFIX, id, access_token)
@ -1081,8 +1085,8 @@ mod tests {
cx.foreground().forbid_parking(); cx.foreground().forbid_parking();
let user_id = 5; let user_id = 5;
let mut client = Client::new(FakeHttpClient::with_404_response()); let client = Client::new(FakeHttpClient::with_404_response());
let server = FakeServer::for_client(user_id, &mut client, &cx).await; let server = FakeServer::for_client(user_id, &client, cx).await;
let mut status = client.status(); let mut status = client.status();
assert!(matches!( assert!(matches!(
status.next().await, status.next().await,
@ -1169,8 +1173,8 @@ mod tests {
cx.foreground().forbid_parking(); cx.foreground().forbid_parking();
let user_id = 5; let user_id = 5;
let mut client = Client::new(FakeHttpClient::with_404_response()); let client = Client::new(FakeHttpClient::with_404_response());
let server = FakeServer::for_client(user_id, &mut client, &cx).await; let server = FakeServer::for_client(user_id, &client, cx).await;
let (done_tx1, mut done_rx1) = smol::channel::unbounded(); let (done_tx1, mut done_rx1) = smol::channel::unbounded();
let (done_tx2, mut done_rx2) = smol::channel::unbounded(); let (done_tx2, mut done_rx2) = smol::channel::unbounded();
@ -1215,8 +1219,8 @@ mod tests {
cx.foreground().forbid_parking(); cx.foreground().forbid_parking();
let user_id = 5; let user_id = 5;
let mut client = Client::new(FakeHttpClient::with_404_response()); let client = Client::new(FakeHttpClient::with_404_response());
let server = FakeServer::for_client(user_id, &mut client, &cx).await; let server = FakeServer::for_client(user_id, &client, cx).await;
let model = cx.add_model(|_| Model::default()); let model = cx.add_model(|_| Model::default());
let (done_tx1, _done_rx1) = smol::channel::unbounded(); let (done_tx1, _done_rx1) = smol::channel::unbounded();
@ -1243,8 +1247,8 @@ mod tests {
cx.foreground().forbid_parking(); cx.foreground().forbid_parking();
let user_id = 5; let user_id = 5;
let mut client = Client::new(FakeHttpClient::with_404_response()); let client = Client::new(FakeHttpClient::with_404_response());
let server = FakeServer::for_client(user_id, &mut client, &cx).await; let server = FakeServer::for_client(user_id, &client, cx).await;
let model = cx.add_model(|_| Model::default()); let model = cx.add_model(|_| Model::default());
let (done_tx, mut done_rx) = smol::channel::unbounded(); let (done_tx, mut done_rx) = smol::channel::unbounded();

View File

@ -16,7 +16,7 @@ pub type Request = isahc::Request<AsyncBody>;
pub type Response = isahc::Response<AsyncBody>; pub type Response = isahc::Response<AsyncBody>;
pub trait HttpClient: Send + Sync { pub trait HttpClient: Send + Sync {
fn send<'a>(&'a self, req: Request) -> BoxFuture<'a, Result<Response, Error>>; fn send(&self, req: Request) -> BoxFuture<Result<Response, Error>>;
fn get<'a>( fn get<'a>(
&'a self, &'a self,
@ -45,7 +45,7 @@ pub fn client() -> Arc<dyn HttpClient> {
} }
impl HttpClient for isahc::HttpClient { impl HttpClient for isahc::HttpClient {
fn send<'a>(&'a self, req: Request) -> BoxFuture<'a, Result<Response, Error>> { fn send(&self, req: Request) -> BoxFuture<Result<Response, Error>> {
Box::pin(async move { self.send_async(req).await }) Box::pin(async move { self.send_async(req).await })
} }
} }

View File

@ -56,7 +56,7 @@ impl FakeServer {
} }
}) })
.override_establish_connection({ .override_establish_connection({
let peer = Arc::downgrade(&server.peer).clone(); let peer = Arc::downgrade(&server.peer);
let state = Arc::downgrade(&server.state); let state = Arc::downgrade(&server.state);
move |credentials, cx| { move |credentials, cx| {
let peer = peer.clone(); let peer = peer.clone();
@ -123,6 +123,7 @@ impl FakeServer {
self.peer.send(self.connection_id(), message).unwrap(); self.peer.send(self.connection_id(), message).unwrap();
} }
#[allow(clippy::await_holding_lock)]
pub async fn receive<M: proto::EnvelopedMessage>(&self) -> Result<TypedEnvelope<M>> { pub async fn receive<M: proto::EnvelopedMessage>(&self) -> Result<TypedEnvelope<M>> {
self.executor.start_waiting(); self.executor.start_waiting();
let message = self let message = self
@ -194,7 +195,7 @@ pub struct FakeHttpClient {
} }
impl FakeHttpClient { impl FakeHttpClient {
pub fn new<Fut, F>(handler: F) -> Arc<dyn HttpClient> pub fn create<Fut, F>(handler: F) -> Arc<dyn HttpClient>
where where
Fut: 'static + Send + Future<Output = Result<Response, http::Error>>, Fut: 'static + Send + Future<Output = Result<Response, http::Error>>,
F: 'static + Send + Sync + Fn(Request) -> Fut, F: 'static + Send + Sync + Fn(Request) -> Fut,
@ -205,7 +206,7 @@ impl FakeHttpClient {
} }
pub fn with_404_response() -> Arc<dyn HttpClient> { pub fn with_404_response() -> Arc<dyn HttpClient> {
Self::new(|_| async move { Self::create(|_| async move {
Ok(isahc::Response::builder() Ok(isahc::Response::builder()
.status(404) .status(404)
.body(Default::default()) .body(Default::default())
@ -221,7 +222,7 @@ impl fmt::Debug for FakeHttpClient {
} }
impl HttpClient for FakeHttpClient { impl HttpClient for FakeHttpClient {
fn send<'a>(&'a self, req: Request) -> BoxFuture<'a, Result<Response, crate::http::Error>> { fn send(&self, req: Request) -> BoxFuture<Result<Response, crate::http::Error>> {
let future = (self.handler)(req); let future = (self.handler)(req);
Box::pin(async move { future.await.map(Into::into) }) Box::pin(async move { future.await.map(Into::into) })
} }

View File

@ -17,7 +17,7 @@ pub struct User {
impl PartialOrd for User { impl PartialOrd for User {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(&other)) Some(self.cmp(other))
} }
} }

View File

@ -54,14 +54,14 @@ impl<'a> Add<&'a Self> for Local {
type Output = Local; type Output = Local;
fn add(self, other: &'a Self) -> Self::Output { fn add(self, other: &'a Self) -> Self::Output {
cmp::max(&self, other).clone() *cmp::max(&self, other)
} }
} }
impl<'a> AddAssign<&'a Local> for Local { impl<'a> AddAssign<&'a Local> for Local {
fn add_assign(&mut self, other: &Self) { fn add_assign(&mut self, other: &Self) {
if *self < *other { if *self < *other {
*self = other.clone(); *self = *other;
} }
} }
} }
@ -177,7 +177,7 @@ impl Global {
false false
} }
pub fn iter<'a>(&'a self) -> impl 'a + Iterator<Item = Local> { pub fn iter(&self) -> impl Iterator<Item = Local> + '_ {
self.0.iter().enumerate().map(|(replica_id, seq)| Local { self.0.iter().enumerate().map(|(replica_id, seq)| Local {
replica_id: replica_id as ReplicaId, replica_id: replica_id as ReplicaId,
value: *seq, value: *seq,

View File

@ -394,7 +394,7 @@ async fn create_access_token(
} else { } else {
return Err(Error::Http( return Err(Error::Http(
StatusCode::UNAUTHORIZED, StatusCode::UNAUTHORIZED,
format!("you do not have permission to impersonate other users"), "you do not have permission to impersonate other users".to_string(),
)); ));
} }
} }

View File

@ -44,7 +44,7 @@ pub async fn validate_header<B>(mut req: Request<B>, next: Next<B>) -> impl Into
let state = req.extensions().get::<Arc<AppState>>().unwrap(); let state = req.extensions().get::<Arc<AppState>>().unwrap();
let mut credentials_valid = false; let mut credentials_valid = false;
for password_hash in state.db.get_access_token_hashes(user_id).await? { for password_hash in state.db.get_access_token_hashes(user_id).await? {
if verify_access_token(&access_token, &password_hash)? { if verify_access_token(access_token, &password_hash)? {
credentials_valid = true; credentials_valid = true;
break; break;
} }
@ -100,7 +100,7 @@ pub fn encrypt_access_token(access_token: &str, public_key: String) -> Result<St
let native_app_public_key = let native_app_public_key =
rpc::auth::PublicKey::try_from(public_key).context("failed to parse app public key")?; rpc::auth::PublicKey::try_from(public_key).context("failed to parse app public key")?;
let encrypted_access_token = native_app_public_key let encrypted_access_token = native_app_public_key
.encrypt_string(&access_token) .encrypt_string(access_token)
.context("failed to encrypt access token with public key")?; .context("failed to encrypt access token with public key")?;
Ok(encrypted_access_token) Ok(encrypted_access_token)
} }

View File

@ -154,7 +154,7 @@ pub trait Db: Send + Sync {
#[cfg(test)] #[cfg(test)]
async fn teardown(&self, url: &str); async fn teardown(&self, url: &str);
#[cfg(test)] #[cfg(test)]
fn as_fake<'a>(&'a self) -> Option<&'a tests::FakeDb>; fn as_fake(&self) -> Option<&tests::FakeDb>;
} }
pub struct PostgresDb { pub struct PostgresDb {
@ -165,7 +165,7 @@ impl PostgresDb {
pub async fn new(url: &str, max_connections: u32) -> Result<Self> { pub async fn new(url: &str, max_connections: u32) -> Result<Self> {
let pool = DbOptions::new() let pool = DbOptions::new()
.max_connections(max_connections) .max_connections(max_connections)
.connect(&url) .connect(url)
.await .await
.context("failed to connect to postgres database")?; .context("failed to connect to postgres database")?;
Ok(Self { pool }) Ok(Self { pool })
@ -568,7 +568,7 @@ impl Db for PostgresDb {
for count in counts { for count in counts {
extension_counts extension_counts
.entry(count.worktree_id as u64) .entry(count.worktree_id as u64)
.or_insert(HashMap::default()) .or_insert_with(HashMap::default)
.insert(count.extension, count.count as usize); .insert(count.extension, count.count as usize);
} }
Ok(extension_counts) Ok(extension_counts)
@ -863,8 +863,7 @@ impl Db for PostgresDb {
should_notify, should_notify,
}); });
} }
} else { } else if accepted {
if accepted {
contacts.push(Contact::Accepted { contacts.push(Contact::Accepted {
user_id: user_id_a, user_id: user_id_a,
should_notify: should_notify && !a_to_b, should_notify: should_notify && !a_to_b,
@ -878,7 +877,6 @@ impl Db for PostgresDb {
contacts.push(Contact::Outgoing { user_id: user_id_a }); contacts.push(Contact::Outgoing { user_id: user_id_a });
} }
} }
}
contacts.sort_unstable_by_key(|contact| contact.user_id()); contacts.sort_unstable_by_key(|contact| contact.user_id());
@ -1331,7 +1329,7 @@ macro_rules! id_type {
} }
#[allow(unused)] #[allow(unused)]
pub fn to_proto(&self) -> u64 { pub fn to_proto(self) -> u64 {
self.0 as u64 self.0 as u64
} }
} }
@ -2408,6 +2406,7 @@ pub mod tests {
} }
impl TestDb { impl TestDb {
#[allow(clippy::await_holding_lock)]
pub async fn postgres() -> Self { pub async fn postgres() -> Self {
lazy_static! { lazy_static! {
static ref LOCK: Mutex<()> = Mutex::new(()); static ref LOCK: Mutex<()> = Mutex::new(());

View File

@ -157,7 +157,7 @@ async fn test_share_project(
// Edit the buffer as client B and see that edit as client A. // Edit the buffer as client B and see that edit as client A.
editor_b.update(cx_b, |editor, cx| editor.handle_input("ok, ", cx)); editor_b.update(cx_b, |editor, cx| editor.handle_input("ok, ", cx));
buffer_a buffer_a
.condition(&cx_a, |buffer, _| buffer.text() == "ok, b-contents") .condition(cx_a, |buffer, _| buffer.text() == "ok, b-contents")
.await; .await;
// TODO // TODO
@ -482,7 +482,7 @@ async fn test_cancel_join_request(
client_b.client.clone(), client_b.client.clone(),
client_b.user_store.clone(), client_b.user_store.clone(),
client_b.project_store.clone(), client_b.project_store.clone(),
client_b.language_registry.clone().clone(), client_b.language_registry.clone(),
FakeFs::new(cx.background()), FakeFs::new(cx.background()),
cx, cx,
) )
@ -504,7 +504,7 @@ async fn test_cancel_join_request(
deterministic.run_until_parked(); deterministic.run_until_parked();
assert_eq!( assert_eq!(
&*project_a_events.borrow(), &*project_a_events.borrow(),
&[project::Event::ContactCancelledJoinRequest(user_b.clone())] &[project::Event::ContactCancelledJoinRequest(user_b)]
); );
} }
@ -554,17 +554,17 @@ async fn test_offline_projects(
user_store: ModelHandle<UserStore>, user_store: ModelHandle<UserStore>,
cx: &mut gpui::MutableAppContext, cx: &mut gpui::MutableAppContext,
) { ) {
let open_project_ids = project_store
.read(cx)
.projects(cx)
.filter_map(|project| project.read(cx).remote_id())
.collect::<Vec<_>>();
let user_store = user_store.read(cx); let user_store = user_store.read(cx);
for contact in user_store.contacts() { for contact in user_store.contacts() {
if contact.user.id == user_store.current_user().unwrap().id { if contact.user.id == user_store.current_user().unwrap().id {
for project in &contact.projects { for project in &contact.projects {
if !open_project_ids.contains(&project.id) { let store_contains_project = project_store
.read(cx)
.projects(cx)
.filter_map(|project| project.read(cx).remote_id())
.any(|x| x == project.id);
if !store_contains_project {
panic!( panic!(
concat!( concat!(
"current user's contact data has a project", "current user's contact data has a project",
@ -903,7 +903,7 @@ async fn test_propagate_saves_and_fs_changes(
client_a.fs.insert_file("/a/file4", "4".into()).await; client_a.fs.insert_file("/a/file4", "4".into()).await;
worktree_a worktree_a
.condition(&cx_a, |tree, _| { .condition(cx_a, |tree, _| {
tree.paths() tree.paths()
.map(|p| p.to_string_lossy()) .map(|p| p.to_string_lossy())
.collect::<Vec<_>>() .collect::<Vec<_>>()
@ -911,7 +911,7 @@ async fn test_propagate_saves_and_fs_changes(
}) })
.await; .await;
worktree_b worktree_b
.condition(&cx_b, |tree, _| { .condition(cx_b, |tree, _| {
tree.paths() tree.paths()
.map(|p| p.to_string_lossy()) .map(|p| p.to_string_lossy())
.collect::<Vec<_>>() .collect::<Vec<_>>()
@ -919,7 +919,7 @@ async fn test_propagate_saves_and_fs_changes(
}) })
.await; .await;
worktree_c worktree_c
.condition(&cx_c, |tree, _| { .condition(cx_c, |tree, _| {
tree.paths() tree.paths()
.map(|p| p.to_string_lossy()) .map(|p| p.to_string_lossy())
.collect::<Vec<_>>() .collect::<Vec<_>>()
@ -929,17 +929,17 @@ async fn test_propagate_saves_and_fs_changes(
// Ensure buffer files are updated as well. // Ensure buffer files are updated as well.
buffer_a buffer_a
.condition(&cx_a, |buf, _| { .condition(cx_a, |buf, _| {
buf.file().unwrap().path().to_str() == Some("file1-renamed") buf.file().unwrap().path().to_str() == Some("file1-renamed")
}) })
.await; .await;
buffer_b buffer_b
.condition(&cx_b, |buf, _| { .condition(cx_b, |buf, _| {
buf.file().unwrap().path().to_str() == Some("file1-renamed") buf.file().unwrap().path().to_str() == Some("file1-renamed")
}) })
.await; .await;
buffer_c buffer_c
.condition(&cx_c, |buf, _| { .condition(cx_c, |buf, _| {
buf.file().unwrap().path().to_str() == Some("file1-renamed") buf.file().unwrap().path().to_str() == Some("file1-renamed")
}) })
.await; .await;
@ -1246,7 +1246,7 @@ async fn test_buffer_conflict_after_save(cx_a: &mut TestAppContext, cx_b: &mut T
buffer_b.update(cx_b, |buf, cx| buf.save(cx)).await.unwrap(); buffer_b.update(cx_b, |buf, cx| buf.save(cx)).await.unwrap();
buffer_b buffer_b
.condition(&cx_b, |buffer_b, _| !buffer_b.is_dirty()) .condition(cx_b, |buffer_b, _| !buffer_b.is_dirty())
.await; .await;
buffer_b.read_with(cx_b, |buf, _| { buffer_b.read_with(cx_b, |buf, _| {
assert!(!buf.has_conflict()); assert!(!buf.has_conflict());
@ -1299,7 +1299,7 @@ async fn test_buffer_reloading(cx_a: &mut TestAppContext, cx_b: &mut TestAppCont
.await .await
.unwrap(); .unwrap();
buffer_b buffer_b
.condition(&cx_b, |buf, _| { .condition(cx_b, |buf, _| {
buf.text() == new_contents.to_string() && !buf.is_dirty() buf.text() == new_contents.to_string() && !buf.is_dirty()
}) })
.await; .await;
@ -1349,7 +1349,7 @@ async fn test_editing_while_guest_opens_buffer(
let text = buffer_a.read_with(cx_a, |buf, _| buf.text()); let text = buffer_a.read_with(cx_a, |buf, _| buf.text());
let buffer_b = buffer_b.await.unwrap(); let buffer_b = buffer_b.await.unwrap();
buffer_b.condition(&cx_b, |buf, _| buf.text() == text).await; buffer_b.condition(cx_b, |buf, _| buf.text() == text).await;
} }
#[gpui::test(iterations = 10)] #[gpui::test(iterations = 10)]
@ -1374,7 +1374,7 @@ async fn test_leaving_worktree_while_opening_buffer(
// See that a guest has joined as client A. // See that a guest has joined as client A.
project_a project_a
.condition(&cx_a, |p, _| p.collaborators().len() == 1) .condition(cx_a, |p, _| p.collaborators().len() == 1)
.await; .await;
// Begin opening a buffer as client B, but leave the project before the open completes. // Begin opening a buffer as client B, but leave the project before the open completes.
@ -1386,7 +1386,7 @@ async fn test_leaving_worktree_while_opening_buffer(
// See that the guest has left. // See that the guest has left.
project_a project_a
.condition(&cx_a, |p, _| p.collaborators().len() == 0) .condition(cx_a, |p, _| p.collaborators().is_empty())
.await; .await;
} }
@ -1421,7 +1421,7 @@ async fn test_leaving_project(cx_a: &mut TestAppContext, cx_b: &mut TestAppConte
// Drop client B's connection and ensure client A observes client B leaving the project. // Drop client B's connection and ensure client A observes client B leaving the project.
client_b.disconnect(&cx_b.to_async()).unwrap(); client_b.disconnect(&cx_b.to_async()).unwrap();
project_a project_a
.condition(cx_a, |p, _| p.collaborators().len() == 0) .condition(cx_a, |p, _| p.collaborators().is_empty())
.await; .await;
// Rejoin the project as client B // Rejoin the project as client B
@ -1437,7 +1437,7 @@ async fn test_leaving_project(cx_a: &mut TestAppContext, cx_b: &mut TestAppConte
server.disconnect_client(client_b.current_user_id(cx_b)); server.disconnect_client(client_b.current_user_id(cx_b));
cx_a.foreground().advance_clock(rpc::RECEIVE_TIMEOUT); cx_a.foreground().advance_clock(rpc::RECEIVE_TIMEOUT);
project_a project_a
.condition(cx_a, |p, _| p.collaborators().len() == 0) .condition(cx_a, |p, _| p.collaborators().is_empty())
.await; .await;
} }
@ -1639,7 +1639,6 @@ async fn test_collaborating_with_diagnostics(
buffer buffer
.snapshot() .snapshot()
.diagnostics_in_range::<_, Point>(0..buffer.len(), false) .diagnostics_in_range::<_, Point>(0..buffer.len(), false)
.map(|entry| entry)
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
&[ &[
DiagnosticEntry { DiagnosticEntry {
@ -1744,7 +1743,7 @@ async fn test_collaborating_with_completion(cx_a: &mut TestAppContext, cx_b: &mu
let fake_language_server = fake_language_servers.next().await.unwrap(); let fake_language_server = fake_language_servers.next().await.unwrap();
buffer_b buffer_b
.condition(&cx_b, |buffer, _| !buffer.completion_triggers().is_empty()) .condition(cx_b, |buffer, _| !buffer.completion_triggers().is_empty())
.await; .await;
// Type a completion trigger character as the guest. // Type a completion trigger character as the guest.
@ -1808,12 +1807,12 @@ async fn test_collaborating_with_completion(cx_a: &mut TestAppContext, cx_b: &mu
.await .await
.unwrap(); .unwrap();
buffer_a buffer_a
.condition(&cx_a, |buffer, _| buffer.text() == "fn main() { a. }") .condition(cx_a, |buffer, _| buffer.text() == "fn main() { a. }")
.await; .await;
// Confirm a completion on the guest. // Confirm a completion on the guest.
editor_b editor_b
.condition(&cx_b, |editor, _| editor.context_menu_visible()) .condition(cx_b, |editor, _| editor.context_menu_visible())
.await; .await;
editor_b.update(cx_b, |editor, cx| { editor_b.update(cx_b, |editor, cx| {
editor.confirm_completion(&ConfirmCompletion { item_ix: Some(0) }, cx); editor.confirm_completion(&ConfirmCompletion { item_ix: Some(0) }, cx);
@ -1844,12 +1843,12 @@ async fn test_collaborating_with_completion(cx_a: &mut TestAppContext, cx_b: &mu
// The additional edit is applied. // The additional edit is applied.
buffer_a buffer_a
.condition(&cx_a, |buffer, _| { .condition(cx_a, |buffer, _| {
buffer.text() == "use d::SomeTrait;\nfn main() { a.first_method() }" buffer.text() == "use d::SomeTrait;\nfn main() { a.first_method() }"
}) })
.await; .await;
buffer_b buffer_b
.condition(&cx_b, |buffer, _| { .condition(cx_b, |buffer, _| {
buffer.text() == "use d::SomeTrait;\nfn main() { a.first_method() }" buffer.text() == "use d::SomeTrait;\nfn main() { a.first_method() }"
}) })
.await; .await;
@ -2256,9 +2255,9 @@ async fn test_references(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) {
Path::new("three.rs") Path::new("three.rs")
); );
assert_eq!(references[0].range.to_offset(&two_buffer), 24..27); assert_eq!(references[0].range.to_offset(two_buffer), 24..27);
assert_eq!(references[1].range.to_offset(&two_buffer), 35..38); assert_eq!(references[1].range.to_offset(two_buffer), 35..38);
assert_eq!(references[2].range.to_offset(&three_buffer), 37..40); assert_eq!(references[2].range.to_offset(three_buffer), 37..40);
}); });
} }
@ -2707,7 +2706,7 @@ async fn test_collaborating_with_code_actions(
cx_b: &mut TestAppContext, cx_b: &mut TestAppContext,
) { ) {
cx_a.foreground().forbid_parking(); cx_a.foreground().forbid_parking();
cx_b.update(|cx| editor::init(cx)); cx_b.update(editor::init);
let mut server = TestServer::start(cx_a.foreground(), cx_a.background()).await; let mut server = TestServer::start(cx_a.foreground(), cx_a.background()).await;
let client_a = server.create_client(cx_a, "user_a").await; let client_a = server.create_client(cx_a, "user_a").await;
let client_b = server.create_client(cx_b, "user_b").await; let client_b = server.create_client(cx_b, "user_b").await;
@ -2839,7 +2838,7 @@ async fn test_collaborating_with_code_actions(
); );
}); });
editor_b editor_b
.condition(&cx_b, |editor, _| editor.context_menu_visible()) .condition(cx_b, |editor, _| editor.context_menu_visible())
.await; .await;
fake_language_server.remove_request_handler::<lsp::request::CodeActionRequest>(); fake_language_server.remove_request_handler::<lsp::request::CodeActionRequest>();
@ -2912,7 +2911,7 @@ async fn test_collaborating_with_code_actions(
#[gpui::test(iterations = 10)] #[gpui::test(iterations = 10)]
async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) { async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) {
cx_a.foreground().forbid_parking(); cx_a.foreground().forbid_parking();
cx_b.update(|cx| editor::init(cx)); cx_b.update(editor::init);
let mut server = TestServer::start(cx_a.foreground(), cx_a.background()).await; let mut server = TestServer::start(cx_a.foreground(), cx_a.background()).await;
let client_a = server.create_client(cx_a, "user_a").await; let client_a = server.create_client(cx_a, "user_a").await;
let client_b = server.create_client(cx_b, "user_b").await; let client_b = server.create_client(cx_b, "user_b").await;
@ -3098,7 +3097,7 @@ async fn test_language_server_statuses(
) { ) {
deterministic.forbid_parking(); deterministic.forbid_parking();
cx_b.update(|cx| editor::init(cx)); cx_b.update(editor::init);
let mut server = TestServer::start(cx_a.foreground(), cx_a.background()).await; let mut server = TestServer::start(cx_a.foreground(), cx_a.background()).await;
let client_a = server.create_client(cx_a, "user_a").await; let client_a = server.create_client(cx_a, "user_a").await;
let client_b = server.create_client(cx_b, "user_b").await; let client_b = server.create_client(cx_b, "user_b").await;
@ -3207,24 +3206,24 @@ async fn test_basic_chat(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) {
// Create an org that includes these 2 users. // Create an org that includes these 2 users.
let db = &server.app_state.db; let db = &server.app_state.db;
let org_id = db.create_org("Test Org", "test-org").await.unwrap(); let org_id = db.create_org("Test Org", "test-org").await.unwrap();
db.add_org_member(org_id, client_a.current_user_id(&cx_a), false) db.add_org_member(org_id, client_a.current_user_id(cx_a), false)
.await .await
.unwrap(); .unwrap();
db.add_org_member(org_id, client_b.current_user_id(&cx_b), false) db.add_org_member(org_id, client_b.current_user_id(cx_b), false)
.await .await
.unwrap(); .unwrap();
// Create a channel that includes all the users. // Create a channel that includes all the users.
let channel_id = db.create_org_channel(org_id, "test-channel").await.unwrap(); let channel_id = db.create_org_channel(org_id, "test-channel").await.unwrap();
db.add_channel_member(channel_id, client_a.current_user_id(&cx_a), false) db.add_channel_member(channel_id, client_a.current_user_id(cx_a), false)
.await .await
.unwrap(); .unwrap();
db.add_channel_member(channel_id, client_b.current_user_id(&cx_b), false) db.add_channel_member(channel_id, client_b.current_user_id(cx_b), false)
.await .await
.unwrap(); .unwrap();
db.create_channel_message( db.create_channel_message(
channel_id, channel_id,
client_b.current_user_id(&cx_b), client_b.current_user_id(cx_b),
"hello A, it's B.", "hello A, it's B.",
OffsetDateTime::now_utc(), OffsetDateTime::now_utc(),
1, 1,
@ -3251,7 +3250,7 @@ async fn test_basic_chat(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) {
}); });
channel_a.read_with(cx_a, |channel, _| assert!(channel.messages().is_empty())); channel_a.read_with(cx_a, |channel, _| assert!(channel.messages().is_empty()));
channel_a channel_a
.condition(&cx_a, |channel, _| { .condition(cx_a, |channel, _| {
channel_messages(channel) channel_messages(channel)
== [("user_b".to_string(), "hello A, it's B.".to_string(), false)] == [("user_b".to_string(), "hello A, it's B.".to_string(), false)]
}) })
@ -3277,7 +3276,7 @@ async fn test_basic_chat(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) {
}); });
channel_b.read_with(cx_b, |channel, _| assert!(channel.messages().is_empty())); channel_b.read_with(cx_b, |channel, _| assert!(channel.messages().is_empty()));
channel_b channel_b
.condition(&cx_b, |channel, _| { .condition(cx_b, |channel, _| {
channel_messages(channel) channel_messages(channel)
== [("user_b".to_string(), "hello A, it's B.".to_string(), false)] == [("user_b".to_string(), "hello A, it's B.".to_string(), false)]
}) })
@ -3304,7 +3303,7 @@ async fn test_basic_chat(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) {
.unwrap(); .unwrap();
channel_b channel_b
.condition(&cx_b, |channel, _| { .condition(cx_b, |channel, _| {
channel_messages(channel) channel_messages(channel)
== [ == [
("user_b".to_string(), "hello A, it's B.".to_string(), false), ("user_b".to_string(), "hello A, it's B.".to_string(), false),
@ -3344,10 +3343,10 @@ async fn test_chat_message_validation(cx_a: &mut TestAppContext) {
let db = &server.app_state.db; let db = &server.app_state.db;
let org_id = db.create_org("Test Org", "test-org").await.unwrap(); let org_id = db.create_org("Test Org", "test-org").await.unwrap();
let channel_id = db.create_org_channel(org_id, "test-channel").await.unwrap(); let channel_id = db.create_org_channel(org_id, "test-channel").await.unwrap();
db.add_org_member(org_id, client_a.current_user_id(&cx_a), false) db.add_org_member(org_id, client_a.current_user_id(cx_a), false)
.await .await
.unwrap(); .unwrap();
db.add_channel_member(channel_id, client_a.current_user_id(&cx_a), false) db.add_channel_member(channel_id, client_a.current_user_id(cx_a), false)
.await .await
.unwrap(); .unwrap();
@ -3406,24 +3405,24 @@ async fn test_chat_reconnection(cx_a: &mut TestAppContext, cx_b: &mut TestAppCon
// Create an org that includes these 2 users. // Create an org that includes these 2 users.
let db = &server.app_state.db; let db = &server.app_state.db;
let org_id = db.create_org("Test Org", "test-org").await.unwrap(); let org_id = db.create_org("Test Org", "test-org").await.unwrap();
db.add_org_member(org_id, client_a.current_user_id(&cx_a), false) db.add_org_member(org_id, client_a.current_user_id(cx_a), false)
.await .await
.unwrap(); .unwrap();
db.add_org_member(org_id, client_b.current_user_id(&cx_b), false) db.add_org_member(org_id, client_b.current_user_id(cx_b), false)
.await .await
.unwrap(); .unwrap();
// Create a channel that includes all the users. // Create a channel that includes all the users.
let channel_id = db.create_org_channel(org_id, "test-channel").await.unwrap(); let channel_id = db.create_org_channel(org_id, "test-channel").await.unwrap();
db.add_channel_member(channel_id, client_a.current_user_id(&cx_a), false) db.add_channel_member(channel_id, client_a.current_user_id(cx_a), false)
.await .await
.unwrap(); .unwrap();
db.add_channel_member(channel_id, client_b.current_user_id(&cx_b), false) db.add_channel_member(channel_id, client_b.current_user_id(cx_b), false)
.await .await
.unwrap(); .unwrap();
db.create_channel_message( db.create_channel_message(
channel_id, channel_id,
client_b.current_user_id(&cx_b), client_b.current_user_id(cx_b),
"hello A, it's B.", "hello A, it's B.",
OffsetDateTime::now_utc(), OffsetDateTime::now_utc(),
2, 2,
@ -3451,7 +3450,7 @@ async fn test_chat_reconnection(cx_a: &mut TestAppContext, cx_b: &mut TestAppCon
}); });
channel_a.read_with(cx_a, |channel, _| assert!(channel.messages().is_empty())); channel_a.read_with(cx_a, |channel, _| assert!(channel.messages().is_empty()));
channel_a channel_a
.condition(&cx_a, |channel, _| { .condition(cx_a, |channel, _| {
channel_messages(channel) channel_messages(channel)
== [("user_b".to_string(), "hello A, it's B.".to_string(), false)] == [("user_b".to_string(), "hello A, it's B.".to_string(), false)]
}) })
@ -3477,7 +3476,7 @@ async fn test_chat_reconnection(cx_a: &mut TestAppContext, cx_b: &mut TestAppCon
}); });
channel_b.read_with(cx_b, |channel, _| assert!(channel.messages().is_empty())); channel_b.read_with(cx_b, |channel, _| assert!(channel.messages().is_empty()));
channel_b channel_b
.condition(&cx_b, |channel, _| { .condition(cx_b, |channel, _| {
channel_messages(channel) channel_messages(channel)
== [("user_b".to_string(), "hello A, it's B.".to_string(), false)] == [("user_b".to_string(), "hello A, it's B.".to_string(), false)]
}) })
@ -3485,7 +3484,7 @@ async fn test_chat_reconnection(cx_a: &mut TestAppContext, cx_b: &mut TestAppCon
// Disconnect client B, ensuring we can still access its cached channel data. // Disconnect client B, ensuring we can still access its cached channel data.
server.forbid_connections(); server.forbid_connections();
server.disconnect_client(client_b.current_user_id(&cx_b)); server.disconnect_client(client_b.current_user_id(cx_b));
cx_b.foreground().advance_clock(rpc::RECEIVE_TIMEOUT); cx_b.foreground().advance_clock(rpc::RECEIVE_TIMEOUT);
while !matches!( while !matches!(
status_b.next().await, status_b.next().await,
@ -3554,7 +3553,7 @@ async fn test_chat_reconnection(cx_a: &mut TestAppContext, cx_b: &mut TestAppCon
// Verify that B sees the new messages upon reconnection, as well as the message client B // Verify that B sees the new messages upon reconnection, as well as the message client B
// sent while offline. // sent while offline.
channel_b channel_b
.condition(&cx_b, |channel, _| { .condition(cx_b, |channel, _| {
channel_messages(channel) channel_messages(channel)
== [ == [
("user_b".to_string(), "hello A, it's B.".to_string(), false), ("user_b".to_string(), "hello A, it's B.".to_string(), false),
@ -3573,7 +3572,7 @@ async fn test_chat_reconnection(cx_a: &mut TestAppContext, cx_b: &mut TestAppCon
.await .await
.unwrap(); .unwrap();
channel_b channel_b
.condition(&cx_b, |channel, _| { .condition(cx_b, |channel, _| {
channel_messages(channel) channel_messages(channel)
== [ == [
("user_b".to_string(), "hello A, it's B.".to_string(), false), ("user_b".to_string(), "hello A, it's B.".to_string(), false),
@ -3592,7 +3591,7 @@ async fn test_chat_reconnection(cx_a: &mut TestAppContext, cx_b: &mut TestAppCon
.await .await
.unwrap(); .unwrap();
channel_a channel_a
.condition(&cx_a, |channel, _| { .condition(cx_a, |channel, _| {
channel_messages(channel) channel_messages(channel)
== [ == [
("user_b".to_string(), "hello A, it's B.".to_string(), false), ("user_b".to_string(), "hello A, it's B.".to_string(), false),
@ -3701,7 +3700,7 @@ async fn test_contacts(
} }
project_a project_a
.condition(&cx_a, |project, _| { .condition(cx_a, |project, _| {
project.collaborators().contains_key(&client_b.peer_id) project.collaborators().contains_key(&client_b.peer_id)
}) })
.await; .await;
@ -3766,6 +3765,7 @@ async fn test_contacts(
}); });
} }
#[allow(clippy::type_complexity)]
fn contacts(user_store: &UserStore) -> Vec<(&str, bool, Vec<(&str, Vec<&str>)>)> { fn contacts(user_store: &UserStore) -> Vec<(&str, bool, Vec<(&str, Vec<&str>)>)> {
user_store user_store
.contacts() .contacts()
@ -3831,27 +3831,27 @@ async fn test_contact_requests(
// All users see the pending request appear in all their clients. // All users see the pending request appear in all their clients.
assert_eq!( assert_eq!(
client_a.summarize_contacts(&cx_a).outgoing_requests, client_a.summarize_contacts(cx_a).outgoing_requests,
&["user_b"] &["user_b"]
); );
assert_eq!( assert_eq!(
client_a2.summarize_contacts(&cx_a2).outgoing_requests, client_a2.summarize_contacts(cx_a2).outgoing_requests,
&["user_b"] &["user_b"]
); );
assert_eq!( assert_eq!(
client_b.summarize_contacts(&cx_b).incoming_requests, client_b.summarize_contacts(cx_b).incoming_requests,
&["user_a", "user_c"] &["user_a", "user_c"]
); );
assert_eq!( assert_eq!(
client_b2.summarize_contacts(&cx_b2).incoming_requests, client_b2.summarize_contacts(cx_b2).incoming_requests,
&["user_a", "user_c"] &["user_a", "user_c"]
); );
assert_eq!( assert_eq!(
client_c.summarize_contacts(&cx_c).outgoing_requests, client_c.summarize_contacts(cx_c).outgoing_requests,
&["user_b"] &["user_b"]
); );
assert_eq!( assert_eq!(
client_c2.summarize_contacts(&cx_c2).outgoing_requests, client_c2.summarize_contacts(cx_c2).outgoing_requests,
&["user_b"] &["user_b"]
); );
@ -3861,15 +3861,15 @@ async fn test_contact_requests(
disconnect_and_reconnect(&client_c, cx_c).await; disconnect_and_reconnect(&client_c, cx_c).await;
executor.run_until_parked(); executor.run_until_parked();
assert_eq!( assert_eq!(
client_a.summarize_contacts(&cx_a).outgoing_requests, client_a.summarize_contacts(cx_a).outgoing_requests,
&["user_b"] &["user_b"]
); );
assert_eq!( assert_eq!(
client_b.summarize_contacts(&cx_b).incoming_requests, client_b.summarize_contacts(cx_b).incoming_requests,
&["user_a", "user_c"] &["user_a", "user_c"]
); );
assert_eq!( assert_eq!(
client_c.summarize_contacts(&cx_c).outgoing_requests, client_c.summarize_contacts(cx_c).outgoing_requests,
&["user_b"] &["user_b"]
); );
@ -3885,18 +3885,18 @@ async fn test_contact_requests(
executor.run_until_parked(); executor.run_until_parked();
// User B sees user A as their contact now in all client, and the incoming request from them is removed. // User B sees user A as their contact now in all client, and the incoming request from them is removed.
let contacts_b = client_b.summarize_contacts(&cx_b); let contacts_b = client_b.summarize_contacts(cx_b);
assert_eq!(contacts_b.current, &["user_a", "user_b"]); assert_eq!(contacts_b.current, &["user_a", "user_b"]);
assert_eq!(contacts_b.incoming_requests, &["user_c"]); assert_eq!(contacts_b.incoming_requests, &["user_c"]);
let contacts_b2 = client_b2.summarize_contacts(&cx_b2); let contacts_b2 = client_b2.summarize_contacts(cx_b2);
assert_eq!(contacts_b2.current, &["user_a", "user_b"]); assert_eq!(contacts_b2.current, &["user_a", "user_b"]);
assert_eq!(contacts_b2.incoming_requests, &["user_c"]); assert_eq!(contacts_b2.incoming_requests, &["user_c"]);
// User A sees user B as their contact now in all clients, and the outgoing request to them is removed. // User A sees user B as their contact now in all clients, and the outgoing request to them is removed.
let contacts_a = client_a.summarize_contacts(&cx_a); let contacts_a = client_a.summarize_contacts(cx_a);
assert_eq!(contacts_a.current, &["user_a", "user_b"]); assert_eq!(contacts_a.current, &["user_a", "user_b"]);
assert!(contacts_a.outgoing_requests.is_empty()); assert!(contacts_a.outgoing_requests.is_empty());
let contacts_a2 = client_a2.summarize_contacts(&cx_a2); let contacts_a2 = client_a2.summarize_contacts(cx_a2);
assert_eq!(contacts_a2.current, &["user_a", "user_b"]); assert_eq!(contacts_a2.current, &["user_a", "user_b"]);
assert!(contacts_a2.outgoing_requests.is_empty()); assert!(contacts_a2.outgoing_requests.is_empty());
@ -3906,20 +3906,20 @@ async fn test_contact_requests(
disconnect_and_reconnect(&client_c, cx_c).await; disconnect_and_reconnect(&client_c, cx_c).await;
executor.run_until_parked(); executor.run_until_parked();
assert_eq!( assert_eq!(
client_a.summarize_contacts(&cx_a).current, client_a.summarize_contacts(cx_a).current,
&["user_a", "user_b"] &["user_a", "user_b"]
); );
assert_eq!( assert_eq!(
client_b.summarize_contacts(&cx_b).current, client_b.summarize_contacts(cx_b).current,
&["user_a", "user_b"] &["user_a", "user_b"]
); );
assert_eq!( assert_eq!(
client_b.summarize_contacts(&cx_b).incoming_requests, client_b.summarize_contacts(cx_b).incoming_requests,
&["user_c"] &["user_c"]
); );
assert_eq!(client_c.summarize_contacts(&cx_c).current, &["user_c"]); assert_eq!(client_c.summarize_contacts(cx_c).current, &["user_c"]);
assert_eq!( assert_eq!(
client_c.summarize_contacts(&cx_c).outgoing_requests, client_c.summarize_contacts(cx_c).outgoing_requests,
&["user_b"] &["user_b"]
); );
@ -3935,18 +3935,18 @@ async fn test_contact_requests(
executor.run_until_parked(); executor.run_until_parked();
// User B doesn't see user C as their contact, and the incoming request from them is removed. // User B doesn't see user C as their contact, and the incoming request from them is removed.
let contacts_b = client_b.summarize_contacts(&cx_b); let contacts_b = client_b.summarize_contacts(cx_b);
assert_eq!(contacts_b.current, &["user_a", "user_b"]); assert_eq!(contacts_b.current, &["user_a", "user_b"]);
assert!(contacts_b.incoming_requests.is_empty()); assert!(contacts_b.incoming_requests.is_empty());
let contacts_b2 = client_b2.summarize_contacts(&cx_b2); let contacts_b2 = client_b2.summarize_contacts(cx_b2);
assert_eq!(contacts_b2.current, &["user_a", "user_b"]); assert_eq!(contacts_b2.current, &["user_a", "user_b"]);
assert!(contacts_b2.incoming_requests.is_empty()); assert!(contacts_b2.incoming_requests.is_empty());
// User C doesn't see user B as their contact, and the outgoing request to them is removed. // User C doesn't see user B as their contact, and the outgoing request to them is removed.
let contacts_c = client_c.summarize_contacts(&cx_c); let contacts_c = client_c.summarize_contacts(cx_c);
assert_eq!(contacts_c.current, &["user_c"]); assert_eq!(contacts_c.current, &["user_c"]);
assert!(contacts_c.outgoing_requests.is_empty()); assert!(contacts_c.outgoing_requests.is_empty());
let contacts_c2 = client_c2.summarize_contacts(&cx_c2); let contacts_c2 = client_c2.summarize_contacts(cx_c2);
assert_eq!(contacts_c2.current, &["user_c"]); assert_eq!(contacts_c2.current, &["user_c"]);
assert!(contacts_c2.outgoing_requests.is_empty()); assert!(contacts_c2.outgoing_requests.is_empty());
@ -3956,20 +3956,20 @@ async fn test_contact_requests(
disconnect_and_reconnect(&client_c, cx_c).await; disconnect_and_reconnect(&client_c, cx_c).await;
executor.run_until_parked(); executor.run_until_parked();
assert_eq!( assert_eq!(
client_a.summarize_contacts(&cx_a).current, client_a.summarize_contacts(cx_a).current,
&["user_a", "user_b"] &["user_a", "user_b"]
); );
assert_eq!( assert_eq!(
client_b.summarize_contacts(&cx_b).current, client_b.summarize_contacts(cx_b).current,
&["user_a", "user_b"] &["user_a", "user_b"]
); );
assert!(client_b assert!(client_b
.summarize_contacts(&cx_b) .summarize_contacts(cx_b)
.incoming_requests .incoming_requests
.is_empty()); .is_empty());
assert_eq!(client_c.summarize_contacts(&cx_c).current, &["user_c"]); assert_eq!(client_c.summarize_contacts(cx_c).current, &["user_c"]);
assert!(client_c assert!(client_c
.summarize_contacts(&cx_c) .summarize_contacts(cx_c)
.outgoing_requests .outgoing_requests
.is_empty()); .is_empty());
@ -4553,13 +4553,13 @@ async fn test_peers_simultaneously_following_each_other(
futures::try_join!(a_follow_b, b_follow_a).unwrap(); futures::try_join!(a_follow_b, b_follow_a).unwrap();
workspace_a.read_with(cx_a, |workspace, _| { workspace_a.read_with(cx_a, |workspace, _| {
assert_eq!( assert_eq!(
workspace.leader_for_pane(&workspace.active_pane()), workspace.leader_for_pane(workspace.active_pane()),
Some(client_b_id) Some(client_b_id)
); );
}); });
workspace_b.read_with(cx_b, |workspace, _| { workspace_b.read_with(cx_b, |workspace, _| {
assert_eq!( assert_eq!(
workspace.leader_for_pane(&workspace.active_pane()), workspace.leader_for_pane(workspace.active_pane()),
Some(client_a_id) Some(client_a_id)
); );
}); });
@ -4740,7 +4740,7 @@ async fn test_random_collaboration(
fake_server.handle_request::<lsp::request::DocumentHighlightRequest, _, _>({ fake_server.handle_request::<lsp::request::DocumentHighlightRequest, _, _>({
let rng = rng.clone(); let rng = rng.clone();
let project = project.clone(); let project = project;
move |params, mut cx| { move |params, mut cx| {
let highlights = if let Some(project) = project.upgrade(&cx) { let highlights = if let Some(project) = project.upgrade(&cx) {
project.update(&mut cx, |project, cx| { project.update(&mut cx, |project, cx| {
@ -5027,10 +5027,12 @@ async fn test_random_collaboration(
for guest_buffer in &guest_client.buffers { for guest_buffer in &guest_client.buffers {
let buffer_id = guest_buffer.read_with(&guest_cx, |buffer, _| buffer.remote_id()); let buffer_id = guest_buffer.read_with(&guest_cx, |buffer, _| buffer.remote_id());
let host_buffer = host_project.read_with(&host_cx, |project, cx| { let host_buffer = host_project.read_with(&host_cx, |project, cx| {
project.buffer_for_id(buffer_id, cx).expect(&format!( project.buffer_for_id(buffer_id, cx).unwrap_or_else(|| {
panic!(
"host does not have buffer for guest:{}, peer:{}, id:{}", "host does not have buffer for guest:{}, peer:{}, id:{}",
guest_client.username, guest_client.peer_id, buffer_id guest_client.username, guest_client.peer_id, buffer_id
)) )
})
}); });
let path = let path =
host_buffer.read_with(&host_cx, |buffer, cx| buffer.file().unwrap().full_path(cx)); host_buffer.read_with(&host_cx, |buffer, cx| buffer.file().unwrap().full_path(cx));
@ -5174,7 +5176,7 @@ impl TestServer {
languages: Arc::new(LanguageRegistry::new(Task::ready(()))), languages: Arc::new(LanguageRegistry::new(Task::ready(()))),
themes: ThemeRegistry::new((), cx.font_cache()), themes: ThemeRegistry::new((), cx.font_cache()),
fs: fs.clone(), fs: fs.clone(),
build_window_options: || Default::default(), build_window_options: Default::default,
initialize_workspace: |_, _, _| unimplemented!(), initialize_workspace: |_, _, _| unimplemented!(),
}); });
@ -5540,7 +5542,7 @@ impl TestClient {
log::info!("Host: creating file {:?}", path,); log::info!("Host: creating file {:?}", path,);
if fs.create_dir(&parent_path).await.is_ok() if fs.create_dir(parent_path).await.is_ok()
&& fs.create_file(&path, Default::default()).await.is_ok() && fs.create_file(&path, Default::default()).await.is_ok()
{ {
break; break;
@ -5587,7 +5589,7 @@ impl TestClient {
let buffer = if client.buffers.is_empty() || rng.lock().gen() { let buffer = if client.buffers.is_empty() || rng.lock().gen() {
let worktree = if let Some(worktree) = project.read_with(cx, |project, cx| { let worktree = if let Some(worktree) = project.read_with(cx, |project, cx| {
project project
.worktrees(&cx) .worktrees(cx)
.filter(|worktree| { .filter(|worktree| {
let worktree = worktree.read(cx); let worktree = worktree.read(cx);
worktree.is_visible() worktree.is_visible()
@ -5820,7 +5822,7 @@ impl TestClient {
let worktree = project let worktree = project
.read_with(cx, |project, cx| { .read_with(cx, |project, cx| {
project project
.worktrees(&cx) .worktrees(cx)
.filter(|worktree| { .filter(|worktree| {
let worktree = worktree.read(cx); let worktree = worktree.read(cx);
worktree.is_visible() worktree.is_visible()

View File

@ -832,7 +832,7 @@ impl Server {
// First, we send the metadata associated with each worktree. // First, we send the metadata associated with each worktree.
for (receipt, replica_id) in &receipts_with_replica_ids { for (receipt, replica_id) in &receipts_with_replica_ids {
self.peer.respond( self.peer.respond(
receipt.clone(), *receipt,
proto::JoinProjectResponse { proto::JoinProjectResponse {
variant: Some(proto::join_project_response::Variant::Accept( variant: Some(proto::join_project_response::Variant::Accept(
proto::join_project_response::Accept { proto::join_project_response::Accept {
@ -1711,7 +1711,7 @@ impl Server {
Ok(()) Ok(())
} }
pub(crate) async fn store<'a>(&'a self) -> StoreGuard<'a> { pub(crate) async fn store(&self) -> StoreGuard {
#[cfg(test)] #[cfg(test)]
tokio::task::yield_now().await; tokio::task::yield_now().await;
let guard = self.store.lock().await; let guard = self.store.lock().await;
@ -1796,7 +1796,7 @@ impl Header for ProtocolVersion {
{ {
let version = values let version = values
.next() .next()
.ok_or_else(|| axum::headers::Error::invalid())? .ok_or_else(axum::headers::Error::invalid)?
.to_str() .to_str()
.map_err(|_| axum::headers::Error::invalid())? .map_err(|_| axum::headers::Error::invalid())?
.parse() .parse()

View File

@ -159,8 +159,10 @@ impl Store {
let connection_projects = mem::take(&mut connection.projects); let connection_projects = mem::take(&mut connection.projects);
let connection_channels = mem::take(&mut connection.channels); let connection_channels = mem::take(&mut connection.channels);
let mut result = RemovedConnectionState::default(); let mut result = RemovedConnectionState {
result.user_id = user_id; user_id,
..Default::default()
};
// Leave all channels. // Leave all channels.
for channel_id in connection_channels { for channel_id in connection_channels {
@ -223,10 +225,10 @@ impl Store {
.user_id) .user_id)
} }
pub fn connection_ids_for_user<'a>( pub fn connection_ids_for_user(
&'a self, &self,
user_id: UserId, user_id: UserId,
) -> impl 'a + Iterator<Item = ConnectionId> { ) -> impl Iterator<Item = ConnectionId> + '_ {
self.connections_by_user_id self.connections_by_user_id
.get(&user_id) .get(&user_id)
.into_iter() .into_iter()
@ -425,14 +427,14 @@ impl Store {
} }
for guest_connection in project.guests.keys() { for guest_connection in project.guests.keys() {
if let Some(connection) = self.connections.get_mut(&guest_connection) { if let Some(connection) = self.connections.get_mut(guest_connection) {
connection.projects.remove(&project_id); connection.projects.remove(&project_id);
} }
} }
for requester_user_id in project.join_requests.keys() { for requester_user_id in project.join_requests.keys() {
if let Some(requester_connection_ids) = if let Some(requester_connection_ids) =
self.connections_by_user_id.get_mut(&requester_user_id) self.connections_by_user_id.get_mut(requester_user_id)
{ {
for requester_connection_id in requester_connection_ids.iter() { for requester_connection_id in requester_connection_ids.iter() {
if let Some(requester_connection) = if let Some(requester_connection) =
@ -544,6 +546,7 @@ impl Store {
Some(receipts) Some(receipts)
} }
#[allow(clippy::type_complexity)]
pub fn accept_join_project_request( pub fn accept_join_project_request(
&mut self, &mut self,
responder_connection_id: ConnectionId, responder_connection_id: ConnectionId,
@ -638,6 +641,7 @@ impl Store {
}) })
} }
#[allow(clippy::too_many_arguments)]
pub fn update_worktree( pub fn update_worktree(
&mut self, &mut self,
connection_id: ConnectionId, connection_id: ConnectionId,
@ -660,7 +664,7 @@ impl Store {
worktree.root_name = worktree_root_name.to_string(); worktree.root_name = worktree_root_name.to_string();
for entry_id in removed_entries { for entry_id in removed_entries {
worktree.entries.remove(&entry_id); worktree.entries.remove(entry_id);
} }
for entry in updated_entries { for entry in updated_entries {
@ -760,7 +764,7 @@ impl Store {
pub fn check_invariants(&self) { pub fn check_invariants(&self) {
for (connection_id, connection) in &self.connections { for (connection_id, connection) in &self.connections {
for project_id in &connection.projects { for project_id in &connection.projects {
let project = &self.projects.get(&project_id).unwrap(); let project = &self.projects.get(project_id).unwrap();
if project.host_connection_id != *connection_id { if project.host_connection_id != *connection_id {
assert!(project.guests.contains_key(connection_id)); assert!(project.guests.contains_key(connection_id));
} }

View File

@ -83,7 +83,9 @@ impl CommandPalette {
fn toggle(_: &mut Workspace, _: &Toggle, cx: &mut ViewContext<Workspace>) { fn toggle(_: &mut Workspace, _: &Toggle, cx: &mut ViewContext<Workspace>) {
let workspace = cx.handle(); let workspace = cx.handle();
let window_id = cx.window_id(); let window_id = cx.window_id();
let focused_view_id = cx.focused_view_id(window_id).unwrap_or(workspace.id()); let focused_view_id = cx
.focused_view_id(window_id)
.unwrap_or_else(|| workspace.id());
cx.as_mut().defer(move |cx| { cx.as_mut().defer(move |cx| {
let this = cx.add_view(workspace.clone(), |cx| Self::new(focused_view_id, cx)); let this = cx.add_view(workspace.clone(), |cx| Self::new(focused_view_id, cx));

View File

@ -111,7 +111,7 @@ impl PickerDelegate for ContactFinder {
) -> ElementBox { ) -> ElementBox {
let theme = &cx.global::<Settings>().theme; let theme = &cx.global::<Settings>().theme;
let user = &self.potential_contacts[ix]; let user = &self.potential_contacts[ix];
let request_status = self.user_store.read(cx).contact_request_status(&user); let request_status = self.user_store.read(cx).contact_request_status(user);
let icon_path = match request_status { let icon_path = match request_status {
ContactRequestStatus::None | ContactRequestStatus::RequestReceived => { ContactRequestStatus::None | ContactRequestStatus::RequestReceived => {
@ -121,7 +121,7 @@ impl PickerDelegate for ContactFinder {
"icons/x_mark_8.svg" "icons/x_mark_8.svg"
} }
}; };
let button_style = if self.user_store.read(cx).is_contact_request_pending(&user) { let button_style = if self.user_store.read(cx).is_contact_request_pending(user) {
&theme.contact_finder.disabled_contact_button &theme.contact_finder.disabled_contact_button
} else { } else {
&theme.contact_finder.contact_button &theme.contact_finder.contact_button

View File

@ -131,9 +131,9 @@ impl ContactsPanel {
move |_, cx| { move |_, cx| {
if let Some(workspace_handle) = workspace.upgrade(cx) { if let Some(workspace_handle) = workspace.upgrade(cx) {
cx.subscribe(&workspace_handle.read(cx).project().clone(), { cx.subscribe(&workspace_handle.read(cx).project().clone(), {
let workspace = workspace.clone(); let workspace = workspace;
move |_, project, event, cx| match event { move |_, project, event, cx| {
project::Event::ContactRequestedJoin(user) => { if let project::Event::ContactRequestedJoin(user) = event {
if let Some(workspace) = workspace.upgrade(cx) { if let Some(workspace) = workspace.upgrade(cx) {
workspace.update(cx, |workspace, cx| { workspace.update(cx, |workspace, cx| {
workspace.show_notification(user.id as usize, cx, |cx| { workspace.show_notification(user.id as usize, cx, |cx| {
@ -148,7 +148,6 @@ impl ContactsPanel {
}); });
} }
} }
_ => {}
} }
}) })
.detach(); .detach();
@ -161,17 +160,16 @@ impl ContactsPanel {
cx.subscribe(&user_store, move |_, user_store, event, cx| { cx.subscribe(&user_store, move |_, user_store, event, cx| {
if let Some(workspace) = workspace.upgrade(cx) { if let Some(workspace) = workspace.upgrade(cx) {
workspace.update(cx, |workspace, cx| match event { workspace.update(cx, |workspace, cx| {
client::Event::Contact { user, kind } => match kind { if let client::Event::Contact { user, kind } = event {
ContactEventKind::Requested | ContactEventKind::Accepted => workspace if let ContactEventKind::Requested | ContactEventKind::Accepted = kind {
.show_notification(user.id as usize, cx, |cx| { workspace.show_notification(user.id as usize, cx, |cx| {
cx.add_view(|cx| { cx.add_view(|cx| {
ContactNotification::new(user.clone(), *kind, user_store, cx) ContactNotification::new(user.clone(), *kind, user_store, cx)
}) })
}), })
_ => {} }
}, }
_ => {}
}); });
} }
@ -188,7 +186,7 @@ impl ContactsPanel {
match &this.entries[ix] { match &this.entries[ix] {
ContactEntry::Header(section) => { ContactEntry::Header(section) => {
let is_collapsed = this.collapsed_sections.contains(&section); let is_collapsed = this.collapsed_sections.contains(section);
Self::render_header( Self::render_header(
*section, *section,
&theme.contacts_panel, &theme.contacts_panel,
@ -229,7 +227,7 @@ impl ContactsPanel {
contact.clone(), contact.clone(),
current_user_id, current_user_id,
*project_ix, *project_ix,
open_project.clone(), *open_project,
&theme.contacts_panel, &theme.contacts_panel,
&theme.tooltip, &theme.tooltip,
is_last_project_for_contact, is_last_project_for_contact,
@ -238,7 +236,7 @@ impl ContactsPanel {
) )
} }
ContactEntry::OfflineProject(project) => Self::render_offline_project( ContactEntry::OfflineProject(project) => Self::render_offline_project(
project.clone(), *project,
&theme.contacts_panel, &theme.contacts_panel,
&theme.tooltip, &theme.tooltip,
is_selected, is_selected,
@ -345,6 +343,7 @@ impl ContactsPanel {
.boxed() .boxed()
} }
#[allow(clippy::too_many_arguments)]
fn render_project( fn render_project(
contact: Arc<Contact>, contact: Arc<Contact>,
current_user_id: Option<u64>, current_user_id: Option<u64>,
@ -370,7 +369,7 @@ impl ContactsPanel {
.or(theme.contact_avatar.height) .or(theme.contact_avatar.height)
.unwrap_or(0.); .unwrap_or(0.);
let row = &theme.project_row.default; let row = &theme.project_row.default;
let tree_branch = theme.tree_branch.clone(); let tree_branch = theme.tree_branch;
let line_height = row.name.text.line_height(font_cache); let line_height = row.name.text.line_height(font_cache);
let cap_height = row.name.text.cap_height(font_cache); let cap_height = row.name.text.cap_height(font_cache);
let baseline_offset = let baseline_offset =
@ -641,7 +640,7 @@ impl ContactsPanel {
let button_style = if is_contact_request_pending { let button_style = if is_contact_request_pending {
&theme.disabled_button &theme.disabled_button
} else { } else {
&theme.contact_button.style_for(mouse_state, false) theme.contact_button.style_for(mouse_state, false)
}; };
render_icon_button(button_style, "icons/x_mark_8.svg") render_icon_button(button_style, "icons/x_mark_8.svg")
.aligned() .aligned()
@ -663,7 +662,7 @@ impl ContactsPanel {
let button_style = if is_contact_request_pending { let button_style = if is_contact_request_pending {
&theme.disabled_button &theme.disabled_button
} else { } else {
&theme.contact_button.style_for(mouse_state, false) theme.contact_button.style_for(mouse_state, false)
}; };
render_icon_button(button_style, "icons/check_8.svg") render_icon_button(button_style, "icons/check_8.svg")
.aligned() .aligned()
@ -685,7 +684,7 @@ impl ContactsPanel {
let button_style = if is_contact_request_pending { let button_style = if is_contact_request_pending {
&theme.disabled_button &theme.disabled_button
} else { } else {
&theme.contact_button.style_for(mouse_state, false) theme.contact_button.style_for(mouse_state, false)
}; };
render_icon_button(button_style, "icons/x_mark_8.svg") render_icon_button(button_style, "icons/x_mark_8.svg")
.aligned() .aligned()
@ -1224,7 +1223,7 @@ mod tests {
let client = Client::new(http_client.clone()); let client = Client::new(http_client.clone());
let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http_client, cx)); let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http_client, cx));
let project_store = cx.add_model(|_| ProjectStore::new(project::Db::open_fake())); let project_store = cx.add_model(|_| ProjectStore::new(project::Db::open_fake()));
let server = FakeServer::for_client(current_user_id, &client, &cx).await; let server = FakeServer::for_client(current_user_id, &client, cx).await;
let fs = FakeFs::new(cx.background()); let fs = FakeFs::new(cx.background());
fs.insert_tree("/private_dir", json!({ "one.rs": "" })) fs.insert_tree("/private_dir", json!({ "one.rs": "" }))
.await; .await;

View File

@ -365,7 +365,7 @@ impl ProjectDiagnosticsEditor {
if !diagnostic.message.is_empty() { if !diagnostic.message.is_empty() {
group_state.block_count += 1; group_state.block_count += 1;
blocks_to_add.push(BlockProperties { blocks_to_add.push(BlockProperties {
position: (excerpt_id.clone(), entry.range.start.clone()), position: (excerpt_id.clone(), entry.range.start),
height: diagnostic.message.matches('\n').count() as u8 + 1, height: diagnostic.message.matches('\n').count() as u8 + 1,
style: BlockStyle::Fixed, style: BlockStyle::Fixed,
render: diagnostic_block_renderer(diagnostic, true), render: diagnostic_block_renderer(diagnostic, true),
@ -460,7 +460,7 @@ impl ProjectDiagnosticsEditor {
for selection in &mut selections { for selection in &mut selections {
if let Some(new_excerpt_id) = new_excerpt_ids_by_selection_id.get(&selection.id) { if let Some(new_excerpt_id) = new_excerpt_ids_by_selection_id.get(&selection.id) {
let group_ix = match groups.binary_search_by(|probe| { let group_ix = match groups.binary_search_by(|probe| {
probe.excerpts.last().unwrap().cmp(&new_excerpt_id) probe.excerpts.last().unwrap().cmp(new_excerpt_id)
}) { }) {
Ok(ix) | Err(ix) => ix, Ok(ix) | Err(ix) => ix,
}; };
@ -468,7 +468,7 @@ impl ProjectDiagnosticsEditor {
let offset = excerpts_snapshot let offset = excerpts_snapshot
.anchor_in_excerpt( .anchor_in_excerpt(
group.excerpts[group.primary_excerpt_ix].clone(), group.excerpts[group.primary_excerpt_ix].clone(),
group.primary_diagnostic.range.start.clone(), group.primary_diagnostic.range.start,
) )
.to_offset(&excerpts_snapshot); .to_offset(&excerpts_snapshot);
selection.start = offset; selection.start = offset;
@ -486,11 +486,9 @@ impl ProjectDiagnosticsEditor {
if self.editor.is_focused(cx) { if self.editor.is_focused(cx) {
cx.focus_self(); cx.focus_self();
} }
} else { } else if cx.handle().is_focused(cx) {
if cx.handle().is_focused(cx) {
cx.focus(&self.editor); cx.focus(&self.editor);
} }
}
cx.notify(); cx.notify();
} }
@ -725,12 +723,12 @@ fn compare_diagnostics<L: language::ToOffset, R: language::ToOffset>(
) -> Ordering { ) -> Ordering {
lhs.range lhs.range
.start .start
.to_offset(&snapshot) .to_offset(snapshot)
.cmp(&rhs.range.start.to_offset(snapshot)) .cmp(&rhs.range.start.to_offset(snapshot))
.then_with(|| { .then_with(|| {
lhs.range lhs.range
.end .end
.to_offset(&snapshot) .to_offset(snapshot)
.cmp(&rhs.range.end.to_offset(snapshot)) .cmp(&rhs.range.end.to_offset(snapshot))
}) })
.then_with(|| lhs.diagnostic.message.cmp(&rhs.diagnostic.message)) .then_with(|| lhs.diagnostic.message.cmp(&rhs.diagnostic.message))
@ -873,7 +871,7 @@ mod tests {
ProjectDiagnosticsEditor::new(project.clone(), workspace.downgrade(), cx) ProjectDiagnosticsEditor::new(project.clone(), workspace.downgrade(), cx)
}); });
view.next_notification(&cx).await; view.next_notification(cx).await;
view.update(cx, |view, cx| { view.update(cx, |view, cx| {
assert_eq!( assert_eq!(
editor_blocks(&view.editor, cx), editor_blocks(&view.editor, cx),
@ -960,7 +958,7 @@ mod tests {
project.disk_based_diagnostics_finished(0, cx); project.disk_based_diagnostics_finished(0, cx);
}); });
view.next_notification(&cx).await; view.next_notification(cx).await;
view.update(cx, |view, cx| { view.update(cx, |view, cx| {
assert_eq!( assert_eq!(
editor_blocks(&view.editor, cx), editor_blocks(&view.editor, cx),
@ -1074,7 +1072,7 @@ mod tests {
project.disk_based_diagnostics_finished(0, cx); project.disk_based_diagnostics_finished(0, cx);
}); });
view.next_notification(&cx).await; view.next_notification(cx).await;
view.update(cx, |view, cx| { view.update(cx, |view, cx| {
assert_eq!( assert_eq!(
editor_blocks(&view.editor, cx), editor_blocks(&view.editor, cx),

View File

@ -253,7 +253,7 @@ impl DisplaySnapshot {
self.buffer_snapshot.len() == 0 self.buffer_snapshot.len() == 0
} }
pub fn buffer_rows<'a>(&'a self, start_row: u32) -> DisplayBufferRows<'a> { pub fn buffer_rows(&self, start_row: u32) -> DisplayBufferRows {
self.blocks_snapshot.buffer_rows(start_row) self.blocks_snapshot.buffer_rows(start_row)
} }
@ -313,7 +313,7 @@ impl DisplaySnapshot {
fn point_to_display_point(&self, point: Point, bias: Bias) -> DisplayPoint { fn point_to_display_point(&self, point: Point, bias: Bias) -> DisplayPoint {
let fold_point = self.folds_snapshot.to_fold_point(point, bias); let fold_point = self.folds_snapshot.to_fold_point(point, bias);
let tab_point = self.tabs_snapshot.to_tab_point(fold_point); let tab_point = self.tabs_snapshot.to_tab_point(fold_point);
let wrap_point = self.wraps_snapshot.from_tab_point(tab_point); let wrap_point = self.wraps_snapshot.tab_point_to_wrap_point(tab_point);
let block_point = self.blocks_snapshot.to_block_point(wrap_point); let block_point = self.blocks_snapshot.to_block_point(wrap_point);
DisplayPoint(block_point) DisplayPoint(block_point)
} }
@ -336,16 +336,12 @@ impl DisplaySnapshot {
.map(|h| h.text) .map(|h| h.text)
} }
pub fn chunks<'a>( pub fn chunks(&self, display_rows: Range<u32>, language_aware: bool) -> DisplayChunks<'_> {
&'a self,
display_rows: Range<u32>,
language_aware: bool,
) -> DisplayChunks<'a> {
self.blocks_snapshot self.blocks_snapshot
.chunks(display_rows, language_aware, Some(&self.text_highlights)) .chunks(display_rows, language_aware, Some(&self.text_highlights))
} }
pub fn chars_at<'a>(&'a self, point: DisplayPoint) -> impl Iterator<Item = char> + 'a { pub fn chars_at(&self, point: DisplayPoint) -> impl Iterator<Item = char> + '_ {
let mut column = 0; let mut column = 0;
let mut chars = self.text_chunks(point.row()).flat_map(str::chars); let mut chars = self.text_chunks(point.row()).flat_map(str::chars);
while column < point.column() { while column < point.column() {
@ -372,15 +368,15 @@ impl DisplaySnapshot {
} }
pub fn column_from_chars(&self, display_row: u32, char_count: u32) -> u32 { pub fn column_from_chars(&self, display_row: u32, char_count: u32) -> u32 {
let mut count = 0;
let mut column = 0; let mut column = 0;
for c in self.chars_at(DisplayPoint::new(display_row, 0)) {
if c == '\n' || count >= char_count { for (count, c) in self.chars_at(DisplayPoint::new(display_row, 0)).enumerate() {
if c == '\n' || count >= char_count as usize {
break; break;
} }
count += 1;
column += c.len_utf8() as u32; column += c.len_utf8() as u32;
} }
column column
} }
@ -401,20 +397,17 @@ impl DisplaySnapshot {
DisplayPoint(point) DisplayPoint(point)
} }
pub fn folds_in_range<'a, T>( pub fn folds_in_range<T>(&self, range: Range<T>) -> impl Iterator<Item = &Range<Anchor>>
&'a self,
range: Range<T>,
) -> impl Iterator<Item = &'a Range<Anchor>>
where where
T: ToOffset, T: ToOffset,
{ {
self.folds_snapshot.folds_in_range(range) self.folds_snapshot.folds_in_range(range)
} }
pub fn blocks_in_range<'a>( pub fn blocks_in_range(
&'a self, &self,
rows: Range<u32>, rows: Range<u32>,
) -> impl Iterator<Item = (u32, &'a TransformBlock)> { ) -> impl Iterator<Item = (u32, &TransformBlock)> {
self.blocks_snapshot.blocks_in_range(rows) self.blocks_snapshot.blocks_in_range(rows)
} }
@ -1015,7 +1008,7 @@ pub mod tests {
}); });
let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx)); let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
buffer.condition(&cx, |buf, _| !buf.is_parsing()).await; buffer.condition(cx, |buf, _| !buf.is_parsing()).await;
let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
let font_cache = cx.font_cache(); let font_cache = cx.font_cache();
@ -1102,7 +1095,7 @@ pub mod tests {
cx.update(|cx| cx.set_global(Settings::test(cx))); cx.update(|cx| cx.set_global(Settings::test(cx)));
let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx)); let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
buffer.condition(&cx, |buf, _| !buf.is_parsing()).await; buffer.condition(cx, |buf, _| !buf.is_parsing()).await;
let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
let font_cache = cx.font_cache(); let font_cache = cx.font_cache();
@ -1173,7 +1166,7 @@ pub mod tests {
let (text, highlighted_ranges) = marked_text_ranges(r#"constˇ «a»: B = "c «d»""#, false); let (text, highlighted_ranges) = marked_text_ranges(r#"constˇ «a»: B = "c «d»""#, false);
let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx)); let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
buffer.condition(&cx, |buf, _| !buf.is_parsing()).await; buffer.condition(cx, |buf, _| !buf.is_parsing()).await;
let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
let buffer_snapshot = buffer.read_with(cx, |buffer, cx| buffer.snapshot(cx)); let buffer_snapshot = buffer.read_with(cx, |buffer, cx| buffer.snapshot(cx));

View File

@ -20,7 +20,7 @@ use std::{
use sum_tree::{Bias, SumTree}; use sum_tree::{Bias, SumTree};
use text::{Edit, Point}; use text::{Edit, Point};
const NEWLINES: &'static [u8] = &[b'\n'; u8::MAX as usize]; const NEWLINES: &[u8] = &[b'\n'; u8::MAX as usize];
pub struct BlockMap { pub struct BlockMap {
next_block_id: AtomicUsize, next_block_id: AtomicUsize,
@ -102,6 +102,7 @@ struct Transform {
block: Option<TransformBlock>, block: Option<TransformBlock>,
} }
#[allow(clippy::large_enum_variant)]
#[derive(Clone)] #[derive(Clone)]
pub enum TransformBlock { pub enum TransformBlock {
Custom(Arc<Block>), Custom(Arc<Block>),
@ -317,7 +318,7 @@ impl BlockMap {
let start_block_ix = match self.blocks[last_block_ix..].binary_search_by(|probe| { let start_block_ix = match self.blocks[last_block_ix..].binary_search_by(|probe| {
probe probe
.position .position
.to_point(&buffer) .to_point(buffer)
.cmp(&new_buffer_start) .cmp(&new_buffer_start)
.then(Ordering::Greater) .then(Ordering::Greater)
}) { }) {
@ -335,7 +336,7 @@ impl BlockMap {
match self.blocks[start_block_ix..].binary_search_by(|probe| { match self.blocks[start_block_ix..].binary_search_by(|probe| {
probe probe
.position .position
.to_point(&buffer) .to_point(buffer)
.cmp(&new_buffer_end) .cmp(&new_buffer_end)
.then(Ordering::Greater) .then(Ordering::Greater)
}) { }) {
@ -349,14 +350,14 @@ impl BlockMap {
self.blocks[start_block_ix..end_block_ix] self.blocks[start_block_ix..end_block_ix]
.iter() .iter()
.map(|block| { .map(|block| {
let mut position = block.position.to_point(&buffer); let mut position = block.position.to_point(buffer);
match block.disposition { match block.disposition {
BlockDisposition::Above => position.column = 0, BlockDisposition::Above => position.column = 0,
BlockDisposition::Below => { BlockDisposition::Below => {
position.column = buffer.line_len(position.row) position.column = buffer.line_len(position.row)
} }
} }
let position = wrap_snapshot.from_point(position, Bias::Left); let position = wrap_snapshot.make_wrap_point(position, Bias::Left);
(position.row(), TransformBlock::Custom(block.clone())) (position.row(), TransformBlock::Custom(block.clone()))
}), }),
); );
@ -366,7 +367,7 @@ impl BlockMap {
.map(|excerpt_boundary| { .map(|excerpt_boundary| {
( (
wrap_snapshot wrap_snapshot
.from_point(Point::new(excerpt_boundary.row, 0), Bias::Left) .make_wrap_point(Point::new(excerpt_boundary.row, 0), Bias::Left)
.row(), .row(),
TransformBlock::ExcerptHeader { TransformBlock::ExcerptHeader {
key: excerpt_boundary.key, key: excerpt_boundary.key,
@ -385,7 +386,7 @@ impl BlockMap {
// Place excerpt headers above custom blocks on the same row. // Place excerpt headers above custom blocks on the same row.
blocks_in_edit.sort_unstable_by(|(row_a, block_a), (row_b, block_b)| { blocks_in_edit.sort_unstable_by(|(row_a, block_a), (row_b, block_b)| {
row_a.cmp(&row_b).then_with(|| match (block_a, block_b) { row_a.cmp(row_b).then_with(|| match (block_a, block_b) {
( (
TransformBlock::ExcerptHeader { .. }, TransformBlock::ExcerptHeader { .. },
TransformBlock::ExcerptHeader { .. }, TransformBlock::ExcerptHeader { .. },
@ -498,9 +499,9 @@ impl<'a> BlockMapWriter<'a> {
ids.push(id); ids.push(id);
let position = block.position; let position = block.position;
let point = position.to_point(&buffer); let point = position.to_point(buffer);
let wrap_row = wrap_snapshot let wrap_row = wrap_snapshot
.from_point(Point::new(point.row, 0), Bias::Left) .make_wrap_point(Point::new(point.row, 0), Bias::Left)
.row(); .row();
let start_row = wrap_snapshot.prev_row_boundary(WrapPoint::new(wrap_row, 0)); let start_row = wrap_snapshot.prev_row_boundary(WrapPoint::new(wrap_row, 0));
let end_row = wrap_snapshot let end_row = wrap_snapshot
@ -510,7 +511,7 @@ impl<'a> BlockMapWriter<'a> {
let block_ix = match self let block_ix = match self
.0 .0
.blocks .blocks
.binary_search_by(|probe| probe.position.cmp(&position, &buffer)) .binary_search_by(|probe| probe.position.cmp(&position, buffer))
{ {
Ok(ix) | Err(ix) => ix, Ok(ix) | Err(ix) => ix,
}; };
@ -543,11 +544,11 @@ impl<'a> BlockMapWriter<'a> {
let mut last_block_buffer_row = None; let mut last_block_buffer_row = None;
self.0.blocks.retain(|block| { self.0.blocks.retain(|block| {
if block_ids.contains(&block.id) { if block_ids.contains(&block.id) {
let buffer_row = block.position.to_point(&buffer).row; let buffer_row = block.position.to_point(buffer).row;
if last_block_buffer_row != Some(buffer_row) { if last_block_buffer_row != Some(buffer_row) {
last_block_buffer_row = Some(buffer_row); last_block_buffer_row = Some(buffer_row);
let wrap_row = wrap_snapshot let wrap_row = wrap_snapshot
.from_point(Point::new(buffer_row, 0), Bias::Left) .make_wrap_point(Point::new(buffer_row, 0), Bias::Left)
.row(); .row();
let start_row = wrap_snapshot.prev_row_boundary(WrapPoint::new(wrap_row, 0)); let start_row = wrap_snapshot.prev_row_boundary(WrapPoint::new(wrap_row, 0));
let end_row = wrap_snapshot let end_row = wrap_snapshot
@ -620,7 +621,7 @@ impl BlockSnapshot {
} }
} }
pub fn buffer_rows<'a>(&'a self, start_row: u32) -> BlockBufferRows<'a> { pub fn buffer_rows(&self, start_row: u32) -> BlockBufferRows {
let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>(); let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>();
cursor.seek(&BlockRow(start_row), Bias::Right, &()); cursor.seek(&BlockRow(start_row), Bias::Right, &());
let (output_start, input_start) = cursor.start(); let (output_start, input_start) = cursor.start();
@ -638,10 +639,10 @@ impl BlockSnapshot {
} }
} }
pub fn blocks_in_range<'a>( pub fn blocks_in_range(
&'a self, &self,
rows: Range<u32>, rows: Range<u32>,
) -> impl Iterator<Item = (u32, &'a TransformBlock)> { ) -> impl Iterator<Item = (u32, &TransformBlock)> {
let mut cursor = self.transforms.cursor::<BlockRow>(); let mut cursor = self.transforms.cursor::<BlockRow>();
cursor.seek(&BlockRow(rows.start), Bias::Right, &()); cursor.seek(&BlockRow(rows.start), Bias::Right, &());
std::iter::from_fn(move || { std::iter::from_fn(move || {
@ -1025,7 +1026,7 @@ mod tests {
let buffer_snapshot = buffer.read(cx).snapshot(cx); let buffer_snapshot = buffer.read(cx).snapshot(cx);
let subscription = buffer.update(cx, |buffer, _| buffer.subscribe()); let subscription = buffer.update(cx, |buffer, _| buffer.subscribe());
let (fold_map, folds_snapshot) = FoldMap::new(buffer_snapshot.clone()); let (fold_map, folds_snapshot) = FoldMap::new(buffer_snapshot.clone());
let (tab_map, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), 1.try_into().unwrap()); let (tab_map, tabs_snapshot) = TabMap::new(folds_snapshot, 1.try_into().unwrap());
let (wrap_map, wraps_snapshot) = WrapMap::new(tabs_snapshot, font_id, 14.0, None, cx); let (wrap_map, wraps_snapshot) = WrapMap::new(tabs_snapshot, font_id, 14.0, None, cx);
let mut block_map = BlockMap::new(wraps_snapshot.clone(), 1, 1); let mut block_map = BlockMap::new(wraps_snapshot.clone(), 1, 1);
@ -1194,7 +1195,7 @@ mod tests {
let buffer = MultiBuffer::build_simple(text, cx); let buffer = MultiBuffer::build_simple(text, cx);
let buffer_snapshot = buffer.read(cx).snapshot(cx); let buffer_snapshot = buffer.read(cx).snapshot(cx);
let (_, folds_snapshot) = FoldMap::new(buffer_snapshot.clone()); let (_, folds_snapshot) = FoldMap::new(buffer_snapshot.clone());
let (_, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), 1.try_into().unwrap()); let (_, tabs_snapshot) = TabMap::new(folds_snapshot, 1.try_into().unwrap());
let (_, wraps_snapshot) = WrapMap::new(tabs_snapshot, font_id, 14.0, Some(60.), cx); let (_, wraps_snapshot) = WrapMap::new(tabs_snapshot, font_id, 14.0, Some(60.), cx);
let mut block_map = BlockMap::new(wraps_snapshot.clone(), 1, 1); let mut block_map = BlockMap::new(wraps_snapshot.clone(), 1, 1);
@ -1262,11 +1263,11 @@ mod tests {
let mut buffer_snapshot = buffer.read(cx).snapshot(cx); let mut buffer_snapshot = buffer.read(cx).snapshot(cx);
let (fold_map, folds_snapshot) = FoldMap::new(buffer_snapshot.clone()); let (fold_map, folds_snapshot) = FoldMap::new(buffer_snapshot.clone());
let (tab_map, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), tab_size); let (tab_map, tabs_snapshot) = TabMap::new(folds_snapshot, tab_size);
let (wrap_map, wraps_snapshot) = let (wrap_map, wraps_snapshot) =
WrapMap::new(tabs_snapshot, font_id, font_size, wrap_width, cx); WrapMap::new(tabs_snapshot, font_id, font_size, wrap_width, cx);
let mut block_map = BlockMap::new( let mut block_map = BlockMap::new(
wraps_snapshot.clone(), wraps_snapshot,
buffer_start_header_height, buffer_start_header_height,
excerpt_header_height, excerpt_header_height,
); );
@ -1383,7 +1384,7 @@ mod tests {
position.column = buffer_snapshot.line_len(position.row); position.column = buffer_snapshot.line_len(position.row);
} }
}; };
let row = wraps_snapshot.from_point(position, Bias::Left).row(); let row = wraps_snapshot.make_wrap_point(position, Bias::Left).row();
( (
row, row,
ExpectedBlock::Custom { ExpectedBlock::Custom {
@ -1396,7 +1397,7 @@ mod tests {
expected_blocks.extend(buffer_snapshot.excerpt_boundaries_in_range(0..).map( expected_blocks.extend(buffer_snapshot.excerpt_boundaries_in_range(0..).map(
|boundary| { |boundary| {
let position = let position =
wraps_snapshot.from_point(Point::new(boundary.row, 0), Bias::Left); wraps_snapshot.make_wrap_point(Point::new(boundary.row, 0), Bias::Left);
( (
position.row(), position.row(),
ExpectedBlock::ExcerptHeader { ExpectedBlock::ExcerptHeader {

View File

@ -41,27 +41,27 @@ impl FoldPoint {
&mut self.0.column &mut self.0.column
} }
pub fn to_buffer_point(&self, snapshot: &FoldSnapshot) -> Point { pub fn to_buffer_point(self, snapshot: &FoldSnapshot) -> Point {
let mut cursor = snapshot.transforms.cursor::<(FoldPoint, Point)>(); let mut cursor = snapshot.transforms.cursor::<(FoldPoint, Point)>();
cursor.seek(self, Bias::Right, &()); cursor.seek(&self, Bias::Right, &());
let overshoot = self.0 - cursor.start().0 .0; let overshoot = self.0 - cursor.start().0 .0;
cursor.start().1 + overshoot cursor.start().1 + overshoot
} }
pub fn to_buffer_offset(&self, snapshot: &FoldSnapshot) -> usize { pub fn to_buffer_offset(self, snapshot: &FoldSnapshot) -> usize {
let mut cursor = snapshot.transforms.cursor::<(FoldPoint, Point)>(); let mut cursor = snapshot.transforms.cursor::<(FoldPoint, Point)>();
cursor.seek(self, Bias::Right, &()); cursor.seek(&self, Bias::Right, &());
let overshoot = self.0 - cursor.start().0 .0; let overshoot = self.0 - cursor.start().0 .0;
snapshot snapshot
.buffer_snapshot .buffer_snapshot
.point_to_offset(cursor.start().1 + overshoot) .point_to_offset(cursor.start().1 + overshoot)
} }
pub fn to_offset(&self, snapshot: &FoldSnapshot) -> FoldOffset { pub fn to_offset(self, snapshot: &FoldSnapshot) -> FoldOffset {
let mut cursor = snapshot let mut cursor = snapshot
.transforms .transforms
.cursor::<(FoldPoint, TransformSummary)>(); .cursor::<(FoldPoint, TransformSummary)>();
cursor.seek(self, Bias::Right, &()); cursor.seek(&self, Bias::Right, &());
let overshoot = self.0 - cursor.start().1.output.lines; let overshoot = self.0 - cursor.start().1.output.lines;
let mut offset = cursor.start().1.output.len; let mut offset = cursor.start().1.output.len;
if !overshoot.is_zero() { if !overshoot.is_zero() {
@ -600,10 +600,7 @@ impl FoldSnapshot {
self.transforms.summary().output.longest_row self.transforms.summary().output.longest_row
} }
pub fn folds_in_range<'a, T>( pub fn folds_in_range<T>(&self, range: Range<T>) -> impl Iterator<Item = &Range<Anchor>>
&'a self,
range: Range<T>,
) -> impl Iterator<Item = &'a Range<Anchor>>
where where
T: ToOffset, T: ToOffset,
{ {
@ -689,7 +686,7 @@ impl FoldSnapshot {
let ranges = &highlights.1; let ranges = &highlights.1;
let start_ix = match ranges.binary_search_by(|probe| { let start_ix = match ranges.binary_search_by(|probe| {
let cmp = probe.end.cmp(&transform_start, &self.buffer_snapshot()); let cmp = probe.end.cmp(&transform_start, self.buffer_snapshot());
if cmp.is_gt() { if cmp.is_gt() {
Ordering::Greater Ordering::Greater
} else { } else {
@ -1040,11 +1037,7 @@ impl<'a> Iterator for FoldChunks<'a> {
return None; return None;
} }
let transform = if let Some(item) = self.transform_cursor.item() { let transform = self.transform_cursor.item()?;
item
} else {
return None;
};
// If we're in a fold, then return the fold's display text and // If we're in a fold, then return the fold's display text and
// advance the transform and buffer cursors to the end of the fold. // advance the transform and buffer cursors to the end of the fold.
@ -1150,11 +1143,11 @@ impl Ord for HighlightEndpoint {
pub struct FoldOffset(pub usize); pub struct FoldOffset(pub usize);
impl FoldOffset { impl FoldOffset {
pub fn to_point(&self, snapshot: &FoldSnapshot) -> FoldPoint { pub fn to_point(self, snapshot: &FoldSnapshot) -> FoldPoint {
let mut cursor = snapshot let mut cursor = snapshot
.transforms .transforms
.cursor::<(FoldOffset, TransformSummary)>(); .cursor::<(FoldOffset, TransformSummary)>();
cursor.seek(self, Bias::Right, &()); cursor.seek(&self, Bias::Right, &());
let overshoot = if cursor.item().map_or(true, |t| t.is_fold()) { let overshoot = if cursor.item().map_or(true, |t| t.is_fold()) {
Point::new(0, (self.0 - cursor.start().0 .0) as u32) Point::new(0, (self.0 - cursor.start().0 .0) as u32)
} else { } else {
@ -1214,7 +1207,7 @@ mod tests {
let buffer_snapshot = buffer.read(cx).snapshot(cx); let buffer_snapshot = buffer.read(cx).snapshot(cx);
let mut map = FoldMap::new(buffer_snapshot.clone()).0; let mut map = FoldMap::new(buffer_snapshot.clone()).0;
let (mut writer, _, _) = map.write(buffer_snapshot.clone(), vec![]); let (mut writer, _, _) = map.write(buffer_snapshot, vec![]);
let (snapshot2, edits) = writer.fold(vec![ let (snapshot2, edits) = writer.fold(vec![
Point::new(0, 2)..Point::new(2, 2), Point::new(0, 2)..Point::new(2, 2),
Point::new(2, 4)..Point::new(4, 1), Point::new(2, 4)..Point::new(4, 1),
@ -1245,8 +1238,7 @@ mod tests {
); );
buffer.snapshot(cx) buffer.snapshot(cx)
}); });
let (snapshot3, edits) = let (snapshot3, edits) = map.read(buffer_snapshot, subscription.consume().into_inner());
map.read(buffer_snapshot.clone(), subscription.consume().into_inner());
assert_eq!(snapshot3.text(), "123a…c123c…eeeee"); assert_eq!(snapshot3.text(), "123a…c123c…eeeee");
assert_eq!( assert_eq!(
edits, edits,
@ -1276,7 +1268,7 @@ mod tests {
let (mut writer, _, _) = map.write(buffer_snapshot.clone(), vec![]); let (mut writer, _, _) = map.write(buffer_snapshot.clone(), vec![]);
writer.unfold(Some(Point::new(0, 4)..Point::new(0, 4)), true); writer.unfold(Some(Point::new(0, 4)..Point::new(0, 4)), true);
let (snapshot6, _) = map.read(buffer_snapshot.clone(), vec![]); let (snapshot6, _) = map.read(buffer_snapshot, vec![]);
assert_eq!(snapshot6.text(), "123aaaaa\nbbbbbb\nccc123456eee"); assert_eq!(snapshot6.text(), "123aaaaa\nbbbbbb\nccc123456eee");
} }
@ -1314,7 +1306,7 @@ mod tests {
// Create two adjacent folds. // Create two adjacent folds.
let (mut writer, _, _) = map.write(buffer_snapshot.clone(), vec![]); let (mut writer, _, _) = map.write(buffer_snapshot.clone(), vec![]);
writer.fold(vec![0..2, 2..5]); writer.fold(vec![0..2, 2..5]);
let (snapshot, _) = map.read(buffer_snapshot.clone(), vec![]); let (snapshot, _) = map.read(buffer_snapshot, vec![]);
assert_eq!(snapshot.text(), "…fghijkl"); assert_eq!(snapshot.text(), "…fghijkl");
// Edit within one of the folds. // Edit within one of the folds.
@ -1322,8 +1314,7 @@ mod tests {
buffer.edit([(0..1, "12345")], None, cx); buffer.edit([(0..1, "12345")], None, cx);
buffer.snapshot(cx) buffer.snapshot(cx)
}); });
let (snapshot, _) = let (snapshot, _) = map.read(buffer_snapshot, subscription.consume().into_inner());
map.read(buffer_snapshot.clone(), subscription.consume().into_inner());
assert_eq!(snapshot.text(), "12345…fghijkl"); assert_eq!(snapshot.text(), "12345…fghijkl");
} }
} }
@ -1340,7 +1331,7 @@ mod tests {
Point::new(1, 2)..Point::new(3, 2), Point::new(1, 2)..Point::new(3, 2),
Point::new(3, 1)..Point::new(4, 1), Point::new(3, 1)..Point::new(4, 1),
]); ]);
let (snapshot, _) = map.read(buffer_snapshot.clone(), vec![]); let (snapshot, _) = map.read(buffer_snapshot, vec![]);
assert_eq!(snapshot.text(), "aa…eeeee"); assert_eq!(snapshot.text(), "aa…eeeee");
} }
@ -1357,14 +1348,14 @@ mod tests {
Point::new(0, 2)..Point::new(2, 2), Point::new(0, 2)..Point::new(2, 2),
Point::new(3, 1)..Point::new(4, 1), Point::new(3, 1)..Point::new(4, 1),
]); ]);
let (snapshot, _) = map.read(buffer_snapshot.clone(), vec![]); let (snapshot, _) = map.read(buffer_snapshot, vec![]);
assert_eq!(snapshot.text(), "aa…cccc\nd…eeeee"); assert_eq!(snapshot.text(), "aa…cccc\nd…eeeee");
let buffer_snapshot = buffer.update(cx, |buffer, cx| { let buffer_snapshot = buffer.update(cx, |buffer, cx| {
buffer.edit([(Point::new(2, 2)..Point::new(3, 1), "")], None, cx); buffer.edit([(Point::new(2, 2)..Point::new(3, 1), "")], None, cx);
buffer.snapshot(cx) buffer.snapshot(cx)
}); });
let (snapshot, _) = map.read(buffer_snapshot.clone(), subscription.consume().into_inner()); let (snapshot, _) = map.read(buffer_snapshot, subscription.consume().into_inner());
assert_eq!(snapshot.text(), "aa…eeeee"); assert_eq!(snapshot.text(), "aa…eeeee");
} }
@ -1661,7 +1652,7 @@ mod tests {
Point::new(3, 1)..Point::new(4, 1), Point::new(3, 1)..Point::new(4, 1),
]); ]);
let (snapshot, _) = map.read(buffer_snapshot.clone(), vec![]); let (snapshot, _) = map.read(buffer_snapshot, vec![]);
assert_eq!(snapshot.text(), "aa…cccc\nd…eeeee\nffffff\n"); assert_eq!(snapshot.text(), "aa…cccc\nd…eeeee\nffffff\n");
assert_eq!( assert_eq!(
snapshot.buffer_rows(0).collect::<Vec<_>>(), snapshot.buffer_rows(0).collect::<Vec<_>>(),

View File

@ -253,7 +253,7 @@ impl TabSnapshot {
) )
} }
pub fn from_point(&self, point: Point, bias: Bias) -> TabPoint { pub fn make_tab_point(&self, point: Point, bias: Bias) -> TabPoint {
self.to_tab_point(self.fold_snapshot.to_fold_point(point, bias)) self.to_tab_point(self.fold_snapshot.to_fold_point(point, bias))
} }
@ -290,7 +290,7 @@ impl TabSnapshot {
} }
fn collapse_tabs( fn collapse_tabs(
mut chars: impl Iterator<Item = char>, chars: impl Iterator<Item = char>,
column: usize, column: usize,
bias: Bias, bias: Bias,
tab_size: NonZeroU32, tab_size: NonZeroU32,
@ -298,7 +298,7 @@ impl TabSnapshot {
let mut expanded_bytes = 0; let mut expanded_bytes = 0;
let mut expanded_chars = 0; let mut expanded_chars = 0;
let mut collapsed_bytes = 0; let mut collapsed_bytes = 0;
while let Some(c) = chars.next() { for c in chars {
if expanded_bytes >= column { if expanded_bytes >= column {
break; break;
} }
@ -410,7 +410,7 @@ impl<'a> std::ops::AddAssign<&'a Self> for TextSummary {
} }
// Handles a tab width <= 16 // Handles a tab width <= 16
const SPACES: &'static str = " "; const SPACES: &str = " ";
pub struct TabChunks<'a> { pub struct TabChunks<'a> {
fold_chunks: fold_map::FoldChunks<'a>, fold_chunks: fold_map::FoldChunks<'a>,
@ -518,7 +518,7 @@ mod tests {
let (mut fold_map, _) = FoldMap::new(buffer_snapshot.clone()); let (mut fold_map, _) = FoldMap::new(buffer_snapshot.clone());
fold_map.randomly_mutate(&mut rng); fold_map.randomly_mutate(&mut rng);
let (folds_snapshot, _) = fold_map.read(buffer_snapshot.clone(), vec![]); let (folds_snapshot, _) = fold_map.read(buffer_snapshot, vec![]);
log::info!("FoldMap text: {:?}", folds_snapshot.text()); log::info!("FoldMap text: {:?}", folds_snapshot.text());
let (_, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), tab_size); let (_, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), tab_size);

View File

@ -285,7 +285,7 @@ impl WrapMap {
if tab_snapshot.version <= self.snapshot.tab_snapshot.version { if tab_snapshot.version <= self.snapshot.tab_snapshot.version {
to_remove_len += 1; to_remove_len += 1;
} else { } else {
let interpolated_edits = self.snapshot.interpolate(tab_snapshot.clone(), &edits); let interpolated_edits = self.snapshot.interpolate(tab_snapshot.clone(), edits);
self.edits_since_sync = self.edits_since_sync.compose(&interpolated_edits); self.edits_since_sync = self.edits_since_sync.compose(&interpolated_edits);
self.interpolated_edits = self.interpolated_edits.compose(&interpolated_edits); self.interpolated_edits = self.interpolated_edits.compose(&interpolated_edits);
} }
@ -394,7 +394,7 @@ impl WrapSnapshot {
new_rows: Range<u32>, new_rows: Range<u32>,
} }
let mut tab_edits_iter = tab_edits.into_iter().peekable(); let mut tab_edits_iter = tab_edits.iter().peekable();
let mut row_edits = Vec::new(); let mut row_edits = Vec::new();
while let Some(edit) = tab_edits_iter.next() { while let Some(edit) = tab_edits_iter.next() {
let mut row_edit = RowEdit { let mut row_edit = RowEdit {
@ -671,11 +671,11 @@ impl WrapSnapshot {
self.tab_snapshot.to_point(self.to_tab_point(point), bias) self.tab_snapshot.to_point(self.to_tab_point(point), bias)
} }
pub fn from_point(&self, point: Point, bias: Bias) -> WrapPoint { pub fn make_wrap_point(&self, point: Point, bias: Bias) -> WrapPoint {
self.from_tab_point(self.tab_snapshot.from_point(point, bias)) self.tab_point_to_wrap_point(self.tab_snapshot.make_tab_point(point, bias))
} }
pub fn from_tab_point(&self, point: TabPoint) -> WrapPoint { pub fn tab_point_to_wrap_point(&self, point: TabPoint) -> WrapPoint {
let mut cursor = self.transforms.cursor::<(TabPoint, WrapPoint)>(); let mut cursor = self.transforms.cursor::<(TabPoint, WrapPoint)>();
cursor.seek(&point, Bias::Right, &()); cursor.seek(&point, Bias::Right, &());
WrapPoint(cursor.start().1 .0 + (point.0 - cursor.start().0 .0)) WrapPoint(cursor.start().1 .0 + (point.0 - cursor.start().0 .0))
@ -691,7 +691,7 @@ impl WrapSnapshot {
} }
} }
self.from_tab_point(self.tab_snapshot.clip_point(self.to_tab_point(point), bias)) self.tab_point_to_wrap_point(self.tab_snapshot.clip_point(self.to_tab_point(point), bias))
} }
pub fn prev_row_boundary(&self, mut point: WrapPoint) -> u32 { pub fn prev_row_boundary(&self, mut point: WrapPoint) -> u32 {
@ -1301,7 +1301,7 @@ mod tests {
end_row += 1; end_row += 1;
let mut expected_text = self.text_chunks(start_row).collect::<String>(); let mut expected_text = self.text_chunks(start_row).collect::<String>();
if expected_text.ends_with("\n") { if expected_text.ends_with('\n') {
expected_text.push('\n'); expected_text.push('\n');
} }
let mut expected_text = expected_text let mut expected_text = expected_text

View File

@ -425,6 +425,7 @@ pub struct Editor {
vertical_scroll_margin: f32, vertical_scroll_margin: f32,
placeholder_text: Option<Arc<str>>, placeholder_text: Option<Arc<str>>,
highlighted_rows: Option<Range<u32>>, highlighted_rows: Option<Range<u32>>,
#[allow(clippy::type_complexity)]
background_highlights: BTreeMap<TypeId, (fn(&Theme) -> Color, Vec<Range<Anchor>>)>, background_highlights: BTreeMap<TypeId, (fn(&Theme) -> Color, Vec<Range<Anchor>>)>,
nav_history: Option<ItemNavHistory>, nav_history: Option<ItemNavHistory>,
context_menu: Option<ContextMenu>, context_menu: Option<ContextMenu>,
@ -475,6 +476,7 @@ impl Default for SelectionHistoryMode {
#[derive(Default)] #[derive(Default)]
struct SelectionHistory { struct SelectionHistory {
#[allow(clippy::type_complexity)]
selections_by_transaction: selections_by_transaction:
HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>, HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
mode: SelectionHistoryMode, mode: SelectionHistoryMode,
@ -492,6 +494,7 @@ impl SelectionHistory {
.insert(transaction_id, (selections, None)); .insert(transaction_id, (selections, None));
} }
#[allow(clippy::type_complexity)]
fn transaction( fn transaction(
&self, &self,
transaction_id: TransactionId, transaction_id: TransactionId,
@ -499,6 +502,7 @@ impl SelectionHistory {
self.selections_by_transaction.get(&transaction_id) self.selections_by_transaction.get(&transaction_id)
} }
#[allow(clippy::type_complexity)]
fn transaction_mut( fn transaction_mut(
&mut self, &mut self,
transaction_id: TransactionId, transaction_id: TransactionId,
@ -1023,7 +1027,7 @@ impl Editor {
background_highlights: Default::default(), background_highlights: Default::default(),
nav_history: None, nav_history: None,
context_menu: None, context_menu: None,
mouse_context_menu: cx.add_view(|cx| context_menu::ContextMenu::new(cx)), mouse_context_menu: cx.add_view(context_menu::ContextMenu::new),
completion_tasks: Default::default(), completion_tasks: Default::default(),
next_completion_id: 0, next_completion_id: 0,
available_code_actions: Default::default(), available_code_actions: Default::default(),
@ -1649,7 +1653,7 @@ impl Editor {
if let Some(tail) = self.columnar_selection_tail.as_ref() { if let Some(tail) = self.columnar_selection_tail.as_ref() {
let tail = tail.to_display_point(&display_map); let tail = tail.to_display_point(&display_map);
self.select_columns(tail, position, goal_column, &display_map, cx); self.select_columns(tail, position, goal_column, &display_map, cx);
} else if let Some(mut pending) = self.selections.pending_anchor().clone() { } else if let Some(mut pending) = self.selections.pending_anchor() {
let buffer = self.buffer.read(cx).snapshot(cx); let buffer = self.buffer.read(cx).snapshot(cx);
let head; let head;
let tail; let tail;
@ -1764,10 +1768,10 @@ impl Editor {
if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) { if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
let start = display_map let start = display_map
.clip_point(DisplayPoint::new(row, start_column), Bias::Left) .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
.to_point(&display_map); .to_point(display_map);
let end = display_map let end = display_map
.clip_point(DisplayPoint::new(row, end_column), Bias::Right) .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
.to_point(&display_map); .to_point(display_map);
if reversed { if reversed {
Some(end..start) Some(end..start)
} else { } else {
@ -1915,7 +1919,7 @@ impl Editor {
cursor.row -= 1; cursor.row -= 1;
cursor.column = buffer.line_len(cursor.row); cursor.column = buffer.line_len(cursor.row);
} }
new_selection.map(|_| cursor.clone()) new_selection.map(|_| cursor)
}) })
.collect(); .collect();
@ -2279,7 +2283,7 @@ impl Editor {
let query = Self::completion_query(&self.buffer.read(cx).read(cx), position.clone()); let query = Self::completion_query(&self.buffer.read(cx).read(cx), position.clone());
let completions = project.update(cx, |project, cx| { let completions = project.update(cx, |project, cx| {
project.completions(&buffer, buffer_position.clone(), cx) project.completions(&buffer, buffer_position, cx)
}); });
let id = post_inc(&mut self.next_completion_id); let id = post_inc(&mut self.next_completion_id);
@ -2369,7 +2373,7 @@ impl Editor {
}; };
let selections = self.selections.all::<usize>(cx); let selections = self.selections.all::<usize>(cx);
let buffer = buffer_handle.read(cx); let buffer = buffer_handle.read(cx);
let old_range = completion.old_range.to_offset(&buffer); let old_range = completion.old_range.to_offset(buffer);
let old_text = buffer.text_for_range(old_range.clone()).collect::<String>(); let old_text = buffer.text_for_range(old_range.clone()).collect::<String>();
let newest_selection = self.selections.newest_anchor(); let newest_selection = self.selections.newest_anchor();
@ -2807,7 +2811,7 @@ impl Editor {
let mut tabstop_ranges = tabstop let mut tabstop_ranges = tabstop
.iter() .iter()
.flat_map(|tabstop_range| { .flat_map(|tabstop_range| {
let mut delta = 0 as isize; let mut delta = 0_isize;
insertion_ranges.iter().map(move |insertion_range| { insertion_ranges.iter().map(move |insertion_range| {
let insertion_start = insertion_range.start as isize + delta; let insertion_start = insertion_range.start as isize + delta;
delta += delta +=
@ -2871,7 +2875,7 @@ impl Editor {
} }
if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) { if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
self.change_selections(Some(Autoscroll::Fit), cx, |s| { self.change_selections(Some(Autoscroll::Fit), cx, |s| {
s.select_anchor_ranges(current_ranges.into_iter().cloned()) s.select_anchor_ranges(current_ranges.iter().cloned())
}); });
// If snippet state is not at the last tabstop, push it back on the stack // If snippet state is not at the last tabstop, push it back on the stack
if snippet.active_index + 1 < snippet.ranges.len() { if snippet.active_index + 1 < snippet.ranges.len() {
@ -2953,7 +2957,7 @@ impl Editor {
} }
}) })
}); });
this.insert(&"", cx); this.insert("", cx);
}); });
} }
@ -3220,13 +3224,13 @@ impl Editor {
} }
let buffer = &display_map.buffer_snapshot; let buffer = &display_map.buffer_snapshot;
let mut edit_start = Point::new(rows.start, 0).to_offset(&buffer); let mut edit_start = Point::new(rows.start, 0).to_offset(buffer);
let edit_end; let edit_end;
let cursor_buffer_row; let cursor_buffer_row;
if buffer.max_point().row >= rows.end { if buffer.max_point().row >= rows.end {
// If there's a line after the range, delete the \n from the end of the row range // If there's a line after the range, delete the \n from the end of the row range
// and position the cursor on the next line. // and position the cursor on the next line.
edit_end = Point::new(rows.end, 0).to_offset(&buffer); edit_end = Point::new(rows.end, 0).to_offset(buffer);
cursor_buffer_row = rows.end; cursor_buffer_row = rows.end;
} else { } else {
// If there isn't a line after the range, delete the \n from the line before the // If there isn't a line after the range, delete the \n from the line before the
@ -3292,7 +3296,7 @@ impl Editor {
while let Some(next_selection) = selections_iter.peek() { while let Some(next_selection) = selections_iter.peek() {
let next_rows = next_selection.spanned_rows(false, &display_map); let next_rows = next_selection.spanned_rows(false, &display_map);
if next_rows.start <= rows.end - 1 { if next_rows.start < rows.end {
rows.end = next_rows.end; rows.end = next_rows.end;
selections_iter.next().unwrap(); selections_iter.next().unwrap();
} else { } else {
@ -3414,7 +3418,7 @@ impl Editor {
} }
// If we didn't move line(s), preserve the existing selections // If we didn't move line(s), preserve the existing selections
new_selections.extend(contiguous_row_selections.drain(..)); new_selections.append(&mut contiguous_row_selections);
} }
self.transact(cx, |this, cx| { self.transact(cx, |this, cx| {
@ -3519,7 +3523,7 @@ impl Editor {
} }
// If we didn't move line(s), preserve the existing selections // If we didn't move line(s), preserve the existing selections
new_selections.extend(contiguous_row_selections.drain(..)); new_selections.append(&mut contiguous_row_selections);
} }
self.transact(cx, |this, cx| { self.transact(cx, |this, cx| {
@ -3831,7 +3835,7 @@ impl Editor {
if !selection.is_empty() && !line_mode { if !selection.is_empty() && !line_mode {
selection.goal = SelectionGoal::None; selection.goal = SelectionGoal::None;
} }
let (cursor, goal) = movement::up(&map, selection.start, selection.goal, false); let (cursor, goal) = movement::up(map, selection.start, selection.goal, false);
selection.collapse_to(cursor, goal); selection.collapse_to(cursor, goal);
}); });
}) })
@ -3863,7 +3867,7 @@ impl Editor {
if !selection.is_empty() && !line_mode { if !selection.is_empty() && !line_mode {
selection.goal = SelectionGoal::None; selection.goal = SelectionGoal::None;
} }
let (cursor, goal) = movement::down(&map, selection.end, selection.goal, false); let (cursor, goal) = movement::down(map, selection.end, selection.goal, false);
selection.collapse_to(cursor, goal); selection.collapse_to(cursor, goal);
}); });
}); });
@ -4779,8 +4783,7 @@ impl Editor {
} else { } else {
search_start = buffer.len(); search_start = buffer.len();
} }
} else { } else if search_start == 0 {
if search_start == 0 {
break; break;
} else { } else {
search_start = 0; search_start = 0;
@ -4788,7 +4791,6 @@ impl Editor {
} }
} }
} }
}
pub fn go_to_definition( pub fn go_to_definition(
workspace: &mut Workspace, workspace: &mut Workspace,
@ -5107,13 +5109,7 @@ impl Editor {
})?; })?;
let rename = workspace.project().clone().update(cx, |project, cx| { let rename = workspace.project().clone().update(cx, |project, cx| {
project.perform_rename( project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx)
buffer.clone(),
range.start.clone(),
new_name.clone(),
true,
cx,
)
}); });
Some(cx.spawn(|workspace, mut cx| async move { Some(cx.spawn(|workspace, mut cx| async move {
@ -5292,7 +5288,7 @@ impl Editor {
fn push_to_selection_history(&mut self) { fn push_to_selection_history(&mut self) {
self.selection_history.push(SelectionHistoryEntry { self.selection_history.push(SelectionHistoryEntry {
selections: self.selections.disjoint_anchors().clone(), selections: self.selections.disjoint_anchors(),
select_next_state: self.select_next_state.clone(), select_next_state: self.select_next_state.clone(),
add_selections_state: self.add_selections_state.clone(), add_selections_state: self.add_selections_state.clone(),
}); });
@ -5325,7 +5321,7 @@ impl Editor {
.update(cx, |buffer, cx| buffer.start_transaction_at(now, cx)) .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
{ {
self.selection_history self.selection_history
.insert_transaction(tx_id, self.selections.disjoint_anchors().clone()); .insert_transaction(tx_id, self.selections.disjoint_anchors());
} }
} }
@ -5339,7 +5335,7 @@ impl Editor {
.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx)) .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
{ {
if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) { if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) {
*end_selections = Some(self.selections.disjoint_anchors().clone()); *end_selections = Some(self.selections.disjoint_anchors());
} else { } else {
log::error!("unexpectedly ended a transaction that wasn't started by this editor"); log::error!("unexpectedly ended a transaction that wasn't started by this editor");
} }
@ -5441,7 +5437,7 @@ impl Editor {
} }
let end = end.unwrap_or(max_point); let end = end.unwrap_or(max_point);
return start.to_point(display_map)..end.to_point(display_map); start.to_point(display_map)..end.to_point(display_map)
} }
pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) { pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
@ -5588,6 +5584,7 @@ impl Editor {
cx.notify(); cx.notify();
} }
#[allow(clippy::type_complexity)]
pub fn clear_background_highlights<T: 'static>( pub fn clear_background_highlights<T: 'static>(
&mut self, &mut self,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
@ -5629,7 +5626,7 @@ impl Editor {
.chain(write_highlights) .chain(write_highlights)
.flat_map(move |ranges| { .flat_map(move |ranges| {
let start_ix = match ranges.binary_search_by(|probe| { let start_ix = match ranges.binary_search_by(|probe| {
let cmp = probe.end.cmp(&left_position, &buffer); let cmp = probe.end.cmp(&left_position, buffer);
if cmp.is_ge() { if cmp.is_ge() {
Ordering::Greater Ordering::Greater
} else { } else {
@ -5642,7 +5639,7 @@ impl Editor {
let right_position = right_position.clone(); let right_position = right_position.clone();
ranges[start_ix..] ranges[start_ix..]
.iter() .iter()
.take_while(move |range| range.start.cmp(&right_position, &buffer).is_le()) .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
}) })
} }
@ -5657,7 +5654,7 @@ impl Editor {
for (color_fetcher, ranges) in self.background_highlights.values() { for (color_fetcher, ranges) in self.background_highlights.values() {
let color = color_fetcher(theme); let color = color_fetcher(theme);
let start_ix = match ranges.binary_search_by(|probe| { let start_ix = match ranges.binary_search_by(|probe| {
let cmp = probe.end.cmp(&search_range.start, &buffer); let cmp = probe.end.cmp(&search_range.start, buffer);
if cmp.is_gt() { if cmp.is_gt() {
Ordering::Greater Ordering::Greater
} else { } else {
@ -5667,7 +5664,7 @@ impl Editor {
Ok(i) | Err(i) => i, Ok(i) | Err(i) => i,
}; };
for range in &ranges[start_ix..] { for range in &ranges[start_ix..] {
if range.start.cmp(&search_range.end, &buffer).is_ge() { if range.start.cmp(&search_range.end, buffer).is_ge() {
break; break;
} }
let start = range let start = range
@ -5899,7 +5896,7 @@ impl Editor {
let (_, ranges) = self.text_highlights::<InputComposition>(cx)?; let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
Some( Some(
ranges ranges
.into_iter() .iter()
.map(move |range| { .map(move |range| {
range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot) range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
}) })
@ -6138,10 +6135,8 @@ impl View for Editor {
let new_selected_ranges = if let Some(range_utf16) = range_utf16 { let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end); let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
Some(this.selection_replacement_ranges(range_utf16, cx)) Some(this.selection_replacement_ranges(range_utf16, cx))
} else if let Some(marked_ranges) = this.marked_text_ranges(cx) {
Some(marked_ranges)
} else { } else {
None this.marked_text_ranges(cx)
}; };
if let Some(new_selected_ranges) = new_selected_ranges { if let Some(new_selected_ranges) = new_selected_ranges {
@ -6202,7 +6197,7 @@ impl View for Editor {
let snapshot = this.buffer.read(cx).read(cx); let snapshot = this.buffer.read(cx).read(cx);
this.selections this.selections
.disjoint_anchors() .disjoint_anchors()
.into_iter() .iter()
.map(|selection| { .map(|selection| {
selection.start.bias_left(&*snapshot)..selection.end.bias_right(&*snapshot) selection.start.bias_left(&*snapshot)..selection.end.bias_right(&*snapshot)
}) })
@ -6385,9 +6380,9 @@ impl<T: InvalidationRegion> InvalidationStack<T> {
if selections.len() == region.ranges().len() { if selections.len() == region.ranges().len() {
selections selections
.iter() .iter()
.zip(region.ranges().iter().map(|r| r.to_offset(&buffer))) .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
.all(|(selection, invalidation_range)| { .all(|(selection, invalidation_range)| {
let head = selection.head().to_offset(&buffer); let head = selection.head().to_offset(buffer);
invalidation_range.start <= head && invalidation_range.end >= head invalidation_range.start <= head && invalidation_range.end >= head
}) })
} else { } else {
@ -6602,7 +6597,7 @@ pub fn styled_runs_for_code_label<'a>(
} else { } else {
return Default::default(); return Default::default();
}; };
let mut muted_style = style.clone(); let mut muted_style = style;
muted_style.highlight(fade_out); muted_style.highlight(fade_out);
let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new(); let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
@ -7104,7 +7099,7 @@ mod tests {
fn test_navigation_history(cx: &mut gpui::MutableAppContext) { fn test_navigation_history(cx: &mut gpui::MutableAppContext) {
cx.set_global(Settings::test(cx)); cx.set_global(Settings::test(cx));
use workspace::Item; use workspace::Item;
let (_, pane) = cx.add_window(Default::default(), |cx| Pane::new(cx)); let (_, pane) = cx.add_window(Default::default(), Pane::new);
let buffer = MultiBuffer::build_simple(&sample_text(300, 5, 'a'), cx); let buffer = MultiBuffer::build_simple(&sample_text(300, 5, 'a'), cx);
cx.add_view(&pane, |cx| { cx.add_view(&pane, |cx| {
@ -7194,7 +7189,7 @@ mod tests {
Box::new(NavigationData { Box::new(NavigationData {
cursor_anchor: invalid_anchor.clone(), cursor_anchor: invalid_anchor.clone(),
cursor_position: invalid_point, cursor_position: invalid_point,
scroll_top_anchor: invalid_anchor.clone(), scroll_top_anchor: invalid_anchor,
scroll_top_row: invalid_point.row, scroll_top_row: invalid_point.row,
scroll_position: Default::default(), scroll_position: Default::default(),
}), }),
@ -8704,7 +8699,8 @@ mod tests {
fn test_transpose(cx: &mut gpui::MutableAppContext) { fn test_transpose(cx: &mut gpui::MutableAppContext) {
cx.set_global(Settings::test(cx)); cx.set_global(Settings::test(cx));
cx.add_window(Default::default(), |cx| { _ = cx
.add_window(Default::default(), |cx| {
let mut editor = build_editor(MultiBuffer::build_simple("abc", cx), cx); let mut editor = build_editor(MultiBuffer::build_simple("abc", cx), cx);
editor.change_selections(None, cx, |s| s.select_ranges([1..1])); editor.change_selections(None, cx, |s| s.select_ranges([1..1]));
@ -8724,7 +8720,8 @@ mod tests {
}) })
.1; .1;
cx.add_window(Default::default(), |cx| { _ = cx
.add_window(Default::default(), |cx| {
let mut editor = build_editor(MultiBuffer::build_simple("abc\nde", cx), cx); let mut editor = build_editor(MultiBuffer::build_simple("abc\nde", cx), cx);
editor.change_selections(None, cx, |s| s.select_ranges([3..3])); editor.change_selections(None, cx, |s| s.select_ranges([3..3]));
@ -8749,7 +8746,8 @@ mod tests {
}) })
.1; .1;
cx.add_window(Default::default(), |cx| { _ = cx
.add_window(Default::default(), |cx| {
let mut editor = build_editor(MultiBuffer::build_simple("abc\nde", cx), cx); let mut editor = build_editor(MultiBuffer::build_simple("abc\nde", cx), cx);
editor.change_selections(None, cx, |s| s.select_ranges([1..1, 2..2, 4..4])); editor.change_selections(None, cx, |s| s.select_ranges([1..1, 2..2, 4..4]));
@ -8777,7 +8775,8 @@ mod tests {
}) })
.1; .1;
cx.add_window(Default::default(), |cx| { _ = cx
.add_window(Default::default(), |cx| {
let mut editor = build_editor(MultiBuffer::build_simple("🍐🏀✋", cx), cx); let mut editor = build_editor(MultiBuffer::build_simple("🍐🏀✋", cx), cx);
editor.change_selections(None, cx, |s| s.select_ranges([4..4])); editor.change_selections(None, cx, |s| s.select_ranges([4..4]));
@ -9347,7 +9346,7 @@ mod tests {
let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx)); let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
let (_, view) = cx.add_window(|cx| build_editor(buffer, cx)); let (_, view) = cx.add_window(|cx| build_editor(buffer, cx));
view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing(cx)) view.condition(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx))
.await; .await;
view.update(cx, |view, cx| { view.update(cx, |view, cx| {
@ -9506,7 +9505,7 @@ mod tests {
let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
let (_, editor) = cx.add_window(|cx| build_editor(buffer, cx)); let (_, editor) = cx.add_window(|cx| build_editor(buffer, cx));
editor editor
.condition(&cx, |editor, cx| !editor.buffer.read(cx).is_parsing(cx)) .condition(cx, |editor, cx| !editor.buffer.read(cx).is_parsing(cx))
.await; .await;
editor.update(cx, |editor, cx| { editor.update(cx, |editor, cx| {
@ -9566,7 +9565,7 @@ mod tests {
let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx)); let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
let (_, view) = cx.add_window(|cx| build_editor(buffer, cx)); let (_, view) = cx.add_window(|cx| build_editor(buffer, cx));
view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing(cx)) view.condition(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx))
.await; .await;
view.update(cx, |view, cx| { view.update(cx, |view, cx| {
@ -9742,7 +9741,7 @@ mod tests {
let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx)); let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
let (_, view) = cx.add_window(|cx| build_editor(buffer, cx)); let (_, view) = cx.add_window(|cx| build_editor(buffer, cx));
view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing(cx)) view.condition(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx))
.await; .await;
view.update(cx, |view, cx| { view.update(cx, |view, cx| {
@ -9824,7 +9823,7 @@ mod tests {
let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
let (_, editor) = cx.add_window(|cx| build_editor(buffer, cx)); let (_, editor) = cx.add_window(|cx| build_editor(buffer, cx));
editor editor
.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing(cx)) .condition(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx))
.await; .await;
editor.update(cx, |editor, cx| { editor.update(cx, |editor, cx| {
@ -10028,7 +10027,7 @@ mod tests {
})) }))
.await; .await;
let fs = FakeFs::new(cx.background().clone()); let fs = FakeFs::new(cx.background());
fs.insert_file("/file.rs", Default::default()).await; fs.insert_file("/file.rs", Default::default()).await;
let project = Project::test(fs, ["/file.rs".as_ref()], cx).await; let project = Project::test(fs, ["/file.rs".as_ref()], cx).await;
@ -10142,7 +10141,7 @@ mod tests {
})) }))
.await; .await;
let fs = FakeFs::new(cx.background().clone()); let fs = FakeFs::new(cx.background());
fs.insert_file("/file.rs", Default::default()).await; fs.insert_file("/file.rs", Default::default()).await;
let project = Project::test(fs, ["/file.rs".as_ref()], cx).await; let project = Project::test(fs, ["/file.rs".as_ref()], cx).await;
@ -10425,7 +10424,7 @@ mod tests {
.map(|completion_text| lsp::CompletionItem { .map(|completion_text| lsp::CompletionItem {
label: completion_text.to_string(), label: completion_text.to_string(),
text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit { text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
range: replace_range.clone(), range: replace_range,
new_text: completion_text.to_string(), new_text: completion_text.to_string(),
})), })),
..Default::default() ..Default::default()
@ -10856,7 +10855,7 @@ mod tests {
let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx)); let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
let (_, view) = cx.add_window(|cx| build_editor(buffer, cx)); let (_, view) = cx.add_window(|cx| build_editor(buffer, cx));
view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing(cx)) view.condition(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx))
.await; .await;
view.update(cx, |view, cx| { view.update(cx, |view, cx| {
@ -11084,7 +11083,7 @@ mod tests {
let match_indices = [4, 6, 7, 8]; let match_indices = [4, 6, 7, 8];
assert_eq!( assert_eq!(
combine_syntax_and_fuzzy_match_highlights( combine_syntax_and_fuzzy_match_highlights(
&string, string,
Default::default(), Default::default(),
syntax_ranges.into_iter(), syntax_ranges.into_iter(),
&match_indices, &match_indices,

View File

@ -110,6 +110,7 @@ impl EditorElement {
self.update_view(cx, |view, cx| view.snapshot(cx)) self.update_view(cx, |view, cx| view.snapshot(cx))
} }
#[allow(clippy::too_many_arguments)]
fn mouse_down( fn mouse_down(
&self, &self,
position: Vector2F, position: Vector2F,
@ -696,6 +697,7 @@ impl EditorElement {
cx.scene.pop_layer(); cx.scene.pop_layer();
} }
#[allow(clippy::too_many_arguments)]
fn paint_highlighted_range( fn paint_highlighted_range(
&self, &self,
range: Range<DisplayPoint>, range: Range<DisplayPoint>,
@ -857,7 +859,7 @@ impl EditorElement {
.style .style
.placeholder_text .placeholder_text
.as_ref() .as_ref()
.unwrap_or_else(|| &self.style.text); .unwrap_or(&self.style.text);
let placeholder_text = snapshot.placeholder_text(); let placeholder_text = snapshot.placeholder_text();
let placeholder_lines = placeholder_text let placeholder_lines = placeholder_text
.as_ref() .as_ref()
@ -866,7 +868,7 @@ impl EditorElement {
.skip(rows.start as usize) .skip(rows.start as usize)
.chain(iter::repeat("")) .chain(iter::repeat(""))
.take(rows.len()); .take(rows.len());
return placeholder_lines placeholder_lines
.map(|line| { .map(|line| {
cx.text_layout_cache.layout_str( cx.text_layout_cache.layout_str(
line, line,
@ -881,7 +883,7 @@ impl EditorElement {
)], )],
) )
}) })
.collect(); .collect()
} else { } else {
let style = &self.style; let style = &self.style;
let chunks = snapshot.chunks(rows.clone(), true).map(|chunk| { let chunks = snapshot.chunks(rows.clone(), true).map(|chunk| {
@ -926,14 +928,15 @@ impl EditorElement {
layout_highlighted_chunks( layout_highlighted_chunks(
chunks, chunks,
&style.text, &style.text,
&cx.text_layout_cache, cx.text_layout_cache,
&cx.font_cache, cx.font_cache,
MAX_LINE_LEN, MAX_LINE_LEN,
rows.len() as usize, rows.len() as usize,
) )
} }
} }
#[allow(clippy::too_many_arguments)]
fn layout_blocks( fn layout_blocks(
&mut self, &mut self,
rows: Range<u32>, rows: Range<u32>,
@ -1299,7 +1302,9 @@ impl Element for EditorElement {
} }
// Render the local selections in the leader's color when following. // Render the local selections in the leader's color when following.
let local_replica_id = view.leader_replica_id.unwrap_or(view.replica_id(cx)); let local_replica_id = view
.leader_replica_id
.unwrap_or_else(|| view.replica_id(cx));
selections.push(( selections.push((
local_replica_id, local_replica_id,
@ -1357,19 +1362,19 @@ impl Element for EditorElement {
self.update_view(cx.app, |view, cx| { self.update_view(cx.app, |view, cx| {
let clamped = view.clamp_scroll_left(scroll_max.x()); let clamped = view.clamp_scroll_left(scroll_max.x());
let autoscrolled;
if autoscroll_horizontally { let autoscrolled = if autoscroll_horizontally {
autoscrolled = view.autoscroll_horizontally( view.autoscroll_horizontally(
start_row, start_row,
text_size.x(), text_size.x(),
scroll_width, scroll_width,
em_width, em_width,
&line_layouts, &line_layouts,
cx, cx,
); )
} else { } else {
autoscrolled = false; false
} };
if clamped || autoscrolled { if clamped || autoscrolled {
snapshot = view.snapshot(cx); snapshot = view.snapshot(cx);
@ -1991,8 +1996,8 @@ mod tests {
let layouts = editor.update(cx, |editor, cx| { let layouts = editor.update(cx, |editor, cx| {
let snapshot = editor.snapshot(cx); let snapshot = editor.snapshot(cx);
let mut presenter = cx.build_presenter(window_id, 30.); let mut presenter = cx.build_presenter(window_id, 30.);
let mut layout_cx = presenter.build_layout_context(Vector2F::zero(), false, cx); let layout_cx = presenter.build_layout_context(Vector2F::zero(), false, cx);
element.layout_line_numbers(0..6, &Default::default(), &snapshot, &mut layout_cx) element.layout_line_numbers(0..6, &Default::default(), &snapshot, &layout_cx)
}); });
assert_eq!(layouts.len(), 6); assert_eq!(layouts.len(), 6);
} }

View File

@ -158,7 +158,7 @@ fn show_hover(
// query the LSP for hover info // query the LSP for hover info
let hover_request = cx.update(|cx| { let hover_request = cx.update(|cx| {
project.update(cx, |project, cx| { project.update(cx, |project, cx| {
project.hover(&buffer, buffer_position.clone(), cx) project.hover(&buffer, buffer_position, cx)
}) })
}); });
@ -222,7 +222,7 @@ fn show_hover(
Some(InfoPopover { Some(InfoPopover {
project: project.clone(), project: project.clone(),
symbol_range: range.clone(), symbol_range: range,
contents: hover_result.contents, contents: hover_result.contents,
}) })
}); });

View File

@ -76,14 +76,14 @@ impl FollowableItem for Editor {
}) })
.collect::<Result<Vec<_>>>()?; .collect::<Result<Vec<_>>>()?;
if !selections.is_empty() { if !selections.is_empty() {
editor.set_selections_from_remote(selections.into(), cx); editor.set_selections_from_remote(selections, cx);
} }
if let Some(anchor) = state.scroll_top_anchor { if let Some(anchor) = state.scroll_top_anchor {
editor.set_scroll_top_anchor( editor.set_scroll_top_anchor(
Anchor { Anchor {
buffer_id: Some(state.buffer_id as usize), buffer_id: Some(state.buffer_id as usize),
excerpt_id: excerpt_id.clone(), excerpt_id,
text_anchor: language::proto::deserialize_anchor(anchor) text_anchor: language::proto::deserialize_anchor(anchor)
.ok_or_else(|| anyhow!("invalid scroll top"))?, .ok_or_else(|| anyhow!("invalid scroll top"))?,
}, },
@ -198,12 +198,11 @@ impl FollowableItem for Editor {
if !selections.is_empty() { if !selections.is_empty() {
self.set_selections_from_remote(selections, cx); self.set_selections_from_remote(selections, cx);
self.request_autoscroll_remotely(Autoscroll::Newest, cx); self.request_autoscroll_remotely(Autoscroll::Newest, cx);
} else { } else if let Some(anchor) = message.scroll_top_anchor {
if let Some(anchor) = message.scroll_top_anchor {
self.set_scroll_top_anchor( self.set_scroll_top_anchor(
Anchor { Anchor {
buffer_id: Some(buffer_id), buffer_id: Some(buffer_id),
excerpt_id: excerpt_id.clone(), excerpt_id,
text_anchor: language::proto::deserialize_anchor(anchor) text_anchor: language::proto::deserialize_anchor(anchor)
.ok_or_else(|| anyhow!("invalid scroll top"))?, .ok_or_else(|| anyhow!("invalid scroll top"))?,
}, },
@ -213,7 +212,6 @@ impl FollowableItem for Editor {
} }
} }
} }
}
Ok(()) Ok(())
} }
@ -436,8 +434,7 @@ impl Item for Editor {
.buffer() .buffer()
.read(cx) .read(cx)
.as_singleton() .as_singleton()
.expect("cannot call save_as on an excerpt list") .expect("cannot call save_as on an excerpt list");
.clone();
project.update(cx, |project, cx| { project.update(cx, |project, cx| {
project.save_buffer_as(buffer, abs_path, cx) project.save_buffer_as(buffer, abs_path, cx)
@ -503,6 +500,12 @@ pub struct CursorPosition {
_observe_active_editor: Option<Subscription>, _observe_active_editor: Option<Subscription>,
} }
impl Default for CursorPosition {
fn default() -> Self {
Self::new()
}
}
impl CursorPosition { impl CursorPosition {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {

View File

@ -83,7 +83,7 @@ pub fn update_go_to_definition_link(
&point, &point,
&editor.link_go_to_definition_state.last_mouse_location, &editor.link_go_to_definition_state.last_mouse_location,
) { ) {
if a.cmp(&b, &snapshot.buffer_snapshot).is_eq() { if a.cmp(b, &snapshot.buffer_snapshot).is_eq() {
return; return;
} }
} }
@ -126,7 +126,7 @@ pub fn cmd_shift_changed(
LinkDefinitionKind::Symbol LinkDefinitionKind::Symbol
}; };
show_link_definition(kind, editor, point.clone(), snapshot, cx); show_link_definition(kind, editor, point, snapshot, cx);
} else { } else {
hide_link_definition(editor, cx) hide_link_definition(editor, cx)
} }
@ -204,12 +204,10 @@ pub fn show_link_definition(
// query the LSP for definition info // query the LSP for definition info
let definition_request = cx.update(|cx| { let definition_request = cx.update(|cx| {
project.update(cx, |project, cx| match definition_kind { project.update(cx, |project, cx| match definition_kind {
LinkDefinitionKind::Symbol => { LinkDefinitionKind::Symbol => project.definition(&buffer, buffer_position, cx),
project.definition(&buffer, buffer_position.clone(), cx)
}
LinkDefinitionKind::Type => { LinkDefinitionKind::Type => {
project.type_definition(&buffer, buffer_position.clone(), cx) project.type_definition(&buffer, buffer_position, cx)
} }
}) })
}); });
@ -363,7 +361,7 @@ fn go_to_fetched_definition_of_kind(
editor_handle.update(cx, |editor, cx| { editor_handle.update(cx, |editor, cx| {
editor.select( editor.select(
&Select(SelectPhase::Begin { &Select(SelectPhase::Begin {
position: point.clone(), position: point,
add: false, add: false,
click_count: 1, click_count: 1,
}), }),

View File

@ -33,7 +33,7 @@ use text::{
use theme::SyntaxTheme; use theme::SyntaxTheme;
use util::post_inc; use util::post_inc;
const NEWLINES: &'static [u8] = &[b'\n'; u8::MAX as usize]; const NEWLINES: &[u8] = &[b'\n'; u8::MAX as usize];
pub type ExcerptId = Locator; pub type ExcerptId = Locator;
@ -289,10 +289,16 @@ impl MultiBuffer {
self.read(cx).has_conflict() self.read(cx).has_conflict()
} }
// The `is_empty` signature doesn't match what clippy expects
#[allow(clippy::len_without_is_empty)]
pub fn len(&self, cx: &AppContext) -> usize { pub fn len(&self, cx: &AppContext) -> usize {
self.read(cx).len() self.read(cx).len()
} }
pub fn is_empty(&self, cx: &AppContext) -> bool {
self.len(cx) != 0
}
pub fn symbols_containing<T: ToOffset>( pub fn symbols_containing<T: ToOffset>(
&self, &self,
offset: T, offset: T,
@ -338,6 +344,7 @@ impl MultiBuffer {
_ => Default::default(), _ => Default::default(),
}; };
#[allow(clippy::type_complexity)]
let mut buffer_edits: HashMap<usize, Vec<(Range<usize>, Arc<str>, bool, u32)>> = let mut buffer_edits: HashMap<usize, Vec<(Range<usize>, Arc<str>, bool, u32)>> =
Default::default(); Default::default();
let mut cursor = snapshot.excerpts.cursor::<usize>(); let mut cursor = snapshot.excerpts.cursor::<usize>();
@ -594,13 +601,13 @@ impl MultiBuffer {
break; break;
} }
let mut start = excerpt.range.context.start.clone(); let mut start = excerpt.range.context.start;
let mut end = excerpt.range.context.end.clone(); let mut end = excerpt.range.context.end;
if excerpt.id == selection.start.excerpt_id { if excerpt.id == selection.start.excerpt_id {
start = selection.start.text_anchor.clone(); start = selection.start.text_anchor;
} }
if excerpt.id == selection.end.excerpt_id { if excerpt.id == selection.end.excerpt_id {
end = selection.end.text_anchor.clone(); end = selection.end.text_anchor;
} }
selections_by_buffer selections_by_buffer
.entry(excerpt.buffer_id) .entry(excerpt.buffer_id)
@ -666,7 +673,7 @@ impl MultiBuffer {
while let Some(transaction) = self.history.pop_undo() { while let Some(transaction) = self.history.pop_undo() {
let mut undone = false; let mut undone = false;
for (buffer_id, buffer_transaction_id) in &mut transaction.buffer_transactions { for (buffer_id, buffer_transaction_id) in &mut transaction.buffer_transactions {
if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(&buffer_id) { if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(buffer_id) {
undone |= buffer.update(cx, |buffer, cx| { undone |= buffer.update(cx, |buffer, cx| {
let undo_to = *buffer_transaction_id; let undo_to = *buffer_transaction_id;
if let Some(entry) = buffer.peek_undo_stack() { if let Some(entry) = buffer.peek_undo_stack() {
@ -693,7 +700,7 @@ impl MultiBuffer {
while let Some(transaction) = self.history.pop_redo() { while let Some(transaction) = self.history.pop_redo() {
let mut redone = false; let mut redone = false;
for (buffer_id, buffer_transaction_id) in &mut transaction.buffer_transactions { for (buffer_id, buffer_transaction_id) in &mut transaction.buffer_transactions {
if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(&buffer_id) { if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(buffer_id) {
redone |= buffer.update(cx, |buffer, cx| { redone |= buffer.update(cx, |buffer, cx| {
let redo_to = *buffer_transaction_id; let redo_to = *buffer_transaction_id;
if let Some(entry) = buffer.peek_redo_stack() { if let Some(entry) = buffer.peek_redo_stack() {
@ -982,8 +989,8 @@ impl MultiBuffer {
} }
// If point is at the end of the buffer, the last excerpt is returned // If point is at the end of the buffer, the last excerpt is returned
pub fn point_to_buffer_offset<'a, T: ToOffset>( pub fn point_to_buffer_offset<T: ToOffset>(
&'a self, &self,
point: T, point: T,
cx: &AppContext, cx: &AppContext,
) -> Option<(ModelHandle<Buffer>, usize)> { ) -> Option<(ModelHandle<Buffer>, usize)> {
@ -1004,8 +1011,8 @@ impl MultiBuffer {
}) })
} }
pub fn range_to_buffer_ranges<'a, T: ToOffset>( pub fn range_to_buffer_ranges<T: ToOffset>(
&'a self, &self,
range: Range<T>, range: Range<T>,
cx: &AppContext, cx: &AppContext,
) -> Vec<(ModelHandle<Buffer>, Range<usize>)> { ) -> Vec<(ModelHandle<Buffer>, Range<usize>)> {
@ -1112,8 +1119,8 @@ impl MultiBuffer {
cx.notify(); cx.notify();
} }
pub fn text_anchor_for_position<'a, T: ToOffset>( pub fn text_anchor_for_position<T: ToOffset>(
&'a self, &self,
position: T, position: T,
cx: &AppContext, cx: &AppContext,
) -> Option<(ModelHandle<Buffer>, language::Anchor)> { ) -> Option<(ModelHandle<Buffer>, language::Anchor)> {
@ -1439,7 +1446,7 @@ impl MultiBuffer {
.flat_map(|b| &b.excerpts) .flat_map(|b| &b.excerpts)
.cloned() .cloned()
.collect::<Vec<_>>(); .collect::<Vec<_>>();
if excerpt_ids.len() == 0 || (rng.gen() && excerpt_ids.len() < max_excerpts) { if excerpt_ids.is_empty() || (rng.gen() && excerpt_ids.len() < max_excerpts) {
let buffer_handle = if rng.gen() || self.buffers.borrow().is_empty() { let buffer_handle = if rng.gen() || self.buffers.borrow().is_empty() {
let text = RandomCharIter::new(&mut *rng).take(10).collect::<String>(); let text = RandomCharIter::new(&mut *rng).take(10).collect::<String>();
buffers.push(cx.add_model(|cx| Buffer::new(0, text, cx))); buffers.push(cx.add_model(|cx| Buffer::new(0, text, cx)));
@ -1514,8 +1521,8 @@ impl MultiBuffer {
.choose(rng) .choose(rng)
.map(|state| state.buffer.clone()); .map(|state| state.buffer.clone());
if rng.gen() && buffer.is_some() { if let Some(buffer) = buffer {
buffer.unwrap().update(cx, |buffer, cx| { buffer.update(cx, |buffer, cx| {
if rng.gen() { if rng.gen() {
buffer.randomly_edit(rng, mutation_count, cx); buffer.randomly_edit(rng, mutation_count, cx);
} else { } else {
@ -1542,10 +1549,7 @@ impl MultiBufferSnapshot {
.collect() .collect()
} }
pub fn reversed_chars_at<'a, T: ToOffset>( pub fn reversed_chars_at<T: ToOffset>(&self, position: T) -> impl Iterator<Item = char> + '_ {
&'a self,
position: T,
) -> impl Iterator<Item = char> + 'a {
let mut offset = position.to_offset(self); let mut offset = position.to_offset(self);
let mut cursor = self.excerpts.cursor::<usize>(); let mut cursor = self.excerpts.cursor::<usize>();
cursor.seek(&offset, Bias::Left, &()); cursor.seek(&offset, Bias::Left, &());
@ -1579,16 +1583,13 @@ impl MultiBufferSnapshot {
.flat_map(|c| c.chars().rev()) .flat_map(|c| c.chars().rev())
} }
pub fn chars_at<'a, T: ToOffset>(&'a self, position: T) -> impl Iterator<Item = char> + 'a { pub fn chars_at<T: ToOffset>(&self, position: T) -> impl Iterator<Item = char> + '_ {
let offset = position.to_offset(self); let offset = position.to_offset(self);
self.text_for_range(offset..self.len()) self.text_for_range(offset..self.len())
.flat_map(|chunk| chunk.chars()) .flat_map(|chunk| chunk.chars())
} }
pub fn text_for_range<'a, T: ToOffset>( pub fn text_for_range<T: ToOffset>(&self, range: Range<T>) -> impl Iterator<Item = &str> + '_ {
&'a self,
range: Range<T>,
) -> impl Iterator<Item = &'a str> {
self.chunks(range, false).map(|chunk| chunk.text) self.chunks(range, false).map(|chunk| chunk.text)
} }
@ -1655,6 +1656,10 @@ impl MultiBufferSnapshot {
self.excerpts.summary().text.len self.excerpts.summary().text.len
} }
pub fn is_empty(&self) -> bool {
self.excerpts.summary().text.len == 0
}
pub fn max_buffer_row(&self) -> u32 { pub fn max_buffer_row(&self) -> u32 {
self.excerpts.summary().max_buffer_row self.excerpts.summary().max_buffer_row
} }
@ -1737,7 +1742,7 @@ impl MultiBufferSnapshot {
*cursor.start() + overshoot *cursor.start() + overshoot
} }
pub fn bytes_in_range<'a, T: ToOffset>(&'a self, range: Range<T>) -> MultiBufferBytes<'a> { pub fn bytes_in_range<T: ToOffset>(&self, range: Range<T>) -> MultiBufferBytes {
let range = range.start.to_offset(self)..range.end.to_offset(self); let range = range.start.to_offset(self)..range.end.to_offset(self);
let mut excerpts = self.excerpts.cursor::<usize>(); let mut excerpts = self.excerpts.cursor::<usize>();
excerpts.seek(&range.start, Bias::Right, &()); excerpts.seek(&range.start, Bias::Right, &());
@ -1760,7 +1765,7 @@ impl MultiBufferSnapshot {
} }
} }
pub fn buffer_rows<'a>(&'a self, start_row: u32) -> MultiBufferRows<'a> { pub fn buffer_rows(&self, start_row: u32) -> MultiBufferRows {
let mut result = MultiBufferRows { let mut result = MultiBufferRows {
buffer_row_range: 0..0, buffer_row_range: 0..0,
excerpts: self.excerpts.cursor(), excerpts: self.excerpts.cursor(),
@ -1769,11 +1774,7 @@ impl MultiBufferSnapshot {
result result
} }
pub fn chunks<'a, T: ToOffset>( pub fn chunks<T: ToOffset>(&self, range: Range<T>, language_aware: bool) -> MultiBufferChunks {
&'a self,
range: Range<T>,
language_aware: bool,
) -> MultiBufferChunks<'a> {
let range = range.start.to_offset(self)..range.end.to_offset(self); let range = range.start.to_offset(self)..range.end.to_offset(self);
let mut chunks = MultiBufferChunks { let mut chunks = MultiBufferChunks {
range: range.clone(), range: range.clone(),
@ -2033,7 +2034,7 @@ impl MultiBufferSnapshot {
self.excerpts.summary().text.clone() self.excerpts.summary().text.clone()
} }
pub fn text_summary_for_range<'a, D, O>(&'a self, range: Range<O>) -> D pub fn text_summary_for_range<D, O>(&self, range: Range<O>) -> D
where where
D: TextDimension, D: TextDimension,
O: ToOffset, O: ToOffset,
@ -2204,15 +2205,15 @@ impl MultiBufferSnapshot {
let (anchor_ix, anchor) = anchors.next().unwrap(); let (anchor_ix, anchor) = anchors.next().unwrap();
let mut anchor = anchor.clone(); let mut anchor = anchor.clone();
// Leave min and max anchors unchanged. let id_invalid =
if *old_excerpt_id == ExcerptId::max() || *old_excerpt_id == ExcerptId::min() { *old_excerpt_id == ExcerptId::max() || *old_excerpt_id == ExcerptId::min();
kept_position = true; let still_exists = next_excerpt.map_or(false, |excerpt| {
}
// If the old excerpt still exists at this location, then leave
// the anchor unchanged.
else if next_excerpt.map_or(false, |excerpt| {
excerpt.id == *old_excerpt_id && excerpt.contains(&anchor) excerpt.id == *old_excerpt_id && excerpt.contains(&anchor)
}) { });
// Leave min and max anchors unchanged if invalid or
// if the old excerpt still exists at this location
if id_invalid || still_exists {
kept_position = true; kept_position = true;
} }
// If the old excerpt no longer exists at this location, then attempt to // If the old excerpt no longer exists at this location, then attempt to
@ -2239,7 +2240,7 @@ impl MultiBufferSnapshot {
.cmp(&excerpt.range.context.end, &excerpt.buffer) .cmp(&excerpt.range.context.end, &excerpt.buffer)
.is_gt() .is_gt()
{ {
text_anchor = excerpt.range.context.end.clone(); text_anchor = excerpt.range.context.end;
} }
Anchor { Anchor {
buffer_id: Some(excerpt.buffer_id), buffer_id: Some(excerpt.buffer_id),
@ -2256,7 +2257,7 @@ impl MultiBufferSnapshot {
.cmp(&excerpt.range.context.start, &excerpt.buffer) .cmp(&excerpt.range.context.start, &excerpt.buffer)
.is_lt() .is_lt()
{ {
text_anchor = excerpt.range.context.start.clone(); text_anchor = excerpt.range.context.start;
} }
Anchor { Anchor {
buffer_id: Some(excerpt.buffer_id), buffer_id: Some(excerpt.buffer_id),
@ -2349,10 +2350,10 @@ impl MultiBufferSnapshot {
} }
} }
pub fn excerpt_boundaries_in_range<'a, R, T>( pub fn excerpt_boundaries_in_range<R, T>(
&'a self, &self,
range: R, range: R,
) -> impl Iterator<Item = ExcerptBoundary> + 'a ) -> impl Iterator<Item = ExcerptBoundary> + '_
where where
R: RangeBounds<T>, R: RangeBounds<T>,
T: ToOffset, T: ToOffset,
@ -2635,13 +2636,12 @@ impl MultiBufferSnapshot {
cursor cursor
.take_while(move |excerpt| excerpt.id <= range.end.excerpt_id) .take_while(move |excerpt| excerpt.id <= range.end.excerpt_id)
.flat_map(move |excerpt| { .flat_map(move |excerpt| {
let mut query_range = let mut query_range = excerpt.range.context.start..excerpt.range.context.end;
excerpt.range.context.start.clone()..excerpt.range.context.end.clone();
if excerpt.id == range.start.excerpt_id { if excerpt.id == range.start.excerpt_id {
query_range.start = range.start.text_anchor.clone(); query_range.start = range.start.text_anchor;
} }
if excerpt.id == range.end.excerpt_id { if excerpt.id == range.end.excerpt_id {
query_range.end = range.end.text_anchor.clone(); query_range.end = range.end.text_anchor;
} }
excerpt excerpt
@ -2652,12 +2652,12 @@ impl MultiBufferSnapshot {
let mut start = Anchor { let mut start = Anchor {
buffer_id: Some(excerpt.buffer_id), buffer_id: Some(excerpt.buffer_id),
excerpt_id: excerpt.id.clone(), excerpt_id: excerpt.id.clone(),
text_anchor: selection.start.clone(), text_anchor: selection.start,
}; };
let mut end = Anchor { let mut end = Anchor {
buffer_id: Some(excerpt.buffer_id), buffer_id: Some(excerpt.buffer_id),
excerpt_id: excerpt.id.clone(), excerpt_id: excerpt.id.clone(),
text_anchor: selection.end.clone(), text_anchor: selection.end,
}; };
if range.start.cmp(&start, self).is_gt() { if range.start.cmp(&start, self).is_gt() {
start = range.start.clone(); start = range.start.clone();
@ -2862,11 +2862,7 @@ impl Excerpt {
} }
} }
fn chunks_in_range<'a>( fn chunks_in_range(&self, range: Range<usize>, language_aware: bool) -> ExcerptChunks {
&'a self,
range: Range<usize>,
language_aware: bool,
) -> ExcerptChunks<'a> {
let content_start = self.range.context.start.to_offset(&self.buffer); let content_start = self.range.context.start.to_offset(&self.buffer);
let chunks_start = content_start + range.start; let chunks_start = content_start + range.start;
let chunks_end = content_start + cmp::min(range.end, self.text_summary.len); let chunks_end = content_start + cmp::min(range.end, self.text_summary.len);
@ -2913,12 +2909,12 @@ impl Excerpt {
.cmp(&self.range.context.start, &self.buffer) .cmp(&self.range.context.start, &self.buffer)
.is_lt() .is_lt()
{ {
self.range.context.start.clone() self.range.context.start
} else if text_anchor } else if text_anchor
.cmp(&self.range.context.end, &self.buffer) .cmp(&self.range.context.end, &self.buffer)
.is_gt() .is_gt()
{ {
self.range.context.end.clone() self.range.context.end
} else { } else {
text_anchor text_anchor
} }
@ -3835,7 +3831,7 @@ mod tests {
"Removing excerpt {}: {:?}", "Removing excerpt {}: {:?}",
ix, ix,
buffer buffer
.text_for_range(range.to_offset(&buffer)) .text_for_range(range.to_offset(buffer))
.collect::<String>(), .collect::<String>(),
); );
} }
@ -3851,7 +3847,7 @@ mod tests {
let bias = if rng.gen() { Bias::Left } else { Bias::Right }; let bias = if rng.gen() { Bias::Left } else { Bias::Right };
log::info!("Creating anchor at {} with bias {:?}", offset, bias); log::info!("Creating anchor at {} with bias {:?}", offset, bias);
anchors.push(multibuffer.anchor_at(offset, bias)); anchors.push(multibuffer.anchor_at(offset, bias));
anchors.sort_by(|a, b| a.cmp(&b, &multibuffer)); anchors.sort_by(|a, b| a.cmp(b, &multibuffer));
} }
40..=44 if !anchors.is_empty() => { 40..=44 if !anchors.is_empty() => {
let multibuffer = multibuffer.read(cx).read(cx); let multibuffer = multibuffer.read(cx).read(cx);
@ -3896,7 +3892,7 @@ mod tests {
let prev_excerpt_id = excerpt_ids let prev_excerpt_id = excerpt_ids
.get(prev_excerpt_ix) .get(prev_excerpt_ix)
.cloned() .cloned()
.unwrap_or(ExcerptId::max()); .unwrap_or_else(ExcerptId::max);
let excerpt_ix = (prev_excerpt_ix + 1).min(expected_excerpts.len()); let excerpt_ix = (prev_excerpt_ix + 1).min(expected_excerpts.len());
log::info!( log::info!(
@ -3984,11 +3980,7 @@ mod tests {
assert_eq!( assert_eq!(
snapshot.max_buffer_row(), snapshot.max_buffer_row(),
expected_buffer_rows expected_buffer_rows.into_iter().flatten().max().unwrap()
.into_iter()
.filter_map(|r| r)
.max()
.unwrap()
); );
let mut excerpt_starts = excerpt_starts.into_iter(); let mut excerpt_starts = excerpt_starts.into_iter();

View File

@ -34,7 +34,7 @@ impl Anchor {
&self.excerpt_id &self.excerpt_id
} }
pub fn cmp<'a>(&self, other: &Anchor, snapshot: &MultiBufferSnapshot) -> Ordering { pub fn cmp(&self, other: &Anchor, snapshot: &MultiBufferSnapshot) -> Ordering {
let excerpt_id_cmp = self.excerpt_id.cmp(&other.excerpt_id); let excerpt_id_cmp = self.excerpt_id.cmp(&other.excerpt_id);
if excerpt_id_cmp.is_eq() { if excerpt_id_cmp.is_eq() {
if self.excerpt_id == ExcerptId::min() || self.excerpt_id == ExcerptId::max() { if self.excerpt_id == ExcerptId::min() || self.excerpt_id == ExcerptId::max() {
@ -111,15 +111,15 @@ impl AnchorRangeExt for Range<Anchor> {
fn cmp(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Ordering { fn cmp(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Ordering {
match self.start.cmp(&other.start, buffer) { match self.start.cmp(&other.start, buffer) {
Ordering::Equal => other.end.cmp(&self.end, buffer), Ordering::Equal => other.end.cmp(&self.end, buffer),
ord @ _ => ord, ord => ord,
} }
} }
fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize> { fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize> {
self.start.to_offset(&content)..self.end.to_offset(&content) self.start.to_offset(content)..self.end.to_offset(content)
} }
fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point> { fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point> {
self.start.to_point(&content)..self.end.to_point(&content) self.start.to_point(content)..self.end.to_point(content)
} }
} }

View File

@ -68,7 +68,7 @@ impl SelectionsCollection {
self.pending = other.pending.clone(); self.pending = other.pending.clone();
} }
pub fn count<'a>(&self) -> usize { pub fn count(&self) -> usize {
let mut count = self.disjoint.len(); let mut count = self.disjoint.len();
if self.pending.is_some() { if self.pending.is_some() {
count += 1; count += 1;
@ -365,7 +365,7 @@ impl<'a> MutableSelectionsCollection<'a> {
let mut changed = false; let mut changed = false;
self.collection.disjoint = self self.collection.disjoint = self
.disjoint .disjoint
.into_iter() .iter()
.filter(|selection| { .filter(|selection| {
let found = selection.id == selection_id; let found = selection.id == selection_id;
changed |= found; changed |= found;
@ -464,7 +464,7 @@ impl<'a> MutableSelectionsCollection<'a> {
return true; return true;
} }
return false; false
} }
pub fn insert_range<T>(&mut self, range: Range<T>) pub fn insert_range<T>(&mut self, range: Range<T>)
@ -729,8 +729,7 @@ impl<'a> MutableSelectionsCollection<'a> {
kept_end kept_end
}; };
if !kept_head { if !kept_head {
selections_with_lost_position selections_with_lost_position.insert(selection.id, selection.head().excerpt_id);
.insert(selection.id, selection.head().excerpt_id.clone());
} }
Selection { Selection {
@ -761,10 +760,8 @@ impl<'a> MutableSelectionsCollection<'a> {
kept_end kept_end
}; };
if !kept_head { if !kept_head {
selections_with_lost_position.insert( selections_with_lost_position
pending.selection.id, .insert(pending.selection.id, pending.selection.head().excerpt_id);
pending.selection.head().excerpt_id.clone(),
);
} }
pending.selection.start = start; pending.selection.start = start;
@ -814,5 +811,5 @@ fn resolve<D: TextDimension + Ord + Sub<D, Output = D>>(
selection: &Selection<Anchor>, selection: &Selection<Anchor>,
buffer: &MultiBufferSnapshot, buffer: &MultiBufferSnapshot,
) -> Selection<D> { ) -> Selection<D> {
selection.map(|p| p.summary::<D>(&buffer)) selection.map(|p| p.summary::<D>(buffer))
} }

View File

@ -262,7 +262,7 @@ impl PickerDelegate for FileFinder {
self.labels_for_match(path_match); self.labels_for_match(path_match);
Flex::column() Flex::column()
.with_child( .with_child(
Label::new(file_name.to_string(), style.label.clone()) Label::new(file_name, style.label.clone())
.with_highlights(file_name_positions) .with_highlights(file_name_positions)
.boxed(), .boxed(),
) )
@ -333,7 +333,7 @@ mod tests {
cx.dispatch_action(window_id, SelectNext); cx.dispatch_action(window_id, SelectNext);
cx.dispatch_action(window_id, Confirm); cx.dispatch_action(window_id, Confirm);
active_pane active_pane
.condition(&cx, |pane, _| pane.active_item().is_some()) .condition(cx, |pane, _| pane.active_item().is_some())
.await; .await;
cx.read(|cx| { cx.read(|cx| {
let active_item = active_pane.read(cx).active_item().unwrap(); let active_item = active_pane.read(cx).active_item().unwrap();

View File

@ -4,7 +4,7 @@ use std::{env::args, path::Path, time::Duration};
fn main() { fn main() {
let paths = args().skip(1).collect::<Vec<_>>(); let paths = args().skip(1).collect::<Vec<_>>();
let paths = paths.iter().map(Path::new).collect::<Vec<_>>(); let paths = paths.iter().map(Path::new).collect::<Vec<_>>();
assert!(paths.len() > 0, "Must pass 1 or more paths as arguments"); assert!(!paths.is_empty(), "Must pass 1 or more paths as arguments");
let (stream, _handle) = EventStream::new(&paths, Duration::from_millis(100)); let (stream, _handle) = EventStream::new(&paths, Duration::from_millis(100));
stream.run(|events| { stream.run(|events| {
eprintln!("event batch"); eprintln!("event batch");

View File

@ -233,15 +233,13 @@ impl EventStream {
} }
} }
if !events.is_empty() { if !events.is_empty() && !callback(events) {
if !callback(events) {
fs::FSEventStreamStop(stream_ref); fs::FSEventStreamStop(stream_ref);
cf::CFRunLoopStop(cf::CFRunLoopGetCurrent()); cf::CFRunLoopStop(cf::CFRunLoopGetCurrent());
} }
} }
} }
} }
}
} }
impl Drop for Handle { impl Drop for Handle {

View File

@ -10,15 +10,15 @@ impl CharBag {
fn insert(&mut self, c: char) { fn insert(&mut self, c: char) {
let c = c.to_ascii_lowercase(); let c = c.to_ascii_lowercase();
if c >= 'a' && c <= 'z' { if ('a'..='z').contains(&c) {
let mut count = self.0; let mut count = self.0;
let idx = c as u8 - 'a' as u8; let idx = c as u8 - b'a';
count = count >> (idx * 2); count >>= idx * 2;
count = ((count << 1) | 1) & 3; count = ((count << 1) | 1) & 3;
count = count << idx * 2; count <<= idx * 2;
self.0 |= count; self.0 |= count;
} else if c >= '0' && c <= '9' { } else if ('0'..='9').contains(&c) {
let idx = c as u8 - '0' as u8; let idx = c as u8 - b'0';
self.0 |= 1 << (idx + 52); self.0 |= 1 << (idx + 52);
} else if c == '-' { } else if c == '-' {
self.0 |= 1 << 62; self.0 |= 1 << 62;

View File

@ -35,7 +35,7 @@ trait Match: Ord {
trait MatchCandidate { trait MatchCandidate {
fn has_chars(&self, bag: CharBag) -> bool; fn has_chars(&self, bag: CharBag) -> bool;
fn to_string<'a>(&'a self) -> Cow<'a, str>; fn to_string(&self) -> Cow<'_, str>;
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -64,6 +64,9 @@ pub trait PathMatchCandidateSet<'a>: Send + Sync {
type Candidates: Iterator<Item = PathMatchCandidate<'a>>; type Candidates: Iterator<Item = PathMatchCandidate<'a>>;
fn id(&self) -> usize; fn id(&self) -> usize;
fn len(&self) -> usize; fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
fn prefix(&self) -> Arc<str>; fn prefix(&self) -> Arc<str>;
fn candidates(&'a self, start: usize) -> Self::Candidates; fn candidates(&'a self, start: usize) -> Self::Candidates;
} }
@ -239,7 +242,7 @@ pub async fn match_strings(
if results.is_empty() { if results.is_empty() {
results = segment_result; results = segment_result;
} else { } else {
util::extend_sorted(&mut results, segment_result, max_results, |a, b| b.cmp(&a)); util::extend_sorted(&mut results, segment_result, max_results, |a, b| b.cmp(a));
} }
} }
results results
@ -299,7 +302,7 @@ pub async fn match_paths<'a, Set: PathMatchCandidateSet<'a>>(
candidate_set.prefix(), candidate_set.prefix(),
candidates, candidates,
results, results,
&cancel_flag, cancel_flag,
); );
} }
if tree_end >= segment_end { if tree_end >= segment_end {
@ -317,7 +320,7 @@ pub async fn match_paths<'a, Set: PathMatchCandidateSet<'a>>(
if results.is_empty() { if results.is_empty() {
results = segment_result; results = segment_result;
} else { } else {
util::extend_sorted(&mut results, segment_result, max_results, |a, b| b.cmp(&a)); util::extend_sorted(&mut results, segment_result, max_results, |a, b| b.cmp(a));
} }
} }
results results
@ -426,7 +429,7 @@ impl<'a> Matcher<'a> {
lowercase_candidate_chars.push(c.to_ascii_lowercase()); lowercase_candidate_chars.push(c.to_ascii_lowercase());
} }
if !self.find_last_positions(&lowercase_prefix, &lowercase_candidate_chars) { if !self.find_last_positions(lowercase_prefix, &lowercase_candidate_chars) {
continue; continue;
} }
@ -439,13 +442,13 @@ impl<'a> Matcher<'a> {
let score = self.score_match( let score = self.score_match(
&candidate_chars, &candidate_chars,
&lowercase_candidate_chars, &lowercase_candidate_chars,
&prefix, prefix,
&lowercase_prefix, lowercase_prefix,
); );
if score > 0.0 { if score > 0.0 {
let mut mat = build_match(&candidate, score); let mut mat = build_match(&candidate, score);
if let Err(i) = results.binary_search_by(|m| mat.cmp(&m)) { if let Err(i) = results.binary_search_by(|m| mat.cmp(m)) {
if results.len() < self.max_results { if results.len() < self.max_results {
mat.set_positions(self.match_positions.clone()); mat.set_positions(self.match_positions.clone());
results.insert(i, mat); results.insert(i, mat);
@ -523,6 +526,7 @@ impl<'a> Matcher<'a> {
score score
} }
#[allow(clippy::too_many_arguments)]
fn recursive_score_match( fn recursive_score_match(
&mut self, &mut self,
path: &[char], path: &[char],
@ -579,9 +583,9 @@ impl<'a> Matcher<'a> {
if last == '/' { if last == '/' {
char_score = 0.9; char_score = 0.9;
} else if last == '-' || last == '_' || last == ' ' || last.is_numeric() { } else if (last == '-' || last == '_' || last == ' ' || last.is_numeric())
char_score = 0.8; || (last.is_lowercase() && curr.is_uppercase())
} else if last.is_lowercase() && curr.is_uppercase() { {
char_score = 0.8; char_score = 0.8;
} else if last == '.' { } else if last == '.' {
char_score = 0.7; char_score = 0.7;
@ -662,18 +666,18 @@ mod tests {
let mut query: &[char] = &['d', 'c']; let mut query: &[char] = &['d', 'c'];
let mut matcher = Matcher::new(query, query, query.into(), false, 10); let mut matcher = Matcher::new(query, query, query.into(), false, 10);
let result = matcher.find_last_positions(&['a', 'b', 'c'], &['b', 'd', 'e', 'f']); let result = matcher.find_last_positions(&['a', 'b', 'c'], &['b', 'd', 'e', 'f']);
assert_eq!(result, false); assert!(!result);
query = &['c', 'd']; query = &['c', 'd'];
let mut matcher = Matcher::new(query, query, query.into(), false, 10); let mut matcher = Matcher::new(query, query, query.into(), false, 10);
let result = matcher.find_last_positions(&['a', 'b', 'c'], &['b', 'd', 'e', 'f']); let result = matcher.find_last_positions(&['a', 'b', 'c'], &['b', 'd', 'e', 'f']);
assert_eq!(result, true); assert!(result);
assert_eq!(matcher.last_positions, vec![2, 4]); assert_eq!(matcher.last_positions, vec![2, 4]);
query = &['z', '/', 'z', 'f']; query = &['z', '/', 'z', 'f'];
let mut matcher = Matcher::new(query, query, query.into(), false, 10); let mut matcher = Matcher::new(query, query, query.into(), false, 10);
let result = matcher.find_last_positions(&['z', 'e', 'd', '/'], &['z', 'e', 'd', '/', 'f']); let result = matcher.find_last_positions(&['z', 'e', 'd', '/'], &['z', 'e', 'd', '/', 'f']);
assert_eq!(result, true); assert!(result);
assert_eq!(matcher.last_positions, vec![0, 3, 4, 8]); assert_eq!(matcher.last_positions, vec![0, 3, 4, 8]);
} }
@ -741,7 +745,7 @@ mod tests {
fn match_query<'a>( fn match_query<'a>(
query: &str, query: &str,
smart_case: bool, smart_case: bool,
paths: &Vec<&'a str>, paths: &[&'a str],
) -> Vec<(&'a str, Vec<usize>)> { ) -> Vec<(&'a str, Vec<usize>)> {
let lowercase_query = query.to_lowercase().chars().collect::<Vec<_>>(); let lowercase_query = query.to_lowercase().chars().collect::<Vec<_>>();
let query = query.chars().collect::<Vec<_>>(); let query = query.chars().collect::<Vec<_>>();

View File

@ -41,7 +41,7 @@ fn compile_context_predicate_parser() {
.compile("tree_sitter_context_predicate"); .compile("tree_sitter_context_predicate");
} }
const SHADER_HEADER_PATH: &'static str = "./src/platform/mac/shaders/shaders.h"; const SHADER_HEADER_PATH: &str = "./src/platform/mac/shaders/shaders.h";
fn compile_metal_shaders() { fn compile_metal_shaders() {
let shader_path = "./src/platform/mac/shaders/shaders.metal"; let shader_path = "./src/platform/mac/shaders/shaders.metal";

View File

@ -85,11 +85,11 @@ impl gpui::Element for TextElement {
text, text,
font_size, font_size,
&[ &[
(1, normal.clone()), (1, normal),
(1, bold.clone()), (1, bold),
(1, normal.clone()), (1, normal),
(1, bold.clone()), (1, bold),
(text.len() - 4, normal.clone()), (text.len() - 4, normal),
], ],
); );

View File

@ -432,7 +432,7 @@ impl TestAppContext {
first_entity_id: usize, first_entity_id: usize,
) -> Self { ) -> Self {
let mut cx = MutableAppContext::new( let mut cx = MutableAppContext::new(
foreground.clone(), foreground,
background, background,
platform, platform,
foreground_platform.clone(), foreground_platform.clone(),
@ -964,6 +964,7 @@ pub struct MutableAppContext {
release_observations: Arc<Mutex<HashMap<usize, BTreeMap<usize, ReleaseObservationCallback>>>>, release_observations: Arc<Mutex<HashMap<usize, BTreeMap<usize, ReleaseObservationCallback>>>>,
action_dispatch_observations: Arc<Mutex<BTreeMap<usize, ActionObservationCallback>>>, action_dispatch_observations: Arc<Mutex<BTreeMap<usize, ActionObservationCallback>>>,
#[allow(clippy::type_complexity)]
presenters_and_platform_windows: presenters_and_platform_windows:
HashMap<usize, (Rc<RefCell<Presenter>>, Box<dyn platform::Window>)>, HashMap<usize, (Rc<RefCell<Presenter>>, Box<dyn platform::Window>)>,
foreground: Rc<executor::Foreground>, foreground: Rc<executor::Foreground>,
@ -1172,7 +1173,9 @@ impl MutableAppContext {
F: 'static + FnMut(&mut V, &A, &mut ViewContext<V>) -> Option<Task<Result<()>>>, F: 'static + FnMut(&mut V, &A, &mut ViewContext<V>) -> Option<Task<Result<()>>>,
{ {
self.add_action(move |view, action, cx| { self.add_action(move |view, action, cx| {
handler(view, action, cx).map(|task| task.detach_and_log_err(cx)); if let Some(task) = handler(view, action, cx) {
task.detach_and_log_err(cx);
}
}) })
} }
@ -1240,7 +1243,7 @@ impl MutableAppContext {
.cx .cx
.views .views
.remove(&(window_id, view_id)) .remove(&(window_id, view_id))
.ok_or(anyhow!("view not found"))?; .ok_or_else(|| anyhow!("view not found"))?;
let element = view.render(params, self); let element = view.render(params, self);
self.cx.views.insert((window_id, view_id), view); self.cx.views.insert((window_id, view_id), view);
Ok(element) Ok(element)
@ -1252,6 +1255,7 @@ impl MutableAppContext {
titlebar_height: f32, titlebar_height: f32,
) -> HashMap<usize, ElementBox> { ) -> HashMap<usize, ElementBox> {
self.start_frame(); self.start_frame();
#[allow(clippy::needless_collect)]
let view_ids = self let view_ids = self
.views .views
.keys() .keys()
@ -1263,6 +1267,7 @@ impl MutableAppContext {
} }
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
view_ids view_ids
.into_iter() .into_iter()
.map(|view_id| { .map(|view_id| {
@ -2401,7 +2406,7 @@ impl MutableAppContext {
let mut invalidation = self let mut invalidation = self
.cx .cx
.windows .windows
.get_mut(&window_id) .get_mut(window_id)
.unwrap() .unwrap()
.invalidation .invalidation
.take(); .take();
@ -2626,7 +2631,7 @@ impl MutableAppContext {
fn handle_action_dispatch_notification_effect(&mut self, action_id: TypeId) { fn handle_action_dispatch_notification_effect(&mut self, action_id: TypeId) {
let mut callbacks = mem::take(&mut *self.action_dispatch_observations.lock()); let mut callbacks = mem::take(&mut *self.action_dispatch_observations.lock());
for (_, callback) in &mut callbacks { for callback in callbacks.values_mut() {
callback(action_id, self); callback(action_id, self);
} }
self.action_dispatch_observations.lock().extend(callbacks); self.action_dispatch_observations.lock().extend(callbacks);
@ -3228,7 +3233,7 @@ pub trait AnyView {
cx: &mut MutableAppContext, cx: &mut MutableAppContext,
) -> Option<Pin<Box<dyn 'static + Future<Output = ()>>>>; ) -> Option<Pin<Box<dyn 'static + Future<Output = ()>>>>;
fn ui_name(&self) -> &'static str; fn ui_name(&self) -> &'static str;
fn render<'a>(&mut self, params: RenderParams, cx: &mut MutableAppContext) -> ElementBox; fn render(&mut self, params: RenderParams, cx: &mut MutableAppContext) -> ElementBox;
fn on_focus_in( fn on_focus_in(
&mut self, &mut self,
cx: &mut MutableAppContext, cx: &mut MutableAppContext,
@ -3304,7 +3309,7 @@ where
T::ui_name() T::ui_name()
} }
fn render<'a>(&mut self, params: RenderParams, cx: &mut MutableAppContext) -> ElementBox { fn render(&mut self, params: RenderParams, cx: &mut MutableAppContext) -> ElementBox {
View::render(self, &mut RenderContext::new(params, cx)) View::render(self, &mut RenderContext::new(params, cx))
} }
@ -3611,7 +3616,7 @@ impl<M> Deref for ModelContext<'_, M> {
type Target = MutableAppContext; type Target = MutableAppContext;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.app self.app
} }
} }
@ -4140,7 +4145,7 @@ impl<M> Deref for ViewContext<'_, M> {
type Target = MutableAppContext; type Target = MutableAppContext;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.app self.app
} }
} }
@ -4290,7 +4295,7 @@ impl<T: Entity> ModelHandle<T> {
cx.read_model(self) cx.read_model(self)
} }
pub fn read_with<'a, C, F, S>(&self, cx: &C, read: F) -> S pub fn read_with<C, F, S>(&self, cx: &C, read: F) -> S
where where
C: ReadModelWith, C: ReadModelWith,
F: FnOnce(&T, &AppContext) -> S, F: FnOnce(&T, &AppContext) -> S,
@ -4381,7 +4386,6 @@ impl<T: Entity> ModelHandle<T> {
} }
}), }),
cx.subscribe(self, { cx.subscribe(self, {
let tx = tx.clone();
move |_, _, _| { move |_, _, _| {
tx.unbounded_send(()).ok(); tx.unbounded_send(()).ok();
} }
@ -5258,6 +5262,7 @@ pub enum Subscription {
ReleaseObservation { ReleaseObservation {
id: usize, id: usize,
entity_id: usize, entity_id: usize,
#[allow(clippy::type_complexity)]
observations: observations:
Option<Weak<Mutex<HashMap<usize, BTreeMap<usize, ReleaseObservationCallback>>>>>, Option<Weak<Mutex<HashMap<usize, BTreeMap<usize, ReleaseObservationCallback>>>>>,
}, },
@ -5407,7 +5412,7 @@ impl Drop for Subscription {
} }
Subscription::ActionObservation { id, observations } => { Subscription::ActionObservation { id, observations } => {
if let Some(observations) = observations.as_ref().and_then(Weak::upgrade) { if let Some(observations) = observations.as_ref().and_then(Weak::upgrade) {
observations.lock().remove(&id); observations.lock().remove(id);
} }
} }
Subscription::WindowActivationObservation { Subscription::WindowActivationObservation {
@ -5465,6 +5470,7 @@ lazy_static! {
#[derive(Default)] #[derive(Default)]
pub struct LeakDetector { pub struct LeakDetector {
next_handle_id: usize, next_handle_id: usize,
#[allow(clippy::type_complexity)]
handle_backtraces: HashMap< handle_backtraces: HashMap<
usize, usize,
( (
@ -5502,12 +5508,10 @@ impl LeakDetector {
pub fn assert_dropped(&mut self, entity_id: usize) { pub fn assert_dropped(&mut self, entity_id: usize) {
if let Some((type_name, backtraces)) = self.handle_backtraces.get_mut(&entity_id) { if let Some((type_name, backtraces)) = self.handle_backtraces.get_mut(&entity_id) {
for trace in backtraces.values_mut() { for trace in backtraces.values_mut().flatten() {
if let Some(trace) = trace {
trace.resolve(); trace.resolve();
eprintln!("{:?}", crate::util::CwdBacktrace(trace)); eprintln!("{:?}", crate::util::CwdBacktrace(trace));
} }
}
let hint = if *LEAK_BACKTRACE { let hint = if *LEAK_BACKTRACE {
"" ""
@ -5534,12 +5538,10 @@ impl LeakDetector {
type_name.unwrap_or("entity"), type_name.unwrap_or("entity"),
id id
); );
for trace in backtraces.values_mut() { for trace in backtraces.values_mut().flatten() {
if let Some(trace) = trace {
trace.resolve(); trace.resolve();
eprintln!("{:?}", crate::util::CwdBacktrace(trace)); eprintln!("{:?}", crate::util::CwdBacktrace(trace));
} }
}
found_leaks = true; found_leaks = true;
} }
@ -6586,7 +6588,7 @@ mod tests {
let subscription = subscription.clone(); let subscription = subscription.clone();
move |_, _, e, _| { move |_, _, e, _| {
subscription.borrow_mut().take(); subscription.borrow_mut().take();
events.borrow_mut().push(e.clone()); events.borrow_mut().push(*e);
} }
})); }));
}); });
@ -7158,8 +7160,8 @@ mod tests {
let model = cx.add_model(|_| Counter(0)); let model = cx.add_model(|_| Counter(0));
let condition1 = model.condition(&cx, |model, _| model.0 == 2); let condition1 = model.condition(cx, |model, _| model.0 == 2);
let condition2 = model.condition(&cx, |model, _| model.0 == 3); let condition2 = model.condition(cx, |model, _| model.0 == 3);
smol::pin!(condition1, condition2); smol::pin!(condition1, condition2);
model.update(cx, |model, cx| model.inc(cx)); model.update(cx, |model, cx| model.inc(cx));
@ -7186,7 +7188,7 @@ mod tests {
} }
let model = cx.add_model(|_| Model); let model = cx.add_model(|_| Model);
model.condition(&cx, |_, _| false).await; model.condition(cx, |_, _| false).await;
} }
#[crate::test(self)] #[crate::test(self)]
@ -7199,7 +7201,7 @@ mod tests {
} }
let model = cx.add_model(|_| Model); let model = cx.add_model(|_| Model);
let condition = model.condition(&cx, |_, _| false); let condition = model.condition(cx, |_, _| false);
cx.update(|_| drop(model)); cx.update(|_| drop(model));
condition.await; condition.await;
} }
@ -7231,8 +7233,8 @@ mod tests {
let (_, view) = cx.add_window(|_| Counter(0)); let (_, view) = cx.add_window(|_| Counter(0));
let condition1 = view.condition(&cx, |view, _| view.0 == 2); let condition1 = view.condition(cx, |view, _| view.0 == 2);
let condition2 = view.condition(&cx, |view, _| view.0 == 3); let condition2 = view.condition(cx, |view, _| view.0 == 3);
smol::pin!(condition1, condition2); smol::pin!(condition1, condition2);
view.update(cx, |view, cx| view.inc(cx)); view.update(cx, |view, cx| view.inc(cx));
@ -7268,7 +7270,7 @@ mod tests {
} }
let (_, view) = cx.add_window(|_| View); let (_, view) = cx.add_window(|_| View);
view.condition(&cx, |_, _| false).await; view.condition(cx, |_, _| false).await;
} }
#[crate::test(self)] #[crate::test(self)]
@ -7293,7 +7295,7 @@ mod tests {
let (_, root_view) = cx.add_window(|_| View); let (_, root_view) = cx.add_window(|_| View);
let view = cx.add_view(&root_view, |_| View); let view = cx.add_view(&root_view, |_| View);
let condition = view.condition(&cx, |_, _| false); let condition = view.condition(cx, |_, _| false);
cx.update(|_| drop(view)); cx.update(|_| drop(view));
condition.await; condition.await;
} }

View File

@ -389,9 +389,9 @@ impl ElementBox {
} }
} }
impl Into<ElementRc> for ElementBox { impl From<ElementBox> for ElementRc {
fn into(self) -> ElementRc { fn from(val: ElementBox) -> Self {
self.0 val.0
} }
} }

View File

@ -11,13 +11,14 @@ use crate::{
}; };
use crate::{Element, Event, EventContext, LayoutContext, PaintContext, SizeConstraint}; use crate::{Element, Event, EventContext, LayoutContext, PaintContext, SizeConstraint};
#[derive(Default)]
pub struct Empty { pub struct Empty {
collapsed: bool, collapsed: bool,
} }
impl Empty { impl Empty {
pub fn new() -> Self { pub fn new() -> Self {
Self { collapsed: false } Self::default()
} }
pub fn collapsed(mut self) -> Self { pub fn collapsed(mut self) -> Self {

View File

@ -24,13 +24,13 @@ impl Expanded {
} }
} }
pub fn to_full_width(mut self) -> Self { pub fn full_width(mut self) -> Self {
self.full_width = true; self.full_width = true;
self.full_height = false; self.full_height = false;
self self
} }
pub fn to_full_height(mut self) -> Self { pub fn full_height(mut self) -> Self {
self.full_width = false; self.full_width = false;
self.full_height = true; self.full_height = true;
self self

View File

@ -53,8 +53,8 @@ impl Element for Image {
_: &mut LayoutContext, _: &mut LayoutContext,
) -> (Vector2F, Self::LayoutState) { ) -> (Vector2F, Self::LayoutState) {
let desired_size = vec2f( let desired_size = vec2f(
self.style.width.unwrap_or(constraint.max.x()), self.style.width.unwrap_or_else(|| constraint.max.x()),
self.style.height.unwrap_or(constraint.max.y()), self.style.height.unwrap_or_else(|| constraint.max.y()),
); );
let size = constrain_size_preserving_aspect_ratio( let size = constrain_size_preserving_aspect_ratio(
constraint.constrain(desired_size), constraint.constrain(desired_size),

View File

@ -33,6 +33,7 @@ struct StateInner {
logical_scroll_top: Option<ListOffset>, logical_scroll_top: Option<ListOffset>,
orientation: Orientation, orientation: Orientation,
overdraw: f32, overdraw: f32,
#[allow(clippy::type_complexity)]
scroll_handler: Option<Box<dyn FnMut(Range<usize>, &mut EventContext)>>, scroll_handler: Option<Box<dyn FnMut(Range<usize>, &mut EventContext)>>,
} }
@ -311,20 +312,18 @@ impl Element for List {
drop(cursor); drop(cursor);
state.items = new_items; state.items = new_items;
match event { if let Event::ScrollWheel(ScrollWheelEvent {
Event::ScrollWheel(ScrollWheelEvent {
position, position,
delta, delta,
precise, precise,
}) => { }) = event
if bounds.contains_point(*position) { {
if state.scroll(scroll_top, bounds.height(), *delta, *precise, cx) { if bounds.contains_point(*position)
&& state.scroll(scroll_top, bounds.height(), *delta, *precise, cx)
{
handled = true; handled = true;
} }
} }
}
_ => {}
}
handled handled
} }

View File

@ -129,7 +129,7 @@ impl Element for MouseEventHandler {
cx.scene.push_mouse_region(MouseRegion::from_handlers( cx.scene.push_mouse_region(MouseRegion::from_handlers(
cx.current_view_id(), cx.current_view_id(),
Some(self.discriminant.clone()), Some(self.discriminant),
hit_bounds, hit_bounds,
self.handlers.clone(), self.handlers.clone(),
)); ));

View File

@ -74,7 +74,7 @@ impl Element for Overlay {
size: &mut Self::LayoutState, size: &mut Self::LayoutState,
cx: &mut PaintContext, cx: &mut PaintContext,
) { ) {
let mut bounds = RectF::new(self.abs_position.unwrap_or(bounds.origin()), *size); let mut bounds = RectF::new(self.abs_position.unwrap_or_else(|| bounds.origin()), *size);
cx.scene.push_stacking_context(None); cx.scene.push_stacking_context(None);
if self.hoverable { if self.hoverable {

View File

@ -8,15 +8,14 @@ use crate::{
SizeConstraint, SizeConstraint,
}; };
#[derive(Default)]
pub struct Stack { pub struct Stack {
children: Vec<ElementBox>, children: Vec<ElementBox>,
} }
impl Stack { impl Stack {
pub fn new() -> Self { pub fn new() -> Self {
Stack { Self::default()
children: Vec::new(),
}
} }
} }

View File

@ -100,7 +100,7 @@ impl Element for Text {
chunks, chunks,
&self.style, &self.style,
cx.text_layout_cache, cx.text_layout_cache,
&cx.font_cache, cx.font_cache,
usize::MAX, usize::MAX,
self.text.matches('\n').count() + 1, self.text.matches('\n').count() + 1,
); );

View File

@ -45,6 +45,7 @@ pub struct LayoutState {
pub struct UniformList { pub struct UniformList {
state: UniformListState, state: UniformListState,
item_count: usize, item_count: usize,
#[allow(clippy::type_complexity)]
append_items: Box<dyn Fn(Range<usize>, &mut Vec<ElementBox>, &mut LayoutContext)>, append_items: Box<dyn Fn(Range<usize>, &mut Vec<ElementBox>, &mut LayoutContext)>,
padding_top: f32, padding_top: f32,
padding_bottom: f32, padding_bottom: f32,
@ -310,20 +311,18 @@ impl Element for UniformList {
handled = item.dispatch_event(event, cx) || handled; handled = item.dispatch_event(event, cx) || handled;
} }
match event { if let Event::ScrollWheel(ScrollWheelEvent {
Event::ScrollWheel(ScrollWheelEvent {
position, position,
delta, delta,
precise, precise,
}) => { }) = event
if bounds.contains_point(*position) { {
if self.scroll(*position, *delta, *precise, layout.scroll_max, cx) { if bounds.contains_point(*position)
&& self.scroll(*position, *delta, *precise, layout.scroll_max, cx)
{
handled = true; handled = true;
} }
} }
}
_ => {}
}
handled handled
} }

View File

@ -332,7 +332,7 @@ impl Deterministic {
pub fn now(&self) -> std::time::Instant { pub fn now(&self) -> std::time::Instant {
let state = self.state.lock(); let state = self.state.lock();
state.now.clone() state.now
} }
pub fn advance_clock(&self, duration: Duration) { pub fn advance_clock(&self, duration: Duration) {
@ -681,6 +681,12 @@ impl Background {
} }
} }
impl Default for Background {
fn default() -> Self {
Self::new()
}
}
pub struct Scope<'a> { pub struct Scope<'a> {
executor: Arc<Background>, executor: Arc<Background>,
futures: Vec<Pin<Box<dyn Future<Output = ()> + Send + 'static>>>, futures: Vec<Pin<Box<dyn Future<Output = ()> + Send + 'static>>>,

View File

@ -117,7 +117,7 @@ impl FontCache {
.font_selections .font_selections
.entry(family_id) .entry(family_id)
.or_default() .or_default()
.insert(properties.clone(), font_id); .insert(*properties, font_id);
Ok(font_id) Ok(font_id)
} }
} }
@ -257,10 +257,10 @@ mod tests {
let arial = fonts.load_family(&["Arial"]).unwrap(); let arial = fonts.load_family(&["Arial"]).unwrap();
let arial_regular = fonts.select_font(arial, &Properties::new()).unwrap(); let arial_regular = fonts.select_font(arial, &Properties::new()).unwrap();
let arial_italic = fonts let arial_italic = fonts
.select_font(arial, &Properties::new().style(Style::Italic)) .select_font(arial, Properties::new().style(Style::Italic))
.unwrap(); .unwrap();
let arial_bold = fonts let arial_bold = fonts
.select_font(arial, &Properties::new().weight(Weight::BOLD)) .select_font(arial, Properties::new().weight(Weight::BOLD))
.unwrap(); .unwrap();
assert_ne!(arial_regular, arial_italic); assert_ne!(arial_regular, arial_italic);
assert_ne!(arial_regular, arial_bold); assert_ne!(arial_regular, arial_bold);

View File

@ -332,8 +332,7 @@ impl<'de> Deserialize<'de> for TextStyle {
where where
D: serde::Deserializer<'de>, D: serde::Deserializer<'de>,
{ {
Ok(Self::from_json(TextStyleJson::deserialize(deserializer)?) Self::from_json(TextStyleJson::deserialize(deserializer)?).map_err(de::Error::custom)
.map_err(|e| de::Error::custom(e))?)
} }
} }

View File

@ -19,6 +19,12 @@ enum PathVertexKind {
Quadratic, Quadratic,
} }
impl Default for PathBuilder {
fn default() -> Self {
PathBuilder::new()
}
}
impl PathBuilder { impl PathBuilder {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
@ -58,10 +64,7 @@ impl PathBuilder {
pub fn build(mut self, color: Color, clip_bounds: Option<RectF>) -> Path { pub fn build(mut self, color: Color, clip_bounds: Option<RectF>) -> Path {
if let Some(clip_bounds) = clip_bounds { if let Some(clip_bounds) = clip_bounds {
self.bounds = self self.bounds = self.bounds.intersection(clip_bounds).unwrap_or_default();
.bounds
.intersection(clip_bounds)
.unwrap_or(RectF::default());
} }
Path { Path {
bounds: self.bounds, bounds: self.bounds,

View File

@ -202,7 +202,7 @@ impl Keymap {
for (ix, binding) in bindings.iter().enumerate() { for (ix, binding) in bindings.iter().enumerate() {
binding_indices_by_action_type binding_indices_by_action_type
.entry(binding.action.as_any().type_id()) .entry(binding.action.as_any().type_id())
.or_insert_with(|| SmallVec::new()) .or_insert_with(SmallVec::new)
.push(ix); .push(ix);
} }
Self { Self {
@ -211,10 +211,7 @@ impl Keymap {
} }
} }
fn bindings_for_action_type<'a>( fn bindings_for_action_type(&self, action_type: TypeId) -> impl Iterator<Item = &'_ Binding> {
&'a self,
action_type: TypeId,
) -> impl Iterator<Item = &'a Binding> {
self.binding_indices_by_action_type self.binding_indices_by_action_type
.get(&action_type) .get(&action_type)
.map(SmallVec::as_slice) .map(SmallVec::as_slice)
@ -253,7 +250,7 @@ impl Binding {
let keystrokes = keystrokes let keystrokes = keystrokes
.split_whitespace() .split_whitespace()
.map(|key| Keystroke::parse(key)) .map(Keystroke::parse)
.collect::<Result<_>>()?; .collect::<Result<_>>()?;
Ok(Self { Ok(Self {
@ -281,7 +278,7 @@ impl Keystroke {
let mut function = false; let mut function = false;
let mut key = None; let mut key = None;
let mut components = source.split("-").peekable(); let mut components = source.split('-').peekable();
while let Some(component) = components.next() { while let Some(component) = components.next() {
match component { match component {
"ctrl" => ctrl = true, "ctrl" => ctrl = true,
@ -379,12 +376,12 @@ impl ContextPredicate {
let kind = node.kind(); let kind = node.kind();
match kind { match kind {
"source" => Self::from_node(node.child(0).ok_or(anyhow!(parse_error))?, source), "source" => Self::from_node(node.child(0).ok_or_else(|| anyhow!(parse_error))?, source),
"identifier" => Ok(Self::Identifier(node.utf8_text(source)?.into())), "identifier" => Ok(Self::Identifier(node.utf8_text(source)?.into())),
"not" => { "not" => {
let child = Self::from_node( let child = Self::from_node(
node.child_by_field_name("expression") node.child_by_field_name("expression")
.ok_or(anyhow!(parse_error))?, .ok_or_else(|| anyhow!(parse_error))?,
source, source,
)?; )?;
Ok(Self::Not(Box::new(child))) Ok(Self::Not(Box::new(child)))
@ -392,12 +389,12 @@ impl ContextPredicate {
"and" | "or" => { "and" | "or" => {
let left = Box::new(Self::from_node( let left = Box::new(Self::from_node(
node.child_by_field_name("left") node.child_by_field_name("left")
.ok_or(anyhow!(parse_error))?, .ok_or_else(|| anyhow!(parse_error))?,
source, source,
)?); )?);
let right = Box::new(Self::from_node( let right = Box::new(Self::from_node(
node.child_by_field_name("right") node.child_by_field_name("right")
.ok_or(anyhow!(parse_error))?, .ok_or_else(|| anyhow!(parse_error))?,
source, source,
)?); )?);
if kind == "and" { if kind == "and" {
@ -409,12 +406,12 @@ impl ContextPredicate {
"equal" | "not_equal" => { "equal" | "not_equal" => {
let left = node let left = node
.child_by_field_name("left") .child_by_field_name("left")
.ok_or(anyhow!(parse_error))? .ok_or_else(|| anyhow!(parse_error))?
.utf8_text(source)? .utf8_text(source)?
.into(); .into();
let right = node let right = node
.child_by_field_name("right") .child_by_field_name("right")
.ok_or(anyhow!(parse_error))? .ok_or_else(|| anyhow!(parse_error))?
.utf8_text(source)? .utf8_text(source)?
.into(); .into();
if kind == "equal" { if kind == "equal" {
@ -425,7 +422,7 @@ impl ContextPredicate {
} }
"parenthesized" => Self::from_node( "parenthesized" => Self::from_node(
node.child_by_field_name("expression") node.child_by_field_name("expression")
.ok_or(anyhow!(parse_error))?, .ok_or_else(|| anyhow!(parse_error))?,
source, source,
), ),
_ => Err(anyhow!(parse_error)), _ => Err(anyhow!(parse_error)),
@ -604,7 +601,7 @@ mod tests {
Ok(()) Ok(())
} }
fn downcast<'a, A: Action>(action: &'a Option<Box<dyn Action>>) -> Option<&'a A> { fn downcast<A: Action>(action: &Option<Box<dyn Action>>) -> Option<&A> {
action action
.as_ref() .as_ref()
.and_then(|action| action.as_any().downcast_ref()) .and_then(|action| action.as_any().downcast_ref())

View File

@ -74,7 +74,7 @@ pub(crate) trait ForegroundPlatform {
fn on_quit(&self, callback: Box<dyn FnMut()>); fn on_quit(&self, callback: Box<dyn FnMut()>);
fn on_event(&self, callback: Box<dyn FnMut(Event) -> bool>); fn on_event(&self, callback: Box<dyn FnMut(Event) -> bool>);
fn on_open_urls(&self, callback: Box<dyn FnMut(Vec<String>)>); fn on_open_urls(&self, callback: Box<dyn FnMut(Vec<String>)>);
fn run(&self, on_finish_launching: Box<dyn FnOnce() -> ()>); fn run(&self, on_finish_launching: Box<dyn FnOnce()>);
fn on_menu_command(&self, callback: Box<dyn FnMut(&dyn Action)>); fn on_menu_command(&self, callback: Box<dyn FnMut(&dyn Action)>);
fn on_validate_menu_command(&self, callback: Box<dyn FnMut(&dyn Action) -> bool>); fn on_validate_menu_command(&self, callback: Box<dyn FnMut(&dyn Action) -> bool>);

View File

@ -223,7 +223,7 @@ unsafe fn parse_keystroke(native_event: id) -> Keystroke {
let cmd = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); let cmd = 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| {
ch < NSUpArrowFunctionKey || ch > NSModeSwitchFunctionKey !(NSUpArrowFunctionKey..=NSModeSwitchFunctionKey).contains(&ch)
}); });
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]

View File

@ -53,6 +53,12 @@ impl FontSystem {
} }
} }
impl Default for FontSystem {
fn default() -> Self {
Self::new()
}
}
impl platform::FontSystem for FontSystem { impl platform::FontSystem for FontSystem {
fn add_fonts(&self, fonts: &[Arc<Vec<u8>>]) -> anyhow::Result<()> { fn add_fonts(&self, fonts: &[Arc<Vec<u8>>]) -> anyhow::Result<()> {
self.0.write().add_fonts(fonts) self.0.write().add_fonts(fonts)
@ -402,7 +408,7 @@ impl FontSystemState {
fn wrap_line(&self, text: &str, font_id: FontId, font_size: f32, width: f32) -> Vec<usize> { fn wrap_line(&self, text: &str, font_id: FontId, font_size: f32, width: f32) -> Vec<usize> {
let mut string = CFMutableAttributedString::new(); let mut string = CFMutableAttributedString::new();
string.replace_str(&CFString::new(text), CFRange::init(0, 0)); string.replace_str(&CFString::new(text), CFRange::init(0, 0));
let cf_range = CFRange::init(0 as isize, text.encode_utf16().count() as isize); let cf_range = CFRange::init(0, text.encode_utf16().count() as isize);
let font = &self.fonts[font_id.0]; let font = &self.fonts[font_id.0];
unsafe { unsafe {
string.set_attribute( string.set_attribute(
@ -505,14 +511,14 @@ mod tests {
}; };
let menlo_italic = RunStyle { let menlo_italic = RunStyle {
font_id: fonts font_id: fonts
.select_font(&menlo, &Properties::new().style(Style::Italic)) .select_font(&menlo, Properties::new().style(Style::Italic))
.unwrap(), .unwrap(),
color: Default::default(), color: Default::default(),
underline: Default::default(), underline: Default::default(),
}; };
let menlo_bold = RunStyle { let menlo_bold = RunStyle {
font_id: fonts font_id: fonts
.select_font(&menlo, &Properties::new().weight(Weight::BOLD)) .select_font(&menlo, Properties::new().weight(Weight::BOLD))
.unwrap(), .unwrap(),
color: Default::default(), color: Default::default(),
underline: Default::default(), underline: Default::default(),
@ -599,7 +605,7 @@ mod tests {
let name = format!("/Users/as-cii/Desktop/twog-{}.png", i); let name = format!("/Users/as-cii/Desktop/twog-{}.png", i);
let path = Path::new(&name); let path = Path::new(&name);
let file = File::create(path).unwrap(); let file = File::create(path).unwrap();
let ref mut w = BufWriter::new(file); let w = &mut BufWriter::new(file);
let mut encoder = png::Encoder::new(w, bounds.width() as u32, bounds.height() as u32); let mut encoder = png::Encoder::new(w, bounds.width() as u32, bounds.height() as u32);
encoder.set_color(png::ColorType::Grayscale); encoder.set_color(png::ColorType::Grayscale);

View File

@ -50,7 +50,7 @@ use time::UtcOffset;
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
const NSUTF8StringEncoding: NSUInteger = 4; const NSUTF8StringEncoding: NSUInteger = 4;
const MAC_PLATFORM_IVAR: &'static str = "platform"; const MAC_PLATFORM_IVAR: &str = "platform";
static mut APP_CLASS: *const Class = ptr::null(); static mut APP_CLASS: *const Class = ptr::null();
static mut APP_DELEGATE_CLASS: *const Class = ptr::null(); static mut APP_DELEGATE_CLASS: *const Class = ptr::null();
@ -118,7 +118,7 @@ pub struct MacForegroundPlatformState {
validate_menu_command: Option<Box<dyn FnMut(&dyn Action) -> bool>>, validate_menu_command: Option<Box<dyn FnMut(&dyn Action) -> bool>>,
will_open_menu: Option<Box<dyn FnMut()>>, will_open_menu: Option<Box<dyn FnMut()>>,
open_urls: Option<Box<dyn FnMut(Vec<String>)>>, open_urls: Option<Box<dyn FnMut(Vec<String>)>>,
finish_launching: Option<Box<dyn FnOnce() -> ()>>, finish_launching: Option<Box<dyn FnOnce()>>,
menu_actions: Vec<Box<dyn Action>>, menu_actions: Vec<Box<dyn Action>>,
} }
@ -277,7 +277,7 @@ impl platform::ForegroundPlatform for MacForegroundPlatform {
self.0.borrow_mut().open_urls = Some(callback); self.0.borrow_mut().open_urls = Some(callback);
} }
fn run(&self, on_finish_launching: Box<dyn FnOnce() -> ()>) { fn run(&self, on_finish_launching: Box<dyn FnOnce()>) {
self.0.borrow_mut().finish_launching = Some(on_finish_launching); self.0.borrow_mut().finish_launching = Some(on_finish_launching);
unsafe { unsafe {
@ -533,7 +533,7 @@ impl platform::Platform for MacPlatform {
fn read_from_clipboard(&self) -> Option<ClipboardItem> { fn read_from_clipboard(&self) -> Option<ClipboardItem> {
unsafe { unsafe {
if let Some(text_bytes) = self.read_from_pasteboard(NSPasteboardTypeString) { if let Some(text_bytes) = self.read_from_pasteboard(NSPasteboardTypeString) {
let text = String::from_utf8_lossy(&text_bytes).to_string(); let text = String::from_utf8_lossy(text_bytes).to_string();
let hash_bytes = self let hash_bytes = self
.read_from_pasteboard(self.text_hash_pasteboard_type) .read_from_pasteboard(self.text_hash_pasteboard_type)
.and_then(|bytes| bytes.try_into().ok()) .and_then(|bytes| bytes.try_into().ok())

View File

@ -14,8 +14,7 @@ use metal::{MTLPixelFormat, MTLResourceOptions, NSRange};
use shaders::ToFloat2 as _; use shaders::ToFloat2 as _;
use std::{collections::HashMap, ffi::c_void, iter::Peekable, mem, sync::Arc, vec}; use std::{collections::HashMap, ffi::c_void, iter::Peekable, mem, sync::Arc, vec};
const SHADERS_METALLIB: &'static [u8] = const SHADERS_METALLIB: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib"));
include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib"));
const INSTANCE_BUFFER_SIZE: usize = 8192 * 1024; // This is an arbitrary decision. There's probably a more optimal value. const INSTANCE_BUFFER_SIZE: usize = 8192 * 1024; // This is an arbitrary decision. There's probably a more optimal value.
pub struct Renderer { pub struct Renderer {
@ -385,10 +384,10 @@ impl Renderer {
drawable_size: Vector2F, drawable_size: Vector2F,
command_encoder: &metal::RenderCommandEncoderRef, command_encoder: &metal::RenderCommandEncoderRef,
) { ) {
let clip_bounds = (layer.clip_bounds().unwrap_or(RectF::new( let clip_bounds = (layer
vec2f(0., 0.), .clip_bounds()
drawable_size / scene.scale_factor(), .unwrap_or_else(|| RectF::new(vec2f(0., 0.), drawable_size / scene.scale_factor()))
)) * scene.scale_factor()) * scene.scale_factor())
.round(); .round();
command_encoder.set_scissor_rect(metal::MTLScissorRect { command_encoder.set_scissor_rect(metal::MTLScissorRect {
x: clip_bounds.origin_x() as NSUInteger, x: clip_bounds.origin_x() as NSUInteger,
@ -438,8 +437,7 @@ impl Renderer {
); );
let buffer_contents = unsafe { let buffer_contents = unsafe {
(self.instances.contents() as *mut u8).offset(*offset as isize) (self.instances.contents() as *mut u8).add(*offset) as *mut shaders::GPUIShadow
as *mut shaders::GPUIShadow
}; };
for (ix, shadow) in shadows.iter().enumerate() { for (ix, shadow) in shadows.iter().enumerate() {
let shape_bounds = shadow.bounds * scale_factor; let shape_bounds = shadow.bounds * scale_factor;
@ -451,7 +449,7 @@ impl Renderer {
color: shadow.color.to_uchar4(), color: shadow.color.to_uchar4(),
}; };
unsafe { unsafe {
*(buffer_contents.offset(ix as isize)) = shader_shadow; *(buffer_contents.add(ix)) = shader_shadow;
} }
} }
@ -503,8 +501,7 @@ impl Renderer {
); );
let buffer_contents = unsafe { let buffer_contents = unsafe {
(self.instances.contents() as *mut u8).offset(*offset as isize) (self.instances.contents() as *mut u8).add(*offset) as *mut shaders::GPUIQuad
as *mut shaders::GPUIQuad
}; };
for (ix, quad) in quads.iter().enumerate() { for (ix, quad) in quads.iter().enumerate() {
let bounds = quad.bounds * scale_factor; let bounds = quad.bounds * scale_factor;
@ -514,7 +511,7 @@ impl Renderer {
size: bounds.size().round().to_float2(), size: bounds.size().round().to_float2(),
background_color: quad background_color: quad
.background .background
.unwrap_or(Color::transparent_black()) .unwrap_or_else(Color::transparent_black)
.to_uchar4(), .to_uchar4(),
border_top: border_width * (quad.border.top as usize as f32), border_top: border_width * (quad.border.top as usize as f32),
border_right: border_width * (quad.border.right as usize as f32), border_right: border_width * (quad.border.right as usize as f32),
@ -524,7 +521,7 @@ impl Renderer {
corner_radius: quad.corner_radius * scale_factor, corner_radius: quad.corner_radius * scale_factor,
}; };
unsafe { unsafe {
*(buffer_contents.offset(ix as isize)) = shader_quad; *(buffer_contents.add(ix)) = shader_quad;
} }
} }
@ -641,9 +638,8 @@ impl Renderer {
); );
unsafe { unsafe {
let buffer_contents = (self.instances.contents() as *mut u8) let buffer_contents =
.offset(*offset as isize) (self.instances.contents() as *mut u8).add(*offset) as *mut shaders::GPUISprite;
as *mut shaders::GPUISprite;
std::ptr::copy_nonoverlapping(sprites.as_ptr(), buffer_contents, sprites.len()); std::ptr::copy_nonoverlapping(sprites.as_ptr(), buffer_contents, sprites.len());
} }
@ -757,9 +753,8 @@ impl Renderer {
); );
unsafe { unsafe {
let buffer_contents = (self.instances.contents() as *mut u8) let buffer_contents =
.offset(*offset as isize) (self.instances.contents() as *mut u8).add(*offset) as *mut shaders::GPUIImage;
as *mut shaders::GPUIImage;
std::ptr::copy_nonoverlapping(images.as_ptr(), buffer_contents, images.len()); std::ptr::copy_nonoverlapping(images.as_ptr(), buffer_contents, images.len());
} }
@ -821,10 +816,9 @@ impl Renderer {
} }
unsafe { unsafe {
let buffer_contents = (self.instances.contents() as *mut u8) let buffer_contents =
.offset(*offset as isize) (self.instances.contents() as *mut u8).add(*offset) as *mut shaders::GPUISprite;
as *mut shaders::GPUISprite; *buffer_contents.add(atlas_sprite_count) = sprite.shader_data;
*buffer_contents.offset(atlas_sprite_count as isize) = sprite.shader_data;
} }
atlas_sprite_count += 1; atlas_sprite_count += 1;
@ -917,8 +911,7 @@ impl Renderer {
); );
let buffer_contents = unsafe { let buffer_contents = unsafe {
(self.instances.contents() as *mut u8).offset(*offset as isize) (self.instances.contents() as *mut u8).add(*offset) as *mut shaders::GPUIUnderline
as *mut shaders::GPUIUnderline
}; };
for (ix, underline) in underlines.iter().enumerate() { for (ix, underline) in underlines.iter().enumerate() {
let origin = underline.origin * scale_factor; let origin = underline.origin * scale_factor;
@ -935,7 +928,7 @@ impl Renderer {
squiggly: underline.squiggly as u8, squiggly: underline.squiggly as u8,
}; };
unsafe { unsafe {
*(buffer_contents.offset(ix as isize)) = shader_underline; *(buffer_contents.add(ix)) = shader_underline;
} }
} }

View File

@ -48,7 +48,7 @@ use std::{
time::Duration, time::Duration,
}; };
const WINDOW_STATE_IVAR: &'static str = "windowState"; const WINDOW_STATE_IVAR: &str = "windowState";
static mut WINDOW_CLASS: *const Class = ptr::null(); static mut WINDOW_CLASS: *const Class = ptr::null();
static mut VIEW_CLASS: *const Class = ptr::null(); static mut VIEW_CLASS: *const Class = ptr::null();
@ -72,7 +72,7 @@ impl NSRange {
self.location != NSNotFound as NSUInteger self.location != NSNotFound as NSUInteger
} }
fn to_range(&self) -> Option<Range<usize>> { fn to_range(self) -> Option<Range<usize>> {
if self.is_valid() { if self.is_valid() {
let start = self.location as usize; let start = self.location as usize;
let end = start + self.length as usize; let end = start + self.length as usize;
@ -513,7 +513,7 @@ impl platform::Window for Window {
}; };
let _: () = msg_send![alert, setAlertStyle: alert_style]; let _: () = msg_send![alert, setAlertStyle: alert_style];
let _: () = msg_send![alert, setMessageText: ns_string(msg)]; let _: () = msg_send![alert, setMessageText: ns_string(msg)];
for (ix, answer) in answers.into_iter().enumerate() { for (ix, answer) in answers.iter().enumerate() {
let button: id = msg_send![alert, addButtonWithTitle: ns_string(answer)]; let button: id = msg_send![alert, addButtonWithTitle: ns_string(answer)];
let _: () = msg_send![button, setTag: ix as NSInteger]; let _: () = msg_send![button, setTag: ix as NSInteger];
} }
@ -721,14 +721,14 @@ extern "C" fn yes(_: &Object, _: Sel) -> BOOL {
extern "C" fn dealloc_window(this: &Object, _: Sel) { extern "C" fn dealloc_window(this: &Object, _: Sel) {
unsafe { unsafe {
drop_window_state(this); drop_window_state(this);
let () = msg_send![super(this, class!(NSWindow)), dealloc]; let _: () = msg_send![super(this, class!(NSWindow)), dealloc];
} }
} }
extern "C" fn dealloc_view(this: &Object, _: Sel) { extern "C" fn dealloc_view(this: &Object, _: Sel) {
unsafe { unsafe {
drop_window_state(this); drop_window_state(this);
let () = msg_send![super(this, class!(NSView)), dealloc]; let _: () = msg_send![super(this, class!(NSView)), dealloc];
} }
} }
@ -912,7 +912,7 @@ extern "C" fn cancel_operation(this: &Object, _sel: Sel, _sender: id) {
extern "C" fn send_event(this: &Object, _: Sel, native_event: id) { extern "C" fn send_event(this: &Object, _: Sel, native_event: id) {
unsafe { unsafe {
let () = msg_send![super(this, class!(NSWindow)), sendEvent: native_event]; let _: () = msg_send![super(this, class!(NSWindow)), sendEvent: native_event];
get_window_state(this).borrow_mut().performed_key_equivalent = false; get_window_state(this).borrow_mut().performed_key_equivalent = false;
} }
} }
@ -991,7 +991,7 @@ extern "C" fn close_window(this: &Object, _: Sel) {
callback(); callback();
} }
let () = msg_send![super(this, class!(NSWindow)), close]; let _: () = msg_send![super(this, class!(NSWindow)), close];
} }
} }
@ -1157,18 +1157,23 @@ extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NS
.flatten() .flatten()
.is_some(); .is_some();
if is_composing || text.chars().count() > 1 || pending_key_down.is_none() { match pending_key_down {
None | Some(_) if is_composing || text.chars().count() > 1 => {
with_input_handler(this, |input_handler| { with_input_handler(this, |input_handler| {
input_handler.replace_text_in_range(replacement_range, text) input_handler.replace_text_in_range(replacement_range, text)
}); });
} else { }
let mut pending_key_down = pending_key_down.unwrap();
Some(mut pending_key_down) => {
pending_key_down.1 = Some(InsertText { pending_key_down.1 = Some(InsertText {
replacement_range, replacement_range,
text: text.to_string(), text: text.to_string(),
}); });
window_state.borrow_mut().pending_key_down = Some(pending_key_down); window_state.borrow_mut().pending_key_down = Some(pending_key_down);
} }
_ => unreachable!(),
}
} }
} }

View File

@ -74,7 +74,7 @@ impl super::ForegroundPlatform for ForegroundPlatform {
fn on_open_urls(&self, _: Box<dyn FnMut(Vec<String>)>) {} fn on_open_urls(&self, _: Box<dyn FnMut(Vec<String>)>) {}
fn run(&self, _on_finish_launching: Box<dyn FnOnce() -> ()>) { fn run(&self, _on_finish_launching: Box<dyn FnOnce()>) {
unimplemented!() unimplemented!()
} }

View File

@ -89,8 +89,8 @@ impl Presenter {
) { ) {
cx.start_frame(); cx.start_frame();
for view_id in &invalidation.removed { for view_id in &invalidation.removed {
invalidation.updated.remove(&view_id); invalidation.updated.remove(view_id);
self.rendered_views.remove(&view_id); self.rendered_views.remove(view_id);
} }
for view_id in &invalidation.updated { for view_id in &invalidation.updated {
self.rendered_views.insert( self.rendered_views.insert(
@ -285,7 +285,7 @@ impl Presenter {
{ {
dragged_region = Some(( dragged_region = Some((
clicked_region.clone(), clicked_region.clone(),
MouseRegionEvent::Drag(*prev_drag_position, e.clone()), MouseRegionEvent::Drag(*prev_drag_position, *e),
)); ));
*prev_drag_position = *position; *prev_drag_position = *position;
} }
@ -366,7 +366,7 @@ impl Presenter {
}, },
) = event ) = event
{ {
if let None = pressed_button { if pressed_button.is_none() {
let mut style_to_assign = CursorStyle::Arrow; let mut style_to_assign = CursorStyle::Arrow;
for region in self.cursor_regions.iter().rev() { for region in self.cursor_regions.iter().rev() {
if region.bounds.contains_point(*position) { if region.bounds.contains_point(*position) {
@ -385,28 +385,22 @@ impl Presenter {
if let Some(region_id) = region.id() { if let Some(region_id) = region.id() {
if !self.hovered_region_ids.contains(&region_id) { if !self.hovered_region_ids.contains(&region_id) {
invalidated_views.push(region.view_id); invalidated_views.push(region.view_id);
hover_regions.push(( hover_regions
region.clone(), .push((region.clone(), MouseRegionEvent::Hover(true, *e)));
MouseRegionEvent::Hover(true, e.clone()),
));
self.hovered_region_ids.insert(region_id); self.hovered_region_ids.insert(region_id);
} }
} }
} else { } else if let Some(region_id) = region.id() {
if let Some(region_id) = region.id() {
if self.hovered_region_ids.contains(&region_id) { if self.hovered_region_ids.contains(&region_id) {
invalidated_views.push(region.view_id); invalidated_views.push(region.view_id);
hover_regions.push(( hover_regions
region.clone(), .push((region.clone(), MouseRegionEvent::Hover(false, *e)));
MouseRegionEvent::Hover(false, e.clone()),
));
self.hovered_region_ids.remove(&region_id); self.hovered_region_ids.remove(&region_id);
} }
} }
} }
} }
} }
}
let mut event_cx = self.build_event_context(cx); let mut event_cx = self.build_event_context(cx);
let mut handled = false; let mut handled = false;
@ -625,7 +619,7 @@ impl<'a> PaintContext<'a> {
#[inline] #[inline]
pub fn paint_layer<F>(&mut self, clip_bounds: Option<RectF>, f: F) pub fn paint_layer<F>(&mut self, clip_bounds: Option<RectF>, f: F)
where where
F: FnOnce(&mut Self) -> (), F: FnOnce(&mut Self),
{ {
self.scene.push_layer(clip_bounds); self.scene.push_layer(clip_bounds);
f(self); f(self);

View File

@ -107,6 +107,7 @@ pub struct MouseRegionId {
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub struct HandlerSet { pub struct HandlerSet {
#[allow(clippy::type_complexity)]
pub set: HashMap< pub set: HashMap<
(Discriminant<MouseRegionEvent>, Option<MouseButton>), (Discriminant<MouseRegionEvent>, Option<MouseButton>),
Rc<dyn Fn(MouseRegionEvent, &mut EventContext)>, Rc<dyn Fn(MouseRegionEvent, &mut EventContext)>,
@ -115,6 +116,7 @@ pub struct HandlerSet {
impl HandlerSet { impl HandlerSet {
pub fn handle_all() -> Self { pub fn handle_all() -> Self {
#[allow(clippy::type_complexity)]
let mut set: HashMap< let mut set: HashMap<
(Discriminant<MouseRegionEvent>, Option<MouseButton>), (Discriminant<MouseRegionEvent>, Option<MouseButton>),
Rc<dyn Fn(MouseRegionEvent, &mut EventContext)>, Rc<dyn Fn(MouseRegionEvent, &mut EventContext)>,

View File

@ -66,7 +66,7 @@ impl TextLayoutCache {
let mut curr_frame = RwLockUpgradableReadGuard::upgrade(curr_frame); let mut curr_frame = RwLockUpgradableReadGuard::upgrade(curr_frame);
if let Some((key, layout)) = self.prev_frame.lock().remove_entry(key) { if let Some((key, layout)) = self.prev_frame.lock().remove_entry(key) {
curr_frame.insert(key, layout.clone()); curr_frame.insert(key, layout.clone());
Line::new(layout.clone(), runs) Line::new(layout, runs)
} else { } else {
let layout = Arc::new(self.fonts.layout_line(text, font_size, runs)); let layout = Arc::new(self.fonts.layout_line(text, font_size, runs));
let key = CacheKeyValue { let key = CacheKeyValue {
@ -81,7 +81,7 @@ impl TextLayoutCache {
} }
trait CacheKey { trait CacheKey {
fn key<'a>(&'a self) -> CacheKeyRef<'a>; fn key(&self) -> CacheKeyRef;
} }
impl<'a> PartialEq for (dyn CacheKey + 'a) { impl<'a> PartialEq for (dyn CacheKey + 'a) {
@ -98,7 +98,7 @@ impl<'a> Hash for (dyn CacheKey + 'a) {
} }
} }
#[derive(Eq, PartialEq)] #[derive(Eq)]
struct CacheKeyValue { struct CacheKeyValue {
text: String, text: String,
font_size: OrderedFloat<f32>, font_size: OrderedFloat<f32>,
@ -106,15 +106,21 @@ struct CacheKeyValue {
} }
impl CacheKey for CacheKeyValue { impl CacheKey for CacheKeyValue {
fn key<'a>(&'a self) -> CacheKeyRef<'a> { fn key(&self) -> CacheKeyRef {
CacheKeyRef { CacheKeyRef {
text: &self.text.as_str(), text: self.text.as_str(),
font_size: self.font_size, font_size: self.font_size,
runs: self.runs.as_slice(), runs: self.runs.as_slice(),
} }
} }
} }
impl PartialEq for CacheKeyValue {
fn eq(&self, other: &Self) -> bool {
self.key().eq(&other.key())
}
}
impl Hash for CacheKeyValue { impl Hash for CacheKeyValue {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
self.key().hash(state); self.key().hash(state);
@ -135,7 +141,7 @@ struct CacheKeyRef<'a> {
} }
impl<'a> CacheKey for CacheKeyRef<'a> { impl<'a> CacheKey for CacheKeyRef<'a> {
fn key<'b>(&'b self) -> CacheKeyRef<'b> { fn key(&self) -> CacheKeyRef {
*self *self
} }
} }
@ -242,6 +248,10 @@ impl Line {
self.layout.len self.layout.len
} }
pub fn is_empty(&self) -> bool {
self.layout.len == 0
}
pub fn index_for_x(&self, x: f32) -> Option<usize> { pub fn index_for_x(&self, x: f32) -> Option<usize> {
if x >= self.layout.width { if x >= self.layout.width {
None None
@ -300,7 +310,7 @@ impl Line {
), ),
Underline { Underline {
color: Some(run_underline.color.unwrap_or(*run_color)), color: Some(run_underline.color.unwrap_or(*run_color)),
thickness: run_underline.thickness.into(), thickness: run_underline.thickness,
squiggly: run_underline.squiggly, squiggly: run_underline.squiggly,
}, },
)); ));
@ -484,7 +494,7 @@ impl LineWrapper {
let mut prev_c = '\0'; let mut prev_c = '\0';
let mut char_indices = line.char_indices(); let mut char_indices = line.char_indices();
iter::from_fn(move || { iter::from_fn(move || {
while let Some((ix, c)) = char_indices.next() { for (ix, c) in char_indices.by_ref() {
if c == '\n' { if c == '\n' {
continue; continue;
} }
@ -746,7 +756,7 @@ mod tests {
let mut wrapper = LineWrapper::new(font_id, 16., font_system); let mut wrapper = LineWrapper::new(font_id, 16., font_system);
assert_eq!( assert_eq!(
wrapper wrapper
.wrap_shaped_line(&text, &line, 72.0) .wrap_shaped_line(text, &line, 72.0)
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
&[ &[
ShapedBoundary { ShapedBoundary {

View File

@ -25,7 +25,7 @@ pub fn test(args: TokenStream, function: TokenStream) -> TokenStream {
NestedMeta::Meta(Meta::NameValue(meta)) => { NestedMeta::Meta(Meta::NameValue(meta)) => {
let key_name = meta.path.get_ident().map(|i| i.to_string()); let key_name = meta.path.get_ident().map(|i| i.to_string());
let result = (|| { let result = (|| {
match key_name.as_ref().map(String::as_str) { match key_name.as_deref() {
Some("retries") => max_retries = parse_int(&meta.lit)?, Some("retries") => max_retries = parse_int(&meta.lit)?,
Some("iterations") => num_iterations = parse_int(&meta.lit)?, Some("iterations") => num_iterations = parse_int(&meta.lit)?,
Some("seed") => starting_seed = parse_int(&meta.lit)?, Some("seed") => starting_seed = parse_int(&meta.lit)?,

View File

@ -737,9 +737,7 @@ impl Buffer {
this.parsing_in_background = false; this.parsing_in_background = false;
this.did_finish_parsing(new_tree, parsed_version, cx); this.did_finish_parsing(new_tree, parsed_version, cx);
if parse_again && this.reparse(cx) { if parse_again && this.reparse(cx) {}
return;
}
}); });
}) })
.detach(); .detach();
@ -933,10 +931,12 @@ impl Buffer {
indent_sizes.entry(row).or_insert_with(|| { indent_sizes.entry(row).or_insert_with(|| {
let mut size = snapshot.indent_size_for_line(row); let mut size = snapshot.indent_size_for_line(row);
if size.kind == new_indent.kind { if size.kind == new_indent.kind {
if delta > 0 { match delta.cmp(&0) {
size.len = size.len + delta as u32; Ordering::Greater => size.len += delta as u32,
} else if delta < 0 { Ordering::Less => {
size.len = size.len.saturating_sub(-delta as u32); size.len = size.len.saturating_sub(-delta as u32)
}
Ordering::Equal => {}
} }
} }
size size
@ -961,7 +961,7 @@ impl Buffer {
let edits: Vec<_> = indent_sizes let edits: Vec<_> = indent_sizes
.into_iter() .into_iter()
.filter_map(|(row, indent_size)| { .filter_map(|(row, indent_size)| {
let current_size = indent_size_for_line(&self, row); let current_size = indent_size_for_line(self, row);
Self::edit_for_indent_size_adjustment(row, current_size, indent_size) Self::edit_for_indent_size_adjustment(row, current_size, indent_size)
}) })
.collect(); .collect();
@ -978,7 +978,8 @@ impl Buffer {
return None; return None;
} }
if new_size.len > current_size.len { match new_size.len.cmp(&current_size.len) {
Ordering::Greater => {
let point = Point::new(row, 0); let point = Point::new(row, 0);
Some(( Some((
point..point, point..point,
@ -986,13 +987,14 @@ impl Buffer {
.take((new_size.len - current_size.len) as usize) .take((new_size.len - current_size.len) as usize)
.collect::<String>(), .collect::<String>(),
)) ))
} else if new_size.len < current_size.len { }
Some((
Ordering::Less => Some((
Point::new(row, 0)..Point::new(row, current_size.len - new_size.len), Point::new(row, 0)..Point::new(row, current_size.len - new_size.len),
String::new(), String::new(),
)) )),
} else {
None Ordering::Equal => None,
} }
} }
@ -1599,7 +1601,7 @@ impl Deref for Buffer {
impl BufferSnapshot { impl BufferSnapshot {
pub fn indent_size_for_line(&self, row: u32) -> IndentSize { pub fn indent_size_for_line(&self, row: u32) -> IndentSize {
indent_size_for_line(&self, row) indent_size_for_line(self, row)
} }
pub fn single_indent_size(&self, cx: &AppContext) -> IndentSize { pub fn single_indent_size(&self, cx: &AppContext) -> IndentSize {
@ -1643,10 +1645,10 @@ impl BufferSnapshot {
result result
} }
fn suggest_autoindents<'a>( fn suggest_autoindents(
&'a self, &self,
row_range: Range<u32>, row_range: Range<u32>,
) -> Option<impl Iterator<Item = Option<IndentSuggestion>> + 'a> { ) -> Option<impl Iterator<Item = Option<IndentSuggestion>> + '_> {
let language = self.language.as_ref()?; let language = self.language.as_ref()?;
let grammar = language.grammar.as_ref()?; let grammar = language.grammar.as_ref()?;
let config = &language.config; let config = &language.config;
@ -1675,7 +1677,7 @@ impl BufferSnapshot {
start.get_or_insert(Point::from_ts_point(capture.node.start_position())); start.get_or_insert(Point::from_ts_point(capture.node.start_position()));
end.get_or_insert(Point::from_ts_point(capture.node.end_position())); end.get_or_insert(Point::from_ts_point(capture.node.end_position()));
} else if Some(capture.index) == end_capture_ix { } else if Some(capture.index) == end_capture_ix {
end = Some(Point::from_ts_point(capture.node.start_position().into())); end = Some(Point::from_ts_point(capture.node.start_position()));
} }
} }
@ -1733,15 +1735,17 @@ impl BufferSnapshot {
let mut outdent_to_row = u32::MAX; let mut outdent_to_row = u32::MAX;
while let Some((indent_row, delta)) = indent_changes.peek() { while let Some((indent_row, delta)) = indent_changes.peek() {
if *indent_row == row { match indent_row.cmp(&row) {
match delta { Ordering::Equal => match delta {
Ordering::Less => outdent_from_prev_row = true, Ordering::Less => outdent_from_prev_row = true,
Ordering::Greater => indent_from_prev_row = true, Ordering::Greater => indent_from_prev_row = true,
_ => {} _ => {}
},
Ordering::Greater => break,
Ordering::Less => {}
} }
} else if *indent_row > row {
break;
}
indent_changes.next(); indent_changes.next();
} }
@ -1805,11 +1809,7 @@ impl BufferSnapshot {
None None
} }
pub fn chunks<'a, T: ToOffset>( pub fn chunks<T: ToOffset>(&self, range: Range<T>, language_aware: bool) -> BufferChunks {
&'a self,
range: Range<T>,
language_aware: bool,
) -> BufferChunks<'a> {
let range = range.start.to_offset(self)..range.end.to_offset(self); let range = range.start.to_offset(self)..range.end.to_offset(self);
let mut tree = None; let mut tree = None;
@ -1843,7 +1843,7 @@ impl BufferSnapshot {
) )
} }
pub fn for_each_line<'a>(&'a self, range: Range<Point>, mut callback: impl FnMut(u32, &str)) { pub fn for_each_line(&self, range: Range<Point>, mut callback: impl FnMut(u32, &str)) {
let mut line = String::new(); let mut line = String::new();
let mut row = range.start.row; let mut row = range.start.row;
for chunk in self for chunk in self
@ -1969,7 +1969,7 @@ impl BufferSnapshot {
position: T, position: T,
theme: Option<&SyntaxTheme>, theme: Option<&SyntaxTheme>,
) -> Option<Vec<OutlineItem<Anchor>>> { ) -> Option<Vec<OutlineItem<Anchor>>> {
let position = position.to_offset(&self); let position = position.to_offset(self);
let mut items = let mut items =
self.outline_items_containing(position.saturating_sub(1)..position + 1, theme)?; self.outline_items_containing(position.saturating_sub(1)..position + 1, theme)?;
let mut prev_depth = None; let mut prev_depth = None;
@ -2050,7 +2050,7 @@ impl BufferSnapshot {
let mut offset = range.start; let mut offset = range.start;
chunks.seek(offset); chunks.seek(offset);
while let Some(mut chunk) = chunks.next() { for mut chunk in chunks.by_ref() {
if chunk.text.len() > range.end - offset { if chunk.text.len() > range.end - offset {
chunk.text = &chunk.text[0..(range.end - offset)]; chunk.text = &chunk.text[0..(range.end - offset)];
offset = range.end; offset = range.end;
@ -2105,7 +2105,7 @@ impl BufferSnapshot {
let range = range.start.to_offset(self).saturating_sub(1)..range.end.to_offset(self) + 1; let range = range.start.to_offset(self).saturating_sub(1)..range.end.to_offset(self) + 1;
let mut cursor = QueryCursorHandle::new(); let mut cursor = QueryCursorHandle::new();
let matches = cursor.set_byte_range(range).matches( let matches = cursor.set_byte_range(range).matches(
&brackets_query, brackets_query,
tree.root_node(), tree.root_node(),
TextProvider(self.as_rope()), TextProvider(self.as_rope()),
); );
@ -2120,17 +2120,17 @@ impl BufferSnapshot {
.min_by_key(|(open_range, close_range)| close_range.end - open_range.start) .min_by_key(|(open_range, close_range)| close_range.end - open_range.start)
} }
pub fn remote_selections_in_range<'a>( #[allow(clippy::type_complexity)]
&'a self, pub fn remote_selections_in_range(
&self,
range: Range<Anchor>, range: Range<Anchor>,
) -> impl 'a ) -> impl Iterator<
+ Iterator<
Item = ( Item = (
ReplicaId, ReplicaId,
bool, bool,
impl 'a + Iterator<Item = &'a Selection<Anchor>>, impl Iterator<Item = &Selection<Anchor>> + '_,
), ),
> { > + '_ {
self.remote_selections self.remote_selections
.iter() .iter()
.filter(|(replica_id, set)| { .filter(|(replica_id, set)| {
@ -2165,8 +2165,7 @@ impl BufferSnapshot {
T: 'a + Clone + ToOffset, T: 'a + Clone + ToOffset,
O: 'a + FromAnchor, O: 'a + FromAnchor,
{ {
self.diagnostics self.diagnostics.range(search_range, self, true, reversed)
.range(search_range.clone(), self, true, reversed)
} }
pub fn diagnostic_groups(&self) -> Vec<DiagnosticGroup<Anchor>> { pub fn diagnostic_groups(&self) -> Vec<DiagnosticGroup<Anchor>> {
@ -2469,10 +2468,7 @@ impl<'a> Iterator for BufferChunks<'a> {
impl QueryCursorHandle { impl QueryCursorHandle {
pub(crate) fn new() -> Self { pub(crate) fn new() -> Self {
let mut cursor = QUERY_CURSORS let mut cursor = QUERY_CURSORS.lock().pop().unwrap_or_else(QueryCursor::new);
.lock()
.pop()
.unwrap_or_else(|| QueryCursor::new());
cursor.set_match_limit(64); cursor.set_match_limit(64);
QueryCursorHandle(Some(cursor)) QueryCursorHandle(Some(cursor))
} }
@ -2614,7 +2610,7 @@ pub fn contiguous_ranges(
values: impl Iterator<Item = u32>, values: impl Iterator<Item = u32>,
max_len: usize, max_len: usize,
) -> impl Iterator<Item = Range<u32>> { ) -> impl Iterator<Item = Range<u32>> {
let mut values = values.into_iter(); let mut values = values;
let mut current_range: Option<Range<u32>> = None; let mut current_range: Option<Range<u32>> = None;
std::iter::from_fn(move || loop { std::iter::from_fn(move || loop {
if let Some(value) = values.next() { if let Some(value) = values.next() {

View File

@ -8,7 +8,7 @@ use std::{
use sum_tree::{self, Bias, SumTree}; use sum_tree::{self, Bias, SumTree};
use text::{Anchor, FromAnchor, PointUtf16, ToOffset}; use text::{Anchor, FromAnchor, PointUtf16, ToOffset};
#[derive(Clone, Debug)] #[derive(Clone, Debug, Default)]
pub struct DiagnosticSet { pub struct DiagnosticSet {
diagnostics: SumTree<DiagnosticEntry<Anchor>>, diagnostics: SumTree<DiagnosticEntry<Anchor>>,
} }
@ -167,24 +167,15 @@ impl DiagnosticSet {
.map(|entry| entry.resolve(buffer)) .map(|entry| entry.resolve(buffer))
} }
} }
impl Default for DiagnosticSet {
fn default() -> Self {
Self {
diagnostics: Default::default(),
}
}
}
impl sum_tree::Item for DiagnosticEntry<Anchor> { impl sum_tree::Item for DiagnosticEntry<Anchor> {
type Summary = Summary; type Summary = Summary;
fn summary(&self) -> Self::Summary { fn summary(&self) -> Self::Summary {
Summary { Summary {
start: self.range.start.clone(), start: self.range.start,
end: self.range.end.clone(), end: self.range.end,
min_start: self.range.start.clone(), min_start: self.range.start,
max_end: self.range.end.clone(), max_end: self.range.end,
count: 1, count: 1,
} }
} }
@ -217,13 +208,13 @@ impl sum_tree::Summary for Summary {
fn add_summary(&mut self, other: &Self, buffer: &Self::Context) { fn add_summary(&mut self, other: &Self, buffer: &Self::Context) {
if other.min_start.cmp(&self.min_start, buffer).is_lt() { if other.min_start.cmp(&self.min_start, buffer).is_lt() {
self.min_start = other.min_start.clone(); self.min_start = other.min_start;
} }
if other.max_end.cmp(&self.max_end, buffer).is_gt() { if other.max_end.cmp(&self.max_end, buffer).is_gt() {
self.max_end = other.max_end.clone(); self.max_end = other.max_end;
} }
self.start = other.start.clone(); self.start = other.start;
self.end = other.end.clone(); self.end = other.end;
self.count += other.count; self.count += other.count;
} }
} }

View File

@ -56,10 +56,7 @@ impl HighlightId {
} }
pub fn style(&self, theme: &SyntaxTheme) -> Option<HighlightStyle> { pub fn style(&self, theme: &SyntaxTheme) -> Option<HighlightStyle> {
theme theme.highlights.get(self.0 as usize).map(|entry| entry.1)
.highlights
.get(self.0 as usize)
.map(|entry| entry.1.clone())
} }
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]

View File

@ -308,6 +308,7 @@ pub struct LanguageRegistry {
lsp_binary_statuses_tx: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>, lsp_binary_statuses_tx: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>,
lsp_binary_statuses_rx: async_broadcast::Receiver<(Arc<Language>, LanguageServerBinaryStatus)>, lsp_binary_statuses_rx: async_broadcast::Receiver<(Arc<Language>, LanguageServerBinaryStatus)>,
login_shell_env_loaded: Shared<Task<()>>, login_shell_env_loaded: Shared<Task<()>>,
#[allow(clippy::type_complexity)]
lsp_binary_paths: Mutex< lsp_binary_paths: Mutex<
HashMap< HashMap<
LanguageServerName, LanguageServerName,
@ -342,7 +343,7 @@ impl LanguageRegistry {
if let Some(theme) = self.theme.read().clone() { if let Some(theme) = self.theme.read().clone() {
language.set_theme(&theme.editor.syntax); language.set_theme(&theme.editor.syntax);
} }
self.languages.write().push(language.clone()); self.languages.write().push(language);
*self.subscription.write().0.borrow_mut() = (); *self.subscription.write().0.borrow_mut() = ();
} }
@ -409,7 +410,7 @@ impl LanguageRegistry {
) -> Option<Task<Result<lsp::LanguageServer>>> { ) -> Option<Task<Result<lsp::LanguageServer>>> {
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
if language.fake_adapter.is_some() { if language.fake_adapter.is_some() {
let language = language.clone(); let language = language;
return Some(cx.spawn(|cx| async move { return Some(cx.spawn(|cx| async move {
let (servers_tx, fake_adapter) = language.fake_adapter.as_ref().unwrap(); let (servers_tx, fake_adapter) = language.fake_adapter.as_ref().unwrap();
let (server, mut fake_server) = lsp::LanguageServer::fake( let (server, mut fake_server) = lsp::LanguageServer::fake(
@ -474,7 +475,7 @@ impl LanguageRegistry {
let server = lsp::LanguageServer::new( let server = lsp::LanguageServer::new(
server_id, server_id,
&server_binary_path, &server_binary_path,
&server_args, server_args,
&root_path, &root_path,
cx, cx,
)?; )?;

View File

@ -408,10 +408,12 @@ pub async fn deserialize_completion(
Ok(Completion { Ok(Completion {
old_range: old_start..old_end, old_range: old_start..old_end,
new_text: completion.new_text, new_text: completion.new_text,
label: label.unwrap_or(CodeLabel::plain( label: label.unwrap_or_else(|| {
CodeLabel::plain(
lsp_completion.label.clone(), lsp_completion.label.clone(),
lsp_completion.filter_text.as_deref(), lsp_completion.filter_text.as_deref(),
)), )
}),
lsp_completion, lsp_completion,
}) })
} }
@ -465,7 +467,7 @@ pub fn deserialize_transaction(transaction: proto::Transaction) -> Result<Transa
.into_iter() .into_iter()
.map(deserialize_local_timestamp) .map(deserialize_local_timestamp)
.collect(), .collect(),
start: deserialize_version(transaction.start.into()), start: deserialize_version(transaction.start),
}) })
} }

View File

@ -107,7 +107,7 @@ fn test_edit_events(cx: &mut gpui::MutableAppContext) {
let buffer_1_events = buffer_1_events.clone(); let buffer_1_events = buffer_1_events.clone();
cx.subscribe(&buffer1, move |_, _, event, _| match event.clone() { cx.subscribe(&buffer1, move |_, _, event, _| match event.clone() {
Event::Operation(op) => buffer1_ops.borrow_mut().push(op), Event::Operation(op) => buffer1_ops.borrow_mut().push(op),
event @ _ => buffer_1_events.borrow_mut().push(event), event => buffer_1_events.borrow_mut().push(event),
}) })
.detach(); .detach();
let buffer_2_events = buffer_2_events.clone(); let buffer_2_events = buffer_2_events.clone();
@ -190,7 +190,7 @@ async fn test_apply_diff(cx: &mut gpui::TestAppContext) {
buffer.update(cx, |buffer, cx| { buffer.update(cx, |buffer, cx| {
buffer.apply_diff(diff, cx).unwrap(); buffer.apply_diff(diff, cx).unwrap();
assert_eq!(buffer.text(), text); assert_eq!(buffer.text(), text);
assert_eq!(anchor.to_point(&buffer), Point::new(2, 3)); assert_eq!(anchor.to_point(buffer), Point::new(2, 3));
}); });
let text = "a\n1\n\nccc\ndd2dd\nffffff\n"; let text = "a\n1\n\nccc\ndd2dd\nffffff\n";
@ -198,7 +198,7 @@ async fn test_apply_diff(cx: &mut gpui::TestAppContext) {
buffer.update(cx, |buffer, cx| { buffer.update(cx, |buffer, cx| {
buffer.apply_diff(diff, cx).unwrap(); buffer.apply_diff(diff, cx).unwrap();
assert_eq!(buffer.text(), text); assert_eq!(buffer.text(), text);
assert_eq!(anchor.to_point(&buffer), Point::new(4, 4)); assert_eq!(anchor.to_point(buffer), Point::new(4, 4));
}); });
} }
@ -209,11 +209,9 @@ async fn test_reparse(cx: &mut gpui::TestAppContext) {
cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx)); cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
// Wait for the initial text to parse // Wait for the initial text to parse
buffer buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
.condition(&cx, |buffer, _| !buffer.is_parsing())
.await;
assert_eq!( assert_eq!(
get_tree_sexp(&buffer, &cx), get_tree_sexp(&buffer, cx),
concat!( concat!(
"(source_file (function_item name: (identifier) ", "(source_file (function_item name: (identifier) ",
"parameters: (parameters) ", "parameters: (parameters) ",
@ -230,11 +228,11 @@ async fn test_reparse(cx: &mut gpui::TestAppContext) {
buffer.update(cx, |buf, cx| { buffer.update(cx, |buf, cx| {
buf.start_transaction(); buf.start_transaction();
let offset = buf.text().find(")").unwrap(); let offset = buf.text().find(')').unwrap();
buf.edit([(offset..offset, "b: C")], None, cx); buf.edit([(offset..offset, "b: C")], None, cx);
assert!(!buf.is_parsing()); assert!(!buf.is_parsing());
let offset = buf.text().find("}").unwrap(); let offset = buf.text().find('}').unwrap();
buf.edit([(offset..offset, " d; ")], None, cx); buf.edit([(offset..offset, " d; ")], None, cx);
assert!(!buf.is_parsing()); assert!(!buf.is_parsing());
@ -242,11 +240,9 @@ async fn test_reparse(cx: &mut gpui::TestAppContext) {
assert_eq!(buf.text(), "fn a(b: C) { d; }"); assert_eq!(buf.text(), "fn a(b: C) { d; }");
assert!(buf.is_parsing()); assert!(buf.is_parsing());
}); });
buffer buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
.condition(&cx, |buffer, _| !buffer.is_parsing())
.await;
assert_eq!( assert_eq!(
get_tree_sexp(&buffer, &cx), get_tree_sexp(&buffer, cx),
concat!( concat!(
"(source_file (function_item name: (identifier) ", "(source_file (function_item name: (identifier) ",
"parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ", "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
@ -259,13 +255,13 @@ async fn test_reparse(cx: &mut gpui::TestAppContext) {
// * turn field expression into a method call // * turn field expression into a method call
// * add a turbofish to the method call // * add a turbofish to the method call
buffer.update(cx, |buf, cx| { buffer.update(cx, |buf, cx| {
let offset = buf.text().find(";").unwrap(); let offset = buf.text().find(';').unwrap();
buf.edit([(offset..offset, ".e")], None, cx); buf.edit([(offset..offset, ".e")], None, cx);
assert_eq!(buf.text(), "fn a(b: C) { d.e; }"); assert_eq!(buf.text(), "fn a(b: C) { d.e; }");
assert!(buf.is_parsing()); assert!(buf.is_parsing());
}); });
buffer.update(cx, |buf, cx| { buffer.update(cx, |buf, cx| {
let offset = buf.text().find(";").unwrap(); let offset = buf.text().find(';').unwrap();
buf.edit([(offset..offset, "(f)")], None, cx); buf.edit([(offset..offset, "(f)")], None, cx);
assert_eq!(buf.text(), "fn a(b: C) { d.e(f); }"); assert_eq!(buf.text(), "fn a(b: C) { d.e(f); }");
assert!(buf.is_parsing()); assert!(buf.is_parsing());
@ -276,11 +272,9 @@ async fn test_reparse(cx: &mut gpui::TestAppContext) {
assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }"); assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
assert!(buf.is_parsing()); assert!(buf.is_parsing());
}); });
buffer buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
.condition(&cx, |buffer, _| !buffer.is_parsing())
.await;
assert_eq!( assert_eq!(
get_tree_sexp(&buffer, &cx), get_tree_sexp(&buffer, cx),
concat!( concat!(
"(source_file (function_item name: (identifier) ", "(source_file (function_item name: (identifier) ",
"parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ", "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
@ -297,11 +291,9 @@ async fn test_reparse(cx: &mut gpui::TestAppContext) {
assert_eq!(buf.text(), "fn a() {}"); assert_eq!(buf.text(), "fn a() {}");
assert!(buf.is_parsing()); assert!(buf.is_parsing());
}); });
buffer buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
.condition(&cx, |buffer, _| !buffer.is_parsing())
.await;
assert_eq!( assert_eq!(
get_tree_sexp(&buffer, &cx), get_tree_sexp(&buffer, cx),
concat!( concat!(
"(source_file (function_item name: (identifier) ", "(source_file (function_item name: (identifier) ",
"parameters: (parameters) ", "parameters: (parameters) ",
@ -314,11 +306,9 @@ async fn test_reparse(cx: &mut gpui::TestAppContext) {
assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }"); assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
assert!(buf.is_parsing()); assert!(buf.is_parsing());
}); });
buffer buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
.condition(&cx, |buffer, _| !buffer.is_parsing())
.await;
assert_eq!( assert_eq!(
get_tree_sexp(&buffer, &cx), get_tree_sexp(&buffer, cx),
concat!( concat!(
"(source_file (function_item name: (identifier) ", "(source_file (function_item name: (identifier) ",
"parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ", "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
@ -340,21 +330,17 @@ async fn test_resetting_language(cx: &mut gpui::TestAppContext) {
}); });
// Wait for the initial text to parse // Wait for the initial text to parse
buffer buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
.condition(&cx, |buffer, _| !buffer.is_parsing())
.await;
assert_eq!( assert_eq!(
get_tree_sexp(&buffer, &cx), get_tree_sexp(&buffer, cx),
"(source_file (expression_statement (block)))" "(source_file (expression_statement (block)))"
); );
buffer.update(cx, |buffer, cx| { buffer.update(cx, |buffer, cx| {
buffer.set_language(Some(Arc::new(json_lang())), cx) buffer.set_language(Some(Arc::new(json_lang())), cx)
}); });
buffer buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
.condition(&cx, |buffer, _| !buffer.is_parsing()) assert_eq!(get_tree_sexp(&buffer, cx), "(document (object))");
.await;
assert_eq!(get_tree_sexp(&buffer, &cx), "(document (object))");
} }
#[gpui::test] #[gpui::test]
@ -417,7 +403,7 @@ async fn test_outline(cx: &mut gpui::TestAppContext) {
// Without space, we only match on names // Without space, we only match on names
assert_eq!( assert_eq!(
search(&outline, "oon", &cx).await, search(&outline, "oon", cx).await,
&[ &[
("mod module", vec![]), // included as the parent of a match ("mod module", vec![]), // included as the parent of a match
("enum LoginState", vec![]), // included as the parent of a match ("enum LoginState", vec![]), // included as the parent of a match
@ -427,18 +413,18 @@ async fn test_outline(cx: &mut gpui::TestAppContext) {
); );
assert_eq!( assert_eq!(
search(&outline, "dp p", &cx).await, search(&outline, "dp p", cx).await,
&[ &[
("impl Drop for Person", vec![5, 8, 9, 14]), ("impl Drop for Person", vec![5, 8, 9, 14]),
("fn drop", vec![]), ("fn drop", vec![]),
] ]
); );
assert_eq!( assert_eq!(
search(&outline, "dpn", &cx).await, search(&outline, "dpn", cx).await,
&[("impl Drop for Person", vec![5, 14, 19])] &[("impl Drop for Person", vec![5, 14, 19])]
); );
assert_eq!( assert_eq!(
search(&outline, "impl ", &cx).await, search(&outline, "impl ", cx).await,
&[ &[
("impl Eq for Person", vec![0, 1, 2, 3, 4]), ("impl Eq for Person", vec![0, 1, 2, 3, 4]),
("impl Drop for Person", vec![0, 1, 2, 3, 4]), ("impl Drop for Person", vec![0, 1, 2, 3, 4]),
@ -530,9 +516,9 @@ async fn test_symbols_containing(cx: &mut gpui::TestAppContext) {
] ]
); );
fn symbols_containing<'a>( fn symbols_containing(
position: Point, position: Point,
snapshot: &'a BufferSnapshot, snapshot: &BufferSnapshot,
) -> Vec<(String, Range<Point>)> { ) -> Vec<(String, Range<Point>)> {
snapshot snapshot
.symbols_containing(position, None) .symbols_containing(position, None)
@ -799,7 +785,7 @@ fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut Muta
Ok(()) Ok(())
} }
" "
.replace("|", "") // included in the string to preserve trailing whites .replace('|', "") // included in the string to preserve trailing whites
.unindent() .unindent()
); );
@ -971,7 +957,7 @@ fn test_autoindent_block_mode(cx: &mut MutableAppContext) {
buffer.undo(cx); buffer.undo(cx);
buffer.edit([(Point::new(2, 0)..Point::new(2, 0), " ")], None, cx); buffer.edit([(Point::new(2, 0)..Point::new(2, 0), " ")], None, cx);
buffer.edit( buffer.edit(
[(Point::new(2, 8)..Point::new(2, 8), inserted_text.clone())], [(Point::new(2, 8)..Point::new(2, 8), inserted_text)],
Some(AutoindentMode::Block { Some(AutoindentMode::Block {
original_indent_columns: vec![0], original_indent_columns: vec![0],
}), }),
@ -1098,7 +1084,7 @@ fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) {
if let Event::Operation(op) = event { if let Event::Operation(op) = event {
network network
.borrow_mut() .borrow_mut()
.broadcast(buffer.replica_id(), vec![proto::serialize_operation(&op)]); .broadcast(buffer.replica_id(), vec![proto::serialize_operation(op)]);
} }
}) })
.detach(); .detach();
@ -1202,7 +1188,7 @@ fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) {
if let Event::Operation(op) = event { if let Event::Operation(op) = event {
network.borrow_mut().broadcast( network.borrow_mut().broadcast(
buffer.replica_id(), buffer.replica_id(),
vec![proto::serialize_operation(&op)], vec![proto::serialize_operation(op)],
); );
} }
}) })

View File

@ -27,8 +27,8 @@ use std::{
use std::{path::Path, process::Stdio}; use std::{path::Path, process::Stdio};
use util::{ResultExt, TryFutureExt}; use util::{ResultExt, TryFutureExt};
const JSON_RPC_VERSION: &'static str = "2.0"; const JSON_RPC_VERSION: &str = "2.0";
const CONTENT_LEN_HEADER: &'static str = "Content-Length: "; const CONTENT_LEN_HEADER: &str = "Content-Length: ";
type NotificationHandler = Box<dyn Send + FnMut(Option<usize>, &str, AsyncAppContext)>; type NotificationHandler = Box<dyn Send + FnMut(Option<usize>, &str, AsyncAppContext)>;
type ResponseHandler = Box<dyn Send + FnOnce(Result<&str, Error>)>; type ResponseHandler = Box<dyn Send + FnOnce(Result<&str, Error>)>;
@ -42,6 +42,7 @@ pub struct LanguageServer {
notification_handlers: Arc<Mutex<HashMap<&'static str, NotificationHandler>>>, notification_handlers: Arc<Mutex<HashMap<&'static str, NotificationHandler>>>,
response_handlers: Arc<Mutex<HashMap<usize, ResponseHandler>>>, response_handlers: Arc<Mutex<HashMap<usize, ResponseHandler>>>,
executor: Arc<executor::Background>, executor: Arc<executor::Background>,
#[allow(clippy::type_complexity)]
io_tasks: Mutex<Option<(Task<Option<()>>, Task<Option<()>>)>>, io_tasks: Mutex<Option<(Task<Option<()>>, Task<Option<()>>)>>,
output_done_rx: Mutex<Option<barrier::Receiver>>, output_done_rx: Mutex<Option<barrier::Receiver>>,
root_path: PathBuf, root_path: PathBuf,
@ -112,7 +113,7 @@ impl LanguageServer {
let working_dir = if root_path.is_dir() { let working_dir = if root_path.is_dir() {
root_path root_path
} else { } else {
root_path.parent().unwrap_or(Path::new("/")) root_path.parent().unwrap_or_else(|| Path::new("/"))
}; };
let mut server = process::Command::new(binary_path) let mut server = process::Command::new(binary_path)
.current_dir(working_dir) .current_dir(working_dir)
@ -251,7 +252,7 @@ impl LanguageServer {
capabilities: Default::default(), capabilities: Default::default(),
next_id: Default::default(), next_id: Default::default(),
outbound_tx, outbound_tx,
executor: cx.background().clone(), executor: cx.background(),
io_tasks: Mutex::new(Some((input_task, output_task))), io_tasks: Mutex::new(Some((input_task, output_task))),
output_done_rx: Mutex::new(Some(output_done_rx)), output_done_rx: Mutex::new(Some(output_done_rx)),
root_path: root_path.to_path_buf(), root_path: root_path.to_path_buf(),
@ -641,7 +642,7 @@ impl LanguageServer {
stdin_reader, stdin_reader,
None, None,
Path::new("/"), Path::new("/"),
cx.clone(), cx,
move |msg| { move |msg| {
notifications_tx notifications_tx
.try_send((msg.method.to_string(), msg.params.get().to_string())) .try_send((msg.method.to_string(), msg.params.get().to_string()))
@ -651,7 +652,7 @@ impl LanguageServer {
notifications_rx, notifications_rx,
}; };
fake.handle_request::<request::Initialize, _, _>({ fake.handle_request::<request::Initialize, _, _>({
let capabilities = capabilities.clone(); let capabilities = capabilities;
move |_, _| { move |_, _| {
let capabilities = capabilities.clone(); let capabilities = capabilities.clone();
let name = name.clone(); let name = name.clone();
@ -662,7 +663,6 @@ impl LanguageServer {
name, name,
..Default::default() ..Default::default()
}), }),
..Default::default()
}) })
} }
} }
@ -697,7 +697,7 @@ impl FakeLanguageServer {
loop { loop {
let (method, params) = self.notifications_rx.next().await?; let (method, params) = self.notifications_rx.next().await?;
if &method == T::METHOD { if method == T::METHOD {
return Some(serde_json::from_str::<T::Params>(&params).unwrap()); return Some(serde_json::from_str::<T::Params>(&params).unwrap());
} else { } else {
log::info!("skipping message in fake language server {:?}", params); log::info!("skipping message in fake language server {:?}", params);

View File

@ -115,8 +115,8 @@ impl OutlineView {
self.active_editor.update(cx, |active_editor, cx| { self.active_editor.update(cx, |active_editor, cx| {
let snapshot = active_editor.snapshot(cx).display_snapshot; let snapshot = active_editor.snapshot(cx).display_snapshot;
let buffer_snapshot = &snapshot.buffer_snapshot; let buffer_snapshot = &snapshot.buffer_snapshot;
let start = outline_item.range.start.to_point(&buffer_snapshot); let start = outline_item.range.start.to_point(buffer_snapshot);
let end = outline_item.range.end.to_point(&buffer_snapshot); let end = outline_item.range.end.to_point(buffer_snapshot);
let display_rows = start.to_display_point(&snapshot).row() let display_rows = start.to_display_point(&snapshot).row()
..end.to_display_point(&snapshot).row() + 1; ..end.to_display_point(&snapshot).row() + 1;
active_editor.highlight_rows(Some(display_rows)); active_editor.highlight_rows(Some(display_rows));
@ -183,8 +183,8 @@ impl PickerDelegate for OutlineView {
.map(|(ix, item)| { .map(|(ix, item)| {
let range = item.range.to_offset(&buffer); let range = item.range.to_offset(&buffer);
let distance_to_closest_endpoint = cmp::min( let distance_to_closest_endpoint = cmp::min(
(range.start as isize - cursor_offset as isize).abs() as usize, (range.start as isize - cursor_offset as isize).abs(),
(range.end as isize - cursor_offset as isize).abs() as usize, (range.end as isize - cursor_offset as isize).abs(),
); );
let depth = if range.contains(&cursor_offset) { let depth = if range.contains(&cursor_offset) {
Some(item.depth) Some(item.depth)

View File

@ -29,7 +29,7 @@ impl __Buffer {
pub extern "C" fn __alloc_buffer(len: u32) -> u32 { pub extern "C" fn __alloc_buffer(len: u32) -> u32 {
let vec = vec![0; len as usize]; let vec = vec![0; len as usize];
let buffer = unsafe { __Buffer::from_vec(vec) }; let buffer = unsafe { __Buffer::from_vec(vec) };
return buffer.ptr; buffer.ptr
} }
/// Frees a given buffer, requires the size. /// Frees a given buffer, requires the size.

View File

@ -17,7 +17,6 @@ fn main() {
// Clear out and recreate the plugin bin directory // Clear out and recreate the plugin bin directory
let _ = std::fs::remove_dir_all(base.join("bin")); let _ = std::fs::remove_dir_all(base.join("bin"));
let _ =
std::fs::create_dir_all(base.join("bin")).expect("Could not make plugins bin directory"); std::fs::create_dir_all(base.join("bin")).expect("Could not make plugins bin directory");
// Compile the plugins using the same profile as the current Zed build // Compile the plugins using the same profile as the current Zed build
@ -43,7 +42,7 @@ fn main() {
// Get the target architecture for pre-cross-compilation of plugins // Get the target architecture for pre-cross-compilation of plugins
// and create and engine with the appropriate config // and create and engine with the appropriate config
let target_triple = std::env::var("TARGET").unwrap().to_string(); let target_triple = std::env::var("TARGET").unwrap();
println!("cargo:rerun-if-env-changed=TARGET"); println!("cargo:rerun-if-env-changed=TARGET");
let engine = create_default_engine(&target_triple); let engine = create_default_engine(&target_triple);
@ -77,7 +76,7 @@ fn create_default_engine(target_triple: &str) -> Engine {
let mut config = Config::default(); let mut config = Config::default();
config config
.target(target_triple) .target(target_triple)
.expect(&format!("Could not set target to `{}`", target_triple)); .unwrap_or_else(|_| panic!("Could not set target to `{}`", target_triple));
config.async_support(true); config.async_support(true);
config.consume_fuel(true); config.consume_fuel(true);
Engine::new(&config).expect("Could not create precompilation engine") Engine::new(&config).expect("Could not create precompilation engine")

View File

@ -69,13 +69,13 @@ mod tests {
let unsorted = vec![1, 3, 4, 2, 5]; let unsorted = vec![1, 3, 4, 2, 5];
let sorted = vec![1, 2, 3, 4, 5]; let sorted = vec![1, 2, 3, 4, 5];
assert_eq!(runtime.call(&plugin.noop, ()).await.unwrap(), ()); runtime.call(&plugin.noop, ()).await.unwrap();
assert_eq!(runtime.call(&plugin.constant, ()).await.unwrap(), 27); assert_eq!(runtime.call(&plugin.constant, ()).await.unwrap(), 27);
assert_eq!(runtime.call(&plugin.identity, 58).await.unwrap(), 58); assert_eq!(runtime.call(&plugin.identity, 58).await.unwrap(), 58);
assert_eq!(runtime.call(&plugin.add, (3, 4)).await.unwrap(), 7); assert_eq!(runtime.call(&plugin.add, (3, 4)).await.unwrap(), 7);
assert_eq!(runtime.call(&plugin.swap, (1, 2)).await.unwrap(), (2, 1)); assert_eq!(runtime.call(&plugin.swap, (1, 2)).await.unwrap(), (2, 1));
assert_eq!(runtime.call(&plugin.sort, unsorted).await.unwrap(), sorted); assert_eq!(runtime.call(&plugin.sort, unsorted).await.unwrap(), sorted);
assert_eq!(runtime.call(&plugin.print, "Hi!".into()).await.unwrap(), ()); runtime.call(&plugin.print, "Hi!".into()).await.unwrap();
assert_eq!(runtime.call(&plugin.and_back, 1).await.unwrap(), 8); assert_eq!(runtime.call(&plugin.and_back, 1).await.unwrap(), 8);
assert_eq!(runtime.call(&plugin.imports, 1).await.unwrap(), 8); assert_eq!(runtime.call(&plugin.imports, 1).await.unwrap(), 8);
assert_eq!(runtime.call(&plugin.half_async, 4).await.unwrap(), 2); assert_eq!(runtime.call(&plugin.half_async, 4).await.unwrap(), 2);

View File

@ -135,7 +135,7 @@ impl PluginBuilder {
// TODO: use try block once avaliable // TODO: use try block once avaliable
let result: Result<(WasiBuffer, Memory, _), Trap> = (|| { let result: Result<(WasiBuffer, Memory, _), Trap> = (|| {
// grab a handle to the memory // grab a handle to the memory
let mut plugin_memory = match caller.get_export("memory") { let plugin_memory = match caller.get_export("memory") {
Some(Extern::Memory(mem)) => mem, Some(Extern::Memory(mem)) => mem,
_ => return Err(Trap::new("Could not grab slice of plugin memory"))?, _ => return Err(Trap::new("Could not grab slice of plugin memory"))?,
}; };
@ -144,9 +144,9 @@ impl PluginBuilder {
// get the args passed from Guest // get the args passed from Guest
let args = let args =
Plugin::buffer_to_bytes(&mut plugin_memory, caller.as_context(), &buffer)?; Plugin::buffer_to_bytes(&plugin_memory, caller.as_context(), &buffer)?;
let args: A = Plugin::deserialize_to_type(&args)?; let args: A = Plugin::deserialize_to_type(args)?;
// Call the Host-side function // Call the Host-side function
let result = function(args); let result = function(args);
@ -214,7 +214,7 @@ impl PluginBuilder {
// TODO: use try block once avaliable // TODO: use try block once avaliable
let result: Result<(WasiBuffer, Memory, Vec<u8>), Trap> = (|| { let result: Result<(WasiBuffer, Memory, Vec<u8>), Trap> = (|| {
// grab a handle to the memory // grab a handle to the memory
let mut plugin_memory = match caller.get_export("memory") { let plugin_memory = match caller.get_export("memory") {
Some(Extern::Memory(mem)) => mem, Some(Extern::Memory(mem)) => mem,
_ => return Err(Trap::new("Could not grab slice of plugin memory"))?, _ => return Err(Trap::new("Could not grab slice of plugin memory"))?,
}; };
@ -222,7 +222,7 @@ impl PluginBuilder {
let buffer = WasiBuffer::from_u64(packed_buffer); let buffer = WasiBuffer::from_u64(packed_buffer);
// get the args passed from Guest // get the args passed from Guest
let args = Plugin::buffer_to_type(&mut plugin_memory, &mut caller, &buffer)?; let args = Plugin::buffer_to_type(&plugin_memory, &mut caller, &buffer)?;
// Call the Host-side function // Call the Host-side function
let result: R = function(args); let result: R = function(args);
@ -258,7 +258,7 @@ impl PluginBuilder {
/// Initializes a [`Plugin`] from a given compiled Wasm module. /// Initializes a [`Plugin`] from a given compiled Wasm module.
/// Both binary (`.wasm`) and text (`.wat`) module formats are supported. /// Both binary (`.wasm`) and text (`.wat`) module formats are supported.
pub async fn init<'a>(self, binary: PluginBinary<'a>) -> Result<Plugin, Error> { pub async fn init(self, binary: PluginBinary<'_>) -> Result<Plugin, Error> {
Plugin::init(binary, self).await Plugin::init(binary, self).await
} }
} }
@ -324,7 +324,7 @@ impl Plugin {
println!(); println!();
} }
async fn init<'a>(binary: PluginBinary<'a>, plugin: PluginBuilder) -> Result<Self, Error> { async fn init(binary: PluginBinary<'_>, plugin: PluginBuilder) -> Result<Self, Error> {
// initialize the WebAssembly System Interface context // initialize the WebAssembly System Interface context
let engine = plugin.engine; let engine = plugin.engine;
let mut linker = plugin.linker; let mut linker = plugin.linker;
@ -576,7 +576,7 @@ impl Plugin {
.await?; .await?;
Self::buffer_to_type( Self::buffer_to_type(
&mut plugin_memory, &plugin_memory,
&mut self.store, &mut self.store,
&WasiBuffer::from_u64(result_buffer), &WasiBuffer::from_u64(result_buffer),
) )

View File

@ -460,7 +460,7 @@ impl FakeFs {
} }
} }
Null => { Null => {
self.create_dir(&path).await.unwrap(); self.create_dir(path).await.unwrap();
} }
String(contents) => { String(contents) => {
self.insert_file(&path, contents).await; self.insert_file(&path, contents).await;

View File

@ -1027,7 +1027,7 @@ impl LspCommand for GetHover {
lsp::HoverContents::Array(marked_strings) => { lsp::HoverContents::Array(marked_strings) => {
let content: Vec<HoverBlock> = marked_strings let content: Vec<HoverBlock> = marked_strings
.into_iter() .into_iter()
.filter_map(|marked_string| HoverBlock::try_new(marked_string)) .filter_map(HoverBlock::try_new)
.collect(); .collect();
if content.is_empty() { if content.is_empty() {
None None
@ -1049,9 +1049,7 @@ impl LspCommand for GetHover {
} }
Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(new_language))) => { Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(new_language))) => {
if !current_text.is_empty() { if !current_text.is_empty() {
let text = std::mem::replace(&mut current_text, String::new()) let text = std::mem::take(&mut current_text).trim().to_string();
.trim()
.to_string();
contents.push(HoverBlock { text, language }); contents.push(HoverBlock { text, language });
} }
@ -1067,9 +1065,7 @@ impl LspCommand for GetHover {
| Event::End(Tag::BlockQuote) | Event::End(Tag::BlockQuote)
| Event::HardBreak => { | Event::HardBreak => {
if !current_text.is_empty() { if !current_text.is_empty() {
let text = std::mem::replace(&mut current_text, String::new()) let text = std::mem::take(&mut current_text).trim().to_string();
.trim()
.to_string();
contents.push(HoverBlock { text, language }); contents.push(HoverBlock { text, language });
} }
language = None; language = None;

View File

@ -114,10 +114,12 @@ pub struct Project {
_subscriptions: Vec<gpui::Subscription>, _subscriptions: Vec<gpui::Subscription>,
opened_buffer: (Rc<RefCell<watch::Sender<()>>>, watch::Receiver<()>), opened_buffer: (Rc<RefCell<watch::Sender<()>>>, watch::Receiver<()>),
shared_buffers: HashMap<PeerId, HashSet<u64>>, shared_buffers: HashMap<PeerId, HashSet<u64>>,
#[allow(clippy::type_complexity)]
loading_buffers: HashMap< loading_buffers: HashMap<
ProjectPath, ProjectPath,
postage::watch::Receiver<Option<Result<ModelHandle<Buffer>, Arc<anyhow::Error>>>>, postage::watch::Receiver<Option<Result<ModelHandle<Buffer>, Arc<anyhow::Error>>>>,
>, >,
#[allow(clippy::type_complexity)]
loading_local_worktrees: loading_local_worktrees:
HashMap<Arc<Path>, Shared<Task<Result<ModelHandle<Worktree>, Arc<anyhow::Error>>>>>, HashMap<Arc<Path>, Shared<Task<Result<ModelHandle<Worktree>, Arc<anyhow::Error>>>>>,
opened_buffers: HashMap<u64, OpenBuffer>, opened_buffers: HashMap<u64, OpenBuffer>,
@ -993,7 +995,7 @@ impl Project {
.iter() .iter()
.filter_map(|worktree| { .filter_map(|worktree| {
worktree worktree
.upgrade(&cx) .upgrade(cx)
.map(|worktree| worktree.read(cx).as_local().unwrap().metadata_proto()) .map(|worktree| worktree.read(cx).as_local().unwrap().metadata_proto())
}) })
.collect() .collect()
@ -1080,7 +1082,7 @@ impl Project {
self.worktrees self.worktrees
.iter() .iter()
.filter_map(|worktree| { .filter_map(|worktree| {
let worktree = worktree.upgrade(&cx)?.read(cx); let worktree = worktree.upgrade(cx)?.read(cx);
if worktree.is_visible() { if worktree.is_visible() {
Some(format!( Some(format!(
"project-path-online:{}", "project-path-online:{}",
@ -1121,7 +1123,7 @@ impl Project {
} }
pub fn contains_paths(&self, paths: &[PathBuf], cx: &AppContext) -> bool { pub fn contains_paths(&self, paths: &[PathBuf], cx: &AppContext) -> bool {
paths.iter().all(|path| self.contains_path(&path, cx)) paths.iter().all(|path| self.contains_path(path, cx))
} }
pub fn contains_path(&self, path: &Path, cx: &AppContext) -> bool { pub fn contains_path(&self, path: &Path, cx: &AppContext) -> bool {
@ -1395,12 +1397,9 @@ impl Project {
} }
for open_buffer in self.opened_buffers.values_mut() { for open_buffer in self.opened_buffers.values_mut() {
match open_buffer { if let OpenBuffer::Strong(buffer) = open_buffer {
OpenBuffer::Strong(buffer) => {
*open_buffer = OpenBuffer::Weak(buffer.downgrade()); *open_buffer = OpenBuffer::Weak(buffer.downgrade());
} }
_ => {}
}
} }
cx.notify(); cx.notify();
@ -1493,7 +1492,7 @@ impl Project {
let buffer = cx.add_model(|cx| { let buffer = cx.add_model(|cx| {
Buffer::new(self.replica_id(), text, cx) Buffer::new(self.replica_id(), text, cx)
.with_language(language.unwrap_or(language::PLAIN_TEXT.clone()), cx) .with_language(language.unwrap_or_else(|| language::PLAIN_TEXT.clone()), cx)
}); });
self.register_buffer(&buffer, cx)?; self.register_buffer(&buffer, cx)?;
Ok(buffer) Ok(buffer)
@ -1791,7 +1790,7 @@ impl Project {
server server
.notify::<lsp::notification::DidCloseTextDocument>( .notify::<lsp::notification::DidCloseTextDocument>(
lsp::DidCloseTextDocumentParams { lsp::DidCloseTextDocumentParams {
text_document: lsp::TextDocumentIdentifier::new(uri.clone()), text_document: lsp::TextDocumentIdentifier::new(uri),
}, },
) )
.log_err(); .log_err();
@ -1825,7 +1824,7 @@ impl Project {
language_server = self language_server = self
.language_server_ids .language_server_ids
.get(&(worktree_id, adapter.name.clone())) .get(&(worktree_id, adapter.name.clone()))
.and_then(|id| self.language_servers.get(&id)) .and_then(|id| self.language_servers.get(id))
.and_then(|server_state| { .and_then(|server_state| {
if let LanguageServerState::Running { server, .. } = server_state { if let LanguageServerState::Running { server, .. } = server_state {
Some(server.clone()) Some(server.clone())
@ -1838,7 +1837,7 @@ impl Project {
if let Some(local_worktree) = file.worktree.read(cx).as_local() { if let Some(local_worktree) = file.worktree.read(cx).as_local() {
if let Some(diagnostics) = local_worktree.diagnostics_for_path(file.path()) { if let Some(diagnostics) = local_worktree.diagnostics_for_path(file.path()) {
self.update_buffer_diagnostics(&buffer_handle, diagnostics, None, cx) self.update_buffer_diagnostics(buffer_handle, diagnostics, None, cx)
.log_err(); .log_err();
} }
} }
@ -1853,8 +1852,7 @@ impl Project {
0, 0,
initial_snapshot.text(), initial_snapshot.text(),
), ),
} },
.clone(),
) )
.log_err(); .log_err();
buffer_handle.update(cx, |buffer, cx| { buffer_handle.update(cx, |buffer, cx| {
@ -1864,7 +1862,7 @@ impl Project {
.completion_provider .completion_provider
.as_ref() .as_ref()
.and_then(|provider| provider.trigger_characters.clone()) .and_then(|provider| provider.trigger_characters.clone())
.unwrap_or(Vec::new()), .unwrap_or_default(),
cx, cx,
) )
}); });
@ -1910,7 +1908,7 @@ impl Project {
let request = self.client.request(proto::UpdateBuffer { let request = self.client.request(proto::UpdateBuffer {
project_id, project_id,
buffer_id: buffer.read(cx).remote_id(), buffer_id: buffer.read(cx).remote_id(),
operations: vec![language::proto::serialize_operation(&operation)], operations: vec![language::proto::serialize_operation(operation)],
}); });
cx.background().spawn(request).detach_and_log_err(cx); cx.background().spawn(request).detach_and_log_err(cx);
} else if let Some(project_id) = self.remote_id() { } else if let Some(project_id) = self.remote_id() {
@ -2014,7 +2012,7 @@ impl Project {
.filter_map(move |((language_server_worktree_id, _), id)| { .filter_map(move |((language_server_worktree_id, _), id)| {
if *language_server_worktree_id == worktree_id { if *language_server_worktree_id == worktree_id {
if let Some(LanguageServerState::Running { adapter, server }) = if let Some(LanguageServerState::Running { adapter, server }) =
self.language_servers.get(&id) self.language_servers.get(id)
{ {
return Some((adapter, server)); return Some((adapter, server));
} }
@ -2151,7 +2149,7 @@ impl Project {
let this = this.downgrade(); let this = this.downgrade();
let adapter = adapter.clone(); let adapter = adapter.clone();
move |mut params, cx| { move |mut params, cx| {
let this = this.clone(); let this = this;
let adapter = adapter.clone(); let adapter = adapter.clone();
cx.spawn(|mut cx| async move { cx.spawn(|mut cx| async move {
adapter.process_diagnostics(&mut params).await; adapter.process_diagnostics(&mut params).await;
@ -2371,7 +2369,7 @@ impl Project {
.and_then(|provider| { .and_then(|provider| {
provider.trigger_characters.clone() provider.trigger_characters.clone()
}) })
.unwrap_or(Vec::new()), .unwrap_or_default(),
cx, cx,
) )
}); });
@ -2502,10 +2500,8 @@ impl Project {
.cloned() .cloned()
{ {
for orphaned_worktree in orphaned_worktrees { for orphaned_worktree in orphaned_worktrees {
this.language_server_ids.insert( this.language_server_ids
(orphaned_worktree, server_name.clone()), .insert((orphaned_worktree, server_name.clone()), new_server_id);
new_server_id.clone(),
);
} }
} }
}); });
@ -2528,9 +2524,7 @@ impl Project {
return; return;
} }
}; };
let progress = match progress.value { let lsp::ProgressParamsValue::WorkDone(progress) = progress.value;
lsp::ProgressParamsValue::WorkDone(value) => value,
};
let language_server_status = let language_server_status =
if let Some(status) = self.language_server_statuses.get_mut(&server_id) { if let Some(status) = self.language_server_statuses.get_mut(&server_id) {
status status
@ -2543,7 +2537,7 @@ impl Project {
} }
let is_disk_based_diagnostics_progress = let is_disk_based_diagnostics_progress =
Some(token.as_ref()) == disk_based_diagnostics_progress_token.as_ref().map(|x| &**x); Some(token.as_ref()) == disk_based_diagnostics_progress_token.as_deref();
match progress { match progress {
lsp::WorkDoneProgress::Begin(report) => { lsp::WorkDoneProgress::Begin(report) => {
@ -2796,7 +2790,7 @@ impl Project {
} else { } else {
let group_id = post_inc(&mut self.next_diagnostic_group_id); let group_id = post_inc(&mut self.next_diagnostic_group_id);
let is_disk_based = let is_disk_based =
source.map_or(false, |source| disk_based_sources.contains(&source)); source.map_or(false, |source| disk_based_sources.contains(source));
sources_by_group_id.insert(group_id, source); sources_by_group_id.insert(group_id, source);
primary_diagnostic_group_ids primary_diagnostic_group_ids
@ -3194,7 +3188,7 @@ impl Project {
if let Some(lsp_edits) = lsp_edits { if let Some(lsp_edits) = lsp_edits {
let edits = this let edits = this
.update(cx, |this, cx| { .update(cx, |this, cx| {
this.edits_from_lsp(&buffer, lsp_edits, None, cx) this.edits_from_lsp(buffer, lsp_edits, None, cx)
}) })
.await?; .await?;
buffer.update(cx, |buffer, cx| { buffer.update(cx, |buffer, cx| {
@ -3366,7 +3360,7 @@ impl Project {
if let Some((worktree, rel_path)) = if let Some((worktree, rel_path)) =
this.find_local_worktree(&abs_path, cx) this.find_local_worktree(&abs_path, cx)
{ {
worktree_id = (&worktree.read(cx)).id(); worktree_id = worktree.read(cx).id();
path = rel_path; path = rel_path;
} else { } else {
path = relativize_path(&worktree_abs_path, &abs_path); path = relativize_path(&worktree_abs_path, &abs_path);
@ -3613,7 +3607,7 @@ impl Project {
.clone(); .clone();
( (
snapshot.anchor_before(start)..snapshot.anchor_after(end), snapshot.anchor_before(start)..snapshot.anchor_after(end),
text.clone(), text,
) )
} }
Some(lsp::CompletionTextEdit::InsertAndReplace(_)) => { Some(lsp::CompletionTextEdit::InsertAndReplace(_)) => {
@ -3791,7 +3785,7 @@ impl Project {
let lsp_range = range_to_lsp(range.to_point_utf16(buffer)); let lsp_range = range_to_lsp(range.to_point_utf16(buffer));
cx.foreground().spawn(async move { cx.foreground().spawn(async move {
if !lang_server.capabilities().code_action_provider.is_some() { if lang_server.capabilities().code_action_provider.is_none() {
return Ok(Default::default()); return Ok(Default::default());
} }
@ -4120,6 +4114,7 @@ impl Project {
) )
} }
#[allow(clippy::type_complexity)]
pub fn search( pub fn search(
&self, &self,
query: SearchQuery, query: SearchQuery,
@ -4341,7 +4336,7 @@ impl Project {
) { ) {
let lsp_params = request.to_lsp(&file.abs_path(cx), cx); let lsp_params = request.to_lsp(&file.abs_path(cx), cx);
return cx.spawn(|this, cx| async move { return cx.spawn(|this, cx| async move {
if !request.check_capabilities(&language_server.capabilities()) { if !request.check_capabilities(language_server.capabilities()) {
return Ok(Default::default()); return Ok(Default::default());
} }
@ -4375,7 +4370,7 @@ impl Project {
) -> Task<Result<(ModelHandle<Worktree>, PathBuf)>> { ) -> Task<Result<(ModelHandle<Worktree>, PathBuf)>> {
let abs_path = abs_path.as_ref(); let abs_path = abs_path.as_ref();
if let Some((tree, relative_path)) = self.find_local_worktree(abs_path, cx) { if let Some((tree, relative_path)) = self.find_local_worktree(abs_path, cx) {
Task::ready(Ok((tree.clone(), relative_path.into()))) Task::ready(Ok((tree, relative_path)))
} else { } else {
let worktree = self.create_local_worktree(abs_path, visible, cx); let worktree = self.create_local_worktree(abs_path, visible, cx);
cx.foreground() cx.foreground()
@ -4455,7 +4450,7 @@ impl Project {
Ok(worktree) Ok(worktree)
} }
.map_err(|err| Arc::new(err)) .map_err(Arc::new)
}) })
.shared() .shared()
}) })
@ -4487,9 +4482,9 @@ impl Project {
} }
fn add_worktree(&mut self, worktree: &ModelHandle<Worktree>, cx: &mut ModelContext<Self>) { fn add_worktree(&mut self, worktree: &ModelHandle<Worktree>, cx: &mut ModelContext<Self>) {
cx.observe(&worktree, |_, _, cx| cx.notify()).detach(); cx.observe(worktree, |_, _, cx| cx.notify()).detach();
if worktree.read(cx).is_local() { if worktree.read(cx).is_local() {
cx.subscribe(&worktree, |this, worktree, _, cx| { cx.subscribe(worktree, |this, worktree, _, cx| {
this.update_local_worktree_buffers(worktree, cx); this.update_local_worktree_buffers(worktree, cx);
}) })
.detach(); .detach();
@ -4508,7 +4503,7 @@ impl Project {
} }
self.metadata_changed(true, cx); self.metadata_changed(true, cx);
cx.observe_release(&worktree, |this, worktree, cx| { cx.observe_release(worktree, |this, worktree, cx| {
this.remove_worktree(worktree.id(), cx); this.remove_worktree(worktree.id(), cx);
cx.notify(); cx.notify();
}) })
@ -4610,9 +4605,9 @@ impl Project {
} }
} }
pub fn language_servers_running_disk_based_diagnostics<'a>( pub fn language_servers_running_disk_based_diagnostics(
&'a self, &self,
) -> impl 'a + Iterator<Item = usize> { ) -> impl Iterator<Item = usize> + '_ {
self.language_server_statuses self.language_server_statuses
.iter() .iter()
.filter_map(|(id, status)| { .filter_map(|(id, status)| {
@ -4762,7 +4757,7 @@ impl Project {
.remove(&peer_id) .remove(&peer_id)
.ok_or_else(|| anyhow!("unknown peer {:?}", peer_id))? .ok_or_else(|| anyhow!("unknown peer {:?}", peer_id))?
.replica_id; .replica_id;
for (_, buffer) in &this.opened_buffers { for buffer in this.opened_buffers.values() {
if let Some(buffer) = buffer.upgrade(cx) { if let Some(buffer) = buffer.upgrade(cx) {
buffer.update(cx, |buffer, cx| buffer.remove_peer(replica_id, cx)); buffer.update(cx, |buffer, cx| buffer.remove_peer(replica_id, cx));
} }
@ -5088,7 +5083,7 @@ impl Project {
let ops = payload let ops = payload
.operations .operations
.into_iter() .into_iter()
.map(|op| language::proto::deserialize_operation(op)) .map(language::proto::deserialize_operation)
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
let is_remote = this.is_remote(); let is_remote = this.is_remote();
match this.opened_buffers.entry(buffer_id) { match this.opened_buffers.entry(buffer_id) {
@ -5125,7 +5120,7 @@ impl Project {
let worktree = this let worktree = this
.worktree_for_id(WorktreeId::from_proto(file.worktree_id), cx) .worktree_for_id(WorktreeId::from_proto(file.worktree_id), cx)
.ok_or_else(|| anyhow!("no such worktree"))?; .ok_or_else(|| anyhow!("no such worktree"))?;
let file = File::from_proto(file, worktree.clone(), cx)?; let file = File::from_proto(file, worktree, cx)?;
let buffer = this let buffer = this
.opened_buffers .opened_buffers
.get_mut(&buffer_id) .get_mut(&buffer_id)
@ -5791,6 +5786,7 @@ impl Project {
}) })
} }
#[allow(clippy::type_complexity)]
fn edits_from_lsp( fn edits_from_lsp(
&mut self, &mut self,
buffer: &ModelHandle<Buffer>, buffer: &ModelHandle<Buffer>,
@ -5837,7 +5833,7 @@ impl Project {
new_text.push('\n'); new_text.push('\n');
} }
range.end = next_range.end; range.end = next_range.end;
new_text.push_str(&next_text); new_text.push_str(next_text);
lsp_edits.next(); lsp_edits.next();
} }
@ -5872,7 +5868,7 @@ impl Project {
ChangeTag::Insert => { ChangeTag::Insert => {
if moved_since_edit { if moved_since_edit {
let anchor = snapshot.anchor_after(offset); let anchor = snapshot.anchor_after(offset);
edits.push((anchor.clone()..anchor, value.to_string())); edits.push((anchor..anchor, value.to_string()));
} else { } else {
edits.last_mut().unwrap().1.push_str(value); edits.last_mut().unwrap().1.push_str(value);
} }
@ -5882,7 +5878,7 @@ impl Project {
} }
} else if range.end == range.start { } else if range.end == range.start {
let anchor = snapshot.anchor_after(range.start); let anchor = snapshot.anchor_after(range.start);
edits.push((anchor.clone()..anchor, new_text)); edits.push((anchor..anchor, new_text));
} else { } else {
let edit_start = snapshot.anchor_after(range.start); let edit_start = snapshot.anchor_after(range.start);
let edit_end = snapshot.anchor_before(range.end); let edit_end = snapshot.anchor_before(range.end);
@ -5944,7 +5940,7 @@ impl Project {
if let Some(server_id) = self.language_server_ids.get(&key) { if let Some(server_id) = self.language_server_ids.get(&key) {
if let Some(LanguageServerState::Running { adapter, server }) = if let Some(LanguageServerState::Running { adapter, server }) =
self.language_servers.get(&server_id) self.language_servers.get(server_id)
{ {
return Some((adapter, server)); return Some((adapter, server));
} }

View File

@ -499,7 +499,7 @@ async fn test_single_file_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
}); });
buffer_a.read_with(cx, |buffer, _| { buffer_a.read_with(cx, |buffer, _| {
let chunks = chunks_with_diagnostics(&buffer, 0..buffer.len()); let chunks = chunks_with_diagnostics(buffer, 0..buffer.len());
assert_eq!( assert_eq!(
chunks chunks
.iter() .iter()
@ -513,7 +513,7 @@ async fn test_single_file_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
); );
}); });
buffer_b.read_with(cx, |buffer, _| { buffer_b.read_with(cx, |buffer, _| {
let chunks = chunks_with_diagnostics(&buffer, 0..buffer.len()); let chunks = chunks_with_diagnostics(buffer, 0..buffer.len());
assert_eq!( assert_eq!(
chunks chunks
.iter() .iter()
@ -579,7 +579,7 @@ async fn test_hidden_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
.await .await
.unwrap(); .unwrap();
buffer.read_with(cx, |buffer, _| { buffer.read_with(cx, |buffer, _| {
let chunks = chunks_with_diagnostics(&buffer, 0..buffer.len()); let chunks = chunks_with_diagnostics(buffer, 0..buffer.len());
assert_eq!( assert_eq!(
chunks chunks
.iter() .iter()
@ -1262,7 +1262,7 @@ async fn test_empty_diagnostic_ranges(cx: &mut gpui::TestAppContext) {
// At the end of a line, an empty range is extended backward to include // At the end of a line, an empty range is extended backward to include
// the preceding character. // the preceding character.
buffer.read_with(cx, |buffer, _| { buffer.read_with(cx, |buffer, _| {
let chunks = chunks_with_diagnostics(&buffer, 0..buffer.len()); let chunks = chunks_with_diagnostics(buffer, 0..buffer.len());
assert_eq!( assert_eq!(
chunks chunks
.iter() .iter()
@ -1511,7 +1511,7 @@ async fn test_edits_from_lsp_with_edits_on_adjacent_lines(cx: &mut gpui::TestApp
.into_iter() .into_iter()
.map(|(range, text)| { .map(|(range, text)| {
( (
range.start.to_point(&buffer)..range.end.to_point(&buffer), range.start.to_point(buffer)..range.end.to_point(buffer),
text, text,
) )
}) })
@ -1614,7 +1614,7 @@ async fn test_invalid_edits_from_lsp(cx: &mut gpui::TestAppContext) {
.into_iter() .into_iter()
.map(|(range, text)| { .map(|(range, text)| {
( (
range.start.to_point(&buffer)..range.end.to_point(&buffer), range.start.to_point(buffer)..range.end.to_point(buffer),
text, text,
) )
}) })
@ -2139,7 +2139,7 @@ async fn test_rescan_and_remote_updates(
let tree = project.worktrees(cx).next().unwrap(); let tree = project.worktrees(cx).next().unwrap();
tree.read(cx) tree.read(cx)
.entry_for_path(path) .entry_for_path(path)
.expect(&format!("no entry for path {}", path)) .unwrap_or_else(|| panic!("no entry for path {}", path))
.id .id
}) })
}; };
@ -2149,9 +2149,9 @@ async fn test_rescan_and_remote_updates(
let buffer4 = buffer_for_path("b/c/file4", cx).await; let buffer4 = buffer_for_path("b/c/file4", cx).await;
let buffer5 = buffer_for_path("b/c/file5", cx).await; let buffer5 = buffer_for_path("b/c/file5", cx).await;
let file2_id = id_for_path("a/file2", &cx); let file2_id = id_for_path("a/file2", cx);
let file3_id = id_for_path("a/file3", &cx); let file3_id = id_for_path("a/file3", cx);
let file4_id = id_for_path("b/c/file4", &cx); let file4_id = id_for_path("b/c/file4", cx);
// Create a remote copy of this worktree. // Create a remote copy of this worktree.
let tree = project.read_with(cx, |project, cx| project.worktrees(cx).next().unwrap()); let tree = project.read_with(cx, |project, cx| project.worktrees(cx).next().unwrap());
@ -2183,12 +2183,12 @@ async fn test_rescan_and_remote_updates(
}); });
// Rename and delete files and directories. // Rename and delete files and directories.
tree.flush_fs_events(&cx).await; tree.flush_fs_events(cx).await;
std::fs::rename(dir.path().join("a/file3"), dir.path().join("b/c/file3")).unwrap(); std::fs::rename(dir.path().join("a/file3"), dir.path().join("b/c/file3")).unwrap();
std::fs::remove_file(dir.path().join("b/c/file5")).unwrap(); std::fs::remove_file(dir.path().join("b/c/file5")).unwrap();
std::fs::rename(dir.path().join("b/c"), dir.path().join("d")).unwrap(); std::fs::rename(dir.path().join("b/c"), dir.path().join("d")).unwrap();
std::fs::rename(dir.path().join("a/file2"), dir.path().join("a/file2.new")).unwrap(); std::fs::rename(dir.path().join("a/file2"), dir.path().join("a/file2.new")).unwrap();
tree.flush_fs_events(&cx).await; tree.flush_fs_events(cx).await;
let expected_paths = vec![ let expected_paths = vec![
"a", "a",
@ -2209,9 +2209,9 @@ async fn test_rescan_and_remote_updates(
expected_paths expected_paths
); );
assert_eq!(id_for_path("a/file2.new", &cx), file2_id); assert_eq!(id_for_path("a/file2.new", cx), file2_id);
assert_eq!(id_for_path("d/file3", &cx), file3_id); assert_eq!(id_for_path("d/file3", cx), file3_id);
assert_eq!(id_for_path("d/file4", &cx), file4_id); assert_eq!(id_for_path("d/file4", cx), file4_id);
assert_eq!( assert_eq!(
buffer2.read(app).file().unwrap().path().as_ref(), buffer2.read(app).file().unwrap().path().as_ref(),
@ -2689,7 +2689,7 @@ async fn test_grouped_diagnostics(cx: &mut gpui::TestAppContext) {
message: "error 2 hint 2".to_string(), message: "error 2 hint 2".to_string(),
related_information: Some(vec![lsp::DiagnosticRelatedInformation { related_information: Some(vec![lsp::DiagnosticRelatedInformation {
location: lsp::Location { location: lsp::Location {
uri: buffer_uri.clone(), uri: buffer_uri,
range: lsp::Range::new(lsp::Position::new(2, 8), lsp::Position::new(2, 17)), range: lsp::Range::new(lsp::Position::new(2, 8), lsp::Position::new(2, 17)),
}, },
message: "original diagnostic".to_string(), message: "original diagnostic".to_string(),

View File

@ -53,7 +53,7 @@ impl SearchQuery {
query = word_query query = word_query
} }
let multiline = query.contains("\n") || query.contains("\\n"); let multiline = query.contains('\n') || query.contains("\\n");
let regex = RegexBuilder::new(&query) let regex = RegexBuilder::new(&query)
.case_insensitive(!case_sensitive) .case_insensitive(!case_sensitive)
.multi_line(multiline) .multi_line(multiline)

View File

@ -57,6 +57,7 @@ lazy_static! {
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)] #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)]
pub struct WorktreeId(usize); pub struct WorktreeId(usize);
#[allow(clippy::large_enum_variant)]
pub enum Worktree { pub enum Worktree {
Local(LocalWorktree), Local(LocalWorktree),
Remote(RemoteWorktree), Remote(RemoteWorktree),
@ -157,7 +158,7 @@ impl Worktree {
cx: &mut AsyncAppContext, cx: &mut AsyncAppContext,
) -> Result<ModelHandle<Self>> { ) -> Result<ModelHandle<Self>> {
let (tree, scan_states_tx) = let (tree, scan_states_tx) =
LocalWorktree::new(client, path, visible, fs.clone(), next_entry_id, cx).await?; LocalWorktree::create(client, path, visible, fs.clone(), next_entry_id, cx).await?;
tree.update(cx, |tree, cx| { tree.update(cx, |tree, cx| {
let tree = tree.as_local_mut().unwrap(); let tree = tree.as_local_mut().unwrap();
let abs_path = tree.abs_path().clone(); let abs_path = tree.abs_path().clone();
@ -229,7 +230,7 @@ impl Worktree {
cx.spawn(|mut cx| { cx.spawn(|mut cx| {
let this = worktree_handle.downgrade(); let this = worktree_handle.downgrade();
async move { async move {
while let Some(_) = snapshot_updated_rx.recv().await { while (snapshot_updated_rx.recv().await).is_some() {
if let Some(this) = this.upgrade(&cx) { if let Some(this) = this.upgrade(&cx) {
this.update(&mut cx, |this, cx| { this.update(&mut cx, |this, cx| {
this.poll_snapshot(cx); this.poll_snapshot(cx);
@ -322,15 +323,15 @@ impl Worktree {
} }
} }
pub fn diagnostic_summaries<'a>( pub fn diagnostic_summaries(
&'a self, &self,
) -> impl Iterator<Item = (Arc<Path>, DiagnosticSummary)> + 'a { ) -> impl Iterator<Item = (Arc<Path>, DiagnosticSummary)> + '_ {
match self { match self {
Worktree::Local(worktree) => &worktree.diagnostic_summaries, Worktree::Local(worktree) => &worktree.diagnostic_summaries,
Worktree::Remote(worktree) => &worktree.diagnostic_summaries, Worktree::Remote(worktree) => &worktree.diagnostic_summaries,
} }
.iter() .iter()
.map(|(path, summary)| (path.0.clone(), summary.clone())) .map(|(path, summary)| (path.0.clone(), *summary))
} }
fn poll_snapshot(&mut self, cx: &mut ModelContext<Self>) { fn poll_snapshot(&mut self, cx: &mut ModelContext<Self>) {
@ -342,7 +343,7 @@ impl Worktree {
} }
impl LocalWorktree { impl LocalWorktree {
async fn new( async fn create(
client: Arc<Client>, client: Arc<Client>,
path: impl Into<Arc<Path>>, path: impl Into<Arc<Path>>,
visible: bool, visible: bool,
@ -386,7 +387,7 @@ impl LocalWorktree {
}; };
if let Some(metadata) = metadata { if let Some(metadata) = metadata {
let entry = Entry::new( let entry = Entry::new(
path.into(), path,
&metadata, &metadata,
&snapshot.next_entry_id, &snapshot.next_entry_id,
snapshot.root_char_bag, snapshot.root_char_bag,
@ -651,7 +652,7 @@ impl LocalWorktree {
let abs_path = self.absolutize(&entry.path); let abs_path = self.absolutize(&entry.path);
let delete = cx.background().spawn({ let delete = cx.background().spawn({
let fs = self.fs.clone(); let fs = self.fs.clone();
let abs_path = abs_path.clone(); let abs_path = abs_path;
async move { async move {
if entry.is_file() { if entry.is_file() {
fs.remove_file(&abs_path, Default::default()).await fs.remove_file(&abs_path, Default::default()).await
@ -848,7 +849,7 @@ impl LocalWorktree {
let rpc = self.client.clone(); let rpc = self.client.clone();
let worktree_id = cx.model_id() as u64; let worktree_id = cx.model_id() as u64;
let maintain_remote_snapshot = cx.background().spawn({ let maintain_remote_snapshot = cx.background().spawn({
let rpc = rpc.clone(); let rpc = rpc;
let diagnostic_summaries = self.diagnostic_summaries.clone(); let diagnostic_summaries = self.diagnostic_summaries.clone();
async move { async move {
let mut prev_snapshot = match snapshots_rx.recv().await { let mut prev_snapshot = match snapshots_rx.recv().await {
@ -1002,10 +1003,9 @@ impl RemoteWorktree {
warning_count: summary.warning_count as usize, warning_count: summary.warning_count as usize,
}; };
if summary.is_empty() { if summary.is_empty() {
self.diagnostic_summaries.remove(&PathKey(path.clone())); self.diagnostic_summaries.remove(&PathKey(path));
} else { } else {
self.diagnostic_summaries self.diagnostic_summaries.insert(PathKey(path), summary);
.insert(PathKey(path.clone()), summary);
} }
} }
@ -1513,7 +1513,7 @@ impl LocalSnapshot {
let mut ignore_stack = IgnoreStack::none(); let mut ignore_stack = IgnoreStack::none();
for (parent_abs_path, ignore) in new_ignores.into_iter().rev() { for (parent_abs_path, ignore) in new_ignores.into_iter().rev() {
if ignore_stack.is_abs_path_ignored(&parent_abs_path, true) { if ignore_stack.is_abs_path_ignored(parent_abs_path, true) {
ignore_stack = IgnoreStack::all(); ignore_stack = IgnoreStack::all();
break; break;
} else if let Some(ignore) = ignore { } else if let Some(ignore) = ignore {
@ -1530,8 +1530,8 @@ impl LocalSnapshot {
} }
async fn build_gitignore(abs_path: &Path, fs: &dyn Fs) -> Result<Gitignore> { async fn build_gitignore(abs_path: &Path, fs: &dyn Fs) -> Result<Gitignore> {
let contents = fs.load(&abs_path).await?; let contents = fs.load(abs_path).await?;
let parent = abs_path.parent().unwrap_or(Path::new("/")); let parent = abs_path.parent().unwrap_or_else(|| Path::new("/"));
let mut builder = GitignoreBuilder::new(parent); let mut builder = GitignoreBuilder::new(parent);
for line in contents.lines() { for line in contents.lines() {
builder.add_line(Some(abs_path.into()), line)?; builder.add_line(Some(abs_path.into()), line)?;
@ -1769,7 +1769,7 @@ impl language::LocalFile for File {
.send(proto::BufferReloaded { .send(proto::BufferReloaded {
project_id, project_id,
buffer_id, buffer_id,
version: serialize_version(&version), version: serialize_version(version),
mtime: Some(mtime.into()), mtime: Some(mtime.into()),
fingerprint, fingerprint,
line_ending: serialize_line_ending(line_ending) as i32, line_ending: serialize_line_ending(line_ending) as i32,
@ -2285,7 +2285,7 @@ impl BackgroundScanner {
snapshot.scan_id += 1; snapshot.scan_id += 1;
for event in &events { for event in &events {
if let Ok(path) = event.path.strip_prefix(&root_canonical_path) { if let Ok(path) = event.path.strip_prefix(&root_canonical_path) {
snapshot.remove_path(&path); snapshot.remove_path(path);
} }
} }
@ -2528,13 +2528,13 @@ impl WorktreeHandle for ModelHandle<Worktree> {
fs.create_file(&root_path.join(filename), Default::default()) fs.create_file(&root_path.join(filename), Default::default())
.await .await
.unwrap(); .unwrap();
tree.condition(&cx, |tree, _| tree.entry_for_path(filename).is_some()) tree.condition(cx, |tree, _| tree.entry_for_path(filename).is_some())
.await; .await;
fs.remove_file(&root_path.join(filename), Default::default()) fs.remove_file(&root_path.join(filename), Default::default())
.await .await
.unwrap(); .unwrap();
tree.condition(&cx, |tree, _| tree.entry_for_path(filename).is_none()) tree.condition(cx, |tree, _| tree.entry_for_path(filename).is_none())
.await; .await;
cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete()) cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
@ -2726,7 +2726,7 @@ impl<'a> TryFrom<(&'a CharBag, proto::Entry)> for Entry {
let kind = if entry.is_dir { let kind = if entry.is_dir {
EntryKind::Dir EntryKind::Dir
} else { } else {
let mut char_bag = root_char_bag.clone(); let mut char_bag = *root_char_bag;
char_bag.extend( char_bag.extend(
String::from_utf8_lossy(&entry.path) String::from_utf8_lossy(&entry.path)
.chars() .chars()
@ -2738,7 +2738,7 @@ impl<'a> TryFrom<(&'a CharBag, proto::Entry)> for Entry {
Ok(Entry { Ok(Entry {
id: ProjectEntryId::from_proto(entry.id), id: ProjectEntryId::from_proto(entry.id),
kind, kind,
path: path.clone(), path,
inode: entry.inode, inode: entry.inode,
mtime: mtime.into(), mtime: mtime.into(),
is_symlink: entry.is_symlink, is_symlink: entry.is_symlink,
@ -2955,7 +2955,7 @@ mod tests {
.unwrap(); .unwrap();
cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete()) cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
.await; .await;
tree.flush_fs_events(&cx).await; tree.flush_fs_events(cx).await;
cx.read(|cx| { cx.read(|cx| {
let tree = tree.read(cx); let tree = tree.read(cx);
assert!( assert!(
@ -2979,7 +2979,7 @@ mod tests {
std::fs::write(dir.join("tracked-dir/tracked-file2"), "").unwrap(); std::fs::write(dir.join("tracked-dir/tracked-file2"), "").unwrap();
std::fs::write(dir.join("tracked-dir/ancestor-ignored-file2"), "").unwrap(); std::fs::write(dir.join("tracked-dir/ancestor-ignored-file2"), "").unwrap();
std::fs::write(dir.join("ignored-dir/ignored-file2"), "").unwrap(); std::fs::write(dir.join("ignored-dir/ignored-file2"), "").unwrap();
tree.flush_fs_events(&cx).await; tree.flush_fs_events(cx).await;
cx.read(|cx| { cx.read(|cx| {
let tree = tree.read(cx); let tree = tree.read(cx);
assert!( assert!(
@ -3026,7 +3026,7 @@ mod tests {
.unwrap(); .unwrap();
cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete()) cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
.await; .await;
tree.flush_fs_events(&cx).await; tree.flush_fs_events(cx).await;
tree.update(cx, |tree, cx| { tree.update(cx, |tree, cx| {
tree.as_local().unwrap().write_file( tree.as_local().unwrap().write_file(
@ -3052,8 +3052,8 @@ mod tests {
tree.read_with(cx, |tree, _| { tree.read_with(cx, |tree, _| {
let tracked = tree.entry_for_path("tracked-dir/file.txt").unwrap(); let tracked = tree.entry_for_path("tracked-dir/file.txt").unwrap();
let ignored = tree.entry_for_path("ignored-dir/file.txt").unwrap(); let ignored = tree.entry_for_path("ignored-dir/file.txt").unwrap();
assert_eq!(tracked.is_ignored, false); assert!(!tracked.is_ignored);
assert_eq!(ignored.is_ignored, true); assert!(ignored.is_ignored);
}); });
} }
@ -3226,9 +3226,9 @@ mod tests {
let mut ignore_contents = String::new(); let mut ignore_contents = String::new();
for path_to_ignore in files_to_ignore.chain(dirs_to_ignore) { for path_to_ignore in files_to_ignore.chain(dirs_to_ignore) {
write!( writeln!(
ignore_contents, ignore_contents,
"{}\n", "{}",
path_to_ignore path_to_ignore
.strip_prefix(&ignore_dir_path)? .strip_prefix(&ignore_dir_path)?
.to_str() .to_str()
@ -3363,7 +3363,7 @@ mod tests {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
assert_eq!(dfs_paths_via_traversal, dfs_paths_via_iter); assert_eq!(dfs_paths_via_traversal, dfs_paths_via_iter);
for (ignore_parent_abs_path, _) in &self.ignores_by_parent_abs_path { for ignore_parent_abs_path in self.ignores_by_parent_abs_path.keys() {
let ignore_parent_path = let ignore_parent_path =
ignore_parent_abs_path.strip_prefix(&self.abs_path).unwrap(); ignore_parent_abs_path.strip_prefix(&self.abs_path).unwrap();
assert!(self.entry_for_path(&ignore_parent_path).is_some()); assert!(self.entry_for_path(&ignore_parent_path).is_some());
@ -3389,7 +3389,7 @@ mod tests {
paths.push((entry.path.as_ref(), entry.inode, entry.is_ignored)); paths.push((entry.path.as_ref(), entry.inode, entry.is_ignored));
} }
} }
paths.sort_by(|a, b| a.0.cmp(&b.0)); paths.sort_by(|a, b| a.0.cmp(b.0));
paths paths
} }
} }

View File

@ -186,8 +186,8 @@ impl ProjectPanel {
}); });
cx.observe_focus(&filename_editor, |this, _, is_focused, cx| { cx.observe_focus(&filename_editor, |this, _, is_focused, cx| {
if !is_focused { if !is_focused
if this && this
.edit_state .edit_state
.as_ref() .as_ref()
.map_or(false, |state| state.processing_filename.is_none()) .map_or(false, |state| state.processing_filename.is_none())
@ -195,7 +195,6 @@ impl ProjectPanel {
this.edit_state = None; this.edit_state = None;
this.update_visible_entries(None, cx); this.update_visible_entries(None, cx);
} }
}
}) })
.detach(); .detach();
@ -209,7 +208,7 @@ impl ProjectPanel {
edit_state: None, edit_state: None,
filename_editor, filename_editor,
clipboard_entry: None, clipboard_entry: None,
context_menu: cx.add_view(|cx| ContextMenu::new(cx)), context_menu: cx.add_view(ContextMenu::new),
}; };
this.update_visible_entries(None, cx); this.update_visible_entries(None, cx);
this this
@ -380,14 +379,12 @@ impl ProjectPanel {
self.index_for_selection(selection).unwrap_or_default(); self.index_for_selection(selection).unwrap_or_default();
if entry_ix > 0 { if entry_ix > 0 {
entry_ix -= 1; entry_ix -= 1;
} else { } else if worktree_ix > 0 {
if worktree_ix > 0 {
worktree_ix -= 1; worktree_ix -= 1;
entry_ix = self.visible_entries[worktree_ix].1.len() - 1; entry_ix = self.visible_entries[worktree_ix].1.len() - 1;
} else { } else {
return; return;
} }
}
let (worktree_id, worktree_entries) = &self.visible_entries[worktree_ix]; let (worktree_id, worktree_entries) = &self.visible_entries[worktree_ix];
self.selection = Some(Selection { self.selection = Some(Selection {
@ -734,17 +731,15 @@ impl ProjectPanel {
self.clipboard_entry.take(); self.clipboard_entry.take();
if clipboard_entry.is_cut() { if clipboard_entry.is_cut() {
self.project if let Some(task) = self.project.update(cx, |project, cx| {
.update(cx, |project, cx| {
project.rename_entry(clipboard_entry.entry_id(), new_path, cx) project.rename_entry(clipboard_entry.entry_id(), new_path, cx)
}) }) {
.map(|task| task.detach_and_log_err(cx)); task.detach_and_log_err(cx)
} else { }
self.project } else if let Some(task) = self.project.update(cx, |project, cx| {
.update(cx, |project, cx| {
project.copy_entry(clipboard_entry.entry_id(), new_path, cx) project.copy_entry(clipboard_entry.entry_id(), new_path, cx)
}) }) {
.map(|task| task.detach_and_log_err(cx)); task.detach_and_log_err(cx)
} }
} }
None None
@ -760,10 +755,9 @@ impl ProjectPanel {
} }
fn index_for_selection(&self, selection: Selection) -> Option<(usize, usize, usize)> { fn index_for_selection(&self, selection: Selection) -> Option<(usize, usize, usize)> {
let mut worktree_index = 0;
let mut entry_index = 0; let mut entry_index = 0;
let mut visible_entries_index = 0; let mut visible_entries_index = 0;
for (worktree_id, worktree_entries) in &self.visible_entries { for (worktree_index, (worktree_id, worktree_entries)) in self.visible_entries.iter().enumerate() {
if *worktree_id == selection.worktree_id { if *worktree_id == selection.worktree_id {
for entry in worktree_entries { for entry in worktree_entries {
if entry.id == selection.entry_id { if entry.id == selection.entry_id {
@ -777,7 +771,6 @@ impl ProjectPanel {
} else { } else {
visible_entries_index += worktree_entries.len(); visible_entries_index += worktree_entries.len();
} }
worktree_index += 1;
} }
None None
} }
@ -849,11 +842,11 @@ impl ProjectPanel {
is_ignored: false, is_ignored: false,
}); });
} }
if expanded_dir_ids.binary_search(&entry.id).is_err() { if expanded_dir_ids.binary_search(&entry.id).is_err()
if entry_iter.advance_to_sibling() { && entry_iter.advance_to_sibling()
{
continue; continue;
} }
}
entry_iter.advance(); entry_iter.advance();
} }
visible_worktree_entries.sort_by(|entry_a, entry_b| { visible_worktree_entries.sort_by(|entry_a, entry_b| {
@ -982,7 +975,7 @@ impl ProjectPanel {
if let Some(processing_filename) = &edit_state.processing_filename { if let Some(processing_filename) = &edit_state.processing_filename {
details.is_processing = true; details.is_processing = true;
details.filename.clear(); details.filename.clear();
details.filename.push_str(&processing_filename); details.filename.push_str(processing_filename);
} else { } else {
if edit_state.is_new_entry { if edit_state.is_new_entry {
details.filename.clear(); details.filename.clear();
@ -1116,7 +1109,7 @@ impl View for ProjectPanel {
cx, cx,
move |this, range, items, cx| { move |this, range, items, cx| {
let theme = cx.global::<Settings>().theme.clone(); let theme = cx.global::<Settings>().theme.clone();
this.for_each_visible_entry(range.clone(), cx, |id, details, cx| { this.for_each_visible_entry(range, cx, |id, details, cx| {
items.push(Self::render_entry( items.push(Self::render_entry(
id, id,
details, details,

View File

@ -50,6 +50,7 @@ impl Connection {
killed, killed,
); );
#[allow(clippy::type_complexity)]
fn channel( fn channel(
killed: Arc<AtomicBool>, killed: Arc<AtomicBool>,
executor: Arc<gpui::executor::Background>, executor: Arc<gpui::executor::Background>,
@ -76,9 +77,7 @@ impl Connection {
// Writes to a half-open TCP connection will error. // Writes to a half-open TCP connection will error.
if killed.load(SeqCst) { if killed.load(SeqCst) {
std::io::Result::Err( std::io::Result::Err(Error::new(ErrorKind::Other, "connection lost"))?;
Error::new(ErrorKind::Other, "connection lost").into(),
)?;
} }
Ok(msg) Ok(msg)
@ -87,7 +86,7 @@ impl Connection {
}); });
let rx = rx.then({ let rx = rx.then({
let killed = killed.clone(); let killed = killed;
let executor = Arc::downgrade(&executor); let executor = Arc::downgrade(&executor);
move |msg| { move |msg| {
let killed = killed.clone(); let killed = killed.clone();

View File

@ -94,6 +94,7 @@ pub struct ConnectionState {
#[serde(skip)] #[serde(skip)]
outgoing_tx: mpsc::UnboundedSender<proto::Message>, outgoing_tx: mpsc::UnboundedSender<proto::Message>,
next_message_id: Arc<AtomicU32>, next_message_id: Arc<AtomicU32>,
#[allow(clippy::type_complexity)]
#[serde(skip)] #[serde(skip)]
response_channels: response_channels:
Arc<Mutex<Option<HashMap<u32, oneshot::Sender<(proto::Envelope, oneshot::Sender<()>)>>>>>, Arc<Mutex<Option<HashMap<u32, oneshot::Sender<(proto::Envelope, oneshot::Sender<()>)>>>>>,
@ -139,7 +140,7 @@ impl Peer {
let connection_id = ConnectionId(self.next_connection_id.fetch_add(1, SeqCst)); let connection_id = ConnectionId(self.next_connection_id.fetch_add(1, SeqCst));
let connection_state = ConnectionState { let connection_state = ConnectionState {
outgoing_tx: outgoing_tx.clone(), outgoing_tx,
next_message_id: Default::default(), next_message_id: Default::default(),
response_channels: Arc::new(Mutex::new(Some(Default::default()))), response_channels: Arc::new(Mutex::new(Some(Default::default()))),
}; };

View File

@ -265,7 +265,9 @@ entity_messages!(
entity_messages!(channel_id, ChannelMessageSent); entity_messages!(channel_id, ChannelMessageSent);
const MAX_BUFFER_LEN: usize = 1 * 1024 * 1024; const KIB: usize = 1024;
const MIB: usize = KIB * 1024;
const MAX_BUFFER_LEN: usize = MIB;
/// A stream of protobuf messages. /// A stream of protobuf messages.
pub struct MessageStream<S> { pub struct MessageStream<S> {
@ -273,6 +275,7 @@ pub struct MessageStream<S> {
encoding_buffer: Vec<u8>, encoding_buffer: Vec<u8>,
} }
#[allow(clippy::large_enum_variant)]
#[derive(Debug)] #[derive(Debug)]
pub enum Message { pub enum Message {
Envelope(Envelope), Envelope(Envelope),
@ -309,7 +312,7 @@ where
self.encoding_buffer.reserve(message.encoded_len()); self.encoding_buffer.reserve(message.encoded_len());
message message
.encode(&mut self.encoding_buffer) .encode(&mut self.encoding_buffer)
.map_err(|err| io::Error::from(err))?; .map_err(io::Error::from)?;
let buffer = let buffer =
zstd::stream::encode_all(self.encoding_buffer.as_slice(), COMPRESSION_LEVEL) zstd::stream::encode_all(self.encoding_buffer.as_slice(), COMPRESSION_LEVEL)
.unwrap(); .unwrap();
@ -360,10 +363,10 @@ where
} }
} }
impl Into<SystemTime> for Timestamp { impl From<Timestamp> for SystemTime {
fn into(self) -> SystemTime { fn from(val: Timestamp) -> Self {
UNIX_EPOCH UNIX_EPOCH
.checked_add(Duration::new(self.seconds, self.nanos)) .checked_add(Duration::new(val.seconds, val.nanos))
.unwrap() .unwrap()
} }
} }
@ -451,7 +454,7 @@ mod tests {
.unwrap(); .unwrap();
assert!(sink.encoding_buffer.capacity() <= MAX_BUFFER_LEN); assert!(sink.encoding_buffer.capacity() <= MAX_BUFFER_LEN);
let mut stream = MessageStream::new(rx.map(|msg| anyhow::Ok(msg))); let mut stream = MessageStream::new(rx.map(anyhow::Ok));
stream.read().await.unwrap(); stream.read().await.unwrap();
assert!(stream.encoding_buffer.capacity() <= MAX_BUFFER_LEN); assert!(stream.encoding_buffer.capacity() <= MAX_BUFFER_LEN);
stream.read().await.unwrap(); stream.read().await.unwrap();

View File

@ -216,7 +216,7 @@ impl BufferSearchBar {
fn dismiss(&mut self, _: &Dismiss, cx: &mut ViewContext<Self>) { fn dismiss(&mut self, _: &Dismiss, cx: &mut ViewContext<Self>) {
self.dismissed = true; self.dismissed = true;
for (editor, _) in &self.editors_with_matches { for editor in self.editors_with_matches.keys() {
if let Some(editor) = editor.upgrade(cx) { if let Some(editor) = editor.upgrade(cx) {
editor.update(cx, |editor, cx| { editor.update(cx, |editor, cx| {
editor.clear_background_highlights::<Self>(cx) editor.clear_background_highlights::<Self>(cx)
@ -450,15 +450,12 @@ impl BufferSearchBar {
event: &editor::Event, event: &editor::Event,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) { ) {
match event { if let editor::Event::BufferEdited { .. } = event {
editor::Event::BufferEdited { .. } => {
self.query_contains_error = false; self.query_contains_error = false;
self.clear_matches(cx); self.clear_matches(cx);
self.update_matches(true, cx); self.update_matches(true, cx);
cx.notify(); cx.notify();
} }
_ => {}
}
} }
fn on_active_editor_event( fn on_active_editor_event(
@ -586,7 +583,7 @@ impl BufferSearchBar {
let ranges = self.editors_with_matches.get(&editor.downgrade())?; let ranges = self.editors_with_matches.get(&editor.downgrade())?;
let editor = editor.read(cx); let editor = editor.read(cx);
active_match_index( active_match_index(
&ranges, ranges,
&editor.selections.newest_anchor().head(), &editor.selections.newest_anchor().head(),
&editor.buffer().read(cx).snapshot(cx), &editor.buffer().read(cx).snapshot(cx),
) )
@ -610,7 +607,7 @@ mod tests {
#[gpui::test] #[gpui::test]
async fn test_search_simple(cx: &mut TestAppContext) { async fn test_search_simple(cx: &mut TestAppContext) {
let fonts = cx.font_cache(); let fonts = cx.font_cache();
let mut theme = gpui::fonts::with_font_cache(fonts.clone(), || theme::Theme::default()); let mut theme = gpui::fonts::with_font_cache(fonts.clone(), theme::Theme::default);
theme.search.match_background = Color::red(); theme.search.match_background = Color::red();
cx.update(|cx| { cx.update(|cx| {
let mut settings = Settings::test(cx); let mut settings = Settings::test(cx);
@ -649,7 +646,7 @@ mod tests {
search_bar.update(cx, |search_bar, cx| { search_bar.update(cx, |search_bar, cx| {
search_bar.set_query("us", cx); search_bar.set_query("us", cx);
}); });
editor.next_notification(&cx).await; editor.next_notification(cx).await;
editor.update(cx, |editor, cx| { editor.update(cx, |editor, cx| {
assert_eq!( assert_eq!(
editor.all_background_highlights(cx), editor.all_background_highlights(cx),
@ -670,7 +667,7 @@ mod tests {
search_bar.update(cx, |search_bar, cx| { search_bar.update(cx, |search_bar, cx| {
search_bar.toggle_search_option(SearchOption::CaseSensitive, cx); search_bar.toggle_search_option(SearchOption::CaseSensitive, cx);
}); });
editor.next_notification(&cx).await; editor.next_notification(cx).await;
editor.update(cx, |editor, cx| { editor.update(cx, |editor, cx| {
assert_eq!( assert_eq!(
editor.all_background_highlights(cx), editor.all_background_highlights(cx),
@ -686,7 +683,7 @@ mod tests {
search_bar.update(cx, |search_bar, cx| { search_bar.update(cx, |search_bar, cx| {
search_bar.set_query("or", cx); search_bar.set_query("or", cx);
}); });
editor.next_notification(&cx).await; editor.next_notification(cx).await;
editor.update(cx, |editor, cx| { editor.update(cx, |editor, cx| {
assert_eq!( assert_eq!(
editor.all_background_highlights(cx), editor.all_background_highlights(cx),
@ -727,7 +724,7 @@ mod tests {
search_bar.update(cx, |search_bar, cx| { search_bar.update(cx, |search_bar, cx| {
search_bar.toggle_search_option(SearchOption::WholeWord, cx); search_bar.toggle_search_option(SearchOption::WholeWord, cx);
}); });
editor.next_notification(&cx).await; editor.next_notification(cx).await;
editor.update(cx, |editor, cx| { editor.update(cx, |editor, cx| {
assert_eq!( assert_eq!(
editor.all_background_highlights(cx), editor.all_background_highlights(cx),

View File

@ -367,7 +367,7 @@ impl ProjectSearchView {
}); });
// Subcribe to query_editor in order to reraise editor events for workspace item activation purposes // Subcribe to query_editor in order to reraise editor events for workspace item activation purposes
cx.subscribe(&query_editor, |_, _, event, cx| { cx.subscribe(&query_editor, |_, _, event, cx| {
cx.emit(ViewEvent::EditorEvent(event.clone())) cx.emit(ViewEvent::EditorEvent(*event))
}) })
.detach(); .detach();
@ -384,7 +384,7 @@ impl ProjectSearchView {
this.update_match_index(cx); this.update_match_index(cx);
} }
// Reraise editor events for workspace item activation purposes // Reraise editor events for workspace item activation purposes
cx.emit(ViewEvent::EditorEvent(event.clone())); cx.emit(ViewEvent::EditorEvent(*event));
}) })
.detach(); .detach();
@ -567,6 +567,12 @@ impl ProjectSearchView {
} }
} }
impl Default for ProjectSearchBar {
fn default() -> Self {
Self::new()
}
}
impl ProjectSearchBar { impl ProjectSearchBar {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
@ -903,7 +909,7 @@ mod tests {
#[gpui::test] #[gpui::test]
async fn test_project_search(cx: &mut TestAppContext) { async fn test_project_search(cx: &mut TestAppContext) {
let fonts = cx.font_cache(); let fonts = cx.font_cache();
let mut theme = gpui::fonts::with_font_cache(fonts.clone(), || theme::Theme::default()); let mut theme = gpui::fonts::with_font_cache(fonts.clone(), theme::Theme::default);
theme.search.match_background = Color::red(); theme.search.match_background = Color::red();
cx.update(|cx| { cx.update(|cx| {
let mut settings = Settings::test(cx); let mut settings = Settings::test(cx);
@ -933,7 +939,7 @@ mod tests {
.update(cx, |query_editor, cx| query_editor.set_text("TWO", cx)); .update(cx, |query_editor, cx| query_editor.set_text("TWO", cx));
search_view.search(cx); search_view.search(cx);
}); });
search_view.next_notification(&cx).await; search_view.next_notification(cx).await;
search_view.update(cx, |search_view, cx| { search_view.update(cx, |search_view, cx| {
assert_eq!( assert_eq!(
search_view search_view

View File

@ -66,9 +66,9 @@ pub(crate) fn active_match_index(
None None
} else { } else {
match ranges.binary_search_by(|probe| { match ranges.binary_search_by(|probe| {
if probe.end.cmp(&cursor, &*buffer).is_lt() { if probe.end.cmp(cursor, &*buffer).is_lt() {
Ordering::Less Ordering::Less
} else if probe.start.cmp(&cursor, &*buffer).is_gt() { } else if probe.start.cmp(cursor, &*buffer).is_gt() {
Ordering::Greater Ordering::Greater
} else { } else {
Ordering::Equal Ordering::Equal
@ -86,7 +86,7 @@ pub(crate) fn match_index_for_direction(
direction: Direction, direction: Direction,
buffer: &MultiBufferSnapshot, buffer: &MultiBufferSnapshot,
) -> usize { ) -> usize {
if ranges[index].start.cmp(&cursor, &buffer).is_gt() { if ranges[index].start.cmp(cursor, buffer).is_gt() {
if direction == Direction::Prev { if direction == Direction::Prev {
if index == 0 { if index == 0 {
index = ranges.len() - 1; index = ranges.len() - 1;
@ -94,7 +94,7 @@ pub(crate) fn match_index_for_direction(
index -= 1; index -= 1;
} }
} }
} else if ranges[index].end.cmp(&cursor, &buffer).is_lt() { } else if ranges[index].end.cmp(cursor, buffer).is_lt() {
if direction == Direction::Next { if direction == Direction::Next {
index = 0; index = 0;
} }

View File

@ -49,13 +49,12 @@ impl KeymapFileContent {
pub fn load(asset_path: &str, cx: &mut MutableAppContext) -> Result<()> { pub fn load(asset_path: &str, cx: &mut MutableAppContext) -> Result<()> {
let content = Assets::get(asset_path).unwrap().data; let content = Assets::get(asset_path).unwrap().data;
let content_str = std::str::from_utf8(content.as_ref()).unwrap(); let content_str = std::str::from_utf8(content.as_ref()).unwrap();
Ok(parse_json_with_comments::<Self>(content_str)?.add(cx)?) parse_json_with_comments::<Self>(content_str)?.add_to_cx(cx)
} }
pub fn add(self, cx: &mut MutableAppContext) -> Result<()> { pub fn add_to_cx(self, cx: &mut MutableAppContext) -> Result<()> {
for KeymapBlock { context, bindings } in self.0 { for KeymapBlock { context, bindings } in self.0 {
cx.add_bindings( let bindings = bindings
bindings
.into_iter() .into_iter()
.map(|(keystroke, action)| { .map(|(keystroke, action)| {
let action = action.0.get(); let action = action.0.get();
@ -78,8 +77,9 @@ impl KeymapFileContent {
})?; })?;
Binding::load(&keystroke, action, context.as_deref()) Binding::load(&keystroke, action, context.as_deref())
}) })
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>>>()?;
)
cx.add_bindings(bindings);
} }
Ok(()) Ok(())
} }
@ -98,7 +98,7 @@ pub fn keymap_file_json_schema(action_names: &[&'static str]) -> serde_json::Val
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))), instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))),
enum_values: Some( enum_values: Some(
action_names action_names
.into_iter() .iter()
.map(|name| Value::String(name.to_string())) .map(|name| Value::String(name.to_string()))
.collect(), .collect(),
), ),

View File

@ -200,7 +200,7 @@ impl Settings {
} }
} }
if let Some(value) = &data.theme { if let Some(value) = &data.theme {
if let Some(theme) = theme_registry.get(&value.to_string()).log_err() { if let Some(theme) = theme_registry.get(value).log_err() {
self.theme = theme; self.theme = theme;
} }
} }
@ -301,7 +301,7 @@ impl Settings {
language_overrides: Default::default(), language_overrides: Default::default(),
lsp: Default::default(), lsp: Default::default(),
projects_online_by_default: true, projects_online_by_default: true,
theme: gpui::fonts::with_font_cache(cx.font_cache().clone(), || Default::default()), theme: gpui::fonts::with_font_cache(cx.font_cache().clone(), Default::default),
} }
} }
@ -309,7 +309,7 @@ impl Settings {
pub fn test_async(cx: &mut gpui::TestAppContext) { pub fn test_async(cx: &mut gpui::TestAppContext) {
cx.update(|cx| { cx.update(|cx| {
let settings = Self::test(cx); let settings = Self::test(cx);
cx.set_global(settings.clone()); cx.set_global(settings);
}); });
} }
} }
@ -327,12 +327,7 @@ pub fn settings_file_json_schema(
// Create a schema for a theme name. // Create a schema for a theme name.
let theme_name_schema = SchemaObject { let theme_name_schema = SchemaObject {
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))), instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))),
enum_values: Some( enum_values: Some(theme_names.into_iter().map(Value::String).collect()),
theme_names
.into_iter()
.map(|name| Value::String(name))
.collect(),
),
..Default::default() ..Default::default()
}; };

View File

@ -78,22 +78,22 @@ fn parse_tabstop<'a>(
) -> Result<&'a str> { ) -> Result<&'a str> {
let tabstop_start = text.len(); let tabstop_start = text.len();
let tabstop_index; let tabstop_index;
if source.chars().next() == Some('{') { if source.starts_with('{') {
let (index, rest) = parse_int(&source[1..])?; let (index, rest) = parse_int(&source[1..])?;
tabstop_index = index; tabstop_index = index;
source = rest; source = rest;
if source.chars().next() == Some(':') { if source.starts_with(':') {
source = parse_snippet(&source[1..], true, text, tabstops)?; source = parse_snippet(&source[1..], true, text, tabstops)?;
} }
if source.chars().next() == Some('}') { if source.starts_with('}') {
source = &source[1..]; source = &source[1..];
} else { } else {
return Err(anyhow!("expected a closing brace")); return Err(anyhow!("expected a closing brace"));
} }
} else { } else {
let (index, rest) = parse_int(&source)?; let (index, rest) = parse_int(source)?;
tabstop_index = index; tabstop_index = index;
source = rest; source = rest;
} }

View File

@ -160,7 +160,7 @@ where
let mut descending = false; let mut descending = false;
while !self.stack.is_empty() { while !self.stack.is_empty() {
if let Some(StackEntry { position, .. }) = self.stack.iter().rev().skip(1).next() { if let Some(StackEntry { position, .. }) = self.stack.iter().rev().nth(1) {
self.position = position.clone(); self.position = position.clone();
} else { } else {
self.position = D::default(); self.position = D::default();
@ -224,7 +224,7 @@ where
self.did_seek = true; self.did_seek = true;
} }
while self.stack.len() > 0 { while !self.stack.is_empty() {
let new_subtree = { let new_subtree = {
let entry = self.stack.last_mut().unwrap(); let entry = self.stack.last_mut().unwrap();
match entry.tree.0.as_ref() { match entry.tree.0.as_ref() {
@ -409,7 +409,7 @@ where
.zip(&child_summaries[entry.index..]) .zip(&child_summaries[entry.index..])
{ {
let mut child_end = self.position.clone(); let mut child_end = self.position.clone();
child_end.add_summary(&child_summary, cx); child_end.add_summary(child_summary, cx);
let comparison = target.cmp(&child_end, cx); let comparison = target.cmp(&child_end, cx);
if comparison == Ordering::Greater if comparison == Ordering::Greater
@ -503,7 +503,7 @@ impl<'a, T: Item> Iterator for Iter<'a, T> {
descend = true; descend = true;
} }
while self.stack.len() > 0 { while !self.stack.is_empty() {
let new_subtree = { let new_subtree = {
let entry = self.stack.last_mut().unwrap(); let entry = self.stack.last_mut().unwrap();
match entry.tree.0.as_ref() { match entry.tree.0.as_ref() {

View File

@ -304,7 +304,7 @@ impl<T: Item> SumTree<T> {
} }
pub fn push_tree(&mut self, other: Self, cx: &<T::Summary as Summary>::Context) { pub fn push_tree(&mut self, other: Self, cx: &<T::Summary as Summary>::Context) {
if !other.0.is_leaf() || other.0.items().len() > 0 { if !other.0.is_leaf() || !other.0.items().is_empty() {
if self.0.height() < other.0.height() { if self.0.height() < other.0.height() {
for tree in other.0.child_trees() { for tree in other.0.child_trees() {
self.push_tree(tree.clone(), cx); self.push_tree(tree.clone(), cx);
@ -610,10 +610,7 @@ pub enum Node<T: Item> {
impl<T: Item> Node<T> { impl<T: Item> Node<T> {
fn is_leaf(&self) -> bool { fn is_leaf(&self) -> bool {
match self { matches!(self, Node::Leaf { .. })
Node::Leaf { .. } => true,
_ => false,
}
} }
fn height(&self) -> u8 { fn height(&self) -> u8 {
@ -786,8 +783,7 @@ mod tests {
while item_ix < expected_filtered_items.len() { while item_ix < expected_filtered_items.len() {
log::info!("filter_cursor, item_ix: {}", item_ix); log::info!("filter_cursor, item_ix: {}", item_ix);
let actual_item = filter_cursor.item().unwrap(); let actual_item = filter_cursor.item().unwrap();
let (reference_index, reference_item) = let (reference_index, reference_item) = expected_filtered_items[item_ix];
expected_filtered_items[item_ix].clone();
assert_eq!(actual_item, &reference_item); assert_eq!(actual_item, &reference_item);
assert_eq!(filter_cursor.start().0, reference_index); assert_eq!(filter_cursor.start().0, reference_index);
log::info!("next"); log::info!("next");

View File

@ -73,7 +73,7 @@ impl<K: Clone + Debug + Default + Ord, V: Clone + Debug> TreeMap<K, V> {
removed removed
} }
pub fn iter<'a>(&'a self) -> impl 'a + Iterator<Item = (&'a K, &'a V)> { pub fn iter(&self) -> impl Iterator<Item = (&K, &V)> + '_ {
self.0.iter().map(|entry| (&entry.key, &entry.value)) self.0.iter().map(|entry| (&entry.key, &entry.value))
} }
} }
@ -162,7 +162,7 @@ where
self.0.get(key).is_some() self.0.get(key).is_some()
} }
pub fn iter<'a>(&'a self) -> impl 'a + Iterator<Item = &'a K> { pub fn iter(&self) -> impl Iterator<Item = &K> + '_ {
self.0.iter().map(|(k, _)| k) self.0.iter().map(|(k, _)| k)
} }
} }

View File

@ -190,7 +190,7 @@ impl RelativeHighlightedRange {
let end_x = let end_x =
origin.x() + self.range.end as f32 * layout.size.cell_width + layout.size.cell_width; origin.x() + self.range.end as f32 * layout.size.cell_width + layout.size.cell_width;
return HighlightedRangeLine { start_x, end_x }; HighlightedRangeLine { start_x, end_x }
} }
} }
@ -273,7 +273,7 @@ impl TerminalEl {
cur_rect = cur_rect.take().map(|rect| rect.extend()); cur_rect = cur_rect.take().map(|rect| rect.extend());
} else { } else {
cur_alac_color = Some(bg); cur_alac_color = Some(bg);
if let Some(_) = cur_rect { if cur_rect.is_some() {
rects.push(cur_rect.take().unwrap()); rects.push(cur_rect.take().unwrap());
} }
cur_rect = Some(LayoutRect::new( cur_rect = Some(LayoutRect::new(
@ -402,7 +402,7 @@ impl TerminalEl {
RunStyle { RunStyle {
color: fg, color: fg,
font_id: font_id, font_id,
underline, underline,
} }
} }
@ -416,9 +416,9 @@ impl TerminalEl {
display_offset: usize, display_offset: usize,
cx: &mut PaintContext, cx: &mut PaintContext,
) { ) {
let mouse_down_connection = self.terminal.clone(); let mouse_down_connection = self.terminal;
let click_connection = self.terminal.clone(); let click_connection = self.terminal;
let drag_connection = self.terminal.clone(); let drag_connection = self.terminal;
cx.scene.push_mouse_region( cx.scene.push_mouse_region(
MouseRegion::new(view_id, None, visible_bounds) MouseRegion::new(view_id, None, visible_bounds)
.on_down( .on_down(
@ -500,7 +500,7 @@ impl TerminalEl {
.terminal_overrides .terminal_overrides
.font_family .font_family
.as_ref() .as_ref()
.or_else(|| settings.terminal_defaults.font_family.as_ref()) .or(settings.terminal_defaults.font_family.as_ref())
.and_then(|family_name| font_cache.load_family(&[family_name]).log_err()) .and_then(|family_name| font_cache.load_family(&[family_name]).log_err())
.unwrap_or(settings.buffer_font_family); .unwrap_or(settings.buffer_font_family);
@ -581,7 +581,7 @@ impl Element for TerminalEl {
//Setup layout information //Setup layout information
let terminal_theme = settings.theme.terminal.clone(); //TODO: Try to minimize this clone. let terminal_theme = settings.theme.terminal.clone(); //TODO: Try to minimize this clone.
let text_style = TerminalEl::make_text_style(font_cache, &settings); let text_style = TerminalEl::make_text_style(font_cache, settings);
let selection_color = settings.theme.editor.selection.selection; let selection_color = settings.theme.editor.selection.selection;
let dimensions = { let dimensions = {
let line_height = font_cache.line_height(text_style.font_size); let line_height = font_cache.line_height(text_style.font_size);
@ -590,9 +590,9 @@ impl Element for TerminalEl {
}; };
let background_color = if self.modal { let background_color = if self.modal {
terminal_theme.colors.modal_background.clone() terminal_theme.colors.modal_background
} else { } else {
terminal_theme.colors.background.clone() terminal_theme.colors.background
}; };
let (cells, selection, cursor, display_offset, cursor_text) = self let (cells, selection, cursor, display_offset, cursor_text) = self
@ -614,17 +614,17 @@ impl Element for TerminalEl {
// && !ic.flags.contains(Flags::INVERSE)) // && !ic.flags.contains(Flags::INVERSE))
// }) // })
.map(|ic| IndexedCell { .map(|ic| IndexedCell {
point: ic.point.clone(), point: ic.point,
cell: ic.cell.clone(), cell: ic.cell.clone(),
}), }),
); );
( (
cells, cells,
content.selection.clone(), content.selection,
content.cursor.clone(), content.cursor,
content.display_offset.clone(), content.display_offset,
cursor_text.clone(), cursor_text,
) )
}) })
}); });
@ -666,7 +666,7 @@ impl Element for TerminalEl {
dimensions.line_height, dimensions.line_height,
terminal_theme.colors.cursor, terminal_theme.colors.cursor,
CursorShape::Block, CursorShape::Block,
Some(cursor_text.clone()), Some(cursor_text),
) )
}, },
) )
@ -721,7 +721,7 @@ impl Element for TerminalEl {
}); });
for rect in &layout.rects { for rect in &layout.rects {
rect.paint(origin, &layout, cx) rect.paint(origin, layout, cx)
} }
}); });
@ -786,11 +786,11 @@ impl Element for TerminalEl {
let vertical_scroll = let vertical_scroll =
(delta.y() / layout.size.line_height) * ALACRITTY_SCROLL_MULTIPLIER; (delta.y() / layout.size.line_height) * ALACRITTY_SCROLL_MULTIPLIER;
self.terminal.upgrade(cx.app).map(|terminal| { if let Some(terminal) = self.terminal.upgrade(cx.app) {
terminal.update(cx.app, |term, _| { terminal.update(cx.app, |term, _| {
term.scroll(Scroll::Delta(vertical_scroll.round() as i32)) term.scroll(Scroll::Delta(vertical_scroll.round() as i32))
}); });
}); }
cx.notify(); cx.notify();
}) })

View File

@ -82,7 +82,7 @@ impl ConnectedView {
has_new_content: true, has_new_content: true,
has_bell: false, has_bell: false,
modal, modal,
context_menu: cx.add_view(|cx| ContextMenu::new(cx)), context_menu: cx.add_view(ContextMenu::new),
} }
} }
@ -127,9 +127,9 @@ impl ConnectedView {
///Attempt to paste the clipboard into the terminal ///Attempt to paste the clipboard into the terminal
fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) { fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
cx.read_from_clipboard().map(|item| { if let Some(item) = cx.read_from_clipboard() {
self.terminal.read(cx).paste(item.text()); self.terminal.read(cx).paste(item.text());
}); }
} }
///Synthesize the keyboard event corresponding to 'up' ///Synthesize the keyboard event corresponding to 'up'

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