From 510986de7ad6930ba92bfeb47b8db287c7812544 Mon Sep 17 00:00:00 2001 From: nickyinluo Date: Mon, 11 Dec 2023 16:15:28 +0800 Subject: [PATCH] fix doc issue --- package-lock.json | 24 +++- package.json | 26 +++- src/autocomplete/TerraformResDocProvider.ts | 135 ++++++++++++++++---- src/extension.ts | 29 ++++- 4 files changed, 177 insertions(+), 37 deletions(-) diff --git a/package-lock.json b/package-lock.json index e008fc9..c6568b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "jsdom": "^22.1.0", "lodash": "^4.17.21", "lodash-es": "^4.17.21", - "marked": "^0.3.6", + "marked": "^11.0.1", "opn": "^6.0.0", "reflect-metadata": "^0.1.13", "shared": "^0.2.0", @@ -38,6 +38,7 @@ "@types/fs-extra": "^11.0.1", "@types/glob": "^8.0.1", "@types/lodash": "^4.14.191", + "@types/marked": "^6.0.0", "@types/mocha": "^10.0.1", "@types/node": "16.x", "@types/opn": "^3.0.28", @@ -622,6 +623,16 @@ "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==", "dev": true }, + "node_modules/@types/marked": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-6.0.0.tgz", + "integrity": "sha512-jmjpa4BwUsmhxcfsgUit/7A9KbrC48Q0q8KvnY107ogcjGgTFDlIL3RpihNpx2Mu1hM4mdFQjoVc4O6JoGKHsA==", + "deprecated": "This is a stub types definition. marked provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "marked": "*" + } + }, "node_modules/@types/minimatch": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", @@ -3495,11 +3506,14 @@ } }, "node_modules/marked": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.6.tgz", - "integrity": "sha512-gE75oL01YUIxaBqgeGBuNNd8u0L+H1N6xeW/s+O57o5EC31aPX1M1lD4W9eGyHFJGTwOgMkqzYODZ4yp5w20gQ==", + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/marked/-/marked-11.0.1.tgz", + "integrity": "sha512-P4kDhFEMlvLePBPRwOcMOv6+lYUbhfbSxJFs3Jb4Qx7v6K7l+k8Dxh9CEGfRvK71tL+qIFz5y7Pe4uzt4+/A3A==", "bin": { - "marked": "bin/marked" + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" } }, "node_modules/mdurl": { diff --git a/package.json b/package.json index 1c390fe..a39bd8c 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,12 @@ "when": "view == tcTerraform.resourcesExplorer.cvm", "group": "navigation" } + ], + "editor/context": [ + { + "command": "tcTerraform.doc.show", + "group": "navigation" + } ] }, "viewsContainers": { @@ -164,12 +170,25 @@ { "command": "tcTerraformer.import", "title": "Import", - "category": "TencentCloud Terraformer" + "category": "Hidden" }, { "command": "tcTerraformer.plan", "title": "Plan", - "category": "TencentCloud Terraformer" + "category": "Hidden" + }, + { + "command": "tcTerraform.doc.show", + "title": "Go to Terraform Definition", + "category": "Hidden" + } + ], + "keybindings": [ + { + "command": "tcTerraform.doc.show", + "key": "ctrl+alt+d", + "mac": "cmd+alt+d", + "when": "editorTextFocus" } ], "configuration": { @@ -241,6 +260,7 @@ "@types/fs-extra": "^11.0.1", "@types/glob": "^8.0.1", "@types/lodash": "^4.14.191", + "@types/marked": "^6.0.0", "@types/mocha": "^10.0.1", "@types/node": "16.x", "@types/opn": "^3.0.28", @@ -270,7 +290,7 @@ "jsdom": "^22.1.0", "lodash": "^4.17.21", "lodash-es": "^4.17.21", - "marked": "^0.3.6", + "marked": "^11.0.1", "opn": "^6.0.0", "reflect-metadata": "^0.1.13", "shared": "^0.2.0", diff --git a/src/autocomplete/TerraformResDocProvider.ts b/src/autocomplete/TerraformResDocProvider.ts index 089fb29..43f4a12 100644 --- a/src/autocomplete/TerraformResDocProvider.ts +++ b/src/autocomplete/TerraformResDocProvider.ts @@ -1,28 +1,113 @@ -import { - DefinitionProvider, - TextDocument, - Position, - CancellationToken, - Definition -} from "vscode"; +import * as vscode from "vscode"; import * as _ from "lodash"; -// import * as opn from "opn"; -import opn from "opn"; -import resources from '../../config/tips/tiat-resources.json'; - -const urlPrefix = "https://www.terraform.io"; - -export class TerraformResDocProvider implements DefinitionProvider { - public provideDefinition(document: TextDocument, position: Position, token: CancellationToken): Definition { - const words = document.getWordRangeAtPosition(position); - const resName = document.getText(words); - - const found = _.get(resources, resName); - const urlSuffix = found.url?.toString() || ""; - var target = (urlPrefix + urlSuffix); - if (urlSuffix && target) { - opn(target); +import * as fs from "fs"; +import * as path from "path"; +import { marked } from 'marked'; +import { dispose } from "vscode-extension-telemetry-wrapper"; + +export class TerraformResDocProvider { + // public provideDefinition(document: TextDocument, position: Position, token: CancellationToken): Definition { + // const words = document.getWordRangeAtPosition(position); + // const resName = document.getText(words); + + // const found = _.get(resources, resName); + // const urlSuffix = found.url?.toString() || ""; + // var target = (urlPrefix + urlSuffix); + // if (urlSuffix && target) { + // opn(target); + // } + // return null; + // } + + public static currentProvider: TerraformResDocProvider | undefined; + private readonly _panel: vscode.WebviewPanel; + private readonly _extensionUri: vscode.Uri; + private _disposables: vscode.Disposable[] = []; + public static readonly viewType = 'tcTerraform.doc.show.id'; + + public static async createOrShow(context: vscode.ExtensionContext, resType: string) { + const column = vscode.window.activeTextEditor + ? vscode.window.activeTextEditor.viewColumn + : undefined; + + + const targetColumn = column + 1; + const rightEditor = vscode.window.visibleTextEditors.find((editor) => editor.viewColumn === targetColumn); + + let newEditor = rightEditor; + + if (!newEditor) { + // new editor to the right of the current editor + const tempFile = await vscode.workspace.openTextDocument({ content: '', language: 'plaintext' }); + newEditor = await vscode.window.showTextDocument(tempFile, { viewColumn: targetColumn, preview: false }); + } + + // If we already have a panel, show it. + if (TerraformResDocProvider.currentProvider) { + // TerraformResDocProvider.currentProvider._panel.reveal(targetColumn); + TerraformResDocProvider.currentProvider.dispose(); + return; + } + + // Otherwise, create a new panel. + const panel = vscode.window.createWebviewPanel( + TerraformResDocProvider.viewType, + `Doc Definition: ${resType}`, + newEditor.viewColumn, + getWebviewOptions(context.extensionUri), + ); + // construct the _panel + TerraformResDocProvider.currentProvider = new TerraformResDocProvider(panel, context.extensionUri); + const current = TerraformResDocProvider.currentProvider; + const docsRoot = path.join(context.extensionPath, 'config', 'docs', 'r'); + const mdResType = resType.replace('tencentcloud_', ''); + const markdownPath = path.join(docsRoot, `${mdResType}.html.markdown`); + if (!fs.existsSync(markdownPath)) { + console.error('Can not find the markdownFile: %s', markdownPath); + return; } - return null; + const markdownFile = fs.readFileSync(markdownPath, 'utf8'); + + let markdown; + try { + const cleanedMarkdownFile = markdownFile.replace(/---[\s\S]*?---/, ''); + markdown = marked(cleanedMarkdownFile); + current._panel.webview.html = markdown; + } catch (error) { + console.error('Error processing the Markdown file:', error); + return; + } + // Listen for when the panel is disposed + current._panel.onDidDispose(() => current.dispose(), null, current._disposables); + } + + dispose() { + TerraformResDocProvider.currentProvider = undefined; + + // Clean up our resources + this._panel.dispose(); + + while (this._disposables.length) { + const x = this._disposables.pop(); + if (x) { + x.dispose(); + } + } + } + + public constructor(panel?: vscode.WebviewPanel, extensionUri?: vscode.Uri) { + this._panel = panel; + this._extensionUri = extensionUri; } -} \ No newline at end of file +} + +function getWebviewOptions(extensionUri: vscode.Uri): vscode.WebviewOptions { + return { + // Enable javascript in the webview + enableScripts: true, + + // And restrict the webview to only loading content from our extension's `media` directory. + localResourceRoots: [vscode.Uri.joinPath(extensionUri, 'media')] + }; +} + diff --git a/src/extension.ts b/src/extension.ts index b0f972b..5f11026 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -65,17 +65,38 @@ export async function activate(context: vscode.ExtensionContext) { context.subscriptions.push(disposableTferPlan); // auto-complete - console.log('activate the tips(resource and options) feature'); - const tipsProvider = new TerraformTipsProvider(); + console.log('activate the auto-complete(resource and argument) feature'); const exampleProvider = new autocomplete.TerraformExampleProvider(); + context.subscriptions.push(vscode.languages.registerCompletionItemProvider(TF_MODE, exampleProvider, autocomplete.EXAMPLE_TRIGGER_CHARACTER)); + + // tips + console.log('activate the tips(options and doc) feature'); + const tipsProvider = new TerraformTipsProvider(); context.subscriptions.push( vscode.workspace.onDidChangeTextDocument((event) => { tipsProvider.handleCharacterEvent(event); }) ); context.subscriptions.push(vscode.languages.registerCompletionItemProvider(TF_MODE, tipsProvider, ...TIPS_TRIGGER_CHARACTER)); - context.subscriptions.push(vscode.languages.registerDefinitionProvider(TF_MODE, new TerraformResDocProvider())); - context.subscriptions.push(vscode.languages.registerCompletionItemProvider(TF_MODE, exampleProvider, autocomplete.EXAMPLE_TRIGGER_CHARACTER)); + + context.subscriptions.push(vscode.commands.registerCommand('tcTerraform.doc.show', () => { + const editor = vscode.window.activeTextEditor; + if (!editor) { + return; // no editor opening + } + + // get the words under current selection + const doc = editor.document; + const selection = editor.selection; + const words = doc.getWordRangeAtPosition(selection.start); + const resType = doc.getText(words); + + const regex = /^tencentcloud(?:_[^\s]+)*$/; + if (!regex.test(resType)) { + return; // not match the regex + } + TerraformResDocProvider.createOrShow(context, resType); + })); // example console.log('activate the auto complete(example) feature');