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
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: hacer
Title: Plain-Text Nested ToDo Planning
Version: 0.2.1
Version: 0.2.2
Authors@R: c(
person("Troy", "Hernandez", role = c("aut", "cre"),
email = "troy@cornball.ai",
Expand Down
19 changes: 17 additions & 2 deletions R/io.R
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,26 @@ write_todo_txt <- function(df, file, period, cfg = todo_config()) {
.df_to_lines <- function(df, indent) {
if (!nrow(df)) return(character())
df <- df[order(df$order), , drop=FALSE]
out <- character(nrow(df))

has_descendants <- function(i) {
if (i == nrow(df)) return(FALSE)
df$level[i + 1L] > df$level[i]
}

out <- character()
for (i in seq_len(nrow(df))) {
# Insert a blank line before this row when:
# - it's not the first row, AND it's at depth 0, AND
# either it heads a subtree, or the previous row was a deeper descendant.
# That keeps flat top-level items clustered and visually separates them
# from project containers and their subtrees.
if (i > 1L && df$level[i] == 0L &&
(has_descendants(i) || df$level[i - 1L] > 0L)) {
out <- c(out, "")
}
pad <- paste(rep(" ", df$level[i] * indent), collapse = "")
stat <- paste0("[", df$status[i], "]")
out[i] <- paste0(pad, "- ", stat, " ", df$name[i])
out <- c(out, paste0(pad, "- ", stat, " ", df$name[i]))
}
out
}
Expand Down
32 changes: 32 additions & 0 deletions inst/tinytest/test_recurring.R
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,38 @@ expect_true(grepl("One-off in progress", combined),

unlink(repo, recursive = TRUE)

# ---- Writer inserts blank lines between top-level groups ----
# Flat top-level items cluster together; project containers (with children)
# get blank-line breathing room before them and after their subtrees.
df_blank <- data.frame(
id = c("A", "B", "C", "D", "D > D1", "E", "F"),
parent_id = c(NA, NA, NA, NA, "D", NA, NA),
period = "Daily", section = "Monday",
name = c("A", "B", "C", "D", "D1", "E", "F"),
recur = FALSE, status = " ",
level = c(0L, 0L, 0L, 0L, 1L, 0L, 0L),
order = 1:7,
path = c("A", "B", "C", "D", "D > D1", "E", "F"),
stringsAsFactors = FALSE
)
out_blank <- hacer:::.df_to_lines(df_blank, indent = 2L)
# Expect: A, B, C are flat top-level (no blanks). D heads a subtree → blank
# before. D1 is a child. E follows a deeper descendant (D1) → blank before.
# F is flat after E (E has no descendants, F has no descendants) → no blank.
expect_true("" %in% out_blank,
info = "Writer inserts blank lines between groups")
# Find the indices of A and D in the output
a_idx <- which(out_blank == "- [ ] A")
d_idx <- which(out_blank == "- [ ] D")
expect_true(out_blank[d_idx - 1L] == "",
info = "Blank line precedes D (which has a child)")
e_idx <- which(out_blank == "- [ ] E")
expect_true(out_blank[e_idx - 1L] == "",
info = "Blank line precedes E (follows a deeper descendant)")
b_idx <- which(out_blank == "- [ ] B")
expect_false(out_blank[b_idx - 1L] == "",
info = "No blank between flat top-level A and B")

# ---- Materialization is depth-first preorder (children stay with parents) ----
rec_dfs <- read_recurring(tmp_dfs <- {
f <- tempfile()
Expand Down
67 changes: 0 additions & 67 deletions tests/test_fix_parents_base.R

This file was deleted.