commit 6a28e40ea97f7e3c9ed8c5742d2d41ca895bb5d2 Author: manga_osyo Date: Thu Jul 31 12:23:32 2014 +0900 first commit. diff --git a/README.md b/README.md new file mode 100644 index 0000000..80435ba --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +#brightest.vim + +カーソル下の単語を移動するたびにハイライトする。 + +## Screencapture + +![brightest](https://cloud.githubusercontent.com/assets/214488/3297888/eb37a8dc-f5f9-11e3-8620-5876f030d762.gif) + +## Using + +```vim +" ハイライトを有効にします(既定値) +BrightestEnable + +" ハイライトを無効にします +BrightestDisable + +" ハイライトするグループ名を設定します +let g:brightest_highlight = { +\ "group" : "Search" +\} + +" ハイライトする単語のパターンを設定します +" デフォルト(空の文字列の場合)は が使用されます +let g:brightest_pattern = '\k\+' + + +" filetype=cpp を無効にする +let g:brightest#enable_filetypes = { +\ "cpp" : 0 +\} + +" filetype=vim のみを有効にする +let g:brightest#enable_filetypes = { +\ "_" : 0 +\ "vim" : 1 +\} +``` + + diff --git a/autoload/brightest.vim b/autoload/brightest.vim new file mode 100644 index 0000000..4d13eb5 --- /dev/null +++ b/autoload/brightest.vim @@ -0,0 +1,96 @@ +scriptencoding utf-8 +let s:save_cpo = &cpo +set cpo&vim + +let s:V = vital#of("brightest") +let s:Prelude = s:V.import("Prelude") +let s:Buffer = s:V.import("Coaster.Buffer") +let s:Highlight = s:V.import("Coaster.Highlight") +let s:Search = s:V.import("Coaster.Search") + + +let g:brightest#enable_filetypes = get(g:, "brightest#enable_filetypes", {}) +" let g:brightest#highlight_format = get(g:, "brightest#highlight_format", "\\<%s\\>") + + +function! s:is_enable_in_current() + let default = get(g:brightest#enable_filetypes, "_", 1) + return g:brightest_enable && get(g:brightest#enable_filetypes, &filetype, default) +endfunction + + +function! brightest#hl_clear() + call s:Highlight.clear("cursor_word") + call s:Highlight.clear("cursor_line") + call s:Highlight.clear("current_word") +endfunction + + +function! s:highlight(name, pattern, hi) + if empty(a:hi) || empty(a:pattern) || a:hi.group == "" + return + endif + let pattern = printf(a:hi.format, a:pattern) + call s:Highlight.highlight(a:name, a:hi.group, pattern, a:hi.priority) +endfunction + + +function! s:single_word(pattern, highlight, cursorline) + let pattern = a:pattern + if pattern ==# "" + let word = expand("") + else + let word = s:Buffer.get_text_from_pattern(pattern) + endif + + " マルチバイト文字はハイライトしない + if word == "" +\ || !empty(filter(split(word, '\zs'), "strlen(v:val) > 1")) + return + endif + + let pattern = s:Prelude.escape_pattern(word) + call s:highlight("cursor_word", pattern, a:highlight) + call s:highlight("cursor_line", '\%' . line('.') . 'l' . pattern, a:cursorline) +endfunction + + +" function! s:with_current(current_group, group, pattern) +" let [first, last] = s:Search.region(a:pattern, "Wncb", "Wnce") +" if first == [0, 0] || last == [0, 0] +" return +" endif +" let word = s:Buffer.get_text_from_region([0] + first + [0], [0] + last + [0], "v") +" if word !~ '^' . a:pattern . '$' +" return +" endif +" let current = s:Search.pattern_by_range("v", first, last) +" +" " マルチバイト文字はハイライトしない +" if !empty(filter(split(word, '\zs'), "strlen(v:val) > 1")) +" return +" endif +" +" let pattern = printf(g:brightest#highlight_format, s:Prelude.escape_pattern(word)) +" +" call s:Highlight.highlight("cursor_word", a:group, pattern, -1) +" call s:Highlight.highlight("current_word", a:current_group, current, -1) +" endfunction + + +function! brightest#highlight(pattern, highlight, cursorline, ...) + call brightest#hl_clear() + if !s:is_enable_in_current() + return + endif + + if get(a:, 1, "") == "" + return s:single_word(a:pattern, a:highlight, a:cursorline) + else + return s:with_current(a:1, a:group, a:pattern) + endif +endfunction + + +let &cpo = s:save_cpo +unlet s:save_cpo diff --git a/autoload/vital.vim b/autoload/vital.vim new file mode 100644 index 0000000..bc0b525 --- /dev/null +++ b/autoload/vital.vim @@ -0,0 +1,12 @@ +function! vital#of(name) + let files = globpath(&runtimepath, 'autoload/vital/' . a:name . '.vital') + let file = split(files, "\n") + if empty(file) + throw 'vital: version file not found: ' . a:name + endif + let ver = readfile(file[0], 'b') + if empty(ver) + throw 'vital: invalid version file: ' . a:name + endif + return vital#_{substitute(ver[0], '\W', '', 'g')}#new() +endfunction diff --git a/autoload/vital/_brightest.vim b/autoload/vital/_brightest.vim new file mode 100644 index 0000000..d65da5e --- /dev/null +++ b/autoload/vital/_brightest.vim @@ -0,0 +1,304 @@ +let s:self_version = expand(':t:r') + +" Note: The extra argument to globpath() was added in Patch 7.2.051. +let s:globpath_third_arg = v:version > 702 || v:version == 702 && has('patch51') + +let s:loaded = {} + +function! s:import(name, ...) + let target = {} + let functions = [] + for a in a:000 + if type(a) == type({}) + let target = a + elseif type(a) == type([]) + let functions = a + endif + unlet a + endfor + let module = s:_import(a:name) + if empty(functions) + call extend(target, module, 'keep') + else + for f in functions + if has_key(module, f) && !has_key(target, f) + let target[f] = module[f] + endif + endfor + endif + return target +endfunction + +function! s:load(...) dict + for arg in a:000 + let [name; as] = type(arg) == type([]) ? arg[: 1] : [arg, arg] + let target = split(join(as, ''), '\W\+') + let dict = self + while 1 <= len(target) + let ns = remove(target, 0) + if !has_key(dict, ns) + let dict[ns] = {} + endif + if type(dict[ns]) == type({}) + let dict = dict[ns] + else + unlet dict + break + endif + endwhile + + if exists('dict') + call extend(dict, s:_import(name)) + endif + unlet arg + endfor + return self +endfunction + +function! s:unload() + let s:loaded = {} +endfunction + +function! s:exists(name) + return s:_get_module_path(a:name) !=# '' +endfunction + +function! s:search(pattern) + let paths = s:_vital_files(a:pattern) + let modules = sort(map(paths, 's:_file2module(v:val)')) + return s:_uniq(modules) +endfunction + +function! s:expand_modules(entry, all) + if type(a:entry) == type([]) + let candidates = s:_concat(map(copy(a:entry), 's:search(v:val)')) + if empty(candidates) + throw printf('vital: Any of module %s is not found', string(a:entry)) + endif + if eval(join(map(copy(candidates), 'has_key(a:all, v:val)'), '+')) + let modules = [] + else + let modules = [candidates[0]] + endif + else + let modules = s:search(a:entry) + if empty(modules) + throw printf('vital: Module %s is not found', a:entry) + endif + endif + call filter(modules, '!has_key(a:all, v:val)') + for module in modules + let a:all[module] = 1 + endfor + return modules +endfunction + +function! s:_import(name) + if type(a:name) == type(0) + return s:_build_module(a:name) + endif + let path = s:_get_module_path(a:name) + if path ==# '' + throw 'vital: module not found: ' . a:name + endif + let sid = s:_get_sid_by_script(path) + if !sid + try + execute 'source' fnameescape(path) + catch /^Vim\%((\a\+)\)\?:E484/ + throw 'vital: module not found: ' . a:name + catch /^Vim\%((\a\+)\)\?:E127/ + " Ignore. + endtry + + let sid = s:_get_sid_by_script(path) + endif + return s:_build_module(sid) +endfunction + +function! s:_get_module_path(name) + if s:_is_absolute_path(a:name) && filereadable(a:name) + return a:name + endif + if a:name ==# '' + let paths = [s:self_file] + elseif a:name =~# '\v^\u\w*%(\.\u\w*)*$' + let paths = s:_vital_files(a:name) + else + throw 'vital: Invalid module name: ' . a:name + endif + + call filter(paths, 'filereadable(expand(v:val))') + let path = get(paths, 0, '') + return path !=# '' ? path : '' +endfunction + +function! s:_get_sid_by_script(path) + let path = s:_unify_path(a:path) + for line in filter(split(s:_redir('scriptnames'), "\n"), + \ 'stridx(v:val, s:self_version) > 0') + let list = matchlist(line, '^\s*\(\d\+\):\s\+\(.\+\)\s*$') + if !empty(list) && s:_unify_path(list[2]) ==# path + return list[1] - 0 + endif + endfor + return 0 +endfunction + +function! s:_file2module(file) + let filename = fnamemodify(a:file, ':p:gs?[\\/]\+?/?') + let tail = matchstr(filename, 'autoload/vital/_\w\+/\zs.*\ze\.vim$') + return join(split(tail, '[\\/]\+'), '.') +endfunction + +if filereadable(expand(':r') . '.VIM') + " resolve() is slow, so we cache results. + let s:_unify_path_cache = {} + " Note: On windows, vim can't expand path names from 8.3 formats. + " So if getting full path via and $HOME was set as 8.3 format, + " vital load duplicated scripts. Below's :~ avoid this issue. + function! s:_unify_path(path) + if has_key(s:_unify_path_cache, a:path) + return s:_unify_path_cache[a:path] + endif + let value = tolower(fnamemodify(resolve(fnamemodify( + \ a:path, ':p')), ':~:gs?[\\/]\+?/?')) + let s:_unify_path_cache[a:path] = value + return value + endfunction +else + function! s:_unify_path(path) + return resolve(fnamemodify(a:path, ':p:gs?[\\/]\+?/?')) + endfunction +endif + +if s:globpath_third_arg + function! s:_runtime_files(path) + return split(globpath(&runtimepath, a:path, 1), "\n") + endfunction +else + function! s:_runtime_files(path) + return split(globpath(&runtimepath, a:path), "\n") + endfunction +endif + +let s:_vital_files_cache_runtimepath = '' +let s:_vital_files_cache = [] +function! s:_vital_files(pattern) + if s:_vital_files_cache_runtimepath !=# &runtimepath + let path = printf('autoload/vital/%s/**/*.vim', s:self_version) + let s:_vital_files_cache = s:_runtime_files(path) + let mod = ':p:gs?[\\/]\+?/?' + call map(s:_vital_files_cache, 'fnamemodify(v:val, mod)') + let s:_vital_files_cache_runtimepath = &runtimepath + endif + let target = substitute(a:pattern, '\.', '/', 'g') + let target = substitute(target, '\*', '[^/]*', 'g') + let regexp = printf('autoload/vital/%s/%s.vim', s:self_version, target) + return filter(copy(s:_vital_files_cache), 'v:val =~# regexp') +endfunction + +" Copy from System.Filepath +if has('win16') || has('win32') || has('win64') + function! s:_is_absolute_path(path) + return a:path =~? '^[a-z]:[/\\]' + endfunction +else + function! s:_is_absolute_path(path) + return a:path[0] ==# '/' + endfunction +endif + +function! s:_build_module(sid) + if has_key(s:loaded, a:sid) + return copy(s:loaded[a:sid]) + endif + let functions = s:_get_functions(a:sid) + + let prefix = '' . a:sid . '_' + let module = {} + for func in functions + let module[func] = function(prefix . func) + endfor + if has_key(module, '_vital_loaded') + let V = vital#{s:self_version}#new() + if has_key(module, '_vital_depends') + let all = {} + let modules = + \ s:_concat(map(module._vital_depends(), + \ 's:expand_modules(v:val, all)')) + call call(V.load, modules, V) + endif + try + call module._vital_loaded(V) + catch + " FIXME: Show an error message for debug. + endtry + endif + if !get(g:, 'vital_debug', 0) + call filter(module, 'v:key =~# "^\\a"') + endif + let s:loaded[a:sid] = module + return copy(module) +endfunction + +if exists('+regexpengine') + function! s:_get_functions(sid) + let funcs = s:_redir(printf("function /\\%%#=2^\%d_", a:sid)) + let map_pat = '' . a:sid . '_\zs\w\+' + return map(split(funcs, "\n"), 'matchstr(v:val, map_pat)') + endfunction +else + function! s:_get_functions(sid) + let prefix = '' . a:sid . '_' + let funcs = s:_redir('function') + let filter_pat = '^\s*function ' . prefix + let map_pat = prefix . '\zs\w\+' + return map(filter(split(funcs, "\n"), + \ 'stridx(v:val, prefix) > 0 && v:val =~# filter_pat'), + \ 'matchstr(v:val, map_pat)') + endfunction +endif + +if exists('*uniq') + function! s:_uniq(list) + return uniq(a:list) + endfunction +else + function! s:_uniq(list) + let i = len(a:list) - 1 + while 0 < i + if a:list[i] ==# a:list[i - 1] + call remove(a:list, i) + let i -= 2 + else + let i -= 1 + endif + endwhile + return a:list + endfunction +endif + +function! s:_concat(lists) + let result_list = [] + for list in a:lists + let result_list += list + endfor + return result_list +endfunction + +function! s:_redir(cmd) + let [save_verbose, save_verbosefile] = [&verbose, &verbosefile] + set verbose=0 verbosefile= + redir => res + silent! execute a:cmd + redir END + let [&verbose, &verbosefile] = [save_verbose, save_verbosefile] + return res +endfunction + +function! vital#{s:self_version}#new() + return s:_import('') +endfunction + +let s:self_file = s:_unify_path(expand('')) diff --git a/autoload/vital/_brightest/Coaster.vim b/autoload/vital/_brightest/Coaster.vim new file mode 100644 index 0000000..d58ef1c --- /dev/null +++ b/autoload/vital/_brightest/Coaster.vim @@ -0,0 +1,9 @@ +scriptencoding utf-8 +let s:save_cpo = &cpo +set cpo&vim + + + + +let &cpo = s:save_cpo +unlet s:save_cpo diff --git a/autoload/vital/_brightest/Coaster/Buffer.vim b/autoload/vital/_brightest/Coaster/Buffer.vim new file mode 100644 index 0000000..a2e0795 --- /dev/null +++ b/autoload/vital/_brightest/Coaster/Buffer.vim @@ -0,0 +1,264 @@ +scriptencoding utf-8 +let s:save_cpo = &cpo +set cpo&vim + +function! s:_vital_loaded(V) + let s:V = a:V + let s:Search = a:V.import("Coaster.Search") +endfunction + + +function! s:_vital_depends() + return [ +\ "Coaster.Search" +\ ] +endfunction + + +" a <= b +function! s:pos_less_equal(a, b) + return a:a[0] == a:b[0] ? a:a[1] <= a:b[1] : a:a[0] <= a:b[0] +endfunction + + +function! s:as_wise_key(name) + return a:name ==# "char" ? "v" +\ : a:name ==# "line" ? "V" +\ : a:name ==# "block" ? "\" +\ : a:name +endfunction + + +function! s:get_text_from_latest_yank(...) + if mode() != "n" + return + endif + + let wise = get(a:, 1, "v") + let register = v:register == "" ? '"' : v:register + + let old_selection = &selection + let &selection = 'inclusive' + let old_pos = getpos(".") + let old_reg = getreg(register) + try + execute printf('silent normal! `[%s`]y', wise) + return getreg(register) + finally + let &selection = old_selection + call setreg(register, old_reg) + call cursor(old_pos[1], old_pos[2]) + endtry +endfunction + + +function! s:get_line_from_pos(pos) + return a:pos[0] == 0 ? getline(a:pos[1]) : getbufline(a:pos[0], a:pos[1]) +endfunction + + +function! s:get_line_from_region(first, last) + if type(a:first) == type(0) + return s:get_line_from_region([0, a:first, 0, 0], a:last) + elseif type(a:last) == type(0) + return s:get_line_from_region(a:first, [0, a:last, 0, 0]) + endif + if a:first[0] != 0 && a:first[0] == a:last[0] + return join(getbufline(a:first[0], a:first[1], a:last[1]), "\n") + endif + return join(getline(a:first[1], a:last[1]), "\n") +endfunction + + +function! s:yank(wise, first, last) + let old_view = winsaveview() + let old_selection = &selection + let &selection = 'inclusive' + let old_first = getpos("'[") + let old_last = getpos("']") + let old_pos = getpos(".") + try + call setpos("'[", a:first) + call setpos("']", a:last) + execute "normal! `[" . a:wise . "`]y" + finally + call setpos("'[", old_first) + call setpos("']", old_last) + let &selection = old_selection + call winrestview(old_view) + call setpos(".", old_pos) + endtry +endfunction + + +function! s:paste(wise, first, last, register) + let old_view = winsaveview() + let old_selection = &selection + let &selection = 'inclusive' + let old_first = getpos("'[") + let old_last = getpos("']") + let old_pos = getpos(".") + try + call setpos("'[", a:first) + call setpos("']", a:last) + execute printf('normal! `[%s`]"%sp', a:wise, a:register) + finally + call setpos("'[", old_first) + call setpos("']", old_last) + let &selection = old_selection + call winrestview(old_view) + call setpos(".", old_pos) + endtry +endfunction + + +function! s:get_text_line_from_lnum(first, last) + return join(getline(a:first, a:last), "\n") +endfunction +" +" +" function! s:get_text_line_from_region(first, last) +" " if type(a:first) == type([]) +" " return s:get_text_line_from_region(a:first[1], a:last) +" " elseif type(a:last) == type([]) +" " return s:get_text_line_from_region(a:first, a:last[1]) +" " endif +" " return join(getline(a:first, a:last), "\n") +" +" return s:get_text_line_from_lnum(a:first[1], a:last[1]) +" endfunction + + +function! s:get_char_from_region(first, last) + if a:first[1] == a:last[1] + return getline(a:first[1])[a:first[2] - 1 : a:last[2] - 1] + elseif (a:last[1] - a:first[1]) == 1 + return getline(a:first[1])[ a:first[2] - 1 : ] . "\n" +\ . getline(a:last[1])[ : a:last[2] - 1] + else + return getline(a:first[1])[ a:first[2] - 1 : ] . "\n" +\ . s:get_text_line_from_lnum(a:first[1] + 1, a:last[1] - 1) . "\n" +\ . getline(a:last[1])[ : a:last[2] - 1] + endif +endfunction + + +function! s:get_block_from_region(first, last) + let first = a:first + let last = a:last + echo join(map(range(a:first[1], a:last[1]), " +\ s:get_char_from_region([first[0], v:val, first[2], first[3]], [last[0], v:val, last[2], last[3]]) +\ "), "\n") +endfunction + + +function! s:get_text_from_region(first, last, ...) + let wise = get(a:, 1, "v") + if wise ==# "v" + return s:get_char_from_region(a:first, a:last) + elseif wise ==# "V" + return s:get_line_from_region(a:first, a:last) + elseif wise ==# "\" + return s:get_block_from_region(a:first, a:last) + endif +" let old_first = getpos("'[") +" let old_last = getpos("']") +" try +" call setpos("'[", a:first) +" call setpos("']", a:last) +" return s:get_text_from_latest_yank(wise) +" finally +" call setpos("'[", old_first) +" call setpos("']", old_last) +" endtry +endfunction + + +function! s:get_text_from_pattern(pattern) + let [first, last] = s:Search.region(a:pattern, "Wncb", "Wnce") + if first == [0, 0] + return "" + endif + if last == [0, 0] + return "" + endif + let result = s:get_text_from_region([0] + first + [0], [0] + last + [0], "v") + if result !~ '^' . a:pattern . '$' + return "" + endif + return result +endfunction + + +function! s:_as_config(config) + let default = { +\ "textobj" : "", +\ "is_cursor_in" : 0, +\ "noremap" : 0, +\ } + let config +\ = type(a:config) == type("") ? { "textobj" : a:config } +\ : type(a:config) == type({}) ? a:config +\ : {} + return extend(default, config) +endfunction + + +let s:region = [] +let s:wise = "" +function! s:_buffer_region_operator(wise) + let reg_save = @@ + let s:wise = a:wise + let s:region = [getpos("'[")[1:], getpos("']")[1:]] + let @@ = reg_save +endfunction + +nnoremap (vital-coaster_buffer_region) +\ :set operatorfunc=_buffer_region_operatorg@ + + +function! s:get_region_from_textobj(textobj) + let s:region = [] + let config = s:_as_config(a:textobj) + + let winview = winsaveview() + let pos = getpos(".") + try + silent execute (config.noremap ? 'onoremap' : 'omap') '' +\ '(vital-coaster_buffer_region-target)' string(config.textobj) + + let tmp = &operatorfunc + silent execute "normal \(vital-coaster_buffer_region)\(vital-coaster_buffer_region-target)" + let &operatorfunc = tmp + + if !empty(s:region) && !s:pos_less_equal(s:region[0], s:region[1]) + return ["", []] + endif + if !empty(s:region) && config.is_cursor_in && (s:pos_less(pos[1:], s:region[0]) || s:pos_less(s:region[1], pos[1:])) + return ["", []] + endif + return deepcopy([s:wise, s:region]) + finally + call winrestview(winview) + call cursor(pos[1], pos[2]) + endtry +endfunction + + +function! s:execute(expr, cmd) + let bufnr = bufnr("%") + try + noautocmd execute "bufdo if bufnr('%') == " a:expr . ' | ' . a:cmd . ' | endif' + finally + execute "buffer" bufnr + endtry +endfunction + + +function! s:setbufline(expr, lnum, text) + return s:execute(a:expr, "call setline(" . a:lnum . "," . string(a:text) . ")") +endfunction + + +let &cpo = s:save_cpo +unlet s:save_cpo diff --git a/autoload/vital/_brightest/Coaster/Highlight.vim b/autoload/vital/_brightest/Coaster/Highlight.vim new file mode 100644 index 0000000..41d6fa3 --- /dev/null +++ b/autoload/vital/_brightest/Coaster/Highlight.vim @@ -0,0 +1,160 @@ +scriptencoding utf-8 +let s:save_cpo = &cpo +set cpo&vim + +let s:base = { +\ "variables" : { +\ "hl_list" : {}, +\ "id_list" : {} +\ } +\} + + +function! s:base.add(name, group, pattern, ...) + call self.delete(a:name) + let priority = get(a:, 1, 10) + let self.variables.hl_list[a:name] = { +\ "group" : a:group, +\ "pattern" : a:pattern, +\ "priority" : priority, +\ } +endfunction + + +function! s:base.is_added(name) + return has_key(self.variables.hl_list, a:name) +endfunction + + +function! s:base.hl_list() + return keys(self.variables.hl_list) +endfunction + + +function! s:base.enable_list(...) + let bufnr = get(a:, 1, bufnr("%")) + return keys(get(self.variables.id_list, bufnr, {})) +endfunction + + +function! s:base.delete(name) + if !self.is_added(a:name) + return -1 + endif + unlet! self.variables.hl_list[a:name] +endfunction + + +function! s:base.delete_by(expr) + for [name, _] in items(self.variables.hl_list) + let group = _.group + let pattern = _.pattern + let priority = _.priority + if eval(a:expr) + call self.delete(name) + endif + endfor +endfunction + + +function! s:base.delete_all() + for name in self.hl_list() + call self.delete(name) + endfor +endfunction + + +function! s:base.get_hl_id(name, ...) + let bufnr = get(a:, 1, bufnr("%")) + return get(get(self.variables.id_list, bufnr, {}), a:name, "") +endfunction + + +function! s:base.is_enabled(name, ...) + let bufnr = get(a:, 1, bufnr("%")) + return self.get_hl_id(a:name, bufnr) != "" +endfunction + + +function! s:base.enable(name) + let hl = get(self.variables.hl_list, a:name, {}) + if empty(hl) + return -1 + endif + if self.is_enabled(a:name) + call self.disable(a:name) + endif + if !has_key(self.variables.id_list, bufnr("%")) + let self.variables.id_list[bufnr("%")] = {} + endif + let self.variables.id_list[bufnr("%")][a:name] = matchadd(hl.group, hl.pattern, hl.priority) +endfunction + + +function! s:base.enable_all() + for name in self.hl_list() + call self.enable(name) + endfor +endfunction + + +function! s:base.disable(name) + if !self.is_enabled(a:name) + return -1 + endif + let id = -1 + silent! let id = matchdelete(self.get_hl_id(a:name)) + if id == -1 + return -1 + endif + let bufnr = bufnr("%") + unlet! self.variables.id_list[bufnr][a:name] +endfunction + + +function! s:base.disable_all() + for name in self.enable_list() + call self.disable(name) + endfor +endfunction + + +function! s:base.highlight(name, group, pattern, ...) + let priority = get(a:, 1, 10) + call self.add(a:name, a:group, a:pattern, priority) + call self.enable(a:name) +endfunction + + +function! s:base.clear(name) + call self.disable(a:name) + call self.delete(a:name) +endfunction + + +function! s:base.clear_all() + call self.disable_all() + call self.delete_all() +endfunction + + +function! s:make() + let result = deepcopy(s:base) + return result +endfunction + + +let s:global = s:make() +let s:funcs = keys(filter(copy(s:global), "type(v:val) == type(function('tr'))")) + +for s:name in s:funcs + execute +\ "function! s:" . s:name . "(...) \n" +\ "return call(s:global." . s:name . ", a:000, s:global) \n" +\ "endfunction" +endfor +unlet s:name + + +let &cpo = s:save_cpo +unlet s:save_cpo diff --git a/autoload/vital/_brightest/Coaster/Search.vim b/autoload/vital/_brightest/Coaster/Search.vim new file mode 100644 index 0000000..875d1ea --- /dev/null +++ b/autoload/vital/_brightest/Coaster/Search.vim @@ -0,0 +1,62 @@ +scriptencoding utf-8 +let s:save_cpo = &cpo +set cpo&vim + + +function! s:_vital_loaded(V) + let s:V = a:V + let s:Buffer = s:V.import("Coaster.Buffer") +endfunction + + +function! s:_vital_depends() + return [ +\ ] +endfunction + + +function! s:region(pattern, ...) + let flag_first = get(a:, 1, "") + let flag_last = get(a:, 2, "") + return [searchpos(a:pattern, flag_first), searchpos(a:pattern, flag_last)] +endfunction + + +function! s:region_pair(fist, last, ...) + " todo +endfunction + + +function! s:pattern_in_range(wise, first, last, pattern) + if a:first == a:last + return printf('\%%%dl\%%%dc', a:first[0], a:first[1]) + elseif a:first[0] == a:last[0] + return printf('\%%%dl\%%>%dc%s\%%<%dc', a:first[0], a:first[1]-1, a:pattern, a:last[1]+1) + elseif a:last[0] - a:first[0] == 1 + return printf('\%%%dl%s\%%>%dc', a:first[0], a:pattern, a:first[1]-1) +\ . "\\|" . printf('\%%%dl%s\%%<%dc', a:last[0], a:pattern, a:last[1]+1) + else + return printf('\%%%dl%s\%%>%dc', a:first[0], a:pattern, a:first[1]-1) +\ . "\\|" . printf('\%%>%dl%s\%%<%dl', a:first[0], a:pattern, a:last[0]) +\ . "\\|" . printf('\%%%dl%s\%%<%dc', a:last[0], a:pattern, a:last[1]+1) + endif +endfunction + + +function! s:pattern_by_range(wise, first, last) + return s:pattern_in_range(a:wise, a:first, a:last, '.\{-}') +endfunction + + +function! s:text_by_pattern(pattern, ...) + let flag = get(a:, 1, "") + let [first, last] = s:region(a:pattern, "c" . flag, "ce" . flag) + if first == [0, 0] || last == [0, 0] + endif + let result = s:Buffer.get_text_from_region([0] + first + [0], [0] + last + [0], "v") + return result +endfunction + + +let &cpo = s:save_cpo +unlet s:save_cpo diff --git a/autoload/vital/_brightest/Prelude.vim b/autoload/vital/_brightest/Prelude.vim new file mode 100644 index 0000000..0738810 --- /dev/null +++ b/autoload/vital/_brightest/Prelude.vim @@ -0,0 +1,385 @@ +let s:save_cpo = &cpo +set cpo&vim + +if v:version ># 703 || +\ (v:version is 703 && has('patch465')) + function! s:glob(expr) + return glob(a:expr, 1, 1) + endfunction +else + function! s:glob(expr) + let R = glob(a:expr, 1) + return split(R, '\n') + endfunction +endif + +function! s:globpath(path, expr) + let R = globpath(a:path, a:expr, 1) + return split(R, '\n') +endfunction + +" Wrapper functions for type(). +let [ +\ s:__TYPE_NUMBER, +\ s:__TYPE_STRING, +\ s:__TYPE_FUNCREF, +\ s:__TYPE_LIST, +\ s:__TYPE_DICT, +\ s:__TYPE_FLOAT] = [ + \ type(3), + \ type(""), + \ type(function('tr')), + \ type([]), + \ type({}), + \ has('float') ? type(str2float('0')) : -1] +" __TYPE_FLOAT = -1 when -float +" This doesn't match to anything. + +" Number or Float +function! s:is_numeric(Value) + let _ = type(a:Value) + return _ ==# s:__TYPE_NUMBER + \ || _ ==# s:__TYPE_FLOAT +endfunction + +" Number +function! s:is_number(Value) + return type(a:Value) ==# s:__TYPE_NUMBER +endfunction + +" Float +function! s:is_float(Value) + return type(a:Value) ==# s:__TYPE_FLOAT +endfunction +" String +function! s:is_string(Value) + return type(a:Value) ==# s:__TYPE_STRING +endfunction +" Funcref +function! s:is_funcref(Value) + return type(a:Value) ==# s:__TYPE_FUNCREF +endfunction +" List +function! s:is_list(Value) + return type(a:Value) ==# s:__TYPE_LIST +endfunction +" Dictionary +function! s:is_dict(Value) + return type(a:Value) ==# s:__TYPE_DICT +endfunction + +function! s:truncate_smart(str, max, footer_width, separator) + echoerr 'Prelude.truncate_smart() is obsolete. Use its truncate_skipping() instead; they are equivalent.' + return s:truncate_skipping(a:str, a:max, a:footer_width, a:separator) +endfunction + +function! s:truncate_skipping(str, max, footer_width, separator) + let width = s:wcswidth(a:str) + if width <= a:max + let ret = a:str + else + let header_width = a:max - s:wcswidth(a:separator) - a:footer_width + let ret = s:strwidthpart(a:str, header_width) . a:separator + \ . s:strwidthpart_reverse(a:str, a:footer_width) + endif + + return s:truncate(ret, a:max) +endfunction + +function! s:truncate(str, width) + " Original function is from mattn. + " http://github.com/mattn/googlereader-vim/tree/master + + if a:str =~# '^[\x00-\x7f]*$' + return len(a:str) < a:width ? + \ printf('%-'.a:width.'s', a:str) : strpart(a:str, 0, a:width) + endif + + let ret = a:str + let width = s:wcswidth(a:str) + if width > a:width + let ret = s:strwidthpart(ret, a:width) + let width = s:wcswidth(ret) + endif + + if width < a:width + let ret .= repeat(' ', a:width - width) + endif + + return ret +endfunction + +function! s:strwidthpart(str, width) + if a:width <= 0 + return '' + endif + let ret = a:str + let width = s:wcswidth(a:str) + while width > a:width + let char = matchstr(ret, '.$') + let ret = ret[: -1 - len(char)] + let width -= s:wcswidth(char) + endwhile + + return ret +endfunction +function! s:strwidthpart_reverse(str, width) + if a:width <= 0 + return '' + endif + let ret = a:str + let width = s:wcswidth(a:str) + while width > a:width + let char = matchstr(ret, '^.') + let ret = ret[len(char) :] + let width -= s:wcswidth(char) + endwhile + + return ret +endfunction + +if v:version >= 703 + " Use builtin function. + function! s:wcswidth(str) + return strwidth(a:str) + endfunction +else + function! s:wcswidth(str) + if a:str =~# '^[\x00-\x7f]*$' + return strlen(a:str) + end + + let mx_first = '^\(.\)' + let str = a:str + let width = 0 + while 1 + let ucs = char2nr(substitute(str, mx_first, '\1', '')) + if ucs == 0 + break + endif + let width += s:_wcwidth(ucs) + let str = substitute(str, mx_first, '', '') + endwhile + return width + endfunction + + " UTF-8 only. + function! s:_wcwidth(ucs) + let ucs = a:ucs + if (ucs >= 0x1100 + \ && (ucs <= 0x115f + \ || ucs == 0x2329 + \ || ucs == 0x232a + \ || (ucs >= 0x2e80 && ucs <= 0xa4cf + \ && ucs != 0x303f) + \ || (ucs >= 0xac00 && ucs <= 0xd7a3) + \ || (ucs >= 0xf900 && ucs <= 0xfaff) + \ || (ucs >= 0xfe30 && ucs <= 0xfe6f) + \ || (ucs >= 0xff00 && ucs <= 0xff60) + \ || (ucs >= 0xffe0 && ucs <= 0xffe6) + \ || (ucs >= 0x20000 && ucs <= 0x2fffd) + \ || (ucs >= 0x30000 && ucs <= 0x3fffd) + \ )) + return 2 + endif + return 1 + endfunction +endif + +let s:is_windows = has('win16') || has('win32') || has('win64') || has('win95') +let s:is_cygwin = has('win32unix') +let s:is_mac = !s:is_windows && !s:is_cygwin + \ && (has('mac') || has('macunix') || has('gui_macvim') || + \ (!isdirectory('/proc') && executable('sw_vers'))) +let s:is_unix = has('unix') + +function! s:is_windows() + return s:is_windows +endfunction + +function! s:is_cygwin() + return s:is_cygwin +endfunction + +function! s:is_mac() + return s:is_mac +endfunction + +function! s:is_unix() + return s:is_unix +endfunction + +function! s:_deprecated2(fname) + echomsg printf("Vital.Prelude.%s is deprecated!", + \ a:fname) +endfunction + +function! s:smart_execute_command(action, word) + execute a:action . ' ' . (a:word == '' ? '' : '`=a:word`') +endfunction + +function! s:escape_file_searching(buffer_name) + return escape(a:buffer_name, '*[]?{}, ') +endfunction + +function! s:escape_pattern(str) + return escape(a:str, '~"\.^$[]*') +endfunction + +function! s:getchar(...) + let c = call('getchar', a:000) + return type(c) == type(0) ? nr2char(c) : c +endfunction + +function! s:getchar_safe(...) + let c = s:input_helper('getchar', a:000) + return type(c) == type("") ? c : nr2char(c) +endfunction + +function! s:input_safe(...) + return s:input_helper('input', a:000) +endfunction + +function! s:input_helper(funcname, args) + let success = 0 + if inputsave() !=# success + throw 'inputsave() failed' + endif + try + return call(a:funcname, a:args) + finally + if inputrestore() !=# success + throw 'inputrestore() failed' + endif + endtry +endfunction + +function! s:set_default(var, val) + if !exists(a:var) || type({a:var}) != type(a:val) + let {a:var} = a:val + endif +endfunction + +function! s:set_dictionary_helper(variable, keys, pattern) + call s:_deprecated2('set_dictionary_helper') + + for key in split(a:keys, '\s*,\s*') + if !has_key(a:variable, key) + let a:variable[key] = a:pattern + endif + endfor +endfunction + +function! s:substitute_path_separator(path) + return s:is_windows ? substitute(a:path, '\\', '/', 'g') : a:path +endfunction + +function! s:path2directory(path) + return s:substitute_path_separator(isdirectory(a:path) ? a:path : fnamemodify(a:path, ':p:h')) +endfunction + +function! s:_path2project_directory_git(path) + let parent = a:path + + while 1 + let path = parent . '/.git' + if isdirectory(path) || filereadable(path) + return parent + endif + let next = fnamemodify(parent, ':h') + if next == parent + return '' + endif + let parent = next + endwhile +endfunction + +function! s:_path2project_directory_svn(path) + let search_directory = a:path + let directory = '' + + let find_directory = s:escape_file_searching(search_directory) + let d = finddir('.svn', find_directory . ';') + if d == '' + return '' + endif + + let directory = fnamemodify(d, ':p:h:h') + + " Search parent directories. + let parent_directory = s:path2directory( + \ fnamemodify(directory, ':h')) + + if parent_directory != '' + let d = finddir('.svn', parent_directory . ';') + if d != '' + let directory = s:_path2project_directory_svn(parent_directory) + endif + endif + return directory +endfunction + +function! s:_path2project_directory_others(vcs, path) + let vcs = a:vcs + let search_directory = a:path + + let find_directory = s:escape_file_searching(search_directory) + let d = finddir(vcs, find_directory . ';') + if d == '' + return '' + endif + return fnamemodify(d, ':p:h:h') +endfunction + +function! s:path2project_directory(path, ...) + let is_allow_empty = get(a:000, 0, 0) + let search_directory = s:path2directory(a:path) + let directory = '' + + " Search VCS directory. + for vcs in ['.git', '.bzr', '.hg', '.svn'] + if vcs ==# '.git' + let directory = s:_path2project_directory_git(search_directory) + elseif vcs ==# '.svn' + let directory = s:_path2project_directory_svn(search_directory) + else + let directory = s:_path2project_directory_others(vcs, search_directory) + endif + if directory != '' + break + endif + endfor + + " Search project file. + if directory == '' + for d in ['build.xml', 'prj.el', '.project', 'pom.xml', 'package.json', + \ 'Makefile', 'configure', 'Rakefile', 'NAnt.build', + \ 'P4CONFIG', 'tags', 'gtags'] + let d = findfile(d, s:escape_file_searching(search_directory) . ';') + if d != '' + let directory = fnamemodify(d, ':p:h') + break + endif + endfor + endif + + if directory == '' + " Search /src/ directory. + let base = s:substitute_path_separator(search_directory) + if base =~# '/src/' + let directory = base[: strridx(base, '/src/') + 3] + endif + endif + + if directory == '' && !is_allow_empty + " Use original path. + let directory = search_directory + endif + + return s:substitute_path_separator(directory) +endfunction + +let &cpo = s:save_cpo +unlet s:save_cpo + +" vim:set et ts=2 sts=2 sw=2 tw=0: diff --git a/autoload/vital/brightest.vital b/autoload/vital/brightest.vital new file mode 100644 index 0000000..71905d0 --- /dev/null +++ b/autoload/vital/brightest.vital @@ -0,0 +1,8 @@ +brightest +439e6d2 + +Coaster +Prelude +Coaster.Buffer +Coaster.Highlight +Coaster.Search diff --git a/doc/brightest.jax b/doc/brightest.jax new file mode 100644 index 0000000..4c81dc4 --- /dev/null +++ b/doc/brightest.jax @@ -0,0 +1,133 @@ +brightest.txt カーソル下の単語を常にハイライトするプラグイン + + +============================================================================== +概要 *brightest-introduction* + +*brightest* はカーソル下の単語をカーソルが移動する度にハイライトするプラグインで +す。 + + +============================================================================== +インターフェース *brightest-interface* +------------------------------------------------------------------------------ +コマンド *brightest-commands* + +:BrightestEnable *:BrightestEnable* + ハイライトを有効にします。 + この状態が既定値になります。 + +:BrightestDisable *:BrightestDisable* + ハイライトを無効にします。 + + +============================================================================== +設定 *brightest-setting* + +------------------------------------------------------------------------------ +変数 *brightest-variables* + +g:brightest#enable_filetypes *g:brightest#enable_filetypes* + 有効にする 'filetype' を設定します。 + 設定されていない 'filetype' は "_" の値を使用します。 + デフォルトではすべての 'filetype' が有効です。 +Example: > + " filetype=cpp を無効にする + let g:brightest#enable_filetypes = { + \ "cpp" : 0 + \} + + " filetype=vim のみを有効にする + let g:brightest#enable_filetypes = { + \ "_" : 0 + \ "vim" : 1 + \} +< + +g:brightest_pattern *g:brightest_pattern* + ハイライトするカーソル位置の単語のパターンを設定します。 + 任意の範囲をハイライトしたい場合はこの変数を変更してください。 + また、空の文字列が設定されている場合は || + の値がハイライトする単語として使用されます。 +Default: > + let brightest_pattern = "" +< +Example: > + " 英数字 + _ の範囲をハイライトする単語として扱う + let brightest_pattern = '\w\+' +< + +b:brightest_pattern *b:brightest_pattern* + |g:brightest_pattern| のバッファローカル版です。 + |g:brightest_pattern| よりも優先して使用されます。 + + +g:brightest_highlight *g:brightest_highlight* + カーソル下の単語をハイライトする |brightest-highlight| の設定です。 + この設定でバッファ内にあるカーソル下の単語をハイライトします。 +Default: > + let g:brightest_highlight = { +\ "group" : "WarningMsg", +\ "priority" : -1, +\ "format" : '\<%s\>', +\ } +< +Example: > + " 単語をアンダーラインでハイライトして、 + " matchadd() の優先順位を 1000 にする + let g:brightest_highlight = { +\ "group" : "BrightestUnderline", +\ "priority" : 1000 +\ } +< + +b:brightest_highlight *b:brightest_highlight* + |g:brightest_highlight| のバッファローカル版です。 + |g:brightest_highlight| よりも優先して使用されます。 + + +g:brightest_highlight_in_corsur *g:brightest_highlight_in_cursor* + |g:brightest_highlight| と同等の設定ですが、カーソル行の単語のみに反映 + されるハイライトの設定です。 + 'cursorline' と併用して使用する場合はこの設定を使用してください。 + +b:brightest_highlight_in_corsur *b:brightest_highlight_in_corsur* + |g:brightest_highlight_in_corsur| のバッファローカル版です。 + |g:brightest_highlight_in_corsur| よりも優先して使用されます。 + + +============================================================================== +ハイライトグループ *brightest-highlight_group* + +BrightestUnderline *BrightestUnderline* + アンダーラインでハイライトします。 + + +============================================================================== +ハイライト *brightest-highlight* + +ハイライトの設定を行う辞書です。 +ハイライトの設定には以下のキーの値が設定できます。 + +- "group" *brightest-highlight-group* + ハイライトグループを設定します。 + 空の文字列が設定されているとハイライトはされません。 + +- "priority" *brightest-highlight-priority* + matchadd()| の {priority} に設定される数値です。 + +- "format" *brightest-highlight-format* + 単語をハイライトする際のフォーマットを設定します。 + +Example: > + " 単語をアンダーラインでハイライトして、 + " matchadd() の優先順位を 1000 にする + let g:brightest_highlight = { +\ "group" : "BrightestUnderline", +\ "priority" : 1000 +\ } +< + + +============================================================================== +vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl diff --git a/plugin/brightest.vim b/plugin/brightest.vim new file mode 100644 index 0000000..89e5dcb --- /dev/null +++ b/plugin/brightest.vim @@ -0,0 +1,68 @@ +scriptencoding utf-8 +if exists('g:loaded_brightest') + finish +endif +let g:loaded_brightest = 1 + +let s:save_cpo = &cpo +set cpo&vim + +let g:brightest_pattern = get(g:, "brightest_pattern", '') +" let g:brightest_pattern = get(g:, "brightest_pattern", '\k\+') +" let g:brightest_highlight_group = get(g:, "brightest_highlight_group", "WarningMsg") +" let g:brightest_highlight_group_in_cursor = get(g:, "brightest_highlight_group_in_cursor", "") +" let g:brightest_highlight_group_in_cursorline = get(g:, "brightest_highlight_group_in_cursorline", "") + +let g:brightest_enable = get(g:, "brightest_enable", 1) + + +let s:highlight_default = { +\ "group" : "WarningMsg", +\ "priority" : -1, +\ "format" : '\<%s\>', +\} +let g:brightest_highlight = get(g:, "brightest_highlight", {}) +function! s:highlight() + return get(b:, "brightest_highlight", extend(s:highlight_default, g:brightest_highlight)) +endfunction + + +let s:highlight_in_cursorline_default = { +\ "group" : "", +\ "priority" : -1, +\ "format" : '\<%s\>', +\} +let g:brightest_highlight_in_cursorline = get(g:, "brightest_highlight_in_cursorline", {}) +function! s:highlight_in_cursorline() + return get(b:, "brightest_highlight_in_cursorline", extend(s:highlight_in_cursorline_default, g:brightest_highlight_in_cursorline)) +endfunction + + +function! s:init_hl() + highlight BrightestDefaultCursorWord gui=underline guifg=NONE + highlight BrightestUnderline term=underline cterm=underline gui=underline +endfunction + +function! s:hl() + call brightest#highlight( +\ get(b:, "brightest_pattern", g:brightest_pattern), +\ s:highlight(), +\ s:highlight_in_cursorline(), +\ ) +endfunction + +command! -bar BrightestEnable let g:brightest_enable = 1 | call s:hl() +command! -bar BrightestDisable let g:brightest_enable = 0 | call brightest#hl_clear() + + +augroup brightest + autocmd! + autocmd CursorMoved * call s:hl() + autocmd BufLeave,WinLeave,InsertEnter * call brightest#hl_clear() + autocmd ColorScheme * call s:init_hl() +augroup END + + + +let &cpo = s:save_cpo +unlet s:save_cpo