Implements DocumentLinkProvider to make IFC entity type names clickable, opening the official buildingSMART documentation in the browser. Features: - Automatic schema version detection (IFC2X3, IFC4, IFC4X3) - Complete entity-to-package mapping for IFC2X3 (653 entities) - Complete entity name mapping for IFC4X3 (876 entities with PascalCase) - Proper URL generation for all three schema versions: * IFC2X3: https://standards.buildingsmart.org/.../[package]/lexical/[entity].htm * IFC4: https://standards.buildingsmart.org/.../link/[entity].htm * IFC4X3: https://ifc43-docs.standards.buildingsmart.org/.../lexical/[Entity].htm Usage: - Ctrl+Click (or Cmd+Click on Mac) on any IFC entity name in an .ifc file - Tooltip shows "Open [ENTITY] documentation ([SCHEMA])" - Browser opens to the correct buildingSMART documentation page Files added: - client/src/ifcDocumentationLinkProvider.ts - Main provider implementation - client/src/ifc2x3-mappings.txt - IFC2X3 entity to package mappings - client/src/ifc4x3-mappings.txt - IFC4X3 entity to PascalCase mappings - client/src/generate-ifc-provider-FINAL.py - Script to regenerate provider The provider is registered in extension.ts for the 'ifc' language.
181 lines
No EOL
8.5 KiB
JavaScript
181 lines
No EOL
8.5 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.activate = activate;
|
|
exports.deactivate = deactivate;
|
|
const path = require("path");
|
|
const vscode = require("vscode");
|
|
const node_1 = require("vscode-languageclient/node");
|
|
const ifcTreeProvider_1 = require("./ifcTreeProvider");
|
|
const ifcReferencesProvider_1 = require("./ifcReferencesProvider");
|
|
const ifcDocumentationLinkProvider_1 = require("./ifcDocumentationLinkProvider");
|
|
let client;
|
|
let treeProvider;
|
|
let referencesProvider;
|
|
function activate(context) {
|
|
console.log('=== IFC Extension Activating ===');
|
|
// Create and register the hierarchy tree view
|
|
treeProvider = new ifcTreeProvider_1.IfcEntityTreeProvider();
|
|
const treeView = vscode.window.createTreeView('ifcEntityHierarchy', {
|
|
treeDataProvider: treeProvider,
|
|
showCollapseAll: true
|
|
});
|
|
context.subscriptions.push(treeView);
|
|
// Create and register the references tree view
|
|
referencesProvider = new ifcReferencesProvider_1.IfcReferencesProvider();
|
|
const referencesView = vscode.window.createTreeView('ifcEntityReferences', {
|
|
treeDataProvider: referencesProvider,
|
|
showCollapseAll: true
|
|
});
|
|
context.subscriptions.push(referencesView);
|
|
// Register command to show entity hierarchy
|
|
const showHierarchyCommand = vscode.commands.registerCommand('ifc.showEntityHierarchy', async () => {
|
|
const editor = vscode.window.activeTextEditor;
|
|
if (!editor || editor.document.languageId !== 'ifc') {
|
|
vscode.window.showWarningMessage('Please open an IFC file first');
|
|
return;
|
|
}
|
|
const position = editor.selection.active;
|
|
const line = editor.document.lineAt(position.line).text;
|
|
const entityId = getEntityIdFromLine(line, position.character);
|
|
if (entityId !== null) {
|
|
await treeProvider.updateForEntity(entityId, editor.document);
|
|
await vscode.commands.executeCommand("ifcEntityHierarchy.focus");
|
|
vscode.window.showInformationMessage(`Showing hierarchy for #${entityId}`);
|
|
}
|
|
else {
|
|
vscode.window.showWarningMessage('Cursor is not on an entity reference');
|
|
}
|
|
});
|
|
context.subscriptions.push(showHierarchyCommand);
|
|
// Register command to find all references
|
|
const findReferencesCommand = vscode.commands.registerCommand('ifc.findEntityReferences', async () => {
|
|
const editor = vscode.window.activeTextEditor;
|
|
if (!editor || editor.document.languageId !== 'ifc') {
|
|
vscode.window.showWarningMessage('Please open an IFC file first');
|
|
return;
|
|
}
|
|
const position = editor.selection.active;
|
|
const line = editor.document.lineAt(position.line).text;
|
|
const entityId = getEntityIdFromLine(line, position.character);
|
|
if (entityId !== null) {
|
|
await referencesProvider.findReferences(entityId, editor.document);
|
|
await vscode.commands.executeCommand("ifcEntityReferences.focus");
|
|
const count = referencesProvider.getReferencesCount();
|
|
vscode.window.showInformationMessage(`Found ${count} reference(s) to #${entityId}`);
|
|
}
|
|
else {
|
|
vscode.window.showWarningMessage('Cursor is not on an entity reference');
|
|
}
|
|
});
|
|
context.subscriptions.push(findReferencesCommand);
|
|
// Register link provider for Ctrl+Click on entity references
|
|
const linkProvider = vscode.languages.registerDocumentLinkProvider({ language: 'ifc' }, {
|
|
provideDocumentLinks(document) {
|
|
const links = [];
|
|
const text = document.getText();
|
|
const lines = text.split('\n');
|
|
lines.forEach((line, lineIndex) => {
|
|
const pattern = /#(\d+)/g;
|
|
let match;
|
|
while ((match = pattern.exec(line)) !== null) {
|
|
const entityId = parseInt(match[1]);
|
|
const startPos = new vscode.Position(lineIndex, match.index);
|
|
const endPos = new vscode.Position(lineIndex, match.index + match[0].length);
|
|
const range = new vscode.Range(startPos, endPos);
|
|
const link = new vscode.DocumentLink(range, vscode.Uri.parse(`command:ifc.showEntityHierarchyForId?${encodeURIComponent(JSON.stringify([entityId]))}`));
|
|
links.push(link);
|
|
}
|
|
});
|
|
return links;
|
|
}
|
|
});
|
|
context.subscriptions.push(linkProvider);
|
|
// Register documentation link provider for entity types (Ctrl+Click to open docs)
|
|
const docLinkProvider = vscode.languages.registerDocumentLinkProvider({ language: 'ifc' }, new ifcDocumentationLinkProvider_1.IfcDocumentationLinkProvider());
|
|
context.subscriptions.push(docLinkProvider);
|
|
// Command to show hierarchy AND references for a specific entity ID (used by Ctrl+Click)
|
|
const showHierarchyForIdCommand = vscode.commands.registerCommand('ifc.showEntityHierarchyForId', async (entityId) => {
|
|
const editor = vscode.window.activeTextEditor;
|
|
if (!editor || editor.document.languageId !== 'ifc') {
|
|
return;
|
|
}
|
|
// Update both hierarchy and references
|
|
await treeProvider.updateForEntity(entityId, editor.document);
|
|
await referencesProvider.findReferences(entityId, editor.document);
|
|
// Focus the hierarchy panel (references will be visible below it)
|
|
await vscode.commands.executeCommand("ifcEntityHierarchy.focus");
|
|
});
|
|
context.subscriptions.push(showHierarchyForIdCommand);
|
|
// Command to update BOTH hierarchy and references (triggered from context menu)
|
|
const updateBothPanelsCommand = vscode.commands.registerCommand('ifc.updateBothPanelsFromTree', async (treeItem) => {
|
|
const editor = vscode.window.activeTextEditor;
|
|
if (!editor || editor.document.languageId !== 'ifc') {
|
|
return;
|
|
}
|
|
// Extract entity ID from the tree item
|
|
// For hierarchy tree items
|
|
let entityId = treeItem?.entityNode?.id;
|
|
// For reference tree items
|
|
if (!entityId && treeItem?.reference?.entityId) {
|
|
entityId = treeItem.reference.entityId;
|
|
}
|
|
if (entityId) {
|
|
// Update both panels
|
|
await treeProvider.updateForEntity(entityId, editor.document);
|
|
await referencesProvider.findReferences(entityId, editor.document);
|
|
vscode.window.showInformationMessage(`Updated both panels for #${entityId}`);
|
|
}
|
|
});
|
|
context.subscriptions.push(updateBothPanelsCommand);
|
|
// Command to handle clicks from hierarchy tree (go to entity AND update references)
|
|
const updateReferencesFromTreeCommand = vscode.commands.registerCommand('ifc.updateReferencesFromTree', async (entityId, uri, line, length) => {
|
|
const editor = vscode.window.activeTextEditor;
|
|
if (!editor) {
|
|
return;
|
|
}
|
|
// Jump to the entity line
|
|
const range = new vscode.Range(new vscode.Position(line, 0), new vscode.Position(line, length));
|
|
editor.selection = new vscode.Selection(range.start, range.end);
|
|
editor.revealRange(range, vscode.TextEditorRevealType.InCenter);
|
|
// Update the references panel for this entity
|
|
await referencesProvider.findReferences(entityId, editor.document);
|
|
});
|
|
context.subscriptions.push(updateReferencesFromTreeCommand);
|
|
// The server is implemented in node
|
|
const serverModule = context.asAbsolutePath(path.join('server', 'out', 'server.js'));
|
|
const serverOptions = {
|
|
run: { module: serverModule, transport: node_1.TransportKind.ipc },
|
|
debug: {
|
|
module: serverModule,
|
|
transport: node_1.TransportKind.ipc,
|
|
}
|
|
};
|
|
const clientOptions = {
|
|
documentSelector: [{ scheme: 'file', language: 'ifc' }],
|
|
synchronize: {
|
|
fileEvents: vscode.workspace.createFileSystemWatcher('**/*.ifc')
|
|
}
|
|
};
|
|
client = new node_1.LanguageClient('ifcLanguageServer', 'IFC Language Server', serverOptions, clientOptions);
|
|
client.start();
|
|
console.log('=== IFC Language Server client started ===');
|
|
}
|
|
function getEntityIdFromLine(line, character) {
|
|
const pattern = /#(\d+)/g;
|
|
let match;
|
|
while ((match = pattern.exec(line)) !== null) {
|
|
const matchStart = match.index;
|
|
const matchEnd = match.index + match[0].length;
|
|
if (character >= matchStart && character <= matchEnd) {
|
|
return parseInt(match[1]);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
function deactivate() {
|
|
if (!client) {
|
|
return undefined;
|
|
}
|
|
return client.stop();
|
|
}
|
|
//# sourceMappingURL=extension.js.map
|