github.com/xztaityozx/sel@v1.1.10/internal/option/option.go (about) 1 package option 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 "text/template" 8 9 "github.com/spf13/viper" 10 ) 11 12 // Option is commandline options 13 type Option struct { 14 // --input/output-delimiter option 15 DelimiterOption 16 // -f, --input-files option 17 InputFiles 18 // XSV support 19 Xsv 20 // --template 21 Template *template.Template 22 } 23 24 // DelimiterOption is setting for --input/output-delimiter option 25 type DelimiterOption struct { 26 // --input-delimiter 27 InputDelimiter string 28 // --output-delimiter 29 OutPutDelimiter string 30 // --remove-empty 31 RemoveEmpty bool 32 // --use-regexp 33 UseRegexp bool 34 // --split-before 35 SplitBefore bool 36 } 37 38 // InputFiles is setting for -f, --input-files option 39 type InputFiles struct { 40 Files []string 41 } 42 43 // Enumerate /path/to/input/files 44 func (ifs InputFiles) Enumerate() ([]string, error) { 45 if ifs.Files == nil || len(ifs.Files) == 0 { 46 return nil, fmt.Errorf("there are no files") 47 } 48 49 var rt []string 50 51 for _, v := range ifs.Files { 52 expanded, err := filepath.Glob(v) 53 if err != nil { 54 return nil, err 55 } 56 57 for _, p := range expanded { 58 fi, err := os.Stat(p) 59 if err != nil { 60 return nil, err 61 } else if !fi.Mode().IsRegular() { 62 return nil, fmt.Errorf("%s is not regular file", p) 63 } else if fi.IsDir() { 64 return nil, fmt.Errorf("%s is directory", p) 65 } 66 67 rt = append(rt, p) 68 } 69 } 70 71 if len(rt) == 0 { 72 return nil, fmt.Errorf("no files(path/glob is wrong?)") 73 } 74 75 return rt, nil 76 } 77 78 const ( 79 NameInputDelimiter = "input-delimiter" 80 NameOutPutDelimiter = "output-delimiter" 81 NameRemoveEmpty = "remove-empty" 82 NameUseRegexp = "use-regexp" 83 NameInputFiles = "input-files" 84 NameSplitBefore = "split-before" 85 NameFieldSplit = "field-split" 86 NameCsv = "csv" 87 NameTsv = "tsv" 88 NameTemplate = "template" 89 90 DefaultTemplate = "" 91 ) 92 93 type SplitStrategy int 94 95 func GetOptionNames() []string { 96 return []string{ 97 NameInputFiles, 98 NameInputDelimiter, 99 NameOutPutDelimiter, 100 NameUseRegexp, 101 NameRemoveEmpty, 102 NameSplitBefore, 103 NameFieldSplit, 104 NameCsv, 105 NameTsv, 106 NameTemplate, 107 } 108 } 109 110 // Xsv is option group for xsv support 111 type Xsv struct { 112 Csv bool 113 Tsv bool 114 } 115 116 func (x Xsv) IsXsv() (bool, rune) { 117 if x.Csv { 118 return true, ',' 119 } else if x.Tsv { 120 return true, '\t' 121 } else { 122 return false, ',' 123 } 124 } 125 126 // NewOption は viper.Viper からフラグの値を取り出して Option を作って返す 127 func NewOption(v *viper.Viper) (Option, error) { 128 129 // 入力のデリミターの受け取り、NameFieldSplit が指定されているときは `\s+` で上書き 130 inputDelimiter := v.GetString(NameInputDelimiter) 131 if v.GetBool(NameFieldSplit) { 132 inputDelimiter = `\s+` 133 } 134 135 // デリミターを正規表現として処理するかどうか。NameFieldSplit が指定されているときは強制的にON 136 useRegexp := v.GetBool(NameUseRegexp) || v.GetBool(NameFieldSplit) 137 138 // --templateオプションで出力のフォーマットを指定するやつ 139 var tmpl *template.Template 140 if v.GetString(NameTemplate) != DefaultTemplate { 141 var err error 142 tmpl, err = parseTemplate(v.GetString(NameTemplate)) 143 if err != nil { 144 return Option{}, err 145 } 146 } 147 148 return Option{ 149 DelimiterOption: DelimiterOption{ 150 InputDelimiter: inputDelimiter, 151 OutPutDelimiter: v.GetString(NameOutPutDelimiter), 152 RemoveEmpty: v.GetBool(NameRemoveEmpty), 153 UseRegexp: useRegexp, 154 SplitBefore: v.GetBool(NameSplitBefore), 155 }, 156 InputFiles: InputFiles{v.GetStringSlice(NameInputFiles)}, 157 Xsv: Xsv{ 158 Csv: v.GetBool(NameCsv), 159 Tsv: v.GetBool(NameTsv), 160 }, 161 Template: tmpl, 162 }, nil 163 } 164 165 func parseTemplate(input string) (*template.Template, error) { 166 var result string 167 168 // input ::= char | marker | input 169 // char ::= 任意の文字 170 // marker ::= {} 171 cnt := 0 172 for i := 0; i < len(input); i++ { 173 switch { 174 case input[i] == '{' && i+1 < len(input) && input[i+1] == '}': 175 result += fmt.Sprintf("{{ index . %d }}", cnt) 176 cnt++ 177 i++ 178 default: 179 result += string(input[i]) 180 } 181 } 182 183 return template.New("output").Parse(result) 184 }