X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=cmd%2Fmicro%2Fmessenger.go;h=0d20603a2df05f026a30e5f4293631d50937ae8c;hb=b9e916999fbf59a64c61c0921802821cd4b35993;hp=5287832e7cc402a738aba1b9c46bc60ea8e6307d;hpb=d13f9602ff228f83c1d1d149aed3a287a93016ff;p=micro.git diff --git a/cmd/micro/messenger.go b/cmd/micro/messenger.go index 5287832e..0d20603a 100644 --- a/cmd/micro/messenger.go +++ b/cmd/micro/messenger.go @@ -3,10 +3,12 @@ package main import ( "bufio" "bytes" + "encoding/gob" "fmt" "os" "strconv" + "github.com/mattn/go-runewidth" "github.com/zyedidia/clipboard" "github.com/zyedidia/tcell" ) @@ -69,16 +71,18 @@ type Messenger struct { 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 = NewBufferFromString("", "") m.log.name = "Log" } return m.log @@ -86,36 +90,68 @@ func (m *Messenger) getBuffer() *Buffer { // 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 + } + // 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.AddLog(m.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 { @@ -129,17 +165,19 @@ func (m *Messenger) YesNoPrompt(prompt string) (bool, bool) { 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 } @@ -150,7 +188,7 @@ func (m *Messenger) YesNoPrompt(prompt string) (bool, bool) { // 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 { @@ -194,13 +232,14 @@ const ( 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 { @@ -259,6 +298,10 @@ func (m *Messenger) Prompt(prompt, placeholder, historyType string, completionTy 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 { @@ -429,8 +472,10 @@ func (m *Messenger) Display() { 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]) } } } @@ -441,6 +486,55 @@ func (m *Messenger) Display() { } } +// 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