1use chrono::{Datelike, Local, Timelike};
2use editor::{Autoscroll, Editor};
3use gpui::{actions, MutableAppContext};
4use std::{fs::OpenOptions, sync::Arc};
5use util::TryFutureExt as _;
6use workspace::AppState;
7
8actions!(journal, [NewJournalEntry]);
9
10pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
11 cx.add_global_action(move |_: &NewJournalEntry, cx| new_journal_entry(app_state.clone(), cx));
12}
13
14pub fn new_journal_entry(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
15 let now = Local::now();
16 let home_dir = match dirs::home_dir() {
17 Some(home_dir) => home_dir,
18 None => {
19 log::error!("can't determine home directory");
20 return;
21 }
22 };
23
24 let journal_dir = home_dir.join("journal");
25 let month_dir = journal_dir
26 .join(format!("{:02}", now.year()))
27 .join(format!("{:02}", now.month()));
28 let entry_path = month_dir.join(format!("{:02}.md", now.day()));
29 let now = now.time();
30 let (pm, hour) = now.hour12();
31 let am_or_pm = if pm { "PM" } else { "AM" };
32 let entry_heading = format!("# {}:{:02} {}\n\n", hour, now.minute(), am_or_pm);
33
34 let create_entry = cx.background().spawn(async move {
35 std::fs::create_dir_all(month_dir)?;
36 OpenOptions::new()
37 .create(true)
38 .write(true)
39 .open(&entry_path)?;
40 Ok::<_, std::io::Error>((journal_dir, entry_path))
41 });
42
43 cx.spawn(|mut cx| {
44 async move {
45 let (journal_dir, entry_path) = create_entry.await?;
46 let (workspace, _) = cx
47 .update(|cx| workspace::open_paths(&[journal_dir], &app_state, cx))
48 .await;
49
50 let opened = workspace
51 .update(&mut cx, |workspace, cx| {
52 workspace.open_paths(vec![entry_path], true, cx)
53 })
54 .await;
55
56 if let Some(Some(Ok(item))) = opened.first() {
57 if let Some(editor) = item.downcast::<Editor>() {
58 editor.update(&mut cx, |editor, cx| {
59 let len = editor.buffer().read(cx).len(cx);
60 editor.change_selections(Some(Autoscroll::Center), cx, |s| {
61 s.select_ranges([len..len])
62 });
63 if len > 0 {
64 editor.insert("\n\n", cx);
65 }
66 editor.insert(&entry_heading, cx);
67 });
68 }
69 }
70
71 Ok(())
72 }
73 .log_err()
74 })
75 .detach();
76}