settings_file.rs

  1use crate::{update_settings_file, watched_json::WatchedJsonFile, SettingsFileContent};
  2use anyhow::Result;
  3use fs::Fs;
  4use gpui::MutableAppContext;
  5use std::{path::Path, sync::Arc};
  6
  7// TODO: Switch SettingsFile to open a worktree and buffer for synchronization
  8//       And instant updates in the Zed editor
  9#[derive(Clone)]
 10pub struct SettingsFile {
 11    path: &'static Path,
 12    settings_file_content: WatchedJsonFile<SettingsFileContent>,
 13    fs: Arc<dyn Fs>,
 14}
 15
 16impl SettingsFile {
 17    pub fn new(
 18        path: &'static Path,
 19        settings_file_content: WatchedJsonFile<SettingsFileContent>,
 20        fs: Arc<dyn Fs>,
 21    ) -> Self {
 22        SettingsFile {
 23            path,
 24            settings_file_content,
 25            fs,
 26        }
 27    }
 28
 29    pub fn update(
 30        cx: &mut MutableAppContext,
 31        update: impl 'static + Send + FnOnce(&mut SettingsFileContent),
 32    ) {
 33        let this = cx.global::<SettingsFile>();
 34
 35        let current_file_content = this.settings_file_content.current();
 36
 37        let fs = this.fs.clone();
 38        let path = this.path.clone();
 39
 40        cx.background()
 41            .spawn(async move {
 42                let old_text = fs.load(path).await?;
 43
 44                let new_text = update_settings_file(old_text, current_file_content, update);
 45
 46                fs.atomic_write(path.to_path_buf(), new_text).await?;
 47
 48                Ok(()) as Result<()>
 49            })
 50            .detach_and_log_err(cx);
 51    }
 52}
 53
 54#[cfg(test)]
 55mod tests {
 56    use super::*;
 57    use crate::{watched_json::watch_settings_file, EditorSettings, Settings, SoftWrap};
 58    use fs::FakeFs;
 59    use theme::ThemeRegistry;
 60
 61    #[gpui::test]
 62    async fn test_watch_settings_files(cx: &mut gpui::TestAppContext) {
 63        let executor = cx.background();
 64        let fs = FakeFs::new(executor.clone());
 65        let font_cache = cx.font_cache();
 66
 67        fs.save(
 68            "/settings.json".as_ref(),
 69            &r#"
 70            {
 71                "buffer_font_size": 24,
 72                "soft_wrap": "editor_width",
 73                "tab_size": 8,
 74                "language_overrides": {
 75                    "Markdown": {
 76                        "tab_size": 2,
 77                        "preferred_line_length": 100,
 78                        "soft_wrap": "preferred_line_length"
 79                    }
 80                }
 81            }
 82            "#
 83            .into(),
 84            Default::default(),
 85        )
 86        .await
 87        .unwrap();
 88
 89        let source = WatchedJsonFile::new(fs.clone(), &executor, "/settings.json".as_ref()).await;
 90
 91        let default_settings = cx.read(Settings::test).with_language_defaults(
 92            "JavaScript",
 93            EditorSettings {
 94                tab_size: Some(2.try_into().unwrap()),
 95                ..Default::default()
 96            },
 97        );
 98        cx.update(|cx| {
 99            watch_settings_file(
100                default_settings.clone(),
101                source,
102                ThemeRegistry::new((), font_cache),
103                cx,
104            )
105        });
106
107        cx.foreground().run_until_parked();
108        let settings = cx.read(|cx| cx.global::<Settings>().clone());
109        assert_eq!(settings.buffer_font_size, 24.0);
110
111        assert_eq!(settings.soft_wrap(None), SoftWrap::EditorWidth);
112        assert_eq!(
113            settings.soft_wrap(Some("Markdown")),
114            SoftWrap::PreferredLineLength
115        );
116        assert_eq!(
117            settings.soft_wrap(Some("JavaScript")),
118            SoftWrap::EditorWidth
119        );
120
121        assert_eq!(settings.preferred_line_length(None), 80);
122        assert_eq!(settings.preferred_line_length(Some("Markdown")), 100);
123        assert_eq!(settings.preferred_line_length(Some("JavaScript")), 80);
124
125        assert_eq!(settings.tab_size(None).get(), 8);
126        assert_eq!(settings.tab_size(Some("Markdown")).get(), 2);
127        assert_eq!(settings.tab_size(Some("JavaScript")).get(), 8);
128
129        fs.save(
130            "/settings.json".as_ref(),
131            &"(garbage)".into(),
132            Default::default(),
133        )
134        .await
135        .unwrap();
136        // fs.remove_file("/settings.json".as_ref(), Default::default())
137        //     .await
138        //     .unwrap();
139
140        cx.foreground().run_until_parked();
141        let settings = cx.read(|cx| cx.global::<Settings>().clone());
142        assert_eq!(settings.buffer_font_size, 24.0);
143
144        assert_eq!(settings.soft_wrap(None), SoftWrap::EditorWidth);
145        assert_eq!(
146            settings.soft_wrap(Some("Markdown")),
147            SoftWrap::PreferredLineLength
148        );
149        assert_eq!(
150            settings.soft_wrap(Some("JavaScript")),
151            SoftWrap::EditorWidth
152        );
153
154        assert_eq!(settings.preferred_line_length(None), 80);
155        assert_eq!(settings.preferred_line_length(Some("Markdown")), 100);
156        assert_eq!(settings.preferred_line_length(Some("JavaScript")), 80);
157
158        assert_eq!(settings.tab_size(None).get(), 8);
159        assert_eq!(settings.tab_size(Some("Markdown")).get(), 2);
160        assert_eq!(settings.tab_size(Some("JavaScript")).get(), 8);
161
162        fs.remove_file("/settings.json".as_ref(), Default::default())
163            .await
164            .unwrap();
165        cx.foreground().run_until_parked();
166        let settings = cx.read(|cx| cx.global::<Settings>().clone());
167        assert_eq!(settings.buffer_font_size, default_settings.buffer_font_size);
168    }
169}