func defaultOptions() *Options { return &Options{ Fuzzy: true, FuzzyAlgo: algo.FuzzyMatchV2, Extended: true, Case: CaseSmart, Normalize: true, Nth: make([]Range, 0), WithNth: make([]Range, 0), Delimiter: Delimiter{}, Sort: 1000, Tac: false, Criteria: []criterion{byScore, byLength}, Multi: false, Ansi: false, Mouse: true, Theme: tui.EmptyTheme(), Black: false, Bold: true, MinHeight: 10, Reverse: false, Cycle: false, Hscroll: true, HscrollOff: 10, FileWord: false, InlineInfo: false, JumpLabels: defaultJumpLabels, Prompt: "> ", Query: "", Select1: false, Exit0: false, Filter: nil, ToggleSort: false, Expect: make(map[int]string), Keymap: make(map[int]actionType), Execmap: make(map[int]string), Preview: previewOpts{"", posRight, sizeSpec{50, true}, false, false}, PrintQuery: false, ReadZero: false, Printer: func(str string) { fmt.Println(str) }, Sync: false, History: nil, Header: make([]string, 0), HeaderLines: 0, Margin: defaultMargin(), Tabstop: 8, Version: false} }
func parseOptions(opts *Options, allArgs []string) { var historyMax int if opts.History == nil { historyMax = defaultHistoryMax } else { historyMax = opts.History.maxSize } setHistory := func(path string) { h, e := NewHistory(path, historyMax) if e != nil { errorExit(e.Error()) } opts.History = h } setHistoryMax := func(max int) { historyMax = max if historyMax < 1 { errorExit("history max must be a positive integer") } if opts.History != nil { opts.History.maxSize = historyMax } } validateJumpLabels := false for i := 0; i < len(allArgs); i++ { arg := allArgs[i] switch arg { case "-h", "--help": help(exitOk) case "-x", "--extended": opts.Extended = true case "-e", "--exact": opts.Fuzzy = false case "--extended-exact": // Note that we now don't have --no-extended-exact opts.Fuzzy = false opts.Extended = true case "+x", "--no-extended": opts.Extended = false case "+e", "--no-exact": opts.Fuzzy = true case "-q", "--query": opts.Query = nextString(allArgs, &i, "query string required") case "-f", "--filter": filter := nextString(allArgs, &i, "query string required") opts.Filter = &filter case "--algo": opts.FuzzyAlgo = parseAlgo(nextString(allArgs, &i, "algorithm required (v1|v2)")) case "--expect": opts.Expect = parseKeyChords(nextString(allArgs, &i, "key names required"), "key names required") case "--tiebreak": opts.Criteria = parseTiebreak(nextString(allArgs, &i, "sort criterion required")) case "--bind": parseKeymap(opts.Keymap, opts.Execmap, nextString(allArgs, &i, "bind expression required")) case "--color": spec := optionalNextString(allArgs, &i) if len(spec) == 0 { opts.Theme = tui.EmptyTheme() } else { opts.Theme = parseTheme(opts.Theme, spec) } case "--toggle-sort": parseToggleSort(opts.Keymap, nextString(allArgs, &i, "key name required")) case "-d", "--delimiter": opts.Delimiter = delimiterRegexp(nextString(allArgs, &i, "delimiter required")) case "-n", "--nth": opts.Nth = splitNth(nextString(allArgs, &i, "nth expression required")) case "--with-nth": opts.WithNth = splitNth(nextString(allArgs, &i, "nth expression required")) case "-s", "--sort": opts.Sort = optionalNumeric(allArgs, &i) case "+s", "--no-sort": opts.Sort = 0 case "--tac": opts.Tac = true case "--no-tac": opts.Tac = false case "-i": opts.Case = CaseIgnore case "+i": opts.Case = CaseRespect case "-m", "--multi": opts.Multi = true case "+m", "--no-multi": opts.Multi = false case "--ansi": opts.Ansi = true case "--no-ansi": opts.Ansi = false case "--no-mouse": opts.Mouse = false case "+c", "--no-color": opts.Theme = nil case "+2", "--no-256": opts.Theme = tui.Default16 case "--black": opts.Black = true case "--no-black": opts.Black = false case "--bold": opts.Bold = true case "--no-bold": opts.Bold = false case "--reverse": opts.Reverse = true case "--no-reverse": opts.Reverse = false case "--cycle": opts.Cycle = true case "--no-cycle": opts.Cycle = false case "--hscroll": opts.Hscroll = true case "--no-hscroll": opts.Hscroll = false case "--hscroll-off": opts.HscrollOff = nextInt(allArgs, &i, "hscroll offset required") case "--inline-info": opts.InlineInfo = true case "--no-inline-info": opts.InlineInfo = false case "--jump-labels": opts.JumpLabels = nextString(allArgs, &i, "label characters required") validateJumpLabels = true case "-1", "--select-1": opts.Select1 = true case "+1", "--no-select-1": opts.Select1 = false case "-0", "--exit-0": opts.Exit0 = true case "+0", "--no-exit-0": opts.Exit0 = false case "--read0": opts.ReadZero = true case "--no-read0": opts.ReadZero = false case "--print0": opts.Printer = func(str string) { fmt.Print(str, "\x00") } case "--no-print0": opts.Printer = func(str string) { fmt.Println(str) } case "--print-query": opts.PrintQuery = true case "--no-print-query": opts.PrintQuery = false case "--prompt": opts.Prompt = nextString(allArgs, &i, "prompt string required") case "--sync": opts.Sync = true case "--no-sync": opts.Sync = false case "--async": opts.Sync = false case "--no-history": opts.History = nil case "--history": setHistory(nextString(allArgs, &i, "history file path required")) case "--history-size": setHistoryMax(nextInt(allArgs, &i, "history max size required")) case "--no-header": opts.Header = []string{} case "--no-header-lines": opts.HeaderLines = 0 case "--header": opts.Header = strLines(nextString(allArgs, &i, "header string required")) case "--header-lines": opts.HeaderLines = atoi( nextString(allArgs, &i, "number of header lines required")) case "--preview": opts.Preview.command = nextString(allArgs, &i, "preview command required") case "--no-preview": opts.Preview.command = "" case "--preview-window": parsePreviewWindow(&opts.Preview, nextString(allArgs, &i, "preview window layout required: [up|down|left|right][:SIZE[%]]")) case "--no-margin": opts.Margin = defaultMargin() case "--margin": opts.Margin = parseMargin( nextString(allArgs, &i, "margin required (TRBL / TB,RL / T,RL,B / T,R,B,L)")) case "--tabstop": opts.Tabstop = nextInt(allArgs, &i, "tab stop required") case "--version": opts.Version = true default: if match, value := optString(arg, "--algo="); match { opts.FuzzyAlgo = parseAlgo(value) } else if match, value := optString(arg, "-q", "--query="); match { opts.Query = value } else if match, value := optString(arg, "-f", "--filter="); match { opts.Filter = &value } else if match, value := optString(arg, "-d", "--delimiter="); match { opts.Delimiter = delimiterRegexp(value) } else if match, value := optString(arg, "--prompt="); match { opts.Prompt = value } else if match, value := optString(arg, "-n", "--nth="); match { opts.Nth = splitNth(value) } else if match, value := optString(arg, "--with-nth="); match { opts.WithNth = splitNth(value) } else if match, _ := optString(arg, "-s", "--sort="); match { opts.Sort = 1 // Don't care } else if match, value := optString(arg, "--toggle-sort="); match { parseToggleSort(opts.Keymap, value) } else if match, value := optString(arg, "--expect="); match { opts.Expect = parseKeyChords(value, "key names required") } else if match, value := optString(arg, "--tiebreak="); match { opts.Criteria = parseTiebreak(value) } else if match, value := optString(arg, "--color="); match { opts.Theme = parseTheme(opts.Theme, value) } else if match, value := optString(arg, "--bind="); match { parseKeymap(opts.Keymap, opts.Execmap, value) } else if match, value := optString(arg, "--history="); match { setHistory(value) } else if match, value := optString(arg, "--history-size="); match { setHistoryMax(atoi(value)) } else if match, value := optString(arg, "--header="); match { opts.Header = strLines(value) } else if match, value := optString(arg, "--header-lines="); match { opts.HeaderLines = atoi(value) } else if match, value := optString(arg, "--preview="); match { opts.Preview.command = value } else if match, value := optString(arg, "--preview-window="); match { parsePreviewWindow(&opts.Preview, value) } else if match, value := optString(arg, "--margin="); match { opts.Margin = parseMargin(value) } else if match, value := optString(arg, "--tabstop="); match { opts.Tabstop = atoi(value) } else if match, value := optString(arg, "--hscroll-off="); match { opts.HscrollOff = atoi(value) } else if match, value := optString(arg, "--jump-labels="); match { opts.JumpLabels = value } else { errorExit("unknown option: " + arg) } } } if opts.HeaderLines < 0 { errorExit("header lines must be a non-negative integer") } if opts.HscrollOff < 0 { errorExit("hscroll offset must be a non-negative integer") } if opts.Tabstop < 1 { errorExit("tab stop must be a positive integer") } if len(opts.JumpLabels) == 0 { errorExit("empty jump labels") } if validateJumpLabels { for _, r := range opts.JumpLabels { if r < 32 || r > 126 { errorExit("non-ascii jump labels are not allowed") } } } }