diff --git a/VERSION b/VERSION index 18fa8e7..7574079 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v1.3.0 +v1.3.1 diff --git a/cmd/book/main.go b/cmd/book/main.go index a188a7c..5d705c6 100644 --- a/cmd/book/main.go +++ b/cmd/book/main.go @@ -388,7 +388,7 @@ func Main() { Before: func(ctx context.Context, c *cli.Command) (context.Context, error) { if c.Args().First() != "" && markURL != "" { return ctx, cli.Exit(config.StyledError( - fmt.Errorf("cannot pass URL as both --url and a positional argument")), 1) + fmt.Errorf("cannot pass url as both --url and a positional argument")), 1) } // use positional argument to populate markURL if flag not used @@ -397,7 +397,7 @@ func Main() { } if markURL == "" { return ctx, cli.Exit(config.StyledError( - fmt.Errorf("must pass URL as --url or argument")), 1) + fmt.Errorf("must pass url as --url or argument")), 1) } return ctx, nil }, diff --git a/cmd/book/mark.go b/cmd/book/mark.go index 7bcaee9..6137b8f 100644 --- a/cmd/book/mark.go +++ b/cmd/book/mark.go @@ -51,10 +51,7 @@ func marks(bs *book.BookShelves, shelfName string, collectionName string, format } switch format { case "toml": - wrapped := struct { - Marks []catalog.SearchResult `toml:"marks"` - }{deleted} - return book.PrintCatalog(wrapped, format) + return book.PrintCatalog(catalog.SearchResultList{Marks: deleted}, format) case "json": return book.PrintCatalog(deleted, format) default: @@ -111,7 +108,7 @@ func editMark(bs *book.BookShelves, id, title, tags, url string, config *book.Co return err } if err := bs.VerifyUniqueURL(book.GenerateID(url), target); err != nil { - return err + return fmt.Errorf("verify unique url: %w", err) } } @@ -142,11 +139,7 @@ func searchMarks(query string, tags string, shelfName string, collectionName str case "json": return book.PrintCatalog(results, format) case "toml": - // TOML requires a top-level map or struct, so wrap the slice. - wrapped := struct { - Marks []catalog.SearchResult `toml:"marks"` - }{results} - return book.PrintCatalog(wrapped, format) + return book.PrintCatalog(catalog.SearchResultList{Marks: results}, format) default: for _, r := range results { fmt.Printf("%s %s\n", r.Title, r.URL) @@ -163,7 +156,7 @@ func addMark(bs *book.BookShelves, URL string, tags string, shelfName string, co // Ensure URL hash not in bookshelves if err := bs.VerifyUniqueURL(mark.ID, nil); err != nil { - return err + return fmt.Errorf("verify unique url: %w", err) } // Use provided title or fetch from URL @@ -172,7 +165,7 @@ func addMark(bs *book.BookShelves, URL string, tags string, shelfName string, co fetchedTitle, err := web.LoadWebsite(mark.URL) if err != nil { if !errors.Is(err, web.ErrTitleUnavailable) { - return err + return fmt.Errorf("load website: %w", err) } fetched.Unavailable = true } else { diff --git a/internal/book/templates.go b/internal/book/templates.go index bea7a12..908284c 100644 --- a/internal/book/templates.go +++ b/internal/book/templates.go @@ -96,33 +96,3 @@ var DefaultViewTemplates = map[string]ViewTemplate{ "mark-get": markTemplate("To open mark:"), "mark-delete": markTemplate("To delete mark:"), } - -// UserViewTemplates holds user-defined template overrides loaded at runtime. -var UserViewTemplates = map[string]ViewTemplate{} - -// GetTemplate merges user overrides over the default for a given key. -func GetTemplate(key string) ViewTemplate { - def, hasDef := DefaultViewTemplates[key] - user, hasUser := UserViewTemplates[key] - - switch { - case !hasDef && !hasUser: - return ViewTemplate{} - case !hasUser: - return def - case !hasDef: - return user - } - - // Overlay: user field non-empty → override default. - if user.PrimaryTitle != "" { - def.PrimaryTitle = user.PrimaryTitle - } - if user.SecondaryTitle != "" { - def.SecondaryTitle = user.SecondaryTitle - } - if user.ListTitle != "" { - def.ListTitle = user.ListTitle - } - return def -} diff --git a/internal/book/types.go b/internal/book/types.go index 75bbb91..f43e9f6 100644 --- a/internal/book/types.go +++ b/internal/book/types.go @@ -177,10 +177,10 @@ func (bs *BookShelves) VerifyUniqueURL(id string, exclude *Mark) error { continue } if m.IsDeleted() { - return fmt.Errorf("URL already trashed!\n\n%s\n\nrestore it with:\nbook mark restore --shelf %s --collection %s --url %s", + return fmt.Errorf("url already trashed\n\n%s\n\nrestore it with:\nbook mark restore --shelf %s --collection %s --url %s", m.FullDetail(), m.Shelf.Name, m.Collection.Name, m.URL) } - return fmt.Errorf("duplicate URL Found!\n\n%s", m.FullDetail()) + return fmt.Errorf("duplicate url found\n\n%s", m.FullDetail()) } } } @@ -582,10 +582,10 @@ func ResolveMarkTitle(providedTitle, url string, fetched TitleFetchResult, inter // ValidateNewShelfName returns an error if name is empty or already in use. func (bs *BookShelves) ValidateNewShelfName(name string) error { if name == "" { - return fmt.Errorf("HARD requirement") + return fmt.Errorf("shelf name is required") } if slices.Contains(bs.ShelfNames(), name) { - return fmt.Errorf("womp womp, shelf already exists") + return fmt.Errorf("shelf already exists") } return nil } diff --git a/internal/catalog/index.go b/internal/catalog/index.go index b5bad44..23f589b 100644 --- a/internal/catalog/index.go +++ b/internal/catalog/index.go @@ -417,6 +417,12 @@ type SearchResult struct { Tags []string `json:"tags" toml:"tags"` } +// SearchResultList wraps a slice of search results so it can be serialized as +// TOML, which requires a top-level map or struct. +type SearchResultList struct { + Marks []SearchResult `toml:"marks" json:"marks"` +} + // Search runs an FTS5 query over mark titles and URLs, excluding soft-deleted // marks. The query string uses FTS5 match syntax and may be empty to search by // filters alone. tagClauses filters results to marks matching every clause