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