diff --git a/Assets/error.png b/Assets/error.png new file mode 100644 index 0000000..9d4f19c Binary files /dev/null and b/Assets/error.png differ diff --git a/Assets/error.xcf b/Assets/error.xcf new file mode 100644 index 0000000..a5a8635 Binary files /dev/null and b/Assets/error.xcf differ diff --git a/DesignTime/CrashReportSampleData.fs b/DesignTime/CrashReportSampleData.fs new file mode 100644 index 0000000..e1e2e94 --- /dev/null +++ b/DesignTime/CrashReportSampleData.fs @@ -0,0 +1,11 @@ +namespace FVim + +type CrashReportSampleData() = + member __.MainMessage = "Some error: some detailed error message.\nThis error is so bad that we have to bail out." + member __.TipMessage = "\n\nIn case of fire,\n 1. git commit\n 2. git push\n 3. run\nThank you for your cooperation." + member __.StackTrace = System.Collections.Generic.List [ + "foo" + "bar" + "baz" + ] + diff --git a/Program.fs b/Program.fs index a7e83eb..dc6ec90 100644 --- a/Program.fs +++ b/Program.fs @@ -64,15 +64,25 @@ let main(args: string[]) = let _ = builder.SetupWithoutStarting() // Avalonia is initialized. SynchronizationContext-reliant code should be working by now; - try - Model.Start opts - with ex -> () - let cfg = config.load() - let cwd = Environment.CurrentDirectory |> Path.GetFullPath - let workspace = cfg.Workspace |> Array.tryFind(fun w -> w.Path = cwd) - let mainwin = new MainWindowViewModel(workspace) - lifetime.MainWindow <- MainWindow(DataContext = mainwin) - let ret = lifetime.Start(args) + let model_start = + try + Model.Start opts + Ok() + with ex -> Error ex - config.save cfg (int mainwin.X) (int mainwin.Y) mainwin.Width mainwin.Height mainwin.WindowState - ret + match model_start with + | Ok() -> + let cfg = config.load() + let cwd = Environment.CurrentDirectory |> Path.GetFullPath + let workspace = cfg.Workspace |> Array.tryFind(fun w -> w.Path = cwd) + let mainwin = new MainWindowViewModel(workspace) + lifetime.MainWindow <- MainWindow(DataContext = mainwin) + let ret = lifetime.Start(args) + + config.save cfg (int mainwin.X) (int mainwin.Y) mainwin.Width mainwin.Height mainwin.WindowState + ret + | Error ex -> + let crash = new CrashReportViewModel(ex) + lifetime.MainWindow <- new CrashReport(DataContext = crash) + ignore <| lifetime.Start(args) + -1 diff --git a/ViewModels/CrashReportViewModel.fs b/ViewModels/CrashReportViewModel.fs new file mode 100644 index 0000000..d06f4f2 --- /dev/null +++ b/ViewModels/CrashReportViewModel.fs @@ -0,0 +1,23 @@ +namespace FVim + +open ui +open log +open common + +type CrashReportViewModel(ex: exn) = + inherit ViewModelBase() + member __.MainMessage = + ex.Message + member __.StackTrace = + ex.StackTrace.Split("\n") + member __.TipMessage = + let tip = + match ex.Message with + | "The system cannot find the file specified." -> "Tip: check your neovim installation. `nvim` is not in your $PATH.\n" + | _ -> "" + let generic_message = + "You can go to /~https://github.com/yatli/fvim/issues, and search\n" + + "for relevant issues with the exception message, or the stack trace.\n" + + "Feel free to create new issues, and I'll help to triage and fix the problem." + tip + generic_message + diff --git a/Views/CrashReport.xaml b/Views/CrashReport.xaml new file mode 100644 index 0000000..b2fe505 --- /dev/null +++ b/Views/CrashReport.xaml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Views/CrashReport.xaml.fs b/Views/CrashReport.xaml.fs new file mode 100644 index 0000000..a78096a --- /dev/null +++ b/Views/CrashReport.xaml.fs @@ -0,0 +1,13 @@ +namespace FVim + +open ui +open log +open common +open Avalonia.Markup.Xaml +open Avalonia.Controls + +type CrashReport() as this = + inherit Window() + + do + AvaloniaXamlLoader.Load(this) diff --git a/fvim.fsproj b/fvim.fsproj index 63bc71d..39da925 100644 --- a/fvim.fsproj +++ b/fvim.fsproj @@ -25,6 +25,7 @@ + @@ -41,12 +42,14 @@ + +