screenWasNil := screen == nil
if !screenWasNil {
screen.Fini()
+ screen = nil
}
fmt.Println(msg...)
// Messenger is an object that makes it easy to send messages to the user
// and get input from the user
type Messenger struct {
+ log *Buffer
// Are we currently prompting the user?
hasPrompt bool
// Is there a message to print
gutterMessage bool
}
+func (m *Messenger) AddLog(msg string) {
+ buffer := m.getBuffer()
+ buffer.insert(buffer.End(), []byte(msg+"\n"))
+ buffer.Cursor.Loc = buffer.End()
+ buffer.Cursor.Relocate()
+}
+
+func (m *Messenger) getBuffer() *Buffer {
+ if m.log == nil {
+ m.log = NewBuffer(strings.NewReader(""), "")
+ m.log.name = "Log"
+ }
+ return m.log
+}
+
// Message sends a message to the user
func (m *Messenger) Message(msg ...interface{}) {
- buf := new(bytes.Buffer)
- fmt.Fprint(buf, msg...)
- m.message = buf.String()
+ m.message = fmt.Sprint(msg...)
m.style = defStyle
if _, ok := colorscheme["message"]; ok {
m.style = colorscheme["message"]
}
+ m.AddLog(m.message)
m.hasMessage = true
}
if _, ok := colorscheme["error-message"]; ok {
m.style = colorscheme["error-message"]
}
+ m.AddLog(m.message)
m.hasMessage = true
}
switch e.Key() {
case tcell.KeyRune:
if e.Rune() == 'y' {
+ m.AddLog("\t--> y")
+ m.hasPrompt = false
return true, false
} else if e.Rune() == 'n' {
+ m.AddLog("\t--> n")
+ m.hasPrompt = false
return false, false
}
case tcell.KeyCtrlC, tcell.KeyCtrlQ, tcell.KeyEscape:
+ m.AddLog("\t--> (cancel)")
+ m.hasPrompt = false
return false, true
}
}
case tcell.KeyRune:
for _, r := range responses {
if e.Rune() == r {
+ m.AddLog("\t--> " + string(r))
m.Clear()
m.Reset()
m.hasPrompt = false
}
}
case tcell.KeyCtrlC, tcell.KeyCtrlQ, tcell.KeyEscape:
+ m.AddLog("\t--> (cancel)")
m.Clear()
m.Reset()
m.hasPrompt = false
CommandCompletion
HelpCompletion
OptionCompletion
+ PluginCmdCompletion
+ PluginNameCompletion
)
// Prompt sends the user a message and waits for a response to be typed in
// This function blocks the main loop while waiting for input
-func (m *Messenger) Prompt(prompt, historyType string, completionTypes ...Completion) (string, bool) {
+func (m *Messenger) Prompt(prompt, placeholder, historyType string, completionTypes ...Completion) (string, bool) {
m.hasPrompt = true
m.Message(prompt)
if _, ok := m.history[historyType]; !ok {
}
m.historyNum = len(m.history[historyType]) - 1
- response, canceled := "", true
+ response, canceled := placeholder, true
+ m.response = response
+ m.cursorx = Count(placeholder)
RedrawAll()
for m.hasPrompt {
switch e.Key() {
case tcell.KeyCtrlQ, tcell.KeyCtrlC, tcell.KeyEscape:
// Cancel
+ m.AddLog("\t--> (cancel)")
m.hasPrompt = false
case tcell.KeyEnter:
// User is done entering their response
+ m.AddLog("\t--> " + m.response)
m.hasPrompt = false
response, canceled = m.response, false
m.history[historyType][len(m.history[historyType])-1] = response
case tcell.KeyTab:
- args := strings.Split(m.response, " ")
+ args := SplitCommandArgs(m.response)
currentArgNum := len(args) - 1
currentArg := args[currentArgNum]
var completionType Completion
chosen, suggestions = HelpComplete(currentArg)
} else if completionType == OptionCompletion {
chosen, suggestions = OptionComplete(currentArg)
+ } else if completionType == PluginCmdCompletion {
+ chosen, suggestions = PluginCmdComplete(currentArg)
+ } else if completionType == PluginNameCompletion {
+ chosen, suggestions = PluginNameComplete(currentArg)
+ } else if completionType < NoCompletion {
+ chosen, suggestions = PluginComplete(completionType, currentArg)
}
if len(suggestions) > 1 {
}
if chosen != "" {
- if len(args) > 1 {
- chosen = " " + chosen
- }
- m.response = strings.Join(args[:len(args)-1], " ") + chosen
+ m.response = JoinCommandArgs(append(args[:len(args)-1], chosen)...)
m.cursorx = Count(m.response)
}
}
func (m *Messenger) HandleEvent(event tcell.Event, history []string) {
switch e := event.(type) {
case *tcell.EventKey:
- switch e.Key() {
- case tcell.KeyUp:
- if m.historyNum > 0 {
- m.historyNum--
- m.response = history[m.historyNum]
- m.cursorx = Count(m.response)
- }
- case tcell.KeyDown:
- if m.historyNum < len(history)-1 {
- m.historyNum++
- m.response = history[m.historyNum]
- m.cursorx = Count(m.response)
- }
- case tcell.KeyLeft:
- if m.cursorx > 0 {
- m.cursorx--
- }
- case tcell.KeyRight:
- if m.cursorx < Count(m.response) {
- m.cursorx++
- }
- case tcell.KeyBackspace2, tcell.KeyBackspace:
- if m.cursorx > 0 {
- m.response = string([]rune(m.response)[:m.cursorx-1]) + string([]rune(m.response)[m.cursorx:])
- m.cursorx--
+ if e.Key() != tcell.KeyRune || e.Modifiers() != 0 {
+ for key, actions := range bindings {
+ if e.Key() == key.keyCode {
+ if e.Key() == tcell.KeyRune {
+ if e.Rune() != key.r {
+ continue
+ }
+ }
+ if e.Modifiers() == key.modifiers {
+ for _, action := range actions {
+ funcName := FuncName(action)
+ switch funcName {
+ case "main.(*View).CursorUp":
+ if m.historyNum > 0 {
+ m.historyNum--
+ m.response = history[m.historyNum]
+ m.cursorx = Count(m.response)
+ }
+ case "main.(*View).CursorDown":
+ if m.historyNum < len(history)-1 {
+ m.historyNum++
+ m.response = history[m.historyNum]
+ m.cursorx = Count(m.response)
+ }
+ case "main.(*View).CursorLeft":
+ if m.cursorx > 0 {
+ m.cursorx--
+ }
+ case "main.(*View).CursorRight":
+ if m.cursorx < Count(m.response) {
+ m.cursorx++
+ }
+ case "main.(*View).CursorStart", "main.(*View).StartOfLine":
+ m.cursorx = 0
+ case "main.(*View).CursorEnd", "main.(*View).EndOfLine":
+ m.cursorx = Count(m.response)
+ case "main.(*View).Backspace":
+ if m.cursorx > 0 {
+ m.response = string([]rune(m.response)[:m.cursorx-1]) + string([]rune(m.response)[m.cursorx:])
+ m.cursorx--
+ }
+ case "main.(*View).Paste":
+ clip, _ := clipboard.ReadAll("clipboard")
+ m.response = Insert(m.response, m.cursorx, clip)
+ m.cursorx += Count(clip)
+ }
+ }
+ }
+ }
}
- case tcell.KeyCtrlV:
- clip, _ := clipboard.ReadAll()
- m.response = Insert(m.response, m.cursorx, clip)
- m.cursorx += Count(clip)
+ }
+ switch e.Key() {
case tcell.KeyRune:
m.response = Insert(m.response, m.cursorx, string(e.Rune()))
m.cursorx++
clip := e.Text()
m.response = Insert(m.response, m.cursorx, clip)
m.cursorx += Count(clip)
+ case *tcell.EventMouse:
+ x, y := e.Position()
+ x -= Count(m.message)
+ button := e.Buttons()
+ _, screenH := screen.Size()
+
+ if y == screenH-1 {
+ switch button {
+ case tcell.Button1:
+ m.cursorx = x
+ if m.cursorx < 0 {
+ m.cursorx = 0
+ } else if m.cursorx > Count(m.response) {
+ m.cursorx = Count(m.response)
+ }
+ }
+ }
}
}