-
Notifications
You must be signed in to change notification settings - Fork 29
/
Program.fs
133 lines (118 loc) · 4.74 KB
/
Program.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
module FVim.Program
open System
open System.IO
open System.Threading
open Avalonia
open Avalonia.ReactiveUI
open Avalonia.Controls.ApplicationLifetimes
open def
open getopt
open common
open shell
open daemon
open FVim.ui
let inline trace x = FVim.log.trace "main" x
// Avalonia configuration, don't remove; also used by visual designer.
[<CompiledName "BuildAvaloniaApp">]
let buildAvaloniaApp() =
AppBuilder
.Configure<App>()
.UsePlatformDetect()
.UseReactiveUI()
//.With(new Win32PlatformOptions(UseDeferredRendering=true, UseWgl=true))
//.With(new AvaloniaNativePlatformOptions(UseDeferredRendering=false))
.With(new X11PlatformOptions(EnableIme=true))
//.With(new MacOSPlatformOptions(ShowInDock=true))
let startMainWindow app opts =
let app = app()
model.Start opts
let cfg = config.load()
let cwd = Environment.CurrentDirectory |> Path.GetFullPath
let workspace = cfg.Workspace |> Array.tryFind(fun w -> w.Path = cwd)
workspace
>>= fun workspace -> workspace.Mainwin.BackgroundComposition
>>= fun comp -> parseBackgroundComposition(box comp)
>>= fun comp -> states.background_composition <- comp; None
|> ignore
model.CreateFrame <- fun _gridui ->
let gridui = _gridui :?> GridViewModel
let framevm = new FrameViewModel(workspace, gridui)
let frame = new Frame(DataContext=framevm)
frame.Show()
let mainwinVM = new FrameViewModel(workspace)
let mainwin = Frame(DataContext = mainwinVM)
// sometimes the metrics will just go off...
// see #136
let screenBounds =
mainwin.Screens.All
|> Seq.fold (fun r (s: Platform.Screen) -> s.Bounds.Union r) (PixelRect())
let boundcheck() =
let mutable winBounds =
PixelRect(max (int mainwinVM.X) screenBounds.X,
max (int mainwinVM.Y) screenBounds.Y,
min (int mainwinVM.Width) screenBounds.Width,
min (int mainwinVM.Height) screenBounds.Height)
if winBounds.Right > screenBounds.Right then
winBounds <- winBounds.WithX(screenBounds.Right - winBounds.Width)
if winBounds.Bottom > screenBounds.Bottom then
winBounds <- winBounds.WithY(screenBounds.Bottom - winBounds.Height)
trace "mainwin bound adjusted to %O" winBounds
mainwinVM.X <- float winBounds.X
mainwinVM.Y <- float winBounds.Y
mainwinVM.Width <- float winBounds.Width
mainwinVM.Height <- float winBounds.Height
boundcheck()
app <| mainwin
boundcheck()
let x, y, w, h = (int mainwinVM.X), (int mainwinVM.Y), (int mainwinVM.Width), (int mainwinVM.Height)
config.save cfg x y w h (mainwinVM.WindowState.ToString()) (backgroundCompositionToString states.background_composition) mainwinVM.CustomTitleBar
0
let startCrashReportWindow app ex =
let app = app()
trace "displaying crash dialog"
trace "exception: %O" ex
let code, msgs = model.get_crash_info()
let crash = new CrashReportViewModel(ex, code, msgs)
let win = new CrashReport(DataContext = crash)
// there may be messages already posted into the sync context,
// so we may immediately crash when we start the app and drive
// the message loop forward... in that case, launch it again.
try app win
with _ -> app win
-1
[<EntryPoint>]
[<STAThread>]
[<CompiledName "Main">]
let main(args: string[]) =
let _ = Thread.CurrentThread.TrySetApartmentState(ApartmentState.STA)
AppDomain.CurrentDomain.UnhandledException.Add(fun exArgs ->
let datetime = DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss")
let filename = Path.Combine(config.configdir, $"fvim-crash-{datetime}.txt")
use dumpfile = new StreamWriter(filename)
dumpfile.WriteLine($"Unhandled exception: (terminating:%A{exArgs.IsTerminating})")
dumpfile.WriteLine($"{exArgs.ExceptionObject}")
)
System.Console.OutputEncoding <- System.Text.Encoding.Unicode
let builder = lazy buildAvaloniaApp()
let lifetime = lazy new ClassicDesktopStyleApplicationLifetime()
let app () =
// Avalonia initialization
let lifetime = lifetime.Value
if not builder.IsValueCreated then
let _ = builder.Value.SetupWithLifetime(lifetime)
()
// Avalonia is initialized. SynchronizationContext-reliant code should be working by now;
(fun (win: Avalonia.Controls.Window) ->
lifetime.ShutdownMode <- Controls.ShutdownMode.OnMainWindowClose
lifetime.MainWindow <- win
lifetime.Start(args) |> ignore)
try
let opts = parseOptions args
FVim.log.init opts
match opts.intent with
| Setup -> setup()
| Uninstall -> uninstall()
| Daemon(pipe, nvim, enc) -> daemon pipe nvim enc
| Start(opts,norc,remote) -> startMainWindow app (opts,norc,remote)
with
| ex -> startCrashReportWindow app ex