main.rs

  1// Allow binary to be called Zed for a nice application menu when running executable direcly
  2#![allow(non_snake_case)]
  3
  4use fs::OpenOptions;
  5use gpui::AssetSource;
  6use log::LevelFilter;
  7use parking_lot::Mutex;
  8use simplelog::SimpleLogger;
  9use std::{fs, path::PathBuf, sync::Arc};
 10use zed::{
 11    self,
 12    assets::Assets,
 13    channel::ChannelList,
 14    chat_panel, editor, file_finder,
 15    fs::RealFs,
 16    language, menus, rpc, settings, theme_selector,
 17    user::UserStore,
 18    workspace::{self, OpenNew, OpenParams, OpenPaths},
 19    AppState,
 20};
 21
 22fn main() {
 23    init_logger();
 24
 25    let app = gpui::App::new(Assets).unwrap();
 26    let embedded_fonts = Assets
 27        .list("fonts")
 28        .into_iter()
 29        .map(|f| Arc::new(Assets.load(&f).unwrap().to_vec()))
 30        .collect::<Vec<_>>();
 31    app.platform().fonts().add_fonts(&embedded_fonts).unwrap();
 32
 33    let themes = settings::ThemeRegistry::new(Assets, app.font_cache());
 34    let (settings_tx, settings) = settings::channel(&app.font_cache(), &themes).unwrap();
 35    let languages = Arc::new(language::LanguageRegistry::new());
 36    languages.set_theme(&settings.borrow().theme.syntax);
 37
 38    app.run(move |cx| {
 39        let rpc = rpc::Client::new();
 40        let user_store = UserStore::new(rpc.clone(), cx.background());
 41        let app_state = Arc::new(AppState {
 42            languages: languages.clone(),
 43            settings_tx: Arc::new(Mutex::new(settings_tx)),
 44            settings,
 45            themes,
 46            channel_list: cx.add_model(|cx| ChannelList::new(user_store.clone(), rpc.clone(), cx)),
 47            rpc,
 48            user_store,
 49            fs: Arc::new(RealFs),
 50        });
 51
 52        zed::init(&app_state, cx);
 53        workspace::init(cx);
 54        editor::init(cx);
 55        file_finder::init(cx);
 56        chat_panel::init(cx);
 57        theme_selector::init(&app_state, cx);
 58
 59        cx.set_menus(menus::menus(&app_state.clone()));
 60
 61        if stdout_is_a_pty() {
 62            cx.platform().activate(true);
 63        }
 64
 65        let paths = collect_path_args();
 66        if paths.is_empty() {
 67            cx.dispatch_global_action(OpenNew(app_state));
 68        } else {
 69            cx.dispatch_global_action(OpenPaths(OpenParams { paths, app_state }));
 70        }
 71    });
 72}
 73
 74fn init_logger() {
 75    let level = LevelFilter::Info;
 76
 77    if stdout_is_a_pty() {
 78        SimpleLogger::init(level, Default::default()).expect("could not initialize logger");
 79    } else {
 80        let log_dir_path = dirs::home_dir()
 81            .expect("could not locate home directory for logging")
 82            .join("Library/Logs/");
 83        let log_file_path = log_dir_path.join("Zed.log");
 84        fs::create_dir_all(&log_dir_path).expect("could not create log directory");
 85        let log_file = OpenOptions::new()
 86            .create(true)
 87            .append(true)
 88            .open(log_file_path)
 89            .expect("could not open logfile");
 90        simplelog::WriteLogger::init(level, simplelog::Config::default(), log_file)
 91            .expect("could not initialize logger");
 92    }
 93}
 94
 95fn stdout_is_a_pty() -> bool {
 96    unsafe { libc::isatty(libc::STDOUT_FILENO as i32) != 0 }
 97}
 98
 99fn collect_path_args() -> Vec<PathBuf> {
100    std::env::args()
101        .skip(1)
102        .filter_map(|arg| match fs::canonicalize(arg) {
103            Ok(path) => Some(path),
104            Err(error) => {
105                log::error!("error parsing path argument: {}", error);
106                None
107            }
108        })
109        .collect::<Vec<_>>()
110}