前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于区块开发(三):VSCode插件

基于区块开发(三):VSCode插件

作者头像
Dickensl
发布2022-06-14 13:53:06
5800
发布2022-06-14 13:53:06
举报
文章被收录于专栏:睿Talks

一、前言

上一篇文章 中,我介绍了服务于区块开发的命令行工具是如何实现的,本文将沿着区块开发这一主题继续讲解 VSCode 插件的实现方式。

本系列总共 3 篇文章,以下是传送门:

基于区块开发(一):概述

基于区块开发(二):命令行工具

基于区块开发(三):VSCode插件

二、区块列表展示

如果刚接触 VSCode 插件开发,可以先看看我之前写的 VS Code插件开发介绍

为了方便用户使用,我希望有一个专门的 tab 页分类列出所有的区块,先看一下效果:

要在左侧工具栏添加 tab,需要先在 package.json 文件中配置一个 View Container 和一个 View

代码语言:javascript
复制
"contributes": {
  "viewsContainers": {
    "activitybar": [
      {
        "id": "tce-block",
        "title": "TCE Block",
        "icon": "media/block.svg"
      }
    ]
  },
  "views": {
    "tce-block": [
      {
        "id": "tceBlock",
        "name": "TCE Block",
        "icon": "media/dep.svg",
        "contextualTitle": "TCE Block"
      }
    ]
  }
}

这里指定了 tab 的位置放在左侧工具栏 activitybar,另一个可选项是 panel,在编辑器底部(终端)的位置。然后再给刚添加的这个 View Container 指定一个 View,通过 tce-block 这个 ID 进行关联。

下一步就是定制 View 的显示内容了。由于显示的内容就是一棵目录树,所以用到了 VSCode 插件开发中内置的 Tree View API。下面我们来定义一棵树,关键是实现 vscode.TreeDataProvider 这一接口:

代码语言:javascript
复制
class BlockProvider implements vscode.TreeDataProvider<Block> {
  constructor(private workspaceRoot: string) {}

  getTreeItem(element: Block): vscode.TreeItem {
    return element;
  }

  async getChildren(element?: Block) {
    if (!this.workspaceRoot) {
      return [];
    }

    // 不是根目录,返回元素的children
    if (element) {
      if (element.children.length > 0) {
        return element.children;
      }
      return null;
    }
    // 根目录,构造树形数据结构
    else {
      const resp = await fetchData<BlockCategories>(
        'http://xxx.com/block-categories.json'
      );

      if (!resp) {
        vscode.window.showErrorMessage('获取区块列表失败');
        return [];
      }

      const { blocks } = resp;
      return toBlock(blocks);
    }
  }
}

这里的重点是实现 getChildren 方法,返回树的数据结构。这里有 2 种情况:

  • 参数 element 为空时,说明是根目录,需要构造出树的第一层数据结构(数组)。
  • 参数 element 非空时,返回子节点数组。

toBlock 函数的作用是构造出树的所有节点。我设计的树只有 2 层,第一层是区块分类,第二层是区块实例:

代码语言:javascript
复制
function toBlock(categories: BlockItem[]): Block[] {
  // 区块分类
  return categories.map((category) => {
    const { id, label, children } = category;
    const categoryItem = new Block(
      id,
      label,
      '',
      vscode.TreeItemCollapsibleState.Collapsed
    );
    
    // 区块实例
    categoryItem.children = children!.map((blockItem) => {
      const { id: blockId, label: blockLabel, url } = blockItem;
      const block = new Block(blockId, blockLabel, url!);
      block.type = blockItem.type;
      return block;
    });

    return categoryItem;
  });
}

下面再来看树节点的定义,继承自 vscode.TreeItem

代码语言:javascript
复制
export class Block extends vscode.TreeItem {
  children: Block[] = [];
  type: number = 2;

  constructor(
    public readonly id: string,
    public readonly label: string,
    public readonly url: string,
    public readonly collapsibleState?: vscode.TreeItemCollapsibleState
  ) {
    super(label, collapsibleState);

    this.id = id;
    this.tooltip = `${this.label}区块`;

    // 区块实例
    if (url) {
      this.contextValue = 'block'; // 控制操作按钮的显示隐藏
      this.command = {
        title: this.label, // 标题
        command: 'tceBlock.openWebview', // 命令 ID
        tooltip: this.label, // 鼠标覆盖时的小小提示框
        arguments: [this], // 向 registerCommand 传递的参数。
      };
    }
  }
}

Block 的定义是包含所有类型的节点的(区块分类和区块实例),所以需要根据构造函数传入的值来定义不同的行为,比如这里对于区块实例,会有 url 属性,点击他会打开一个 webview,这块在下一节详细讲解。

到此为止,树形结构已经能正常展示了。

三、预览区块

区块的预览本质上来说就是在 vscode 里面打开一个网页,这里就用到了 Webviews API。核心代码如下:

代码语言:javascript
复制
let currentPanel: vscode.WebviewPanel | undefined = undefined;

export function openWebView(url: string) {
  if (currentPanel) {
    currentPanel.dispose();
  }

  currentPanel = vscode.window.createWebviewPanel(
    'tceBlock',
    'TCE Block',
    vscode.ViewColumn.One,
    {
      retainContextWhenHidden: true, // 控制是否保持webview面板的内容(iframe),即使面板不再可见。
      enableScripts: true, // 下面的 html 页可以使用 Scripts
    }
  );
  currentPanel.webview.html = getWebviewContent(url);

  // Reset when the current panel is closed
  currentPanel.onDidDispose(() => {
    currentPanel = undefined;
  }, null);
}

function getWebviewContent(url: string) {
  return `<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Cat Coding</title>
    <style>
      html,
      body {
          margin: 0 !important;
          padding: 0 !important;
          width: 100%;
          height: 100%;
      }
      #blockFrame {
          width: 100%;
          height: 100%;
      }
  </style>
</head>
<body>
<iframe id='blockFrame' src="${url}" scrolling="auto"></iframe>
</body>
</html>`;
}

代码很好理解,分为以下几步:

  • 新建一个 webviewPanel
  • 设置 webviewPanelhtml
  • html 中嵌入一个 iframe 来动态加载网页

这个操作会注册成 vscode 的一个命令,然后在点击区块实例的时候被调用:

代码语言:javascript
复制
vscode.commands.registerCommand('tceBlock.openWebview', (node: Block) => {
  openWebView(node.url);
});

export class Block extends vscode.TreeItem {
  constructor(...) {
    ...
    // 区块实例
    if (url) {
      ...
      this.command = {
        command: 'tceBlock.openWebview', // 执行上面定义的命令
        arguments: [this], // 向 registerCommand 传递的参数
        ...
      };
    }
  }
}

四、安装区块

通过区块列表安装

我们希望插入区块这个操作显示在区块实例的边上,当鼠标移动到对应区块时被激活:

这就需要在 package.json 文件中定义这个操作:

代码语言:javascript
复制
"contributes": {
  "menus": {
    "view/item/context": [
      {
        "command": "tceBlock.addBlock",
        "when": "view == tceBlock && viewItem == block",
        "group": "inline"
      }
    ]
  }
}

具体的区块插入代码跟 上一篇文章 大同小异,在此就不重复了。这里会用到一些 VSCode 的 API,如通过对话框的方式获取用户希望区块插入的位置:

代码语言:javascript
复制
const options: vscode.OpenDialogOptions = {
  title: '请选择区块插入位置',
  openLabel: '插入区块',
  canSelectMany: false,
  canSelectFiles: false,
  canSelectFolders: true,
};

const fileUri = await vscode.window.showOpenDialog(options);

insertPath = fileUri[0].fsPath;
通过上下文菜单安装

为了省却选择区块安装目录的麻烦,还能直接在项目中通过上下文菜单的方式安装区块:

这需要在 package.json 中配置上下文菜单:

代码语言:javascript
复制
"contributes": {
  "menus": {
    "explorer/context": [
      {
        "command": "tceBlock.generateBlock",
        "group": "1_modification"
      }
    ]
  }
}

选择插入区块后会提升选择区块实例:

这里用到了 VSCode 的另一个 API:

代码语言:javascript
复制
const blockNames: any[] = []
...
const blockItem = await vscode.window.showQuickPick(blockNames, {
  placeHolder: '请选择要插入的区块',
});

五、总结

本文讲解了基于区块开发的 VSCode 插件的实现细节,主要功能是以树的形式展示区块列表、预览区块和安装区块。当中用到的 VSCode API 非常实用,可以用于开发读者自己设计的插件。

本文是本系列文章的终章,希望对你有所帮助,后会有期。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-06-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、前言
  • 二、区块列表展示
  • 三、预览区块
  • 四、安装区块
    • 通过区块列表安装
      • 通过上下文菜单安装
      • 五、总结
      相关产品与服务
      命令行工具
      腾讯云命令行工具 TCCLI 是管理腾讯云资源的统一工具。使用腾讯云命令行工具,您可以快速调用腾讯云 API 来管理您的腾讯云资源。此外,您还可以基于腾讯云的命令行工具来做自动化和脚本处理,以更多样的方式进行组合和重用。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档