Add plumbing integration and improve output format
- Add PLUMBING.md documentation for denote plumber integration - Update DisplayNotes to use clickable format: denote:ID | title | tags - Simplify plumbing rules to single pattern matching rule
This commit is contained in:
parent
313914d49e
commit
c2c809cdbe
|
|
@ -0,0 +1,64 @@
|
|||
# Plumbing Integration for Denote
|
||||
|
||||
This document describes how to integrate the Denote command with the Plan 9 plumber to enable right-click opening of denote notes.
|
||||
|
||||
## Overview
|
||||
|
||||
The plumbing rules allow you to right-click on `denote:<identifier>` text in acme and have it automatically open the corresponding note.
|
||||
|
||||
## Setup
|
||||
|
||||
Add these rules to your `$HOME/lib/plumbing` file:
|
||||
|
||||
```
|
||||
# declarations of ports without rules
|
||||
plumb to denote
|
||||
|
||||
# Denote identifiers - open note by identifier
|
||||
type is text
|
||||
data matches 'denote:([0-9]+T[0-9]+)'
|
||||
plumb to denote
|
||||
plumb start Denote open $1
|
||||
```
|
||||
|
||||
### Rule Placement
|
||||
|
||||
- The port declaration (`plumb to denote`) should go with other port declarations near the top
|
||||
- The pattern matching rule should be placed **before** generic file matching rules to ensure it fires first
|
||||
|
||||
## Reload Rules
|
||||
|
||||
After editing `$HOME/lib/plumbing`, reload the rules:
|
||||
|
||||
```rc
|
||||
cat $HOME/lib/plumbing | 9p write plumb/rules
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Once configured, you can right-click (button 3) on any text matching the pattern:
|
||||
|
||||
```
|
||||
denote:20251103T165653
|
||||
```
|
||||
|
||||
This will execute `Denote open 20251103T165653` and open the note in acme.
|
||||
|
||||
## Pattern Details
|
||||
|
||||
The regex pattern `denote:([0-9]+T[0-9]+)` matches:
|
||||
- The literal text `denote:`
|
||||
- One or more digits
|
||||
- The letter `T`
|
||||
- One or more digits
|
||||
|
||||
This matches the standard Denote identifier format: `YYYYMMddTHHmmss`
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If right-clicking doesn't work:
|
||||
|
||||
1. Verify rules are loaded: `9p read plumb/rules | grep denote`
|
||||
2. Check the command exists: `which Denote`
|
||||
3. Test manually: `plumb "denote:20251103T165653"`
|
||||
4. Ensure the pattern uses `+` not `{n}` quantifiers (Plan 9 regex limitation)
|
||||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
|
@ -272,6 +273,44 @@ func handleRenameReturnNote(args []string) *denote.Note {
|
|||
return renamedNote
|
||||
}
|
||||
|
||||
func handleOpen(dir string, args []string) {
|
||||
if len(args) == 0 {
|
||||
fmt.Fprintf(os.Stderr, "Usage: open <identifier>\n\nOpen a note by its identifier.\n\nExample:\n open 20251016T091314\n")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
identifier := args[0]
|
||||
|
||||
// Search for note with this identifier
|
||||
identFilter, err := denote.ParseFilter(fmt.Sprintf("date:%s", identifier))
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error: invalid identifier: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
notes, err := denote.FindNotes(dir, []*denote.Filter{identFilter})
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error searching for note: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if len(notes) == 0 {
|
||||
fmt.Fprintf(os.Stderr, "error: no note found with identifier %s\n", identifier)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if len(notes) > 1 {
|
||||
fmt.Fprintf(os.Stderr, "warning: multiple notes found with identifier %s, opening first\n", identifier)
|
||||
}
|
||||
|
||||
// Open the file in acme using plumb
|
||||
cmd := exec.Command("plumb", notes[0].Path)
|
||||
if err := cmd.Run(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error opening file: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
dir := flag.String("dir", denote.DefaultDir(), "denote directory")
|
||||
flag.Parse()
|
||||
|
|
@ -354,6 +393,7 @@ Usage:
|
|||
Denote + 'Title' [tags...] Alias for new
|
||||
Denote rename /path ['Title'] [tags...] Rename a note
|
||||
Denote r /path ['Title'] [tags...] Alias for rename
|
||||
Denote open <identifier> Open note by identifier
|
||||
Denote ? Show this help
|
||||
|
||||
Filters:
|
||||
|
|
@ -390,6 +430,12 @@ For 'rename' command help: Denote rename
|
|||
return
|
||||
}
|
||||
|
||||
// Check if this is an "open" command
|
||||
if len(filterArgs) > 0 && filterArgs[0] == "open" {
|
||||
handleOpen(*dir, filterArgs[1:])
|
||||
return
|
||||
}
|
||||
|
||||
var filters []*denote.Filter
|
||||
sortType := denote.SortByID // Default sort
|
||||
|
||||
|
|
|
|||
|
|
@ -233,11 +233,8 @@ func DisplayNotes(notes []*Note) error {
|
|||
title = "(untitled)"
|
||||
}
|
||||
|
||||
buf.WriteString(title)
|
||||
if len(n.Keywords) > 0 {
|
||||
fmt.Fprintf(&buf, " (%s)", strings.Join(n.Keywords, ", "))
|
||||
}
|
||||
fmt.Fprintf(&buf, "\n%s\n\n", n.Path)
|
||||
tags := strings.Join(n.Keywords, ", ")
|
||||
fmt.Fprintf(&buf, "denote:%s | %s | %s\n", n.Identifier, title, tags)
|
||||
}
|
||||
|
||||
w.Write("body", []byte(buf.String()))
|
||||
|
|
|
|||
Loading…
Reference in New Issue