$shibayu36->blog;

株式会社はてなでエンジニアをしています。プログラミングや読書のことなどについて書いています。

「Visual Studio Code実践ガイド」を読んだ

最近コードを書く時はもっぱらVSCodeを使っていて、拡張とかも書いてみたいなと思い始めていたので、基本知識を付けるために「Visual Studio Code実践ガイド」読んだ。VSCode使い始めたばかりの人には基本的な概念や、便利拡張紹介、簡単なカスタマイズ、拡張開発など網羅的に学べて良い本だと思った。

個人的には特に拡張周りが非常に参考になった。拡張周りは公式ドキュメントを読んでたときにイマイチよく分からないなとなっていたが、この本を読んで開発から公開まで一通り学べたのはありがたかった。テキスト編集、スニペット、リント、カラーテーマそれぞれの拡張の実装サンプルもあるのも今後開発するときの指針になりそうだった。

読書ノート

  • 検索結果のファイル名をマウスオーバー -> xアイコンをクリックでそのファイルが一時的に検索結果から外れる。必要ないファイルを外した後に全て置換で残ったファイルのみ置換できる 733
  • パラメータを含むコマンドを設定する 2231
    • 例) editorScrollにパラメータを与えることで、ページの半分をスクロールする、みたいなことができる
  • 便利そうな拡張 2342
    • Code Spell Checker
    • Visual Studio IntelliCode
    • Path Intelisense
    • Auto Close Tag
    • Bracket Pair Colorizer 2
  • VSCodeを拡張できるAPIが用意された(限られた)箇所をコントリビューションポイントと呼ぶ 4070
    • 例: コマンドに関するもの: commands/menus/keybindings
    • 拡張を書く時は、このコントリビューションポイントをpackage.jsonで指定する
  • package.json中でコントリビューションポイントを指定する 4141
    • contributes
    • activationEvents
  • テキスト編集、スニペット、リント、カラーテーマの拡張のサンプルがあって参考になる 4218
  • 拡張機能は ~/.vscode/extenstionsに置くだけでVSCodeに読み込まれるようになる。手元で確認したいときに便利
$ cd ~/.vscode/extensions
$ git clone https://github.com/74th/vscode-book-markdown-goplay.git
$ cd vscode-book-markdown-goplay
$ npm install
$ npm run compile
  • 拡張機能を公開する前のチェック事項 5093
    • プログラムチェック
      • 外部ファイル参照をするならMac/windows/linuxいずれでも動くようにpathモジュールをつかってるか
      • VSIXファイルを直接インストールしても動作するか
    • Gitにリリースバージョンを示すタグは付けたか
    • .vscodeignoreファイルを適切に作成し、公開してはならないファイルを取り除いたか
    • LICENSEは作ったか
  • 拡張の公開方法 5152
    • vsce packageでvsixを作って、code —install-extension hoge.vsix で手元からインストールできる

VSCodeでQuickOpenの幅を広げ、ファイルを探しやすくする

 VSCodeで大きめプロジェクトを触っていると、QuickOpenでファイルを探すときにコマンドパレットの幅が狭くて探しにくいな...と思うことがあった。調べたら広げる方法があったのでメモ。

 まず Option to widen the command palette · Issue #85374 · microsoft/vscode · GitHub のissueにある通り、設定できるようにする機能は公式のbacklogに載ったようだ。そのため、待ってれば公式の機能で変えられるだろう。

 ひとまずそれまでの間にwork aroundするには、issueにある通りCustomize UIという拡張を使うと良い。この拡張をインストールした後に、以下の設定をsettings.jsonに入れるだけでカスタマイズできる。

  "customizeUI.stylesheet": {
    ".quick-input-widget": "width: 1000px !important; left: calc(50% - 200px);"
  }

これだけで以下のように幅が広がり、ファイルが探しやすくなった。

Before f:id:shiba_yu36:20200620220736p:plain

After f:id:shiba_yu36:20200620221526p:plain

Goで書いたツールの依存管理をdepからGo Modulesに移行した

昔作った notify-issues-to-slackの依存モジュールはdepのままで管理していたが、勉強がてらGo Modulesに移行することにした。

参考にした資料

やったこと

Pull Requestは https://github.com/shibayu36/notify-issues-to-slack/pull/10

  • コード上で使っている依存モジュールをgo.modで管理するように
  • ツール郡をgo.modで管理するように
  • Makefileなどを修正する

の三段階で行った。

コード上で使っている依存モジュールをgo.modで管理するように

まずはコード上で使っている依存モジュールをgo.modで管理するように変更する。golintなどのツール群は後回し。

go mod initする。

$ go mod init github.com/shibayu36/notify-issues-to-slack
go: creating new go.mod: module github.com/shibayu36/notify-issues-to-slack
go: copying requirements from Gopkg.lock
go: converting Gopkg.lock: stat github.com/karrick/tparse@v2.6.1: github.com/karrick/tparse@v2.6.1: invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v2
go: converting Gopkg.lock: stat github.com/google/go-github@v21.0.1: github.com/google/go-github@v21.0.1: invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v21

するとtparseとgo-githubinvalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v21 というエラーが出たので、次にこれを解決する。

Go Modulesの仕様として、v2以上のモジュールをimportする時はimport path自体を変えるという仕様があるようだ。Go ModulesドキュメントのSemantic Import Versioningという章が参考になる。

これに従いつつ、バージョンはGopkg.lockに載っていたものを使うようにimport pathを変えていく。変更はこちら

ここまで出来たらdep用のファイルを全て削除し、go buildすることでgo.modとgo.sumが更新される

$ rm Gopkg.toml Gopkg.lock
$ rm -fr vendor/
$ go build

これでコード上で使っている依存モジュールをgo.modで管理できるようになった。

ツール郡をgo.modで管理する

さらにgolintなどのツール郡もgo.modに載せていく。Goモジュールでツールもバージョン管理する - Plan 9とGo言語のブログを参考にする。変更点はこのcommit

まずツール郡はtools.goにimportだけするというのがベストプラクティスのようだ。これをしておかないと、go getでツールをインストールしてgo.modに載せても、go mod tidyなどを実行した時に消されてしまう。

tools.go

// +build tools

package main

import (
    _ "github.com/Songmu/ghch/cmd/ghch"
    _ "github.com/Songmu/goxz/cmd/goxz"
    _ "github.com/mattn/goveralls"
    _ "github.com/tcnksm/ghr"
    _ "github.com/x-motemen/gobump/cmd/gobump"
    _ "golang.org/x/lint/golint"
)

この状態でまたgo buildすると最新版がインストールされ、ツール郡もgo.modで管理できるようになった。

Makefileを修正する

最後にMakefiledepを使っていたところを修正する。変更点は https://github.com/shibayu36/notify-issues-to-slack/pull/10/files#diff-b67911656ef5d18c4ae36cb6741b7965

  • GO111MODULE=onにしておく
  • go testやgo buildで勝手に依存モジュールを取得してくれるようになったので、depsのようなタスクは必要なくなった
  • ツール郡はgo installで入れることで、go.modで指定されたバージョンをインストールする

これでdepからgo.modへの移行が完了した。

学んだこと

  • ツール郡の管理はtools.goにimport & go installで行う
  • Go ModulesではMinimal version selection algorithmという考え方を取っている
  • v2以上の場合import pathを変える
  • go.modのindirectというのは直接依存でない、依存モジュールの依存という意味
  • go.modのincompatibleというのはSemantic Import Versioningに従ってない場合についている
  • go get (module名)@(バージョン名) みたいなのでうまく取れなかった時は、go proxyに登録されているモジュールのバージョンを確認してみると良い

go proxyに登録されているモジュールのバージョンを確認する方法はこんな感じ。

$ curl 'https://proxy.golang.org/github.com/google/go-github/v21/@v/list'
v21.0.1
v21.0.0
$ curl 'https://proxy.golang.org/github.com/karrick/tparse/v2/@v/list'
v2.3.0
v2.2.0
v2.6.0
v2.1.2
v2.3.4
v2.1.3
v2.4.0
v2.7.1
v2.8.0
v2.3.2
v2.4.1
v2.7.0
v2.8.1
v2.1.0
v2.3.3
v2.1.4
v2.3.1
v2.4.2
v2.6.1
v2.1.1
v2.1.5
v2.5.0

まとめ

depからGo Modulesへの移行を試したので、やったことを記録に残しておいた。Go Modulesについて知見が多少深まった気はする。