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: None,
 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());
 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, language_server) = worktree.read_with(&cx, |worktree, _| {
131                        let language = worktree.languages().select_language(new_file.full_path());
132                        let language_server = worktree.language_server();
133                        (language.cloned(), language_server.cloned())
134                    });
135
136                    buffer.update(&mut cx, |buffer, cx| {
137                        buffer.did_save(version, new_file.mtime, Some(Box::new(new_file)), cx);
138                        buffer.set_language(language, language_server, cx);
139                    });
140                })
141            })
142        })
143    }
144
145    fn is_dirty(&self, cx: &AppContext) -> bool {
146        self.buffer().read(cx).is_dirty()
147    }
148
149    fn has_conflict(&self, cx: &AppContext) -> bool {
150        self.buffer().read(cx).has_conflict()
151    }
152}