Skip to content
Closed
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
1 change: 1 addition & 0 deletions extension/.vscodeignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ vsc-extension-quickstart.md
**/.eslintrc.json
**/*.map
**/*.ts
!types/**/*.d.ts
RESEARCH.md
package-lock.json
2 changes: 1 addition & 1 deletion extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "phpx-language-support",
"displayName": "PHPX Language Support",
"description": "Syntax highlighting and language support for PHPX - JSX-like syntax for PHP",
"version": "0.2.0",
"version": "0.2.1",
"publisher": "attitude",
"license": "MIT",
"engines": {
Expand Down
88 changes: 88 additions & 0 deletions extension/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ import {
PHPXRenameProvider,
PHPXImplementationProvider,
} from './providers';
import {
initTsxQuery,
disposeTsxQuery,
getTsxAttributeCompletions,
getTsxAttributeHover,
detectTagAtCursor,
detectTagAndAttributeAtCursor,
} from './tsxQuery';

const PHPX_SELECTOR: vscode.DocumentSelector = {
language: 'phpx',
Expand Down Expand Up @@ -48,6 +56,83 @@ export function activate(context: vscode.ExtensionContext) {
}
}

// ─── TypeScript JSX attribute query ──────────────────────────────────────
//
// Initialises a small virtual TypeScript project using phpx-intrinsics.d.ts
// (the PHPX JSX type declarations, no React) in the extension's global
// storage directory. This lets us query VS Code's built-in TypeScript
// language service for per-element HTML attribute completions and types.
//
// The query is purely additive — if the TypeScript server is unavailable
// the PHPX LSP's own completions continue to work unchanged.
Comment on lines +59 to +67

Copilot AI Apr 13, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR description focuses on compiler/LSP plugin extension points, but this change also introduces a new TypeScript-based completion/hover pipeline in the VS Code extension (tsxQuery + shipped DOM intrinsics types). Please update the PR description to include this user-facing editor feature (or split it into a separate PR) so reviewers know to evaluate packaging, performance, and behavior changes in the extension.

Copilot uses AI. Check for mistakes.
// ─────────────────────────────────────────────────────────────────────────

// Fire-and-forget: initialisation happens async so activation stays fast
initTsxQuery(context).catch((err) => {
outputChannel.appendLine(`[PHPX] TSX query init error: ${err}`);
});

// Supplementary completion provider: queries TypeScript for per-element
// HTML attribute types and merges them with the PHPX LSP's own suggestions.
context.subscriptions.push(
vscode.languages.registerCompletionItemProvider(
PHPX_SELECTOR,
{
async provideCompletionItems(
document: vscode.TextDocument,
position: vscode.Position,
): Promise<vscode.CompletionItem[] | undefined> {
const tagName = detectTagAtCursor(document, position);
if (!tagName) {
return undefined;
}

// Only trigger for HTML intrinsic elements (lowercase first char)
if (tagName[0] !== tagName[0].toLowerCase() || tagName[0] === tagName[0].toUpperCase()) {
return undefined;
}

return getTsxAttributeCompletions(tagName);
},
},
' ', // trigger on space (same as PHPX LSP)
'\n', // and newline (for multi-line attribute lists)
),
);

// Supplementary hover provider: queries TypeScript for attribute type info
// when hovering over an HTML attribute name inside a PHPX tag.
context.subscriptions.push(
vscode.languages.registerHoverProvider(
PHPX_SELECTOR,
{
async provideHover(
document: vscode.TextDocument,
position: vscode.Position,
): Promise<vscode.Hover | undefined> {
const hit = detectTagAndAttributeAtCursor(document, position);
if (!hit) {
return undefined;
}

const markdown = await getTsxAttributeHover(hit.tagName, hit.attrName);
if (!markdown) {
return undefined;
}

const range = new vscode.Range(
position.line, hit.attrStart,
position.line, hit.attrEnd,
);
return new vscode.Hover(
new vscode.MarkdownString(markdown),
range,
);
},
},
),
);

// ─── Compilation pipeline ────────────────────────────────────────────────
//
// The compiler creates a shadow .php file for each .phpx file. This is
Expand Down Expand Up @@ -307,6 +392,9 @@ export async function deactivate() {
}
compilationTimers.clear();

// Clean up the TypeScript JSX attribute query environment
disposeTsxQuery();

// Stop the PHPX Language Server
await stopLanguageClient();
}
Loading
Loading