Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make symboluse command more robust again #46

Merged
merged 1 commit into from
Jul 30, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions FsAutoComplete/CommandResponse.fs
Original file line number Diff line number Diff line change
Expand Up @@ -218,11 +218,11 @@ module CommandResponse =
let (glyph, glyphChar) = CompletionUtils.getIcon d.Glyph
yield { Name = d.Name; Glyph = glyph; GlyphChar = glyphChar } ] }

let symbolUse(symboluses: FSharpSymbolUse[]) =
let symbolUse(symbol: FSharpSymbolUse, uses: FSharpSymbolUse[]) =
let su =
{ Name = symboluses.[0].Symbol.DisplayName
{ Name = symbol.Symbol.DisplayName
Uses =
[ for su in symboluses do
[ for su in uses do
yield { StartLine = su.RangeAlternate.StartLine
StartColumn = su.RangeAlternate.StartColumn + 1
EndLine = su.RangeAlternate.EndLine
Expand Down
2 changes: 1 addition & 1 deletion FsAutoComplete/CompilerServiceInterface.fs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ type ParseAndCheckResults(parseResults: FSharpParseFileResults,
| Some symboluse ->

let! symboluses = checkResults.GetUsesOfSymbolInFile symboluse.Symbol
return Success symboluses }
return Success (symboluse, symboluses) }
|> Async.RunSynchronously

member x.TryGetCompletions line col lineStr timeout filter =
Expand Down
282 changes: 144 additions & 138 deletions FsAutoComplete/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -80,160 +80,166 @@ module internal Main =
let rec main (state:State) : int =
currentFiles <- state.Files

match CommandInput.parseCommand(Console.ReadLine()) with
| Parse(file,kind) ->
let parse fileName text options =
let task =
async {
let! _parseResults, checkResults = checker.ParseAndCheckFileInProject(fileName, 0, text, options)
match checkResults with
| FSharpCheckFileAnswer.Aborted -> ()
| FSharpCheckFileAnswer.Succeeded results -> Response.errors(results.Errors)
}
match kind with
| Synchronous -> Response.info "Synchronous parsing started"
Async.RunSynchronously task
| Normal -> Response.info "Background parsing started"
Async.StartImmediate task

let file = Path.GetFullPath file
let lines = CommandInput.readInput [] |> Array.ofList

let text = String.concat "\n" lines

if Utils.isAScript file then
let checkOptions = checker.GetProjectOptionsFromScript(file, text)
let state = state.WithFileTextAndCheckerOptions(file, lines, checkOptions)
parse file text checkOptions
main state
else
let state, checkOptions = state.WithFileTextGetCheckerOptions(file, lines)
parse file text checkOptions
main state

| Project file ->
let file = Path.GetFullPath file
match checker.TryGetProjectOptions(file) with
| Result.Failure s ->
Response.error(s)
try
match CommandInput.parseCommand(Console.ReadLine()) with
| Parse(file,kind) ->
let parse fileName text options =
let task =
async {
let! _parseResults, checkResults = checker.ParseAndCheckFileInProject(fileName, 0, text, options)
match checkResults with
| FSharpCheckFileAnswer.Aborted -> ()
| FSharpCheckFileAnswer.Succeeded results -> Response.errors(results.Errors)
}
match kind with
| Synchronous -> Response.info "Synchronous parsing started"
Async.RunSynchronously task
| Normal -> Response.info "Background parsing started"
Async.StartImmediate task

let file = Path.GetFullPath file
let lines = CommandInput.readInput [] |> Array.ofList

let text = String.concat "\n" lines

if Utils.isAScript file then
let checkOptions = checker.GetProjectOptionsFromScript(file, text)
let state = state.WithFileTextAndCheckerOptions(file, lines, checkOptions)
parse file text checkOptions
main state
else
let state, checkOptions = state.WithFileTextGetCheckerOptions(file, lines)
parse file text checkOptions
main state

| Result.Success(po, projectFiles, outFileOpt, references, frameworkOpt) ->
Response.project(file, projectFiles, outFileOpt, references, frameworkOpt)

let projects =
projectFiles
|> List.fold (fun s f -> Map.add f po s) state.FileCheckOptions
main { state with FileCheckOptions = projects }

| Declarations file ->
let file = Path.GetFullPath file
match state.TryGetFileCheckerOptionsWithSource(file) with
| Failure s -> Response.error(s)
| Success (checkOptions, source) ->
let decls = checker.GetDeclarations(file, source, checkOptions)
Response.declarations(decls)

main state

| HelpText sym ->
match Map.tryFind sym state.HelpText with
| None -> Response.error (sprintf "No help text available for symbol '%s'" sym)
| Some tip -> Response.helpText(sym, tip)

main state

| PosCommand(cmd, file, line, col, timeout, filter) ->
let file = Path.GetFullPath file
match state.TryGetFileCheckerOptionsWithLinesAndLineStr(file, line, col) with
| Failure s -> Response.error(s)
main state
| Success (options, lines, lineStr) ->
// TODO: Should sometimes pass options.Source in here to force a reparse
// for completions e.g. `(some typed expr).$`
let tyResOpt = checker.TryGetRecentTypeCheckResultsForFile(file, options)
match tyResOpt with
| None -> Response.error "Cached typecheck results not yet available"; main state
| Some tyRes ->

match cmd with
| Completion ->
match tyRes.TryGetCompletions line col lineStr timeout filter with
| Some (decls, residue) ->
let declName (d: FSharpDeclarationListItem) = d.Name

// Send the first helptext without being requested.
// This allows it to be displayed immediately in the editor.
let firstMatchOpt =
Array.sortBy declName decls
|> Array.tryFind (fun d -> (declName d).StartsWith residue)
match firstMatchOpt with
| None -> ()
| Some d -> Response.helpText(d.Name, d.DescriptionText)

Response.completion(decls)

let helptext =
Seq.fold (fun m d -> Map.add (declName d) d.DescriptionText m) Map.empty decls
main { state with HelpText = helptext }

| None ->
Response.error "Timed out while fetching completions"
main state

| ToolTip ->
// A failure is only info here, as this command is expected to be
// used 'on idle', and frequent errors are expected.
match tyRes.TryGetToolTip line col lineStr with
| Result.Failure s -> Response.info(s)
| Result.Success tip -> Response.toolTip(tip)

| Project file ->
let file = Path.GetFullPath file
match checker.TryGetProjectOptions(file) with
| Result.Failure s ->
Response.error(s)
main state

| SymbolUse ->
// A failure is only info here, as this command is expected to be
// used 'on idle', and frequent errors are expected.
match tyRes.TryGetSymbolUse line col lineStr with
| Result.Failure s -> Response.info(s)
| Result.Success su -> Response.symbolUse(su)
| Result.Success(po, projectFiles, outFileOpt, references, frameworkOpt) ->
Response.project(file, projectFiles, outFileOpt, references, frameworkOpt)

main state
let projects =
projectFiles
|> List.fold (fun s f -> Map.add f po s) state.FileCheckOptions
main { state with FileCheckOptions = projects }

| FindDeclaration ->
match tyRes.TryFindDeclaration line col lineStr with
| Result.Failure s -> Response.error s
| Result.Success range -> Response.findDeclaration(range)
| Declarations file ->
let file = Path.GetFullPath file
match state.TryGetFileCheckerOptionsWithSource(file) with
| Failure s -> Response.error(s)
| Success (checkOptions, source) ->
let decls = checker.GetDeclarations(file, source, checkOptions)
Response.declarations(decls)

main state
main state

| Methods ->
match tyRes.TryGetMethodOverrides lines line col with
| Result.Failure s -> Response.error s
| Result.Success (meth, commas) -> Response.methods(meth, commas)
| HelpText sym ->
match Map.tryFind sym state.HelpText with
| None -> Response.error (sprintf "No help text available for symbol '%s'" sym)
| Some tip -> Response.helpText(sym, tip)

main state
main state

| CompilerLocation ->
let locopt = FSharpEnvironment.BinFolderOfDefaultFSharpCompiler None
match locopt with
| None -> Response.error "Could not find compiler"
| Some loc -> Response.message("compilerlocation", loc)
| PosCommand(cmd, file, line, col, timeout, filter) ->
let file = Path.GetFullPath file
match state.TryGetFileCheckerOptionsWithLinesAndLineStr(file, line, col) with
| Failure s -> Response.error(s)
main state
| Success (options, lines, lineStr) ->
// TODO: Should sometimes pass options.Source in here to force a reparse
// for completions e.g. `(some typed expr).$`
let tyResOpt = checker.TryGetRecentTypeCheckResultsForFile(file, options)
match tyResOpt with
| None -> Response.error "Cached typecheck results not yet available"; main state
| Some tyRes ->

match cmd with
| Completion ->
match tyRes.TryGetCompletions line col lineStr timeout filter with
| Some (decls, residue) ->
let declName (d: FSharpDeclarationListItem) = d.Name

// Send the first helptext without being requested.
// This allows it to be displayed immediately in the editor.
let firstMatchOpt =
Array.sortBy declName decls
|> Array.tryFind (fun d -> (declName d).StartsWith residue)
match firstMatchOpt with
| None -> ()
| Some d -> Response.helpText(d.Name, d.DescriptionText)

Response.completion(decls)

let helptext =
Seq.fold (fun m d -> Map.add (declName d) d.DescriptionText m) Map.empty decls
main { state with HelpText = helptext }

| None ->
Response.error "Timed out while fetching completions"
main state

| ToolTip ->
// A failure is only info here, as this command is expected to be
// used 'on idle', and frequent errors are expected.
match tyRes.TryGetToolTip line col lineStr with
| Result.Failure s -> Response.info(s)
| Result.Success tip -> Response.toolTip(tip)

main state

| SymbolUse ->
// A failure is only info here, as this command is expected to be
// used 'on idle', and frequent errors are expected.
match tyRes.TryGetSymbolUse line col lineStr with
| Result.Failure s -> Response.info(s)
| Result.Success (sym,usages) -> Response.symbolUse(sym,usages)

main state

| FindDeclaration ->
match tyRes.TryFindDeclaration line col lineStr with
| Result.Failure s -> Response.error s
| Result.Success range -> Response.findDeclaration(range)

main state

| Methods ->
match tyRes.TryGetMethodOverrides lines line col with
| Result.Failure s -> Response.error s
| Result.Success (meth, commas) -> Response.methods(meth, commas)

main state

| CompilerLocation ->
let locopt = FSharpEnvironment.BinFolderOfDefaultFSharpCompiler None
match locopt with
| None -> Response.error "Could not find compiler"
| Some loc -> Response.message("compilerlocation", loc)

main state
main state

| Error(msg) ->
Response.error msg
main state
| Error(msg) ->
Response.error msg
main state

| Quit ->
(!Debug.output).Close ()
0
| Quit ->
(!Debug.output).Close ()
0

with e ->
let msg = "Unexpected internal error. Please report at\
https://github.com/fsharp/FsAutoComplete/issues,\
attaching the following stack trace:\n"
+ e.Message + e.StackTrace
Response.error msg
main state

[<EntryPoint>]
let entry args =
// System.Diagnostics.Debug.Listeners.Add(
// new System.Diagnostics.TextWriterTraceListener(Console.Out))
// |> ignore
let extra = Options.p.Parse args
if extra.Count <> 0 then
printfn "Unrecognised arguments: %s" (String.concat "," extra)
Expand Down
8 changes: 5 additions & 3 deletions FsAutoComplete/test/integration/SymbolUse/Script.fsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@

module console

module XA =
let funky x = x + 1
[<EntryPoint>]
let main argv =
System.IO.Directory

let val99 = XA.funky 21
0 // return an integer exit code
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ p.symboluse "Program.fs" 14 12 //testval shadowed
p.symboluse "Program.fs" 12 4 //miss
p.symboluse "Program.fs" 12 5 //shadowed start
p.symboluse "Program.fs" 12 13 //shadowed end
p.symboluse "Script.fsx" 6 18 // no uses due to compile error

Threading.Thread.Sleep(1000)
p.send "quit\n"
Expand Down
20 changes: 19 additions & 1 deletion FsAutoComplete/test/integration/SymbolUse/output.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,18 @@
}
{
"Kind": "errors",
"Data": []
"Data": [
{
"FileName": "<absolute path removed>/test/integration/SymbolUse/Script.fsx",
"StartLine": 6,
"EndLine": 6,
"StartColumn": 15,
"EndColumn": 24,
"Severity": "Error",
"Message": "The value, constructor, namespace or type 'Directory' is not defined",
"Subcategory": "typecheck"
}
]
}
{
"Kind": "info",
Expand Down Expand Up @@ -167,3 +178,10 @@
]
}
}
{
"Kind": "symboluse",
"Data": {
"Name": "Directory",
"Uses": []
}
}