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

Extract shared line lens and pipeline hint code #1895

Merged
merged 9 commits into from
Aug 19, 2023
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
413 changes: 0 additions & 413 deletions src/Components/LineLens.fs

This file was deleted.

153 changes: 153 additions & 0 deletions src/Components/LineLens/LineLens.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
module Ionide.VSCode.FSharp.LineLens

open System
open System.Collections.Generic
open Fable.Core
open Fable.Import.VSCode
open Fable.Import.VSCode.Vscode
open Fable.Core.JsInterop
open DTO
open LineLensShared

type Number = float

let private logger =
ConsoleAndOutputChannelLogger(Some "LineLens", Level.DEBUG, None, Some Level.DEBUG)

[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module LineLensConfig =

open System.Text.RegularExpressions

type EnabledMode =
| Never
| ReplaceCodeLens
| Always

let private parseEnabledMode (s: string) =
match s.ToLowerInvariant() with
| "never" -> false
| "always" -> true
| "replacecodelens"
| _ -> true


let defaultConfig = { enabled = true; prefix = " // " }

let private themeRegex = Regex("\s*theme\((.+)\)\s*")

let getConfig () =
let cfg = workspace.getConfiguration ()

let fsharpCodeLensConfig =
cfg.get("[fsharp]", JsObject.empty).tryGet<bool> ("editor.codeLens")

{ enabled = cfg.get ("FSharp.lineLens.enabled", "replacecodelens") |> parseEnabledMode
prefix = cfg.get ("FSharp.lineLens.prefix", defaultConfig.prefix) }


module DecorationUpdate =
let formatSignature (sign: SignatureData) : string =
let formatType =
function
| Contains "->" t -> sprintf "(%s)" t
| t -> t

let args =
sign.Parameters
|> List.map (fun group -> group |> List.map (fun p -> formatType p.Type) |> String.concat " * ")
|> String.concat " -> "

if String.IsNullOrEmpty args then
sign.OutputType
else
args + " -> " + formatType sign.OutputType

let interestingSymbolPositions (symbols: Symbols[]) : DTO.Range[] =
symbols
|> Array.collect (fun syms ->
let interestingNested =
syms.Nested
|> Array.choose (fun sym ->
if
sym.GlyphChar <> "Fc"
&& sym.GlyphChar <> "M"
&& sym.GlyphChar <> "F"
&& sym.GlyphChar <> "P"
|| sym.IsAbstract
|| sym.EnclosingEntity = "I" // interface
|| sym.EnclosingEntity = "R" // record
|| sym.EnclosingEntity = "D" // DU
|| sym.EnclosingEntity = "En" // enum
|| sym.EnclosingEntity = "E" // exception
then
None
else
Some sym.BodyRange)

if syms.Declaration.GlyphChar <> "Fc" then
interestingNested
else
interestingNested |> Array.append [| syms.Declaration.BodyRange |])

let private lineRange (doc: TextDocument) (range: Vscode.Range) =
let textLine = doc.lineAt range.start.line
textLine.range

let private getSignature (uri: Uri) (range: DTO.Range) =
async {
try
let! signaturesResult =
LanguageService.signatureData uri range.StartLine (range.StartColumn - 1)
|> Async.AwaitPromise

return signaturesResult |> Option.map (fun r -> range|>CodeRange.fromDTO, formatSignature r.Data)
with e ->
logger.Error("Error getting signature %o", e)
return None
}

let signatureToDecoration
(config: LineLensShared.LineLensConfig)
(doc: TextDocument)
(range: Vscode.Range, signature: string)
=
LineLensShared.LineLensDecorations.create "fsharp.linelens" (lineRange doc range) (config.prefix + signature)

let private onePerLine (ranges: Range[]) =
ranges
|> Array.groupBy (fun r -> r.StartLine)
|> Array.choose (fun (_, ranges) -> if ranges.Length = 1 then Some(ranges.[0]) else None)

let private needUpdate (uri: Uri) (version: Number) { documents = documents } =
(documents |> Documents.tryGetCachedAtVersion uri version).IsSome

let declarationsResultToSignatures document declarationsResult uri =
promise {
let interesting = declarationsResult.Data |> interestingSymbolPositions

let interesting = onePerLine interesting

let! signatures =
interesting
|> Array.map (getSignature uri)
|> Async.Sequential // Need to be sequential otherwise we'll flood the server with requests causing threadpool exhaustion
|> Async.StartAsPromise
|> Promise.map (fun s -> s |> Array.choose (id))

return signatures
}


let private lineLensDecorationUpdate: LineLensShared.DecorationUpdate =
LineLensShared.DecorationUpdate.updateDecorationsForDocument
LanguageService.lineLenses
DecorationUpdate.declarationsResultToSignatures
DecorationUpdate.signatureToDecoration



let createLineLens () =
LineLensShared.LineLens("LineLens", lineLensDecorationUpdate, LineLensConfig.getConfig)

let Instance = createLineLens ()
Loading
Loading