Skip to content
This repository was archived by the owner on Jan 3, 2019. It is now read-only.

Commit e8f8daf

Browse files
committed
Merge pull request #266 from fsharp/refactorIdentParsing
Simplify, rename, refactor Ident parsing
2 parents aae7a6a + 1ae87ad commit e8f8daf

File tree

4 files changed

+93
-131
lines changed

4 files changed

+93
-131
lines changed

FSharp.AutoComplete/Program.fs

+3-39
Original file line numberDiff line numberDiff line change
@@ -219,15 +219,7 @@ type internal IntelliSenseAgent() =
219219
member x.DoCompletion(opts : RequestOptions, ((line, column) as pos), lineStr, time) : Option<DeclarationSet * String> =
220220
let info = x.GetTypeCheckInfo(opts, time)
221221
Option.bind (fun (info: TypeCheckResults) ->
222-
// Get the long identifier before the current location
223-
// 'residue' is the part after the last dot and 'longName' is before
224-
// e.g. System.Console.Wri --> "Wri", [ "System"; "Console"; ]
225-
let lookBack = Parsing.createBackStringReader lineStr (column - 1)
226-
let results = Parser.apply Parsing.parseBackIdentWithEitherResidue lookBack
227-
let residue, longName =
228-
List.sortBy (fun (s,ss) -> String.length s + (List.sumBy String.length ss)) results
229-
|> List.rev
230-
|> List.head
222+
let longName, residue = Parsing.findLongIdentsAndResidue (column, lineStr)
231223

232224
// Get items & generate output
233225
try
@@ -236,34 +228,6 @@ type internal IntelliSenseAgent() =
236228
with :? System.TimeoutException as e ->
237229
None) info
238230

239-
member private x.FindLongIdents(lineStr, col) =
240-
// Parsing - find the identifier around the current location
241-
// (we look for full identifier in the backward direction, but only
242-
// for a short identifier forward - this means that when you hover
243-
// 'B' in 'A.B.C', you will get intellisense for 'A.B' module)
244-
let lookBack = Parsing.createBackStringReader lineStr (col-1)
245-
let lookForw = Parsing.createForwardStringReader lineStr col
246-
247-
let backIdentOpt = Parsing.tryGetFirst Parsing.parseBackLongIdent lookBack
248-
match backIdentOpt with
249-
| None -> None
250-
| Some backIdent ->
251-
let nextIdentOpt = Parsing.tryGetFirst Parsing.parseIdent lookForw
252-
match nextIdentOpt with
253-
| None -> None
254-
| Some nextIdent ->
255-
256-
let currentIdent, identIsland =
257-
match List.rev backIdent with
258-
| last::prev ->
259-
let current = last + nextIdent
260-
current, current::prev |> List.rev
261-
| [] -> "", []
262-
263-
match identIsland with
264-
| [] | [ "" ] -> None
265-
| _ -> Some (col + nextIdent.Length, identIsland)
266-
267231
/// Gets ToolTip for the specified location (and prints it to the output)
268232
member x.GetToolTip(opts, ((line, column) as pos), lineStr, time) : Option<DataTipText> =
269233

@@ -273,7 +237,7 @@ type internal IntelliSenseAgent() =
273237
// case when we're in a string in '#r "Foo.dll"' but we don't do that)
274238
info.GetDataTipText((line,col'), lineStr, identIsland, identToken)
275239
) (x.GetTypeCheckInfo(opts, time))
276-
) (x.FindLongIdents(lineStr, column))
240+
) (Parsing.findLongIdents(column, lineStr))
277241

278242
/// Finds the point of declaration of the symbol at pos
279243
/// and writes information to the standard output
@@ -285,7 +249,7 @@ type internal IntelliSenseAgent() =
285249
// case when we're in a string in '#r "Foo.dll"' but we don't do that)
286250
info.GetDeclarationLocation((line,col'), lineStr, identIsland, identToken, true)
287251
) (x.GetTypeCheckInfo(opts, time))
288-
) (x.FindLongIdents(lineStr, column))
252+
) (Parsing.findLongIdents(column, lineStr))
289253

290254

291255

FSharp.CompilerBinding/Parser.fs

+60
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ module Parser =
138138
/// of the current cursor location etc.)
139139
module Parsing =
140140
open Parser
141+
open System.Diagnostics
141142

142143
let inline isFirstOpChar ch =
143144
ch = '!' || ch = '%'|| ch = '&' || ch = '*'|| ch = '+'|| ch = '-'|| ch = '.'|| ch = '/'|| ch = '<'|| ch = '='|| ch = '>'|| ch = '@'|| ch = '^'|| ch = '|'|| ch = '~'
@@ -265,3 +266,62 @@ module Parsing =
265266
let getFirst p s = apply p s |> List.head
266267
let tryGetFirst p s = match apply p s with h::_ -> Some h | [] -> None
267268

269+
270+
// Parsing - find the identifier around the current location
271+
// (we look for full identifier in the backward direction, but only
272+
// for a short identifier forward - this means that when you hover
273+
// 'B' in 'A.B.C', you will get intellisense for 'A.B' module)
274+
let findLongIdents (col, lineStr) =
275+
let lookBack = createBackStringReader lineStr (col-1)
276+
let lookForw = createForwardStringReader lineStr col
277+
278+
let backIdentOpt = tryGetFirst parseBackLongIdent lookBack
279+
match backIdentOpt with
280+
| None -> None
281+
| Some backIdent ->
282+
let nextIdentOpt = tryGetFirst parseIdent lookForw
283+
match nextIdentOpt with
284+
| None -> None
285+
| Some nextIdent ->
286+
287+
let identIsland =
288+
match List.rev backIdent with
289+
| last::prev ->
290+
let current = last + nextIdent
291+
current::prev |> List.rev
292+
| [] -> []
293+
294+
Debug.WriteLine(sprintf "Result: Crack symbol text at column %d\nIdentifier: %A (Current: %s) \nLine string: %s"
295+
col identIsland lineStr)
296+
297+
match identIsland with
298+
| [] | [ "" ] -> None
299+
| _ -> Some (col + nextIdent.Length,identIsland)
300+
301+
/// find the identifier prior to a '(' or ',' once the method tip trigger '(' shows
302+
let findLongIdentsAtGetMethodsTrigger (col, lineStr) =
303+
let lookBack = createBackStringReader lineStr col
304+
let backIdentOpt = tryGetFirst parseBackTriggerThenLongIdent lookBack
305+
match backIdentOpt with
306+
| None -> None
307+
| Some backIdent ->
308+
309+
let identIsland =
310+
match List.rev backIdent with
311+
| last::prev -> (last::prev |> List.rev)
312+
| [] -> []
313+
314+
match identIsland with
315+
| [] | [ "" ] -> None
316+
| _ -> Some (col,identIsland)
317+
318+
/// Returns the previous long idents and the current 'residue'
319+
let findLongIdentsAndResidue (col, lineStr) =
320+
let lookBack = createBackStringReader lineStr (col - 1)
321+
let results = apply parseBackIdentWithEitherResidue lookBack
322+
let residue, longName =
323+
List.sortBy (fun (s,ss) -> String.length s + (List.sumBy String.length ss)) results
324+
|> List.rev
325+
|> List.head
326+
327+
(longName, residue)

monodevelop/MonoDevelop.FSharpBinding/FSharpTextEditorCompletion.fs

+8-6
Original file line numberDiff line numberDiff line change
@@ -292,12 +292,14 @@ type FSharpTextEditorCompletion() =
292292
let tyRes = LanguageService.Service.GetTypedParseResult(x.Document.FileName, x.Document.Editor.Text, x.Document.Project, config, allowRecentTypeCheckResults, timeout = ServiceSettings.blockingTimeout)
293293

294294
// Get declarations and generate list for MonoDevelop
295-
let decls = tyRes.GetDeclarations(x.Document, context)
296-
if decls.Items.Length > 0 then
297-
let result = CompletionDataList()
298-
for mi in decls.Items do result.Add(new FSharpMemberCompletionData(mi))
299-
result :> ICompletionDataList
300-
else null
295+
match tyRes.GetDeclarations(x.Document, context) with
296+
| Some(decls, residue) when decls.Items.Any() ->
297+
let items = decls.Items
298+
|> Array.map (fun mi -> FSharpMemberCompletionData(mi) :> ICompletionData)
299+
let result = CompletionDataList()
300+
result.AddRange(items)
301+
result :> ICompletionDataList
302+
| _ -> null
301303

302304
with
303305
| :? System.TimeoutException ->

monodevelop/MonoDevelop.FSharpBinding/Services/LanguageService.fs

+22-86
Original file line numberDiff line numberDiff line change
@@ -338,115 +338,51 @@ module internal TipFormatter =
338338
type internal TypedParseResult(info:TypeCheckResults, untyped : UntypedParseInfo) =
339339
let token = Parser.tagOfToken(Parser.token.IDENT(""))
340340

341-
let preCrack (offset, doc:Mono.TextEditor.TextDocument) =
341+
let getLineInfoFromOffset (offset, doc:Mono.TextEditor.TextDocument) =
342342
let loc = doc.OffsetToLocation(offset)
343343
let line, col = max (loc.Line - 1) 0, loc.Column-1
344344
let currentLine = doc.Lines |> Seq.nth line
345345
let lineStr = doc.Text.Substring(currentLine.Offset, currentLine.EndOffset - currentLine.Offset)
346-
(loc, line, col, currentLine, lineStr)
347-
348-
// Parsing - find the identifier around the current location
349-
// (we look for full identifier in the backward direction, but only
350-
// for a short identifier forward - this means that when you hover
351-
// 'B' in 'A.B.C', you will get intellisense for 'A.B' module)
352-
let crackSymbolText (offset:int, doc:Mono.TextEditor.TextDocument) =
353-
354-
let loc, line, col, currentLine, lineStr = preCrack (offset, doc)
355-
356-
let lookBack = Parsing.createBackStringReader lineStr (col-1)
357-
let lookForw = Parsing.createForwardStringReader lineStr col
358-
359-
let backIdentOpt = Parsing.tryGetFirst Parsing.parseBackLongIdent lookBack
360-
match backIdentOpt with
361-
| None -> None
362-
| Some backIdent ->
363-
let nextIdentOpt = Parsing.tryGetFirst Parsing.parseIdent lookForw
364-
match nextIdentOpt with
365-
| None -> None
366-
| Some nextIdent ->
367-
368-
let currentIdent, identIsland =
369-
match List.rev backIdent with
370-
| last::prev ->
371-
let current = last + nextIdent
372-
current, current::prev |> List.rev
373-
| [] -> "", []
374-
375-
Debug.WriteLine(sprintf "Result: Crack symbol text at %d:%d (offset %d - %d)\nIdentifier: %A (Current: %s) \nLine string: %s"
376-
line col currentLine.Offset currentLine.EndOffset identIsland currentIdent lineStr)
377-
378-
match identIsland with
379-
| [] | [ "" ] -> None
380-
| _ -> Some (line,col + nextIdent.Length,lineStr,identIsland,currentIdent,token)
381-
382-
/// Crack the info prior to a '(' or ',' once the method tip trigger '(' shows
383-
let crackSymbolTextAtGetMethodsTrigger (offset:int, doc:Mono.TextEditor.TextDocument) =
384-
385-
let loc, line, col, currentLine, lineStr = preCrack (offset, doc)
386-
let lookBack = Parsing.createBackStringReader lineStr col
387-
let backIdentOpt = Parsing.tryGetFirst Parsing.parseBackTriggerThenLongIdent lookBack
388-
match backIdentOpt with
389-
| None -> None
390-
| Some backIdent ->
391-
392-
let currentIdent, identIsland =
393-
match List.rev backIdent with
394-
| last::prev -> last, (last::prev |> List.rev)
395-
| [] -> "", []
396-
397-
match identIsland with
398-
| [] | [ "" ] -> None
399-
| _ -> Some (line,col,lineStr,identIsland,currentIdent,token)
400-
346+
(line, col, lineStr)
401347

402348
/// Get declarations at the current location in the specified document
403349
/// (used to implement dot-completion in 'FSharpTextEditorCompletion.fs')
404350
member x.GetDeclarations(doc:Document, context: CodeCompletion.CodeCompletionContext) =
405-
let lineStr = doc.Editor.GetLineText(doc.Editor.Caret.Line)
406-
407-
// Get the long identifier before the current location
408-
// 'residue' is the part after the last dot and 'longName' is before
409-
// e.g. System.Debug.Wri --> "Wri", [ "System"; "Debug"; ]
410-
let lookBack = Parsing.createBackStringReader lineStr (doc.Editor.Caret.Column - 2)
411-
match Parsing.tryGetFirst Parsing.parseBackIdentWithResidue lookBack with
412-
| None -> DeclarationSet.Empty
413-
| Some (residue, longName) ->
414-
415-
Debug.WriteLine(sprintf "Result: GetDeclarations: line: %d, column: %d, ident: %A\n Line: '%s'" (doc.Editor.Caret.Line - 1) (doc.Editor.Caret.Column - 1) (longName, residue) lineStr)
416-
417-
//Review: last parameter is a function has changes since last type check, we always return false here.
418-
//let longName = if longName = [""] then [] else longName
419-
let getDeclarations = info.GetDeclarations(Some(untyped), (doc.Editor.Caret.Line - 1, doc.Editor.Caret.Column - 1), lineStr, (longName, residue), fun _ -> false)
420-
421-
let declarations = Async.RunSynchronously(getDeclarations, ServiceSettings.blockingTimeout)
351+
let line, col, lineStr = getLineInfoFromOffset(doc.Editor.Caret.Offset, doc.Editor.Document)
352+
let longName, residue = Parsing.findLongIdentsAndResidue(col, lineStr)
422353

423-
Debug.WriteLine(sprintf "Result: GetDeclarations: returning %d items" declarations.Items.Length)
424-
declarations
354+
// Get items & generate output
355+
try Some (info.GetDeclarations(None, (line,col), lineStr, (longName, residue), fun (_,_) -> false)
356+
|> Async.RunSynchronously, residue)
357+
with :? TimeoutException as e -> None
425358

426-
/// Get the tool-tip to be displayed at the specified offset (relatively
427-
/// from the beginning of the current document)
359+
/// Get the tool-tip to be displayed at the specified offset (relatively
360+
/// from the beginning of the current document)
428361
member x.GetToolTip(offset:int, doc:Mono.TextEditor.TextDocument) =
429-
match crackSymbolText(offset, doc) with
362+
let line, col, lineStr = getLineInfoFromOffset(offset, doc)
363+
match Parsing.findLongIdents(col, lineStr) with
430364
| None -> DataTipText []
431-
| Some(line,col,lineStr,identIsland,currentIdent,token) ->
365+
| Some(col,identIsland) ->
432366
let res = info.GetDataTipText((line, col), lineStr, identIsland, token)
433-
Debug.WriteLine( "Result: Got something, returning" )
367+
Debug.WriteLine("Result: Got something, returning")
434368
res
435369

436370
member x.GetDeclarationLocation(offset:int, doc:Mono.TextEditor.TextDocument) =
437-
match crackSymbolText(offset, doc) with
371+
let line, col, lineStr = getLineInfoFromOffset(offset, doc)
372+
match Parsing.findLongIdents(col, lineStr) with
438373
| None -> DeclNotFound FindDeclFailureReason.Unknown
439-
| Some(line,col,lineStr,identIsland,currentIdent,token) ->
374+
| Some(col,identIsland) ->
440375
let res = info.GetDeclarationLocation((line, col), lineStr, identIsland, token, true)
441-
Debug.WriteLine( "Result: Got something, returning" )
376+
Debug.WriteLine("Result: Got something, returning")
442377
res
443378

444379
member x.GetMethods(offset:int, doc:Mono.TextEditor.TextDocument) =
445-
match crackSymbolTextAtGetMethodsTrigger(offset, doc) with
380+
let line, col, lineStr = getLineInfoFromOffset (offset, doc)
381+
match Parsing.findLongIdentsAtGetMethodsTrigger(col, lineStr) with
446382
| None -> None
447-
| Some(line,col,lineStr,identIsland,currentIdent,token) ->
383+
| Some(col,identIsland) ->
448384
let res = info.GetMethods((line, col), lineStr, Some identIsland)
449-
Debug.WriteLine( "Result: Got something, returning" )
385+
Debug.WriteLine("Result: Got something, returning")
450386
Some (res.Name, res.Methods)
451387

452388
member x.Untyped with get() = untyped

0 commit comments

Comments
 (0)