package gophermap import ( "bufio" "net/url" "os" "path" "path/filepath" "slices" "strings" "tildegit.org/tjp/sliderule/gopher" "tildegit.org/tjp/sliderule/internal/types" ) // ListDir builds a gopher menu representing the contents of a directory. func ListDir(dir string, location *url.URL, settings FileSystemSettings) (gopher.MapDocument, error) { return listDir(dir, location, settings, nil, nil) } func listDir(dir string, location *url.URL, settings FileSystemSettings, hidden map[string]struct{}, extensions map[string]types.Status) (gopher.MapDocument, error) { contents, err := os.ReadDir(dir) if err != nil { return nil, err } doc := gopher.MapDocument{} for _, entry := range contents { name := entry.Name() inf, err := entry.Info() if err != nil { return nil, err } if inf.Mode()&4 == 0 { continue } if _, ok := hidden[name]; ok || slices.Contains(settings.DirMaps, name) { continue } var code types.Status if entry.IsDir() { code = gopher.MenuType } else { ext := strings.TrimPrefix(filepath.Ext(name), ".") if c, ok := extensions[ext]; ok { code = c } else if c, ok := extensions[name]; ok { code = c } else { code = gopher.GuessItemType(name) } } doc = append(doc, gopher.MapItem{ Type: code, Display: displayName(dir, entry, settings), Selector: path.Join(path.Dir(location.Path), name), Hostname: location.Hostname(), Port: location.Port(), }) } return doc, nil } func displayName(dir string, entry os.DirEntry, settings FileSystemSettings) string { fname := entry.Name() fullpath := filepath.Join(dir, fname) if entry.Type().IsRegular() && settings.ParseExtended && (strings.HasSuffix(fname, ".gophermap") || slices.Contains(settings.DirMaps, fname)) { if title := gophermapTitle(fullpath); title != "" { return title } } if entry.IsDir() { if settings.DirTag != "" { if tag := tagTitle(filepath.Join(fullpath, settings.DirTag)); tag != "" { return tag } } if settings.ParseExtended { for _, mapname := range settings.DirMaps { if title := gophermapTitle(filepath.Join(fullpath, mapname)); title != "" { return title } } } } return fname } func gophermapTitle(path string) string { file, err := os.Open(path) if err != nil { return "" } defer func() { _ = file.Close() }() rdr := bufio.NewReader(file) line, err := rdr.ReadString('\n') if err != nil { return "" } if !strings.HasPrefix(line, "!") { return "" } return strings.TrimRight(line[1:], "\r\n") } func tagTitle(path string) string { file, err := os.Open(path) if err != nil { return "" } defer func() { _ = file.Close() }() stat, err := file.Stat() if err != nil || stat.IsDir() { return "" } rdr := bufio.NewReader(file) line, err := rdr.ReadString('\n') if err != nil { return "" } return strings.TrimRight(line, "\r\n") }