Skip to content

Commit 733c2cc

Browse files
committed
~~Uglify~~ Format Code
1 parent 54f7d1e commit 733c2cc

File tree

6 files changed

+1782
-1429
lines changed

6 files changed

+1782
-1429
lines changed

issue.md

+171
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
2+
# InlayHints: LSP `3.17` & `TextEdit`s
3+
4+
Add & Implement `InlayHint`s from LSP `3.17` (as mentioned in #935)
5+
* Note: LSP `3.17` was just released (on `2022-05-10`) -- but in this PR I'm still treating it as still in preview: most code I wrote before `3.17` and Types aren't yet in `Ionide.LanguageServerProtocol` -> in here still temporary
6+
* Note: InlayHint capabilities: not handled at all
7+
8+
Both `textDocument/inlayHint` and `inlayHint/resolve` are implemented -- with exception of `Tooltip`s: That's still always `None`.
9+
* `inlayHint/resolve`: resolves `Tooltip` & `TextEdits` when missing from `InlayHint` -- but in reality it's actually completely unused & unnecessary:
10+
* As mentioned above: Tooltips aren't currently generated at all
11+
* `TextEdits` are always created when collecting all InlayHints and not delayed to be `resolve`d later.
12+
Reason: I changed ident detection & validation (-> "should get a hint?") slightly for type hints. In the process I collect all data necessary for `TextEdit`s too -> no reason to resolve later again...
13+
14+
<br/>
15+
<br/>
16+
17+
Use `TextEdit`s instead of just "insert string at Inlay Hint Location" (-> necessary for parens)
18+
* Note: `fsharp/inlayHints` still exists (-> compatibility with older version) -- but its `InsertText` can only insert at InlayHint location (-> no parens) -> might be wrong
19+
20+
<br/>
21+
<br/>
22+
23+
Use same logic for type `InlayHint`s & `AddExplicitTypeAnnotation` CodeFix
24+
25+
Enhancements around existing type annotation detection, like
26+
* already type annotated?
27+
* needs parens when type annotation gets inserted?
28+
* where must parens go
29+
* And some other special cases like `?a` -> optional parameter, but type annotation cannot have `option` (`: int` instead of `: int option`)
30+
31+
I'm using this (at least in part) to decide if type Hints should be emitted.
32+
-> This replaces some other checks
33+
Though I'm not yet sure it still behaves the same -> there are still some additional tests necessary (-> PR is still *WIP*)
34+
35+
<br/>
36+
37+
On enhancement is to handle function values:
38+
```fsharp
39+
let map f v = f (v+1)
40+
// ^
41+
42+
type A(a) =
43+
member _.F(b, f) = a + b |> f
44+
// ^
45+
46+
let f = fun a b -> a + b
47+
// ^
48+
```
49+
-> `AddExplicitType` can add type annotations to `f`.
50+
But should we show type hints too? (currently disabled)
51+
It's nice for short cases -- but when it accepts many args that hint might get quite large and distracting.
52+
(Ideal solution would be to make it a setting for user -- but not now. And even then we should use reasonable defaults)
53+
54+
(Note: currently not for functions (`let f a b = a + b`). Maybe someday -- but not now. Getting a function's return type is unfortunately not trivial (at least wasn't last time I tried))
55+
56+
<br/>
57+
<br/>
58+
59+
------------------------
60+
61+
<br/>
62+
63+
Still WIP because:
64+
* No tests yet for `textDocument/inlayHint`
65+
* Still some testing to do around change in InlayHint triggering
66+
* Some cleanup (I left some unused code and TODOs)
67+
68+
* Considering LSP `3.17` was just released: Maybe wait till update of `Ionide.LanguageServerProtocol`?
69+
-> Then we don't have to remember to remove `LSP.Preview.fs` sometime later (but instead do that directly in this PR here)
70+
71+
72+
73+
74+
//TODO: show type:
75+
```fsharp
76+
let f a = fun b -> a + b
77+
78+
let map f v = f (v+1)
79+
// ^
80+
```
81+
currently: no (main as well as this PR)
82+
should show?
83+
84+
first f: currently shows `: int`
85+
86+
```fsharp
87+
let f a = fun b -> a + b
88+
89+
let map f v = f (v+1)
90+
91+
type A(a) =
92+
member _.F(b, f) = a + b |> f
93+
94+
let f2: int -> int -> int = fun a b -> a + b
95+
```
96+
97+
98+
-------------------------------------
99+
100+
InlayHint-Data-> Generic
101+
102+
`Data` is of type [`LSPAny`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#lspAny):
103+
```typescript
104+
export type LSPAny = LSPObject | LSPArray | string | integer | uinteger |
105+
decimal | boolean | null;
106+
export type LSPObject = { [key: string]: LSPAny };
107+
export type LSPArray = LSPAny[];
108+
```
109+
Not really representable in F#
110+
-> I decided to use a Generic instead
111+
112+
But then of course correctness is in user hand and not type checked any more. I still think it's way easier to use than anything else.
113+
114+
--------------------------
115+
InlayHints -> tryCreateTypeHint -> Text
116+
117+
`Type` and `Type necessary for annotation` don't necessary need to match:
118+
```fsharp
119+
static member F(?value) = value |> Option.map ((+) 1)
120+
// ^^^^^ type: `int option`
121+
// with type annotation:
122+
static member F(?value: int) = value |> Option.map ((+) 1)
123+
// ^^^ just `int` without `option`
124+
```
125+
What should we use as type hint? (when inserted it correctly uses just `int`)
126+
127+
Currently I'm showing `int option` -- but the sole reason is: That's what was used before.
128+
I'm always confused when type in annotation is without option -- but it's confusing too to show type hint with option but when it gets inserted the option disappears
129+
130+
<br/>
131+
132+
Additional:
133+
I'm currently only handle trailing `option`.
134+
Does `type.Format` always produce a trailing `option`, or is `Option<...>` (maybe even with namespace) possible?
135+
136+
137+
-----------------
138+
139+
InlayHints -> VisitSimplePats -> SyntaxNode.SynTypeDefn
140+
141+
When does this happen?
142+
Case above is normal primary ctor (`type A(v) = ...`) -- but when does this here occur?
143+
144+
145+
----------------
146+
147+
`ServiceParseTreeWalk`
148+
149+
Copied from `dotnet/fsharp`
150+
151+
Current nuget package has a bug when traversing match cases (fixed in `dotnet/fsharp` main) & doesn't walk into all `SynPat`s (dotnet/fsharp#13114)
152+
153+
Once there's a release of FCS with match case traversal fixed, **we must remember to remove this file again!**
154+
155+
156+
157+
158+
-----------
159+
160+
//TODO: lambda -> IsFunction, but not included
161+
162+
//TODO: rename AddExplTyToParameter to `AddExplTy` -> not limited to param any more
163+
---------------------------------
164+
165+
166+
(
167+
In the future this may be expanded to additional identify where a binding is. And then hide and show based on location & user settings.
168+
(location like: `let`, `let!`, local `let`, global `let`, parameter, ...; and even further into bind)
169+
)
170+
171+
//TODO: mention: enhancement: extend to determine location (like let, binding, in match, nested in Record, Union, ...) -> for filtering (user settings)

0 commit comments

Comments
 (0)