"=============================================================================
" File : autoload/unite/sources/outline/defaults/ruby.vim
" Author : h1mesuke <himesuke@gmail.com>
" Updated : 2012-01-11
"
" Licensed under the MIT license:
" http://www.opensource.org/licenses/mit-license.php
"
"=============================================================================
" Default outline info for Ruby
" Version: 0.1.5
function! unite#sources#outline#defaults#ruby#outline_info(...) abort
if a:0
" Redirect to DSL's outline info.
let context = a:1
let path = context.buffer.path
if path =~ '_spec\.rb$'
" RSpec
return 'ruby/rspec'
endif
endif
return s:outline_info
endfunction
let s:Util = unite#sources#outline#import('Util')
"-----------------------------------------------------------------------------
" Outline Info
let s:outline_info = {
\ 'heading-1': s:Util.shared_pattern('sh', 'heading-1'),
\ 'heading_keywords': [
\ 'module', 'class', 'protected', 'private',
\ 'def', '[mc]\=attr_\(accessor\|reader\|writer\)', 'alias',
\ 'BEGIN', 'END', '__END__',
\ ],
\
\ 'skip': {
\ 'header': s:Util.shared_pattern('sh', 'header'),
\ 'block' : ['^=begin', '^=end'],
\ },
\
\ 'heading_groups': {
\ 'type' : ['module', 'class'],
\ 'method': ['method'],
\ },
\
\ 'not_match_patterns': [
\ s:Util.shared_pattern('*', 'parameter_list'),
\ ],
\
\ 'highlight_rules': [
\ { 'name' : 'comment',
\ 'pattern' : '/#.*/' },
\ { 'name' : 'method',
\ 'pattern' : '/:\@<! \zs\%(=>\)\@![_[:alnum:]=\[\]<>!?.]\+/' },
\ { 'name' : 'type',
\ 'pattern' : '/\S\+\ze : \%(module\|class\)/' },
\ { 'name' : 'eigen_class',
\ 'pattern' : '/\<class\s\+<<\s\+.*/',
\ 'highlight': unite#sources#outline#get_highlight('special') },
\ { 'name' : 'access',
\ 'pattern' : '/\<\%(protected\|private\)\>/',
\ 'highlight': unite#sources#outline#get_highlight('special') },
\ { 'name' : 'meta_method',
\ 'pattern' : '/\<def\s\+[^(]*/',
\ 'highlight': unite#sources#outline#get_highlight('special') },
\ { 'name' : 'parameter_list',
\ 'pattern' : '/(.*)/' },
\ ],
\}
function! s:outline_info.initialize() abort
let self.heading = '^\s*\(' . join(self.heading_keywords, '\|') . '\)\>'
endfunction
function! s:outline_info.create_heading(which, heading_line, matched_line, context) abort
let word = a:heading_line
let type = 'generic'
let level = 0
if a:which == 'heading-1' && a:heading_line =~ '^\s*#'
let m_lnum = a:context.matched_lnum
let type = 'comment'
let level = s:Util.get_comment_heading_level(a:context, m_lnum)
elseif a:which == 'heading'
let h_lnum = a:context.heading_lnum
let level = s:Util.get_indent_level(a:context, h_lnum) + 3
" NOTE: Level 1 to 3 are reserved for toplevel comment headings.
let matches = matchlist(a:heading_line, self.heading)
let keyword = matches[1]
let type = keyword
if keyword == 'module' || keyword == 'class'
if word =~ '\s\+<<\s\+'
" Eigen-class
else
" Module, Class
let word = substitute(matchstr(word, '^\s*\%(module\|class\)\s\+\zs\h\%(\w\|\s*::\s*\)*'),'\s*','','g') . ' : ' . keyword
endif
elseif keyword == 'protected' || keyword == 'private'
" Accessibility
let indented = 0
for idx in range(1, 5)
let line = get(a:context.lines, h_lnum + idx, '')
if line =~ '\S'
let indented = level < s:Util.get_indent_level(a:context, h_lnum + idx) + 3
break
endif
endfor
if !indented
let level = 0
endif
elseif keyword == 'def'
if word =~ '#{'
" Meta-method
else
" Method
let type = 'method'
let word = substitute(word, '\<def\s*', '', '')
endif
let word = substitute(word, '\S\zs(', ' (', '')
elseif keyword =~ '^[mc]\=attr_'
" Accessor
let type = 'method'
let access = matches[2]
let word = substitute(word, '\<[mc]\=attr_\w\+\s*', '', '')
let word = substitute(word, ',\s*\S\+\s*=>.*', '', '')
let word = substitute(word, '\s*:', ' ', 'g') . ' : ' . access
elseif keyword == 'alias'
" Alias
let type = 'method'
let word = substitute(word, '\<alias\s*', '', '')
let word = substitute(word, ':\=\(\S\+\)\s\+:\=\(\S\+\)', '\1 => \2', '')
elseif keyword =~ '^\%(BEGIN\|END\)$'
" BEGIN, END
let word = substitute(word, '\s*{.*$', '', '')
else
" __END__
endif
let word = substitute(word, '\%(;\|#{\@!\).*$', '', '')
endif
if level > 0
let heading = {
\ 'word' : word,
\ 'level': level,
\ 'type' : type,
\ }
else
let heading = {}
endif
return heading
endfunction
function! s:outline_info.fold_ruby_block(context, lnum) abort
let line = a:context.lines[a:lnum]
let indent = matchlist(line, '^\(\s*\)')[1]
let line = s:Util.join_to(a:context, a:lnum, indent . '%\(end\>\|}\)')
let line = substitute(line, '\s*\n\s*', '; ', 'g')
let line = substitute(substitute(line, 'do;', '{', ''), '; end', ' }', '')
return line
endfunction
function! s:outline_info.need_blank_between(cand1, cand2, memo) abort
if a:cand1.source__heading_group == 'method' && a:cand2.source__heading_group == 'method'
" Don't insert a blank between two sibling methods.
return 0
else
return (a:cand1.source__heading_group != a:cand2.source__heading_group ||
\ a:cand1.source__has_marked_child || a:cand2.source__has_marked_child)
endif
endfunction