diff --git a/cmd/micro/actions.go b/cmd/micro/actions.go index 6dbee05e..596f76fd 100644 --- a/cmd/micro/actions.go +++ b/cmd/micro/actions.go @@ -711,7 +711,7 @@ func (v *View) Save(usePlugin bool) bool { return false } - if v.Help { + if v.Type == vtHelp { // We can't save the help text return false } @@ -1258,7 +1258,7 @@ func (v *View) ToggleHelp(usePlugin bool) bool { return false } - if !v.Help { + if v.Type != vtHelp { // Open the default help v.openHelp("help") } else { diff --git a/cmd/micro/command.go b/cmd/micro/command.go index f0cfe9b3..d1ef2c53 100644 --- a/cmd/micro/command.go +++ b/cmd/micro/command.go @@ -26,19 +26,20 @@ type StrCommand struct { var commands map[string]Command var commandActions = map[string]func([]string){ - "Set": Set, - "SetLocal": SetLocal, - "Show": Show, - "Run": Run, - "Bind": Bind, - "Quit": Quit, - "Save": Save, - "Replace": Replace, - "VSplit": VSplit, - "HSplit": HSplit, - "Tab": NewTab, - "Help": Help, - "Eval": Eval, + "Set": Set, + "SetLocal": SetLocal, + "Show": Show, + "Run": Run, + "Bind": Bind, + "Quit": Quit, + "Save": Save, + "Replace": Replace, + "VSplit": VSplit, + "HSplit": HSplit, + "Tab": NewTab, + "Help": Help, + "Eval": Eval, + "ToggleLog": ToggleLog, } // InitCommands initializes the default commands @@ -84,6 +85,17 @@ func DefaultCommands() map[string]StrCommand { "tab": {"Tab", []Completion{FileCompletion, NoCompletion}}, "help": {"Help", []Completion{HelpCompletion, NoCompletion}}, "eval": {"Eval", []Completion{NoCompletion}}, + "log": {"ToggleLog", []Completion{NoCompletion}}, + } +} + +func ToggleLog(args []string) { + buffer := messenger.getBuffer() + if CurView().Type != vtLog { + CurView().VSplit(buffer) + CurView().Type = vtLog + } else { + CurView().Quit(true) } } diff --git a/cmd/micro/messenger.go b/cmd/micro/messenger.go index 7e641735..530ba4a3 100644 --- a/cmd/micro/messenger.go +++ b/cmd/micro/messenger.go @@ -24,6 +24,7 @@ func TermMessage(msg ...interface{}) { } fmt.Println(msg...) + messenger.AddLog(fmt.Sprint(msg...)) fmt.Print("\nPress enter to continue") reader := bufio.NewReader(os.Stdin) @@ -43,6 +44,7 @@ func TermError(filename string, lineNum int, err string) { // 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 @@ -67,16 +69,30 @@ type Messenger struct { gutterMessage bool } +func (m *Messenger) AddLog(msg string) { + buffer := m.getBuffer() + buffer.Insert(buffer.End(), msg+"\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" + } + 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 } @@ -92,6 +108,7 @@ func (m *Messenger) Error(msg ...interface{}) { if _, ok := colorscheme["error-message"]; ok { m.style = colorscheme["error-message"] } + m.AddLog(m.message) m.hasMessage = true } @@ -113,13 +130,16 @@ func (m *Messenger) YesNoPrompt(prompt string) (bool, bool) { 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 } @@ -146,6 +166,7 @@ func (m *Messenger) LetterPrompt(prompt string, responses ...rune) (rune, bool) case tcell.KeyRune: for _, r := range responses { if e.Rune() == r { + m.AddLog("\t--> " + string(r)) m.Clear() m.Reset() m.hasPrompt = false @@ -153,6 +174,7 @@ func (m *Messenger) LetterPrompt(prompt string, responses ...rune) (rune, bool) } } case tcell.KeyCtrlC, tcell.KeyCtrlQ, tcell.KeyEscape: + m.AddLog("\t--> (cancel)") m.Clear() m.Reset() m.hasPrompt = false @@ -198,9 +220,11 @@ func (m *Messenger) Prompt(prompt, historyType string, completionTypes ...Comple 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 diff --git a/cmd/micro/statusline.go b/cmd/micro/statusline.go index c5e7e406..b60257ad 100644 --- a/cmd/micro/statusline.go +++ b/cmd/micro/statusline.go @@ -37,7 +37,7 @@ func (sline *Statusline) Display() { file += " " + sline.view.Buf.FileType() rightText := helpBinding + " for help " - if sline.view.Help { + if sline.view.Type == vtHelp { rightText = helpBinding + " to close help " } diff --git a/cmd/micro/view.go b/cmd/micro/view.go index 19371573..085e1abf 100644 --- a/cmd/micro/view.go +++ b/cmd/micro/view.go @@ -11,6 +11,14 @@ import ( "github.com/zyedidia/tcell" ) +type ViewType int + +const ( + vtDefault ViewType = iota + vtHelp + vtLog +) + // The View struct stores information about a view into a buffer. // It stores information about the cursor, and the viewport // that the user sees the buffer from. @@ -28,7 +36,7 @@ type View struct { heightPercent int // Specifies whether or not this view holds a help buffer - Help bool + Type ViewType // Actual with and height width int @@ -185,7 +193,7 @@ func (v *View) ScrollDown(n int) { // If there are unsaved changes, the user will be asked if the view can be closed // causing them to lose the unsaved changes func (v *View) CanClose() bool { - if v.Buf.IsModified { + if v.Type == vtDefault && v.Buf.IsModified { char, canceled := messenger.LetterPrompt("Save changes to "+v.Buf.Name+" before closing? (y,n,esc) ", 'y', 'n') if !canceled { if char == 'y' { @@ -536,11 +544,11 @@ func (v *View) openHelp(helpPage string) { helpBuffer := NewBuffer(data, helpPage+".md") helpBuffer.Name = "Help" - if v.Help { + if v.Type == vtHelp { v.OpenBuffer(helpBuffer) } else { v.HSplit(helpBuffer) - CurView().Help = true + CurView().Type = vtHelp } } } @@ -553,9 +561,15 @@ func (v *View) drawCell(x, y int, ch rune, combc []rune, style tcell.Style) { // DisplayView renders the view to the screen func (v *View) DisplayView() { + if v.Type == vtLog { + // Log views should always follow the cursor... + v.Relocate() + } + if v.Buf.Settings["syntax"].(bool) { v.matches = Match(v) } + // The charNum we are currently displaying // starts at the start of the viewport charNum := Loc{0, v.Topline}