Commits: 7

Write about binary data in diffs

index 34979e9..2768f3f 100644
--- a/spec/BASIC.md
+++ b/spec/BASIC.md
@@ -42,3 +42,16 @@ What about new projects that are not listed yet?
=If some work was done on such a project, there should be a warning about it.
=
=If a project is then added to the list, running the command again should not override existing drafts, but create new files for the newly listed projects.
+
+## Binary files issue
+
+A non-unicode fragment in the diff breaks my script. For example in a repo with some PDFs checked in I'm getting this:
+
+``` nushell-session
+❯ git log --since 2026-04-01T00:00:00+00:00 --until 2026-04-12T00:00:00+00:00 --unified --format="<--- commit --->%n%s%n<--- part --->%b%n<--- part --->"     | split row  "<--- commit --->"
+Error: nu::shell::only_supports_this_input_type
+```
+
+The PDF files are mixed - they are mostly text, but can contain embedded binary blobs (like fonts or bitmap images).
+
+The solutions is the `.gitattributes` in a project repo to filter our any file that might contain binary fragments.

Write about an idea to produce sample data

index 2768f3f..415f213 100644
--- a/spec/BASIC.md
+++ b/spec/BASIC.md
@@ -2,6 +2,9 @@
=
=This program generates a devlog for tad-lispy.com
=
+## Sample data
+
+IT should eventually be possible to evaluate this spec using TBB. The difficulty is, that any sample data to work on needs to be a git repository, while this project itself is version controlled using git. One way would be to have TBB make commits with fabricated dates, using `git commit --date`.
=
=## Get all projects
=

Work around skip swallowing errors

I elaborate on in in the spec.

index a87f7bf..a74113b 100755
--- a/devlog.nu
+++ b/devlog.nu
@@ -42,8 +42,11 @@ def "main project log" [
=    # print $git_command
=
=    # TODO: Handle binary stream somehow coming from Erna's log
-    git log --since=($since | format date %+) --until=($until | format date %+) --patch --format=($log_format)
+    # This is a workaround for `skip` swallowing errors
+    let chunks = git log --since=($since | format date %+) --until=($until | format date %+) --patch --format=($log_format)
=    | split row  "<--- commit --->"
+
+    $chunks
=    | skip 1 # First is empty
=    | split column "<--- part --->"
=    | rename "subject" "body" "diff"
index 415f213..42c8077 100644
--- a/spec/BASIC.md
+++ b/spec/BASIC.md
@@ -58,3 +58,18 @@ Error: nu::shell::only_supports_this_input_type
=The PDF files are mixed - they are mostly text, but can contain embedded binary blobs (like fonts or bitmap images).
=
=The solutions is the `.gitattributes` in a project repo to filter our any file that might contain binary fragments.
+
+A secondary problem is that Nushell's `skip` command seems to be swallowing the errors in a pipeline. If the preceding command fails (like above), it just produces empty list. Consider this, same as above but with an extra step:
+
+``` nushell-session
+❯ git log --since 2026-04-01T00:00:00+00:00 --until 2026-04-12T00:00:00+00:00 --unified --format="<--- commit --->%n%s%n<--- part --->%b%n<--- part --->"
+| split row  "<--- commit --->" 
+| skip 1
+╭────────────╮
+│ empty list │
+╰────────────╯
+```
+
+This seems to be specific to `skip`. Other commands fail as expected.
+
+> TODO: Open an issue in Nushell. There is a similar one about `transpose`: <https://github.com/nushell/nushell/issues/14027>.

Make the git log markers stricter

The <--- commit ---> and <--- part ---> markers are now immediately preceded and followed by newline characters, to avoid confusion when those strings are used in code or docs - for example in this project.

index a74113b..b87590b 100755
--- a/devlog.nu
+++ b/devlog.nu
@@ -33,7 +33,7 @@ def "main project log" [
=    since: datetime,
=    until: datetime,
=] {
-    let log_format = "<--- commit --->%n%s%n<--- part --->%b%n<--- part --->"
+    let log_format = "<--- commit --->%n%s%n<--- part --->%n%b%n<--- part --->%n"
=    cd $path
=
=    # Debugging:
@@ -44,13 +44,13 @@ def "main project log" [
=    # TODO: Handle binary stream somehow coming from Erna's log
=    # This is a workaround for `skip` swallowing errors
=    let chunks = git log --since=($since | format date %+) --until=($until | format date %+) --patch --format=($log_format)
-    | split row  "<--- commit --->"
+    | split row "\n<--- commit --->\n"
=
=    $chunks
=    | skip 1 # First is empty
-    | split column "<--- part --->"
+    | split column "\n<--- part --->\n"
=    | rename "subject" "body" "diff" 
-    | update "diff" { | row | $row.diff | split row --regex "diff --git .+" | skip 1 }
+    | update "diff" { | row | $row.diff | split row --regex "\ndiff --git .+" | skip 1 }
=}
=
=def "format commit" [] {

Make it iterate over days and write the documents

So basically put it all together. The main command now scans all git repositories under the --project-dir (defaults to ~/Projects) and writes markdown documents to files named like 2026-04-13-my-project.md to --out-dir (defaults to ./drafts/). So there is one output file for each day and each project. Days without commits are skipped.

When errors occur, extra diagnostic information is printed. It's a bit ugly. Debugging Nushell scripts seems tricky. Maybe I don't know how to do it properly.

index b87590b..5bad215 100755
--- a/devlog.nu
+++ b/devlog.nu
@@ -81,10 +81,37 @@ def "format log" [
=
=def main [
=    since: datetime,
-    --path: path = "~/Projects",
+    --projects-dir: path = "~/Projects",
=    --day-start: string = "04:00"
+    --out-dir: path = "drafts"
=] {
-    # TODO: Handle multiple projects and write the markdown file
-    main project log $path $since (date now)
-    | format log "Test"
+    mkdir $out_dir
+
+    for project in (main projects $projects_dir | transpose name path) {
+        let project_slug = $project.name | str kebab-case
+
+        # TODO: Iterate over days and write to a file
+        for day in (main days $since) {
+            let date = $day.start | format date %Y-%m-%d
+            let out_path = ($out_dir | path join $"($date)-($project_slug).md")
+
+            try {
+                # TODO: Catch and print errors
+                let log = main project log $project.path $day.start $day.end
+                if ($log | is-empty) {
+                    "No commits on that day"
+                    continue
+                }
+                $log
+                | format log $project.name
+                | save --force $out_path
+            } catch { |error|
+                print --stderr $"Project path: ($project.path)"
+                print --stderr $"Date: ($date)"
+                print --stderr $"Output path: ($out_path)"
+                print --stderr $error.rendered
+            }
+        }
+        
+    }
=}

Make the order of commits chronological

The commits done earlier in the day should be listed first, unlike in git log, where they are listed in reverse chronological order.

index 5bad215..cd1aa1a 100755
--- a/devlog.nu
+++ b/devlog.nu
@@ -97,7 +97,7 @@ def main [
=
=            try {
=                # TODO: Catch and print errors
-                let log = main project log $project.path $day.start $day.end
+                let log = main project log $project.path $day.start $day.end | reverse
=                if ($log | is-empty) {
=                    "No commits on that day"
=                    continue

Write a spec and partially implement configuration

The name and ignore part are working, but there is no warning about recent activity. The difficulty is, that with current architecture it's difficult to print the warning only once. A refactoring is needed before this can be implemented.

A sample configuration file is provided.

index 69d93e1..74bb444 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
+/drafts/
+/devlog.toml
=.direnv
=.devenv
new file mode 100644
index 0000000..698c93f
--- /dev/null
+++ b/devlog-sample.toml
@@ -0,0 +1,11 @@
+[[projects]]
+name = "Tad Better Behavior"
+path = "~/Projects/tad-better-behavior"
+    
+[[projects]]
+name = "Better Tech Club website"
+path = "~/Projects/better-tech-club/bettertech.eu"
+
+[[projects]]
+name = "DevLog"
+path = "."
index cd1aa1a..7622b93 100755
--- a/devlog.nu
+++ b/devlog.nu
@@ -19,13 +19,11 @@ def "main days" [
=
=def "main projects" [
=    path: path
-] {
+]: nothing -> list<path> {
=    $path
=    | path join "**/.git"
=    | glob $in
=    | path dirname
-    | each { |p| { name: ($p | path basename), path: $p } }
-    | transpose --as-record -r
=}
=
=def "main project log" [
@@ -84,12 +82,29 @@ def main [
=    --projects-dir: path = "~/Projects",
=    --day-start: string = "04:00"
=    --out-dir: path = "drafts"
+    --config-file: path = "devlog.toml"
=] {
+    let config = open $config_file
+    | update projects { update path { path expand } } # Resolve all project paths
+
+    # TODO: Allow setting in a config file
=    mkdir $out_dir
=
-    for project in (main projects $projects_dir | transpose name path) {
+    for project_path in (main projects $projects_dir) {
+        let project = $config.projects
+        | where path == $project_path
+        | first
+
+        if ($project | is-empty) {
+            continue
+        }
+
=        let project_slug = $project.name | str kebab-case
=
+        if ($project | get --optional ignore | default false ) {
+            continue
+        }
+
=        # TODO: Iterate over days and write to a file
=        for day in (main days $since) {
=            let date = $day.start | format date %Y-%m-%d
@@ -97,16 +112,18 @@ def main [
=
=            try {
=                # TODO: Catch and print errors
-                let log = main project log $project.path $day.start $day.end | reverse
+                let log = main project log $project_path $day.start $day.end | reverse
+
=                if ($log | is-empty) {
=                    "No commits on that day"
=                    continue
=                }
+
=                $log
=                | format log $project.name
=                | save --force $out_path
=            } catch { |error|
-                print --stderr $"Project path: ($project.path)"
+                print --stderr $"Project path: ($project_path)"
=                print --stderr $"Date: ($date)"
=                print --stderr $"Output path: ($out_path)"
=                print --stderr $error.rendered
index 42c8077..531b178 100644
--- a/spec/BASIC.md
+++ b/spec/BASIC.md
@@ -73,3 +73,12 @@ A secondary problem is that Nushell's `skip` command seems to be swallowing the
=This seems to be specific to `skip`. Other commands fail as expected.
=
=> TODO: Open an issue in Nushell. There is a similar one about `transpose`: <https://github.com/nushell/nushell/issues/14027>.
+
+
+## Configuration file
+
+By default `./devlog.toml` shall be used, but it can be changed with `--config-file` flag. The file must list all the projects for which devlog is to be generated. The name of the project comes from there. See the devlog-sample.toml file.
+
+A project can be flagged to be ignored with the `ignore` key.
+
+Any project that is not listed, but had activity within the period for which a devlog is being generated should produce a warning with useful instructions.