読者です 読者をやめる 読者になる 読者になる

GitHub のハイライトがおかしい時のなおしかた(GitHub のハイライトの仕組み)

GitHub

GitHub でコードを見ていると,ハイライトがおかしいのを見つけることがたまにあります.ここではその直し方を紹介します.

次の2パターンを想定しています.

  • 自分のリポジトリのあるファイルのハイライト言語がおかしい
  • 構文ハイライトが間違えている,言語の新機能に対応していない

自分のリポジトリのあるファイルのハイライト言語がおかしい

コードをどの言語でハイライトするかは自動判別されますが,実はある程度ユーザ側で制御する方法があります.

VimEmacs のモードラインを書く

ファイル単位で VimEmacs の設定をマジックコメントとして書けるモードラインですが,実は GitHub もそれを参照しています

// C++ だけど拡張子は .h … C じゃなくて C++ でハイライトしてほしい

// vim: set ft=cpp
//
// または
//
// -*- mode: cpp;-*-

これで上記のコードは C++ として認識されるはずです.

.gitattributes に指定する

リポジトリ.gitattributes ファイルにハイライトを指定することもできます.

$ cat .gitattributes
*.h linguist-language=C++

またハイライト以外の設定もできて,

$ cat .gitattributes
vendor/* linguist-vendored
docs/*.rb linguist-documentation=false

例えば上記の設定をすると,vendor/ 配下は他のプロジェクトのコードと判断してリポジトリの stat (リポジトリページのヘッダにあるコード率など)から除外できたり,docs/*.rb はドキュメント向けのコードとして,stat カウントから除外できたりします.

構文ハイライトが間違えている,言語の新機能に対応していない

実は GitHub のコードハイライトを行うライブラリは OSS で公開されています.

https://github.com/github/linguist

このリポジトリでは

など様々なメタデータが管理されています.なので例えば新しい言語をつくって十分に普及してきたら,ここに自分の言語を追加したプルリクを出すなどもできるわけですね.

今回は一番最後の言語のハイライト方法を見ます.

GitHub のハイライトは .tmbundle という,TextMate の構文ハイライトフォーマットまたは,Atom の cson を使った構文ハイライトフォーマットを利用してハイライトされています.これらはオープンソースで開発されているものを利用しており,一覧は下記のディレクトリにあります.

https://github.com/github/linguist/tree/master/vendor/grammars

サブモジュールでリビジョン固定されていますが,何らかのタイミングで更新されているので,対象の .tmbundle.cson を管理しているリポジトリにプルリクを投げて修正してもらえばいずれ linguist の依存する構文ハイライターもアップデートされ,GitHub 上のハイライトがなおるという仕組みです.

例えば僕は以前 Vim script の try ... finally がハイライトされていないことに気づいたので,それを追加するプルリクを投げました.

また,上記リポジトリでは各種フレームワーク対応(例えば jquery.*.jsjQuery のファイルなど)も行われているので,各フレームワーク向けのハイライトを改善したい時は YAML の設定ファイル にプルリクを出せば良さそうです.

GitHub でコードを読んでいるとハイライトが壊れていて困ることがあるかもしれませんが,実は自力で修正できますというご紹介でした.

Travis CI で Linux (x86_64, i686, aarch64) 向け(とついでに macOS 向け)に Rust で書いたツールのバイナリをリリースする

rust Travis CI

git-brws のリリース で微妙に Travis CI 上の rust 環境でハマったのでメモ. 前提として,cargo build でビルドできるものとします.Travis の環境はツールチェーンが古いと困るので Ubuntu 14.04 を使ってます.今回は下記の環境向けのバイナリをビルドしてリリースしました.

Linux は musl libc を使う選択肢もありますが,使い慣れた glibc にしました.

f:id:rhysd:20170101204916p:plain

3行で

ビルド環境

まずは matrix: でビルドを回すジョブを書いておきます.これによって,1回の CI で4つのビルドが走ります.

matrix:
  include:
    - os: osx
      rust: stable
      env: TARGET=x86_64-apple-darwin
    - os: linux
      rust: stable
      env: TARGET=x86_64-unknown-linux-gnu
    - os: linux
      rust: stable
      env: TARGET=i686-unknown-linux-gnu
    - os: linux
      rust: stable
      env: TARGET=aarch64-unknown-linux-gnu

cargo でビルドするときにターゲットを指定する必要があるので $TARGET 変数に triple を指定しておきます.未指定だとデフォルトのターゲットが使われるので実質必要なのはクロスコンパイルが必要な i686-unknown-linux-gnu だけですが,Travis のビルド一覧で分かりやすいので書いておきます.

os:osx だと macOS が,linux だと Ubuntu 14.04 が使われます.

Deploy 設定を書く

deploy:
  provider: releases
  api_key:
    secure: XXXXX
  file: git-brws-${TRAVIS_TAG}-${TARGET}.zip
  skip_cleanup: true
  on:
    repo: rhysd/git-brws
    # On specific condition -> condition: $TRAVIS_RUST_VERSION = nightly
    #
    # Only deploy tagged commit
    tags: true

初期設定は travis コマンドがやってくれるので,gem install travis して travis setup releases するいつものやつで生成し,そのあと自分用の設定を足します.

今回はビルド後の before_deploy で zip に固めているので,生成物を削除されないように skip_cleanup を付けています.また,タグを打ったときだけリリースしてほしいので,tags: true を指定してます.

ここまでが Travis の一般的なリリース設定です.

rustup を自前で入れる

Travis の rust ツールチェーンの管理は,rustup がまだシェルスクリプトで書かれていた頃のものを使っているようなので,最新の rustup コマンドを入れます.

before_script:
  - sh ~/rust/lib/rustlib/uninstall.sh
  - export PATH="$PATH:$HOME/.cargo/bin"
  - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain=$TRAVIS_RUST_VERSION
  - rustc -V
  - cargo -V

$TRAVIS_RUST_VERSION でインストールされるツールチェーンのバージョンを指定しているので,新しい rustup でも同じバージョンの Rust がインストールされます.

ここは Travis の環境が更新されればいずれ要らなくなるかもしれません.

ターゲットの追加

i686 向けのビルドにはクロスコンパイルする必要があるので,i686 向けのツールチェーンを入れます.

before_script:
  - if [[ "${TARGET}" == "i686-unknown-linux-gnu" ]]; then rustup target add $TARGET; fi

また,aarch64 向けの gcc はコマンド名が aarch64-linux-gnu-gcc なので,cargo がリンク時にそっちを使うようにします..cargo/config に TOML 形式でビルド設定を書けます.

before_script:
  - |
    if [[ "${TARGET}" == "aarch64-unknown-linux-gnu" ]]; then
        rustup target add $TARGET
        aarch64-linux-gnu-gcc -v
        mkdir -p .cargo
        echo "[target.${TARGET}]" > .cargo/config
        echo "linker = \"aarch64-linux-gnu-gcc\"" >> .cargo/config
        cat .cargo/config
    fi

また,今回は glibc を使ってビルドするので,リンクに 32bit 環境の gcc を入れます.これには apt addon を使って gcc-4.8-multilib パッケージをインストールしておけば OK です.gcc-multilib は gcc 4.4 でかなり古いので gcc-4.8-multilib にしました.

addons:
  apt:
    packages:
      - gcc-4.8-multilib
      - gcc-4.8-aarch64-linux-gnu
      - gcc-aarch64-linux-gnu
      - libc6-arm64-cross
      - libc6-dev-arm64-cross

ビルドして zip に固める

ここは普段通りリリースビルドして成果物を入れるディレクトリをつくり,zip に固めるだけです.各環境向けに $TARGET を指定してやります.

before_deploy:
  - cargo build --target $TARGET --release
  - mkdir "git-brws-${TRAVIS_TAG}-${TARGET}"
  - cp target/$TARGET/release/git-brws LICENSE.txt README.md "git-brws-${TRAVIS_TAG}-${TARGET}"
  - zip "git-brws-${TRAVIS_TAG}-${TARGET}.zip" -r "git-brws-${TRAVIS_TAG}-${TARGET}"

これで tag 付きのコミットが push されるとクロスビルドに必要なツールが入り,ビルドされ,成果物が zip で GitHub のリリースページにアップロードされるはずです.

また,上記の設定で macOS でもビルド及びリリースできているはずです.

今手元に Windows マシンが無いのでできませんが,AppVeyor でのビルドも try してみる予定です.

2016 年につくったやつ一覧

年の瀬 雑記

f:id:rhysd:20161231221520p:plain

GitHub contributions グラフを続けるのも4年目に入っていて,来年も無理しない程度に続けて行こうかなぁと思ってます.今年は中盤あたりイマイチだったけど後半結構時間ができたので例年通りぐらいになりました.

今年もぼちぼち使っているツールのためのプラグインとか,ほしいアプリとかで新しく色々つくった気がするのでまとめてみました.

また,GitHub 検索 によると,今年は 130 件の pull request を出したようです.(自身のリポジトリ除く,public リポジトリのみ)

あと去年からつくっているもののメンテや継続的な開発も引き続きやっていて,NyaoVim には結構時間を割いたと思います.

前半にソフトウェアデザインに記事を寄稿したり,システムプログラミング会で発表させてもらったりしました.

来年もぼちぼち頑張っていきたいと思います.良いお年を.