cli: Improve the feel of using commands in conversation mode

This commit is contained in:
John Brooks 2017-09-21 06:53:37 -06:00
parent 9bd509c3d8
commit 48aab2536a
1 changed files with 44 additions and 26 deletions

View File

@ -20,6 +20,7 @@ type UI struct {
Client *Client Client *Client
CurrentContact *Contact CurrentContact *Contact
commandMode bool
baseConfig *readline.Config baseConfig *readline.Config
baseChatConfig *readline.Config baseChatConfig *readline.Config
@ -54,17 +55,12 @@ func (ui *UI) Execute(line string) error {
ui.Client.Block() ui.Client.Block()
defer ui.Client.Unblock() defer ui.Client.Unblock()
words := strings.SplitN(line, " ", 2) if ui.CurrentContact != nil && !ui.commandMode {
ui.CurrentContact.Conversation.SendMessage(line)
if ui.CurrentContact != nil { return nil
if len(words[0]) > 0 && words[0][0] == '/' {
words[0] = words[0][1:]
} else {
ui.CurrentContact.Conversation.SendMessage(line)
return nil
}
} }
words := strings.SplitN(line, " ", 2)
if id, err := strconv.Atoi(words[0]); err == nil { if id, err := strconv.Atoi(words[0]); err == nil {
contact := ui.Client.Contacts.ById(int32(id)) contact := ui.Client.Contacts.ById(int32(id))
if contact != nil { if contact != nil {
@ -280,36 +276,55 @@ type conversationInputConfig struct {
BaseConfig *readline.Config BaseConfig *readline.Config
PromptFmt string PromptFmt string
CommandModeFlag *bool
editingLine []rune
usingConfig bool usingConfig bool
stopPromptTimer chan struct{} stopPromptTimer chan struct{}
} }
func (cc *conversationInputConfig) OnChange(line []rune, pos int, key rune) ([]rune, int, bool) { func (cc *conversationInputConfig) OnChange(line []rune, pos int, key rune) ([]rune, int, bool) {
if len(line) == 0 && key != 0 && !cc.usingConfig { cc.editingLine = line
cc.Install()
}
if len(line) > 0 && line[0] == '/' { // Unset command mode at the beginning of a new read
if cc.usingConfig { if line == nil && pos == 0 && key == 0 {
cc.stopPromptTimer <- struct{}{} cc.Install()
cc.usingConfig = false
close(cc.stopPromptTimer)
cc.BaseConfig.Listener = cc.Config.Listener
cc.Input.SetConfig(cc.BaseConfig)
}
} else if !cc.usingConfig {
line = append([]rune{'/'}, line...)
} }
return line, pos, true return line, pos, true
} }
func (cc *conversationInputConfig) FilterInputRune(key rune) (rune, bool) {
if key == '/' && len(cc.editingLine) == 0 && cc.usingConfig {
// '/' at the beginning of the input triggers command mode
cc.stopPromptTimer <- struct{}{}
cc.usingConfig = false
close(cc.stopPromptTimer)
cc.BaseConfig.Listener = cc.Config.Listener
cc.BaseConfig.FuncFilterInputRune = cc.FilterInputRune
cc.Input.SetConfig(cc.BaseConfig)
*cc.CommandModeFlag = true
// The / is suppressed from the output
return key, false
} else if (key == readline.CharBackspace || key == readline.CharCtrlH) &&
len(cc.editingLine) == 0 && !cc.usingConfig {
// Backspace on an empty command mode line unsets command mode
cc.Install()
return key, false
} else {
return key, true
}
}
func (cc *conversationInputConfig) Install() { func (cc *conversationInputConfig) Install() {
if !cc.usingConfig { if !cc.usingConfig {
cc.usingConfig = true cc.usingConfig = true
cc.Config.FuncFilterInputRune = cc.FilterInputRune
cc.Input.SetConfig(cc.Config) cc.Input.SetConfig(cc.Config)
cc.stopPromptTimer = make(chan struct{}) cc.stopPromptTimer = make(chan struct{})
go cc.updatePromptTimer() go cc.updatePromptTimer()
*cc.CommandModeFlag = false
} }
} }
@ -320,7 +335,9 @@ func (cc *conversationInputConfig) Remove() {
cc.stopPromptTimer <- struct{}{} cc.stopPromptTimer <- struct{}{}
cc.usingConfig = false cc.usingConfig = false
close(cc.stopPromptTimer) close(cc.stopPromptTimer)
cc.BaseConfig.FuncFilterInputRune = nil
cc.Input.SetConfig(cc.BaseConfig) cc.Input.SetConfig(cc.BaseConfig)
*cc.CommandModeFlag = true
} }
} }
@ -346,10 +363,11 @@ func (ui *UI) setupConversationPrompt() {
} }
listener := &conversationInputConfig{ listener := &conversationInputConfig{
Input: ui.Input, Input: ui.Input,
Config: ui.baseChatConfig.Clone(), Config: ui.baseChatConfig.Clone(),
BaseConfig: ui.baseConfig, BaseConfig: ui.baseConfig,
PromptFmt: fmt.Sprintf(ui.baseChatConfig.Prompt, "%s", ui.CurrentContact.Data.Nickname), PromptFmt: fmt.Sprintf(ui.baseChatConfig.Prompt, "%s", ui.CurrentContact.Data.Nickname),
CommandModeFlag: &ui.commandMode,
} }
listener.Config.Listener = listener listener.Config.Listener = listener
listener.Install() listener.Install()