Files
oddmu/missing_cmd.go
Alex Schroeder f99a092d8c Missing subcommand accepts other files
Files that don't have a .md extension are legitimate link targets.
2023-10-05 09:36:02 +02:00

103 lines
2.5 KiB
Go

package main
import (
"context"
"flag"
"fmt"
"io/fs"
"path/filepath"
"github.com/google/subcommands"
"github.com/gomarkdown/markdown"
"github.com/gomarkdown/markdown/ast"
"io"
"net/url"
"os"
"strings"
)
type missingCmd struct {
}
func (*missingCmd) Name() string { return "missing" }
func (*missingCmd) Synopsis() string { return "Listing the missing pages." }
func (*missingCmd) Usage() string {
return `missing:
Listing pages with links to missing pages.
`
}
func (cmd *missingCmd) SetFlags(f *flag.FlagSet) {
}
func (cmd *missingCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
return missingCli(os.Stdout, f.Args())
}
func missingCli(w io.Writer, args []string) subcommands.ExitStatus {
names := make(map[string]bool);
err := filepath.Walk(".", func(path string, info fs.FileInfo, err error) error {
if err != nil {
return err
}
filename := path
if info.IsDir() || strings.HasPrefix(filename, ".") {
return nil
}
if strings.HasSuffix(filename, ".md") {
name := strings.TrimSuffix(filename, ".md")
names[name] = true
} else {
names[filename] = false
}
return nil
})
if err != nil {
fmt.Println(err)
return subcommands.ExitFailure
}
fmt.Println("Page\tMissing")
for name, isPage := range names {
if !isPage {
continue
}
p, err := loadPage(name)
if err != nil {
fmt.Printf("Loading %s: %s\n", name, err)
return subcommands.ExitFailure
}
for _, link := range p.links() {
if !strings.HasPrefix(link, "/") &&
!strings.HasPrefix(link, "http:") &&
!strings.HasPrefix(link, "https:") &&
!strings.HasPrefix(link, "mailto:") &&
!strings.HasPrefix(link, "gopher:") &&
!strings.HasPrefix(link, "gemini:") {
destination, err := url.PathUnescape(link)
if err != nil {
fmt.Printf("Cannot decode %s: %s\n", link, err)
return subcommands.ExitFailure
}
_, ok := names[destination]
if !ok {
fmt.Printf("%s\t%s\n", name, link)
}
}
}
}
return subcommands.ExitSuccess
}
func (p *Page) links() []string {
var links []string
parser, _ := wikiParser()
doc := markdown.Parse(p.Body, parser)
ast.WalkFunc(doc, func(node ast.Node, entering bool) ast.WalkStatus {
switch v := node.(type) {
case *ast.Link:
links = append(links, string(v.Destination))
}
return ast.GoToNext
})
return links
}