import (
"bufio"
"bytes"
+ "encoding/gob"
"fmt"
"os"
"strconv"
+ "github.com/mattn/go-runewidth"
"github.com/zyedidia/clipboard"
"github.com/zyedidia/tcell"
)
gutterMessage bool
}
-func (m *Messenger) AddLog(msg string) {
+// AddLog sends a message to the log view
+func (m *Messenger) AddLog(msg ...interface{}) {
+ logMessage := fmt.Sprint(msg...)
buffer := m.getBuffer()
- buffer.insert(buffer.End(), []byte(msg+"\n"))
+ buffer.insert(buffer.End(), []byte(logMessage+"\n"))
buffer.Cursor.Loc = buffer.End()
buffer.Cursor.Relocate()
}
func (m *Messenger) getBuffer() *Buffer {
if m.log == nil {
- m.log = NewBuffer([]byte{}, "")
- m.log.Name = "Log"
+ m.log = NewBufferFromString("", "")
+ m.log.name = "Log"
}
return m.log
}
// Message sends a message to the user
func (m *Messenger) Message(msg ...interface{}) {
- m.message = fmt.Sprint(msg...)
- m.style = defStyle
+ displayMessage := fmt.Sprint(msg...)
+ // only display a new message if there isn't an active prompt
+ // this is to prevent overwriting an existing prompt to the user
+ if m.hasPrompt == false {
+ // if there is no active prompt then style and display the message as normal
+ m.message = displayMessage
- if _, ok := colorscheme["message"]; ok {
- m.style = colorscheme["message"]
+ m.style = defStyle
+
+ if _, ok := colorscheme["message"]; ok {
+ m.style = colorscheme["message"]
+ }
+
+ m.hasMessage = true
}
- m.AddLog(m.message)
- m.hasMessage = true
+ // add the message to the log regardless of active prompts
+ m.AddLog(displayMessage)
}
// Error sends an error message to the user
func (m *Messenger) Error(msg ...interface{}) {
buf := new(bytes.Buffer)
fmt.Fprint(buf, msg...)
- m.message = buf.String()
- m.style = defStyle.
- Foreground(tcell.ColorBlack).
- Background(tcell.ColorMaroon)
- if _, ok := colorscheme["error-message"]; ok {
- m.style = colorscheme["error-message"]
+ // only display a new message if there isn't an active prompt
+ // this is to prevent overwriting an existing prompt to the user
+ if m.hasPrompt == false {
+ // if there is no active prompt then style and display the message as normal
+ m.message = buf.String()
+ m.style = defStyle.
+ Foreground(tcell.ColorBlack).
+ Background(tcell.ColorMaroon)
+
+ if _, ok := colorscheme["error-message"]; ok {
+ m.style = colorscheme["error-message"]
+ }
+ m.hasMessage = true
}
- m.AddLog(m.message)
+ // add the message to the log regardless of active prompts
+ m.AddLog(buf.String())
+}
+
+func (m *Messenger) PromptText(msg ...interface{}) {
+ displayMessage := fmt.Sprint(msg...)
+ // if there is no active prompt then style and display the message as normal
+ m.message = displayMessage
+
+ m.style = defStyle
+
+ if _, ok := colorscheme["message"]; ok {
+ m.style = colorscheme["message"]
+ }
+
m.hasMessage = true
+ // add the message to the log regardless of active prompts
+ m.AddLog(displayMessage)
}
// YesNoPrompt asks the user a yes or no question (waits for y or n) and returns the result
func (m *Messenger) YesNoPrompt(prompt string) (bool, bool) {
m.hasPrompt = true
- m.Message(prompt)
+ m.PromptText(prompt)
_, h := screen.Size()
for {
case *tcell.EventKey:
switch e.Key() {
case tcell.KeyRune:
- if e.Rune() == 'y' {
+ if e.Rune() == 'y' || e.Rune() == 'Y' {
m.AddLog("\t--> y")
m.hasPrompt = false
return true, false
- } else if e.Rune() == 'n' {
+ } else if e.Rune() == 'n' || 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.Clear()
+ m.Reset()
m.hasPrompt = false
return false, true
}
// LetterPrompt gives the user a prompt and waits for a one letter response
func (m *Messenger) LetterPrompt(prompt string, responses ...rune) (rune, bool) {
m.hasPrompt = true
- m.Message(prompt)
+ m.PromptText(prompt)
_, h := screen.Size()
for {
OptionCompletion
PluginCmdCompletion
PluginNameCompletion
+ OptionValueCompletion
)
// 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, placeholder, historyType string, completionTypes ...Completion) (string, bool) {
m.hasPrompt = true
- m.Message(prompt)
+ m.PromptText(prompt)
if _, ok := m.history[historyType]; !ok {
m.history[historyType] = []string{""}
} else {
chosen, suggestions = HelpComplete(currentArg)
} else if completionType == OptionCompletion {
chosen, suggestions = OptionComplete(currentArg)
+ } else if completionType == OptionValueCompletion {
+ if currentArgNum-1 > 0 {
+ chosen, suggestions = OptionValueComplete(args[currentArgNum-1], currentArg)
+ }
} else if completionType == PluginCmdCompletion {
chosen, suggestions = PluginCmdComplete(currentArg)
} else if completionType == PluginNameCompletion {
if m.hasMessage {
if m.hasPrompt || globalSettings["infobar"].(bool) {
runes := []rune(m.message + m.response)
+ posx := 0
for x := 0; x < len(runes); x++ {
- screen.SetContent(x, h-1, runes[x], nil, m.style)
+ screen.SetContent(posx, h-1, runes[x], nil, m.style)
+ posx += runewidth.RuneWidth(runes[x])
}
}
}
}
}
+// LoadHistory attempts to load user history from configDir/buffers/history
+// into the history map
+// The savehistory option must be on
+func (m *Messenger) LoadHistory() {
+ if GetGlobalOption("savehistory").(bool) {
+ file, err := os.Open(configDir + "/buffers/history")
+ var decodedMap map[string][]string
+ if err == nil {
+ decoder := gob.NewDecoder(file)
+ err = decoder.Decode(&decodedMap)
+ file.Close()
+ }
+
+ if err != nil {
+ m.Error("Error loading history:", err)
+ return
+ }
+
+ m.history = decodedMap
+ } else {
+ m.history = make(map[string][]string)
+ }
+}
+
+// SaveHistory saves the user's command history to configDir/buffers/history
+// only if the savehistory option is on
+func (m *Messenger) SaveHistory() {
+ if GetGlobalOption("savehistory").(bool) {
+ // Don't save history past 100
+ for k, v := range m.history {
+ if len(v) > 100 {
+ m.history[k] = v[0:100]
+ }
+ }
+
+ file, err := os.Create(configDir + "/buffers/history")
+ if err == nil {
+ encoder := gob.NewEncoder(file)
+
+ err = encoder.Encode(m.history)
+ if err != nil {
+ m.Error("Error saving history:", err)
+ return
+ }
+ file.Close()
+ }
+ }
+}
+
// A GutterMessage is a message displayed on the side of the editor
type GutterMessage struct {
lineNum int