尝试启用lsp
This commit is contained in:
parent
2901b86a45
commit
7add109ad5
146
esbuild.js
146
esbuild.js
|
|
@ -1,9 +1,9 @@
|
|||
const esbuild = require("esbuild");
|
||||
const esbuild = require('esbuild');
|
||||
|
||||
const production = process.argv.includes("--production");
|
||||
const watch = process.argv.includes("--watch");
|
||||
const path = require("path");
|
||||
const fs = require("fs").promises;
|
||||
const production = process.argv.includes('--production');
|
||||
const watch = process.argv.includes('--watch');
|
||||
const path = require('path');
|
||||
const fs = require('fs').promises;
|
||||
|
||||
/**
|
||||
* 递归复制目录
|
||||
|
|
@ -11,92 +11,96 @@ const fs = require("fs").promises;
|
|||
* @param {string} dest 目标目录
|
||||
*/
|
||||
async function copyDir(src, dest) {
|
||||
await fs.mkdir(dest, { recursive: true });
|
||||
let entries = await fs.readdir(src, { withFileTypes: true });
|
||||
await fs.mkdir(dest, { recursive: true });
|
||||
let entries = await fs.readdir(src, { withFileTypes: true });
|
||||
|
||||
for (let entry of entries) {
|
||||
let srcPath = path.join(src, entry.name);
|
||||
let destPath = path.join(dest, entry.name);
|
||||
for (let entry of entries) {
|
||||
let srcPath = path.join(src, entry.name);
|
||||
let destPath = path.join(dest, entry.name);
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
await copyDir(srcPath, destPath);
|
||||
} else {
|
||||
await fs.copyFile(srcPath, destPath);
|
||||
console.log(`Copied ${srcPath} to ${destPath}`);
|
||||
}
|
||||
}
|
||||
if (entry.isDirectory()) {
|
||||
await copyDir(srcPath, destPath);
|
||||
} else {
|
||||
await fs.copyFile(srcPath, destPath);
|
||||
console.log(`Copied ${srcPath} to ${destPath}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {import('esbuild').Plugin}
|
||||
*/
|
||||
const copyTemplatesPlugin = {
|
||||
name: "copy-templates",
|
||||
setup(build) {
|
||||
build.onEnd(async () => {
|
||||
const srcDir = path.join(__dirname, "src", "templates");
|
||||
const destDir = path.join(__dirname, "dist", "templates");
|
||||
name: 'copy-templates',
|
||||
setup(build) {
|
||||
build.onEnd(async () => {
|
||||
const srcDir = path.join(__dirname, 'src', 'templates');
|
||||
const destDir = path.join(__dirname, 'dist', 'templates');
|
||||
|
||||
try {
|
||||
await copyDir(srcDir, destDir);
|
||||
console.log("Templates copied successfully");
|
||||
} catch (err) {
|
||||
console.error("Error copying templates:", err);
|
||||
}
|
||||
});
|
||||
},
|
||||
try {
|
||||
await copyDir(srcDir, destDir);
|
||||
console.log('Templates copied successfully');
|
||||
} catch (err) {
|
||||
console.error('Error copying templates:', err);
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @type {import('esbuild').Plugin}
|
||||
*/
|
||||
const esbuildProblemMatcherPlugin = {
|
||||
name: "esbuild-problem-matcher",
|
||||
name: 'esbuild-problem-matcher',
|
||||
|
||||
setup(build) {
|
||||
build.onStart(() => {
|
||||
console.log("[watch] build started");
|
||||
});
|
||||
build.onEnd((result) => {
|
||||
result.errors.forEach(({ text, location }) => {
|
||||
console.error(`✘ [ERROR] ${text}`);
|
||||
console.error(
|
||||
` ${location.file}:${location.line}:${location.column}:`
|
||||
);
|
||||
});
|
||||
console.log("[watch] build finished");
|
||||
});
|
||||
},
|
||||
setup(build) {
|
||||
build.onStart(() => {
|
||||
console.log('[watch] build started');
|
||||
});
|
||||
build.onEnd((result) => {
|
||||
result.errors.forEach(({ text, location }) => {
|
||||
console.error(`✘ [ERROR] ${text}`);
|
||||
console.error(
|
||||
` ${location.file}:${location.line}:${location.column}:`
|
||||
);
|
||||
});
|
||||
console.log('[watch] build finished');
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
async function main() {
|
||||
const ctx = await esbuild.context({
|
||||
entryPoints: ["src/extension.ts", "src/utils/analyzeWorker.ts"],
|
||||
bundle: true,
|
||||
format: "cjs",
|
||||
minify: production,
|
||||
sourcemap: !production,
|
||||
sourcesContent: false,
|
||||
platform: "node",
|
||||
outdir: "dist",
|
||||
entryNames: "[dir]/[name]",
|
||||
external: ["vscode"],
|
||||
logLevel: "silent",
|
||||
plugins: [
|
||||
/* add to the end of plugins array */
|
||||
esbuildProblemMatcherPlugin,
|
||||
copyTemplatesPlugin,
|
||||
],
|
||||
});
|
||||
if (watch) {
|
||||
await ctx.watch();
|
||||
} else {
|
||||
await ctx.rebuild();
|
||||
await ctx.dispose();
|
||||
}
|
||||
const ctx = await esbuild.context({
|
||||
entryPoints: [
|
||||
'src/extension.ts',
|
||||
'src/utils/analyzeWorker.ts',
|
||||
// 'src/server/xmlLanguageServer.ts',
|
||||
],
|
||||
bundle: true,
|
||||
format: 'cjs',
|
||||
minify: production,
|
||||
sourcemap: !production,
|
||||
sourcesContent: false,
|
||||
platform: 'node',
|
||||
outdir: 'dist',
|
||||
entryNames: '[dir]/[name]',
|
||||
external: ['vscode'],
|
||||
logLevel: 'silent',
|
||||
plugins: [
|
||||
/* add to the end of plugins array */
|
||||
esbuildProblemMatcherPlugin,
|
||||
copyTemplatesPlugin,
|
||||
],
|
||||
});
|
||||
if (watch) {
|
||||
await ctx.watch();
|
||||
} else {
|
||||
await ctx.rebuild();
|
||||
await ctx.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -117,7 +117,10 @@
|
|||
"dependencies": {
|
||||
"glob": "^11.0.0",
|
||||
"handlebars": "^4.7.8",
|
||||
"lodash": "^4.17.21"
|
||||
"lodash": "^4.17.21",
|
||||
"vscode-languageclient": "^9.0.1",
|
||||
"vscode-languageserver": "^9.0.1",
|
||||
"vscode-languageserver-textdocument": "^1.0.12"
|
||||
},
|
||||
"description": "OAK框架辅助开发插件",
|
||||
"devDependencies": {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,15 @@ importers:
|
|||
lodash:
|
||||
specifier: ^4.17.21
|
||||
version: 4.17.21
|
||||
vscode-languageclient:
|
||||
specifier: ^9.0.1
|
||||
version: 9.0.1
|
||||
vscode-languageserver:
|
||||
specifier: ^9.0.1
|
||||
version: 9.0.1
|
||||
vscode-languageserver-textdocument:
|
||||
specifier: ^1.0.12
|
||||
version: 1.0.12
|
||||
devDependencies:
|
||||
'@types/lodash':
|
||||
specifier: ^4.17.12
|
||||
|
|
@ -1999,6 +2008,27 @@ packages:
|
|||
validate-npm-package-license@3.0.4:
|
||||
resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
|
||||
|
||||
vscode-jsonrpc@8.2.0:
|
||||
resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
vscode-languageclient@9.0.1:
|
||||
resolution: {integrity: sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA==}
|
||||
engines: {vscode: ^1.82.0}
|
||||
|
||||
vscode-languageserver-protocol@3.17.5:
|
||||
resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==}
|
||||
|
||||
vscode-languageserver-textdocument@1.0.12:
|
||||
resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==}
|
||||
|
||||
vscode-languageserver-types@3.17.5:
|
||||
resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==}
|
||||
|
||||
vscode-languageserver@9.0.1:
|
||||
resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==}
|
||||
hasBin: true
|
||||
|
||||
webidl-conversions@5.0.0:
|
||||
resolution: {integrity: sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==}
|
||||
engines: {node: '>=8'}
|
||||
|
|
@ -4267,6 +4297,27 @@ snapshots:
|
|||
spdx-correct: 3.2.0
|
||||
spdx-expression-parse: 3.0.1
|
||||
|
||||
vscode-jsonrpc@8.2.0: {}
|
||||
|
||||
vscode-languageclient@9.0.1:
|
||||
dependencies:
|
||||
minimatch: 5.1.6
|
||||
semver: 7.6.3
|
||||
vscode-languageserver-protocol: 3.17.5
|
||||
|
||||
vscode-languageserver-protocol@3.17.5:
|
||||
dependencies:
|
||||
vscode-jsonrpc: 8.2.0
|
||||
vscode-languageserver-types: 3.17.5
|
||||
|
||||
vscode-languageserver-textdocument@1.0.12: {}
|
||||
|
||||
vscode-languageserver-types@3.17.5: {}
|
||||
|
||||
vscode-languageserver@9.0.1:
|
||||
dependencies:
|
||||
vscode-languageserver-protocol: 3.17.5
|
||||
|
||||
webidl-conversions@5.0.0: {}
|
||||
|
||||
whatwg-encoding@3.1.1:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { workspace, ExtensionContext } from 'vscode';
|
||||
|
||||
import {
|
||||
LanguageClient,
|
||||
LanguageClientOptions,
|
||||
ServerOptions,
|
||||
TransportKind,
|
||||
} from 'vscode-languageclient/node';
|
||||
|
||||
let client: LanguageClient;
|
||||
|
||||
function createLanguageServer() {
|
||||
// 服务器是在独立的进程中启动的
|
||||
let serverModule = path.join(__dirname, 'server', 'xmlLanguageServer.js');
|
||||
|
||||
if (!fs.existsSync(serverModule)) {
|
||||
console.error('Could not find server module');
|
||||
return;
|
||||
}
|
||||
|
||||
// 服务器的调试选项
|
||||
// --inspect=6009: 在Node的调试器中运行服务器
|
||||
// --nolazy: 不要延迟加载
|
||||
let debugOptions = { execArgv: ['--nolazy', '--inspect=6009'] };
|
||||
|
||||
// 如果扩展在调试模式下运行,那么调试服务器选项
|
||||
// 否则运行正常的服务器
|
||||
let serverOptions: ServerOptions = {
|
||||
run: { module: serverModule, transport: TransportKind.ipc },
|
||||
debug: {
|
||||
module: serverModule,
|
||||
transport: TransportKind.ipc,
|
||||
options: debugOptions,
|
||||
},
|
||||
};
|
||||
|
||||
// 控制语言客户端的选项
|
||||
let clientOptions: LanguageClientOptions = {
|
||||
// 为语言服务器注册xml文件
|
||||
documentSelector: [{ scheme: 'file', language: 'xml' }],
|
||||
synchronize: {
|
||||
// 通知服务器关于文件更改的事件
|
||||
fileEvents: workspace.createFileSystemWatcher('**/.clientrc'),
|
||||
},
|
||||
};
|
||||
|
||||
// 创建语言客户端并启动
|
||||
client = new LanguageClient(
|
||||
'xmlLanguageServer',
|
||||
'XML Language Server',
|
||||
serverOptions,
|
||||
clientOptions
|
||||
);
|
||||
}
|
||||
|
||||
export async function startAndWaitForReacy(): Promise<void> {
|
||||
createLanguageServer();
|
||||
return new Promise<void>((resolve) => {
|
||||
if (client) {
|
||||
client.onNotification('xmlLanguageServer/ready', () => {
|
||||
console.log('xmlLanguageServer is ready');
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
// 启动客户端。这也会启动服务器
|
||||
client.start();
|
||||
});
|
||||
}
|
||||
|
||||
export function deactivateClient(): Thenable<void> | undefined {
|
||||
if (!client) {
|
||||
return undefined;
|
||||
}
|
||||
return client.stop();
|
||||
}
|
||||
|
|
@ -16,7 +16,10 @@ import entityProviders from './plugins/entityJump';
|
|||
import { activateOakLocale, deactivateOakLocale } from './plugins/oakLocale';
|
||||
import { startWorker, stopWorker, waitWorkerReady } from './utils/workers';
|
||||
import { loadComponents } from './utils/components';
|
||||
import { activateOakComponentPropsLinkProvider, deactivateOakComponentPropsLinkProvider } from './plugins/oakComponent';
|
||||
import {
|
||||
activateOakComponentPropsLinkProvider,
|
||||
deactivateOakComponentPropsLinkProvider,
|
||||
} from './plugins/oakComponent';
|
||||
|
||||
// 初始化配置
|
||||
// 查找工作区的根目录中的oak.config.json文件,排除src和node_modules目录
|
||||
|
|
@ -123,7 +126,7 @@ export async function activate(context: vscode.ExtensionContext) {
|
|||
oakPathCompletion.oakPathCompletion,
|
||||
oakPathCompletion.oakPathDocumentLinkProvider,
|
||||
...oakPathHighlighter,
|
||||
entityProviders.documentLinkProvider,
|
||||
entityProviders.documentLinkProvider
|
||||
);
|
||||
createFileWatcher(context);
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,132 @@
|
|||
import {
|
||||
createConnection,
|
||||
TextDocuments,
|
||||
ProposedFeatures,
|
||||
InitializeParams,
|
||||
TextDocumentPositionParams,
|
||||
CompletionItem,
|
||||
CompletionItemKind,
|
||||
TextDocumentSyncKind,
|
||||
DidChangeConfigurationNotification,
|
||||
Hover,
|
||||
} from 'vscode-languageserver/node';
|
||||
|
||||
import { TextDocument } from 'vscode-languageserver-textdocument';
|
||||
|
||||
// 创建一个连接来使用Node的IPC作为传输
|
||||
let connection = createConnection(ProposedFeatures.all);
|
||||
|
||||
// 创建一个简单的文本文档管理器
|
||||
let documents: TextDocuments<TextDocument> = new TextDocuments(TextDocument);
|
||||
|
||||
let hasConfigurationCapability: boolean = false;
|
||||
let hasWorkspaceFolderCapability: boolean = false;
|
||||
|
||||
connection.onInitialize((params: InitializeParams) => {
|
||||
let capabilities = params.capabilities;
|
||||
|
||||
hasConfigurationCapability = !!(
|
||||
capabilities.workspace && !!capabilities.workspace.configuration
|
||||
);
|
||||
hasWorkspaceFolderCapability = !!(
|
||||
capabilities.workspace && !!capabilities.workspace.workspaceFolders
|
||||
);
|
||||
|
||||
return {
|
||||
capabilities: {
|
||||
textDocumentSync: TextDocumentSyncKind.Incremental,
|
||||
completionProvider: {
|
||||
resolveProvider: true,
|
||||
},
|
||||
hoverProvider: true,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
connection.onInitialized(() => {
|
||||
if (hasConfigurationCapability) {
|
||||
connection.client.register(
|
||||
DidChangeConfigurationNotification.type,
|
||||
undefined
|
||||
);
|
||||
}
|
||||
if (hasWorkspaceFolderCapability) {
|
||||
connection.workspace.onDidChangeWorkspaceFolders((_event) => {
|
||||
connection.console.log('Workspace folder change event received.');
|
||||
});
|
||||
}
|
||||
|
||||
// 发送服务器就绪通知
|
||||
connection.sendNotification("xmlLanguageServer/ready");
|
||||
});
|
||||
|
||||
// 这个处理程序提供初始补全项。
|
||||
connection.onCompletion(
|
||||
(_textDocumentPosition: TextDocumentPositionParams): CompletionItem[] => {
|
||||
return [
|
||||
{
|
||||
label: 'TypeScript',
|
||||
kind: CompletionItemKind.Text,
|
||||
data: 1,
|
||||
},
|
||||
{
|
||||
label: 'JavaScript',
|
||||
kind: CompletionItemKind.Text,
|
||||
data: 2,
|
||||
},
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
// 这个处理程序解析补全项的附加信息。
|
||||
connection.onCompletionResolve((item: CompletionItem): CompletionItem => {
|
||||
if (item.data === 1) {
|
||||
item.detail = 'TypeScript details';
|
||||
item.documentation = 'TypeScript documentation';
|
||||
} else if (item.data === 2) {
|
||||
item.detail = 'JavaScript details';
|
||||
item.documentation = 'JavaScript documentation';
|
||||
}
|
||||
return item;
|
||||
});
|
||||
|
||||
connection.onHover((params: TextDocumentPositionParams): Hover | null => {
|
||||
const document = documents.get(params.textDocument.uri);
|
||||
if (!document) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const text = document.getText();
|
||||
const position = params.position;
|
||||
const offset = document.offsetAt(position);
|
||||
|
||||
// 查找 {{attr}} 模式
|
||||
const regex = /{{(\w+)}}/g;
|
||||
let match;
|
||||
while ((match = regex.exec(text)) !== null) {
|
||||
if (match.index <= offset && offset <= match.index + match[0].length) {
|
||||
const attr = match[1];
|
||||
const type = getTypeForAttr(attr);
|
||||
return {
|
||||
contents: {
|
||||
kind: 'markdown',
|
||||
value: `Type of \`${attr}\`: \`${type}\``,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
function getTypeForAttr(attr: string): string {
|
||||
// 这里应该实现实际的类型推断逻辑
|
||||
// 为了示例,我们返回一个模拟的类型
|
||||
return `MockType<${attr}>`;
|
||||
}
|
||||
|
||||
// 使文档管理器监听连接的所有相关事件
|
||||
documents.listen(connection);
|
||||
|
||||
// 监听连接
|
||||
connection.listen();
|
||||
Loading…
Reference in New Issue