Add auto icon mode fallback and Nerd Font docs
This commit is contained in:
parent
ef47410bcf
commit
780150500d
6 changed files with 193 additions and 18 deletions
32
README.md
32
README.md
|
|
@ -9,6 +9,20 @@
|
||||||
- Asynchronous copy/move with progress and background mode
|
- Asynchronous copy/move with progress and background mode
|
||||||
- Theme support and configurable layout/columns
|
- Theme support and configurable layout/columns
|
||||||
|
|
||||||
|
## Font requirement (icons)
|
||||||
|
|
||||||
|
For file icons, `vcom` expects a Nerd Font in your terminal profile.
|
||||||
|
|
||||||
|
Default behavior is `ui.icon_mode = "auto"`:
|
||||||
|
|
||||||
|
- if a Nerd Font is detected, `vcom` uses Nerd icons
|
||||||
|
- if not, `vcom` falls back to ASCII icons automatically
|
||||||
|
|
||||||
|
You can force behavior in config:
|
||||||
|
|
||||||
|
- `ui.icon_mode = "nerd"`: always use Nerd icons
|
||||||
|
- `ui.icon_mode = "ascii"`: always use ASCII icons
|
||||||
|
|
||||||
Preview mode (`F9` / `i`) temporarily replaces the inactive pane and shows:
|
Preview mode (`F9` / `i`) temporarily replaces the inactive pane and shows:
|
||||||
|
|
||||||
- directory listing preview
|
- directory listing preview
|
||||||
|
|
@ -60,6 +74,17 @@ Download the release `.deb` for `v0.1.2`, then install:
|
||||||
sudo apt install ./vcom_0.1.2_amd64.deb
|
sudo apt install ./vcom_0.1.2_amd64.deb
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Install a Nerd Font (example):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
wget -qO /tmp/JetBrainsMono.zip https://github.com/ryanoasis/nerd-fonts/releases/latest/download/JetBrainsMono.zip
|
||||||
|
mkdir -p ~/.local/share/fonts/JetBrainsMonoNerd
|
||||||
|
unzip -o /tmp/JetBrainsMono.zip -d ~/.local/share/fonts/JetBrainsMonoNerd
|
||||||
|
fc-cache -fv
|
||||||
|
```
|
||||||
|
|
||||||
|
Then set your terminal font to a Nerd Font variant (for example, `JetBrainsMono Nerd Font`).
|
||||||
|
|
||||||
### Arch Linux
|
### Arch Linux
|
||||||
|
|
||||||
A `PKGBUILD` is included in the repository:
|
A `PKGBUILD` is included in the repository:
|
||||||
|
|
@ -80,6 +105,13 @@ Optional config lookup order:
|
||||||
|
|
||||||
Reference config: [vcom.toml](/home/vrubel/projects/vcom/vcom.toml)
|
Reference config: [vcom.toml](/home/vrubel/projects/vcom/vcom.toml)
|
||||||
|
|
||||||
|
Icon mode example:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[ui]
|
||||||
|
icon_mode = "auto" # auto | nerd | ascii
|
||||||
|
```
|
||||||
|
|
||||||
## Themes
|
## Themes
|
||||||
|
|
||||||
Built-in themes:
|
Built-in themes:
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ type StartupConfig struct {
|
||||||
type UIConfig struct {
|
type UIConfig struct {
|
||||||
AppTitle string `toml:"app_title"`
|
AppTitle string `toml:"app_title"`
|
||||||
Theme string `toml:"theme"`
|
Theme string `toml:"theme"`
|
||||||
|
IconMode string `toml:"icon_mode"`
|
||||||
ShowTitleBar bool `toml:"show_title_bar"`
|
ShowTitleBar bool `toml:"show_title_bar"`
|
||||||
ShowFooter bool `toml:"show_footer"`
|
ShowFooter bool `toml:"show_footer"`
|
||||||
Border string `toml:"border"`
|
Border string `toml:"border"`
|
||||||
|
|
@ -76,6 +77,7 @@ func Default() Config {
|
||||||
UI: UIConfig{
|
UI: UIConfig{
|
||||||
AppTitle: "vcom",
|
AppTitle: "vcom",
|
||||||
Theme: "catppuccin-mocha",
|
Theme: "catppuccin-mocha",
|
||||||
|
IconMode: "auto",
|
||||||
ShowTitleBar: true,
|
ShowTitleBar: true,
|
||||||
ShowFooter: true,
|
ShowFooter: true,
|
||||||
Border: "rounded",
|
Border: "rounded",
|
||||||
|
|
@ -138,10 +140,49 @@ func Load(explicitPath string) (Config, string, error) {
|
||||||
return cfg, path, nil
|
return cfg, path, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Save(cfg Config, path string) (string, error) {
|
||||||
|
if err := cfg.Validate(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
targetPath := strings.TrimSpace(path)
|
||||||
|
if targetPath == "" {
|
||||||
|
var err error
|
||||||
|
targetPath, err = DefaultUserPath()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
absPath, err := filepath.Abs(targetPath)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("resolve %s: %w", targetPath, err)
|
||||||
|
}
|
||||||
|
if err := os.MkdirAll(filepath.Dir(absPath), 0o755); err != nil {
|
||||||
|
return "", fmt.Errorf("mkdir %s: %w", filepath.Dir(absPath), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := toml.Marshal(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("marshal config: %w", err)
|
||||||
|
}
|
||||||
|
if err := os.WriteFile(absPath, data, 0o644); err != nil {
|
||||||
|
return "", fmt.Errorf("write %s: %w", absPath, err)
|
||||||
|
}
|
||||||
|
return absPath, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Config) Validate() error {
|
func (c *Config) Validate() error {
|
||||||
if c.UI.Theme == "" {
|
if c.UI.Theme == "" {
|
||||||
return errors.New("ui.theme must not be empty")
|
return errors.New("ui.theme must not be empty")
|
||||||
}
|
}
|
||||||
|
switch strings.ToLower(strings.TrimSpace(c.UI.IconMode)) {
|
||||||
|
case "", "auto":
|
||||||
|
c.UI.IconMode = "auto"
|
||||||
|
case "nerd", "ascii":
|
||||||
|
default:
|
||||||
|
return errors.New("ui.icon_mode must be one of: auto, nerd, ascii")
|
||||||
|
}
|
||||||
if strings.TrimSpace(c.UI.AppTitle) == "" {
|
if strings.TrimSpace(c.UI.AppTitle) == "" {
|
||||||
c.UI.AppTitle = "vcom"
|
c.UI.AppTitle = "vcom"
|
||||||
}
|
}
|
||||||
|
|
@ -213,3 +254,15 @@ func resolvePath(explicitPath string) (string, bool, error) {
|
||||||
|
|
||||||
return "", false, nil
|
return "", false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DefaultUserPath() (string, error) {
|
||||||
|
homeDir, err := os.UserHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("resolve home dir: %w", err)
|
||||||
|
}
|
||||||
|
xdgDir := os.Getenv("XDG_CONFIG_HOME")
|
||||||
|
if xdgDir == "" {
|
||||||
|
xdgDir = filepath.Join(homeDir, ".config")
|
||||||
|
}
|
||||||
|
return filepath.Join(xdgDir, "vcom", "vcom.toml"), nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ type PreviewOptions struct {
|
||||||
DirectoryPreviewLimit int
|
DirectoryPreviewLimit int
|
||||||
HumanReadableSize bool
|
HumanReadableSize bool
|
||||||
ThemeName string
|
ThemeName string
|
||||||
|
UseNerdIcons bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuildPreview(entry Entry, options PreviewOptions) Preview {
|
func BuildPreview(entry Entry, options PreviewOptions) Preview {
|
||||||
|
|
@ -317,7 +318,7 @@ func buildDirectoryPreview(path string, options PreviewOptions) string {
|
||||||
if entry.IsParent {
|
if entry.IsParent {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
icon := previewIcon(entry)
|
icon := previewIcon(entry, options.UseNerdIcons)
|
||||||
|
|
||||||
size := ""
|
size := ""
|
||||||
if !entry.IsDir {
|
if !entry.IsDir {
|
||||||
|
|
@ -338,7 +339,26 @@ func buildDirectoryPreview(path string, options PreviewOptions) string {
|
||||||
return strings.Join(lines, "\n")
|
return strings.Join(lines, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func previewIcon(entry Entry) string {
|
func previewIcon(entry Entry, useNerdIcons bool) string {
|
||||||
|
if !useNerdIcons {
|
||||||
|
switch entry.Category() {
|
||||||
|
case "directory":
|
||||||
|
return "[D]"
|
||||||
|
case "config":
|
||||||
|
return "[C]"
|
||||||
|
case "text":
|
||||||
|
return "[T]"
|
||||||
|
case "image":
|
||||||
|
return "[I]"
|
||||||
|
case "executable":
|
||||||
|
return "[X]"
|
||||||
|
case "archive":
|
||||||
|
return "[A]"
|
||||||
|
default:
|
||||||
|
return "[F]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch entry.Category() {
|
switch entry.Category() {
|
||||||
case "directory":
|
case "directory":
|
||||||
return ""
|
return ""
|
||||||
|
|
|
||||||
37
internal/ui/icon_mode.go
Normal file
37
internal/ui/icon_mode.go
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
package ui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resolveIconMode(mode string) (bool, string) {
|
||||||
|
switch strings.ToLower(strings.TrimSpace(mode)) {
|
||||||
|
case "ascii":
|
||||||
|
return false, "Icon mode: ASCII"
|
||||||
|
case "nerd":
|
||||||
|
return true, ""
|
||||||
|
case "", "auto":
|
||||||
|
default:
|
||||||
|
return true, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if runtime.GOOS != "linux" {
|
||||||
|
return true, ""
|
||||||
|
}
|
||||||
|
if _, err := exec.LookPath("fc-list"); err != nil {
|
||||||
|
return true, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := exec.Command("fc-list", ":", "family").Output()
|
||||||
|
if err != nil {
|
||||||
|
return true, ""
|
||||||
|
}
|
||||||
|
text := strings.ToLower(string(out))
|
||||||
|
if strings.Contains(text, "nerd font") {
|
||||||
|
return true, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, "Nerd Font not found: using ASCII icons"
|
||||||
|
}
|
||||||
|
|
@ -141,6 +141,7 @@ type Model struct {
|
||||||
configPath string
|
configPath string
|
||||||
palette theme.Palette
|
palette theme.Palette
|
||||||
keys KeyMap
|
keys KeyMap
|
||||||
|
nerdIcons bool
|
||||||
|
|
||||||
width int
|
width int
|
||||||
height int
|
height int
|
||||||
|
|
@ -199,6 +200,10 @@ func NewModel(cfg config.Config, configPath string) (Model, error) {
|
||||||
status: "Ready",
|
status: "Ready",
|
||||||
copyProgress: make(chan tea.Msg, 256),
|
copyProgress: make(chan tea.Msg, 256),
|
||||||
}
|
}
|
||||||
|
model.nerdIcons, model.status = resolveIconMode(cfg.UI.IconMode)
|
||||||
|
if model.status == "" {
|
||||||
|
model.status = "Ready"
|
||||||
|
}
|
||||||
|
|
||||||
model.previewModel = viewport.New(0, 0)
|
model.previewModel = viewport.New(0, 0)
|
||||||
if err := model.reloadPane(PaneLeft, ""); err != nil {
|
if err := model.reloadPane(PaneLeft, ""); err != nil {
|
||||||
|
|
@ -546,7 +551,7 @@ func (m Model) View() string {
|
||||||
if m.active == PaneLeft {
|
if m.active == PaneLeft {
|
||||||
panels = lipgloss.JoinHorizontal(
|
panels = lipgloss.JoinHorizontal(
|
||||||
lipgloss.Top,
|
lipgloss.Top,
|
||||||
renderPane(m.left, m.cfg, m.palette, leftWidth, bodyHeight, true, m.hoverIndexFor(PaneLeft)),
|
renderPane(m.left, m.cfg, m.palette, leftWidth, bodyHeight, true, m.hoverIndexFor(PaneLeft), m.nerdIcons),
|
||||||
gap,
|
gap,
|
||||||
renderPreviewPane(m.previewData, &m.previewModel, m.cfg, m.palette, previewWidth, bodyHeight),
|
renderPreviewPane(m.previewData, &m.previewModel, m.cfg, m.palette, previewWidth, bodyHeight),
|
||||||
)
|
)
|
||||||
|
|
@ -555,15 +560,15 @@ func (m Model) View() string {
|
||||||
lipgloss.Top,
|
lipgloss.Top,
|
||||||
renderPreviewPane(m.previewData, &m.previewModel, m.cfg, m.palette, previewWidth, bodyHeight),
|
renderPreviewPane(m.previewData, &m.previewModel, m.cfg, m.palette, previewWidth, bodyHeight),
|
||||||
gap,
|
gap,
|
||||||
renderPane(m.right, m.cfg, m.palette, rightWidth, bodyHeight, true, m.hoverIndexFor(PaneRight)),
|
renderPane(m.right, m.cfg, m.palette, rightWidth, bodyHeight, true, m.hoverIndexFor(PaneRight), m.nerdIcons),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
panels = lipgloss.JoinHorizontal(
|
panels = lipgloss.JoinHorizontal(
|
||||||
lipgloss.Top,
|
lipgloss.Top,
|
||||||
renderPane(m.left, m.cfg, m.palette, leftWidth, bodyHeight, m.active == PaneLeft, m.hoverIndexFor(PaneLeft)),
|
renderPane(m.left, m.cfg, m.palette, leftWidth, bodyHeight, m.active == PaneLeft, m.hoverIndexFor(PaneLeft), m.nerdIcons),
|
||||||
gap,
|
gap,
|
||||||
renderPane(m.right, m.cfg, m.palette, rightWidth, bodyHeight, m.active == PaneRight, m.hoverIndexFor(PaneRight)),
|
renderPane(m.right, m.cfg, m.palette, rightWidth, bodyHeight, m.active == PaneRight, m.hoverIndexFor(PaneRight), m.nerdIcons),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -841,6 +846,7 @@ func (m Model) loadPreviewCmd() tea.Cmd {
|
||||||
DirectoryPreviewLimit: m.cfg.Preview.DirectoryPreviewLimit,
|
DirectoryPreviewLimit: m.cfg.Preview.DirectoryPreviewLimit,
|
||||||
HumanReadableSize: m.cfg.Browser.HumanReadableSize,
|
HumanReadableSize: m.cfg.Browser.HumanReadableSize,
|
||||||
ThemeName: m.cfg.UI.Theme,
|
ThemeName: m.cfg.UI.Theme,
|
||||||
|
UseNerdIcons: m.nerdIcons,
|
||||||
}
|
}
|
||||||
|
|
||||||
return func() tea.Msg {
|
return func() tea.Msg {
|
||||||
|
|
@ -1150,7 +1156,13 @@ func (m *Model) cycleTheme() (tea.Model, tea.Cmd) {
|
||||||
}
|
}
|
||||||
m.cfg.UI.Theme = next
|
m.cfg.UI.Theme = next
|
||||||
m.palette = palette
|
m.palette = palette
|
||||||
m.status = fmt.Sprintf("Theme: %s", next)
|
savedPath, saveErr := config.Save(m.cfg, m.configPath)
|
||||||
|
if saveErr != nil {
|
||||||
|
m.status = fmt.Sprintf("Theme: %s (save failed: %v)", next, saveErr)
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
m.configPath = savedPath
|
||||||
|
m.status = fmt.Sprintf("Theme: %s (saved)", next)
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -179,6 +179,7 @@ func renderPane(
|
||||||
height int,
|
height int,
|
||||||
active bool,
|
active bool,
|
||||||
hoverIndex int,
|
hoverIndex int,
|
||||||
|
useNerdIcons bool,
|
||||||
) string {
|
) string {
|
||||||
if width <= 0 || height <= 0 {
|
if width <= 0 || height <= 0 {
|
||||||
return ""
|
return ""
|
||||||
|
|
@ -208,8 +209,8 @@ func renderPane(
|
||||||
Render(renderPaneHeader(pane, cfg, palette, innerWidth, active, headerBg))
|
Render(renderPaneHeader(pane, cfg, palette, innerWidth, active, headerBg))
|
||||||
|
|
||||||
rowsHeight := max(innerHeight-2, 1)
|
rowsHeight := max(innerHeight-2, 1)
|
||||||
headerRow := renderColumnsHeader(cfg, innerWidth, palette, bodyBg)
|
headerRow := renderColumnsHeader(cfg, innerWidth, palette, bodyBg, useNerdIcons)
|
||||||
rows := renderPaneRows(pane, cfg, palette, innerWidth, rowsHeight, active, hoverIndex, bodyBg)
|
rows := renderPaneRows(pane, cfg, palette, innerWidth, rowsHeight, active, hoverIndex, bodyBg, useNerdIcons)
|
||||||
content := lipgloss.JoinVertical(lipgloss.Left, header, headerRow, rows)
|
content := lipgloss.JoinVertical(lipgloss.Left, header, headerRow, rows)
|
||||||
return box.Render(content)
|
return box.Render(content)
|
||||||
}
|
}
|
||||||
|
|
@ -231,8 +232,8 @@ func renderPaneHeader(pane BrowserPane, cfg config.Config, palette theme.Palette
|
||||||
Render(pathStyle.Render(truncateMiddle(compactPath(pane.Path, cfg.UI.PathDisplay), pathWidth)))
|
Render(pathStyle.Render(truncateMiddle(compactPath(pane.Path, cfg.UI.PathDisplay), pathWidth)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderColumnsHeader(cfg config.Config, width int, palette theme.Palette, background lipgloss.Color) string {
|
func renderColumnsHeader(cfg config.Config, width int, palette theme.Palette, background lipgloss.Color, useNerdIcons bool) string {
|
||||||
columns := buildColumns(cfg, width)
|
columns := buildColumns(cfg, width, useNerdIcons)
|
||||||
parts := make([]string, 0, len(columns))
|
parts := make([]string, 0, len(columns))
|
||||||
for idx, column := range columns {
|
for idx, column := range columns {
|
||||||
style := lipgloss.NewStyle().
|
style := lipgloss.NewStyle().
|
||||||
|
|
@ -254,7 +255,7 @@ func renderColumnsHeader(cfg config.Config, width int, palette theme.Palette, ba
|
||||||
Render(strings.Join(parts, ""))
|
Render(strings.Join(parts, ""))
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderPaneRows(pane BrowserPane, cfg config.Config, palette theme.Palette, width int, height int, active bool, hoverIndex int, background lipgloss.Color) string {
|
func renderPaneRows(pane BrowserPane, cfg config.Config, palette theme.Palette, width int, height int, active bool, hoverIndex int, background lipgloss.Color, useNerdIcons bool) string {
|
||||||
if len(pane.Entries) == 0 {
|
if len(pane.Entries) == 0 {
|
||||||
return lipgloss.NewStyle().
|
return lipgloss.NewStyle().
|
||||||
Width(width).
|
Width(width).
|
||||||
|
|
@ -274,7 +275,7 @@ func renderPaneRows(pane BrowserPane, cfg config.Config, palette theme.Palette,
|
||||||
entry := pane.Entries[idx]
|
entry := pane.Entries[idx]
|
||||||
isSelected := idx == pane.Cursor && active
|
isSelected := idx == pane.Cursor && active
|
||||||
marked := !entry.IsParent && pane.IsMarked(entry.Path)
|
marked := !entry.IsParent && pane.IsMarked(entry.Path)
|
||||||
row := renderEntryRow(entry, cfg, width, isSelected, marked, idx == hoverIndex, active, palette, background)
|
row := renderEntryRow(entry, cfg, width, isSelected, marked, idx == hoverIndex, active, palette, background, useNerdIcons)
|
||||||
lines = append(lines, row)
|
lines = append(lines, row)
|
||||||
}
|
}
|
||||||
for len(lines) < visibleHeight {
|
for len(lines) < visibleHeight {
|
||||||
|
|
@ -287,8 +288,8 @@ func renderPaneRows(pane BrowserPane, cfg config.Config, palette theme.Palette,
|
||||||
Render(strings.Join(lines, "\n"))
|
Render(strings.Join(lines, "\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderEntryRow(entry vfs.Entry, cfg config.Config, width int, selected bool, marked bool, hovered bool, active bool, palette theme.Palette, baseBackground lipgloss.Color) string {
|
func renderEntryRow(entry vfs.Entry, cfg config.Config, width int, selected bool, marked bool, hovered bool, active bool, palette theme.Palette, baseBackground lipgloss.Color, useNerdIcons bool) string {
|
||||||
columns := buildColumns(cfg, width)
|
columns := buildColumns(cfg, width, useNerdIcons)
|
||||||
rowBackground := baseBackground
|
rowBackground := baseBackground
|
||||||
switch {
|
switch {
|
||||||
case marked:
|
case marked:
|
||||||
|
|
@ -340,7 +341,7 @@ type columnSpec struct {
|
||||||
Value func(entry vfs.Entry, human bool) string
|
Value func(entry vfs.Entry, human bool) string
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildColumns(cfg config.Config, totalWidth int) []columnSpec {
|
func buildColumns(cfg config.Config, totalWidth int, useNerdIcons bool) []columnSpec {
|
||||||
fixed := []columnSpec{}
|
fixed := []columnSpec{}
|
||||||
|
|
||||||
if cfg.Browser.Columns.Permissions {
|
if cfg.Browser.Columns.Permissions {
|
||||||
|
|
@ -453,7 +454,7 @@ func buildColumns(cfg config.Config, totalWidth int) []columnSpec {
|
||||||
Width: nameWidth,
|
Width: nameWidth,
|
||||||
MinWidth: minNameWidth,
|
MinWidth: minNameWidth,
|
||||||
Value: func(entry vfs.Entry, _ bool) string {
|
Value: func(entry vfs.Entry, _ bool) string {
|
||||||
return entryIcon(entry) + " " + entry.DisplayName()
|
return entryIcon(entry, useNerdIcons) + " " + entry.DisplayName()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -583,7 +584,27 @@ func trimToWidthLeft(value string, maxWidth int) string {
|
||||||
return string(runes[start:])
|
return string(runes[start:])
|
||||||
}
|
}
|
||||||
|
|
||||||
func entryIcon(entry vfs.Entry) string {
|
func entryIcon(entry vfs.Entry, useNerdIcons bool) string {
|
||||||
|
if !useNerdIcons {
|
||||||
|
switch entry.Category() {
|
||||||
|
case "parent":
|
||||||
|
return "<-"
|
||||||
|
case "directory":
|
||||||
|
return "[D]"
|
||||||
|
case "config":
|
||||||
|
return "[C]"
|
||||||
|
case "text":
|
||||||
|
return "[T]"
|
||||||
|
case "image":
|
||||||
|
return "[I]"
|
||||||
|
case "executable":
|
||||||
|
return "[X]"
|
||||||
|
case "archive":
|
||||||
|
return "[A]"
|
||||||
|
default:
|
||||||
|
return "[F]"
|
||||||
|
}
|
||||||
|
}
|
||||||
switch entry.Category() {
|
switch entry.Category() {
|
||||||
case "parent":
|
case "parent":
|
||||||
return "↩"
|
return "↩"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue