From 8a8fc0081f3ae838d23623f67c454a0fc825bf3b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 12 Mar 2026 14:23:43 +0000 Subject: [PATCH 1/3] fix: only include diagnostic help links for verified compiler error codes (#1437) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before this change, every F# compiler diagnostic was given a CodeDescription link (pointing to the Microsoft docs page for that error code), even when no page exists for that code. This commit adds a per-process validation cache (CompilerCodeLinkCache): - On first encounter of an error code, a background HTTP GET is started to check whether the URL resolves. - Until the check completes, no link is included (conservative — better to show nothing than a broken link). - Once validated, valid links are included for that code for the rest of the FSAC process lifetime. - Invalid URLs are permanently suppressed. The HttpClient has a 5-second timeout and a single shared instance is used for all checks (consistent with the pattern already used in Sourcelink.fs and Fsdn.fs). Closes #1437 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/FsAutoComplete/LspHelpers.fs | 39 +++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/FsAutoComplete/LspHelpers.fs b/src/FsAutoComplete/LspHelpers.fs index 8cd0c3142..6b74b3bf5 100644 --- a/src/FsAutoComplete/LspHelpers.fs +++ b/src/FsAutoComplete/LspHelpers.fs @@ -110,6 +110,43 @@ module Conversions = let urlForCompilerCode (number: int) = $"https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/compiler-messages/fs%04d{number}" + /// Per-process cache: None = not yet validated, Some true = URL resolves, Some false = URL is dead. + /// Validated lazily in the background — first occurrence of a code returns no link; subsequent + /// occurrences return a link only once the URL has been confirmed to resolve. + module private CompilerCodeLinkCache = + open System.Collections.Concurrent + open System.Net.Http + + let private cache = ConcurrentDictionary() + + // A single long-lived client shared for all link checks. + let private httpClient = + let client = new HttpClient() + client.Timeout <- TimeSpan.FromSeconds(5.0) + client + + let private checkAndCache (code: int) = + async { + let url = urlForCompilerCode code + + try + let! response = httpClient.GetAsync(url) |> Async.AwaitTask + cache.[code] <- response.IsSuccessStatusCode + with _ -> + cache.[code] <- false + } + + /// Returns a CodeDescription if the help URL for `code` has been validated as live. + /// Fires an async background check on first encounter of an unseen code. + let tryGetCodeDescription (code: int) : CodeDescription option = + match cache.TryGetValue(code) with + | true, true -> Some { Href = urlForCompilerCode code } + | true, false -> None + | false, _ -> + // Not yet checked: kick off background validation and return nothing for now. + checkAndCache code |> Async.Start + None + [] let unicodeParagraphCharacter: string = "\u001d" @@ -130,7 +167,7 @@ module Conversions = RelatedInformation = Some [||] Tags = None Data = None - CodeDescription = Some { Href = urlForCompilerCode error.ErrorNumber } } + CodeDescription = CompilerCodeLinkCache.tryGetCodeDescription error.ErrorNumber } let getSymbolInformations (uri: DocumentUri) From 58c119571d35ef509290640613cb6462b952cc7c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 12 Mar 2026 14:35:05 +0000 Subject: [PATCH 2/3] ci: trigger checks From f4096e6a642627fb8adfdd2a64202a2d02f66eb8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 23 Mar 2026 14:30:56 +0000 Subject: [PATCH 3/3] perf: use HEAD requests for compiler error URL validation Using HTTP HEAD instead of GET avoids downloading the full page body when validating compiler error help links, reducing bandwidth and response time. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/FsAutoComplete/LspHelpers.fs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/FsAutoComplete/LspHelpers.fs b/src/FsAutoComplete/LspHelpers.fs index 6b74b3bf5..998858987 100644 --- a/src/FsAutoComplete/LspHelpers.fs +++ b/src/FsAutoComplete/LspHelpers.fs @@ -130,7 +130,8 @@ module Conversions = let url = urlForCompilerCode code try - let! response = httpClient.GetAsync(url) |> Async.AwaitTask + use req = new HttpRequestMessage(HttpMethod.Head, url) + let! response = httpClient.SendAsync(req) |> Async.AwaitTask cache.[code] <- response.IsSuccessStatusCode with _ -> cache.[code] <- false