From c58b03b6653a0de0f215c117910bbbe94589545a Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Fri, 20 Mar 2026 17:04:32 +0100 Subject: [PATCH] Sync frontmatter on body write; add refresh ctl command --- internal/p9/server/server.go | 49 +++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/internal/p9/server/server.go b/internal/p9/server/server.go index a7e15ea..1a028f7 100644 --- a/internal/p9/server/server.go +++ b/internal/p9/server/server.go @@ -34,6 +34,7 @@ package fs import ( "denotesrv/internal/disk" + "denotesrv/pkg/encoding/frontmatter" "denotesrv/pkg/encoding/results" "denotesrv/pkg/metadata" "errors" @@ -700,7 +701,7 @@ func (s *server) dispatchWrite(f *fid, tag uint16) *plan9.Fcall { } } case "body": - if err := s.writeBody(note.Path, input); err != nil { + if err := s.writeBody(note.Path, input, note); err != nil { return errorFcall(fc, err.Error()) } default: @@ -1006,12 +1007,23 @@ func (s *server) readBody(path string) string { return string(data) } -// writeBody writes content to file -func (s *server) writeBody(path, body string) error { +// writeBody writes content to file and syncs frontmatter to metadata +func (s *server) writeBody(path, body string, note *metadata.Metadata) error { if path == "" { return fmt.Errorf("no path") } - return os.WriteFile(path, []byte(body), 0644) + if err := os.WriteFile(path, []byte(body), 0644); err != nil { + return err + } + // Parse frontmatter and sync to metadata + ext := filepath.Ext(path) + fm, _, _ := frontmatter.Unmarshal([]byte(body), ext) + if fm != nil && fm.Title != "" { + note.Title = fm.Title + note.Tags = fm.Tags + note.Signature = fm.Signature + } + return nil } func errorFcall(fc *plan9.Fcall, msg string) *plan9.Fcall { @@ -1035,9 +1047,38 @@ func (s *server) handleCtlCommand(fc *plan9.Fcall) *plan9.Fcall { return s.handleCdCommand(fc, command) } + if command == "refresh" { + return s.handleRefreshCommand(fc) + } + return errorFcall(fc, fmt.Sprintf("unknown ctl command: %s", command)) } +// handleRefreshCommand reloads metadata from disk for all notes +func (s *server) handleRefreshCommand(fc *plan9.Fcall) *plan9.Fcall { + s.mu.Lock() + defer s.mu.Unlock() + + for _, note := range s.notes { + if note.Path == "" { + continue + } + data, err := os.ReadFile(note.Path) + if err != nil { + continue + } + ext := filepath.Ext(note.Path) + fm, _, _ := frontmatter.Unmarshal(data, ext) + if fm != nil && fm.Title != "" { + note.Title = fm.Title + note.Tags = fm.Tags + note.Signature = fm.Signature + } + } + + return &plan9.Fcall{Type: plan9.Rwrite, Tag: fc.Tag, Count: uint32(len(fc.Data))} +} + // handleFilterCommand processes the 'filter' ctl command func (s *server) handleFilterCommand(fc *plan9.Fcall, command string) *plan9.Fcall { // Extract filter query after "filter" keyword