mirror of
https://github.com/skidoodle/ctx.git
synced 2026-04-28 11:17:42 +02:00
220 lines
3.3 KiB
Go
220 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
configDirName = "ctx"
|
|
ignoreFileName = "ignore"
|
|
)
|
|
|
|
const defaultIgnoreText = `
|
|
.git
|
|
.svn
|
|
.hg
|
|
.gitignore
|
|
.idea
|
|
.vscode
|
|
.vs
|
|
.settings
|
|
.classpath
|
|
.project
|
|
.DS_Store
|
|
*.swp
|
|
*.swo
|
|
*.tmp
|
|
*.bak
|
|
node_modules
|
|
bower_components
|
|
jspm_packages
|
|
vendor
|
|
.venv
|
|
venv
|
|
env
|
|
.env
|
|
__pycache__
|
|
.tox
|
|
.mypy_cache
|
|
.pytest_cache
|
|
.npm
|
|
.yarn
|
|
.pnpm-store
|
|
dist
|
|
build
|
|
out
|
|
target
|
|
bin
|
|
obj
|
|
cmake-build-*
|
|
package-lock.json
|
|
yarn.lock
|
|
pnpm-lock.yaml
|
|
bun.lockb
|
|
go.sum
|
|
Cargo.lock
|
|
poetry.lock
|
|
Pipfile.lock
|
|
*.exe
|
|
*.dll
|
|
*.so
|
|
*.dylib
|
|
*.test
|
|
*.class
|
|
*.jar
|
|
*.war
|
|
*.ear
|
|
*.o
|
|
*.obj
|
|
*.sqlite
|
|
*.db
|
|
*.sqlitedb
|
|
*.zip
|
|
*.tar
|
|
*.tar.gz
|
|
*.tgz
|
|
*.rar
|
|
*.7z
|
|
*.jpg
|
|
*.jpeg
|
|
*.png
|
|
*.gif
|
|
*.ico
|
|
*.svg
|
|
*.webp
|
|
*.mp3
|
|
*.mp4
|
|
*.mov
|
|
*.avi
|
|
*.pdf
|
|
*.doc
|
|
*.docx
|
|
*.pyc
|
|
*.pyo
|
|
*.pyd
|
|
*.egg-info
|
|
*_templ.go
|
|
`
|
|
|
|
type Config struct {
|
|
ExactIgnores map[string]struct{}
|
|
ExtIgnores map[string]struct{}
|
|
ComplexGlobs []string
|
|
}
|
|
|
|
func parseConfig(text string) *Config {
|
|
cfg := &Config{
|
|
ExactIgnores: make(map[string]struct{}),
|
|
ExtIgnores: make(map[string]struct{}),
|
|
}
|
|
|
|
scanner := bufio.NewScanner(strings.NewReader(text))
|
|
for scanner.Scan() {
|
|
line := strings.TrimSpace(scanner.Text())
|
|
if line == "" || strings.HasPrefix(line, "#") {
|
|
continue
|
|
}
|
|
|
|
if strings.HasPrefix(line, "*.") && strings.Count(line, "*") == 1 && !strings.Contains(line, "/") {
|
|
ext := strings.TrimPrefix(line, "*")
|
|
cfg.ExtIgnores[ext] = struct{}{}
|
|
} else if !strings.ContainsAny(line, "*?[]") && !strings.Contains(line, "/") {
|
|
cfg.ExactIgnores[line] = struct{}{}
|
|
} else {
|
|
cfg.ComplexGlobs = append(cfg.ComplexGlobs, line)
|
|
}
|
|
}
|
|
return cfg
|
|
}
|
|
|
|
func (c *Config) IsIgnored(name, relPath string, isDir bool) bool {
|
|
if _, ok := c.ExactIgnores[name]; ok {
|
|
return true
|
|
}
|
|
|
|
if !isDir {
|
|
ext := filepath.Ext(name)
|
|
if _, ok := c.ExtIgnores[ext]; ok {
|
|
return true
|
|
}
|
|
}
|
|
|
|
checkPath := filepath.ToSlash(relPath)
|
|
|
|
for _, p := range c.ComplexGlobs {
|
|
cleanPattern := strings.TrimSuffix(p, "/")
|
|
|
|
if matched, _ := filepath.Match(cleanPattern, name); matched {
|
|
return true
|
|
}
|
|
|
|
if matched, _ := filepath.Match(cleanPattern, checkPath); matched {
|
|
return true
|
|
}
|
|
|
|
if strings.HasPrefix(checkPath, cleanPattern+"/") {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func getConfigPath() (string, error) {
|
|
configDir, err := os.UserConfigDir()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
appDir := filepath.Join(configDir, configDirName)
|
|
if err := os.MkdirAll(appDir, 0755); err != nil {
|
|
return "", err
|
|
}
|
|
return filepath.Join(appDir, ignoreFileName), nil
|
|
}
|
|
|
|
func loadConfig() (*Config, error) {
|
|
path, err := getConfigPath()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if _, err := os.Stat(path); os.IsNotExist(err) {
|
|
if err := os.WriteFile(path, []byte(defaultIgnoreText), 0644); err != nil {
|
|
return nil, err
|
|
}
|
|
return parseConfig(defaultIgnoreText), nil
|
|
}
|
|
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return parseConfig(string(data)), nil
|
|
}
|
|
|
|
func openConfigFile() error {
|
|
path, err := getConfigPath()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := os.Stat(path); os.IsNotExist(err) {
|
|
_, _ = loadConfig()
|
|
}
|
|
|
|
var cmd *exec.Cmd
|
|
switch runtime.GOOS {
|
|
case "windows":
|
|
cmd = exec.Command("cmd", "/c", "start", "", path)
|
|
case "darwin":
|
|
cmd = exec.Command("open", path)
|
|
default:
|
|
cmd = exec.Command("xdg-open", path)
|
|
}
|
|
return cmd.Start()
|
|
}
|