Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ pub enum Commands {
Import{
#[arg(value_name = "markdown-file")]
file: Option<String>,

#[arg(short, long)]
from_logseq: bool,
},

/// -> launch file manager on basedir
Expand Down
10 changes: 7 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@ fn main() {
if let Some(boxname) = args.inbox {
&boxname.clone()
} else {
let cmdname = arg0.split(path::MAIN_SEPARATOR).last().unwrap();
let cmdname = arg0.split(path::MAIN_SEPARATOR).next_back().unwrap();

if cmdname == "todor" {
"inbox"
} else {
// e.g. "today", "tomorrow", "yesterday", "t.read", "todo.working"
cmdname.split('.').last().unwrap()
cmdname.split('.').next_back().unwrap()
}
};

Expand Down Expand Up @@ -56,7 +57,10 @@ fn main() {
if cc > 0 { println!("{}", cc) }
}

Some(Commands::Import{ file }) => TaskBox::new(inbox_path).import(file),
Some(Commands::Import{ file, from_logseq }) => {
TaskBox::new(inbox_path).import(file, from_logseq);
}

Some(Commands::Purge { sort }) => {
if i_confirm("are you sure?") {
if sort && ! i_confirm("sort cannot handle subtasks well, continue?") { return }
Expand Down
102 changes: 76 additions & 26 deletions src/taskbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ const PREFIX_OPEN :&str = "- [ ] ";
const PREFIX_DONE :&str = "- [x] ";
const PREFIX_SUBT :&str = " 󱞩 ";

const PREFIX_OPEN_LOGSEQ :&str = "- TODO ";
const PREFIX_OPEN2_LOGSEQ :&str = "- LATER ";
// const PREFIX_DONE_LOGSEQ :&str = "- DONE ";

#[derive(Debug)]
pub struct TaskBox {
pub fpath: PathBuf,
Expand Down Expand Up @@ -205,8 +209,8 @@ impl TaskBox {
return false
} else if *done {
// found done sub-task for this major task
if task_status.is_some() {
*task_status.unwrap() = true;
if let Some(task_status) = task_status {
*task_status = true;
}
return true
}
Expand Down Expand Up @@ -519,40 +523,86 @@ impl TaskBox {
}

// specified markdown file -> cur
pub fn import(&mut self, file: Option<String>) {
pub fn import(&mut self, file: Option<String>, from_logseq: bool) {
#[allow(clippy::redundant_closure)]
let mdfile= file.unwrap_or_else(|| super::util::pick_file());

let fpath = Path::new(&mdfile);
if ! fpath.is_file() {
eprintln!("not a file or not exists: {}", S_fpath!(mdfile));
std::process::exit(1)
}
println!("importing {} {}", S_fpath!(mdfile), PROGRESS);

let mut newt = Vec::new();
let mut newr = Vec::new();
for rline in fs::read_to_string(fpath).expect("cannot read file").lines() {
let line = rline.trim();
if line.is_empty() { continue }

if let Some(stripped) = line.strip_prefix(PREFIX_OPEN) {
if RE_ROUTINES.is_match(stripped) {
println!(" {} : {}", S_checkbox!(ROUTINES), stripped);
newr.push(stripped.to_string())
} else {
println!(" {} : {}", S_checkbox!(CHECKBOX), stripped);
newt.push(stripped.to_string())
let mut newt = Vec::new(); // new tasks
let mut newr = Vec::new(); // new routines
let mut newl = Vec::new(); // new later tasks from logseq to Inbox

let mdfiles :Vec<String> = if from_logseq {
// get icloud path of "Logseq"
let icloud = dirs::home_dir().unwrap().join("Library/Mobile Documents/iCloud~com~logseq~logseq/Documents/journals");

// when logseq is true, the input "mdfile" is the date string of the journal file
// and can accept today, yesterday, week, etc.
// if date is not provided, use today
let mdfile_names = match file {
Some(d) if d == "today" => get_today(),
Some(d) if d == "yesterday" => get_yesterday(),
Some(d) if d.ends_with(".md") => d,
Some(d) => format!("{}.md", d),

None => super::util::pick_file(icloud.to_str().unwrap()),
};

mdfile_names.split("\n").map(|s| icloud.join(s).to_str().unwrap().to_string()).collect()
} else {
file.unwrap_or_else(|| super::util::pick_file(".")).split("\n").map(|s| s.to_string()).collect()
};

for mdfile in mdfiles {
let fpath = Path::new(&mdfile);
if ! fpath.is_file() {
eprintln!("not a file or not exists: {}", S_fpath!(mdfile));
std::process::exit(1)
}
println!("importing {} {}", S_fpath!(mdfile), PROGRESS);

for rline in fs::read_to_string(fpath).expect("cannot read file").lines() {
let line = rline.trim();
if line.is_empty() { continue }

if let Some(stripped) = line.strip_prefix(PREFIX_OPEN) {
if RE_ROUTINES.is_match(stripped) {
newr.push(stripped.to_string())
} else {
newt.push(stripped.to_string())
}
}

if from_logseq {
if let Some(stripped) = line.strip_prefix(PREFIX_OPEN_LOGSEQ) {
newt.push(stripped.to_string())
} else if let Some(stripped) = line.strip_prefix(PREFIX_OPEN2_LOGSEQ) {
newl.push(stripped.to_string())
}
}
}
}

if newt.is_empty() && newr.is_empty() {
if newt.is_empty() && newr.is_empty() && newl.is_empty() {
println!("{} found!", S_empty!("nothing"));
return
} else {
println!("New tasks found in input file:");
for task in &newt {
println!(" {} : {}", S_checkbox!(CHECKBOX), task);
}
for task in &newl {
println!(" {} : {} [{}]", S_checkbox!(CHECKBOX), task, S_checkbox!("LATER"));
}
for task in &newr {
println!(" {} : {}", S_checkbox!(ROUTINES), task);
}
}

self.add_tasks(newt);
self.load(); self.add_tasks(newt);
if self.tbname == INBOX_BOXNAME {
self.add_tasks(newl);
} else {
self.sibling(INBOX_BOXNAME).add_tasks(newl);
}
self.sibling(ROUTINE_BOXNAME).add_tasks(newr);
}

Expand Down
4 changes: 2 additions & 2 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ pub fn path_normalize(path_str: &str) -> String {
Path::new(path_str).normalize().unwrap()
}

pub fn pick_file() -> String {
pub fn pick_file(dir: &str) -> String {
run_fun!(
ls | fzf;
ls -r $dir | fzf -m --preview "cat '$dir/{}'";
).unwrap_or_else(|_|
std::process::exit(1)
)
Expand Down
11 changes: 10 additions & 1 deletion tests/taskbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,11 @@ fn test_import_somefile_to_inbox() {
- [ ] Task2 to import
- [ ] {󰃯:d 2024-10-01Tue 󰳟} one daily to import
- [ ] {󰃯:m 2024-10-31Mon 󰳟} one montly to import

## belows are logseq style
- TODO Task to import to "Today"
- LATER Task to import also to "Inbox"
- DONE Task Done not to import
"#;

let (mut inbox, dir) = setup_test_taskbox(INBOX_BOXNAME);
Expand All @@ -390,9 +395,13 @@ fn test_import_somefile_to_inbox() {
assert_eq!(inbox.tasks.len(), 1);
assert_eq!(routine.tasks.len(), 1);

inbox.import(Some(fpath.to_str().unwrap().to_string()));
inbox.import(Some(fpath.to_str().unwrap().to_string()), false);
routine = inbox.sibling("routine"); //reset for force reload
routine.load();
assert_eq!(inbox.tasks.len(), 4);
assert_eq!(routine.tasks.len(), 3);

// import again with "from_logseq" true
inbox.import(Some(fpath.to_str().unwrap().to_string()), true);
assert_eq!(inbox.tasks.len(), 6);
}
Loading