Compare commits
	
		
			3 Commits
		
	
	
		
			main
			...
			f2976c66e3
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					f2976c66e3 | ||
| 
						 | 
					0562cc0877 | ||
| 
						 | 
					15f7db8d3e | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,2 @@
 | 
				
			|||||||
**/__debug_bin*
 | 
					**/__debug_bin*
 | 
				
			||||||
main
 | 
					main
 | 
				
			||||||
/pat
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							@@ -13,7 +13,7 @@
 | 
				
			|||||||
            "request": "launch",
 | 
					            "request": "launch",
 | 
				
			||||||
            "mode": "auto",
 | 
					            "mode": "auto",
 | 
				
			||||||
            "program": "${workspaceFolder}/cmd/main.go",
 | 
					            "program": "${workspaceFolder}/cmd/main.go",
 | 
				
			||||||
            "args": [ "."]
 | 
					            "args": [ ".."]
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										42
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								README.md
									
									
									
									
									
								
							@@ -1,22 +1,18 @@
 | 
				
			|||||||
# PAT
 | 
					# PAT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## What it Does
 | 
					## What it Does
 | 
				
			||||||
 | 
					 | 
				
			||||||
`pat` is a command-line tool for concatenating and displaying the contents of files and directories. It:
 | 
					`pat` is a command-line tool for concatenating and displaying the contents of files and directories. It:
 | 
				
			||||||
 | 
					 | 
				
			||||||
1. Processes the specified files and directories recursively.
 | 
					1. Processes the specified files and directories recursively.
 | 
				
			||||||
2. Appends content to a structured output with file paths and a delimiter for clarity.
 | 
					2. Appends content to a structured output with file paths and a delimiter for clarity.
 | 
				
			||||||
3. Copies the resulting output to the system clipboard for convenient sharing or reuse.
 | 
					3. Copies the resulting output to the system clipboard for convenient sharing or reuse.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Example use case:
 | 
					Example use case:
 | 
				
			||||||
 | 
					 | 
				
			||||||
- Aggregate and view the contents of multiple files or directories in one command.
 | 
					- Aggregate and view the contents of multiple files or directories in one command.
 | 
				
			||||||
- Automatically copy the aggregated result to the clipboard for seamless integration with other tools or platforms.
 | 
					- Automatically copy the aggregated result to the clipboard for seamless integration with other tools or platforms.
 | 
				
			||||||
- Export your codebase to a markdown document.
 | 
					
 | 
				
			||||||
- Export your codebase to a typst document.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Dependencies
 | 
					## Dependencies
 | 
				
			||||||
 | 
					 | 
				
			||||||
1. **Golang** (only to install / build):
 | 
					1. **Golang** (only to install / build):
 | 
				
			||||||
   - The application requires the Go programming language (`>= 1.18`) to compile and run.
 | 
					   - The application requires the Go programming language (`>= 1.18`) to compile and run.
 | 
				
			||||||
   - Dependency: `golang.design/x/clipboard` for clipboard interaction.
 | 
					   - Dependency: `golang.design/x/clipboard` for clipboard interaction.
 | 
				
			||||||
@@ -25,43 +21,31 @@ Example use case:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## Installation
 | 
					## Installation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Install pat:
 | 
					Install go-cat directly using go install:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```sh
 | 
					``` sh
 | 
				
			||||||
git clone --depth 1 https://git.schreifuchs.ch/schreifuchs/pat.git
 | 
					go install git.schreifuchs.ch/schreifuchs/pat@latest
 | 
				
			||||||
cd pat
 | 
					 | 
				
			||||||
go build -o=pat cmd/main.go
 | 
					 | 
				
			||||||
mv pat $GOPATH/bin/
 | 
					 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
In one go:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```sh
 | 
					 | 
				
			||||||
git clone --depth 1 https://git.schreifuchs.ch/schreifuchs/pat.git && cd pat && go build -o=pat cmd/main.go && mv pat $GOPATH/bin/
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
The binary will be placed in your $GOPATH/bin directory. Ensure $GOPATH/bin is in your system's PATH to run it directly.
 | 
					The binary will be placed in your $GOPATH/bin directory. Ensure $GOPATH/bin is in your system's PATH to run it directly.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Example Usage
 | 
					## Example Usage
 | 
				
			||||||
 | 
					Concatenate files and directories:
 | 
				
			||||||
### Concatenate files and directories:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
pat file1.txt folder/
 | 
					./pat file1.txt folder/
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Output is printed to the terminal and copied to the clipboard, allowing you to paste it elsewhere.
 | 
					Output is printed to the terminal and copied to the clipboard, allowing you to paste it elsewhere.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Create printed
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```sh
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pat -t -i .gitignore . | typst compile /dev/stdin pat.pdf
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Notes
 | 
					#### Notes
 | 
				
			||||||
 | 
					 | 
				
			||||||
- The tool uses `---------------------------------------------------------------------------` as a delimiter to separate file contents for readability.
 | 
					- The tool uses `---------------------------------------------------------------------------` as a delimiter to separate file contents for readability.
 | 
				
			||||||
- If clipboard functionality fails (e.g., unsupported environment), the application will still display the result in the terminal.
 | 
					- If clipboard functionality fails (e.g., unsupported environment), the application will still display the result in the terminal.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										16
									
								
								cmd/main.go
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								cmd/main.go
									
									
									
									
									
								
							@@ -13,11 +13,9 @@ import (
 | 
				
			|||||||
const DELEMITTER = "-(%s)--------------------------------------------------------------------------\n"
 | 
					const DELEMITTER = "-(%s)--------------------------------------------------------------------------\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ignorePath := flag.String("i", "", "set path to gitignore, if no gitignore parent dirs will be searched")
 | 
						ignorePath := flag.String("i", "", "set path to gitignore, if no gitignore parent dirs will be searched")
 | 
				
			||||||
	hiddenFiles := flag.Bool("h", false, "show hidden files")
 | 
						hiddenFiles := flag.Bool("h", false, "show hidden files")
 | 
				
			||||||
	delemitter := flag.String("d", DELEMITTER, "delemitter to use to split files when not in markdown mode must contain %s for filename")
 | 
					 | 
				
			||||||
	markdown := flag.Bool("m", false, "markdown mode, outputs files in markdown")
 | 
					 | 
				
			||||||
	typst := flag.Bool("t", false, "typst mode, outputs files in typst")
 | 
					 | 
				
			||||||
	flag.Parse()
 | 
						flag.Parse()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cats, err := cat.Path(flag.Args()...)
 | 
						cats, err := cat.Path(flag.Args()...)
 | 
				
			||||||
@@ -35,19 +33,11 @@ func main() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		cats = cats.Ignored(i)
 | 
							cats = cats.Ignored(i)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if *hiddenFiles == false {
 | 
				
			||||||
	if !*hiddenFiles {
 | 
					 | 
				
			||||||
		cats = cats.Ignored(ignore.Filesystem{})
 | 
							cats = cats.Ignored(ignore.Filesystem{})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var out string
 | 
						out := cats.ToString(DELEMITTER)
 | 
				
			||||||
	if *markdown {
 | 
					 | 
				
			||||||
		out = cats.ToMarkdown()
 | 
					 | 
				
			||||||
	} else if *typst {
 | 
					 | 
				
			||||||
		out = cats.ToTypst()
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		out = cats.ToString(*delemitter)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	fmt.Print(out)
 | 
						fmt.Print(out)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err = clip.Copy(out); err != nil {
 | 
						if err = clip.Copy(out); err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,10 +6,10 @@ import (
 | 
				
			|||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Cater []entry
 | 
					type Cater map[string]string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Path(paths ...string) (c Cater, err error) {
 | 
					func Path(paths ...string) (c Cater, err error) {
 | 
				
			||||||
	c = make(Cater, 0, 10)
 | 
						c = make(Cater)
 | 
				
			||||||
	var p os.FileInfo
 | 
						var p os.FileInfo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, path := range paths {
 | 
						for _, path := range paths {
 | 
				
			||||||
@@ -17,29 +17,28 @@ func Path(paths ...string) (c Cater, err error) {
 | 
				
			|||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		var e entry
 | 
					
 | 
				
			||||||
		if p.IsDir() {
 | 
							if p.IsDir() {
 | 
				
			||||||
			e, err = c.dir(path)
 | 
								err = c.dir(path)
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			e, err = c.file(path)
 | 
								err = c.file(path)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		c = append(c, e)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c Cater) Ignored(ignore ignorer) Cater {
 | 
					func (c Cater) Ignored(ignore ignorer) Cater {
 | 
				
			||||||
	cat := make(Cater, 0, len(c))
 | 
						cat := make(Cater)
 | 
				
			||||||
	ok := func(e entry) bool {
 | 
					 | 
				
			||||||
		return !ignore.Ignore(e.fqname)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, entry := range c {
 | 
						for name, content := range c {
 | 
				
			||||||
		cat = append(cat, entry.filter(ok))
 | 
							if ignore.Ignore(name) {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							cat[name] = content
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return cat
 | 
						return cat
 | 
				
			||||||
@@ -48,20 +47,9 @@ func (c Cater) Ignored(ignore ignorer) Cater {
 | 
				
			|||||||
func (c Cater) ToString(delemiter string) string {
 | 
					func (c Cater) ToString(delemiter string) string {
 | 
				
			||||||
	var sb strings.Builder
 | 
						var sb strings.Builder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var entries []entry
 | 
						for name, content := range c {
 | 
				
			||||||
	entries = c
 | 
							sb.WriteString(fmt.Sprintf(delemiter, name))
 | 
				
			||||||
 | 
							sb.WriteString(content)
 | 
				
			||||||
	for len(entries) > 0 {
 | 
					 | 
				
			||||||
		n := make([]entry, 0, len(entries))
 | 
					 | 
				
			||||||
		for _, e := range entries {
 | 
					 | 
				
			||||||
			if len(e.children) > 0 {
 | 
					 | 
				
			||||||
				n = append(n, e.children...)
 | 
					 | 
				
			||||||
				continue
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			sb.WriteString(fmt.Sprintf(delemiter, e.fqname))
 | 
					 | 
				
			||||||
			sb.WriteString(e.content)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		entries = n
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sb.String()
 | 
						return sb.String()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,32 +0,0 @@
 | 
				
			|||||||
package cat
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type entry struct {
 | 
					 | 
				
			||||||
	name     string
 | 
					 | 
				
			||||||
	fqname   string
 | 
					 | 
				
			||||||
	content  string
 | 
					 | 
				
			||||||
	children []entry
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (e entry) filter(ok func(e entry) bool) entry {
 | 
					 | 
				
			||||||
	children := make([]entry, 0, len(e.children))
 | 
					 | 
				
			||||||
	for _, entry := range e.children {
 | 
					 | 
				
			||||||
		if !ok(entry) {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		children = append(children, entry.filter(ok))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return entry{
 | 
					 | 
				
			||||||
		name:     e.name,
 | 
					 | 
				
			||||||
		fqname:   e.fqname,
 | 
					 | 
				
			||||||
		content:  e.content,
 | 
					 | 
				
			||||||
		children: children,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (e entry) traverse(lvl int, do func(e entry, lvl int)) {
 | 
					 | 
				
			||||||
	do(e, lvl)
 | 
					 | 
				
			||||||
	for _, entry := range e.children {
 | 
					 | 
				
			||||||
		entry.traverse(lvl+1, do)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										58
									
								
								pkg/cat/internal.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								pkg/cat/internal.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					package cat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bufio"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"path"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c Cater) dir(dir string) error {
 | 
				
			||||||
 | 
						files, err := os.ReadDir(dir)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, file := range files {
 | 
				
			||||||
 | 
							i, err := file.Info()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							path := path.Join(dir, i.Name())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if !file.IsDir() {
 | 
				
			||||||
 | 
								c.file(path)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								c.dir(path)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c Cater) file(filePath string) error {
 | 
				
			||||||
 | 
						file, err := os.Open(filePath)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer file.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// read file into strings.Builder
 | 
				
			||||||
 | 
						var sb strings.Builder
 | 
				
			||||||
 | 
						reader := bufio.NewReader(file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							line, err := reader.ReadString('\n')
 | 
				
			||||||
 | 
							if err != nil && err != io.EOF {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							sb.WriteString(line)
 | 
				
			||||||
 | 
							if err == io.EOF {
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c[filePath] = sb.String()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,39 +0,0 @@
 | 
				
			|||||||
package cat
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (c Cater) ToMarkdown() string {
 | 
					 | 
				
			||||||
	var sb strings.Builder
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	write := func(e entry, lvl int) {
 | 
					 | 
				
			||||||
		for range lvl {
 | 
					 | 
				
			||||||
			sb.WriteString("#")
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		sb.WriteString(fmt.Sprintf(" %s (`%s`)\n", e.name, e.fqname))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if len(e.content) > 0 {
 | 
					 | 
				
			||||||
			prts := strings.Split(e.name, ".")
 | 
					 | 
				
			||||||
			sb.WriteString(
 | 
					 | 
				
			||||||
				fmt.Sprintf(
 | 
					 | 
				
			||||||
					"```%s\n%s\n```\n\n",
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					prts[len(prts)-1],
 | 
					 | 
				
			||||||
					strings.ReplaceAll(
 | 
					 | 
				
			||||||
						e.content,
 | 
					 | 
				
			||||||
						"```",
 | 
					 | 
				
			||||||
						"\\`\\`\\`",
 | 
					 | 
				
			||||||
					),
 | 
					 | 
				
			||||||
				),
 | 
					 | 
				
			||||||
			)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, e := range c {
 | 
					 | 
				
			||||||
		e.traverse(1, write)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return sb.String()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,81 +0,0 @@
 | 
				
			|||||||
package cat
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"bufio"
 | 
					 | 
				
			||||||
	"io"
 | 
					 | 
				
			||||||
	"os"
 | 
					 | 
				
			||||||
	"path"
 | 
					 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
	"unicode/utf8"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (c Cater) dir(dir string) (e entry, err error) {
 | 
					 | 
				
			||||||
	files, err := os.ReadDir(dir)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	e.fqname = dir
 | 
					 | 
				
			||||||
	e.name = name(dir)
 | 
					 | 
				
			||||||
	e.children = []entry{}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, file := range files {
 | 
					 | 
				
			||||||
		i, err := file.Info()
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return e, err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		path := path.Join(dir, i.Name())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		var ent entry
 | 
					 | 
				
			||||||
		if !file.IsDir() {
 | 
					 | 
				
			||||||
			ent, err = c.file(path)
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			ent, err = c.dir(path)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return e, err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		e.children = append(e.children, ent)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (c Cater) file(filePath string) (e entry, err error) {
 | 
					 | 
				
			||||||
	file, err := os.Open(filePath)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer file.Close()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	e.fqname = filePath
 | 
					 | 
				
			||||||
	e.name = name(filePath)
 | 
					 | 
				
			||||||
	e.children = []entry{}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// read file into strings.Builder
 | 
					 | 
				
			||||||
	var sb strings.Builder
 | 
					 | 
				
			||||||
	reader := bufio.NewReader(file)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for {
 | 
					 | 
				
			||||||
		line, err := reader.ReadString('\n')
 | 
					 | 
				
			||||||
		if err != nil && err != io.EOF {
 | 
					 | 
				
			||||||
			return e, err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if !utf8.Valid([]byte(line)) {
 | 
					 | 
				
			||||||
			e.content = "blob\n"
 | 
					 | 
				
			||||||
			return e, nil
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		sb.WriteString(line)
 | 
					 | 
				
			||||||
		if err == io.EOF {
 | 
					 | 
				
			||||||
			break
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	e.content = sb.String()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func name(name string) string {
 | 
					 | 
				
			||||||
	ps := strings.Split(name, "/")
 | 
					 | 
				
			||||||
	return ps[len(ps)-1]
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,42 +0,0 @@
 | 
				
			|||||||
package cat
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (c Cater) ToTypst() string {
 | 
					 | 
				
			||||||
	var sb strings.Builder
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	write := func(e entry, lvl int) {
 | 
					 | 
				
			||||||
		for range lvl {
 | 
					 | 
				
			||||||
			sb.WriteString("=")
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		sb.WriteString(fmt.Sprintf(" %s (`%s`)\n", e.name, e.fqname))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if len(e.content) > 0 {
 | 
					 | 
				
			||||||
			prts := strings.Split(e.name, ".")
 | 
					 | 
				
			||||||
			sb.WriteString(
 | 
					 | 
				
			||||||
				fmt.Sprintf(
 | 
					 | 
				
			||||||
					"```%s\n%s\n```\n\n",
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					prts[len(prts)-1],
 | 
					 | 
				
			||||||
					strings.ReplaceAll(
 | 
					 | 
				
			||||||
						e.content,
 | 
					 | 
				
			||||||
						"```",
 | 
					 | 
				
			||||||
						"\\`\\`\\`",
 | 
					 | 
				
			||||||
					),
 | 
					 | 
				
			||||||
				),
 | 
					 | 
				
			||||||
			)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, e := range c {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		sb.WriteString("= Export\n")
 | 
					 | 
				
			||||||
		sb.WriteString("#outline()\n")
 | 
					 | 
				
			||||||
		e.traverse(1, write)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return sb.String()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,12 +1,9 @@
 | 
				
			|||||||
package ignore
 | 
					package ignore
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import "strings"
 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Filesystem struct{}
 | 
					type Filesystem struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (f Filesystem) Ignore(name string) bool {
 | 
					func (f Filesystem) Ignore(name string) bool {
 | 
				
			||||||
	parts := strings.Split(name, "/")
 | 
						return strings.Contains(name, "/.") || strings.HasPrefix(name, ".")
 | 
				
			||||||
	return strings.HasPrefix(parts[len(parts)-1], ".")
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user