Conversation
Inside a <script> block CodeHintManager already routes to the LSP's JS
provider (getLanguageForSelection() === "javascript"), but the request came
back empty: DocumentSync keys off the document's top-level language ("html"),
so vtsls was never sent the HTML document.
Add an opt-in "embedded language" capability. The TS extension registers
`embeddedLanguages: { html: {...} }`; DocumentSync then presents an HTML
document to the server as a JavaScript *view* of itself - every <script>
block kept verbatim, everything else blanked to spaces with newlines
preserved (reusing HTMLUtils.findBlocks, mirroring the legacy Tern path).
Because the blank-padding keeps the exact line/column layout, a position in
the HTML maps 1:1 to the same position in the view - no source map needed -
so completion/hover/signatureHelp/definition/references all work unchanged.
- TypeScriptSupport/main.js: _extractHtmlJs(editor) + EMBEDDED_LANGUAGES;
HTML files also start the server lazily.
- DocumentSync.js: embedded docs sync the extracted view with languageId
"javascript" and always full-sync (the view is a transform).
- LSPClient.js: client carries embeddedLanguages; isLintingProviderActive
reports embedded hosts (so Tern stands down in HTML); publishDiagnostics
are dropped for embedded views (unreliable without cross-script context).
Integration test opens an HTML fixture and asserts Array completions at
`arr.` inside a <script>.
The documentation popup anchored at list.right + 6px, which read as a wide gap between the two floating boxes. Reduce it to 2px so the docs sit snug against the completion list.
For keyword/plain-identifier completions vtsls returns the label itself as `detail` (`this` -> "this", `throw` -> "throw"), so the docs popup rendered a box containing only that word - a verbatim echo of the highlighted hint row. _docPopupHtml now treats a detail that merely restates the label as "no signature"; with no documentation either it returns "", and _showDocPopup hides the popup entirely. Items with a real signature (function foo(): void) or actual documentation are unaffected. Also drops the hint-list-to-docs-popup gap to 0 so they sit flush. Covered in the integration:TypeScript LSP suite: the echo cases, a meaningful signature, and docs-present-with-a-trivial-signature.
The JS view of an HTML doc (script blocks verbatim, everything else blanked
to spaces, 1:1 positions) was rebuilt by HTMLUtils.findBlocks on every
debounced sync AND every flush() before a feature request - i.e. an
O(document) re-tokenize potentially per keystroke on large HTML files.
New core module languageTools/HtmlJsView keeps an invisible text marker on
each <script>'s JS range; CodeMirror auto-adjusts markers on every edit, so
the view is rebuilt from marker.find() ranges - an O(N) memory copy with no
tokenizer - and memoized until the next edit. findBlocks runs only when the
structure could have changed: a full-buffer replace, an edit whose
inserted/removed text contains '<'/'>' (typing </script> inside a script is
invisible to markers), a marker-boundary touch, or a multi-record change
batch. An idle-time findBlocks parity check self-heals (and console.warns)
any drift, so the view can never silently diverge. extract(editor) keeps the
old stateless contract, so DocumentSync is untouched.
HtmlJsView is preloaded in brackets.js/SpecRunner.js: languageTools/* is
otherwise lazy-loaded, and the extension's synchronous getModule at load
time crashed the whole extension ("Module name ... has not been loaded yet").
Tests (integration:TypeScript LSP) generate a ~2.6k-line, 120-<script> HTML
file programmatically (temp dir, no checked-in asset) and cover: member
completion in the large file, marker-view/findBlocks parity after edits,
zero recompiles across safe in-script keystrokes, structural-edit recompile,
self-heal recovery, and blank-markup/verbatim-JS at 1:1 columns.
…cript>
vtsls sees the embedded script view under the host .html URI, so it doesn't
recognize string context there and answers with a junk "all globals +
auto-imports" dump inside quotes (e.g. console.log("|")).
Add a generic shouldSuppressHints(editor) config hook to the LSP
CodeHintsProvider (same pattern as shouldAutoTrigger/filterDiagnostics); the
TypeScript extension supplies the policy: veto hints when the doc is an
embedded HTML host, the selection language is javascript, and CodeMirror's
token at the cursor is a string/template literal. Plain JS/TS files are
untouched - the server handles their in-string behaviour itself.
The TS-LSP embedded-HTML approach (blanked JS view synced under the .html
URI) hit a hard vtsls limitation: it won't semantically analyze an in-memory
.html document, so bare-dot member completion (arr.) returned a junk
globals/auto-import dump and only prefix-typed completions worked. Tern's
legacy inline-<script> support is simply better here - real member
completion on a bare dot, native in-string suppression, parameter hints,
jump-to-def - and its machinery ("html" in HintUtils.SUPPORTED_LANGUAGES,
Session.getJavascriptText, ScopeManager's blanked-view send) was fully
intact, just gated off. So: the LSP keeps serving real .js/.ts/.jsx/.tsx
files; HTML <script> goes back to Tern.
Two gates were keeping Tern silent in HTML, both opened here:
1. Session gate - isLintingProviderActive("html") was true purely because
the client declared html in embeddedLanguages, so JavaScriptCodeHints
never created a Tern session for HTML files. Remove the embedded-HTML
machinery: EMBEDDED_LANGUAGES + the in-string hint veto (Tern suppresses
in strings natively) in TypeScriptSupport, the embeddedLanguages field /
isLintingProviderActive disjunct / publishDiagnostics drop-guard in
LSPClient, the DocumentSync embedded branch (back to its pre-embedded
form), and the HtmlJsView module with its brackets.js/SpecRunner preloads
and tests.
2. Priority starvation - LSP providers are selected by the language at the
CURSOR ("javascript" inside a <script> or a markdown ```js fence) at
priority 1 with capability-only checks, so they claimed requests in host
documents the server never syncs, returned nothing, starved Tern
(priority 0), and logged "Cannot find provider for hover/signatureHelp"
errors. New LanguageClient.servesDocument(editor) gates all five feature
providers (completion, signature help, jump-to-def, references, hover)
off the DOCUMENT's language, so the LSP stands down in any document it
doesn't serve - HTML, markdown fences, and future embedded contexts.
The embedded-HTML completion test now asserts at the provider layer (LSP
gate closed for html + Tern's registered provider returns Array members):
the previous SHOW_CODE_HINTS path needs a FOCUSED editor
(CodeHintManager._startNewSession -> getFocusedEditor), which an unfocused
test-runner window never has, so the UI-driven variant could never pass in
automation. integration:TypeScript LSP is 12/12 green.
…create + TS upgrade The auto-created project config now embeds an autoGeneratedByPhoenixCode marker object as its first key: a human-readable `doc` (why the file exists, delete to opt out) and `autoManage: true` with its own doc. autoManage is the management contract: while true, Phoenix may silently rewrite or upgrade the file, always preserving the user's compilerOptions; setting it to false (or any unparseable/unmarked config) makes the file user-owned - Phoenix never touches it again. TypeScript ignores unknown top-level keys in ts/jsconfig (ts-node and Angular stash custom fields there), so the marker is safe. Because the file now self-documents, the automatic flows go silent: - Creation shows no toast. Projects that already contain TypeScript get a tsconfig.json directly; JS projects get jsconfig.json as before. - New upgrade path: the first time a TypeScript file becomes active in a project scoped by a Phoenix-managed jsconfig.json, it is silently upgraded to tsconfig.json (compilerOptions preserved, old jsconfig removed, server restarted). A hand-written tsconfig or non-managed jsconfig is never touched. - Any tsconfig we write carries allowJs (JS stays first-class in mixed projects) and noEmit (tsconfig, unlike editor-only jsconfig, is read by real build tools - an accidental `npx tsc` must never emit files). The only remaining toast is the Problems-panel "Enable" click - an explicit action deserves visible confirmation. That flow and the toast's "Enable TypeScript" (checkJs) button now target whichever config type fits instead of hardcoding jsconfig.json. Adds a contract unit test (marker shape, compilerOptions preservation, checkJs semantics, tsconfig allowJs/noEmit) to the integration:TypeScript LSP suite via a test-only _configContent export; the event-driven flow stays inert in test windows. Suite green 13/13; all six UX scenarios verified live (silent create, upgrade preserving a hand-added checkJs, autoManage:false hands-off, TS-first direct tsconfig, delete + re-enable toast).
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
Improves TypeScript/JavaScript code hints by removing noisy documentation popups and enabling JS code intelligence inside HTML
<script>blocks.Details
Hides the docs popup when completion
detailonly repeats the selected hint label.Keeps real signatures and documented completions unaffected.
Makes the docs popup sit flush with the hint list.
Adds embedded JavaScript LSP support for HTML files:
<script>blocks as a JavaScript viewStarts the TypeScript server lazily for HTML files when needed.
Prevents unreliable diagnostics from embedded HTML views.
Tests
Added TypeScript LSP integration coverage for:
<script>blocks