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}