-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathProgram.fs
168 lines (122 loc) · 4.58 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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
open System
open System.IO
open System.IO.Pipes
open System.Text
open FSharp.Data
open System.Runtime.InteropServices
// Enable ANSI escape codes for the terminal
[<Literal>]
let STD_OUTPUT_HANDLE = -11
[<Literal>]
let ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4u
[<DllImport("kernel32.dll", SetLastError = true)>]
extern IntPtr GetStdHandle(int nStdHandle)
[<DllImport("kernel32.dll")>]
extern bool GetConsoleMode(IntPtr hConsoleHandle, uint& lpMode)
[<DllImport("kernel32.dll")>]
extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode)
let handle = GetStdHandle(STD_OUTPUT_HANDLE)
let mutable mode = 0u
GetConsoleMode(handle, &mode) |> ignore
mode <- mode ||| ENABLE_VIRTUAL_TERMINAL_PROCESSING
SetConsoleMode(handle, mode) |> ignore
// *****************************************
type Event =
JsonProvider<"data/sample-events.json", SampleIsList=true, InferenceMode=InferenceMode.ValuesAndInlineSchemasOverrides>
let reset = "\x1b[0m"
let italic = "\x1b[3m"
let deepskyblue = "\x1b[48;5;23m"
let underline = "\x1b[4m"
let magenta = "\x1b[35m"
let deepink = "\x1b[38;5;131m"
let join col = List.fold (+) "" col
let indent = List.replicate 4 " " |> join
let style escapeSequence s = $"{escapeSequence}{s}{reset}"
let (|Indent|_|) (s: string) =
if s.StartsWith(indent) then
Some(s.Substring(indent.Length))
else
None
let splitIndent s =
let seed = []
let rec dosplit s l =
match s with
| Indent rest -> dosplit rest (l @ [ indent ])
| "" -> l
| _ -> l @ [ s ]
dosplit s seed
let fmtFocus focused (s: string) =
if focused then
let sections = splitIndent s
let indents = sections[.. sections.Length - 2] |> join
$"{indents}{deepskyblue}{(List.last sections)}{reset}"
else
s
type WorkspaceElement =
| ContainerElement of Event.Element3
| Content of Event.Content
let formatContent (w: Event.Content) =
$"{indent}{indent} - {italic}{w.Exe} | {w.Title}{reset}"
let formatContainer thisMonitorFocused thisWorkspaceFocused containerFocused title i workspaceElement =
let thisContainerFocused = i = containerFocused
let containerName = $"{title}: {i + 1}"
fmtFocus
(thisMonitorFocused && thisWorkspaceFocused && thisContainerFocused)
$"{indent}{indent}{style underline containerName}"
|> style deepink
|> printfn "%s"
match workspaceElement with
| ContainerElement c ->
let windowFocused = c.Windows.Focused
c.Windows.Elements
|> Seq.iteri (fun i w ->
(fmtFocus
(thisMonitorFocused
&& thisWorkspaceFocused
&& thisContainerFocused
&& windowFocused = i)
(formatContent w))
|> printfn "%s")
| Content w -> formatContent w |> printfn "%s"
let pipeServer = new NamedPipeServerStream("komorebi-pipe")
printfn "Waiting for connection."
pipeServer.WaitForConnection()
printfn "Client connected."
let sr = new StreamReader(pipeServer)
let rec loop () =
async {
let! line = sr.ReadLineAsync() |> Async.AwaitTask
// Erase screen
Console.WriteLine("\x1b[2J")
let event = line |> Event.Parse
let monitorFocused = event.State.Monitors.Focused
event.State.Monitors.Elements
|> Seq.iteri (fun i m ->
let thisMonitorFocused = i = monitorFocused
fmtFocus thisMonitorFocused $"Monitor: {m.Name}"
|> style magenta
|> style underline
|> printfn " %s"
let workspaceFocused = m.Workspaces.Focused
m.Workspaces.Elements
|> Seq.iteri (fun i w ->
let thisWorkspaceFocused = i = workspaceFocused
fmtFocus (thisMonitorFocused && thisWorkspaceFocused) (sprintf "%s%s" indent $"Workspace: {w.Name}")
|> printfn "%s"
let containerFocused = w.Containers.Focused
let containerFormatter =
formatContainer thisWorkspaceFocused thisMonitorFocused containerFocused
w.Containers.Elements
|> Seq.map ContainerElement
|> Seq.iteri (containerFormatter "Container")
match w.MonocleContainer with
| Some monocle -> containerFormatter "Container (monocle)" 0 (ContainerElement monocle)
| None -> ()
w.FloatingWindows
|> Seq.map Content
|> Seq.iteri (containerFormatter "Container (floating)")))
do! loop ()
}
loop () |> Async.RunSynchronously
sr.Close()
pipeServer.Close()