github.com/jmigpin/editor@v1.6.0/core/listdir.go (about)

     1  package core
     2  
     3  import (
     4  	"context"
     5  	"io"
     6  	"os"
     7  	"path/filepath"
     8  	"sort"
     9  	"strings"
    10  
    11  	"github.com/jmigpin/editor/util/parseutil"
    12  )
    13  
    14  func ListDirERow(erow *ERow, filepath string, tree, hidden bool) {
    15  	erow.Exec.RunAsync(func(ctx context.Context, rw io.ReadWriter) error {
    16  		return ListDirContext(ctx, rw, erow.Info.Name(), tree, hidden)
    17  	})
    18  }
    19  
    20  //----------
    21  
    22  func ListDirContext(ctx context.Context, w io.Writer, filepath string, tree, hidden bool) error {
    23  	// "../" at the top
    24  	u := ".." + string(os.PathSeparator)
    25  	if _, err := w.Write([]byte(u + "\n")); err != nil {
    26  		return err
    27  	}
    28  
    29  	return listDirContext(ctx, w, filepath, "", tree, hidden)
    30  }
    31  
    32  func listDirContext(ctx context.Context, w io.Writer, fpath, addedFilepath string, tree, hidden bool) error {
    33  	fp2 := filepath.Join(fpath, addedFilepath)
    34  
    35  	out := func(s string) bool {
    36  		_, err := w.Write([]byte(s))
    37  		return err == nil
    38  	}
    39  
    40  	f, err := os.Open(fp2)
    41  	if err != nil {
    42  		out(err.Error())
    43  		return nil
    44  	}
    45  
    46  	fis, err := f.Readdir(-1)
    47  	f.Close() // close as soon as possible
    48  	if err != nil {
    49  		out(err.Error())
    50  		return nil
    51  	}
    52  
    53  	// stop on context
    54  	if ctx.Err() != nil {
    55  		return ctx.Err()
    56  	}
    57  
    58  	sort.Sort(ByListOrder(fis))
    59  
    60  	for _, fi := range fis {
    61  		// stop on context
    62  		if ctx.Err() != nil {
    63  			return ctx.Err()
    64  		}
    65  
    66  		name := fi.Name()
    67  
    68  		if !hidden && strings.HasPrefix(name, ".") {
    69  			continue
    70  		}
    71  
    72  		name2 := filepath.Join(addedFilepath, name)
    73  		if fi.IsDir() {
    74  			name2 += string(os.PathSeparator)
    75  		}
    76  		s := parseutil.EscapeFilename(name2) + "\n"
    77  		if !out(s) {
    78  			return nil
    79  		}
    80  
    81  		if fi.IsDir() && tree {
    82  			afp := filepath.Join(addedFilepath, name)
    83  			err := listDirContext(ctx, w, fpath, afp, tree, hidden)
    84  			if err != nil {
    85  				return err
    86  			}
    87  		}
    88  	}
    89  	return nil
    90  }
    91  
    92  //----------
    93  
    94  type ByListOrder []os.FileInfo
    95  
    96  func (a ByListOrder) Len() int {
    97  	return len(a)
    98  }
    99  func (a ByListOrder) Swap(i, j int) {
   100  	a[i], a[j] = a[j], a[i]
   101  }
   102  func (a ByListOrder) Less(i, j int) bool {
   103  	ei := a[i]
   104  	ej := a[j]
   105  	iname := strings.ToLower(ei.Name())
   106  	jname := strings.ToLower(ej.Name())
   107  	if ei.IsDir() && ej.IsDir() {
   108  		return iname < jname
   109  	}
   110  	if ei.IsDir() {
   111  		return true
   112  	}
   113  	if ej.IsDir() {
   114  		return false
   115  	}
   116  	return iname < jname
   117  }