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