Reorganization, renaming. Readme updates. Better feature parity in Djournal.
This commit is contained in:
parent
7b1e3f5787
commit
58f6fa4fe8
68
README.md
68
README.md
|
|
@ -8,12 +8,14 @@ The goal of this program is to provide an implementation of prot's [denote](http
|
|||
|
||||
This README assumes you already have [plan9port](https://github.com/9fans/plan9port) installed.
|
||||
|
||||
### Install
|
||||
```sh
|
||||
mk install
|
||||
```
|
||||
|
||||
This installs `Denote` and all its extensions to $HOME/bin.
|
||||
|
||||
### Setup
|
||||
|
||||
Start the Denote program by middle-clicking `Denote` anywhere in acme. This will open the `/Denote/` window. Notes are stored in `~/doc` by default, simply edit this in `main.go` to change your denote base directory.
|
||||
|
||||
## Usage
|
||||
|
|
@ -26,7 +28,6 @@ In Acme, you can highlight something like:
|
|||
|
||||
Pass it as input to the `New` tag with the `2-1` chord. This will create a new Acme window with Denote frontmatter and an appropriate file path. **Important:** the actual file is not created until the `Put` command is executed. (Tags are optional but recommended).
|
||||
|
||||
#### Create notes in subdirectories
|
||||
You can organize notes into subdirectories using the `/:` separator in the title:
|
||||
```
|
||||
'journal/:today's entry' journal
|
||||
|
|
@ -40,6 +41,10 @@ The text before `/:` becomes the subdirectory path (e.g., `journal/`, `projects/
|
|||
|
||||
First, be sure to set up the [plumbing rules](./PLUMBING.md). Then, simply right-click on any identifier in the `/Denote/` window.
|
||||
|
||||
### Edit a note
|
||||
|
||||
Edit a note just like any other text file. Use `Put` to save. The Denote metadata will be refreshed automatically.
|
||||
|
||||
### Delete a note
|
||||
|
||||
To delete a note, highlight its identifier in the `/Denote/` window:
|
||||
|
|
@ -62,25 +67,9 @@ tag1
|
|||
|
||||
Highlight this and pass it as input to the `Look` command with the `2-1` chord. This will filter the list of entries to those that match the search query. Executing `Look` without arguments resets the search filter. You may also right-click in the Denote window on titles or tags to jump between matches.
|
||||
|
||||
### Journal
|
||||
|
||||
Create or open today's journal:
|
||||
```
|
||||
Journal
|
||||
```
|
||||
|
||||
Journal for other times:
|
||||
```
|
||||
Journal +1d # tomorrow
|
||||
Journal -7d # 7 days ago
|
||||
Journal +3h # 3 hours from now
|
||||
Journal -30m # 30 minutes ago
|
||||
```
|
||||
|
||||
Supports: `d` (days), `h` (hours), `m` (minutes). You can use this to create multiple entries on the same day. To find an existing journal entry, use the search function in `Denote` described above. You can also pass the args in with the `2-1` chord.
|
||||
|
||||
### Metadata Editing
|
||||
You may edit metadata directly in the Denote window.
|
||||
|
||||
Quality of life feature: you may edit metadata directly in the Denote window.
|
||||
|
||||
```
|
||||
-------------------------------------------------------
|
||||
|
|
@ -110,7 +99,7 @@ You may edit metadata directly in the Denote window.
|
|||
|
||||
Middle-click `Put` to write all metadata changes. This will rename files and, when possible, update front matter.
|
||||
|
||||
## Sync
|
||||
### Sync
|
||||
|
||||
Sometimes it's necessary to update the Denote metadata from the filesystem. Middle-click `Sync` to do this.
|
||||
|
||||
|
|
@ -126,3 +115,40 @@ You may change this by changing `ftype` in main.go.
|
|||
## Encryption Support
|
||||
|
||||
This program supports encrypted notes by integrating with [acme-crypt](https://github.com/lneely/acme-crypt). Set up the [plumbing rules](./PLUMBING.md) to read encrypted notes, and use `CryptPut` to write them.
|
||||
|
||||
## Extensions
|
||||
|
||||
Some extensions have also been ported.
|
||||
|
||||
### Djournal
|
||||
|
||||
Concept from prot's [denote-journal](https://github.com/protesilaos/denote-journal). While `Djournal` tries to stay as true as possible to the original program and be as feature-complete as possible, it is intentionally *not* an exact replica.
|
||||
|
||||
Create or open today's journal entry (or this week's, month's, or year's, depending on `interval` configuration):
|
||||
|
||||
```
|
||||
Djournal
|
||||
```
|
||||
|
||||
Supports: `d` (days), `h` (hours), `m` (minutes). You can use this to create multiple entries on the same day. To find an existing journal entry, use the search function in `Denote` described above. You can also pass the args in with the `2-1` chord.
|
||||
|
||||
Configure `Djournal` by editing the configuration options in the `Djournal` script.
|
||||
|
||||
```
|
||||
# Journal interval: daily, weekly, monthly, yearly
|
||||
interval=daily
|
||||
|
||||
# Title format: full, date, day, year
|
||||
# Examples:
|
||||
# full: "wednesday 12 november 2025 22:11"
|
||||
# date: "wednesday 12 november 2025"
|
||||
# day: "wednesday"
|
||||
# year: "2025"
|
||||
titleformat=full
|
||||
|
||||
# Signature (optional, added to filename as ==signature)
|
||||
signature=''
|
||||
```
|
||||
|
||||
### Merge
|
||||
|
||||
|
|
|
|||
5
mkfile
5
mkfile
|
|
@ -1,6 +1,7 @@
|
|||
install:V:
|
||||
go build -o $HOME/bin/Denote .
|
||||
cp scripts/Journal $HOME/bin/Journal
|
||||
cp scripts/Djournal $HOME/bin/Djournal
|
||||
cp scripts/Dmerge $HOME/bin/Dmerge
|
||||
|
||||
clean:V:
|
||||
rm -f $HOME/bin/Denote $HOME/bin/Journal
|
||||
rm -f $HOME/bin/Denote $HOME/bin/Djournal $HOME/bin/Dmerge
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
#!/usr/local/plan9/bin/rc
|
||||
|
||||
# Journal interval: daily, weekly, monthly, yearly
|
||||
interval=daily
|
||||
|
||||
# Title format: full, date, day, year
|
||||
# Examples:
|
||||
# full: "wednesday 12 november 2025 22:11"
|
||||
# date: "wednesday 12 november 2025"
|
||||
# day: "wednesday"
|
||||
# year: "2025"
|
||||
titleformat=full
|
||||
|
||||
# Signature (optional, added to filename as ==signature)
|
||||
signature=''
|
||||
|
||||
# Parse time offset argument (e.g., +2d, -3h, +15m)
|
||||
offset=0
|
||||
if(! ~ $#* 0) {
|
||||
arg=$1
|
||||
# Extract components using awk
|
||||
sign=`{echo $arg | awk '{print substr($0,1,1)}'}
|
||||
num=`{echo $arg | awk '{s=substr($0,2); sub(/[a-z]$/,"",s); print s}'}
|
||||
unit=`{echo $arg | awk '{print substr($0,length($0))}'}
|
||||
|
||||
# Calculate offset in seconds
|
||||
switch($unit) {
|
||||
case d
|
||||
offset=`{hoc -e 'int('$num' * 86400)'}
|
||||
case h
|
||||
offset=`{hoc -e 'int('$num' * 3600)'}
|
||||
case m
|
||||
offset=`{hoc -e 'int('$num' * 60)'}
|
||||
}
|
||||
|
||||
# Apply sign
|
||||
if(~ $sign '-') {
|
||||
offset=`{hoc -e 'int(-1 * '$offset')'}
|
||||
}
|
||||
}
|
||||
|
||||
# Calculate reference timestamp based on interval
|
||||
epoch=`{date -n}
|
||||
|
||||
# Adjust epoch to interval start if no offset provided
|
||||
if(~ $#* 0) {
|
||||
switch($interval) {
|
||||
case weekly
|
||||
# Get start of week (Monday)
|
||||
# date outputs: Sun Nov 24 07:30:00 EST 2025
|
||||
dow=`{date $epoch | awk '{print $1}'}
|
||||
# Calculate days since Monday (Mon=0, Tue=1, ..., Sun=6)
|
||||
daysback=0
|
||||
switch($dow) {
|
||||
case Mon; daysback=0
|
||||
case Tue; daysback=1
|
||||
case Wed; daysback=2
|
||||
case Thu; daysback=3
|
||||
case Fri; daysback=4
|
||||
case Sat; daysback=5
|
||||
case Sun; daysback=6
|
||||
}
|
||||
epoch=`{hoc -e 'int('$epoch' - ('$daysback' * 86400))'}
|
||||
case monthly
|
||||
# Get start of month (day 1)
|
||||
# Extract year, month from current date
|
||||
yearmonth=`{date $epoch | awk '{print $6 " " $2}'}
|
||||
# Use date with format: Nov 1 2025
|
||||
epoch=`{date -n `{echo $yearmonth | awk '{print $2 " 1 " $1}'}}
|
||||
case yearly
|
||||
# Get start of year (Jan 1)
|
||||
year=`{date $epoch | awk '{print $6}'}
|
||||
epoch=`{date -n 'Jan 1 '^$year}
|
||||
}
|
||||
}
|
||||
|
||||
targetepoch=`{hoc -e 'int('$epoch' + '$offset')'}
|
||||
|
||||
# Get formatted date (e.g., "Wednesday 12 November 2025 22:11")
|
||||
datefull=`{date $targetepoch | awk '
|
||||
BEGIN {
|
||||
m["Jan"]="January"; m["Feb"]="February"; m["Mar"]="March"
|
||||
m["Apr"]="April"; m["May"]="May"; m["Jun"]="June"
|
||||
m["Jul"]="July"; m["Aug"]="August"; m["Sep"]="September"
|
||||
m["Oct"]="October"; m["Nov"]="November"; m["Dec"]="December"
|
||||
d["Sun"]="Sunday"; d["Mon"]="Monday"; d["Tue"]="Tuesday"
|
||||
d["Wed"]="Wednesday"; d["Thu"]="Thursday"; d["Fri"]="Friday"
|
||||
d["Sat"]="Saturday"
|
||||
}
|
||||
{
|
||||
split($4, t, ":")
|
||||
print d[$1], $3, m[$2], $6, t[1]":"t[2]
|
||||
}'}
|
||||
|
||||
# Format title based on titleformat setting
|
||||
switch($titleformat) {
|
||||
case full
|
||||
title=`{echo $datefull | awk '{print tolower($0)}'}
|
||||
case date
|
||||
title=`{echo $datefull | awk '{print tolower($1 " " $2 " " $3 " " $4)}'}
|
||||
case day
|
||||
title=`{echo $datefull | awk '{print tolower($1)}'}
|
||||
case year
|
||||
title=`{echo $datefull | awk '{print $4}'}
|
||||
case *
|
||||
# Default to full if invalid format specified
|
||||
title=`{echo $datefull | awk '{print tolower($0)}'}
|
||||
}
|
||||
|
||||
# Apply filter
|
||||
echo 'filter title:'''$"title'''' | 9p write denote/ctl
|
||||
|
||||
# Check if there are any results
|
||||
results=`{9p read denote/index}
|
||||
|
||||
# If no results, create new journal entry
|
||||
if(~ $#results 0) {
|
||||
if(! ~ $signature '') {
|
||||
echo '''journal/:'$"title'=='^$signature''' journal' | 9p write denote/new
|
||||
}
|
||||
if not {
|
||||
echo '''journal/:'$"title''' journal' | 9p write denote/new
|
||||
}
|
||||
}
|
||||
if not Denote 'denote:'$results(1)
|
||||
|
||||
# Clear filter
|
||||
echo 'filter' | 9p write denote/ctl
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
#!/usr/local/plan9/bin/rc
|
||||
|
||||
# Merge - Merge source note into destination note
|
||||
# Usage: Merge <source-id> <dest-id>
|
||||
|
||||
if(~ $#* 2) {
|
||||
src=$1
|
||||
dst=$2
|
||||
}
|
||||
if not {
|
||||
echo 'usage: Merge source-id dest-id' >[1=2]
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Read paths and titles
|
||||
srcpath=`{9p read denote/n/$src/path}
|
||||
dstpath=`{9p read denote/n/$dst/path}
|
||||
srctitle=`{9p read denote/n/$src/title}
|
||||
|
||||
if(~ $#srcpath 0 || ~ $#dstpath 0) {
|
||||
echo 'error: note not found' >[1=2]
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Extract content without frontmatter (everything after first blank line)
|
||||
awk '
|
||||
BEGIN { found_blank = 0 }
|
||||
found_blank { print }
|
||||
!found_blank && /^$/ { found_blank = 1 }
|
||||
' $srcpath > /tmp/content.$pid
|
||||
|
||||
# Append source content to destination with annotation
|
||||
{
|
||||
cat $dstpath
|
||||
echo ''
|
||||
echo '* * *'
|
||||
echo ''
|
||||
echo 'MERGED FILE:' $srctitle
|
||||
echo ''
|
||||
cat /tmp/content.$pid
|
||||
} > /tmp/merge.$pid
|
||||
|
||||
rm /tmp/content.$pid
|
||||
|
||||
# Update all backlinks pointing to source
|
||||
9p read denote/n/$src/backlinks | awk -F'|' '{print $1}' | while(read linkid) {
|
||||
linkid=`{echo $linkid | awk '{gsub(/^ +| +$/, ""); print}'}
|
||||
if(! ~ $#linkid 0) {
|
||||
linkpath=`{9p read denote/n/$linkid/path}
|
||||
if(! ~ $#linkpath 0) {
|
||||
# Replace denote:src with denote:dst in the file
|
||||
sed 's/denote:'$src'/denote:'$dst'/g' $linkpath > /tmp/relink.$pid
|
||||
cp /tmp/relink.$pid $linkpath
|
||||
rm /tmp/relink.$pid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Write merged content to destination
|
||||
cp /tmp/merge.$pid $dstpath
|
||||
rm /tmp/merge.$pid
|
||||
|
||||
# Delete source note
|
||||
echo 'd' | 9p write denote/n/$src/ctl
|
||||
|
||||
echo 'Merged' $src 'into' $dst
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
#!/usr/local/plan9/bin/rc
|
||||
|
||||
# Parse time offset argument (e.g., +2d, -3h, +15m)
|
||||
offset=0
|
||||
if(! ~ $#* 0) {
|
||||
arg=$1
|
||||
# Extract components using awk
|
||||
sign=`{echo $arg | awk '{print substr($0,1,1)}'}
|
||||
num=`{echo $arg | awk '{s=substr($0,2); sub(/[a-z]$/,"",s); print s}'}
|
||||
unit=`{echo $arg | awk '{print substr($0,length($0))}'}
|
||||
|
||||
# Calculate offset in seconds
|
||||
switch($unit) {
|
||||
case d
|
||||
offset=`{hoc -e 'int('$num' * 86400)'}
|
||||
case h
|
||||
offset=`{hoc -e 'int('$num' * 3600)'}
|
||||
case m
|
||||
offset=`{hoc -e 'int('$num' * 60)'}
|
||||
}
|
||||
|
||||
# Apply sign
|
||||
if(~ $sign '-') {
|
||||
offset=`{hoc -e 'int(-1 * '$offset')'}
|
||||
}
|
||||
}
|
||||
|
||||
# Calculate target timestamp
|
||||
epoch=`{date -n}
|
||||
targetepoch=`{hoc -e 'int('$epoch' + '$offset')'}
|
||||
|
||||
# Get formatted date (e.g., "Wednesday 12 November 2025 22:11")
|
||||
datefull=`{date $targetepoch | awk '
|
||||
BEGIN {
|
||||
m["Jan"]="January"; m["Feb"]="February"; m["Mar"]="March"
|
||||
m["Apr"]="April"; m["May"]="May"; m["Jun"]="June"
|
||||
m["Jul"]="July"; m["Aug"]="August"; m["Sep"]="September"
|
||||
m["Oct"]="October"; m["Nov"]="November"; m["Dec"]="December"
|
||||
d["Sun"]="Sunday"; d["Mon"]="Monday"; d["Tue"]="Tuesday"
|
||||
d["Wed"]="Wednesday"; d["Thu"]="Thursday"; d["Fri"]="Friday"
|
||||
d["Sat"]="Saturday"
|
||||
}
|
||||
{
|
||||
split($4, t, ":")
|
||||
print d[$1], $3, m[$2], $6, t[1]":"t[2]
|
||||
}'}
|
||||
|
||||
# Extract date-only part (remove time) and convert to lowercase
|
||||
dateonly=`{echo $datefull | awk '{print tolower($1 " " $2 " " $3 " " $4)}'}
|
||||
|
||||
# Apply filter - use full datetime if offset arg provided, date-only otherwise
|
||||
if(! ~ $#* 0) {
|
||||
# With offset: filter by full datetime for precise matching
|
||||
filterdate=`{echo $datefull | awk '{print tolower($0)}'}
|
||||
echo 'filter title:'''$"filterdate'''' | 9p write denote/ctl
|
||||
}
|
||||
if not echo 'filter title:'''$"dateonly'''' | 9p write denote/ctl
|
||||
|
||||
# Check if there are any results
|
||||
results=`{9p read denote/index}
|
||||
|
||||
# If no results, create new journal entry
|
||||
if(~ $#results 0) {
|
||||
echo '''journal/:'$"datefull''' journal' | 9p write denote/new
|
||||
}
|
||||
if not Denote 'denote:'$results(1)
|
||||
|
||||
# Clear filter
|
||||
echo 'filter' | 9p write denote/ctl
|
||||
Loading…
Reference in New Issue