summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlorentzforces <25649139+lorentzforces@users.noreply.github.com>2024-04-07 08:35:46 -0500
committerGitHub <noreply@github.com>2024-04-07 15:35:46 +0200
commit5b108037a309929c8f6da21bdd9750245a02bc76 (patch)
tree09845d654456f7ca0d15a7c18e4c51f8fc9af601
parent21d256d7da8e29baafc825dad4301cd7c043d5f2 (diff)
Use symlink target for stat styling & icons (#566) (#1644)
* use symlink target for stat styling & icons (#566) Support LS_COLORS/dircolors use of "target" for symlinks to select icons and styles for them according to the target stat. This mainly applies to directories - file name-based styles will still be based on the name of the link, not its target. This mirrors `ls` behavior. * remove unnecessary debugging and factor out parsePair in color parsing * move conditional to switch block * clarify ln target behavior in docs * run gofmt on single file --------- Co-authored-by: Gökçehan Kara <gokcehankara@gmail.com>
-rw-r--r--colors.go62
-rw-r--r--doc.md2
-rw-r--r--doc.txt12
-rw-r--r--icons.go62
-rw-r--r--lf.18
5 files changed, 87 insertions, 59 deletions
diff --git a/colors.go b/colors.go
index 9520480..8558b3f 100644
--- a/colors.go
+++ b/colors.go
@@ -10,10 +10,16 @@ import (
"github.com/gdamore/tcell/v2"
)
-type styleMap map[string]tcell.Style
+type styleMap struct {
+ styles map[string]tcell.Style
+ useLinkTarget bool
+}
func parseStyles() styleMap {
- sm := make(styleMap)
+ sm := styleMap{
+ styles: make(map[string]tcell.Style),
+ useLinkTarget: false,
+ }
// Default values from dircolors
//
@@ -191,20 +197,12 @@ func (sm styleMap) parseFile(path string) {
}
for _, pair := range pairs {
- key, val := pair[0], pair[1]
-
- key = replaceTilde(key)
-
- if filepath.IsAbs(key) {
- key = filepath.Clean(key)
- }
-
- sm[key] = applyAnsiCodes(val, tcell.StyleDefault)
+ sm.parsePair(pair)
}
}
// This function parses $LS_COLORS environment variable.
-func (sm styleMap) parseGNU(env string) {
+func (sm *styleMap) parseGNU(env string) {
for _, entry := range strings.Split(env, ":") {
if entry == "" {
continue
@@ -217,16 +215,24 @@ func (sm styleMap) parseGNU(env string) {
return
}
- key, val := pair[0], pair[1]
+ sm.parsePair(pair)
+ }
+}
- key = replaceTilde(key)
+func (sm *styleMap) parsePair(pair []string) {
+ key, val := pair[0], pair[1]
- if filepath.IsAbs(key) {
- key = filepath.Clean(key)
- }
+ key = replaceTilde(key)
- sm[key] = applyAnsiCodes(val, tcell.StyleDefault)
+ if filepath.IsAbs(key) {
+ key = filepath.Clean(key)
}
+
+ if key == "ln" && val == "target" {
+ sm.useLinkTarget = true
+ }
+
+ sm.styles[key] = applyAnsiCodes(val, tcell.StyleDefault)
}
// This function parses $LSCOLORS environment variable.
@@ -267,17 +273,17 @@ func (sm styleMap) parseBSD(env string) {
}
for i, key := range colorNames {
- sm[key] = getStyle(env[i*2], env[i*2+1])
+ sm.styles[key] = getStyle(env[i*2], env[i*2+1])
}
}
func (sm styleMap) get(f *file) tcell.Style {
- if val, ok := sm[f.path]; ok {
+ if val, ok := sm.styles[f.path]; ok {
return val
}
if f.IsDir() {
- if val, ok := sm[f.Name()+"/"]; ok {
+ if val, ok := sm.styles[f.Name()+"/"]; ok {
return val
}
}
@@ -285,7 +291,7 @@ func (sm styleMap) get(f *file) tcell.Style {
var key string
switch {
- case f.linkState == working:
+ case f.linkState == working && !sm.useLinkTarget:
key = "ln"
case f.linkState == broken:
key = "or"
@@ -313,27 +319,27 @@ func (sm styleMap) get(f *file) tcell.Style {
key = "ex"
}
- if val, ok := sm[key]; ok {
+ if val, ok := sm.styles[key]; ok {
return val
}
- if val, ok := sm[f.Name()+"*"]; ok {
+ if val, ok := sm.styles[f.Name()+"*"]; ok {
return val
}
- if val, ok := sm["*"+f.Name()]; ok {
+ if val, ok := sm.styles["*"+f.Name()]; ok {
return val
}
- if val, ok := sm[filepath.Base(f.Name())+".*"]; ok {
+ if val, ok := sm.styles[filepath.Base(f.Name())+".*"]; ok {
return val
}
- if val, ok := sm["*"+strings.ToLower(f.ext)]; ok {
+ if val, ok := sm.styles["*"+strings.ToLower(f.ext)]; ok {
return val
}
- if val, ok := sm["fi"]; ok {
+ if val, ok := sm.styles["fi"]; ok {
return val
}
diff --git a/doc.md b/doc.md
index 92dee46..faf38c9 100644
--- a/doc.md
+++ b/doc.md
@@ -1790,6 +1790,7 @@ You may instead divide it into multiple lines in between double quotes by escapi
ex=01;32:\
"
+The `ln` entry supports the special value `target`, which will use the link target to select a style. File name rules will still apply based on the link's name -- this mirrors GNU's `ls` and `dircolors` behavior.
Having such a long variable definition in a shell configuration file might be undesirable.
You may instead use the colors file (refer to the [CONFIGURATION section](https://github.com/gokcehan/lf/blob/master/doc.md#configuration)) for configuration.
A sample colors file can be found at
@@ -1802,6 +1803,7 @@ https://en.wikipedia.org/wiki/ANSI_escape_code
Icons are configured using `LF_ICONS` environment variable or an icons file (refer to the [CONFIGURATION section](https://github.com/gokcehan/lf/blob/master/doc.md#configuration)).
The variable uses the same syntax as `LS_COLORS/LF_COLORS`.
Instead of colors, you should put a single characters as values of entries.
+The `ln` entry supports the special value `target`, which will use the link target to select a icon. File name rules will still apply based on the link's name -- this mirrors GNU's `ls` and `dircolors` behavior.
The icons file (refer to the [CONFIGURATION section](https://github.com/gokcehan/lf/blob/master/doc.md#configuration)) should consist of whitespace-separated pairs with a `#` character to start comments until the end of the line.
Do not forget to add `set icons true` to your `lfrc` to see the icons.
Default values are as follows given with their matching order in lf:
diff --git a/doc.txt b/doc.txt
index f932ec1..5910ce2 100644
--- a/doc.txt
+++ b/doc.txt
@@ -2026,8 +2026,11 @@ escaping newlines with backslashes as follows:
ex=01;32:\
"
-Having such a long variable definition in a shell configuration file
-might be undesirable. You may instead use the colors file (refer to the
+The ln entry supports the special value target, which will use the link
+target to select a style. File name rules will still apply based on the
+link's name -- this mirrors GNU's ls and dircolors behavior. Having such
+a long variable definition in a shell configuration file might be
+undesirable. You may instead use the colors file (refer to the
CONFIGURATION section) for configuration. A sample colors file can be
found at https://github.com/gokcehan/lf/blob/master/etc/colors.example
You may also see the wiki page for ANSI escape codes
@@ -2038,7 +2041,10 @@ ICONS
Icons are configured using LF_ICONS environment variable or an icons
file (refer to the CONFIGURATION section). The variable uses the same
syntax as LS_COLORS/LF_COLORS. Instead of colors, you should put a
-single characters as values of entries. The icons file (refer to the
+single characters as values of entries. The ln entry supports the
+special value target, which will use the link target to select a icon.
+File name rules will still apply based on the link's name -- this
+mirrors GNU's ls and dircolors behavior. The icons file (refer to the
CONFIGURATION section) should consist of whitespace-separated pairs with
a # character to start comments until the end of the line. Do not forget
to add set icons true to your lfrc to see the icons. Default values are
diff --git a/icons.go b/icons.go
index ac4230f..5583864 100644
--- a/icons.go
+++ b/icons.go
@@ -7,10 +7,16 @@ import (
"strings"
)
-type iconMap map[string]string
+type iconMap struct {
+ icons map[string]string
+ useLinkTarget bool
+}
func parseIcons() iconMap {
- im := make(iconMap)
+ im := iconMap{
+ icons: make(map[string]string),
+ useLinkTarget: false,
+ }
defaultIcons := []string{
"ln=l",
@@ -44,7 +50,7 @@ func parseIcons() iconMap {
return im
}
-func (im iconMap) parseFile(path string) {
+func (im *iconMap) parseFile(path string) {
log.Printf("reading file: %s", path)
f, err := os.Open(path)
@@ -61,19 +67,11 @@ func (im iconMap) parseFile(path string) {
}
for _, pair := range pairs {
- key, val := pair[0], pair[1]
-
- key = replaceTilde(key)
-
- if filepath.IsAbs(key) {
- key = filepath.Clean(key)
- }
-
- im[key] = val
+ im.parsePair(pair)
}
}
-func (im iconMap) parseEnv(env string) {
+func (im *iconMap) parseEnv(env string) {
for _, entry := range strings.Split(env, ":") {
if entry == "" {
continue
@@ -86,25 +84,33 @@ func (im iconMap) parseEnv(env string) {
return
}
- key, val := pair[0], pair[1]
+ im.parsePair(pair)
+ }
+}
- key = replaceTilde(key)
+func (im *iconMap) parsePair(pair []string) {
+ key, val := pair[0], pair[1]
- if filepath.IsAbs(key) {
- key = filepath.Clean(key)
- }
+ key = replaceTilde(key)
- im[key] = val
+ if filepath.IsAbs(key) {
+ key = filepath.Clean(key)
}
+
+ if key == "ln" && val == "target" {
+ im.useLinkTarget = true
+ }
+
+ im.icons[key] = val
}
func (im iconMap) get(f *file) string {
- if val, ok := im[f.path]; ok {
+ if val, ok := im.icons[f.path]; ok {
return val
}
if f.IsDir() {
- if val, ok := im[f.Name()+"/"]; ok {
+ if val, ok := im.icons[f.Name()+"/"]; ok {
return val
}
}
@@ -112,7 +118,7 @@ func (im iconMap) get(f *file) string {
var key string
switch {
- case f.linkState == working:
+ case f.linkState == working && !im.useLinkTarget:
key = "ln"
case f.linkState == broken:
key = "or"
@@ -140,27 +146,27 @@ func (im iconMap) get(f *file) string {
key = "ex"
}
- if val, ok := im[key]; ok {
+ if val, ok := im.icons[key]; ok {
return val
}
- if val, ok := im[f.Name()+"*"]; ok {
+ if val, ok := im.icons[f.Name()+"*"]; ok {
return val
}
- if val, ok := im["*"+f.Name()]; ok {
+ if val, ok := im.icons["*"+f.Name()]; ok {
return val
}
- if val, ok := im[filepath.Base(f.Name())+".*"]; ok {
+ if val, ok := im.icons[filepath.Base(f.Name())+".*"]; ok {
return val
}
- if val, ok := im["*"+strings.ToLower(f.ext)]; ok {
+ if val, ok := im.icons["*"+strings.ToLower(f.ext)]; ok {
return val
}
- if val, ok := im["fi"]; ok {
+ if val, ok := im.icons["fi"]; ok {
return val
}
diff --git a/lf.1 b/lf.1
index 1d0c45e..2bb3238 100644
--- a/lf.1
+++ b/lf.1
@@ -2363,6 +2363,10 @@ ex=01;32:\[rs]
\f[R]
.fi
.PP
+The \f[C]ln\f[R] entry supports the special value \f[C]target\f[R],
+which will use the link target to select a style.
+File name rules will still apply based on the link\[aq]s name -- this
+mirrors GNU\[aq]s \f[C]ls\f[R] and \f[C]dircolors\f[R] behavior.
Having such a long variable definition in a shell configuration file
might be undesirable.
You may instead use the colors file (refer to the CONFIGURATION
@@ -2380,6 +2384,10 @@ section (https://github.com/gokcehan/lf/blob/master/doc.md#configuration)).
The variable uses the same syntax as \f[C]LS_COLORS/LF_COLORS\f[R].
Instead of colors, you should put a single characters as values of
entries.
+The \f[C]ln\f[R] entry supports the special value \f[C]target\f[R],
+which will use the link target to select a icon.
+File name rules will still apply based on the link\[aq]s name -- this
+mirrors GNU\[aq]s \f[C]ls\f[R] and \f[C]dircolors\f[R] behavior.
The icons file (refer to the CONFIGURATION
section (https://github.com/gokcehan/lf/blob/master/doc.md#configuration))
should consist of whitespace-separated pairs with a \f[C]#\f[R]