feat: use glow renderer
This commit is contained in:
123
cmd/list.go
123
cmd/list.go
@@ -4,9 +4,11 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/yeho/doks/internal/registry"
|
||||
"github.com/yeho/doks/internal/tui"
|
||||
)
|
||||
|
||||
var listTagFilter string
|
||||
@@ -24,7 +26,7 @@ var listCmd = &cobra.Command{
|
||||
|
||||
entries := reg.List()
|
||||
if len(entries) == 0 {
|
||||
fmt.Println("No documents registered")
|
||||
fmt.Println(tui.NoResultsStyle.Render("No documents registered"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -45,24 +47,19 @@ var listCmd = &cobra.Command{
|
||||
}
|
||||
|
||||
if len(entries) == 0 {
|
||||
fmt.Printf("No documents found with tag '%s'\n", listTagFilter)
|
||||
fmt.Printf(tui.NoResultsStyle.Render("No documents found with tag '%s'\n"), listTagFilter)
|
||||
return
|
||||
}
|
||||
|
||||
// Print section header
|
||||
fmt.Println(tui.ListTitleStyle.Render("📚 Registered Documents"))
|
||||
fmt.Println(tui.CountStyle.Render(fmt.Sprintf("(%d document%s total)", len(entries), plural(len(entries)))))
|
||||
fmt.Println()
|
||||
|
||||
// Print entries
|
||||
for _, entry := range entries {
|
||||
symlink := ""
|
||||
if entry.HasSymlink {
|
||||
symlink = " [symlinked]"
|
||||
}
|
||||
tags := ""
|
||||
if len(entry.Tags) > 0 {
|
||||
tags = fmt.Sprintf(" [%s]", joinStrings(entry.Tags, ", "))
|
||||
}
|
||||
fmt.Printf(" %s%s%s\n", entry.Key, tags, symlink)
|
||||
if entry.Description != "" {
|
||||
fmt.Printf(" %s\n", entry.Description)
|
||||
}
|
||||
printEntry(entry)
|
||||
fmt.Println()
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -81,13 +78,97 @@ func hasTag(tags []string, target string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func joinStrings(strs []string, sep string) string {
|
||||
if len(strs) == 0 {
|
||||
func plural(n int) string {
|
||||
if n == 1 {
|
||||
return ""
|
||||
}
|
||||
result := strs[0]
|
||||
for i := 1; i < len(strs); i++ {
|
||||
result += sep + strs[i]
|
||||
}
|
||||
return result
|
||||
return "s"
|
||||
}
|
||||
|
||||
func printEntry(entry *registry.Entry) {
|
||||
// Entry key
|
||||
fmt.Print(tui.SymlinkIcon)
|
||||
|
||||
if entry.HasSymlink {
|
||||
fmt.Print(tui.EntryKeyStyle.Render(entry.Key))
|
||||
fmt.Print(" ")
|
||||
fmt.Print(tui.SymlinkIndicator)
|
||||
} else {
|
||||
fmt.Print(tui.EntryKeyStyle.Render(entry.Key))
|
||||
}
|
||||
|
||||
// Filename
|
||||
fmt.Print(" ")
|
||||
fmt.Print(tui.FilenameStyle.Render(entry.Filename))
|
||||
|
||||
// Tags
|
||||
if len(entry.Tags) > 0 {
|
||||
tagsStr := ""
|
||||
for i, tag := range entry.Tags {
|
||||
if i > 0 {
|
||||
tagsStr += ", "
|
||||
}
|
||||
tagsStr += tui.TagsStyle.Render(tag)
|
||||
}
|
||||
fmt.Print(" ")
|
||||
fmt.Print(tagsStr)
|
||||
}
|
||||
|
||||
// Status indicator
|
||||
if entry.HasSymlink {
|
||||
fmt.Print(" ")
|
||||
fmt.Print(tui.TagsStyle.Render("[symlinked]"))
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
|
||||
// Description
|
||||
if entry.Description != "" {
|
||||
fmt.Println(tui.DescriptionStyle.Render(entry.Description))
|
||||
}
|
||||
|
||||
// Metadata
|
||||
if entry.CreatedAt.IsZero() && entry.UpdatedAt.IsZero() {
|
||||
return
|
||||
}
|
||||
|
||||
var createdStr, updatedStr string
|
||||
if !entry.CreatedAt.IsZero() {
|
||||
createdStr = fmt.Sprintf("Created: %s", formatTime(entry.CreatedAt))
|
||||
}
|
||||
if !entry.UpdatedAt.IsZero() {
|
||||
updatedStr = fmt.Sprintf("Updated: %s", formatTime(entry.UpdatedAt))
|
||||
}
|
||||
|
||||
var metaStr string
|
||||
if createdStr != "" && updatedStr != "" {
|
||||
metaStr = createdStr + " • " + updatedStr
|
||||
} else {
|
||||
metaStr = createdStr + updatedStr
|
||||
}
|
||||
if metaStr != "" {
|
||||
fmt.Println(tui.MetadataStyle.Render(metaStr))
|
||||
}
|
||||
}
|
||||
|
||||
func formatTime(t time.Time) string {
|
||||
now := time.Now()
|
||||
diff := now.Sub(t)
|
||||
|
||||
switch {
|
||||
case diff.Seconds() < 60:
|
||||
return "just now"
|
||||
case diff.Hours() < 24:
|
||||
return fmt.Sprintf("%.0f hours ago", diff.Hours())
|
||||
case diff.Hours() < 48:
|
||||
return "yesterday"
|
||||
case diff.Hours() < 7*24:
|
||||
return fmt.Sprintf("%.0f days ago", diff.Hours()/24)
|
||||
case diff.Hours() < 30*24:
|
||||
return fmt.Sprintf("%.0f weeks ago", diff.Hours()/(7*24))
|
||||
case diff.Hours() < 365*24:
|
||||
return fmt.Sprintf("%.0f months ago", diff.Hours()/(30*24))
|
||||
default:
|
||||
return t.Format("Jan 2, 2006")
|
||||
}
|
||||
}
|
||||
24
cmd/root.go
24
cmd/root.go
@@ -156,7 +156,17 @@ func showResult(result *search.Result) {
|
||||
}
|
||||
|
||||
func displayFile(filePath string, highlightLine int) {
|
||||
// Try bat first for syntax highlighting
|
||||
// Try glow first for Markdown rendering
|
||||
if glowPath, err := exec.LookPath("glow"); err == nil {
|
||||
cmd := exec.Command(glowPath, filePath)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err == nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to bat for syntax highlighting
|
||||
if batPath, err := exec.LookPath("bat"); err == nil {
|
||||
args := []string{
|
||||
"--paging=never",
|
||||
@@ -175,7 +185,17 @@ func displayFile(filePath string, highlightLine int) {
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to plain output
|
||||
// Fallback to cat
|
||||
if catPath, err := exec.LookPath("cat"); err == nil {
|
||||
cmd := exec.Command(catPath, filePath)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err == nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Final fallback to plain Go file read
|
||||
content, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error reading file: %v\n", err)
|
||||
|
||||
@@ -48,4 +48,40 @@ var (
|
||||
Foreground(secondaryColor).
|
||||
Italic(true).
|
||||
MarginTop(1)
|
||||
|
||||
// List command styles
|
||||
ListTitleStyle = lipgloss.NewStyle().
|
||||
Bold(true).
|
||||
Foreground(lipgloss.Color("213")). // Magenta/pink
|
||||
MarginBottom(1)
|
||||
|
||||
CountStyle = lipgloss.NewStyle().
|
||||
Foreground(lipgloss.Color("244")). // Dimmed gray
|
||||
Italic(true)
|
||||
|
||||
EntryKeyStyle = lipgloss.NewStyle().
|
||||
Bold(true).
|
||||
Foreground(lipgloss.Color("154")) // Bright green
|
||||
|
||||
EntryKeySelected = lipgloss.NewStyle().
|
||||
Bold(true).
|
||||
Foreground(lipgloss.Color("86")) // Cyan
|
||||
|
||||
FilenameStyle = lipgloss.NewStyle().
|
||||
Foreground(lipgloss.Color("241")) // Gray
|
||||
|
||||
TagsStyle = lipgloss.NewStyle().
|
||||
Foreground(lipgloss.Color("226")) // Yellow
|
||||
|
||||
SymlinkIcon = "➜ "
|
||||
|
||||
SymlinkIndicator = "🔗"
|
||||
|
||||
DescriptionStyle = lipgloss.NewStyle().
|
||||
Foreground(lipgloss.Color("243")). // Dimmed text
|
||||
PaddingLeft(2)
|
||||
|
||||
MetadataStyle = lipgloss.NewStyle().
|
||||
Foreground(lipgloss.Color("245")). // Dimmed gray
|
||||
PaddingLeft(4)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user