diff options
| author | Gabriel Schneider <[email protected]> | 2026-07-30 17:05:12 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-07-30 17:56:23 -0300 |
| commit | 8ec4e135e318c7799b2576a8729493c063da4a97 (patch) | |
| tree | ab37cdbb7f478eb996264cf941891f127f303c85 /vrsite/model.go | |
| parent | cb05c363045bf0e7af5858f6d7bc26f026fa9d70 (diff) | |
| download | notevi-8ec4e135e318c7799b2576a8729493c063da4a97.tar.gz notevi-8ec4e135e318c7799b2576a8729493c063da4a97.zip | |
Diffstat (limited to 'vrsite/model.go')
| -rw-r--r-- | vrsite/model.go | 54 |
1 files changed, 43 insertions, 11 deletions
diff --git a/vrsite/model.go b/vrsite/model.go index 2cafd75..678d5ee 100644 --- a/vrsite/model.go +++ b/vrsite/model.go @@ -74,22 +74,37 @@ type Site struct { Title string Repo string Change string // the change most entries were logged at + Only string // the change this view is scoped to ("" = the whole log) Agents []*Agent Files map[string]*File // traced files Order []string // traced paths, sorted All []*File // every file in the repo at the site change - Notes []*Note - Entries []Entry - Theme *Theme // dark + Notes []*Note // in scope + Entries []Entry // the whole log, scope or no scope + Theme *Theme // dark Light *Theme + + // counted over the whole log, so a scoped view can still say what it is + // not showing + NotesTotal int + NotesAt map[string]int // change -> notes recorded there + Votes map[string]int // change -> entries recorded there + Ranked []string // changes, most-logged first } // buildModel projects log entries onto agents, files and notes. It never // touches the repo, so it is cheap enough to redo on every log change. -func buildModel(title string, entries []Entry) *Site { - s := &Site{Title: title, Files: map[string]*File{}, Entries: entries} +// +// only, when set, keeps just what was recorded at that change: a read logged +// against another change points at line numbers that have since moved, so a +// view of one change must not inherit them. Two things stay whole-log +// regardless — agent colors, so they do not shuffle when the scope changes, +// and note ids, so a link to a note survives it. +func buildModel(title string, entries []Entry, only string) *Site { + s := &Site{Title: title, Only: only, Files: map[string]*File{}, Entries: entries, + NotesAt: map[string]int{}, Votes: map[string]int{}} agents := map[string]*Agent{} - changeVotes := map[string]int{} + noteN := 0 for _, e := range entries { if e.Agent == "" { e.Agent = "unknown" @@ -105,7 +120,15 @@ func buildModel(title string, entries []Entry) *Site { s.Agents = append(s.Agents, a) } if e.Change != "" { - changeVotes[e.Change]++ + s.Votes[e.Change]++ + } + if e.Op == "note" { + noteN++ + s.NotesTotal++ + s.NotesAt[e.Change]++ + } + if only != "" && e.Change != only { + continue } switch e.Op { case "read": @@ -125,7 +148,7 @@ func buildModel(title string, entries []Entry) *Site { case "note": a.Notes++ at := parseTime(e.Time) - n := &Note{ID: len(s.Notes) + 1, NoteID: e.NoteID, Agent: a, Session: e.Session, + n := &Note{ID: noteN, NoteID: e.NoteID, Agent: a, Session: e.Session, Model: e.Model, Reason: e.Reason, File: e.File, Change: e.Change, Rev: e.Rev, Start: e.Start, End: e.End, Kind: e.Type, Text: e.Text, At: at, When: stamp(at), Ago: ago(at)} @@ -136,10 +159,19 @@ func buildModel(title string, entries []Entry) *Site { } } } - for c, n := range changeVotes { - if s.Change == "" || n > changeVotes[s.Change] { - s.Change = c + for c := range s.Votes { + s.Ranked = append(s.Ranked, c) + } + // most-logged first; ties by id so the pick is stable across rebuilds + sort.Slice(s.Ranked, func(i, j int) bool { + a, b := s.Ranked[i], s.Ranked[j] + if s.Votes[a] != s.Votes[b] { + return s.Votes[a] > s.Votes[b] } + return a < b + }) + if len(s.Ranked) > 0 { + s.Change = s.Ranked[0] } // drop grep-only "files" that are really path filters (dirs, non-files) for p, f := range s.Files { |
