Skip to content

Commit 3cbfff7

Browse files
jonhadfieldclaude
andcommitted
fix tag cloud to use Tag→Note references
Fixed tag cloud and tag stats to correctly count note associations by reading references from tags to notes (Tag→Note) instead of from notes to tags (Note→Tag). Standard Notes stores tag associations as references from the tag object to note objects. Changes: - Count tag.Content.References() looking for Note types - Build note UUID map for validation - Add diagnostics to show reference direction - Update both ShowTagCloud() and ShowTagStats() functions This matches the official Standard Notes app behavior. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 92762ef commit 3cbfff7

1 file changed

Lines changed: 112 additions & 82 deletions

File tree

cmd/sncli/tagcloud.go

Lines changed: 112 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -280,102 +280,124 @@ func ShowTagCloud(opts configOptsOutput) error {
280280
return err
281281
}
282282

283-
if opts.debug {
284-
pterm.Debug.Printf("Retrieved %d tags and %d notes from cache\n", len(rawTags), len(rawNotes))
285-
286-
// Check first few notes for references
287-
if len(rawNotes) > 0 {
288-
for i := 0; i < 10 && i < len(rawNotes); i++ {
289-
sampleNote := rawNotes[i].(*items.Note)
290-
refs := sampleNote.Content.References()
291-
if len(refs) > 0 {
292-
pterm.Debug.Printf("Note %d (UUID: %s) has %d references:\n", i, sampleNote.UUID[:12]+"...", len(refs))
293-
for j, ref := range refs {
294-
if j < 3 {
295-
pterm.Debug.Printf(" Ref: ContentType='%s', UUID='%s'\n", ref.ContentType, ref.UUID[:12]+"...")
283+
// Check first 10 notes for references (always show)
284+
fmt.Printf("Checking first 10 notes for references...\n")
285+
foundRefs := false
286+
if len(rawNotes) > 0 {
287+
for i := 0; i < 10 && i < len(rawNotes); i++ {
288+
sampleNote := rawNotes[i].(*items.Note)
289+
refs := sampleNote.Content.References()
290+
if len(refs) > 0 {
291+
foundRefs = true
292+
fmt.Printf(" Note %d has %d references:\n", i, len(refs))
293+
for j, ref := range refs {
294+
if j < 3 {
295+
shortUUID := ref.UUID
296+
if len(shortUUID) > 12 {
297+
shortUUID = shortUUID[:12] + "..."
296298
}
299+
fmt.Printf(" Ref %d: Type='%s', UUID='%s'\n", j, ref.ContentType, shortUUID)
297300
}
298-
break
299301
}
302+
break
300303
}
301304
}
302305
}
303-
304-
// Build tag statistics
305-
tagStats := make(map[string]*TagStats)
306-
307-
for _, item := range rawTags {
308-
tag := item.(*items.Tag)
309-
title := tag.Content.GetTitle()
310-
if opts.debug {
311-
pterm.Debug.Printf("Processing tag: %s (UUID: %s)\n", title, tag.UUID)
312-
}
313-
tagStats[tag.UUID] = &TagStats{
314-
Title: title,
315-
UUID: tag.UUID,
316-
NoteCount: 0,
317-
CreatedAt: tag.CreatedAt,
318-
}
306+
if !foundRefs {
307+
fmt.Printf(" No references found in first 10 notes\n")
319308
}
320309

321-
// Count note references for each tag
322-
totalRefs := 0
323-
matchedRefs := 0
324-
refTypesSeen := make(map[string]int)
325-
notesWithRefs := 0
326-
327-
for _, item := range rawNotes {
328-
note := item.(*items.Note)
329-
refs := note.Content.References()
330-
331-
if len(refs) > 0 {
332-
notesWithRefs++
333-
if opts.debug && notesWithRefs <= 3 {
334-
pterm.Debug.Printf("Note with refs #%d (of %d total notes) has %d references:\n", notesWithRefs, len(rawNotes), len(refs))
310+
// CRITICAL: Check if TAGS have references to NOTES (reverse direction)
311+
fmt.Printf("\nChecking first 10 tags for references to notes...\n")
312+
foundTagRefs := false
313+
if len(rawTags) > 0 {
314+
for i := 0; i < 10 && i < len(rawTags); i++ {
315+
sampleTag := rawTags[i].(*items.Tag)
316+
refs := sampleTag.Content.References()
317+
if len(refs) > 0 {
318+
foundTagRefs = true
319+
fmt.Printf(" Tag '%s' has %d references:\n", sampleTag.Content.GetTitle(), len(refs))
335320
for j, ref := range refs {
336-
if j < 5 {
321+
if j < 3 {
337322
shortUUID := ref.UUID
338323
if len(shortUUID) > 12 {
339324
shortUUID = shortUUID[:12] + "..."
340325
}
341-
pterm.Debug.Printf(" Ref %d: ContentType='%s', UUID='%s'\n", j, ref.ContentType, shortUUID)
326+
fmt.Printf(" Ref %d: Type='%s', UUID='%s'\n", j, ref.ContentType, shortUUID)
342327
}
343328
}
329+
if !foundTagRefs {
330+
break
331+
}
344332
}
345333
}
334+
}
335+
if !foundTagRefs {
336+
fmt.Printf(" No references found in first 10 tags\n")
337+
}
338+
339+
// Build tag statistics and count from tags (Tag → Note references)
340+
tagStats := make(map[string]*TagStats)
341+
noteUUIDs := make(map[string]bool)
342+
343+
// Build note UUID map for validation
344+
for _, item := range rawNotes {
345+
note := item.(*items.Note)
346+
noteUUIDs[note.UUID] = true
347+
}
348+
349+
// Count references FROM tags TO notes
350+
totalRefs := 0
351+
matchedRefs := 0
352+
refTypesSeen := make(map[string]int)
353+
tagsWithRefs := 0
354+
355+
for _, item := range rawTags {
356+
tag := item.(*items.Tag)
357+
title := tag.Content.GetTitle()
358+
refs := tag.Content.References()
346359

360+
noteCount := 0
361+
362+
// Count Note-type references from this tag
347363
for _, ref := range refs {
348364
refTypesSeen[ref.ContentType]++
349365

350-
if ref.ContentType == common.SNItemTypeTag {
366+
if ref.ContentType == common.SNItemTypeNote {
351367
totalRefs++
352-
if stats, ok := tagStats[ref.UUID]; ok {
353-
stats.NoteCount++
368+
// Check if this note UUID exists in our note list
369+
if noteUUIDs[ref.UUID] {
370+
noteCount++
354371
matchedRefs++
355-
} else if opts.debug && totalRefs <= 5 {
356-
pterm.Debug.Printf("Unmatched tag ref UUID: %s\n", ref.UUID)
357-
// Check if any tag UUID starts with the same prefix
358-
found := false
359-
for tagUUID := range tagStats {
360-
if len(ref.UUID) > 8 && len(tagUUID) > 8 && ref.UUID[:8] == tagUUID[:8] {
361-
pterm.Debug.Printf(" Similar tag UUID found: %s\n", tagUUID)
362-
found = true
363-
}
364-
}
365-
if !found && len(tagStats) <= 10 {
366-
pterm.Debug.Printf(" Available tag UUIDs: %v\n", getTagUUIDs(tagStats))
367-
}
368372
}
369373
}
370374
}
375+
376+
if len(refs) > 0 {
377+
tagsWithRefs++
378+
}
379+
380+
if opts.debug {
381+
pterm.Debug.Printf("Tag '%s': %d references, %d matched notes\n", title, len(refs), noteCount)
382+
}
383+
384+
tagStats[tag.UUID] = &TagStats{
385+
Title: title,
386+
UUID: tag.UUID,
387+
NoteCount: noteCount,
388+
CreatedAt: tag.CreatedAt,
389+
}
371390
}
372391

392+
// Always show summary to help diagnose
393+
fmt.Printf("\nDiagnostics (Tag → Note counting):\n")
394+
fmt.Printf(" Tags with references: %d / %d\n", tagsWithRefs, len(rawTags))
395+
fmt.Printf(" Reference types seen in tags: %v\n", refTypesSeen)
396+
fmt.Printf(" SNItemTypeNote constant = '%s'\n", common.SNItemTypeNote)
397+
fmt.Printf(" Total note references from tags: %d, Matched: %d, Unmatched: %d\n", totalRefs, matchedRefs, totalRefs-matchedRefs)
398+
373399
if opts.debug {
374-
pterm.Debug.Printf("\nSummary:\n")
375-
pterm.Debug.Printf(" Notes with references: %d / %d\n", notesWithRefs, len(rawNotes))
376-
pterm.Debug.Printf(" Reference types seen: %v\n", refTypesSeen)
377-
pterm.Debug.Printf(" SNItemTypeTag constant = '%s'\n", common.SNItemTypeTag)
378-
pterm.Debug.Printf(" Total tag references: %d, Matched: %d, Unmatched: %d\n", totalRefs, matchedRefs, totalRefs-matchedRefs)
400+
pterm.Debug.Printf("\nAdditional debug info above\n")
379401
}
380402

381403
// Convert to slice for sorting
@@ -548,31 +570,39 @@ func ShowTagStats(opts configOptsOutput) error {
548570
return err
549571
}
550572

551-
// Build statistics
573+
// Build statistics - count from tags (Tag → Note references)
552574
tagStats := make(map[string]*TagStats)
575+
noteUUIDs := make(map[string]bool)
576+
577+
// Build note UUID map for validation
578+
for _, item := range rawNotes {
579+
note := item.(*items.Note)
580+
noteUUIDs[note.UUID] = true
581+
}
553582

583+
// Count references FROM tags TO notes
554584
for _, item := range rawTags {
555585
tag := item.(*items.Tag)
556-
tagStats[tag.UUID] = &TagStats{
557-
Title: tag.Content.GetTitle(),
558-
UUID: tag.UUID,
559-
NoteCount: 0,
560-
CreatedAt: tag.CreatedAt,
561-
}
562-
}
586+
refs := tag.Content.References()
563587

564-
// Count references
565-
for _, item := range rawNotes {
566-
note := item.(*items.Note)
567-
refs := note.Content.References()
588+
noteCount := 0
568589

590+
// Count Note-type references from this tag
569591
for _, ref := range refs {
570-
if ref.ContentType == common.SNItemTypeTag {
571-
if stats, ok := tagStats[ref.UUID]; ok {
572-
stats.NoteCount++
592+
if ref.ContentType == common.SNItemTypeNote {
593+
// Check if this note UUID exists in our note list
594+
if noteUUIDs[ref.UUID] {
595+
noteCount++
573596
}
574597
}
575598
}
599+
600+
tagStats[tag.UUID] = &TagStats{
601+
Title: tag.Content.GetTitle(),
602+
UUID: tag.UUID,
603+
NoteCount: noteCount,
604+
CreatedAt: tag.CreatedAt,
605+
}
576606
}
577607

578608
// Convert to slice and sort

0 commit comments

Comments
 (0)