diff --git a/internal/cli/g.go b/internal/cli/g.go index aea709d..4be0d66 100644 --- a/internal/cli/g.go +++ b/internal/cli/g.go @@ -58,6 +58,8 @@ var ( groupEnabler = contents.NewGroupEnabler() gitEnabler = contents.NewGitEnabler() gitRepoEnabler = contents.NewGitRepoEnabler() + nameToDisplay = contents.NewNameEnabler() + flagsEnabler = contents.NewFlagsEnabler() depthLimitMap map[string]int limitOnce = util.Once{} hookOnce = util.Once{} @@ -503,7 +505,6 @@ var logic = func(context *cli.Context) error { path := context.Args().Slice() - nameToDisplay := contents.NewNameEnable() if !context.Bool("no-icon") && (context.Bool("icon") || context.Bool("all")) { nameToDisplay.SetIcon() } @@ -531,6 +532,10 @@ var logic = func(context *cli.Context) error { contentFunc = append(contentFunc, gitRepoEnabler.EnableStatus(r)) } + if context.Bool("flags") { + contentFunc = append(contentFunc, flagsEnabler.Enable()) + } + if context.Bool("no-dereference") { nameToDisplay.SetNoDeference() } @@ -588,20 +593,11 @@ var logic = func(context *cli.Context) error { if gitignore { itemFilter.AppendTo(removeGitIgnore) } - - // set sort func - if sort.Len() == 0 { - sort.AddOption(sorter.Default) - } - contentFilter.SetSortFunc(sort.Build()) - contentFilter.SetOptions(contentFunc...) - contentFilter.SetNoOutputOptions(noOutputFunc...) - // if no path, use the current path if len(path) == 0 { path = append(path, ".") } - contentFilter.SetOptions(contentFunc...) + depth := context.Int("depth") // flag: if d is set, display directory them self @@ -689,6 +685,13 @@ var logic = func(context *cli.Context) error { path = newPath } + // set sort func + if sort.Len() == 0 { + sort.AddOption(sorter.Default) + } + contentFilter.SetSortFunc(sort.Build()) + contentFilter.SetOptions(contentFunc...) + contentFilter.SetNoOutputOptions(noOutputFunc...) for i := 0; i < len(path); i++ { start := time.Now() diff --git a/internal/cli/view.go b/internal/cli/view.go index d357734..6711bd1 100644 --- a/internal/cli/view.go +++ b/internal/cli/view.go @@ -831,6 +831,12 @@ var viewFlag = []cli.Flag{ DisableDefaultText: true, Category: "VIEW", }, + &cli.BoolFlag{ + Name: "flags", + Usage: "list file flags[macOS only]", + DisableDefaultText: true, + Category: "VIEW", + }, } func setLimit(context *cli.Context) error { diff --git a/internal/content/flags.go b/internal/content/flags.go new file mode 100644 index 0000000..e9dd987 --- /dev/null +++ b/internal/content/flags.go @@ -0,0 +1,31 @@ +package content + +import ( + "strings" + + "github.com/Equationzhao/g/internal/align" + constval "github.com/Equationzhao/g/internal/global" + "github.com/Equationzhao/g/internal/item" + "github.com/Equationzhao/g/internal/osbased" +) + +type FlagsEnabler struct{} + +func NewFlagsEnabler() *FlagsEnabler { + return &FlagsEnabler{} +} + +const ( + Flags = constval.NameOfFlags +) + +func (f FlagsEnabler) Enable() ContentOption { + align.Register(Flags) + return func(info *item.FileInfo) (string, string) { + flags := osbased.CheckFlags(info) + if len(flags) == 0 { + return "-", Flags + } + return strings.Join(flags, ","), Flags + } +} diff --git a/internal/content/name.go b/internal/content/name.go index 12825bb..f8f6a07 100644 --- a/internal/content/name.go +++ b/internal/content/name.go @@ -184,7 +184,7 @@ func (n *Name) UnsetMounts() *Name { return n } -func NewNameEnable() *Name { +func NewNameEnabler() *Name { return &Name{} } diff --git a/internal/global/const.go b/internal/global/const.go index 5dca23a..de411e8 100644 --- a/internal/global/const.go +++ b/internal/global/const.go @@ -78,4 +78,5 @@ const ( NameOfTimeCreated = "Created" NameOfTimeAccessed = "Accessed" NameOfTimeBirth = "Birth" + NameOfFlags = "Flags" ) diff --git a/internal/osbased/flags_darwin.go b/internal/osbased/flags_darwin.go new file mode 100644 index 0000000..d659b22 --- /dev/null +++ b/internal/osbased/flags_darwin.go @@ -0,0 +1,62 @@ +package osbased + +import ( + "os" + "slices" + "syscall" + + "github.com/Equationzhao/g/internal/item" + "golang.org/x/sys/unix" +) + +var flags = map[int]string{ + unix.UF_APPEND: "uappnd", + unix.UF_COMPRESSED: "compressed", + unix.UF_HIDDEN: "hidden", + unix.UF_IMMUTABLE: "uchg", + unix.UF_NODUMP: "nodump", + unix.UF_OPAQUE: "opaque", + + // unix.UF_SETTABLE: "UF_SETTABLE", + // unix.UF_TRACKED: "UF_TRACKED", + // unix.UF_DATAVAULT: "UF_DATAVAULT", + + unix.SF_APPEND: "sappnd", + unix.SF_ARCHIVED: "arch", + unix.SF_DATALESS: "dataless", + unix.SF_IMMUTABLE: "schg", + unix.SF_RESTRICTED: "restricted", + + // unix.SF_SETTABLE: "SF_SETTABLE", + // unix.SF_SUPPORTED: "SF_SUPPORTED", + // unix.SF_SYNTHETIC: "SF_SYNTHETIC", + // unix.SF_FIRMLINK: "SF_FIRMLINK", +} + +func getFlags(filename string) uint32 { + file, err := os.Open(filename) + if err != nil { + return 0 + } + defer file.Close() + + fileInfo, err := file.Stat() + if err != nil { + return 0 + } + + stat := fileInfo.Sys().(*syscall.Stat_t) + return stat.Flags +} + +func CheckFlags(i *item.FileInfo) []string { + res := make([]string, 0, 8) + f := getFlags(i.FullPath) + for key, val := range flags { + if f&uint32(key) != 0 { + res = append(res, val) + } + } + slices.Sort(res) + return res +} diff --git a/internal/osbased/flags_linux.go b/internal/osbased/flags_linux.go new file mode 100644 index 0000000..d19e37d --- /dev/null +++ b/internal/osbased/flags_linux.go @@ -0,0 +1,7 @@ +package osbased + +import "github.com/Equationzhao/g/internal/item" + +func CheckFlags(_ *item.FileInfo) []string { + return nil +} diff --git a/internal/osbased/flags_windows.go b/internal/osbased/flags_windows.go new file mode 100644 index 0000000..d19e37d --- /dev/null +++ b/internal/osbased/flags_windows.go @@ -0,0 +1,7 @@ +package osbased + +import "github.com/Equationzhao/g/internal/item" + +func CheckFlags(_ *item.FileInfo) []string { + return nil +}