前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >造一轮子:vscode插件--支持json生成go struct,curl生成go代码

造一轮子:vscode插件--支持json生成go struct,curl生成go代码

作者头像
golangLeetcode
发布2023-03-01 16:21:50
1.1K0
发布2023-03-01 16:21:50
举报
文章被收录于专栏:golang算法架构leetcode技术php

最近学习了一下如何写vscode插件,不得不感叹大神写的vscode框架就是厉害,简单通过配置文件加上事件处理代码就可以扩展编辑器前端的能力。膜拜之余,造了一个轮子,交互过程如下,右键json文件选择“json生成go结构体(JsonToGo)”就可以生成json文件对应的golang struct;选择“生成golang代码或者结构体->curl生成go代码(CurlToGo)”就可以从curl命令(从浏览器的debug tool直接copy过来)生成对应的golang客户端代码,简单修改即可发起http请求。

代码放在https://github.com/xiazemin/golangCodeHelper,由于没有自己的独立域名,暂时没有发布到vscode应用市场,感兴趣的小伙伴可以到github

下载下来,然后通过导入vsix文件的方式来安装插件,编译好的插件位于:https://github.com/xiazemin/golangCodeHelper/blob/main/golangCodeHelper-0.0.1.vsix,通过这个插件我们可以在本地做常用的代码生成,提升我们的开发效率。比如:

json文件:

代码语言:javascript
复制
{
  "name": "golangCodeHelper",
  "version": "0.0.1",
  "lockfileVersion": 2,
  "requires": true,
  "packages": {
    "": {
      "name": "golangCodeHelper",
      "version": "0.0.1",
      "devDependencies": {
        "@types/glob": "^8.0.1",
        "@types/mocha": "^10.0.1",

可以生成

代码语言:javascript
复制
type AutoGenerated struct {
  Name string `json:"name"`
  DisplayName string `json:"displayName"`
  Description string `json:"description"`
  Version string `json:"version"`
  Engines struct {
    Vscode string `json:"vscode"`
  } `json:"engines"`
  Categories []string `json:"categories"`
  ActivationEvents []string `json:"activationEvents"`
  Main string `json:"main"`
  Contributes struct {
    Commands []struct {
      Command string `json:"command"`
      Title string `json:"title"`
      Category string `json:"category,omitempty"`
    } `json:"commands"`

在浏览器上复制下来的curl

代码语言:javascript
复制
curl 'https://ug.baidu.com/mcp/pc/pcsearch' \
  -H 'Accept: */*' \
  -H 'Accept-Language: zh-CN,zh;q=0.9' \
  -H 'Connection: keep-alive' \
  -H 'Content-Type: application/json' \
  -H 'Cookie: BIDUPSID=17AC3E8E8275F51ACFD6A4E37AC75966; PSTM=1676794732; BAIDUID=17AC3E8E8275F51AC7F6EA632EC051DD:FG=1; H_PS_PSSID=36555_38112_38092_38132_38116_38150_38175_38173_36802_37935_38088_26350_38119_38097_38008_37881; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; BA_HECTOR=0485ag8g0g2k8ha1250g0hjm1hv49q51k; delPer=0; PSINO=5; BAIDUID_BFESS=17AC3E8E8275F51AC7F6EA632EC051DD:FG=1; ZFY=LzNgJDmgbcwFmDlSJY5RPCv4lgsx3Kzg2hlLesbqjdY:C' \
  -H 'Origin: https://www.baidu.com' \
  -H 'Referer: https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=content-type%20application%2Fjson&fenlei=256&oq=content-type%2520application%252Fjson&rsv_pq=b58f78f900026b99&rsv_t=1445vFHiJ7o4mPEOrw4MQTAUMrxUQJFcddCoRqhH8Q3CjHgKQK8m4sCm2NQ&rqlang=cn&rsv_enter=0&rsv_dl=tb&rsv_btype=t&inputT=95112&rsv_sug3=407&rsv_sug1=450&rsv_sug7=000&rsv_sug2=0&rsv_sug4=95250&rsv_sug=1' \
  -H 'Sec-Fetch-Dest: empty' \
  -H 'Sec-Fetch-Mode: cors' \
  -H 'Sec-Fetch-Site: same-site' \
  -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36' \
  -H 'sec-ch-ua: "Not_A Brand";v="99", "Google Chrome";v="109", "Chromium";v="109"' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'sec-ch-ua-platform: "macOS"' \
  --data-raw '{"invoke_info":{"pos_1":[{}],"pos_2":[{}],"pos_3":[{}]}}' \
  --compressed

可以生成

代码语言:javascript
复制

type Payload struct {
  InvokeInfo InvokeInfo `json:"invoke_info"`
}
type Pos1 struct {
}
type Pos2 struct {
}
type Pos3 struct {
}
type InvokeInfo struct {
  Pos1 []Pos1 `json:"pos_1"`
  Pos2 []Pos2 `json:"pos_2"`
  Pos3 []Pos3 `json:"pos_3"`
}

data := Payload {
  // fill struct
}
payloadBytes, err := json.Marshal(data)
if err != nil {
  // handle err
}
body := bytes.NewReader(payloadBytes)

req, err := http.NewRequest("POST", "https://ug.baidu.com/mcp/pc/pcsearch", body)
if err != nil {
  // handle err
}
req.Header.Set("Accept", "*/*")
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
req.Header.Set("Connection", "keep-alive")
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Cookie", "BIDUPSID=17AC3E8E8275F51ACFD6A4E37AC75966; PSTM=1676794732; BAIDUID=17AC3E8E8275F51AC7F6EA632EC051DD:FG=1; H_PS_PSSID=36555_38112_38092_38132_38116_38150_38175_38173_36802_37935_38088_26350_38119_38097_38008_37881; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; BA_HECTOR=0485ag8g0g2k8ha1250g0hjm1hv49q51k; delPer=0; PSINO=5; BAIDUID_BFESS=17AC3E8E8275F51AC7F6EA632EC051DD:FG=1; ZFY=LzNgJDmgbcwFmDlSJY5RPCv4lgsx3Kzg2hlLesbqjdY:C")
req.Header.Set("Origin", "https://www.baidu.com")
req.Header.Set("Referer", "https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=content-type%20application%2Fjson&fenlei=256&oq=content-type%2520application%252Fjson&rsv_pq=b58f78f900026b99&rsv_t=1445vFHiJ7o4mPEOrw4MQTAUMrxUQJFcddCoRqhH8Q3CjHgKQK8m4sCm2NQ&rqlang=cn&rsv_enter=0&rsv_dl=tb&rsv_btype=t&inputT=95112&rsv_sug3=407&rsv_sug1=450&rsv_sug7=000&rsv_sug2=0&rsv_sug4=95250&rsv_sug=1")
req.Header.Set("Sec-Fetch-Dest", "empty")
req.Header.Set("Sec-Fetch-Mode", "cors")
req.Header.Set("Sec-Fetch-Site", "same-site")
req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36")
req.Header.Set("Sec-Ch-Ua", "\"Not_A Brand\";v=\"99\", \"Google Chrome\";v=\"109\", \"Chromium\";v=\"109\"")
req.Header.Set("Sec-Ch-Ua-Mobile", "?0")
req.Header.Set("Sec-Ch-Ua-Platform", "\"macOS\"")

resp, err := http.DefaultClient.Do(req)
if err != nil {
  // handle err
}
defer resp.Body.Close()

下面详细介绍下插件开发的详细流程。首先安装node环境

代码语言:javascript
复制
% node -v
v18.0.0
% npm -v
8.6.0

然后安装脚手架和插件打包工具

代码语言:javascript
复制
npm install -g yo generator-code
npm install -g @vscode/vsce

通过脚手架生成项目框架

代码语言:javascript
复制
yo code

     _-----_     ╭──────────────────────────╮
    |       |    │   Welcome to the Visual  │
    |--(o)--|    │   Studio Code Extension  │
   `---------´   │        generator!        │
    ( _´U`_ )    ╰──────────────────────────╯
    /___A___\   /
     |  ~  |
   __'.___.'__
 ´   `  |° ´ Y `

? What type of extension do you want to create? (Use arrow keys)
❯ New Extension (TypeScript)
  New Extension (JavaScript)
  New Color Theme
  New Language Support
  New Code Snippets
  New Keymap
  New Extension Pack
  New Language Pack (Localization)
  New Web Extension (TypeScript)
  New Notebook Renderer (TypeScript)

? What type of extension do you want to create? New Extension (TypeScript)
? What's the name of your extension? hello
? What's the identifier of your extension? hello
? What's the description of your extension? hello
? Initialize a git repository? No
? Bundle the source code with webpack? Yes
? Which package manager to use? npm

它生成的代码很简单,是一个最简单的模板,能够在vscode中输出vscode,它的核心代码是下面几行,首先看下package.json

代码语言:javascript
复制
 "activationEvents": [
    "onCommand:hello.helloWorld"
  ],
  "main": "./dist/extension.js",
  "contributes": {
    "commands": [
      {
        "command": "hello.helloWorld",
        "title": "Hello World"
      }
    ]
  },

其中activationEvents,就是我们的插件和对应的命令,./dist/extension.js,是插件的入口文件,commands,后面就是对应的我们的命令。然后我们看下入口文件./dist/extension.js

代码语言:javascript
复制
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';

// This method is called when your extension is activated
// Your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {

  // Use the console to output diagnostic information (console.log) and errors (console.error)
  // This line of code will only be executed once when your extension is activated
  console.log('Congratulations, your extension "hello" is now active!');

  // The command has been defined in the package.json file
  // Now provide the implementation of the command with registerCommand
  // The commandId parameter must match the command field in package.json
  let disposable = vscode.commands.registerCommand('hello.helloWorld', () => {
    // The code you place here will be executed every time your command is executed
    // Display a message box to the user
    vscode.window.showInformationMessage('Hello World from hello1!');
  });

  context.subscriptions.push(disposable);
}

// This method is called when your extension is deactivated
export function deactivate() {}

它最核心的就是暴露了一个激活方法给vscode框架调用,在方法内部,通过vscode.commands.registerCommand,注册了需要执行的命令和对应的callback函数,并将命令发布到context, context.subscriptions.push(disposable);这样一个最简单的插件就制作完毕了。我们可以通过fn+f5进行调试,没有问题后就可以通过

代码语言:javascript
复制
vsce package 

进行打包生成对应的插件文件xxx.vsix,我们发布到应有市场然后搜索,或者直接导入插件文件,就可以使用我们的插件了。

熟悉完上述流程后,就可以开始制作自己的插件,首先在package.json里配置我们需要的命令和菜单。

代码语言:javascript
复制
"activationEvents": [
    "onCommand:golangCodeHelper.helloWorld",
    "onCommand:golangCodeHelper.JsonToGo",
    "onCommand:golangCodeHelper.CurlToGo",
    "onCommand:golangCodeHelper.CurlToGoStructs"
  ],
  "main": "./dist/extension.js",
  "contributes": {
    "commands": [
      {
        "command": "golangCodeHelper.helloWorld",
        "title": "golang编码辅助工具集"
      },
      {
        "command": "golangCodeHelper.JsonToGo",
        "title": "json生成go结构体(JsonToGo)",
        "category": "golangCodeHelper"
      },
      {
        "command": "golangCodeHelper.CurlToGo",
        "title": "curl生成go代码(CurlToGo)",
        "category": "生成golang代码或者结构体"
      },
      {
        "command": "golangCodeHelper.CurlToGoStructs",
        "title": "curl生成go结构体(CurlToGoStructs)",
        "category": "生成golang代码或者结构体"
      }
    ],
    "menus": {
      "explorer/context": [
        {
          "command": "golangCodeHelper.JsonToGo",
          "when": "!explorerResourceIsFolder",
          "group": "2_workspace@1"
        },
        {
          "group": "2_workspace@2",
          "when": "!explorerResourceIsFolder",
          "submenu": "golangCodeHelper/submenu/generate"
        }
      ],
      "golangCodeHelper/submenu/generate": [
        {
          "command": "golangCodeHelper.CurlToGo",
          "group": "1_generate@1"
        },
        {
          "command": "golangCodeHelper.CurlToGoStructs",
          "group": "1_generate@2"
        }
      ]
    },
    "submenus": [
      {
        "id": "golangCodeHelper/submenu/generate",
        "label": "生成golang代码或者结构体"
      }
    ]
  },

然后注册我们的命令执行函数并且发布

代码语言:javascript
复制
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';
import * as fs from 'fs';
import * as nodepath from 'path';
const {jsonToGo} =require('./json-to-go/json-to-go.js');
const {curlToGo} =require('./curl-to-go/resources/js/curl-to-go.js');
const{curlToGoStruct}=require('./curl-to-gostruct/curl-to-gostruct.js')
/**
 * 
 * @param path 写入的文件路径
 * @param content 写入的文件内容
 * @param fileName 写入的文件名
 * @param fileNameExtra 当文件名存在于该文件夹下时的替代文件名
 */

const writeFile = (path: string, content: string, fileName?: string | undefined, fileNameExtra?: string | undefined) => {
  let newfileName = fileName || 'json_to_go.go';
  const opt = {
    flag: 'wx' // 但是如果文件路径存在,则文件写入失败。覆盖写入:'w'
  };
  const exists: boolean = fs.existsSync(`${path}${nodepath.sep}${newfileName}`);
  if (exists) {
    newfileName = fileNameExtra || fileNameExtra+'_副本.go';
  }
  console.log(`写入路径:${path}${nodepath.sep}${newfileName}`);
  fs.writeFile(`${path}${nodepath.sep}${newfileName}`, content, opt, (err) => {
    if (err) {
        vscode.window.showErrorMessage(`写入${newfileName}失败,可能原因是,改文件夹下已存在${newfileName}`);
        return;
    }
    vscode.window.showInformationMessage(`已生成一个示例${newfileName}`);
  });
};

// This method is called when your extension is activated
// Your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {

  // Use the console to output diagnostic information (console.log) and errors (console.error)
  // This line of code will only be executed once when your extension is activated
  console.log('Congratulations, your extension "golangCodeHelper" is now active!');

  // The command has been defined in the package.json file
  // Now provide the implementation of the command with registerCommand
  // The commandId parameter must match the command field in package.json
  let disposable = vscode.commands.registerCommand('golangCodeHelper.helloWorld', () => {
    // The code you place here will be executed every time your command is executed
    // Display a message box to the user
    vscode.window.showInformationMessage('Hello World from golangCodeHelper!');
  });

  let JsonToGo = vscode.commands.registerCommand('golangCodeHelper.JsonToGo', (e) => {
    vscode.window.showInformationMessage('JsonToGo from golangCodeHelper!');
    const filename = e ? e?.fsPath?.split('/').pop() : vscode.window.activeTextEditor?.document.fileName.split('/').pop();
    vscode.window.showInformationMessage(filename+"->"+e.fsPath);
    var data=fs.readFileSync(e.fsPath,"utf-8");
    vscode.window.showInformationMessage(data);
    console.log(data)
    console.log(jsonToGo)
    const got = jsonToGo(data, null, null, false);
    console.log(got)
    vscode.window.showInformationMessage(got);
    if (got.error) {
      vscode.window.showInformationMessage(`JsonToGo from golangCodeHelper failed! ${got.error}`);
    } else {
      writeFile(nodepath.dirname(e.fsPath), got.go,'json-to-go.go');
    }
  });

  let CurlToGo = vscode.commands.registerCommand('golangCodeHelper.CurlToGo', (e) => {
    vscode.window.showInformationMessage('curlToGo from golangCodeHelper!');
    const filename = e ? e?.fsPath?.split('/').pop() : vscode.window.activeTextEditor?.document.fileName.split('/').pop();
    vscode.window.showInformationMessage(filename+"->"+e.fsPath);
    var data=fs.readFileSync(e.fsPath,"utf-8");
    vscode.window.showInformationMessage(data);
    console.log(data)
    console.log(curlToGo)
    const got = curlToGo(data, null, null, false);
    console.log(got)
    vscode.window.showInformationMessage(got);
    writeFile(nodepath.dirname(e.fsPath), got,"curl-to-go.go");
  });

  let CurlToGoStructs = vscode.commands.registerCommand('golangCodeHelper.CurlToGoStructs', (e) => {
    vscode.window.showInformationMessage('CurlToGoStructs from golangCodeHelper!');
    const filename = e ? e?.fsPath?.split('/').pop() : vscode.window.activeTextEditor?.document.fileName.split('/').pop();
    vscode.window.showInformationMessage(filename+"->"+e.fsPath);
    var data=fs.readFileSync(e.fsPath,"utf-8");
    vscode.window.showInformationMessage(data);
    console.log(data)
    console.log(curlToGoStruct)
    const got = curlToGoStruct(data, null, null, false);
    console.log(got)
    vscode.window.showInformationMessage(got);
    writeFile(nodepath.dirname(e.fsPath), got,"curl-to-go-struct.go");
  });

  context.subscriptions.push(disposable);
  context.subscriptions.push(JsonToGo);
  context.subscriptions.push(CurlToGo);
  context.subscriptions.push(CurlToGoStructs);
}

// This method is called when your extension is deactivated
export function deactivate() {}

至此,插件制作完毕,当然vscode还支持更为复杂的插件,可以参考其官方文档进行学习。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-02-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 golang算法架构leetcode技术php 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档