create_buffer.rs

  1use anyhow::{anyhow, Result};
  2use assistant_tooling::{LanguageModelTool, ProjectContext, ToolView};
  3use editor::Editor;
  4use gpui::{prelude::*, Model, Task, View, WeakView};
  5use project::Project;
  6use schemars::JsonSchema;
  7use serde::Deserialize;
  8use ui::prelude::*;
  9use util::ResultExt;
 10use workspace::Workspace;
 11
 12pub struct CreateBufferTool {
 13    workspace: WeakView<Workspace>,
 14    project: Model<Project>,
 15}
 16
 17impl CreateBufferTool {
 18    pub fn new(workspace: WeakView<Workspace>, project: Model<Project>) -> Self {
 19        Self { workspace, project }
 20    }
 21}
 22
 23#[derive(Debug, Clone, Deserialize, JsonSchema)]
 24pub struct CreateBufferInput {
 25    /// The contents of the buffer.
 26    text: String,
 27
 28    /// The name of the language to use for the buffer.
 29    ///
 30    /// This should be a human-readable name, like "Rust", "JavaScript", or "Python".
 31    language: String,
 32}
 33
 34impl LanguageModelTool for CreateBufferTool {
 35    type View = CreateBufferView;
 36
 37    fn name(&self) -> String {
 38        "create_file".to_string()
 39    }
 40
 41    fn description(&self) -> String {
 42        "Create a new untitled file in the current codebase. Side effect: opens it in a new pane/tab for the user to edit.".to_string()
 43    }
 44
 45    fn view(&self, cx: &mut WindowContext) -> View<Self::View> {
 46        cx.new_view(|_cx| CreateBufferView {
 47            workspace: self.workspace.clone(),
 48            project: self.project.clone(),
 49            input: None,
 50            error: None,
 51        })
 52    }
 53}
 54
 55pub struct CreateBufferView {
 56    workspace: WeakView<Workspace>,
 57    project: Model<Project>,
 58    input: Option<CreateBufferInput>,
 59    error: Option<anyhow::Error>,
 60}
 61
 62impl Render for CreateBufferView {
 63    fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
 64        ui::Label::new("Opening a buffer")
 65    }
 66}
 67
 68impl ToolView for CreateBufferView {
 69    type Input = CreateBufferInput;
 70
 71    type SerializedState = ();
 72
 73    fn generate(&self, _project: &mut ProjectContext, _cx: &mut ViewContext<Self>) -> String {
 74        let Some(input) = self.input.as_ref() else {
 75            return "No input".to_string();
 76        };
 77
 78        match &self.error {
 79            None => format!("Created a new {} buffer", input.language),
 80            Some(err) => format!("Failed to create buffer: {err:?}"),
 81        }
 82    }
 83
 84    fn set_input(&mut self, input: Self::Input, cx: &mut ViewContext<Self>) {
 85        self.input = Some(input);
 86        cx.notify();
 87    }
 88
 89    fn execute(&mut self, cx: &mut ViewContext<Self>) -> Task<Result<()>> {
 90        cx.spawn({
 91            let workspace = self.workspace.clone();
 92            let project = self.project.clone();
 93            let input = self.input.clone();
 94            |_this, mut cx| async move {
 95                let input = input.ok_or_else(|| anyhow!("no input"))?;
 96
 97                let text = input.text.clone();
 98                let language_name = input.language.clone();
 99                let language = cx
100                    .update(|cx| {
101                        project
102                            .read(cx)
103                            .languages()
104                            .language_for_name(&language_name)
105                    })?
106                    .await?;
107
108                let buffer = cx
109                    .update(|cx| project.update(cx, |project, cx| project.create_buffer(cx)))?
110                    .await?;
111
112                buffer.update(&mut cx, |buffer, cx| {
113                    buffer.edit([(0..0, text)], None, cx);
114                    buffer.set_language(Some(language), cx)
115                })?;
116
117                workspace
118                    .update(&mut cx, |workspace, cx| {
119                        workspace.add_item_to_active_pane(
120                            Box::new(
121                                cx.new_view(|cx| Editor::for_buffer(buffer, Some(project), cx)),
122                            ),
123                            None,
124                            cx,
125                        );
126                    })
127                    .log_err();
128
129                Ok(())
130            }
131        })
132    }
133
134    fn serialize(&self, _cx: &mut ViewContext<Self>) -> Self::SerializedState {
135        ()
136    }
137
138    fn deserialize(
139        &mut self,
140        _output: Self::SerializedState,
141        _cx: &mut ViewContext<Self>,
142    ) -> Result<()> {
143        Ok(())
144    }
145}