viewer open image files

This commit is contained in:
booleanmaybe 2026-03-24 23:38:39 -04:00
parent 0fa71de797
commit 6317bbdb30
4 changed files with 68 additions and 2 deletions

View file

@ -9,6 +9,22 @@ import (
"strings"
)
var imageExtensions = map[string]bool{
".png": true,
".jpg": true,
".jpeg": true,
".gif": true,
".bmp": true,
".tiff": true,
".tif": true,
".webp": true,
".svg": true,
}
func isImageFile(path string) bool {
return imageExtensions[strings.ToLower(filepath.Ext(path))]
}
// viewer input parsing: decides whether to run the markdown viewer and resolves a
// single positional argument into candidate sources. accepted inputs: "-" for
// stdin, file paths, http(s) urls, and github/gitlab repo or file links.
@ -22,6 +38,7 @@ const (
InputURL InputKind = "url"
InputGitHub InputKind = "github"
InputGitLab InputKind = "gitlab"
InputImage InputKind = "image"
)
// InputSpec carries the resolved input plus candidate URLs/paths to try.
@ -142,8 +159,13 @@ func buildInputSpec(raw string) (InputSpec, error) {
return InputSpec{}, fmt.Errorf("resolve file path: %w", err)
}
kind := InputFile
if isImageFile(raw) {
kind = InputImage
}
return InputSpec{
Kind: InputFile,
Kind: kind,
Raw: raw,
Candidates: []string{absPath},
SearchRoots: []string{filepath.Dir(absPath)},

View file

@ -140,6 +140,44 @@ func TestParseViewerInputInitReserved(t *testing.T) {
}
}
func TestIsImageFile(t *testing.T) {
for _, name := range []string{"photo.png", "photo.jpg", "photo.jpeg", "photo.gif", "photo.bmp", "photo.tiff", "photo.tif", "photo.webp", "photo.svg"} {
if !isImageFile(name) {
t.Errorf("expected %q to be detected as image", name)
}
}
for _, name := range []string{"PHOTO.PNG", "Photo.Jpg", "image.SVG"} {
if !isImageFile(name) {
t.Errorf("expected %q (mixed case) to be detected as image", name)
}
}
for _, name := range []string{"readme.md", "main.go", "data.json", "file.txt", "noext"} {
if isImageFile(name) {
t.Errorf("expected %q to NOT be detected as image", name)
}
}
}
func TestParseViewerInputImageFile(t *testing.T) {
spec, ok, err := ParseViewerInput([]string{"photo.png"}, map[string]struct{}{})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !ok {
t.Fatalf("expected viewer mode")
}
if spec.Kind != InputImage {
t.Fatalf("expected image input, got %s", spec.Kind)
}
abs, err := filepath.Abs("photo.png")
if err != nil {
t.Fatalf("abs path error: %v", err)
}
if len(spec.Candidates) != 1 || spec.Candidates[0] != abs {
t.Fatalf("unexpected candidates: %v", spec.Candidates)
}
}
func TestParseViewerInputUnknownFlag(t *testing.T) {
_, ok, err := ParseViewerInput([]string{"--verson"}, map[string]struct{}{})
if !errors.Is(err, ErrUnknownFlag) {

View file

@ -127,6 +127,12 @@ func loadInitialContent(input InputSpec, provider *loaders.FileHTTP) (string, st
return "", "", fmt.Errorf("no input candidates provided")
}
// image files: wrap in synthetic markdown so the image pipeline renders them
if input.Kind == InputImage || (input.Kind == InputURL && isImageFile(input.Raw)) {
src := input.Candidates[0]
return fmt.Sprintf("![%s](%s)\n", filepath.Base(src), src), src, nil
}
var lastErr error
for _, candidate := range input.Candidates {
content, err := provider.FetchContent(nav.NavElement{URL: candidate})

View file

@ -138,7 +138,7 @@ func printUsage() {
Usage:
tiki Launch TUI in initialized repo
tiki init Initialize project in current git repo
tiki file.md/URL View markdown file
tiki file.md/URL View markdown file or image
echo "Title" | tiki Create task from piped input
tiki sysinfo Display system information
tiki --version Show version