func (m MapStringString) Repr(indent int) string { var builder MapReprBuilder builder.Indent = indent for k, v := range m { builder.WritePair(parse.Quote(k), parse.Quote(v)) } return builder.String() }
// Search tries to resolve an external command and return the full (possibly // relative) path. func (ev *Evaler) Search(exe string) (string, error) { if DontSearch(exe) { if IsExecutable(exe) { return exe, nil } return "", fmt.Errorf("external command %s not executable", parse.Quote(exe)) } for _, p := range ev.searchPaths { full := p + "/" + exe if IsExecutable(full) { return full, nil } } return "", fmt.Errorf("external command %s not found", parse.Quote(exe)) }
// Search tries to resolve an external command and return the full (possibly // relative) path. func (ev *Evaler) Search(exe string) (string, error) { path, err := util.Search(ev.searchPaths(), exe) if err != nil { return "", fmt.Errorf("search %s: %s", parse.Quote(exe), err.Error()) } return path, nil }
func (bt BindingTable) Repr(indent int) string { var builder eval.MapReprBuilder builder.Indent = indent for k, v := range bt.inner { builder.WritePair(parse.Quote(k.String()), v.Repr(eval.IncIndent(indent, 1))) } return builder.String() }
func (s *Struct) Repr(indent int) string { var builder MapReprBuilder builder.Indent = indent for i, name := range s.FieldNames { builder.WritePair(parse.Quote(name), s.Fields[i].Get().Repr(indent+1)) } return builder.String() }
func (e Error) Repr(indent int) string { if e.Inner == nil { return "$ok" } if r, ok := e.Inner.(Reprer); ok { return r.Repr(indent) } return "?(error " + parse.Quote(e.Inner.Error()) + ")" }
func (os *OptSet) Pick(opts map[string]Value) ([]Value, error) { vs := make([]Value, len(os.optSpecs)) for k, v := range opts { if i, ok := os.indices[k]; ok { vs[i] = v } else { return nil, errors.New("unknown option " + parse.Quote(k)) } } for i, optSpec := range os.optSpecs { if vs[i] == nil { vs[i] = optSpec.Default } } return vs, nil }
func (exit ExternalCmdExit) Error() string { ws := exit.WaitStatus quotedName := parse.Quote(exit.CmdName) switch { case ws.Exited(): return quotedName + " exited with " + strconv.Itoa(ws.ExitStatus()) case ws.Signaled(): msg := quotedName + " killed by signal " + ws.Signal().String() if ws.CoreDump() { msg += " (core dumped)" } return msg case ws.Stopped(): msg := quotedName + " stopped by signal " + fmt.Sprintf("%s (pid=%d)", ws.StopSignal(), exit.Pid) trap := ws.TrapCause() if trap != -1 { msg += fmt.Sprintf(" (trapped %v)", trap) } return msg default: return fmt.Sprint(quotedName, " has unknown WaitStatus ", ws) } }
func quote(s string) string { return parse.Quote(s) }
func complGetopt(ec *eval.EvalCtx, elemsv eval.IteratorValue, optsv eval.IteratorValue, argsv eval.IteratorValue) { var ( elems []string opts []*getopt.Option args []eval.FnValue variadic bool ) // Convert arguments. elemsv.Iterate(func(v eval.Value) bool { elem, ok := v.(eval.String) if !ok { throwf("arg should be string, got %s", v.Kind()) } elems = append(elems, string(elem)) return true }) optsv.Iterate(func(v eval.Value) bool { m, ok := v.(eval.MapLike) if !ok { throwf("opt should be map-like, got %s", v.Kind()) } opt := &getopt.Option{} vshort := maybeIndex(m, eval.String("short")) if vshort != nil { sv, ok := vshort.(eval.String) if !ok { throwf("short option should be string, got %s", vshort.Kind()) } s := string(sv) r, size := utf8.DecodeRuneInString(s) if r == utf8.RuneError || size != len(s) { throwf("short option should be exactly one rune, got %v", parse.Quote(s)) } opt.Short = r } vlong := maybeIndex(m, eval.String("long")) if vlong != nil { s, ok := vlong.(eval.String) if !ok { throwf("long option should be string, got %s", vlong.Kind()) } opt.Long = string(s) } if vshort == nil && vlong == nil { throwf("opt should have at least one of short and long as keys") } // TODO support &desc opts = append(opts, opt) return true }) argsv.Iterate(func(v eval.Value) bool { sv, ok := v.(eval.String) if ok { if string(sv) == "..." { variadic = true return true } throwf("string except for ... not allowed as argument handler, got %s", parse.Quote(string(sv))) } arg, ok := v.(eval.FnValue) if !ok { throwf("argument handler should be fn, got %s", v.Kind()) } args = append(args, arg) return true }) // TODO Configurable config g := getopt.Getopt{opts, getopt.GNUGetoptLong} _, _, ctx := g.Parse(elems) out := ec.OutputChan() _ = variadic // XXX switch ctx.Type { case getopt.NewOptionOrArgument, getopt.Argument: case getopt.NewOption: for _, opt := range opts { if opt.Short != 0 { out <- eval.String("-" + string(opt.Short)) } if opt.Long != "" { out <- eval.String("--" + opt.Long) } } case getopt.NewLongOption: for _, opt := range opts { if opt.Long != "" { out <- eval.String("--" + opt.Long) } } case getopt.LongOption: for _, opt := range opts { if strings.HasPrefix(opt.Long, ctx.Text) { out <- eval.String("--" + opt.Long) } } case getopt.ChainShortOption: for _, opt := range opts { if opt.Short != 0 { // XXX loses chained options out <- eval.String("-" + string(opt.Short)) } } case getopt.OptionArgument: } }
func complGetopt(ec *eval.EvalCtx, elemsv eval.IteratorValue, optsv eval.IteratorValue, argsv eval.IteratorValue) { var ( elems []string opts []*getopt.Option args []eval.FnValue variadic bool ) desc := make(map[*getopt.Option]string) // Convert arguments. elemsv.Iterate(func(v eval.Value) bool { elem, ok := v.(eval.String) if !ok { throwf("arg should be string, got %s", v.Kind()) } elems = append(elems, string(elem)) return true }) optsv.Iterate(func(v eval.Value) bool { m, ok := v.(eval.MapLike) if !ok { throwf("opt should be map-like, got %s", v.Kind()) } get := func(ks string) (string, bool) { kv := eval.String(ks) if !m.HasKey(kv) { return "", false } vv := m.IndexOne(kv) if vs, ok := vv.(eval.String); ok { return string(vs), true } else { throwf("%s should be string, got %s", ks, vs.Kind()) panic("unreachable") } } opt := &getopt.Option{} if s, ok := get("short"); ok { r, size := utf8.DecodeRuneInString(s) if r == utf8.RuneError || size != len(s) { throwf("short option should be exactly one rune, got %v", parse.Quote(s)) } opt.Short = r } if s, ok := get("long"); ok { opt.Long = s } if opt.Short == 0 && opt.Long == "" { throwf("opt should have at least one of short and long forms") } if s, ok := get("desc"); ok { desc[opt] = s } opts = append(opts, opt) return true }) argsv.Iterate(func(v eval.Value) bool { sv, ok := v.(eval.String) if ok { if string(sv) == "..." { variadic = true return true } throwf("string except for ... not allowed as argument handler, got %s", parse.Quote(string(sv))) } arg, ok := v.(eval.FnValue) if !ok { throwf("argument handler should be fn, got %s", v.Kind()) } args = append(args, arg) return true }) // TODO Configurable config g := getopt.Getopt{opts, getopt.GNUGetoptLong} _, parsedArgs, ctx := g.Parse(elems) out := ec.OutputChan() putShortOpt := func(opt *getopt.Option) { c := &candidate{text: "-" + string(opt.Short)} if d, ok := desc[opt]; ok { c.display.text = c.text + " (" + d + ")" } out <- c } putLongOpt := func(opt *getopt.Option) { c := &candidate{text: "--" + string(opt.Long)} if d, ok := desc[opt]; ok { c.display.text = c.text + " (" + d + ")" } out <- c } switch ctx.Type { case getopt.NewOptionOrArgument, getopt.Argument: // Find argument completer var argCompl eval.FnValue if len(parsedArgs) < len(args) { argCompl = args[len(parsedArgs)] } else if variadic { argCompl = args[len(args)-1] } if argCompl != nil { cands, err := callFnForCandidates(argCompl, ec.Evaler, []string{ctx.Text}) maybeThrow(err) for _, cand := range cands { out <- cand } } // TODO Notify that there is no suitable argument completer case getopt.NewOption: for _, opt := range opts { if opt.Short != 0 { putShortOpt(opt) } if opt.Long != "" { putLongOpt(opt) } } case getopt.NewLongOption: for _, opt := range opts { if opt.Long != "" { putLongOpt(opt) } } case getopt.LongOption: for _, opt := range opts { if strings.HasPrefix(opt.Long, ctx.Text) { putLongOpt(opt) } } case getopt.ChainShortOption: for _, opt := range opts { if opt.Short != 0 { // XXX loses chained options putShortOpt(opt) } } case getopt.OptionArgument: } }
func (loc *location) Show(i, width int) styled { cand := loc.candidates[i] return unstyled(TrimWcWidth(fmt.Sprintf("%4.0f %s", cand.Score, parse.Quote(cand.Path)), width)) }
func navInsertSelectedAndQuit(ed *Editor) { ed.insertAtDot(parse.Quote(ed.navigation.current.selectedName()) + " ") ed.mode = &ed.insert }
func (s String) Repr() string { return parse.Quote(string(s)) }
func navInsertSelected(ed *Editor) { ed.insertAtDot(parse.Quote(ed.navigation.current.selectedName()) + " ") }
func (loc *location) Show(i, width int) styled { cand := loc.filtered[i] return unstyled(util.TrimWcwidth(fmt.Sprintf("%4.0f %s", cand.Score, parse.Quote(cand.Path)), width)) }
// ReadLine reads a line interactively. func (ed *Editor) ReadLine() (line string, err error) { e := ed.startReadLine() if e != nil { return "", e } defer ed.finishReadLine(func(e error) { if e != nil { err = util.CatError(err, e) } }) ed.mode = &ed.insert isExternalCh := make(chan map[string]bool, 1) go getIsExternal(ed.evaler, isExternalCh) ed.writer.resetOldBuf() go ed.reader.Run() fullRefresh := false beforeReadLines := ed.beforeReadLine.Get().(eval.ListLike) beforeReadLines.Iterate(func(f eval.Value) bool { ed.CallFn(f.(eval.FnValue)) return true }) MainLoop: for { ed.prompt = callFnForPrompt(ed, ed.ps1.Get().(eval.Fn)) ed.rprompt = callFnForPrompt(ed, ed.rps1.Get().(eval.Fn)) err := ed.refresh(fullRefresh, true) fullRefresh = false if err != nil { return "", err } ed.tips = nil select { case m := <-isExternalCh: ed.isExternal = m case sig := <-ed.sigs: // TODO(xiaq): Maybe support customizable handling of signals switch sig { case syscall.SIGINT: // Start over ed.editorState = editorState{ savedTermios: ed.savedTermios, isExternal: ed.isExternal, } ed.mode = &ed.insert goto MainLoop case syscall.SIGWINCH: fullRefresh = true continue MainLoop case syscall.SIGCHLD: // ignore default: ed.addTip("ignored signal %s", sig) } case err := <-ed.reader.ErrorChan(): ed.Notify("reader error: %s", err.Error()) case mouse := <-ed.reader.MouseChan(): ed.addTip("mouse: %+v", mouse) case <-ed.reader.CPRChan(): // Ignore CPR case b := <-ed.reader.PasteChan(): if !b { continue } var buf bytes.Buffer timer := time.NewTimer(EscSequenceTimeout) paste: for { // XXX Should also select on other chans. However those chans // will be unified (agina) into one later so we don't do // busywork here. select { case k := <-ed.reader.KeyChan(): if k.Mod != 0 { ed.Notify("function key within paste") break paste } buf.WriteRune(k.Rune) timer.Reset(EscSequenceTimeout) case b := <-ed.reader.PasteChan(): if !b { break paste } case <-timer.C: ed.Notify("bracketed paste timeout") break paste } } topaste := buf.String() if ed.insert.quotePaste { topaste = parse.Quote(topaste) } ed.insertAtDot(topaste) case k := <-ed.reader.KeyChan(): lookupKey: keyBinding, ok := keyBindings[ed.mode.Mode()] if !ok { ed.addTip("No binding for current mode") continue } fn, bound := keyBinding[k] if !bound { fn = keyBinding[Default] } ed.insert.insertedLiteral = false ed.lastKey = k ed.CallFn(fn) if ed.insert.insertedLiteral { ed.insert.literalInserts++ } else { ed.insert.literalInserts = 0 } act := ed.nextAction ed.nextAction = action{} switch act.typ { case noAction: continue case reprocessKey: err = ed.refresh(false, true) if err != nil { return "", err } goto lookupKey case exitReadLine: if act.returnErr == nil && act.returnLine != "" { ed.appendHistory(act.returnLine) } return act.returnLine, act.returnErr } } } }
// WrapFn wraps an inner function into one suitable as a builtin function. It // generates argument checking and conversion code according to the signature of // the inner function and option specifications. The inner function must accept // EvalCtx* as the first argument, followed by options, followed by arguments. func WrapFn(inner interface{}, optSpecs ...OptSpec) func(*EvalCtx, []Value, map[string]Value) { funcType := reflect.TypeOf(inner) if funcType.In(0) != evalCtxType { panic("bad func to wrap, first argument not *EvalCtx") } nopts := len(optSpecs) optsTo := nopts + 1 optSet := NewOptSet(optSpecs...) // Range occupied by fixed arguments in the argument list to inner. fixedArgsFrom, fixedArgsTo := optsTo, funcType.NumIn() isVariadic := funcType.IsVariadic() hasOptionalIterate := false var variadicType reflect.Type if isVariadic { fixedArgsTo-- variadicType = funcType.In(funcType.NumIn() - 1).Elem() if !supportedArgType(variadicType) { panic(fmt.Sprintf("bad func to wrap, variadic argument type %s unsupported", variadicType)) } } else if funcType.In(funcType.NumIn()-1) == iterateType { fixedArgsTo-- hasOptionalIterate = true } for i := 1; i < fixedArgsTo; i++ { if !supportedArgType(funcType.In(i)) { panic(fmt.Sprintf("bad func to wrap, argument type %s unsupported", funcType.In(i))) } } nFixedArgs := fixedArgsTo - fixedArgsFrom return func(ec *EvalCtx, args []Value, opts map[string]Value) { // Check arity of arguments. if isVariadic { if len(args) < nFixedArgs { throw(fmt.Errorf("arity mismatch: want %d or more arguments, got %d", nFixedArgs, len(args))) } } else if hasOptionalIterate { if len(args) < nFixedArgs || len(args) > nFixedArgs+1 { throw(fmt.Errorf("arity mismatch: want %d or %d arguments, got %d", nFixedArgs, nFixedArgs+1, len(args))) } } else if len(args) != nFixedArgs { throw(fmt.Errorf("arity mismatch: want %d arguments, got %d", nFixedArgs, len(args))) } convertedArgs := make([]reflect.Value, 1+nopts+len(args)) convertedArgs[0] = reflect.ValueOf(ec) // Convert and fill options. var err error optValues := optSet.MustPick(opts) for i, v := range optValues { convertedArgs[1+i], err = convertArg(v, funcType.In(1+i)) if err != nil { throw(errors.New("bad option " + parse.Quote(optSet.optSpecs[i].Name) + ": " + err.Error())) } } // Convert and fill fixed arguments. for i, arg := range args[:nFixedArgs] { convertedArgs[fixedArgsFrom+i], err = convertArg(arg, funcType.In(fixedArgsFrom+i)) if err != nil { throw(errors.New("bad argument: " + err.Error())) } } if isVariadic { for i, arg := range args[nFixedArgs:] { convertedArgs[fixedArgsTo+i], err = convertArg(arg, variadicType) if err != nil { throw(errors.New("bad argument: " + err.Error())) } } } else if hasOptionalIterate { var iterate func(func(Value)) if len(args) == nFixedArgs { // No Iterator specified in arguments. Use input. // Since convertedArgs was created according to the size of the // actual argument list, we now an empty element to make room // for this additional iterator argument. convertedArgs = append(convertedArgs, reflect.Value{}) iterate = ec.IterateInputs } else { iterator, ok := args[nFixedArgs].(Iterator) if !ok { throw(errors.New("bad argument: need iterator, got " + args[nFixedArgs].Kind())) } iterate = func(f func(Value)) { iterator.Iterate(func(v Value) bool { f(v) return true }) } } convertedArgs[fixedArgsTo] = reflect.ValueOf(iterate) } reflect.ValueOf(inner).Call(convertedArgs) } }
func (s *styled) Repr(indent int) string { return "(le:styled " + parse.Quote(s.text) + " " + parse.Quote(s.styles.String()) + ")" }
func (e ExternalCmd) Repr(int) string { return "<external " + parse.Quote(e.Name) + ">" }
func (c *candidate) Repr(int) string { return fmt.Sprintf("(le:candidate %s %s %s)", parse.Quote(c.text), c.display.Repr(eval.NoPretty), parse.Quote(c.suffix)) }