pockestrap

Programmer's memo

Vimでカーソル位置のRubyVM::AST::Nodeを表示する

次のコードをprint-focused-ast.rbとして適当なところに置く

#!ruby

# Usage: print-focused-ast.rb --line 3 --column 5 path
# line is 1 origin
# column is 0 origin

require 'optparse'

OPTION = {}

def line
  OPTION[:line].to_i
end

def column
  OPTION[:column].to_i
end

def has_target?(node)
  return false unless node.first_lineno <= line && line <= node.last_lineno

  if node.first_lineno == node.last_lineno
    return node.first_column <= column && column <= node.last_column
  elsif node.first_lineno == line
    return node.first_column <= column
  elsif node.last_lineno == line
    return column <= node.last_column
  else
    return true
  end
end


def find_target_node(node)
  return nil unless has_target?(node)

  node.children.each do |child|
    next unless child.is_a?(RubyVM::AbstractSyntaxTree::Node)
    ret = find_target_node(child)
    return ret if ret
  end

  node
end


opt = OptionParser.new
opt.on('--line LINE')
opt.on('--column COLUMN')
opt.parse!(ARGV, into: OPTION)

raise "Specify --line and --column" if line.nil? || column.nil?


node = RubyVM::AbstractSyntaxTree.parse(ARGF.read)

pp find_target_node(node)

.vimrcに次を追加する

let g:quickrun_config = {
\   'rubyvm_ast': {
\     'type': 'rubyvm_ast',
\     'command': '/path/to/print-focused-ast.rb',
\     'exec':  "ruby %C %s --line %{line('.')} --column %{col('.') - 1}",
\     'hook/shebang/enable': 0,
\   }
\ }

あとは:QuickRun rubyvm_astを実行するだけ。

私はnnoremap <silent><Leader>a :QuickRun rubyvm_ast<CR>している。

CursorMovedとかを使って常に更新するようにしても面白そうですね。

コマンドに行番号と列番号を指定して実行できれば良いので、VimmerじゃなかったりQuickRunユーザーじゃなかったりしても、適当なツールを使えばいい感じにできると思います。