<p dir="auto">Post the initial implementation of the language server, there are quite a few other features that need to be added as well as some "tech debt" from the initial implementation.  We might want to break some of these off to individual issues, but it is good enough for now to have a "master" issue for tracking purposes.</p>
<h3 dir="auto">Language Service Features</h3>
<p dir="auto">These are server capabilities provided by the language server protocol, which various editors can take advantage of.  Most of these features are exposed <a href="https://github.com/microsoft/vscode/tree/master/extensions/typescript-language-features/src/languageFeatures">here</a> in visual studio code for TypeScript/JavaScript and provide a high level structure of how to take information from the <code class="notranslate">tsc</code> compiler isolate and bring it into Rust and send it back over the language server client.  Specifically, the <em>DefinitionProvider</em> is a good model of how to add a feature.  Looking at the <code class="notranslate">cli/lsp/mod.rs</code> for the <code class="notranslate">GotoDefinition</code> handling demonstrates calling into <code class="notranslate">tsc</code> and dealing with a response back, converting it to a valid lsp response.</p>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> TypeDefinitionProvider<g-emoji class="g-emoji" alias="star" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/2b50.png">⭐</g-emoji>  (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1055645901" data-permission-text="Title is private" data-url="https://github.com/denoland/deno/issues/12789" data-hovercard-type="pull_request" data-hovercard-url="/denoland/deno/pull/12789/hovercard" href="https://github.com/denoland/deno/pull/12789">#12789</a>)</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> WorkspaceSymbolProvider (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1055566624" data-permission-text="Title is private" data-url="https://github.com/denoland/deno/issues/12787" data-hovercard-type="pull_request" data-hovercard-url="/denoland/deno/pull/12787/hovercard" href="https://github.com/denoland/deno/pull/12787">#12787</a>)</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> Workspace Folders (multiple roots per workspace) (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="875159725" data-permission-text="Title is private" data-url="https://github.com/denoland/deno/issues/10488" data-hovercard-type="pull_request" data-hovercard-url="/denoland/deno/pull/10488/hovercard" href="https://github.com/denoland/deno/pull/10488">#10488</a>)</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> Completion Provider <del>(this will be the most complex one, because we also need to enrich the response back from tsc)</del> an mvp exists (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="758854321" data-permission-text="Title is private" data-url="https://github.com/denoland/deno/issues/8651" data-hovercard-type="pull_request" data-hovercard-url="/denoland/deno/pull/8651/hovercard" href="https://github.com/denoland/deno/pull/8651">#8651</a>), but we likely want to enhance it.
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> <del>Enable <code class="notranslate">include_completions_with_insert_text</code> (in consequence enabling <code class="notranslate">include_automatic_optional_chain_completions</code> and <code class="notranslate">include_completions_for_module_exports</code>)</del> <em>this is largely fixed</em></li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> Registry completions (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="844408756" data-permission-text="Title is private" data-url="https://github.com/denoland/deno/issues/9934" data-hovercard-type="pull_request" data-hovercard-url="/denoland/deno/pull/9934/hovercard" href="https://github.com/denoland/deno/pull/9934">#9934</a>)</li>
</ul>
</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> SignatureHelpProvider <g-emoji class="g-emoji" alias="star" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/2b50.png">⭐</g-emoji> (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="797398392" data-permission-text="Title is private" data-url="https://github.com/denoland/deno/issues/9330" data-hovercard-type="pull_request" data-hovercard-url="/denoland/deno/pull/9330/hovercard" href="https://github.com/denoland/deno/pull/9330">#9330</a>)</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> CodeActionProvider <g-emoji class="g-emoji" alias="star" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/2b50.png">⭐</g-emoji>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> QuickFix</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> <code class="notranslate">deno cache</code></li>
</ul>
</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> ImplementationProvider <g-emoji class="g-emoji" alias="star" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/2b50.png">⭐</g-emoji> (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="782644275" data-permission-text="Title is private" data-url="https://github.com/denoland/deno/issues/9071" data-hovercard-type="pull_request" data-hovercard-url="/denoland/deno/pull/9071/hovercard" href="https://github.com/denoland/deno/pull/9071">#9071</a>)</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> CodeLensProvider (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="796588200" data-permission-text="Title is private" data-url="https://github.com/denoland/deno/issues/9316" data-hovercard-type="pull_request" data-hovercard-url="/denoland/deno/pull/9316/hovercard" href="https://github.com/denoland/deno/pull/9316">#9316</a>)
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> References (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="796588200" data-permission-text="Title is private" data-url="https://github.com/denoland/deno/issues/9316" data-hovercard-type="pull_request" data-hovercard-url="/denoland/deno/pull/9316/hovercard" href="https://github.com/denoland/deno/pull/9316">#9316</a>)</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> Implementations</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> Deno specific code lenses, like tests? (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="913078166" data-permission-text="Title is private" data-url="https://github.com/denoland/deno/issues/10874" data-hovercard-type="pull_request" data-hovercard-url="/denoland/deno/pull/10874/hovercard" href="https://github.com/denoland/deno/pull/10874">#10874</a>)</li>
</ul>
</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> RenameProvider (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="775664809" data-permission-text="Title is private" data-url="https://github.com/denoland/deno/issues/8910" data-hovercard-type="pull_request" data-hovercard-url="/denoland/deno/pull/8910/hovercard" href="https://github.com/denoland/deno/pull/8910">#8910</a>)</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> SelectionRangeProvider (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="836990162" data-permission-text="Title is private" data-url="https://github.com/denoland/deno/issues/9845" data-hovercard-type="pull_request" data-hovercard-url="/denoland/deno/pull/9845/hovercard" href="https://github.com/denoland/deno/pull/9845">#9845</a>)</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> FoldingRangeProvider (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="841570002" data-permission-text="Title is private" data-url="https://github.com/denoland/deno/issues/9900" data-hovercard-type="pull_request" data-hovercard-url="/denoland/deno/pull/9900/hovercard" href="https://github.com/denoland/deno/pull/9900">#9900</a>)</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> CallHierarchyProvider (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="852681061" data-permission-text="Title is private" data-url="https://github.com/denoland/deno/issues/10061" data-hovercard-type="pull_request" data-hovercard-url="/denoland/deno/pull/10061/hovercard" href="https://github.com/denoland/deno/pull/10061">#10061</a>)</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> SemanticTokensProvider (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="860550176" data-permission-text="Title is private" data-url="https://github.com/denoland/deno/issues/10233" data-hovercard-type="pull_request" data-hovercard-url="/denoland/deno/pull/10233/hovercard" href="https://github.com/denoland/deno/pull/10233">#10233</a>)</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> DocumentSymbolProvider (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="849682375" data-permission-text="Title is private" data-url="https://github.com/denoland/deno/issues/9981" data-hovercard-type="pull_request" data-hovercard-url="/denoland/deno/pull/9981/hovercard" href="https://github.com/denoland/deno/pull/9981">#9981</a>)</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> DocumentLinkProvider - <em>vscode only implements this for tsconfig.json, we should consider it for <code class="notranslate">deno.jsonc</code></em></li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> DocumentRangeFormattingProvider (maybe)</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> DocumentOnTypeFormattingProvider (maybe)</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> <del>SemanticHighlighting</del> - <em>vscode does not implement this for typescript, semantic tokens instead</em></li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> <del>ColorProvider</del> <em>vscode does not implement this for typescript</em></li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> <del>ExecuteCommandProvider</del> <em>there is nothing to implement here</em></li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> <del>OnTypeRenameProvider</del> <em>vscode does not implement this for typescript</em></li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> <del>DeclarationProvider ⭐</del> <em>vscode does not implement this for typescript</em></li>
</ul>
<h3 dir="auto">Extension Configuration Options</h3>
<p dir="auto">There are several configuration/settings that are currently not respected by the language server, but should be.</p>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> <code class="notranslate">cachePath</code> - allow the <code class="notranslate">DENO_DIR</code> to be set in the configuration for the workspace allowing the default to be overridden and not need to setup an environment variable to change it.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> <code class="notranslate">enable</code> - this is only partially respected at the moment, for diagnostics, but other requests are duplicating values when enabled (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="772548485" data-permission-text="Title is private" data-url="https://github.com/denoland/deno/issues/8850" data-hovercard-type="pull_request" data-hovercard-url="/denoland/deno/pull/8850/hovercard" href="https://github.com/denoland/deno/pull/8850">#8850</a>)</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> <code class="notranslate">unstable</code> - needs to configure the tsc isolate with a new set of libs which include the unstable ones (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="772581825" data-permission-text="Title is private" data-url="https://github.com/denoland/deno/issues/8851" data-hovercard-type="pull_request" data-hovercard-url="/denoland/deno/pull/8851/hovercard" href="https://github.com/denoland/deno/pull/8851">#8851</a>)</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> <code class="notranslate">importMap</code> - the language server state should own the value and be passed when resolving modules (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="760042298" data-permission-text="Title is private" data-url="https://github.com/denoland/deno/issues/8683" data-hovercard-type="pull_request" data-hovercard-url="/denoland/deno/pull/8683/hovercard" href="https://github.com/denoland/deno/pull/8683">#8683</a>)</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> <code class="notranslate">config</code> - needs to change the config to the isolate, since <code class="notranslate">--config</code> is a CLI opt in, it should only be resolved when set and passed to the tsc isolate (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="776238279" data-permission-text="Title is private" data-url="https://github.com/denoland/deno/issues/8926" data-hovercard-type="pull_request" data-hovercard-url="/denoland/deno/pull/8926/hovercard" href="https://github.com/denoland/deno/pull/8926">#8926</a>)</li>
</ul>
<h3 dir="auto">Additional Items</h3>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> The unit tests are quite spotty, and far from exhaustive, we need more unit tests</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> There is a basic integration test infrastructure, but we could use more integration tests</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> We need to provide typeahead completion for module registry via the language server, like the version 2 of the extension was able to do, but not have any of that in the extension, do it all from the language server.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> The current branch only provides access to modules that are already in the DENO_DIR.  We can in theory instruct Deno to go fetch additional remote modules, but that comes with risks, because people will be typing out modules in a lot of cases and we don't want to <em>DDOS</em> registries with bad modules names.  So we need to figure out when is it ok to fetch modules, if we do it automatically, or not.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> Deal with unicode and JavaScript properly.  Investigate using swc's <code class="notranslate">SourceMap</code> to hold the in memory documents.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> Consider using swc's <a href="https://swc.rs/rustdoc/jsdoc/" rel="nofollow">jsdoc</a> crate when handling JSDoc between TypeScript and the language service.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> <code class="notranslate">deno_lint</code> should generate an unused <em>tag</em> as part of its diagnostic structure to flag unreachable code.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> We can spawn off diagnostics for things like <code class="notranslate">deno_lint</code> or reformatting a document to a seperate thread, but we don't allow isolates to be sent to other threads, in order not to have to deal with managing the lock, but it would be good to have a dedicated thread for getting diagnostics from the compiler isolate as to not lock the main loop of the language service.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> Re-work the static built assets... currently the language server is re-lining all the static type definition files... we were able to remove most of them from the Rust side during the build process, as they were actually present in the tsc snapshot and not needed anywhere else (except for a limit set for <code class="notranslate">deno types</code>).  Now we need to have them all in the lsp in Rust to provide them on a goto definition situation.</li>
</ul>
<p dir="auto">Add sync and async APIs to the <code class="notranslate">Deno</code> namespace which allow to acquire (advisory) file-system locks. The API could look something like this:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="interface LockOptions {
  mode: &quot;shared&quot; | &quot;exclusive&quot;;
}

interface Deno {
  // ...

  flock: (pid: number, options: LockOptions) =&gt; Promise&lt;void&gt;;
  fsyncLock: (pid: number, options: LockOptions) =&gt; void;

  funlock: (pid: number) =&gt; Promise&lt;void&gt;;
  fsyncUnlock: (pid: number) =&gt; void;

  // plus potentially something to check if a file lock can
  // be acquired.
  fcheckLock: (pid: number, options: LockOptions) =&gt; Promise&lt;boolean&gt;;
  fsyncCheckLock: (pid: number, options: LockOptions) =&gt; boolean;

  // ...
}"><pre class="notranslate"><span class="pl-k">interface</span> <span class="pl-smi">LockOptions</span> <span class="pl-kos">{</span>
  <span class="pl-c1">mode</span>: <span class="pl-s">"shared"</span> <span class="pl-c1">|</span> <span class="pl-s">"exclusive"</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>

<span class="pl-k">interface</span> <span class="pl-smi">Deno</span> <span class="pl-kos">{</span>
  <span class="pl-c">// ...</span>

  <span class="pl-c1">flock</span>: <span class="pl-kos">(</span><span class="pl-s1">pid</span>: <span class="pl-smi">number</span><span class="pl-kos">,</span> <span class="pl-s1">options</span>: <span class="pl-smi">LockOptions</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-smi">Promise</span><span class="pl-kos">&lt;</span><span class="pl-smi"><span class="pl-k">void</span></span><span class="pl-kos">&gt;</span><span class="pl-kos">;</span>
  <span class="pl-c1">fsyncLock</span>: <span class="pl-kos">(</span><span class="pl-s1">pid</span>: <span class="pl-smi">number</span><span class="pl-kos">,</span> <span class="pl-s1">options</span>: <span class="pl-smi">LockOptions</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-smi"><span class="pl-k">void</span></span><span class="pl-kos">;</span>

  <span class="pl-c1">funlock</span>: <span class="pl-kos">(</span><span class="pl-s1">pid</span>: <span class="pl-smi">number</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-smi">Promise</span><span class="pl-kos">&lt;</span><span class="pl-smi"><span class="pl-k">void</span></span><span class="pl-kos">&gt;</span><span class="pl-kos">;</span>
  <span class="pl-c1">fsyncUnlock</span>: <span class="pl-kos">(</span><span class="pl-s1">pid</span>: <span class="pl-smi">number</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-smi"><span class="pl-k">void</span></span><span class="pl-kos">;</span>

  <span class="pl-c">// plus potentially something to check if a file lock can</span>
  <span class="pl-c">// be acquired.</span>
  <span class="pl-c1">fcheckLock</span>: <span class="pl-kos">(</span><span class="pl-s1">pid</span>: <span class="pl-smi">number</span><span class="pl-kos">,</span> <span class="pl-s1">options</span>: <span class="pl-smi">LockOptions</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-smi">Promise</span><span class="pl-kos">&lt;</span><span class="pl-smi">boolean</span><span class="pl-kos">&gt;</span><span class="pl-kos">;</span>
  <span class="pl-c1">fsyncCheckLock</span>: <span class="pl-kos">(</span><span class="pl-s1">pid</span>: <span class="pl-smi">number</span><span class="pl-kos">,</span> <span class="pl-s1">options</span>: <span class="pl-smi">LockOptions</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-smi">boolean</span><span class="pl-kos">;</span>

  <span class="pl-c">// ...</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">One possible good candidate for implementing those on the Rust side would be the <a href="https://crates.io/crates/fs3" rel="nofollow">fs3 crate</a>.</p>
<p dir="auto">The motivation for having these APIs is that they would enable synchronization between different processes which access the same file. In particular, this functionality would enable the <a href="https://deno.land/x/sqlite" rel="nofollow">https://deno.land/x/sqlite</a> library to provide the complete set of persistence guarantees native SQLite offers.</p>