尝试启用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 production = process.argv.includes('--production');
|
||||||
const watch = process.argv.includes("--watch");
|
const watch = process.argv.includes('--watch');
|
||||||
const path = require("path");
|
const path = require('path');
|
||||||
const fs = require("fs").promises;
|
const fs = require('fs').promises;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 递归复制目录
|
* 递归复制目录
|
||||||
|
|
@ -11,92 +11,96 @@ const fs = require("fs").promises;
|
||||||
* @param {string} dest 目标目录
|
* @param {string} dest 目标目录
|
||||||
*/
|
*/
|
||||||
async function copyDir(src, dest) {
|
async function copyDir(src, dest) {
|
||||||
await fs.mkdir(dest, { recursive: true });
|
await fs.mkdir(dest, { recursive: true });
|
||||||
let entries = await fs.readdir(src, { withFileTypes: true });
|
let entries = await fs.readdir(src, { withFileTypes: true });
|
||||||
|
|
||||||
for (let entry of entries) {
|
for (let entry of entries) {
|
||||||
let srcPath = path.join(src, entry.name);
|
let srcPath = path.join(src, entry.name);
|
||||||
let destPath = path.join(dest, entry.name);
|
let destPath = path.join(dest, entry.name);
|
||||||
|
|
||||||
if (entry.isDirectory()) {
|
if (entry.isDirectory()) {
|
||||||
await copyDir(srcPath, destPath);
|
await copyDir(srcPath, destPath);
|
||||||
} else {
|
} else {
|
||||||
await fs.copyFile(srcPath, destPath);
|
await fs.copyFile(srcPath, destPath);
|
||||||
console.log(`Copied ${srcPath} to ${destPath}`);
|
console.log(`Copied ${srcPath} to ${destPath}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {import('esbuild').Plugin}
|
* @type {import('esbuild').Plugin}
|
||||||
*/
|
*/
|
||||||
const copyTemplatesPlugin = {
|
const copyTemplatesPlugin = {
|
||||||
name: "copy-templates",
|
name: 'copy-templates',
|
||||||
setup(build) {
|
setup(build) {
|
||||||
build.onEnd(async () => {
|
build.onEnd(async () => {
|
||||||
const srcDir = path.join(__dirname, "src", "templates");
|
const srcDir = path.join(__dirname, 'src', 'templates');
|
||||||
const destDir = path.join(__dirname, "dist", "templates");
|
const destDir = path.join(__dirname, 'dist', 'templates');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await copyDir(srcDir, destDir);
|
await copyDir(srcDir, destDir);
|
||||||
console.log("Templates copied successfully");
|
console.log('Templates copied successfully');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Error copying templates:", err);
|
console.error('Error copying templates:', err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {import('esbuild').Plugin}
|
* @type {import('esbuild').Plugin}
|
||||||
*/
|
*/
|
||||||
const esbuildProblemMatcherPlugin = {
|
const esbuildProblemMatcherPlugin = {
|
||||||
name: "esbuild-problem-matcher",
|
name: 'esbuild-problem-matcher',
|
||||||
|
|
||||||
setup(build) {
|
setup(build) {
|
||||||
build.onStart(() => {
|
build.onStart(() => {
|
||||||
console.log("[watch] build started");
|
console.log('[watch] build started');
|
||||||
});
|
});
|
||||||
build.onEnd((result) => {
|
build.onEnd((result) => {
|
||||||
result.errors.forEach(({ text, location }) => {
|
result.errors.forEach(({ text, location }) => {
|
||||||
console.error(`✘ [ERROR] ${text}`);
|
console.error(`✘ [ERROR] ${text}`);
|
||||||
console.error(
|
console.error(
|
||||||
` ${location.file}:${location.line}:${location.column}:`
|
` ${location.file}:${location.line}:${location.column}:`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
console.log("[watch] build finished");
|
console.log('[watch] build finished');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const ctx = await esbuild.context({
|
const ctx = await esbuild.context({
|
||||||
entryPoints: ["src/extension.ts", "src/utils/analyzeWorker.ts"],
|
entryPoints: [
|
||||||
bundle: true,
|
'src/extension.ts',
|
||||||
format: "cjs",
|
'src/utils/analyzeWorker.ts',
|
||||||
minify: production,
|
// 'src/server/xmlLanguageServer.ts',
|
||||||
sourcemap: !production,
|
],
|
||||||
sourcesContent: false,
|
bundle: true,
|
||||||
platform: "node",
|
format: 'cjs',
|
||||||
outdir: "dist",
|
minify: production,
|
||||||
entryNames: "[dir]/[name]",
|
sourcemap: !production,
|
||||||
external: ["vscode"],
|
sourcesContent: false,
|
||||||
logLevel: "silent",
|
platform: 'node',
|
||||||
plugins: [
|
outdir: 'dist',
|
||||||
/* add to the end of plugins array */
|
entryNames: '[dir]/[name]',
|
||||||
esbuildProblemMatcherPlugin,
|
external: ['vscode'],
|
||||||
copyTemplatesPlugin,
|
logLevel: 'silent',
|
||||||
],
|
plugins: [
|
||||||
});
|
/* add to the end of plugins array */
|
||||||
if (watch) {
|
esbuildProblemMatcherPlugin,
|
||||||
await ctx.watch();
|
copyTemplatesPlugin,
|
||||||
} else {
|
],
|
||||||
await ctx.rebuild();
|
});
|
||||||
await ctx.dispose();
|
if (watch) {
|
||||||
}
|
await ctx.watch();
|
||||||
|
} else {
|
||||||
|
await ctx.rebuild();
|
||||||
|
await ctx.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch((e) => {
|
main().catch((e) => {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,10 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"glob": "^11.0.0",
|
"glob": "^11.0.0",
|
||||||
"handlebars": "^4.7.8",
|
"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框架辅助开发插件",
|
"description": "OAK框架辅助开发插件",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,15 @@ importers:
|
||||||
lodash:
|
lodash:
|
||||||
specifier: ^4.17.21
|
specifier: ^4.17.21
|
||||||
version: 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:
|
devDependencies:
|
||||||
'@types/lodash':
|
'@types/lodash':
|
||||||
specifier: ^4.17.12
|
specifier: ^4.17.12
|
||||||
|
|
@ -1999,6 +2008,27 @@ packages:
|
||||||
validate-npm-package-license@3.0.4:
|
validate-npm-package-license@3.0.4:
|
||||||
resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
|
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:
|
webidl-conversions@5.0.0:
|
||||||
resolution: {integrity: sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==}
|
resolution: {integrity: sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
@ -4267,6 +4297,27 @@ snapshots:
|
||||||
spdx-correct: 3.2.0
|
spdx-correct: 3.2.0
|
||||||
spdx-expression-parse: 3.0.1
|
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: {}
|
webidl-conversions@5.0.0: {}
|
||||||
|
|
||||||
whatwg-encoding@3.1.1:
|
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 { activateOakLocale, deactivateOakLocale } from './plugins/oakLocale';
|
||||||
import { startWorker, stopWorker, waitWorkerReady } from './utils/workers';
|
import { startWorker, stopWorker, waitWorkerReady } from './utils/workers';
|
||||||
import { loadComponents } from './utils/components';
|
import { loadComponents } from './utils/components';
|
||||||
import { activateOakComponentPropsLinkProvider, deactivateOakComponentPropsLinkProvider } from './plugins/oakComponent';
|
import {
|
||||||
|
activateOakComponentPropsLinkProvider,
|
||||||
|
deactivateOakComponentPropsLinkProvider,
|
||||||
|
} from './plugins/oakComponent';
|
||||||
|
|
||||||
// 初始化配置
|
// 初始化配置
|
||||||
// 查找工作区的根目录中的oak.config.json文件,排除src和node_modules目录
|
// 查找工作区的根目录中的oak.config.json文件,排除src和node_modules目录
|
||||||
|
|
@ -123,7 +126,7 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||||
oakPathCompletion.oakPathCompletion,
|
oakPathCompletion.oakPathCompletion,
|
||||||
oakPathCompletion.oakPathDocumentLinkProvider,
|
oakPathCompletion.oakPathDocumentLinkProvider,
|
||||||
...oakPathHighlighter,
|
...oakPathHighlighter,
|
||||||
entityProviders.documentLinkProvider,
|
entityProviders.documentLinkProvider
|
||||||
);
|
);
|
||||||
createFileWatcher(context);
|
createFileWatcher(context);
|
||||||
} catch (error) {
|
} 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