Use async_trait for LspCommand

Max Brunsfeld created

Change summary

crates/project/src/lsp_command.rs | 152 +++++++++++++++-----------------
1 file changed, 71 insertions(+), 81 deletions(-)

Detailed changes

crates/project/src/lsp_command.rs 🔗

@@ -1,7 +1,7 @@
 use crate::{Project, ProjectTransaction};
 use anyhow::{anyhow, Result};
+use async_trait::async_trait;
 use client::{proto, PeerId};
-use futures::{future::LocalBoxFuture, FutureExt};
 use gpui::{AppContext, AsyncAppContext, ModelContext, ModelHandle};
 use language::{
     proto::deserialize_anchor, range_from_lsp, Anchor, Bias, Buffer, PointUtf16, ToLspPosition,
@@ -9,6 +9,7 @@ use language::{
 };
 use std::{ops::Range, path::Path};
 
+#[async_trait(?Send)]
 pub(crate) trait LspCommand: 'static + Sized {
     type Response: 'static + Default + Send;
     type LspRequest: 'static + Send + lsp::request::Request;
@@ -19,13 +20,13 @@ pub(crate) trait LspCommand: 'static + Sized {
         path: &Path,
         cx: &AppContext,
     ) -> <Self::LspRequest as lsp::request::Request>::Params;
-    fn response_from_lsp(
+    async fn response_from_lsp(
         self,
         message: <Self::LspRequest as lsp::request::Request>::Result,
         project: ModelHandle<Project>,
         buffer: ModelHandle<Buffer>,
         cx: AsyncAppContext,
-    ) -> LocalBoxFuture<'static, Result<Self::Response>>;
+    ) -> Result<Self::Response>;
 
     fn to_proto(
         &self,
@@ -48,26 +49,26 @@ pub(crate) trait LspCommand: 'static + Sized {
         buffer_version: &clock::Global,
         cx: &mut ModelContext<Project>,
     ) -> <Self::ProtoRequest as proto::RequestMessage>::Response;
-    fn response_from_proto(
+    async fn response_from_proto(
         self,
         message: <Self::ProtoRequest as proto::RequestMessage>::Response,
         project: ModelHandle<Project>,
         buffer: ModelHandle<Buffer>,
         cx: AsyncAppContext,
-    ) -> LocalBoxFuture<'static, Result<Self::Response>>;
+    ) -> Result<Self::Response>;
 }
 
 pub(crate) struct PrepareRename {
     pub position: PointUtf16,
 }
 
-#[derive(Debug)]
 pub(crate) struct PerformRename {
     pub position: PointUtf16,
     pub new_name: String,
     pub push_to_history: bool,
 }
 
+#[async_trait(?Send)]
 impl LspCommand for PrepareRename {
     type Response = Option<Range<Anchor>>;
     type LspRequest = lsp::request::PrepareRenameRequest;
@@ -82,31 +83,28 @@ impl LspCommand for PrepareRename {
         }
     }
 
-    fn response_from_lsp(
+    async fn response_from_lsp(
         self,
         message: Option<lsp::PrepareRenameResponse>,
         _: ModelHandle<Project>,
         buffer: ModelHandle<Buffer>,
         cx: AsyncAppContext,
-    ) -> LocalBoxFuture<'static, Result<Option<Range<Anchor>>>> {
-        async move {
-            Ok(message.and_then(|result| match result {
+    ) -> Result<Option<Range<Anchor>>> {
+        buffer.read_with(&cx, |buffer, _| {
+            if let Some(
                 lsp::PrepareRenameResponse::Range(range)
-                | lsp::PrepareRenameResponse::RangeWithPlaceholder { range, .. } => buffer
-                    .read_with(&cx, |buffer, _| {
-                        let range = range_from_lsp(range);
-                        if buffer.clip_point_utf16(range.start, Bias::Left) == range.start
-                            && buffer.clip_point_utf16(range.end, Bias::Left) == range.end
-                        {
-                            Some(buffer.anchor_after(range.start)..buffer.anchor_before(range.end))
-                        } else {
-                            None
-                        }
-                    }),
-                _ => None,
-            }))
-        }
-        .boxed_local()
+                | lsp::PrepareRenameResponse::RangeWithPlaceholder { range, .. },
+            ) = message
+            {
+                let Range { start, end } = range_from_lsp(range);
+                if buffer.clip_point_utf16(start, Bias::Left) == start
+                    && buffer.clip_point_utf16(end, Bias::Left) == end
+                {
+                    return Ok(Some(buffer.anchor_after(start)..buffer.anchor_before(end)));
+                }
+            }
+            Ok(None)
+        })
     }
 
     fn to_proto(
@@ -166,31 +164,29 @@ impl LspCommand for PrepareRename {
         }
     }
 
-    fn response_from_proto(
+    async fn response_from_proto(
         self,
         message: proto::PrepareRenameResponse,
         _: ModelHandle<Project>,
         buffer: ModelHandle<Buffer>,
         mut cx: AsyncAppContext,
-    ) -> LocalBoxFuture<'static, Result<Option<Range<Anchor>>>> {
-        async move {
-            if message.can_rename {
-                buffer
-                    .update(&mut cx, |buffer, _| {
-                        buffer.wait_for_version(message.version.into())
-                    })
-                    .await;
-                let start = message.start.and_then(deserialize_anchor);
-                let end = message.end.and_then(deserialize_anchor);
-                Ok(start.zip(end).map(|(start, end)| start..end))
-            } else {
-                Ok(None)
-            }
+    ) -> Result<Option<Range<Anchor>>> {
+        if message.can_rename {
+            buffer
+                .update(&mut cx, |buffer, _| {
+                    buffer.wait_for_version(message.version.into())
+                })
+                .await;
+            let start = message.start.and_then(deserialize_anchor);
+            let end = message.end.and_then(deserialize_anchor);
+            Ok(start.zip(end).map(|(start, end)| start..end))
+        } else {
+            Ok(None)
         }
-        .boxed_local()
     }
 }
 
+#[async_trait(?Send)]
 impl LspCommand for PerformRename {
     type Response = ProjectTransaction;
     type LspRequest = lsp::request::Rename;
@@ -209,39 +205,36 @@ impl LspCommand for PerformRename {
         }
     }
 
-    fn response_from_lsp(
+    async fn response_from_lsp(
         self,
         message: Option<lsp::WorkspaceEdit>,
         project: ModelHandle<Project>,
         buffer: ModelHandle<Buffer>,
         mut cx: AsyncAppContext,
-    ) -> LocalBoxFuture<'static, Result<ProjectTransaction>> {
-        async move {
-            if let Some(edit) = message {
-                let (language_name, language_server) = buffer.read_with(&cx, |buffer, _| {
-                    let language = buffer
-                        .language()
-                        .ok_or_else(|| anyhow!("buffer's language was removed"))?;
-                    let language_server = buffer
-                        .language_server()
-                        .cloned()
-                        .ok_or_else(|| anyhow!("buffer's language server was removed"))?;
-                    Ok::<_, anyhow::Error>((language.name().to_string(), language_server))
-                })?;
-                Project::deserialize_workspace_edit(
-                    project,
-                    edit,
-                    self.push_to_history,
-                    language_name,
-                    language_server,
-                    &mut cx,
-                )
-                .await
-            } else {
-                Ok(ProjectTransaction::default())
-            }
+    ) -> Result<ProjectTransaction> {
+        if let Some(edit) = message {
+            let (language_name, language_server) = buffer.read_with(&cx, |buffer, _| {
+                let language = buffer
+                    .language()
+                    .ok_or_else(|| anyhow!("buffer's language was removed"))?;
+                let language_server = buffer
+                    .language_server()
+                    .cloned()
+                    .ok_or_else(|| anyhow!("buffer's language server was removed"))?;
+                Ok::<_, anyhow::Error>((language.name().to_string(), language_server))
+            })?;
+            Project::deserialize_workspace_edit(
+                project,
+                edit,
+                self.push_to_history,
+                language_name,
+                language_server,
+                &mut cx,
+            )
+            .await
+        } else {
+            Ok(ProjectTransaction::default())
         }
-        .boxed_local()
     }
 
     fn to_proto(
@@ -300,23 +293,20 @@ impl LspCommand for PerformRename {
         }
     }
 
-    fn response_from_proto(
+    async fn response_from_proto(
         self,
         message: proto::PerformRenameResponse,
         project: ModelHandle<Project>,
         _: ModelHandle<Buffer>,
         mut cx: AsyncAppContext,
-    ) -> LocalBoxFuture<'static, Result<ProjectTransaction>> {
-        async move {
-            let message = message
-                .transaction
-                .ok_or_else(|| anyhow!("missing transaction"))?;
-            project
-                .update(&mut cx, |project, cx| {
-                    project.deserialize_project_transaction(message, self.push_to_history, cx)
-                })
-                .await
-        }
-        .boxed_local()
+    ) -> Result<ProjectTransaction> {
+        let message = message
+            .transaction
+            .ok_or_else(|| anyhow!("missing transaction"))?;
+        project
+            .update(&mut cx, |project, cx| {
+                project.deserialize_project_transaction(message, self.push_to_history, cx)
+            })
+            .await
     }
 }