NoahOrblog

某・福島にある大学のコンピュータ理工学部の大学生のお話。

Protocol BuffersのLanguage Serverを書いている話

Noahです。この記事はCA20卒アドベントカレンダーの23日目の記事です

adventar.org

かなり前の大学で行われたLT会の際に作ったprotocol buffers用のLanguage Serverについて書きます.

Language Server Protocol

Microsoftの提唱しているエディタによる補完や定義元ジャンプを提供するサーバーとの通信プロトコルです.

microsoft.github.io

The Language Server Protocol (LSP) defines the protocol used between an editor or IDE and a language server that provides language features like auto complete, go to definition, find all references etc.

簡単に言ってしまえば、今まではEmacsVimVSCodeIntellij IDEAなどで補完や定義元ジャンプするには、従来各エディタの拡張として書く必要があったものを単一のサーバーを使ってプロトコル定義をしてしまえばクライアント側(各エディタで使うクライアント)を実装するだけで各言語に対応できる、というもの

protobuf language server

普段からLSPに何かしら貢献をしたいなと思っていたので作ったものがこちら

github.com

( (未だ)テストすら書いておらずmessageの定義元ジャンプしか実装していない上に雑すぎてgoto使ったりしてるのでvaporwareとしています)

現状とりあえずは私の環境(syntax="proto3", macOS, NeoVim(v0.4.2), vim-lsp)で動く状態なので、その際にひっかかったりしたことについて書きたいと思います

簡単な動作はこのような感じで、message の定義へ飛べるようになっています

実装

LSPではサーバーとの通信に標準入出力を使ってJSON-RPCを使います.

sourcegraph/go-langserverを実装の参考にしつつ書いていますので、sourcegraph製のライブラリを多用しています

github.com

github.com

github.com

メソッド群

LSPはサーバーなので、たくさんのメソッドを定義する必要があります。

JSON-RPCで通信する際にはGraphQLのように実質エンドポイントひとつのところへ、実行するメソッド名をリクエストボディに内包する形でリクエストをするので、ペイロードのなかにどのメソッドを呼ぶか示したパラメータから以下のようにswitchで条件分岐できるように実装します

    switch req.Method {
    case "initialize":
        ...
        return ...
    case "initialized":
        log.L().Info("invoked initialized method")
        ...
        return ...
    case "textDocument/didOpen":
        ...
        ...

initialize メソッド

initializeメソッドは、最初に初期化する際に利用されます。この際、どの機能が提供可能か(ここでいう XXProvider)をBoolで返します

protobuf language serverでは型(というかmessage)の定義元ジャンプしか使わないので以下のような感じになっています

   // ref. https://github.com/n04ln/protobuf_langserver/blob/master/langserver/init.go#L28

    kind := lsp.TDSKIncremental
    res := lsp.InitializeResult{
        Capabilities: lsp.ServerCapabilities{
            TextDocumentSync: &lsp.TextDocumentSyncOptionsOrKind{
                Kind: &kind,
            },
            CompletionProvider:           nil,
            DefinitionProvider:           true,
            TypeDefinitionProvider:       false,
            DocumentFormattingProvider:   false,
            DocumentSymbolProvider:       false,
            HoverProvider:                false,
            ReferencesProvider:           false,
            RenameProvider:               false,
            WorkspaceSymbolProvider:      false,
            ImplementationProvider:       false,
            XWorkspaceReferencesProvider: false,
            XDefinitionProvider:          false,
            XWorkspaceSymbolByProperties: false,
            SignatureHelpProvider:        &lsp.SignatureHelpOptions{TriggerCharacters: []string{"(", ","}},
        },
    }

ところでmessageなのにType Definitionではないの?と思うかもしれませんが、Type Definitionにしなかったのは、

message A {
    int64 a = 1;
}

message B {
    A| a = 1;
//  ^ cursor is here
}

な場合に利用したかったので単純にDefinitionにしています.

textDocument/didChange, textDocument/didOpen メソッド

テキストファイルを変更したときと、開いたときに発火します

今回、後述するprotobufのパースを行うために、定義元ジャンプの際に毎回行っていては無駄なので、ここでフックしてパースしています

protobuf_langserver/langserver.go at master · n04ln/protobuf_langserver · GitHub

protobuf_langserver/langserver.go at master · n04ln/protobuf_langserver · GitHub

textDocument/definition メソッド

実際に定義元情報を返すメソッドがこれです. 内部では、パースされて保持しているASTに対してWalkをして探索し、見つかったものを返しています

今回、パースする際にはmyitcv氏のモノレポにあるprotobufパーサーに必要情報を付与させる形で利用しており、そのためにフォークした n/master ブランチを利用しています

github.com

Diffは以下のような感じで、もともとのパーサになかった機能の、トークンの開始位置と終端の位置、行頭からの文字数をカウントする機能を追加するようにしています。現状[]byteで行っているのでマルチバイト文字列が混入するとうまく行かない場合があります

Comparing master...n/master · n04ln/x · GitHub

おわりに

Language Server Protocolのサーバーを作るのは仕組み自体は意外と簡単で、難しいところはパースをする段階や、必要な情報をいかにソースから取得するかの段階だと思います.

個人的にはLSPについて実装をしつつ、なかなかの理解を得られたので満足していますが、補完や自家製パーサーなど実装して実用に耐えうるものにしていきたいのでこれからもやっていくぞ :muscle:

Vimのレジスタをうまくつかいたい話

Noahです。この記事はVim Advent Calendar 15日目の記事です

qiita.com

レジスタをうまく使いたい

日頃Vimを触ってるとき、ぼくは何も考えずにヤンクや削除をしていますが、他のレジスタも有効活用したい.

ただ、"ay とかを打つのはしんどい

打ちやすいようにマッピングしても、結局レジスタを指定する際に [a-z] みたいに打たねばいけないので面倒だったりする

そして多分僕はレジスタを使う頃には中身を覚えていないので :reg などで確認する羽目になる. そのため、名前付きバッファの場合は各バッファに意味を持たせないといけなさそう

レジスタについて

レジスタとは、テキストを保持できるスペースのことで、ヤンクや削除をしたテキストを入れたりしてペーストできるようになっています.

普段ヤンクや削除をする際、なにも設定していなければ無名レジスタに入り、ペーストする際にはそこから利用されます.

レジスタには種類があり、

1. 無名レジスタ ""
2. 10個の番号付きレジスタ "0 から "9
3. 小削除用レジスタ "-
4. 26個の名前付きレジスタ "a から "z または "A から "Z
5. 3個の読み取り専用レジスタ ": と ". と "%
6. 代替バッファ用レジスタ "#
7. expression 用レジスタ "=
8. 選択領域用レジスタ "* と "+ と "~ 
9. 消去専用レジスタ "_
10. 最終検索パターン用レジスタ "/

ref. https://vim-jp.org/vimdoc-ja/change.html#registers

なるほど、たくさんある。

有効活用できるようにしてみる

個人的に思った問題は、

  1. 手軽にレジスタの中身を確認したい
  2. "ap など、レジスタを指定するのに面倒なタイプをしたくない
  3. ヤンクして保存してある内容のFuzzy searchをしたい

を満たす下のようなプラグインを書いてみました

github.com

個人的にfzfが好きなので、fzfありきのコードになっている

上のプレビューでは、README.mdの各見出しをヤンクしてそれぞれ管理しているレジスタの中に入れている (ここでは、"b, "c, "f, "h)

レジスタを複数予め指定しておけば、ヤンクする際に、よしなにレジスタに割り振ってくれるが、ペーストする際にはfzfで検索をかけるのでどこのレジスタに保存したのかを心配しなくていいのがいいところ

総論

個人的に思う、Vimレジスタの有効活用でした。

みなさんどのようにレジスタを有効活用しているのかぜひ教えて下さい。

Bidirectional Streaming VS Unary RPCs

Noahです

以前のハッカソンでgRPCを触ったのですが、時間差ファーストといいつつ、Bidirectional Streamingを使っていなかったので、それについて調査してみた。

Bidirectional Streamingについては下をチェケラ

grpc.io

簡単に言うと双方向ストリーミングですね.

ベンチ用コード

以下のように書きました

gist.github.com

protobufは以下のような感じです. リクエストやレスポンスに特に意味はないです. Emptyよりは少しデータ量が欲しかっただけですね.

syntax = "proto3";
package bench_man;

message Nesting {
    string text = 1;
    int64 index = 2;
}

message BenchRequest {
    string text = 1;
    int64 index = 2;
    Nesting n = 3;
}

message BenchResponse {
    string text = 1;
    int64 index = 2;
    Nesting n = 3;
}

service BenchService {
    rpc UnaryBench(BenchRequest) returns(BenchResponse);
    rpc BidirectionalStreamBench(stream BenchRequest) returns(stream BenchResponse);
}

実行結果

% go test -bench . -benchmem
goos: darwin
goarch: amd64
pkg: github.com/NoahOrberg/bench_man
BenchmarkBidirectionalStream-4             20000             85403 ns/op            1776 B/op         54 allocs/op
BenchmarkUnaryRPC-4                        10000            145166 ns/op            9840 B/op        183 allocs/op
PASS
ok      github.com/NoahOrberg/bench_man 4.084s

まぁ、それはそうという結果ですね. オペレーション辺りの実行時間は倍とまでは言いませんが爆速、メモリも見てみましたがオペレーション辺りのアロケーション回数や使用バイト数も断然良さげです.

概念としてこっちのほうがいいというのはよく知っているのですが、改めてベンチマークを取ると目に見えて結果がわかるのでいいですね.

平成最後のハッカソンに参加してきた

Noahです。

平成最後の日、CAの平成最後のハッカソンというものに後輩と同期と出てきたのでそのおはなしです。

詳細は下をチェケラ

www.cyberagent.co.jp

参加するに至るまで

最初は参加するつもりはなく、参加するといっていた同期や後輩の応援団になろうとしていたのですが、僕の友人の id:flying_hato_bus に、募集締切の一週間前くらいに誘われたので参加しました。

自分は以前からブロックチェーンないしは分散システムに対して興味を持っていたので、せっかくならそれをうまく応用したものを作りたいなと、そのころから密かに思ってました

準備期間 (4/19~4/29)

今回のハッカソンには、十日間ほどの準備期間がありました。自分は現在、東京で 出稼ぎ お仕事をしていたので、テーマ発表兼準備期間の初日の19日(金)に急遽会津へ戻り、土日で作るモノの話し合いを id:yt8492, id:flying_hato_bus とともに行い、画面設計などをしてあとは開発するだけ、というところまで持ち込みました。

実際に作ったものは、ざっくばらんに言えば 黒歴史を永久保存させるSNS です。

f:id:NoahOrberg:20190509184836p:plain
某有名アニメ風ですね

大体どんなものかというと、モバイルアプリでユーザとURLを指定すると、そのユーザの黒歴史としてそのURLを永久保存させるか否かの投票が始まります。(なお実はこの時点でWeb魚拓サービスで魚拓を取ります(悪質))

一定の数の承認を得ると、そのURLの示すページは 黒歴史としてバックで動くブロックチェーンノードに永久不滅の形で残るという恐ろしいものです。

id:yt8492, id:flying_hato_bus はふたりともよく鳥さんのマークのSNSで話すことが多かったので互いの技術セットをよく把握しており、作る箇所もそれぞれの得意分野を選定できました。

f:id:NoahOrberg:20190509185238j:plain
画面の仕様を練る練る

みんなの担当箇所

id:yt8492
id:flying_hato_bus
id:NoahOrberg (自分)

それぞれの開発ですが、自分以外の箇所はおそらく彼ら自身のエントリを読んだほうがいいと思います。

自分(id:NoahOrberg)の範囲でいうと、主に基幹となるブロックチェーンの開発が主で、モバイルとの接続APIは主にid:flying_hato_busに書いてもらい、モバイルと接続する際のデバッグや認証部分などをお手伝い程度に(ゴリッと)書きました。

自分は以前、別のハッカソンで、Proof of Stakeをもとにした合意形成アルゴリズムブロックチェーンを1から実装したことがありましたが、RedisのPub/Subでノード間通信を行ったり今考えるとひどい実装だったので、今回はちゃんとgRPCで相互通信させて実装しました。

今回はProof of Workをもとにした合意形成アルゴリズムを勝手に作り(その場のテンションで考えたので妥当性はともかくとして)、それの実装をしています。

就業後に実装をしていたのですが、初日にほぼほぼ案を固めていたおかげか、アイデア由来で躓くことはなかったです。

躓いたところといえば、タイムラグ関係で少しだけ躓きました。

全ノードに通信する箇所があるのですが、そこを愚直にforで回していたところタイムラグによってうまく合意形成されなかったので、goroutineを使う際によくやる手法ではありますが、goroutineで全ノード用に一気に処理をさせるためにchannelをwaitさせ、すべてのgoroutineが送信だけになったところでmain側でchannelをcloseすることによってほぼ同時にリクエストを投げるようにしたことくらいです。

タイムラグの発生によってうまく合意形成されないのは割と問題でした。

今回PoWがベースなのでひたすらノードに計算をさせるのですが、計算間隔を1msec以下で、検証用にハッシュ計算の難易度を比較的易しめにしたところ、合意形成がバッティングしてうまく合意形成ができなく、かといって(あまり練られてないので)難易度の調整も難しく、仕方なく各ノードのハッシュ計算の間隔を100msecごとにしているなど、妥協点もあります。以前PoSをベースに書いていた時はdiffパラメータを変えることで合意形成のハッシュ計算成功の割合を柔軟に変化できていたのですが、PoWはそうはいかず、色々な手段を右往左往していました。

あとは、Goを普段書いているはずなのに並列処理に関してあまり知見がなかったため、race conditionを引き起こすこともありました。

ひとつのcontrollerで行う処理が多いため、mutexをcontroller単位でかけると時間差によって処理がハングするところがあったので、(正攻法かはわかりませんが)問題ない程度の単位処理ごとにロックを小分けにしてやることでmutexのロックの時間を短くするなど、時間差ファーストに処理を書いたりしています。

今回は、「とりあえず、正常に動かす」という信念があったので、正攻法かどうかを考えるのは、とりあえず考えついた方法を動かして正常に動くところをみてから、という方針で書きました。最近はアルバイトのコードばかり書いているので特に何も考えずに好きなように実装をできたのがすごく楽しかったです。

開発環境にも少しだけ凝って、†最強†のMakefileを書きましたが、今思えばたいしたことなかったです。(スライドに思いっきり†最強†と書いてしまっていた)

ちなみにリポジトリはこちらです。上がサーバー兼ブロックチェーン、下が後輩の仕上げたAndroidアプリです。

github.com

github.com

当日 (4/30)

当日です。発表では他のチームの圧倒的技術力に圧倒されました。やはりインパクトというのは大事ですね。

自分はあまりWebフロントに明るくないですが、すごいWebアプリケーションばかりでした。もちろんハードをつかったものも。個人的に、かわいい女の子に目隠しされる作品がすごく好きでした。

ちなみに、僕は発表終了後にプレゼン用に壇上に置いてあった人事の方のPCを自分のと勘違いしてケーブル引っこ抜いて持ち帰ろうとしたのですが、これも見事に自分の開発したモノに黒歴史として刻まれました。

さいごに

参加チームが20チーム以上あり、とても大規模なハッカソンでした。自分は今まであまりハッカソンには参加していなかったのですが、とても良い刺激になりました。

関係された皆様、ありがとうございました。

自作NeoVimプラグインの軌跡

Noahです。

この記事はVimAdventCalendar2018 16日目の記事です

qiita.com

先日Publishした他アドベントカレンダーの記事が「〜〜の軌跡」なので、それにあやかります。

本当はVimに最近パッチで入った開発中のテキストプロパティを触ってみた話を記事にしたかったのですが、少し時間がなかったので、自作のNeoVimプラグインについて少し話します。

NeoVimのRemotePlugin関係(主にGolang)のスライドや記事はたくさん書いているのでそちらもみていただけると嬉しいです。

noahorberg.hatenablog.com

noahorberg.hatenablog.com

noahorberg.hatenablog.com

noahorberg.hatenablog.com

www.slideshare.net

最近

NoahOrberg/diesirae.nvim

github.com

実装したのはかなり前なのですが、Aizu Online Judge をNeoVimから操作できるようにしたこのプラグインがローカルでテストを回せるようになりました

以前までは提出、結果取得をしなければならず、サーバー側で提出のログに残ってしまったのですが、予め用意されているテスト用のInput, Outputを取得して内部で回せます

その際に、実行するコマンドを自分で指定する必要があります。

READMEにも書いてあるのですが、

let g:diesirae_config = {
\  'commands': {
\    'py': {
\      'build_command': [], 
\      'exec_command': ['python3', '*source*']
\    },
\    'go': {
\      'build_command': ['go', 'build', '-o', '*bin*', '*source*'], 
\      'exec_command': ['*bin*']
\    }
\  }
\}

このように、ファイル拡張子をキーにして build_commanmd, exec_command の二種類を定義します。

*bin*, *source* はそれぞれバイナリとソースファイルのプレースホルダーです。

pythonのようなスクリプト言語には build_command に空の配列を指定し、 exec_command だけ定義します。

NoahOrberg/AYUNiS.nvim

github.com

AYUNiS.nvim では、Spotify.appを操作するためにAppleScriptを内部で利用しています。

そのため、AppleScriptスクリプトの場所を知るためにRuntimePathを内部で定義していて、以前は自分が GitHub - Shougo/dein.vim: Dark powered Vim/Neovim plugin manager を使っていたので、deinからRuntimePathを取得していたのですが、PlugなどもサブPCで使用していたので、プラギンマネージャに左右されないようにRuntimePathをVimscriptで注入できるようにしました。

少しだけ煩わしいですね。

lightline.vim などで以下のように設定するとtablineで現在の再生曲タイトルが見れるのでいい感じです。

ちなみにAppleScriptを使ってるのでMacでしか動かないです。

" use lightline (show in the tabline
let g:lightline = {
      \ 'component_function': {
      \   'ayunis': 'AYUNiSGetNowPlaying'
      \ },
      \ }
let g:lightline.tabline          = {
      \ 'left': [['ayunis', 'buffers']],
      \ 'right': [['close']]
      \ }

最後に

時間がなかったので、今まで開発したプラグインや記事たちの紹介になっちゃったけど、もっとちゃんとした記事を書きたかった...

ぼくのdotfilesの軌跡

Noahです。

この記事は Aizu Advent Calendar 8日目の記事です。

adventar.org

前の記事は id:culumn さんの記事です。自分はiOS開発を行う際によくStoryboardをつかうのですが、Xibも触ってみようという気持ちになりました。

culumn.hatenablog.com

次の記事は id:Nozomi_M さんです。楽しみです。

本題

ところで、早いもので自分ももう学部三年です。

AizuAdventCalendar、自分が学部1年のとき投稿したのはHaskellの遅延評価の話、学部2年のときにはNeoVim/go-clientの記事と書きましたが、来年は忙しくて振り返ってられないと思うのと、

今年は学部一年が結構居たので、あまり小難しい記事は書かずに、僕のdotfilesの軌跡を辿っていきたいと思います。

github.com

序盤、若干ポエム入るので読みたくない人はGoBack!

ぼくのdotfiles黎明期

黎明期っていうけど、最初にdotfilesを上げたのが2015/9/9らしい。

f:id:NoahOrberg:20181206182219p:plain

ちょうど自分が高校3年の秋ですね。僕はこの頃から会津大学の受験勉強を始めていました(推薦入試の3ヶ月くらい前でかなり遅い)

この頃は Qiitaやどこかからコピペしたreferenceすらない .vimrc をお遊びで入れていたくらいで、そもそもGitHubというツールがどのようにつかわれるものかを把握していませんでした。

dotfiles/.vimrc at a1a4a1d449f7ff1219c114f53ebd62b5c0e09ddd · NoahOrberg/dotfiles · GitHub

僕自身、大学に入ってからチーム開発というものを触れたのでしかたがないですね。コミットメッセージも最初の頃はひどいものです。

f:id:NoahOrberg:20181206182858p:plain

ひどいコミットメッセージ

何がcorrectやねん。そもそも定期ってなんやねん定期って。

ぼくの最近の.zshrcのはなし

install script

最初は、上のようにどこから拾ってきたか知らない .vimrc を突っ込んでるだけでしたが、最近はMacBookProと並行して使うマシン(ThinkPad x230)が増えたり、インターンで使用するPCが支給されたりしたので、それらのためにセットアップスクリプトを組んだりしています。

#     __                     
#    / /_  ________ _      __
#   / __ \/ ___/ _ \ | /| / /
#  / /_/ / /  /  __/ |/ |/ / 
# /_.___/_/   \___/|__/|__/  
#                            
if `which brew > /dev/null 2>&1`; then
    echo "brew: already installed"
else
    if [ `uname` = "Darwin" ]; then
        echo "brew: installing..."
        /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
        echo "brew: done."
    elif [ `uname` = "Linux" ]; then
        echo "brew: unnecessary install"
    else
        echo "cannot detect OS"
    fi
fi

よくあるやつですね。Linuxにはbrewは不必要(apt-getなりpacmanなりをつかえばいい)なので、 unameDarwin, Linuxで識別してそれぞれを入れます。

愛用のfzfやzplugもこれで入れています。

widgets

zshは、widgetという機能を使うと、関数をキーにバインドでき、その機能を自分は割と気に入って使っています。以下のような関数をC-jなどホームポジションで実行できるように出来ます。

cd_ghq() {
    selected=`for dir in $(ls $GHQPATH/github.com);do for dir2 in $(ls $GHQPATH/github.com/${dir});do echo ${dir}${dir2}; done; done | fzf`
    [ "${selected}" = "" ] && return 0
    cd $GHQPATH/github.com/${selected}

    zle reset-prompt
    zle -R -c
}

zshプラグインで、anyframeというプラグインanyframe-widget-cd-ghq-repository というウィジェットがあるのですが、細かい挙動を操作したかったので自分で再実装しています。

fzfを割と愛用してて、それで任意のghqパス配下にあるディレクトリに移動できるので心強い

github.com

これ以外によく使うのは、gitのbranchのcheckoutですね。

checkout_gbranch() {
    # NOTE: サブディレクトリからでもcheckout可能にする
    #       プロジェクトルートにcdする制限付き(存在しないディレクトリに入ったりしないために
    tmpdir=`pwd`; branches=""
    while true ; do # NOTE: `$ git branch -a` を、cdしなくてもいい方法があればそちらのほうが良い
        if [ `pwd` = "/" ]; then;
            cd ${tmpdir} && return 0
        fi

        if [ -d .git ]; then;
            branches=`git branch -a`
            break
        else cd ../; fi
    done
    selected=`echo ${branches} | awk 'BEGIN{}{print $1}' | grep -v 'HEAD' | grep -v '\*' | awk 'BEGIN{idx=1;FS="/"}{if($1=="remotes" && $2=="origin"){idx=3};for(i=idx;i<NF;i++){printf "%s/", $i}; print $NF}' | sort | uniq | fzf`
    # NOTE: プロジェクトルートからしかできない安定版は以下(上がぶっ壊れたらつかう)
    # [ ! -d .git ] && return 0
    # selected=`git branch -a | awk 'BEGIN{}{print $1}' | grep -v 'HEAD' | grep -v '\*' | awk 'BEGIN{idx=1;FS="/"}{if($1=="remotes" && $2=="origin"){idx=3};for(i=idx;i<NF;i++){printf "%s/", $i}; print $NF}' | sort | uniq | fzf`
    [ "${selected}" = "" ] && return 0
    git checkout ${selected}

    zle reset-prompt
    zle -R -c
}

プロジェクトルートに戻るために .git/ が見つかるまでひたすら cd ../ してますね。改めて見ると、階層が浅いうちはいいんですけど深くなったらどうなるんでしょうねコレ。

めっちゃコメントがかいてありますが、実際には割といま手探りで、gitのcheckoutの都合上、checkout元のブランチには存在したディレクトリにいまいるとして、checkout先のブランチにはそのディレクトリがない、などの場合が起こると都合が悪いので、チェックアウトしたあとにプロジェクトルートに戻るか、それともこの実行自体をプロジェクトルートから行えるのみにするか、みたいな葛藤をしてますね。

結局前者のほうが都合がいいので、後者はコメントにして残してる状態です。GitHubでコードを管理するとき、わりとみなさん良いコードだけ残そうとしますけど、葛藤したコードとかも残しておくほうがあとから見返せますし個人的にはいいと思います。

fzfを使うと、dockerの操作も簡単にできますのでおすすめです。ここに書くと行数が長くなるので書きません。

dlogs: dotfiles/.zshrc at 6777317032fd9b3e173a9f7fde4e2a7b8e5dcd3a · NoahOrberg/dotfiles · GitHub

dsh: dotfiles/.zshrc at 6777317032fd9b3e173a9f7fde4e2a7b8e5dcd3a · NoahOrberg/dotfiles · GitHub

dshは個人的によく使います。作業する際にコンテナの中に入って操作するときが多いので。

コマンド

あとは gg コマンドですね。chrome-cliを使って、今開いているタブのgitリポジトリghqで取ってくるようにしています。

gg() {
    # NOTE: NEEDs chrome-cli
    #       $ brew install chrome-cli
    ghq get $(chrome-cli info | sed -n 's/Url: https:\/\/github.com\/\(.*\)/git@github.com:\1/p')
    cd $GHQPATH/$(echo $_ | sed -e 's/git\@github.com:\(.*\)/github.com\/\1/')
}

ブラウジングしてて、ふとクローンしたいと思ったときにべんりです。

あまり賢くないので正規表現でごまかしつつスクリプトを組み立てています。

ぼくの最近の.config/nvim/init.vimのはなし

init.vimはNeoVimの設定ファイルです。

ちなみに自分は最近あまり編集をしてません(最近はほぼほぼzshの設定をしている)

自分はよくタイポをするのですが、それの修正のために

iabbrev TOOD TODO
iabbrev srting string
iabbrev strign string
iabbrev strnig string
iabbrev nit int
iabbrev pubric public
iabbrev Pritln Println
iabbrev Prit Print
iabbrev pritn print
iabbrev singup signup
iabbrev singin signin

こんなかんじで、iabbrev に定義をしておいて自動でタイポを直すようにしています。これはべんり。最近知った。

あとは、inccommandですね。

set incsearch
set inccommand=split

これを入れると、nvim側で置換をするときにプレビューしながら置換コマンドをかけます。これは便利。下のgifでは単純な置換のみですが、正規表現は結構難しいので割とアドです。

ぼくの最近の.config/karabinerのはなし

最近はThinkpad KeyboardをBluetoothでつなげてよく使いますが、このキーボード、ミドルボタンが少し癖があります。

Chromeなどウェブブラウザで特に顕著なのですが、スクロールのために押すと、カーソル以下のリンクが別タブで開く謎の挙動をします。

なので、それの修正をkarabinerでするスクリプトや、WindowsキーボードとMacのキーボードの配置の違いである、AltとCommandの逆転なども仕込んでいます。

これらは以下の記事から持ってきたコードなので特に書きません

ref. http://k3174r0.hateblo.jp/entry/2017/12/05/202046

ぼくの最近の.tmux.confのはなし

自分の開発において、tmuxはなくてはならないもので、自分の開発時間中、彼はずっと支えてくれています。

tmuxの見た目に関しては、vimプラグインでカラースキーマにいい感じに合わせてくれるプラグインがあるのでそれを使っています。

github.com

これはべんり。最近、tenderからspacemacs風のカラースキーマに変更したのですが、やっぱり良い。

まとめ

以上、ぼくの最近のdotfiles事情をまとめてみました。俗に言われるシェル芸とか、あまり大したことはしてないです。

「エディタはIDEで十分じゃい!」

vim(ないしはnvim)なんかつかわない!」

「tmuxよりscreenでしょ!w」

とかいうひとでも、普段シェルやターミナル環境は少なくとも使うだろうと思いますし、JetBrainsのIDEでも、~/.ideavimrc を置くことでIdeaVimの設定を行うことができます。

みなさんもこれを期に自分だけのdotfilesを極めてみてはどうでしょうか。いいdotfilesやtipsがあれば紹介していただけるとぼくも嬉しいです。

はてなインターンで最高の夏を過ごして来た

f:id:NoahOrberg:20180907142720j:plain

実はしれっと、はてなインターン2018に参加してきました!!!

developer.hatenastaff.com

応募まで

応募が始まった瞬間、エントリーシートを記入しました。(14:00 からだったのですが、その前から待機していました。)

提出するものは、自分のポートフォリオと簡単な技術課題(ROT13の実装。任意の言語を選択可能)だったので、実装してシュッと提出したのを覚えています(30分位で提出した記憶)

応募に至った動機としては、以前のバイト先が同じで、大学の先輩である id:upamune さんと id:ktr_0731 さんが一昨年、昨年のはてなインターン生(2人ともmackerelチーム)で、話を伺っていたので自分もmackerelチームにインターンで参加したいな、と思っていました。

応募から選考に受かるまで

個人的にはてなインターンが第一で行きたいところで、(もしはてなインターンに落ちたときの万が一のために)それ以外にも複数のインターンの選考を受けていました。

選考のフローとしては、書類選考の後に面談を一回行って、それから合格のメールを数日後にいただきました

前半過程

前半過程では、去年まではPerl, Scalaでしたが、 Webサービス開発の上流から下流までを網羅した充実の講義プログラムを用意 という通り、今年はGolangでのサーバーサイド、React.jsでのフロントエンド、GraphQLを用いたWebサービスの実装、AWS機械学習、インフラなどといった講義が行われ、濃い二週間でした。

GraphQL実装、すごく楽しかった。

普段書いているGolangはもちろん、個人的に普段書かないフロントエンドについてや、触れたことのない機械学習などの技術にそれこそ上から下まで触ることができて最高だった。

後半過程

希望通り、mackerelチームに配属され、 id:albacore (通称メテオ)と最初はペアプロしてました。

Scalaを基本的には使い、外部APIを生やしたらmackerel-client-go にPR投げるなどを主にやりました。

数日でそれぞれ別タスクをやることにしましたが、 id:albacore の実装が尋常じゃないほど早く、自分が1機能作ってる間に彼は3機能くらい手を付けていたのでやばかった。(語彙力)

ちなみにmackerelチームは配属準備の2週目の金曜日、その次週の月曜日(本来はこれが初日)に外部向けのRoleAPIを実装してインターン最速リリースをすることができました。

mackerel.io

mackerel.io

インターン生活

他のインターン生も、みんな同じ志をもっているので、結構仲は良かった(例年より仲が良かったらしい。

夜は id:albacore と共に id:E_ntyo の部屋に押しかけたこともあった。

あと、はてなインターンは本当にお金を使いません。朝はホテルの朝食(券が貰えるが朝に弱く実は一度も使っていない)、昼はまかない、夜は社員の方がご飯に連れてってくれます

あと、素敵なステッカーももらえます。

まとめ

はてなインターン、最高の夏!!!!!!

実はこの記事はインターン後に伝統の三嶋亭に諸用で行けなかったので、みんなと東京ですき焼きを食べながら書いて公開しています。(本当です。)

普段の技術バイトなどで触る一部の業務だけでなく、前半の講義パートでWeb開発の大枠を掴み、後半で実践のできるはてなインターンは、是非大学の後輩にも行って多くを学んで来て欲しいと思いました。

あわせて読みたい他のインターン生の記事

id:E_ntyo キャラが濃い。1日目に遅刻したことをかなり後悔していた。はてなでわっしょい。 e-ntyo.hatenablog.com

id:albacore 通称メテオ氏。技術的にも〇〇的にもヤバかった。mackerelチーム優勝出来なかったのは心残り。 blog.meteors.me

id:gazimum がじまむ。一番の常識人だった気がする。実は同じ地元だったのと、彼が次に行くインターン先に id:culumn がいることも衝撃。 tomoyaf.hatenablog.com

id:YaaMaa 服部の人。 ずっとこれの言語Rubyなの、服部の色意識してかと気になってたけど最終日に違うことが判明してよかった yaamaa-memo.hatenablog.com

id:turtar_fms かめの人。一般人かと思ったら意外とやばかった。 いいんちょと一緒にいるイメージが多い(後半過程より)。 turtar-fms.hatenablog.com

id:mizdra キングドラのひと。一番熱意があって最高。 彼のプレゼンが一番見たかった。

www.mizdra.net

id:guni1192 ツッコミ担当。彼の鋭いツッコミが、僕は好きです。インフラの知識ありまくりで凄かった。

記事が増えたら貼るよ!お楽しみに