forked from nosami/visualfsharp
/
layout.fs
337 lines (293 loc) · 13.5 KB
/
layout.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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
module FSharp.Compiler.Layout
open System
open System.IO
open Internal.Utilities.StructuredFormat
open Microsoft.FSharp.Core.Printf
#nowarn "62" // This construct is for ML compatibility.
type layout = Internal.Utilities.StructuredFormat.Layout
type LayoutTag = Internal.Utilities.StructuredFormat.LayoutTag
type TaggedText = Internal.Utilities.StructuredFormat.TaggedText
type NavigableTaggedText(taggedText: TaggedText, range: Range.range) =
member val Range = range
interface TaggedText with
member _.Tag = taggedText.Tag
member _.Text = taggedText.Text
let mkNav r t = NavigableTaggedText(t, r) :> TaggedText
let spaces n = new String(' ', n)
// NOTE: emptyL might be better represented as a constructor, so then (Sep"") would have true meaning
let emptyL = Leaf (true, TaggedTextOps.mkTag LayoutTag.Text "", true)
let isEmptyL = function Leaf(true, tag, true) when tag.Text = "" -> true | _ -> false
let mkNode l r joint =
if isEmptyL l then r else
if isEmptyL r then l else
Node(l, r, joint)
//--------------------------------------------------------------------------
//INDEX: constructors
//--------------------------------------------------------------------------
let wordL (str:TaggedText) = Leaf (false, str, false)
let sepL (str:TaggedText) = Leaf (true, str, true)
let rightL (str:TaggedText) = Leaf (true, str, false)
let leftL (str:TaggedText) = Leaf (false, str, true)
module TaggedTextOps =
let tagActivePatternCase = TaggedTextOps.mkTag LayoutTag.ActivePatternCase
let tagActivePatternResult = TaggedTextOps.mkTag LayoutTag.ActivePatternResult
let tagAlias = TaggedTextOps.tagAlias
let tagClass = TaggedTextOps.tagClass
let tagUnion = TaggedTextOps.mkTag LayoutTag.Union
let tagUnionCase = TaggedTextOps.tagUnionCase
let tagDelegate = TaggedTextOps.tagDelegate
let tagEnum = TaggedTextOps.tagEnum
let tagEvent = TaggedTextOps.tagEvent
let tagField = TaggedTextOps.tagField
let tagInterface = TaggedTextOps.tagInterface
let tagKeyword = TaggedTextOps.tagKeyword
let tagLineBreak = TaggedTextOps.tagLineBreak
let tagLocal = TaggedTextOps.tagLocal
let tagRecord = TaggedTextOps.tagRecord
let tagRecordField = TaggedTextOps.tagRecordField
let tagMethod = TaggedTextOps.tagMethod
let tagMember = TaggedTextOps.mkTag LayoutTag.Member
let tagModule = TaggedTextOps.tagModule
let tagModuleBinding = TaggedTextOps.tagModuleBinding
let tagFunction = TaggedTextOps.tagFunction
let tagNamespace = TaggedTextOps.tagNamespace
let tagNumericLiteral = TaggedTextOps.tagNumericLiteral
let tagOperator = TaggedTextOps.tagOperator
let tagParameter = TaggedTextOps.tagParameter
let tagProperty = TaggedTextOps.tagProperty
let tagSpace = TaggedTextOps.tagSpace
let tagStringLiteral = TaggedTextOps.tagStringLiteral
let tagStruct = TaggedTextOps.tagStruct
let tagTypeParameter = TaggedTextOps.tagTypeParameter
let tagText = TaggedTextOps.tagText
let tagPunctuation = TaggedTextOps.tagPunctuation
let tagUnknownEntity = TaggedTextOps.mkTag LayoutTag.UnknownEntity
let tagUnknownType = TaggedTextOps.mkTag LayoutTag.UnknownType
module Literals =
// common tagged literals
let lineBreak = TaggedTextOps.Literals.lineBreak
let space = TaggedTextOps.Literals.space
let comma = TaggedTextOps.Literals.comma
let semicolon = TaggedTextOps.Literals.semicolon
let leftParen = TaggedTextOps.Literals.leftParen
let rightParen = TaggedTextOps.Literals.rightParen
let leftBracket = TaggedTextOps.Literals.leftBracket
let rightBracket = TaggedTextOps.Literals.rightBracket
let leftBrace = TaggedTextOps.Literals.leftBrace
let rightBrace = TaggedTextOps.Literals.rightBrace
let leftBraceBar = TaggedTextOps.Literals.leftBraceBar
let rightBraceBar = TaggedTextOps.Literals.rightBraceBar
let equals = TaggedTextOps.Literals.equals
let arrow = TaggedTextOps.Literals.arrow
let questionMark = TaggedTextOps.Literals.questionMark
let dot = tagPunctuation "."
let leftAngle = tagPunctuation "<"
let rightAngle = tagPunctuation ">"
let star = tagOperator "*"
let colon = tagPunctuation ":"
let minus = tagPunctuation "-"
let keywordNew = tagKeyword "new"
let leftBracketAngle = tagPunctuation "[<"
let rightBracketAngle = tagPunctuation ">]"
let structUnit = tagStruct "unit"
let keywordStatic = tagKeyword "static"
let keywordMember = tagKeyword "member"
let keywordVal = tagKeyword "val"
let keywordEvent = tagKeyword "event"
let keywordWith = tagKeyword "with"
let keywordSet = tagKeyword "set"
let keywordGet = tagKeyword "get"
let keywordTrue = tagKeyword "true"
let keywordFalse = tagKeyword "false"
let bar = tagPunctuation "|"
let keywordStruct = tagKeyword "struct"
let keywordInherit = tagKeyword "inherit"
let keywordEnd = tagKeyword "end"
let keywordNested = tagKeyword "nested"
let keywordType = tagKeyword "type"
let keywordDelegate = tagKeyword "delegate"
let keywordOf = tagKeyword "of"
let keywordInternal = tagKeyword "internal"
let keywordPrivate = tagKeyword "private"
let keywordAbstract = tagKeyword "abstract"
let keywordOverride = tagKeyword "override"
let keywordEnum = tagKeyword "enum"
let leftBracketBar = tagPunctuation "[|"
let rightBracketBar = tagPunctuation "|]"
let keywordTypeof = tagKeyword "typeof"
let keywordTypedefof = tagKeyword "typedefof"
open TaggedTextOps
module SepL =
let dot = sepL Literals.dot
let star = sepL Literals.star
let colon = sepL Literals.colon
let questionMark = sepL Literals.questionMark
let leftParen = sepL Literals.leftParen
let comma = sepL Literals.comma
let space = sepL Literals.space
let leftBracket = sepL Literals.leftBracket
let leftAngle = sepL Literals.leftAngle
let lineBreak = sepL Literals.lineBreak
let rightParen = sepL Literals.rightParen
module WordL =
let arrow = wordL Literals.arrow
let star = wordL Literals.star
let colon = wordL Literals.colon
let equals = wordL Literals.equals
let keywordNew = wordL Literals.keywordNew
let structUnit = wordL Literals.structUnit
let keywordStatic = wordL Literals.keywordStatic
let keywordMember = wordL Literals.keywordMember
let keywordVal = wordL Literals.keywordVal
let keywordEvent = wordL Literals.keywordEvent
let keywordWith = wordL Literals.keywordWith
let keywordSet = wordL Literals.keywordSet
let keywordGet = wordL Literals.keywordGet
let keywordTrue = wordL Literals.keywordTrue
let keywordFalse = wordL Literals.keywordFalse
let bar = wordL Literals.bar
let keywordStruct = wordL Literals.keywordStruct
let keywordInherit = wordL Literals.keywordInherit
let keywordEnd = wordL Literals.keywordEnd
let keywordNested = wordL Literals.keywordNested
let keywordType = wordL Literals.keywordType
let keywordDelegate = wordL Literals.keywordDelegate
let keywordOf = wordL Literals.keywordOf
let keywordInternal = wordL Literals.keywordInternal
let keywordPrivate = wordL Literals.keywordPrivate
let keywordAbstract = wordL Literals.keywordAbstract
let keywordOverride = wordL Literals.keywordOverride
let keywordEnum = wordL Literals.keywordEnum
module LeftL =
let leftParen = leftL Literals.leftParen
let questionMark = leftL Literals.questionMark
let colon = leftL Literals.colon
let leftBracketAngle = leftL Literals.leftBracketAngle
let leftBracketBar = leftL Literals.leftBracketBar
let keywordTypeof = leftL Literals.keywordTypeof
let keywordTypedefof = leftL Literals.keywordTypedefof
module RightL =
let comma = rightL Literals.comma
let rightParen = rightL Literals.rightParen
let colon = rightL Literals.colon
let rightBracket = rightL Literals.rightBracket
let rightAngle = rightL Literals.rightAngle
let rightBracketAngle = rightL Literals.rightBracketAngle
let rightBracketBar = rightL Literals.rightBracketBar
let aboveL l r = mkNode l r (Broken 0)
let tagAttrL str attrs ly = Attr (str, attrs, ly)
//--------------------------------------------------------------------------
//INDEX: constructors derived
//--------------------------------------------------------------------------
let apply2 f l r = if isEmptyL l then r else
if isEmptyL r then l else f l r
let (^^) l r = mkNode l r (Unbreakable)
let (++) l r = mkNode l r (Breakable 0)
let (--) l r = mkNode l r (Breakable 1)
let (---) l r = mkNode l r (Breakable 2)
let (----) l r = mkNode l r (Breakable 3)
let (-----) l r = mkNode l r (Breakable 4)
let (@@) l r = apply2 (fun l r -> mkNode l r (Broken 0)) l r
let (@@-) l r = apply2 (fun l r -> mkNode l r (Broken 1)) l r
let (@@--) l r = apply2 (fun l r -> mkNode l r (Broken 2)) l r
let tagListL tagger = function
| [] -> emptyL
| [x] -> x
| x :: xs ->
let rec process' prefixL = function
| [] -> prefixL
| y :: ys -> process' ((tagger prefixL) ++ y) ys in
process' x xs
let commaListL x = tagListL (fun prefixL -> prefixL ^^ rightL Literals.comma) x
let semiListL x = tagListL (fun prefixL -> prefixL ^^ rightL Literals.semicolon) x
let spaceListL x = tagListL (fun prefixL -> prefixL) x
let sepListL x y = tagListL (fun prefixL -> prefixL ^^ x) y
let bracketL l = leftL Literals.leftParen ^^ l ^^ rightL Literals.rightParen
let tupleL xs = bracketL (sepListL (sepL Literals.comma) xs)
let aboveListL = function
| [] -> emptyL
| [x] -> x
| x :: ys -> List.fold (fun pre y -> pre @@ y) x ys
let optionL xL = function
| None -> wordL (tagUnionCase "None")
| Some x -> wordL (tagUnionCase "Some") -- (xL x)
let listL xL xs = leftL Literals.leftBracket ^^ sepListL (sepL Literals.semicolon) (List.map xL xs) ^^ rightL Literals.rightBracket
//--------------------------------------------------------------------------
//INDEX: LayoutRenderer
//--------------------------------------------------------------------------
type LayoutRenderer<'a, 'b> =
abstract Start : unit -> 'b
abstract AddText : 'b -> TaggedText -> 'b
abstract AddBreak : 'b -> int -> 'b
abstract AddTag : 'b -> string * (string * string) list * bool -> 'b
abstract Finish : 'b -> 'a
let renderL (rr: LayoutRenderer<_, _>) layout =
let rec addL z pos i layout k =
match layout with
| ObjLeaf _ -> failwith "ObjLeaf should never appear here"
(* pos is tab level *)
| Leaf (_, text, _) ->
k(rr.AddText z text, i + text.Text.Length)
| Node (l, r, Broken indent) ->
addL z pos i l <|
fun (z, _i) ->
let z, i = rr.AddBreak z (pos+indent), (pos+indent)
addL z (pos+indent) i r k
| Node (l, r, _) ->
let jm = Layout.JuxtapositionMiddle (l, r)
addL z pos i l <|
fun (z, i) ->
let z, i = if jm then z, i else rr.AddText z Literals.space, i+1
let pos = i
addL z pos i r k
| Attr (tag, attrs, l) ->
let z = rr.AddTag z (tag, attrs, true)
addL z pos i l <|
fun (z, i) ->
let z = rr.AddTag z (tag, attrs, false)
k(z, i)
let pos = 0
let z, i = rr.Start(), 0
let z, _i = addL z pos i layout id
rr.Finish z
/// string render
let stringR =
{ new LayoutRenderer<string, string list> with
member _.Start () = []
member _.AddText rstrs taggedText = taggedText.Text :: rstrs
member _.AddBreak rstrs n = (spaces n) :: "\n" :: rstrs
member _.AddTag z (_, _, _) = z
member _.Finish rstrs = String.Join("", Array.ofList (List.rev rstrs)) }
type NoState = NoState
type NoResult = NoResult
/// string render
let taggedTextListR collector =
{ new LayoutRenderer<NoResult, NoState> with
member _.Start () = NoState
member _.AddText z text = collector text; z
member _.AddBreak rstrs n = collector Literals.lineBreak; collector (tagSpace(spaces n)); rstrs
member _.AddTag z (_, _, _) = z
member _.Finish rstrs = NoResult }
/// channel LayoutRenderer
let channelR (chan:TextWriter) =
{ new LayoutRenderer<NoResult, NoState> with
member r.Start () = NoState
member r.AddText z s = chan.Write s.Text; z
member r.AddBreak z n = chan.WriteLine(); chan.Write (spaces n); z
member r.AddTag z (tag, attrs, start) = z
member r.Finish z = NoResult }
/// buffer render
let bufferR os =
{ new LayoutRenderer<NoResult, NoState> with
member r.Start () = NoState
member r.AddText z s = bprintf os "%s" s.Text; z
member r.AddBreak z n = bprintf os "\n"; bprintf os "%s" (spaces n); z
member r.AddTag z (tag, attrs, start) = z
member r.Finish z = NoResult }
//--------------------------------------------------------------------------
//INDEX: showL, outL are most common
//--------------------------------------------------------------------------
let showL layout = renderL stringR layout
let outL (chan:TextWriter) layout = renderL (channelR chan) layout |> ignore
let bufferL os layout = renderL (bufferR os) layout |> ignore