Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ After each implementation run tests and pre-commit.sh.
2. `mark_fetch` `/patterns.md` — build commands, code style, workflow
3. `mark_fetch` `/guidelines.md` — hard rules for code quality, must read before writing code
4. Fetch other pages as needed: `/architecture.md`, `/debugging.md`, `/roadmap.md`
5. If MCP is unavailable, stop and ask the user before proceeding
5. If MCP is unavailable, stop and ask the developer before proceeding

### During Work

Expand Down
4 changes: 2 additions & 2 deletions client/cmd/demarkus-tui/graphview.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"sort"
"strings"

tea "github.com/charmbracelet/bubbletea"
tea "charm.land/bubbletea/v2"
"github.com/latebit/demarkus/client/internal/fetch"
"github.com/latebit/demarkus/client/internal/graph"
"github.com/latebit/demarkus/client/internal/graphstore"
Expand Down Expand Up @@ -308,7 +308,7 @@ func renderTopologyView(items []graphListItem, selectedIdx, width int) string {
}

// handleGraphKey processes key events when the graph view is active.
func (m model) handleGraphKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
func (m model) handleGraphKey(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
switch msg.String() {
case "q":
return m, tea.Quit
Expand Down
47 changes: 34 additions & 13 deletions client/cmd/demarkus-tui/links_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import (
"github.com/latebit/demarkus/client/internal/links"
)

// osc8 wraps text in an OSC 8 hyperlink sequence, matching Glamour v2 output.
func osc8(url, text string) string {
return "\x1b]8;;" + url + "\x07" + text + "\x1b]8;;\x07"
}

func TestInjectLinkMarkers(t *testing.T) {
tests := []struct {
name string
Expand All @@ -25,23 +30,23 @@ func TestInjectLinkMarkers(t *testing.T) {
},
},
{
name: "single link gets markers",
body: "see hello rest",
name: "single link gets markers via OSC 8",
body: "see " + osc8("url.md", "hello") + " rest",
infos: []links.LinkInfo{
{Dest: "url.md", Text: "hello"},
},
check: func(t *testing.T, result string) {
startM := string(markerStart(0))
endM := string(markerEnd(0))
want := "see " + startM + "hello" + endM + " rest"
if result != want {
t.Errorf("got %q, want %q", result, want)
if !strings.Contains(result, string(markerStart(0))) {
t.Error("missing start marker")
}
if !strings.Contains(result, string(markerEnd(0))) {
t.Error("missing end marker")
}
},
},
{
name: "multiple links get unique markers",
body: "first and second end",
body: osc8("a.md", "first") + " and " + osc8("b.md", "second") + " end",
infos: []links.LinkInfo{
{Dest: "a.md", Text: "first"},
{Dest: "b.md", Text: "second"},
Expand All @@ -62,17 +67,19 @@ func TestInjectLinkMarkers(t *testing.T) {
},
},
{
name: "skips ANSI codes when matching",
body: "pre \x1b[35mhello\x1b[0m post",
name: "matches link not preceding plain text with same word",
body: "Hubs link to servers. " + osc8("hubs.md", "Hubs") + " list",
infos: []links.LinkInfo{
{Dest: "url.md", Text: "hello"},
{Dest: "hubs.md", Text: "Hubs"},
},
check: func(t *testing.T, result string) {
// Marker should be inside the OSC 8 region, not on the plain "Hubs".
if !strings.Contains(result, string(markerStart(0))) {
t.Error("missing start marker")
}
if !strings.Contains(result, string(markerEnd(0))) {
t.Error("missing end marker")
// The plain "Hubs" at position 0 should NOT have a marker before it.
if strings.HasPrefix(result, string(markerStart(0))) {
t.Error("marker incorrectly placed on plain text instead of hyperlink")
}
},
},
Expand Down Expand Up @@ -143,6 +150,20 @@ func TestFindVisibleText(t *testing.T) {
wantStart: -1,
wantEnd: -1,
},
{
name: "skips OSC 8 hyperlink with BEL terminator",
runes: "pre \x1b]8;;http://example.com\x07hello\x1b]8;;\x07 post",
text: "hello",
wantStart: 28,
wantEnd: 33,
},
{
name: "skips OSC 8 hyperlink with ST terminator",
runes: "pre \x1b]8;;http://example.com\x1b\\hello\x1b]8;;\x1b\\ post",
text: "hello",
wantStart: 29,
wantEnd: 34,
},
}

for _, tt := range tests {
Expand Down
Loading
Loading