From 34724b941a3278f9bbeb6fa30ca3d301708b3a01 Mon Sep 17 00:00:00 2001 From: Zachary Yedidia Date: Tue, 11 Feb 2020 00:50:24 -0500 Subject: [PATCH] Recover from internal errors without crashing --- cmd/micro/micro.go | 90 ++++++++++++++++++++++++++-------------------- go.sum | 2 -- 2 files changed, 52 insertions(+), 40 deletions(-) diff --git a/cmd/micro/micro.go b/cmd/micro/micro.go index b1e70187..19ab25d5 100644 --- a/cmd/micro/micro.go +++ b/cmd/micro/micro.go @@ -11,6 +11,7 @@ import ( "github.com/go-errors/errors" isatty "github.com/mattn/go-isatty" + lua "github.com/yuin/gopher-lua" "github.com/zyedidia/micro/internal/action" "github.com/zyedidia/micro/internal/buffer" "github.com/zyedidia/micro/internal/config" @@ -218,9 +219,6 @@ func main() { screen.Init() - // If we have an error, we can exit cleanly and not completely - // mess up the terminal being worked in - // In other words we need to shut down tcell before the program crashes defer func() { if err := recover(); err != nil { screen.Screen.Fini() @@ -284,48 +282,64 @@ func main() { <-screen.DrawChan } - var event tcell.Event - // wait for initial resize event select { - case event = <-events: + case event := <-events: action.Tabs.HandleEvent(event) case <-time.After(10 * time.Millisecond): // time out after 10ms } + // Since this loop is very slow (waits for user input every time) it's + // okay to be inefficient and run it via a function every time + // We do this so we can recover from panics without crashing the editor for { - // Display everything - screen.Screen.Fill(' ', config.DefStyle) - screen.Screen.HideCursor() - action.Tabs.Display() - for _, ep := range action.MainTab().Panes { - ep.Display() - } - action.MainTab().Display() - action.InfoBar.Display() - screen.Screen.Show() - - event = nil - - // Check for new events - select { - case f := <-shell.Jobs: - // If a new job has finished while running in the background we should execute the callback - f.Function(f.Output, f.Args) - case <-config.Autosave: - for _, b := range buffer.OpenBuffers { - b.Save() - } - case <-shell.CloseTerms: - case event = <-events: - case <-screen.DrawChan: - } - - if action.InfoBar.HasPrompt { - action.InfoBar.HandleEvent(event) - } else { - action.Tabs.HandleEvent(event) - } + DoEvent() + } +} + +// DoEvent runs the main action loop of the editor +func DoEvent() { + var event tcell.Event + + // recover from errors without crashing the editor + defer func() { + if err := recover(); err != nil { + if e, ok := err.(*lua.ApiError); ok { + screen.TermMessage("Lua API error:", e) + } else { + screen.TermMessage("Micro encountered an error:", errors.Wrap(err, 2).ErrorStack(), "\nIf you can reproduce this error, please report it at https://github.com/zyedidia/micro/issues") + } + } + }() + // Display everything + screen.Screen.Fill(' ', config.DefStyle) + screen.Screen.HideCursor() + action.Tabs.Display() + for _, ep := range action.MainTab().Panes { + ep.Display() + } + action.MainTab().Display() + action.InfoBar.Display() + screen.Screen.Show() + + // Check for new events + select { + case f := <-shell.Jobs: + // If a new job has finished while running in the background we should execute the callback + f.Function(f.Output, f.Args) + case <-config.Autosave: + for _, b := range buffer.OpenBuffers { + b.Save() + } + case <-shell.CloseTerms: + case event = <-events: + case <-screen.DrawChan: + } + + if action.InfoBar.HasPrompt { + action.InfoBar.HandleEvent(event) + } else { + action.Tabs.HandleEvent(event) } } diff --git a/go.sum b/go.sum index 9141da92..1669b93a 100644 --- a/go.sum +++ b/go.sum @@ -50,8 +50,6 @@ github.com/zyedidia/poller v1.0.1 h1:Tt9S3AxAjXwWGNiC2TUdRJkQDZSzCBNVQ4xXiQ7440s github.com/zyedidia/poller v1.0.1/go.mod h1:vZXJOHGDcuK08GXhF6IAY0ZFd2WcgOR5DOTp84Uk5eE= github.com/zyedidia/pty v2.0.0+incompatible h1:Ou5vXL6tvjst+RV8sUFISbuKDnUJPhnpygApMFGweqw= github.com/zyedidia/pty v2.0.0+incompatible/go.mod h1:4y9l9yJZNxRa7GB/fB+mmDmGkG3CqmzLf4vUxGGotEA= -github.com/zyedidia/tcell v1.4.2 h1:JWMDs6O1saINPIR5M3kNqlWJwkfnBZeZDZszEJi3BW8= -github.com/zyedidia/tcell v1.4.2/go.mod h1:HhlbMSCcGX15rFDB+Q1Lk3pKEOocsCUAQC3zhZ9sadA= github.com/zyedidia/tcell v1.4.3 h1:s0nmxj22Jj+vyt4nVmnB6kbnwRxEay1zfS0j8IsbtfI= github.com/zyedidia/tcell v1.4.3/go.mod h1:HhlbMSCcGX15rFDB+Q1Lk3pKEOocsCUAQC3zhZ9sadA= github.com/zyedidia/terminal v0.0.0-20180726154117-533c623e2415 h1:752dTQ5OatJ9M5ULK2+9lor+nzyZz+LYDo3WGngg3Rc=