@@ -4,17 +4,20 @@ open System
44open FSharp.Compiler .CodeAnalysis
55open FSharp.Compiler .EditorServices
66open FSharp.Compiler .Text
7+ open FSharp.Compiler .Text .Range
78open FSharp.Compiler .Tokenization
89
910type SourceContext =
1011 { Source: string
1112 LineText: string
12- CaretPos: pos }
13+ CaretPos: pos
14+ SelectedRange: range option }
1315
1416type ResolveContext =
1517 { SourceContext: SourceContext
1618 Pos: pos
17- Names: string list }
19+ Names: string list
20+ SelectedRange: range option }
1821
1922 member this.Source = this.SourceContext.Source
2023 member this.LineText = this.SourceContext.LineText
@@ -29,16 +32,82 @@ type CodeCompletionContext =
2932
3033[<RequireQualifiedAccess>]
3134module SourceContext =
35+ let private markers = [ " {caret}" ; " {selstart}" ; " {selend}" ]
36+
37+ let getLines ( source : string ) =
38+ source.Split([| " \r\n " ; " \n " |], StringSplitOptions.None)
39+
40+ let rec private extractMarkersOnLine markersAcc ( line , lineText : string ) =
41+ let markersOnLine =
42+ markers
43+ |> List.choose ( fun ( marker : string ) ->
44+ match lineText.IndexOf( marker) with
45+ | - 1 -> None
46+ | column -> Some( marker, column)
47+ )
48+
49+ if markersOnLine.IsEmpty then
50+ markersAcc
51+ else
52+ let marker , column = List.minBy snd markersOnLine
53+
54+ let markerPos =
55+ let column =
56+ match marker with
57+ | " {caret}" -> column - 1
58+ | _ -> column
59+
60+ Position.mkPos ( line + 1 ) column
61+
62+ if markersAcc |> List.map fst |> List.contains marker then
63+ failwith $" Duplicate marker: {marker}"
64+
65+ let markersAcc = ( marker, markerPos) :: markersAcc
66+ let lineText = lineText.Replace( marker, " " )
67+
68+ extractMarkersOnLine markersAcc ( line, lineText)
69+
3270 let fromMarkedSource ( markedSource : string ) : SourceContext =
33- let lines = markedSource.Split([| " \r\n " ; " \n " |], StringSplitOptions.None)
34- let line = lines |> Seq.findIndex _. Contains( " {caret}" )
35- let lineText = lines[ line]
36- let column = lineText.IndexOf( " {caret}" )
71+ let markerPositions =
72+ getLines markedSource
73+ |> Seq.indexed
74+ |> Seq.fold extractMarkersOnLine []
75+
76+ let source =
77+ markerPositions
78+ |> List.map fst
79+ |> List.fold ( fun ( source : string ) marker -> source.Replace( marker, " " )) markedSource
80+
81+ let markerPositions = markerPositions |> dict
82+
83+ let tryGetPos marker =
84+ match markerPositions.TryGetValue( marker) with
85+ | true , pos -> Some pos
86+ | _ -> None
87+
88+ let caretPos , selectedRange =
89+ match tryGetPos " {caret}" , tryGetPos " {selstart}" , tryGetPos " {selend}" with
90+ | Some caretPos, None, None ->
91+ caretPos, None
92+
93+ | Some caretPos, Some startPos, Some endPos ->
94+ let selectedRange = mkRange " Test.fsx" startPos endPos
95+ caretPos, Some selectedRange
96+
97+ | None, Some startPos, Some endPos ->
98+ let selectedRange = mkRange " Test.fsx" startPos endPos
99+ let caretPos = Position.mkPos endPos.Line ( endPos.Column - 1 )
100+ caretPos, Some selectedRange
101+
102+ | _, None, Some _ -> failwith " Missing selected range start"
103+ | _, Some _, None -> failwith " Missing selected range end"
104+
105+ | None, None, None -> failwith " Missing caret marker"
106+
107+ let lines = getLines source
108+ let lineText = Array.get lines ( caretPos.Line - 1 )
37109
38- let source = markedSource.Replace( " {caret}" , " " )
39- let pos = Position.mkPos ( line + 1 ) ( column - 1 )
40- let lineText = lineText.Replace( " {caret}" , " " )
41- { Source = source; CaretPos = pos; LineText = lineText }
110+ { Source = source; CaretPos = caretPos; LineText = lineText; SelectedRange = selectedRange }
42111
43112
44113[<AutoOpen>]
@@ -70,7 +139,7 @@ module Checker =
70139
71140 let plid = QuickParse.GetPartialLongNameEx( context.LineText, pos.Column - 1 )
72141 let names = plid.QualifyingIdents @ [ plid.PartialIdent]
73- { SourceContext = context; Pos = pos; Names = names }
142+ { SourceContext = context; Pos = pos; Names = names; SelectedRange = context.SelectedRange }
74143
75144 let getCompletionContext ( markedSource : string ) =
76145 let context = SourceContext.fromMarkedSource markedSource
0 commit comments