44 description: The journal module allows you to take personal notes with zero friction.
55 summary: Easily track a journal within Neorg.
66 ---
7- The journal module exposes a total of six commands.
7+ The journal module exposes a total of seven commands.
88The first three, `:Neorg journal today|yesterday|tomorrow`, allow you to access entries
99for a given time relative to today. A file will be opened with the respective date as a `.norg` file.
1010
11- The fourth command, `:Neorg journal custom`, allows you to specify a custom date as an argument.
11+ The fourth command, `"Neorg journal previous` opens the last created journal entry.
12+
13+ The fifth command, `:Neorg journal custom`, allows you to specify a custom date as an argument.
1214The date must be formatted according to the `YYYY-mm-dd` format, e.g. `2023-01-01`.
1315
1416The `:Neorg journal template` command creates a template file which will be used as the base whenever
@@ -115,6 +117,7 @@ module.load = function()
115117 tomorrow = { args = 0 , name = " journal.tomorrow" },
116118 yesterday = { args = 0 , name = " journal.yesterday" },
117119 today = { args = 0 , name = " journal.today" },
120+ previous = { args = 0 , name = " journal.previous" },
118121 custom = { max_args = 1 , name = " journal.custom" }, -- format :yyyy-mm-dd
119122 template = { args = 0 , name = " journal.template" },
120123 toc = {
@@ -458,6 +461,98 @@ module.public = {
458461 end )
459462 end )
460463 end ,
464+
465+ --- Opens the most recent journal entry
466+ open_previous = function ()
467+ local rel_path = module .public .find_most_recent_by_filename ()
468+ if not rel_path then
469+ log .info (" No journal entries found." )
470+ return
471+ end
472+
473+ -- we can treat it like a custom date
474+ module .public .open_diary (nil , rel_path )
475+ end ,
476+
477+ --- Finds the most recent journal entry
478+ find_most_recent_by_filename = function ()
479+ local workspace = module .config .public .workspace or module .required [" core.dirman" ].get_current_workspace ()[1 ]
480+ local workspace_path = module .required [" core.dirman" ].get_workspace (workspace )
481+ local folder_name = module .config .public .journal_folder
482+
483+ local best_date = nil
484+ local best_time = 0
485+
486+ local function try_update (year , month , day )
487+ -- Convert to numeric
488+ year = tonumber (year )
489+ month = tonumber (month )
490+ day = tonumber (day )
491+ if not (year and month and day ) then
492+ return
493+ end
494+
495+ local t = os.time ({ year = year , month = month , day = day })
496+ if t > best_time then
497+ best_time = t
498+ best_date = string.format (" %04d-%02d-%02d" , year , month , day )
499+ end
500+ end
501+
502+ local base = workspace_path .. config .pathsep .. folder_name .. config .pathsep
503+ local handle = vim .loop .fs_scandir (base )
504+ if type (handle ) ~= " userdata" then
505+ -- No journal folder (or can't scan) — return nil
506+ return nil
507+ end
508+
509+ while true do
510+ local name , ftype = vim .loop .fs_scandir_next (handle )
511+ if not name then
512+ break
513+ end
514+
515+ -- Nested strategy (year directories)
516+ if ftype == " directory" then
517+ local years_handle = vim .loop .fs_scandir (base .. name )
518+ if type (years_handle ) == " userdata" then
519+ while true do
520+ local mname , mtype = vim .loop .fs_scandir_next (years_handle )
521+ if not mname then
522+ break
523+ end
524+
525+ if mtype == " directory" then
526+ local months_handle = vim .loop .fs_scandir (base .. name .. config .pathsep .. mname )
527+ if type (months_handle ) == " userdata" then
528+ while true do
529+ local dname , dtype = vim .loop .fs_scandir_next (months_handle )
530+ if not dname then
531+ break
532+ end
533+
534+ -- Day files like `02.norg`
535+ if dtype == " file" and string.match (dname , " %d%d%.norg" ) then
536+ local file = vim .split (dname , " ." , { plain = true })
537+ try_update (name , mname , file [1 ])
538+ end
539+ end
540+ end
541+ end
542+ end
543+ end
544+ end
545+
546+ -- Flat strategy files directly in the journal folder
547+ if ftype == " file" and string.match (name , " %d%d%d%d%-%d%d%-%d%d%.norg" ) then
548+ local file = vim .split (name , " ." , { plain = true })
549+ local parts = vim .split (file [1 ], " -" )
550+ try_update (parts [1 ], parts [2 ], parts [3 ])
551+ end
552+ end
553+
554+ return best_date -- nil if none
555+ end ,
461556}
462557
463558module .on_event = function (event )
@@ -466,6 +561,8 @@ module.on_event = function(event)
466561 module .public .diary_tomorrow ()
467562 elseif event .split_type [2 ] == " journal.yesterday" then
468563 module .public .diary_yesterday ()
564+ elseif event .split_type [2 ] == " journal.previous" then
565+ module .public .open_previous ()
469566 elseif event .split_type [2 ] == " journal.custom" then
470567 if not event .content [1 ] then
471568 local calendar = modules .get_module (" core.ui.calendar" )
@@ -507,6 +604,7 @@ module.events.subscribed = {
507604 [" journal.yesterday" ] = true ,
508605 [" journal.tomorrow" ] = true ,
509606 [" journal.today" ] = true ,
607+ [" journal.previous" ] = true ,
510608 [" journal.custom" ] = true ,
511609 [" journal.template" ] = true ,
512610 [" journal.toc.update" ] = true ,
0 commit comments