items.rs

  1use super::{Item, ItemView};
  2use crate::Settings;
  3use anyhow::Result;
  4use editor::{Editor, EditorSettings, Event};
  5use gpui::{fonts::TextStyle, AppContext, ModelHandle, Task, ViewContext};
  6use language::{Buffer, File as _};
  7use postage::watch;
  8use project::{ProjectPath, Worktree};
  9use std::path::Path;
 10
 11impl Item for Buffer {
 12    type View = Editor;
 13
 14    fn build_view(
 15        handle: ModelHandle<Self>,
 16        settings: watch::Receiver<Settings>,
 17        cx: &mut ViewContext<Self::View>,
 18    ) -> Self::View {
 19        Editor::for_buffer(
 20            handle,
 21            move |cx| {
 22                let settings = settings.borrow();
 23                let font_cache = cx.font_cache();
 24                let font_family_id = settings.buffer_font_family;
 25                let font_family_name = cx.font_cache().family_name(font_family_id).unwrap();
 26                let font_properties = Default::default();
 27                let font_id = font_cache
 28                    .select_font(font_family_id, &font_properties)
 29                    .unwrap();
 30                let font_size = settings.buffer_font_size;
 31
 32                let mut theme = settings.theme.editor.clone();
 33                theme.text = TextStyle {
 34                    color: theme.text.color,
 35                    font_family_name,
 36                    font_family_id,
 37                    font_id,
 38                    font_size,
 39                    font_properties,
 40                    underline: false,
 41                };
 42                EditorSettings {
 43                    tab_size: settings.tab_size,
 44                    style: theme,
 45                }
 46            },
 47            cx,
 48        )
 49    }
 50
 51    fn project_path(&self) -> Option<ProjectPath> {
 52        self.file().map(|f| ProjectPath {
 53            worktree_id: f.worktree_id(),
 54            path: f.path().clone(),
 55        })
 56    }
 57}
 58
 59impl ItemView for Editor {
 60    fn should_activate_item_on_event(event: &Event) -> bool {
 61        matches!(event, Event::Activate)
 62    }
 63
 64    fn should_close_item_on_event(event: &Event) -> bool {
 65        matches!(event, Event::Closed)
 66    }
 67
 68    fn should_update_tab_on_event(event: &Event) -> bool {
 69        matches!(
 70            event,
 71            Event::Saved | Event::Dirtied | Event::FileHandleChanged
 72        )
 73    }
 74
 75    fn title(&self, cx: &AppContext) -> String {
 76        let filename = self
 77            .buffer()
 78            .read(cx)
 79            .file()
 80            .and_then(|file| file.file_name(cx));
 81        if let Some(name) = filename {
 82            name.to_string_lossy().into()
 83        } else {
 84            "untitled".into()
 85        }
 86    }
 87
 88    fn project_path(&self, cx: &AppContext) -> Option<ProjectPath> {
 89        self.buffer().read(cx).file().map(|file| ProjectPath {
 90            worktree_id: file.worktree_id(),
 91            path: file.path().clone(),
 92        })
 93    }
 94
 95    fn clone_on_split(&self, cx: &mut ViewContext<Self>) -> Option<Self>
 96    where
 97        Self: Sized,
 98    {
 99        Some(self.clone(cx))
100    }
101
102    fn save(&mut self, cx: &mut ViewContext<Self>) -> Result<Task<Result<()>>> {
103        let save = self.buffer().update(cx, |b, cx| b.save(cx))?;
104        Ok(cx.spawn(|_, _| async move {
105            save.await?;
106            Ok(())
107        }))
108    }
109
110    fn save_as(
111        &mut self,
112        worktree: ModelHandle<Worktree>,
113        path: &Path,
114        cx: &mut ViewContext<Self>,
115    ) -> Task<Result<()>> {
116        self.buffer().update(cx, |buffer, cx| {
117            let handle = cx.handle();
118            let text = buffer.as_rope().clone();
119            let version = buffer.version();
120
121            let save_as = worktree.update(cx, |worktree, cx| {
122                worktree
123                    .as_local_mut()
124                    .unwrap()
125                    .save_buffer_as(handle, path, text, cx)
126            });
127
128            cx.spawn(|buffer, mut cx| async move {
129                save_as.await.map(|new_file| {
130                    let language = worktree.read_with(&cx, |worktree, cx| {
131                        worktree
132                            .languages()
133                            .select_language(new_file.full_path(cx))
134                            .cloned()
135                    });
136
137                    buffer.update(&mut cx, |buffer, cx| {
138                        buffer.did_save(version, new_file.mtime, Some(Box::new(new_file)), cx);
139                        buffer.set_language(language, cx);
140                    });
141                })
142            })
143        })
144    }
145
146    fn is_dirty(&self, cx: &AppContext) -> bool {
147        self.buffer().read(cx).is_dirty()
148    }
149
150    fn has_conflict(&self, cx: &AppContext) -> bool {
151        self.buffer().read(cx).has_conflict()
152    }
153}