From 5c0038d0282e60572f3f2abd65eb521cb39dff95 Mon Sep 17 00:00:00 2001 From: Levi Neely <141506390+lneely@users.noreply.github.com> Date: Thu, 27 Nov 2025 13:31:09 +0100 Subject: [PATCH] support compound extensions --- internal/disk/callbacks.go | 15 +++++++++++++-- internal/disk/loader.go | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/internal/disk/callbacks.go b/internal/disk/callbacks.go index c74baf1..99da015 100644 --- a/internal/disk/callbacks.go +++ b/internal/disk/callbacks.go @@ -43,7 +43,7 @@ func HandleUpdateEvent(f *client.Fsys, identifier, denoteDir string) error { if dir == "." { dir = denoteDir } - ext := filepath.Ext(path) + ext := GetFullExtension(path) var fileType metadata.FileType var fm *metadata.FrontMatter @@ -64,7 +64,18 @@ func HandleUpdateEvent(f *client.Fsys, identifier, denoteDir string) error { fm = existing fileType = ftype - ext = metadata.GetExtension(fileType) + + // Preserve compound extensions (e.g., .md.gpg) + // Replace content extension but keep wrapper layers + contentExt := GetContentExtension(path) + typeExt := metadata.GetExtension(fileType) + if contentExt != ext { + // Compound extension: replace content part with type extension + ext = strings.Replace(ext, contentExt, typeExt, 1) + } else { + // Simple extension: use type extension + ext = typeExt + } } else { // For binary files, build metadata from 9P data fm = &metadata.FrontMatter{ diff --git a/internal/disk/loader.go b/internal/disk/loader.go index d8119ea..bda0127 100644 --- a/internal/disk/loader.go +++ b/internal/disk/loader.go @@ -11,9 +11,43 @@ import ( "strings" ) +// GetFullExtension returns the full extension, including compound extensions. +// For example: "file.md.gpg" returns ".md.gpg", "file.tar.gz" returns ".tar.gz" +func GetFullExtension(path string) string { + ext := filepath.Ext(path) + if ext == "" { + return "" + } + + // Check if there's another extension before this one + pathWithoutExt := strings.TrimSuffix(path, ext) + innerExt := filepath.Ext(pathWithoutExt) + + if innerExt != "" { + // Compound extension found, return both parts + return innerExt + ext + } + + return ext +} + +// GetContentExtension returns the content type extension, stripping encryption/compression layers. +// For example: "file.md.gpg" returns ".md", "file.tar.gz" returns ".tar", "file.md" returns ".md" +func GetContentExtension(path string) string { + fullExt := GetFullExtension(path) + + // For compound extensions, take the first part + parts := strings.Split(fullExt, ".") + if len(parts) >= 3 { // ["", "md", "gpg"] for ".md.gpg" + return "." + parts[1] + } + + return fullExt +} + // SupportsFrontMatter returns true if the file extension supports frontmatter. func SupportsFrontMatter(path string) bool { - ext := strings.ToLower(filepath.Ext(path)) + ext := strings.ToLower(GetContentExtension(path)) return ext == ".org" || ext == ".md" || ext == ".txt" }