【一人 vimrc advent calendar 2017】gvimrc について【23日目】

一人 vimrc advent calendar 2017 23日目の記事になります。
そういえば、gvimrc について書いてなかったので簡単に書いてみようかと。

GUIVim

GUI 版の Vim を起動するには環境にもよりますが gvim コマンドを使って起動させる事が出来ます。
これにより端末上ではなくて GUI アプリとして Vim を起動させることが出来ます。
gvimrc ファイルは vimrc ファイルと同じように起動時に読み込まれる設定ファイルですが、GUI 版の Vim を起動した時に『vimrc の後』に読み込まれます。
読み込まれる gvimrc ファイルは基本的に vimrc ファイルと同じですが、起動オプション -U {gvimrc}$MYGVIMRC で指定することが出来ます。

ユーザーの個人的なGUI初期化ファイルを置くのに推奨される場所:
    Unix            $HOME/.gvimrc、$HOME/.vim/gvimrc
    OS/2            $HOME/.gvimrc、$HOME/vimfiles/gvimrc、$VIM/.gvimrc
    MS-DOSとWin32   $HOME/_gvimrc、$HOME/vimfiles/gvimrc、$VIM/_gvimrc
    Amiga           s:.gvimrc、home:.gvimrc、home:vimfiles:gvimrc、
                    $VIM/.gvimrc

gvimrc で設定するべきオプション

当たり前ですが基本的には GUIVim でのみ有効にしたい設定を記述します。
また、GUI 版だけで意味のあるオプションもあるので、GUI 版の Vim を使う場合は調べてみるとよいと思います。

オプション 内容
'guicursor' カーソルの外観を指定
'guifont' GUI フォントの設定
'guipty' shell で pseudo-tty を使用するかどうかの設定
'guioptions' メニューやスクロールバーなど GUI 固有の設定

ちなみにこれらのオプションは vimrc で設定しておいても問題ないです(GUI 版でのみ有効になる。

まとめ

  • gvimrcGUI 版で読み込まれる設定ファイル
  • vimrc のあとに gvimrc が読み込まれる
  • gvimrc 固有の設定もある


端末上ではなくて GUI 版で Vim を使ってみたい方は試してみるとよいと思います。

【一人 vimrc advent calendar 2017】タブページを操作するキーマッピングいろいろ【22日目】

一人 vimrc advent calendar 2017 22日目の記事になります。
もうすぐ Advent Calendar も終わりですね…。

タブページを操作するキーマッピングいろいろ

さて、わたしは基本的にタブページごとにファイルを開いているのですが、そのタブページを扱うキーマッピングをいろいろと紹介してみます。

" タブの移動
nnoremap <silent> <C-l> :tabnext<CR>
nnoremap <silent> <C-h> :tabprevious<CR>
nnoremap <silent> <C-Tab> :tabnext<CR>

" タブページ自体を左右に移動させる
command! -bar TabMoveNext :execute "tabmove " tabpagenr() % tabpagenr("$") + (tabpagenr("$") == tabpagenr() ? 0 : 1)
command! -bar TabMovePrev :execute "tabmove" (tabpagenr() + tabpagenr("$") - 2) % tabpagenr("$") + (tabpagenr() == 1 ? 1 : 0)

nnoremap <silent> <S-l> :TabMoveNext<CR>
nnoremap <silent> <S-h> :TabMovePrev<CR>

上記のようなキーマッピングを行うことで素早くタブページを移動したりタブページのレイアウトを変更したり出来ます。

おまけ

:help setting-guitablabel にも書かれているんですが、以下のように 'guitablabel' を設定しておくと更にタブページが見やすくなります。

function GuiTabLabel()
  let label = ''
  let bufnrlist = tabpagebuflist(v:lnum)

  " このタブページに変更のあるバッファがるときには '+' を追加する
  for bufnr in bufnrlist
    if getbufvar(bufnr, "&modified")
      let label = '+'
      break
    endif
  endfor

  " ウィンドウが複数あるときにはその数を追加する
  let wincount = tabpagewinnr(v:lnum, '$')
  if wincount > 1
    let label .= wincount
  endif
  if label != ''
    let label .= ' '
  endif

  " バッファ名を追加する
  return label . bufname(bufnrlist[tabpagewinnr(v:lnum) - 1])
endfunction

set guitablabel=%{GuiTabLabel()}

タブページを使うと視覚的にもわかりやすいのでバッファがよくわからんという人は使ってみるとよいと思います。

【一人 Ruby Advent Calendar 2017】Ruby の % 記法【22日目】

一人 Ruby Advent Calendar 2017 22日目の記事になります。
そろそろラストスパート

% 記法

Ruby には % 記法という特別なリテラルがあります。
例えば、%w という記法を使うと以下のように『空白文字で分割した』文字列の配列として定義されます。

p %w(homu mami mado)
# => ["homu", "mami", "mado"]

またこの時に記述した %w()()[]{}<> みたいな括弧や『改行を含めた任意の非英数字』を利用することが出来ます。

p %w<homu () mado>
# => ["homu", "()", "mado"]

p %w`'() [] {}`
# => ["'()", "[]", "{}"]

p %w!` " '!
# => ["`", "\"", "'"]

こんな感じでリテラルで定義する記号によって () の記号を変えることが出来ます。

%%Q:ダブルクオート文字列

%%Qは『ダブルクオート文字列』として定義されます。

p %(homu "mami")
# => "homu \"mami\""

# 式展開も行える
p %Q("#{5 + 4}:mado")
# => "\"9:mado\""

%q:シングルクオート文字列

%q は『シングルクオート文字列』として定義されます。

p %q(homu "mami" 'mado')
# => "homu \"mami\" 'mado'"

# 式展開は行われない
p %q(#{2 + 4})
# => "\#{2 + 4}"

%x:コマンド出力

%x は外部コマンドを実行して結果を返します。

p %x(ls)
# => ls コマンドの実行結果

` と同じです。

%r正規表現

%r は『正規表現リテラル』として定義されます。

p %r(\d+)
# => /\d+/

# / もエスケープされる
p %r(http://.*)
# => /http:\/\/.*/

%w:空白文字で区切った要素が文字列の配列を定義

%w は『空白文字で区切った要素が文字列の配列』を定義します。

p %w(homu mami mado)
# => ["homu", "mami", "mado"]

p %w("homu" "ma mi" "mado")
# => ["\"homu\"", "\"ma", "mi\"", "\"mado\""]

%W%w と同等(式展開とバックスラッシュ記法が有効)

%w と同等ですが『式展開とバックスラッシュ記法』が有効です。

p %W(#{2 + 4}:#{[1, 2, 3]})
# => ["6:[1, 2, 3]"]

p %W(homu ma\mi mado)
# => ["homu", "mami", "mado"]

%s:シンボル

%s は『シンボル』で定義されます。
また、式展開、バックスラッシュ記法は無効です。

p %s(homu)
# => :homu

p %s(42)
# => :"42"

p %s(#{1 + 2})
# => :"\#{1 + 2}"

%i:空白文字で区切った要素がシンボルの配列を定義

%i%w と同様に『空白文字で区切った要素』の配列として定義されますが、文字列ではなくてシンボルとして定義されます。

p %i(homu mami mado)
# => [:homu, :mami, :mado]

p %i(homu mami #{2 + 2})
# => [:homu, :mami, :"\#{2", :+, :"2}"

%I%i と同等(式展開とバックスラッシュ記法が有効)

%i と同等ですが、『式展開とバックスラッシュ記法』が有効になります。

p %I(homu mami mado)
# => [:homu, :mami, :mado]

p %I(homu mami #{2 + 2})
# => [:homu, :mami, :"4"]

まとめ

  • % 記法を使って様々な値を定義することが出来る
  • 文字列の配列を定義する場合は %w を使うと楽
  • 正規表現/ を提議したい場合は %r を使うとエスケープする必要がない


正規表現/ を含めいたことは稀によくあるのでそういう場合は %r を使うと楽ですねえ。

参照

【一人 vimrc advent calendar 2017】コマンドを実行した際にカーソル位置を移動させないスクリプト【21日目】

一人 vimrc advent calendar 2017 21日目の記事になります。
そろそろネタが枯渇してきているのですが、今日 vimrc から便利そうなスクリプトを発掘したのでそれの初回でも。

カーソル位置などを移動させないでコマンドを実行するスクリプト

元々、他の方の vimrc に書かれていたスクリプトになります。

" 元ネタ
" https://github.com/bling/dotvim/blob/d84e501bd12f9c6887599ace398fe26f542e8f6e/vimrc#L105
function! s:preserve(command) "{{{
   " preparation: save last search, and cursor position.
    let _s=@/
    let view = winsaveview()
   " do the business:
    execute a:command
   " clean up: restore previous search history, and cursor position
    let @/=_s
    call winrestview(view)
endfunction "}}}

command! -complete=command -nargs=*
\   Preserve call s:preserve(<q-args>)

上記スクリプトを使うことで例えば :substitute した時などに『カーソル位置を移動させずに』置換を行うことが出来ます。

:Preserve %s/\s\+$//g

また、以下のようなコマンドを定義しておくと :Preserve %s:S として使えるようになります。

command! -complete=command -range -nargs=*
\   S Preserve %s <args>

今までほとんど使ったことがなかったんですが普通に便利そう…。

【一人 Ruby Advent Calendar 2017】ginza.rb で Ruby 2.5 の話を聞いてきた【21日目】

一人 Ruby Advent Calendar 2017 21日目の記事になります。
ちょっと話が前後してしまいますが、火曜日にginra.rb に初参加してきたのでそのまとめを。
今回は Ruby 2.5 のおさらいということで Ruby 2.5 の機能を参加者全員で眺めて生きながら意見を言っていくような内容でした。

当日読んでいた Ruby 2.5 に関する資料

以下、気になった機能を読んでいるときに出た意見などの適当なまとめ。
ちなみにわたしはまだ Ruby 2.5 の機能は殆ど触れてないです。

バックトレースおよびエラーメッセージが逆順に出力されるようになった

以下のようにバックトレースの順番が代わりました。

Ruby 2.4

$ ruby2.4 main.rb 
main.rb:3:in `map': undefined method `to' for 1:Integer (NoMethodError)
  from main.rb:3:in `homu'
    from main.rb:8:in `func'
  from main.rb:11:in `<main>'

Ruby 2.5

$ ruby main.rb
Traceback (most recent call last):
    3: from main.rb:11:in `<main>'
  2: from main.rb:8:in `func'
  1: from main.rb:3:in `homu'
main.rb:3:in `map': undefined method `to' for 1:Integer (NoMethodError)
  • 慣れの問題
  • リリースされたらみんな使うのでいろいろと意見が出てきそう
  • わたしはまだ確認してないのでなんとも言えない

トップレベルの定数検索が Object から削除された

以下の用にトップレベルで定義したクラスなどが X::Toplevel のように :: で参照できなくなった。

class Toplevel
end

class X
end

# この時にトップレベルの定数(クラスなど)が参照できなくなった
X::Toplevel
  • 今までの仕様は挙動としては正しいけど意図しているかは微妙だった
  • Ruby の挙動として見ると Object が検索されるのはわかる
  • Object 内で明示的に定義したクラスも参照されない
class Object
  class X
  end
end

class X2
end

# エラー
X2::X

yield_self

#tap と似ているがブロック内の戻り値を返す。

# yield_self だと break は不要
p [1, 2, 3].yield_self { |myself|
    myself.map { |it| it + myself.size }
}
# => [4, 5, 6]

Procの確保を遅延

  • 今まではブロック引数を明示化しているよりも『していないほうが』パフォーマンスがよかった
  • ブロック引数を明示化したほうがわかりやすいのでなるべくパフォーマンスに影響がでないように対応した
  • jruby だと逆にブロック引数を明示化したほうが早かった
  • パフォーマンスの問題はなくなったのでみんなブロック引数を明示化しよう
  • Ruby 2.5 は引数に &block を書いても速い!!! - onk.ninja

式展開の #to_s が refinements に対応

class X
end

using Module.new {
    refine X do
        def to_s
            "class X"
        end
    end
}

# refinements で定義された #to_s が呼ばれる
p "output: #{X.new}"
# => "output: class X"
  • 便利
  • ほかの内部で呼ばれるメソッドも refinements に対応してほしい
  • respond_to?to_proc も refinements に対応してほしい

Integer.sqrt

p Integer.sqrt(9)
#=> 3

p Integer.sqrt(15)
#=> 3

p Integer.sqrt(16)
#=> 4

String#casecmp で例外が発生しなくなった

Ruby 2.4

# Error no implicit conversion of Symbol into String (TypeError)
"homu".casecmp(:homu)

# Error no implicit conversion of Symbol into String (TypeError)
"homu".casecmp(1234)

Ruby 2.5

p "homu".casecmp(:homu)
# => nil
p "homu".casecmp(1234)
# => nil
  • TypeError のままでもよかったのでは?
  • Symbol だと nil を返していた
  • 一貫性のために TypeError から nil を返すように変更
    • と思ったけど Symbol でも TypeError だったのでうーん?
  • やっぱり TypeError のままの方がよかったのでは?

ERB#result_with_hash が追加

require "erb"

p ERB.new("Hello, <%=name%>").result_with_hash(name: "homu")
# => Hello, homu
  • #result_with_hash でコンテキストを渡した場合でも外部のコンテキストは参照できる
  • それならあまり意味が無いような気がする
  • コンテキストを明示的に上書きすることはできる

Set#===

case :apple
# Set のいずれかに含まれていれば
when Set[:potato, :carrot] then 'vegetable'
when Set[:apple, :banana]  then 'fruit'
end
#=> "fruit"
  • 集合と集合で比較するのではなくて #include? を使う
  • Set オブジェクト同士を比較したい?
  • #include? を呼び出すのは微妙かと思ったけどまあ Set ならいいかー
  • Method#=== を使用して s.method(:include?) みたいに代用することも可能

個人的に #===#include? にするのはなんかなーと思ってましたがまあ Set だからいいかーという位置に落ち着きました。
Range も同じですしね。
ただし、Array#=== を #include? のエイリアスにするのは絶対に許さん。

Ruby 2.5 に対する所感

そんな感じでざっくりまとめてみました。
上記以外にも Ruby 2.5 ではいろいろとメソッドや機能なんかが追加されたんですが割と『それはそうだよねー』みたいな機能とかが多かった印象です。

個人的によさげなのはやっぱりブロック引数周りのパフォーマンスの向上ですかね。
そもそもブロック引数を明示化してないのにブロック引数を渡すことができるという挙動があまり好きではないので、この機会に『ブロック引数を受け取る場合は必ずブロック引数を明示化する』ようになってほしいです。
あと Method#=== もそうですが Set#=== が入っていたのが知らなかったのでちょっと驚きました。
#=== ブーム来てるぞ…。

他には全員に影響があるって意味でバックトレース順が変わることですかねえ。
慣れの問題だったり、Ruby 2.5 の仕様のほうが見やすいって人もいると思いますが、やはり今までと表示形式が変わることに対する影響はコードの仕様が変わるぐらい大きいと思います。
この部分は Ruby 2.5 がリリースされてから色々と意見が出てきそうですねえ。
あ、あとそろそろ refinements さんはどこまでの範囲が影響するのかをしっかりとまとめてほしいところ。

参加してみて

そんな感じで初参加してきましたー。
参加する前はもくもく会みたいな感じで各々が Ruby 2.5 について調べるのかと思っていたのですが、実際は全員で機能を眺めて行くような感じでした。

会自体そこまで重い雰囲気ではなかったので割りと好き勝手意見を言うことができたり、他の人の意見なんかも聞くことができたのでとてもよかったです。
基本的にぼっちなのでこういうみんなで Ruby に対する意見を言い合うような機会は殆ど無いのでとても新鮮でした。
思っていることは割りとみんな同じなんだなーという風に共感できたのもよかったですね。

あと参加者の殆どは Ruby ユーザ(Ruby 本体の開発者ではない)なのでそういう目線で自由に意見を言っているのもいいなーと思いました。
結果的に Ruby 2.5 で追加される機能がなんとなく理解できたので参加してよかったです。
運営の方がありがとうございました。

【一人 vimrc advent calendar 2017】autocmd FileType 時に設定を追加する場合の注意点【20日目】

一人 vimrc advent calendar 2017 20日目の記事になります。
前回filetype の設定に関する記事を書いたのですが、今回はそれに関係するお話。

autocmd FileType 等で設定するときの注意点

autocmd FileType などで『任意の filetype に対して』設定を行う際は基本的には『そのバッファでのみ』反映される設定を行います。
ですので、オプションやキーマップなどはすべてバッファローカルにして設定する必要があります。

オプションの設定

オプションを設定する場合は :set ではなくて :setlocal を使用します。

" なんかいろいろ設定
setlocal cindent
setlocal cinoptions+=:0
setlocal matchpairs+=<:>

ただし、オプションによってはバッファローカルではなくてグローバルでしか設定できないオプションがあるので注意してください。

キーマッピング

キーマッピングは引数に <buffer> を追加することでバッファローカルとして設定することができます。

" 最後に定義された include 箇所へ移動してを挿入モードへ
nnoremap <buffer> <Space>ii :execute "?".&include<CR> :noh<CR> o

Ex コマンド

Ex コマンドの場合は -buffer を追加します。

command! -buffer Hoge echo "hoge"

autocmd

autocmd の場合はちょっと手間で、augroup を利用します。

" filetype 用の augroup を用意する
augroup my-vimfiler
   " その augroup の <buffer> を削除する
    autocmd! * <buffer>

   " autocmd は <buffer> を追加して定義する
   " こうすることでバッファローカルの autocmd になる
    autocmd CursorHold <buffer> execute "normal \<Plug>(vimfiler_print_filename)"
"     autocmd CursorMoved <buffer> execute "normal \<Plug>(vimfiler_print_filename)"
augroup END

このようにグローバルの autocmd と同様に autocmd が2回設定されることを防ぐために augroup を利用する必要があります。

まとめ

  • オプションなどを設定する場合は何に対して設定するのか注意しよう


ちなみに1つのバッファで複数の filetype を切り替えて使う場合の注意点もあるんですが、気力が尽きたので機会があれば別に書きます…。

【一人 Ruby Advent Calendar 2017】Shinjuku.rb #56 2017年開発厄落としLT大会でLTしてきた【20日目】

一人 Ruby Advent Calendar 2017 20日目の記事になります。
Shinjuku.rb で LT してきました。
今回も遅れてしまい申し訳なく。

case-when と === と gem

https://osyo-manga.github.io/slide-shinjukurb-56-case-when/#/

学生LTでも同じような事を話したのですが今回はもうちょっとマニアックな話をしてきました。
まあ何が言いたかっていうと Method#=== が入ったって言いたかっただけですね…。
と、いうかお酒を飲んだ勢いでライブコーディングしましたがぐだってしまって申し訳ねえ…。

ちなみに『なぜそんなに case-when ?』みたいな質問があったんですが、元々別の用途で === を使いたくていろいろと調べていたら『あれ、case-when もよくね?』と思った所存です。
実際、JavaScript のように厳密演算子みたいな用途ではなくて case-when 専用として #=== が定義されているので拡張性はとても高いと思います。
Ruby 2.5 で Set#=== も追加されたのでどんどん #=== 使っていきたい。

所感

今回はほぼ忘年会みたいな感じでお酒を呑みながらビザを食べて人をダメにするソファーに座りながら LT を聞くという素晴らしい会でした。
他の地域.rb と同様にとても話しやすい雰囲気でしたね。
お酒飲んでるとみんないい感じにいいたい放題言っていたのがとてもよかったです。
表題は今年の振り返りということでしたがわたしも割りと好き勝手話してきました。
また機会があれば、参加してみたいと思います。
運営の方々ありがとうございましたー。