Memento memo.

Today I Learned.

VimConf 2016 に参加してきました

vimconf.vim-jp.org

VimConf 2016 に参加してきました。会場はmixiさんで、コーヒーが無限に飲めて最高でした。

vim-jpの中の人や普段お世話になっているプラグインの開発者の方と話せて楽しかったです。

印象に残った発表と感想書きます。全部は書けないので3つほど紹介します。ちなみに全部面白かったです。

Introduction to Vim 8.0

www.slideshare.net

日本一のVimコミッターのK.Takata さんの、Vim8.0についての発表でした。

Vimの歴史的な話や、Vimのpatchを書いてる開発者の多くが日本人、という話が印象的でした。

Vim scriptもいつの間にかLambdaやClosure等のモダンな機能が使えるようになっているそうです。Vim script書きましょう。 あと表記ゆれに注意しましょう。

発表の中で紹介されていた breakindent 機能は知らなかったのですが、便利そうなので今後使って行きたいと思いました。

(参考: Vim 8.0 で追加された機能 'breakindent' - Secret Garden(Instrumental)

Denite.nvim ~The next generation of unite~

暗黒美夢王こと、Shougoさんの Denite.nvim についての発表でした。

発表資料がVimのただのmarkdownだったのが前衛的でした。

とりあえずUniteは開発がつらいのでDenite使いましょう、ってことでした。

実際Deniteは超速くて感動するので使っていない方は導入しましょう。

Dark powered系プラグインは基本的にNeovimで前提ですが、Vim8もサポートするそうです。

今後のDark powered系のプラグインの構想?みたいなお話も聞けました。ちなみにNeovimもDark powered系プラグインもユーザは海外の開発者が多いそうです。

ShougoさんもzcheeさんもPython3書いてプラグインやdeopleteソース書いてるそうなので、VimmerはPython3書きましょう。

ちなみに他の発表ではGolang書きましょう、という話が多かったのでGolangも書きましょう。

vim-mode-plus for Atom editor

t9mdさんの、Atomプラグインvim-mode-plusの発表でした。

Atom上での単なるVimのエミュレートというわけではなく、 Atom上のvim-mode-plusならではの機能を実装しているそうです。

vim-mode-plusのdemoでVim Golf的なことをやっていたのですが、鮮やかなtext-editingでした。使いこなせればまさに思考のスピードで編集できそうです。

VimAtomの双方の特性を深く理解した上で、便利な拡張機能を実装しているようで、t9mdさんのこだわりを感じました。

詳細は上記のリンクの資料とチュートリアルをこなすのが良いと思います。自分も試してみようと思います。

その他

Vim8 vs Neovim だと圧倒的にVim8の方が多いみたいです。ちなみに私はNeovim派です。

PhoenixのTemplate Engineを Slime (Slim) にする

Slime

PhoenixのデフォルトのTemplate Engineは erbライクなeexです。 RailsだとerbよりSlimを使うケースも多いと思いますが、 PhoenixでもSlimライクなTemplate Engineが存在しました。

その名もSlimeです。ロゴがスライムっぽいですね。

github.com

多分発音も"スリム"じゃなくて"スライム"だと思います。

Phoenixに適用する

基本設定

適当なPhoenixのプロジェクトの mix.exs に依存関係を追記します。

...
  defp deps do
    [{:phoenix, "~> 1.2.1"},
     {:phoenix_pubsub, "~> 1.0"},
     {:phoenix_ecto, "~> 3.0"},
     {:postgrex, ">= 0.0.0"},
     {:phoenix_html, "~> 2.6"},
     {:phoenix_live_reload, "~> 1.0", only: :dev},
     {:gettext, "~> 0.11"},
     {:cowboy, "~> 1.0"},
     {:phoenix_slime, "~> 0.6.0"} # here
   ]
  end

config/config.exs にも適当に設定書きます。

# Configure slime
config :phoenix, :template_engines,
  slim: PhoenixSlime.Engine,
  slime: PhoenixSlime.Engine

依存関係を追記したので本体をfetchしてきます

$ mix deps.get

watch対象に追加

my_app/config/dev.exs を修正。ライブリロードを有効にするために、slim, slimeのファイルをwatch対象に追加します。

# Watch static and templates for browser reloading.
config :slime_sample, SlimeSample.Endpoint,
  live_reload: [
    patterns: [
      ~r{priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$},
      ~r{priv/gettext/.*(po)$},
      ~r{web/views/.*(ex)$},
      ~r{web/templates/.*(eex|slim|slime)$} # here
    ]
  ]

Generator Tasks

$ mix help | grep -i phoenix

とすると、phoenix関係のmix taskがドバドバ表示されます。

$ mix help | grep -i phoenix
mix local.phoenix            # Updates Phoenix locally
mix phoenix.digest           # Digests and compress static files
mix phoenix.gen.channel      # Generates a Phoenix channel
mix phoenix.gen.html         # Generates controller, model and views for an HTML based resource
mix phoenix.gen.html.slime   # Generates controller, model and views for an HTML based resource using Slime templates
mix phoenix.gen.json         # Generates a controller and model for a JSON based resource
mix phoenix.gen.layout.slime # Generates a default Phoenix layout file in Slime
mix phoenix.gen.model        # Generates an Ecto model
mix phoenix.gen.presence     # Generates a Presence tracker
mix phoenix.gen.secret       # Generates a secret
mix phoenix.new              # Creates a new Phoenix v1.2.1 application
mix phoenix.routes           # Prints all routes
mix phoenix.server           # Starts applications and their servers

出てこない場合は mix compile なり mix phoenix.routes なりすると buildが走って一緒にtaskが生成されると思います。

slime関係で新しくできたtaskは

mix phoenix.gen.html.slime   # Generates controller, model and views for an HTML based resource using Slime templates
mix phoenix.gen.layout.slime # Generates a default Phoenix layout file in Slime

の2つです。

とりあえず動かしてみます。

User users と書いている部分は 単数形 複数形 で入力します。 生成されるcontroller名はrailsと違って単数形ですね。

$ mix phoenix.gen.html.slime User users --no-model
* creating web/controllers/user_controller.ex
* creating web/views/user_view.ex
* creating test/controllers/user_controller_test.exs
* creating web/templates/user/edit.html.slim
* creating web/templates/user/form.html.slim
* creating web/templates/user/index.html.slim
* creating web/templates/user/new.html.slim
* creating web/templates/user/show.html.slim

Add the resource to your browser scope in web/router.ex:

    resources "/users", UserController

見事にslimファイルが生成されましたね。slimeはどこに行ったんでしょうか。

生成されたslimの中身は以下のようになってます。

h2 Listing users

table.table
  thead
    tr
      th
  tbody
    = for user <- @users do
      tr
        td class="text-right"
          = link "Show", to: user_path(@conn, :show, user), class: "btn btn-default btn-xs"
          | &nbsp;
          = link "Edit", to: user_path(@conn, :edit, user), class: "btn btn-default btn-xs"
          | &nbsp;
          = link "Delete", to: user_path(@conn, :delete, user), method: :delete, data: [confirm: "Are you sure?"], class: "btn btn-danger btn-xs"

= link "New user", to: user_path(@conn, :new)

ページの表示

とりあえずメッセージの通りに web/router.exresources "/users", UserController を追記します。

--no-model にしたせいかサーバ起動しようとするとめっちゃ怒られるので user_controller の余計なアクションを一旦全部削って以下のようにします。

defmodule SlimeSample.UserController do
  use SlimeSample.Web, :controller

  alias SlimeSample.User

  def index(conn, _params) do
    render(conn, "index.html", users: [])
  end
end

[error] Postgrex.Protocol (#PID<0.212.0>) failed to connect: ** (Postgrex.Error) FATAL (invalid_catalog_name): database "slime_sample_dev" does not exist みたいなエラーが出てきます。 DB作ってないので $ mix ecto.create で作りましょう。

とりあえずこれで

$ mix phoenix.server

して、 http://localhost:4000/users にアクセスすれば、ページが表示されるかと思います。

f:id:shotat_jp:20160921234438p:plain

Railsで作ったアプリケーションをPhoenixに移植するのが捗ります。

プログラミングElixir

プログラミングElixir

Programming Phoenix: Productive, Reliable, Fast

Programming Phoenix: Productive, Reliable, Fast

slimeのsyntax highlightのvimプラグインは提供されているようです。

github.com

Vimのtabは使わなくて良いかも

Vimにはbuffer, window, tabという概念があります。
このへんの詳細は以下のエントリ等にまとまっていました。

cohama.hateblo.jp

:tabnewコマンドでtabを生成することができます。が、僕は全く使いません。 複数ファイル編集時はWindow分割してbufferを適当に切り替えて生活しています。tabは一切使いません。 単純にtabとbufferとwindowを自分の脳味噌で管理し切れないからです。

ただ、素のVimで大量のbuffer(とwindow)を扱うのも若干の苦しさがあるので、pluginの力を借ります。

github.com

"vim-airline"というVimの見た目を超かっこよくしてくれるpluginを使います。 こいつは見た目を超かっこよくしてくれるにとどまらず、結構いろいろな機能を提供してくれます。

vim-airlineの機能の一つ、"Smarter tab line"を使うと、bufferをtabっぽく扱えるようになります。画像参照。

f:id:shotat_jp:20160913013218p:plain

設定はこんな感じで使ってます。

" カーソルキーでbuffer移動
nnoremap <Left> :bp<CR>
nnoremap <Right> :bn<CR>
" Smarter tab line有効化
let g:airline#extensions#tabline#enabled = 1
" powerline font入れないと若干ダサい
let g:airline_powerline_fonts = 1
" vim-airline-themesが必要
let g:airline_theme='behelit'

ところでVim8系がリリースされたそうで、おめでたいですね。

実践Vim 思考のスピードで編集しよう!

実践Vim 思考のスピードで編集しよう!

Vim再入門 Operator, Motion, TextObjectの理解とドットコマンド

Vimを使う上で "."コマンドが重要です。
"."コマンドは直前の操作の繰り返しを行うコマンドです。

例えばdawコマンドはカーソル下の単語を削除する操作ですが、ここで"."キーを押下すると再び他の単語を削除することができます。

1単語を削除する、等の定形操作は2,3回続けて行うケースが非常に多いので、ドットコマンドを癖にしておくと効率よくtext editすることができて大変気分が良いです。

"."コマンドは超強力ですが、使いこなすためには少なくとも次の3つの概念を理解することが必要不可欠です。

  • Operator
  • Motion
  • TextObject

上記3つが必要な理由としては、Vimにおける1つの操作単位が、基本的には以下の組み合わせで考えられるためです。(Visualモード等は今回考えないものとします。)

  • Operator + TextObject
  • Operator + Motion

Operator + TextObjectの例

いわゆる有名なdawciw等がこれにあたります。

それぞれdcがOperatorで、awiwがTextObjectに対応します。

Operatorで削除や変更といった操作を指定し、TextObjectで操作範囲を指定しています。

Operator + Motionの例

gU$=G等がこれにあたります。

それぞれgU=がOperatorで、$GがMotionに対応します。

Operatorで大文字化やインデント整形といった操作を指定し、Motionで操作範囲を指定しています。

基本的にはOperator + TextObjectのパターンと似ています。

"."コマンド

上記のOperator + TextObject、Operator + Motionが一つの操作の単位になります。 すなわち、上記コマンド実行後、"."コマンドを実行することで3~4キーストローク必要な操作を1キーストロークで繰り返すことができます。最初の方の繰り返しになりますが、同じ操作を数回繰り返す、ということはtext editにおいてはよくあるケースなので、"."コマンドは多用するように心がけていくのが良いです。

今回深くは踏み込みませんが、insertモードに入ってからnormalモードに戻るまで、というのも一つの操作の単位となり、"."コマンドで繰り返すことができます。

Operator

Operatorはtextを操作するものです。MotionやTextObjectと組み合わせて使います。 操作とは以下のようなものがあります。

  • 削除
  • 変更
  • 大文字小文字の入れ替え
  • テキストフォーマット
  • インデントの変更

上記の操作に対応するOperatorはd(削除) 、c(変更)等です。 Operatorの一覧を見るのが手っ取り早いと思うので、一覧を表示してみましょう。Vimを立ち上げて徐ろに以下のコマンドを打つと具体的なOperatorのリストが表示されます。

:h operator

困ったらヘルプ(:h or :help)を使いましょう。

:help operator

1. Motions and operators             *operator*

The motion commands can be used after an operator command, to have the command
operate on the text that was moved over.  That is the text between the cursor
position before and after the motion.  Operators are generally used to delete
or change text.  The following operators are available:

c   change
d   delete
y   yank into register (does not change the text)
~   swap case (only if 'tildeop' is set)
g~  swap case
gu  make lowercase
gU  make uppercase
!   filter through an external program
=   filter through 'equalprg' or C-indenting if empty
gq  text formatting
g?  ROT13 encoding
>    shift right
<    shift left
zf  define a fold
g@  call function set with the 'operatorfunc' option

g~で大文字小文字変換、zfで折りたたみの定義ができることがわかりますね。

TextObject

TextObjectとは意味のあるtextの固まりです。 通常、単語やカッコの中身を操作対象にすることが多いと思います。TextObjectはそれらをうまく表現するための仕組みです。 具体的には以下のようなものがあります。

  • 単語
  • 段落
  • カッコ内のtext
  • 引用符内のtext

例の如く、以下のコマンドで一覧を確認することができます。

:h objects

:h objects

2.1 Text objects                     *objects*

These can be used after an operator or in Visual mode to select an object.

command        action in op-pending and Visual mode ~
------------------------------------------------------------------------------
a"         double quoted string
a'         single quoted string
a(         same as ab
a)         same as ab
a<          "a <>" from '<' to the matching '>'
a>          same as a<
aB         "a Block" from "[{" to "]}" (with brackets)
aW         "a WORD" (with white space)
a[         "a []" from '[' to the matching ']'
a]         same as a[
a`         string in backticks
ab         "a block" from "[(" to "])" (with braces)
ap         "a paragraph" (with white space)
as         "a sentence" (with white space)
at         "a tag block" (with white space)
aw         "a word" (with white space)
a{         same as aB
a}         same as aB
i"         double quoted string without the quotes
i'         single quoted string without the quotes
i(         same as ib
i)         same as ib
i<          "inner <>" from '<' to the matching '>'
i>          same as i<
iB         "inner Block" from "[{" and "]}"
iW         "inner WORD"
i[         "inner []" from '[' to the matching ']'
i]         same as i[
i`         string in backticks without the backticks
ib         "inner block" from "[(" to "])"
ip         "inner paragraph"
is         "inner sentence"
it         "inner tag block"
iw         "inner word"
i{         same as iB
i}         same as iB

よく使うのはawiwibi"等でしょうか。

Motion

いわゆるh, j, k, lでカーソル移動、0, $で文頭文末移動gg, G`で行頭行末移動、等です。Vim始めて最初に覚えるやつですね。

こちらも以下のコマンドで確認できますが、量が膨大なのでこのページ上では割愛します。

:h motion.txt

まとめ

Vimの機能を深く知るためには:helpを使いこなしましょう。

実践Vim 思考のスピードで編集しよう!

実践Vim 思考のスピードで編集しよう!

実践Vimは1000回くらい読みましょう。

NeovimでElixirを書く環境を整える

備忘録

前提条件

以下導入済みのこと

  • Neovim
  • dein.vim
  • deoplete.nvim

設定

call dein#add('elixir-lang/vim-elixir')
call dein#add('awetzel/elixir.nvim',
      \{'build':
      \ 'sh -c ' . '''yes | ./install.sh'''
      \})

deoplete対応のpluginが増えてきてるので捗ります。
詳細は:h deopleteで確認することができます。

実践Vim 思考のスピードで編集しよう!

実践Vim 思考のスピードで編集しよう!