feat: root-path option

This commit is contained in:
2024-09-03 02:41:29 +03:00
parent 4f432ed412
commit 55032b4f6e
15 changed files with 123 additions and 31 deletions

View File

@@ -22,6 +22,7 @@ Prints a tree-like representation of the input.
- `-c, --charset CHARSET`: Use CHARSET to display characters (utf-8, ascii).
- `-s, --trailing-slash`: Display trailing slash on directory.
- `-p, --full-path`: Display full path.
- `-r, --root-path`: Replace root with given path. Default: "."
- `-D, --no-root-dot`: Do not display a root element.
## Installation

10
args.go
View File

@@ -4,7 +4,6 @@ import (
"embed"
"fmt"
"os"
"strings"
)
//go:embed version.txt
@@ -28,8 +27,8 @@ var VERSION embed.FS
// Returns:
//
// Options - A struct containing the parsed options.
func getOpts() Options {
opts := Options{false, "", strings.Builder{}, "utf-8", false, false, true}
func getOpts() *Options {
opts := DefaultOptions()
args := os.Args[1:]
for len(args) > 0 {
switch args[0] {
@@ -83,6 +82,11 @@ func getOpts() Options {
opts.rootDot = false
args = args[1:]
}
case "-r", "--root-path":
{
opts.rootPath = args[1]
args = args[2:]
}
default:
{
opts.extra.WriteString(args[0] + "\n")

View File

@@ -25,6 +25,7 @@ func helpText() strings.Builder {
builder.WriteString(" -c, --charset CHARSET Use CHARSET to display characters (utf-8, ascii)" + LE)
builder.WriteString(" -s, --trailing-slash Display trailing slash on directory" + LE)
builder.WriteString(" -p, --full-path Display full path" + LE)
builder.WriteString(" -r, --root-path Replace root with given path. Default: \".\"" + LE)
builder.WriteString(" -D, --no-root-dot Do not display a root element" + LE)
return builder
}
@@ -172,8 +173,13 @@ func getName(node *Node, opts *Options) string {
str := chunks.String()
if opts.fullPath && node.parent != nil {
newOpts := Options{false, "", strings.Builder{}, opts.charset, true, opts.fullPath, opts.rootDot}
str = getName(node.parent, &newOpts) + str
newOpts := DefaultOptions()
newOpts.charset = opts.charset
newOpts.fullPath = opts.fullPath
newOpts.rootPath = opts.rootPath
newOpts.rootDot = opts.rootDot
newOpts.trailingSlash = true
str = getName(node.parent, newOpts) + str
}
return str

View File

@@ -44,9 +44,13 @@ func parseDepth(line string, indentSize int) int {
// Returns:
//
// *Node - The root node of the parsed tree structure.
func parseInput(input string) *Node {
func parseInput(input string, opts *Options) *Node {
input = strings.Replace(input, "\r", "", -1)
root := &Node{".", 0, []*Node{}, nil}
rootName := "."
if opts.rootPath != "" && opts.rootPath != "." {
rootName = opts.rootPath
}
root := &Node{rootName, 0, []*Node{}, nil}
current := root
indentSize := 0
LE := LE_UNIX

View File

@@ -24,7 +24,8 @@ func TestParseDepth(t *testing.T) {
func TestParseInput(t *testing.T) {
input := "root\n child1\n child2\n grandchild1\n"
root := parseInput(input)
opts := DefaultOptions()
root := parseInput(input, opts)
if root.name != "." {
t.Errorf("Expected root name to be '.', got %s", root.name)

View File

@@ -10,6 +10,21 @@ type Options struct {
trailingSlash bool
fullPath bool
rootDot bool
rootPath string
}
// default options factory
func DefaultOptions() *Options {
return &Options{
fromStdin: false,
fromFile: "",
extra: strings.Builder{},
charset: "utf-8",
trailingSlash: false,
fullPath: false,
rootDot: true,
rootPath: ".",
}
}
type Node struct {

View File

@@ -1,11 +1,13 @@
#!/usr/bin/env bash
go install
cd "$(dirname $0)/src"
for i in test_*; do
echo "Creating snapshots for $i"
woext="${i%.*}"
treelike -f "$i" -D > "../snapshots/${woext}_snapshot_no_root.txt"
treelike -f "$i" -r "~" -p > "../snapshots/${woext}_snapshot_root_path.txt"
treelike -f "$i" -p > "../snapshots/${woext}_snapshot_full_path.txt"
treelike -f "$i" -s > "../snapshots/${woext}_snapshot_trailing_slash.txt"
treelike -f "$i" -c ascii > "../snapshots/${woext}_snapshot_ascii.txt"

View File

@@ -0,0 +1,7 @@
~
└── ~/a
├── ~/a/b
│ └── ~/a/b/c
└── ~/a/d
├── ~/a/d/e
└── ~/a/d/f

View File

@@ -0,0 +1,7 @@
~
└── ~/SceneBase (Node2D)
├── ~/SceneBase (Node2D)/GroundLayer (TileMapLayer)
│ ├── ~/SceneBase (Node2D)/GroundLayer (TileMapLayer)/Player (CharacterBody2D)
│ └── ~/SceneBase (Node2D)/GroundLayer (TileMapLayer)/Enemy (CharacterBody2D)
├── ~/SceneBase (Node2D)/Trees (TileMapLayer)
└── ~/SceneBase (Node2D)/Rocks (TileMapLayer)

View File

@@ -0,0 +1,8 @@
~
└── ~/.
└── ~/./SceneBase (Node2D)
├── ~/./SceneBase (Node2D)/GroundLayer (TileMapLayer)
│ ├── ~/./SceneBase (Node2D)/GroundLayer (TileMapLayer)/Player (CharacterBody2D)
│ └── ~/./SceneBase (Node2D)/GroundLayer (TileMapLayer)/Enemy (CharacterBody2D)
├── ~/./SceneBase (Node2D)/Trees (TileMapLayer)
└── ~/./SceneBase (Node2D)/Rocks (TileMapLayer)

View File

@@ -0,0 +1,11 @@
~
└── ~/usr
├── ~/usr/local
├── ~/usr/bin
│ ├── ~/usr/bin/sh
│ ├── ~/usr/bin/bash
│ ├── ~/usr/bin/zsh
│ └── ~/usr/bin/fish
└── ~/usr/sbin
├── ~/usr/sbin/sysctl
└── ~/usr/sbin/tcpdump

View File

@@ -0,0 +1,9 @@
~
├── ~/I
│ └── ~/I/am
│ └── ~/I/am/a
│ └── ~/I/am/a/superhero!
├── ~/a
│ └── ~/a/what?
└── ~/a
└── ~/a/superhero!

View File

@@ -0,0 +1,9 @@
~
├── ~/I
│ └── ~/I/am
│ └── ~/I/am/a
│ └── ~/I/am/a/superhero!
├── ~/a
│ └── ~/a/what?
└── ~/a
└── ~/a/superhero!

View File

@@ -8,9 +8,10 @@ import (
func TestDescribeTree(t *testing.T) {
input := "root\n child1\n child2\n grandchild1\n"
root := parseInput(input)
opts := Options{rootDot: true}
result := describeTree(root, &opts)
opts := DefaultOptions()
opts.rootDot = true
root := parseInput(input, opts)
result := describeTree(root, opts)
expected := ".\n└── root\n ├── child1\n └── child2\n └── grandchild1"
if result != expected {
@@ -19,8 +20,8 @@ func TestDescribeTree(t *testing.T) {
}
func TestRemovePrefix(t *testing.T) {
opts := Options{false, "", strings.Builder{}, "utf-8", false, false, true}
CHILD, LAST_CHILD, DIRECTORY, EMPTY := getPrefixes(&opts)
opts := DefaultOptions()
CHILD, LAST_CHILD, DIRECTORY, EMPTY := getPrefixes(opts)
tests := []struct {
str string
@@ -33,7 +34,7 @@ func TestRemovePrefix(t *testing.T) {
}
for _, test := range tests {
result := removePrefix(test.str, &opts)
result := removePrefix(test.str, opts)
if result != test.expected {
t.Errorf("removePrefix(%q)\n actual = %q\nwant = %q", test.str, result, test.expected)
}
@@ -71,9 +72,10 @@ func TestGetPrefixes(t *testing.T) {
func TestMultiRoot(t *testing.T) {
input := "I\n am\n a\n superhero!\na\n what?\na\n superhero!\n"
root := parseInput(input)
opts := Options{rootDot: true}
result := describeTree(root, &opts)
opts := DefaultOptions()
opts.rootDot = true
root := parseInput(input, opts)
result := describeTree(root, opts)
expected := ".\n├── I\n│ └── am\n│ └── a\n│ └── superhero!\n├── a\n│ └── what?\n└── a\n └── superhero!"
if result != expected {
t.Errorf("describeTree()\n actual = %q\nwant = %q", result, expected)
@@ -82,9 +84,10 @@ func TestMultiRoot(t *testing.T) {
func TestWinNewLines(t *testing.T) {
input := "root\r\n child1\r\n child2\r\n grandchild1\r\n"
root := parseInput(input)
opts := Options{rootDot: true}
result := describeTree(root, &opts)
opts := DefaultOptions()
opts.rootDot = true
root := parseInput(input, opts)
result := describeTree(root, opts)
expected := ".\n└── root\n ├── child1\n └── child2\n └── grandchild1"
if result != expected {
t.Errorf("describeTree()\n actual = %q\nwant = %q", result, expected)
@@ -118,13 +121,18 @@ func TestSnapshots(t *testing.T) {
tests := make(map[string]*Options)
// &Options{fromStdin, fromFile, extra, charset, trailingSlash, fullPath, rootDot}
tests[""] = &Options{false, "", strings.Builder{}, "utf-8", false, false, true}
tests["_ascii"] = &Options{false, "", strings.Builder{}, "ascii", false, false, true}
tests["_full_path"] = &Options{false, "", strings.Builder{}, "utf-8", false, true, true}
tests["_no_root"] = &Options{false, "", strings.Builder{}, "utf-8", false, false, false}
tests["_trailing_slash"] = &Options{false, "", strings.Builder{}, "utf-8", true, false, true}
tests[""] = DefaultOptions()
tests["_ascii"] = DefaultOptions()
tests["_ascii"].charset = "ascii"
tests["_full_path"] = DefaultOptions()
tests["_full_path"].fullPath = true
tests["_root_path"] = DefaultOptions()
tests["_root_path"].rootPath = "~"
tests["_root_path"].fullPath = true
tests["_no_root"] = DefaultOptions()
tests["_no_root"].rootDot = false
tests["_trailing_slash"] = DefaultOptions()
tests["_trailing_slash"].trailingSlash = true
contents, err := os.ReadFile(dirPath + string(os.PathSeparator) + entry.Name())
@@ -143,7 +151,7 @@ func TestSnapshots(t *testing.T) {
t.Errorf("Error reading file: %v", err)
break
}
actual := describeTree(parseInput(string(contents)), opts)
actual := describeTree(parseInput(string(contents), opts), opts)
if actual+"\n" != string(want) {
t.Errorf("describeTree()\nactual = %q\nwant = %q\n file %v", actual, want, filePath)

View File

@@ -8,11 +8,11 @@ import (
func main() {
opts := getOpts()
input, err, code := parseRawInput(&opts)
input, err, code := parseRawInput(opts)
if err != nil {
fmt.Println(err)
os.Exit(code)
}
node := parseInput(input.String())
fmt.Println(describeTree(node, &opts))
node := parseInput(input.String(), opts)
fmt.Println(describeTree(node, opts))
}