Loading dclish/completer.go +37 −4 Original line number Diff line number Diff line Loading @@ -10,25 +10,34 @@ import ( type Completer struct { commands []string flags map[string]FlagTable argCompleters map[string]CompleterFunc } // NewCompleter creates a new completer from a CommandTable. func NewCompleter(ct CommandTable) Completer { comps := []string{} flags := map[string]FlagTable{} argCompleters := map[string]CompleterFunc{} for _, entry := range ct { comps = append(comps, entry.Name) flags[entry.Name] = entry.Command.FlagTable if entry.Command.Completer != nil { argCompleters[entry.Name] = entry.Command.Completer } for _, sub := range entry.Command.CommandTable { fullc := entry.Name + " " + sub.Name comps = append(comps, fullc) flags[fullc] = sub.Command.FlagTable if sub.Command.Completer != nil { argCompleters[fullc] = sub.Command.Completer } } } sort.Strings(comps) return Completer{ commands: comps, flags: flags, argCompleters: argCompleters, } } Loading Loading @@ -70,6 +79,30 @@ func (c Completer) Do(line []rune, pos int) ([][]rune, int) { } } // Check if the user is typing an argument after a complete command. if spaceIdx := strings.LastIndex(input, " "); spaceIdx >= 0 { cmdPart := strings.TrimSpace(input[:spaceIdx]) argPart := input[spaceIdx+1:] cmdKey := strings.ToUpper(cmdPart) argUpper := strings.ToUpper(argPart) if completer, ok := c.argCompleters[cmdKey]; ok { choices := completer() newline := [][]rune{} for _, choice := range choices { if strings.HasPrefix(strings.ToUpper(choice), argUpper) { rest := choice[len(argPart):] if lower { newline = append(newline, []rune(strings.ToLower(rest))) } else { newline = append(newline, []rune(rest)) } } } return newline, pos } } // Command partially typed in. newline := [][]rune{} for i := range c.commands { Loading repl/command.go +4 −3 Original line number Diff line number Diff line Loading @@ -939,6 +939,7 @@ message.`, MinArgs: 1, MaxArgs: 1, Action: ActionSelect, Completer: completeFolderNames, Flags: dclish.Flags{ "/MARKED": { Description: ` Selects only messages that have been marked (indicated by an asterisk). Loading repl/folders.go +13 −0 Original line number Diff line number Diff line Loading @@ -142,6 +142,19 @@ func ActionCreate(cmd *dclish.Command) error { return err } // completeFolderNames returns folder names for tab completion. func completeFolderNames() []string { folderList, err := folders.ListFolder() if err != nil { return nil } names := make([]string, len(folderList)) for i, f := range folderList { names[i] = f.Name } return names } // ActionSelect handles the `SELECT` command. This selects a folder. // // This is based on `SELECT_FOLDER` in bulletin5.for. Loading repl/messages.go +22 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,28 @@ func ActionDirectory(cmd *dclish.Command) error { if cmd.Flags["/EXPIRATION"].Value == "true" { showExpiration = true } if cmd.Flags["/FOLDERS"].Value == "true" { folderList, err := folders.ListFolder() if err != nil { return err } if len(folderList) == 0 { fmt.Println("There are no folders.") return nil } showDesc := cmd.Flags["/DESCRIBE"].Value == "true" buf := strings.Builder{} buf.WriteString(fmt.Sprintf("%-25s %5s\n", "Folder", "Msgs")) for _, f := range folderList { buf.WriteString(fmt.Sprintf("%-25s %5d", f.Name, f.Count)) if showDesc && f.Description != "" { buf.WriteString(fmt.Sprintf(" %s", f.Description)) } buf.WriteString("\n") } pager.Pager(buf.String()) return nil } if len(cmd.Args) == 1 { folder, err := folders.ValidFolder(cmd.Args[0]) if err != nil { Loading Loading
dclish/completer.go +37 −4 Original line number Diff line number Diff line Loading @@ -10,25 +10,34 @@ import ( type Completer struct { commands []string flags map[string]FlagTable argCompleters map[string]CompleterFunc } // NewCompleter creates a new completer from a CommandTable. func NewCompleter(ct CommandTable) Completer { comps := []string{} flags := map[string]FlagTable{} argCompleters := map[string]CompleterFunc{} for _, entry := range ct { comps = append(comps, entry.Name) flags[entry.Name] = entry.Command.FlagTable if entry.Command.Completer != nil { argCompleters[entry.Name] = entry.Command.Completer } for _, sub := range entry.Command.CommandTable { fullc := entry.Name + " " + sub.Name comps = append(comps, fullc) flags[fullc] = sub.Command.FlagTable if sub.Command.Completer != nil { argCompleters[fullc] = sub.Command.Completer } } } sort.Strings(comps) return Completer{ commands: comps, flags: flags, argCompleters: argCompleters, } } Loading Loading @@ -70,6 +79,30 @@ func (c Completer) Do(line []rune, pos int) ([][]rune, int) { } } // Check if the user is typing an argument after a complete command. if spaceIdx := strings.LastIndex(input, " "); spaceIdx >= 0 { cmdPart := strings.TrimSpace(input[:spaceIdx]) argPart := input[spaceIdx+1:] cmdKey := strings.ToUpper(cmdPart) argUpper := strings.ToUpper(argPart) if completer, ok := c.argCompleters[cmdKey]; ok { choices := completer() newline := [][]rune{} for _, choice := range choices { if strings.HasPrefix(strings.ToUpper(choice), argUpper) { rest := choice[len(argPart):] if lower { newline = append(newline, []rune(strings.ToLower(rest))) } else { newline = append(newline, []rune(rest)) } } } return newline, pos } } // Command partially typed in. newline := [][]rune{} for i := range c.commands { Loading
repl/command.go +4 −3 Original line number Diff line number Diff line Loading @@ -939,6 +939,7 @@ message.`, MinArgs: 1, MaxArgs: 1, Action: ActionSelect, Completer: completeFolderNames, Flags: dclish.Flags{ "/MARKED": { Description: ` Selects only messages that have been marked (indicated by an asterisk). Loading
repl/folders.go +13 −0 Original line number Diff line number Diff line Loading @@ -142,6 +142,19 @@ func ActionCreate(cmd *dclish.Command) error { return err } // completeFolderNames returns folder names for tab completion. func completeFolderNames() []string { folderList, err := folders.ListFolder() if err != nil { return nil } names := make([]string, len(folderList)) for i, f := range folderList { names[i] = f.Name } return names } // ActionSelect handles the `SELECT` command. This selects a folder. // // This is based on `SELECT_FOLDER` in bulletin5.for. Loading
repl/messages.go +22 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,28 @@ func ActionDirectory(cmd *dclish.Command) error { if cmd.Flags["/EXPIRATION"].Value == "true" { showExpiration = true } if cmd.Flags["/FOLDERS"].Value == "true" { folderList, err := folders.ListFolder() if err != nil { return err } if len(folderList) == 0 { fmt.Println("There are no folders.") return nil } showDesc := cmd.Flags["/DESCRIBE"].Value == "true" buf := strings.Builder{} buf.WriteString(fmt.Sprintf("%-25s %5s\n", "Folder", "Msgs")) for _, f := range folderList { buf.WriteString(fmt.Sprintf("%-25s %5d", f.Name, f.Count)) if showDesc && f.Description != "" { buf.WriteString(fmt.Sprintf(" %s", f.Description)) } buf.WriteString("\n") } pager.Pager(buf.String()) return nil } if len(cmd.Args) == 1 { folder, err := folders.ValidFolder(cmd.Args[0]) if err != nil { Loading