mirror of
https://github.com/chenasraf/treelike.git
synced 2026-05-17 17:48:01 +00:00
feat: root-path option
This commit is contained in:
@@ -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
10
args.go
@@ -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")
|
||||
|
||||
10
describe.go
10
describe.go
@@ -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
|
||||
|
||||
8
parse.go
8
parse.go
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
15
structs.go
15
structs.go
@@ -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 {
|
||||
|
||||
@@ -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"
|
||||
|
||||
7
test_files/snapshots/test_1_snapshot_root_path.txt
Normal file
7
test_files/snapshots/test_1_snapshot_root_path.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
~
|
||||
└── ~/a
|
||||
├── ~/a/b
|
||||
│ └── ~/a/b/c
|
||||
└── ~/a/d
|
||||
├── ~/a/d/e
|
||||
└── ~/a/d/f
|
||||
7
test_files/snapshots/test_2_snapshot_root_path.txt
Normal file
7
test_files/snapshots/test_2_snapshot_root_path.txt
Normal 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)
|
||||
8
test_files/snapshots/test_3_snapshot_root_path.txt
Normal file
8
test_files/snapshots/test_3_snapshot_root_path.txt
Normal 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)
|
||||
11
test_files/snapshots/test_4_snapshot_root_path.txt
Normal file
11
test_files/snapshots/test_4_snapshot_root_path.txt
Normal 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
|
||||
9
test_files/snapshots/test_5_snapshot_root_path.txt
Normal file
9
test_files/snapshots/test_5_snapshot_root_path.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
~
|
||||
├── ~/I
|
||||
│ └── ~/I/am
|
||||
│ └── ~/I/am/a
|
||||
│ └── ~/I/am/a/superhero!
|
||||
├── ~/a
|
||||
│ └── ~/a/what?
|
||||
└── ~/a
|
||||
└── ~/a/superhero!
|
||||
9
test_files/snapshots/test_6_snapshot_root_path.txt
Normal file
9
test_files/snapshots/test_6_snapshot_root_path.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
~
|
||||
├── ~/I
|
||||
│ └── ~/I/am
|
||||
│ └── ~/I/am/a
|
||||
│ └── ~/I/am/a/superhero!
|
||||
├── ~/a
|
||||
│ └── ~/a/what?
|
||||
└── ~/a
|
||||
└── ~/a/superhero!
|
||||
48
tree_test.go
48
tree_test.go
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user