本文是 vim使用的verilog补全插件(即插即用)_vim verilog插件-CSDN博客 的后续,请先阅读这篇文章后再查看
这篇文章更新了一些功能同时修复了插件的使用的bug
新增功能
1:支持变量名称补全,如果变量端口超过1提供中括号补全推荐
2: 简单的识别补全场景功能(比如assign 后面只推荐变量名补全,只会推荐模块内的变量名)
3:更正确的按键功能切换场景判断
和之前的文章一样,没什么时间写代码解释
直接上代码吧
用下面的代码代替上一篇中对应的文件内容
补全函数autocomplete.vim
let g:external_word_list = []
let g:external_module_list = []
let g:external_variable_list = []
let g:external_module_IO = {}
function! s:LoadWordsFromFile(filepath)"抓常用词的函数
let g:external_word_list = []
if !filereadable(a:filepath)
echo "文件未找到:" . a:filepath
return
endif
let l:content = readfile(a:filepath)
let l:words = []
for l:line in l:content
let l:words += filter(split(l:line, '[^a-zA-Z0-9$_]+'),'v:val != "" && v:val != " "')
endfor
let g:external_word_list = uniq(sort(l:words))
endfunction
function! LoadMoudlesFromFile()"抓模块的函数和变量
silent! execute '!~/.vim/plugin/verilog_module ' . expand('%') . ' ' . line('.')
silent! redraw!
let g:external_module_list = []
let g:external_module_IO = {}
if !filereadable("./tmp")
return
endif
let l:content = readfile("./tmp")
let l:words = []
for l:line in l:content
if l:line !~ '[()]'
call add(l:words,l:line)
else
let line_tmp = ' ' . line
let l:function_name = matchstr(l:line_tmp,'\v^([^\(]+)',1)
let l:line = substitute(l:line,'\v^[a-zA-Z$_0-9]+','','')
let g:external_module_IO[l:function_name] = l:line
endif
endfor
let g:external_module_list = uniq(sort(l:words))
silent! execute '!rm tmp'
let g:external_variable_list = []
let l:content = readfile("./tmp_variable")
let l:words = []
for l:line in l:content
let l:words += filter(split(l:line, '[^a-zA-Z0-9$_]+'),'v:val != "" && v:val != " "')
endfor
let g:external_variable_list = uniq(sort(l:words))
silent! execute '!rm tmp_variable'
endfunction
function! s:AutoComplete(findstart, base) "把模糊搜索的补全词语放入补全库的函数
let first_word = matchstr(getline('.'),'\w\+') "行首词语,检测这里是否需要实例化模块
if a:findstart == 1 "模式1,用于返回光标所在字符第一个字母位置
let l:start = col('.') - 1
while l:start > 0 && getline('.')[l:start - 1] =~ '\k'
let l:start -= 1
endwhile
return l:start
else
let l:matches = []
let l:base = substitute(a:base, '\s\+', '', 'g')
let letter_count = {}
let letter_count_in = LetterCount(l:base)
if CheckWord(1)
return l:matches
endif
for l:word in g:external_module_list "优先加载模块,模块里除了变量,其他不进行补全
let letter_count = LetterCount(l:word)
if first_word == l:word
let l:matches = []
if IsCursorInParens()
for l:variable in g:external_variable_list
let variable_count = LetterCount(l:variable)
if CheckLetterCount(variable_count,letter_count_in) == 1
call add(l:matches,l:variable)
endif
endfor
return l:matches
endif
call add(l:matches,l:base . g:external_module_IO[l:word])
return l:matches
endif
if CheckLetterCount(letter_count,letter_count_in) == 1
call add(l:matches,l:word)
endif
endfor
if CheckWord(0)
let l:matches = []
endif
for l:variable in g:external_variable_list "加载变量,只包括光标所在模块的变量
let variable_count = LetterCount(l:variable)
if CheckLetterCount(variable_count,letter_count_in) == 1
call add(l:matches,l:variable)
endif
endfor
if CheckWord(0)
return l:matches
endif
for l:word in g:external_word_list "加载补全单词
let letter_count = LetterCount(l:word)
if CheckLetterCount(letter_count,letter_count_in) == 1
call add(l:matches,l:word)
endif
endfor
return l:matches
endif
endfunction
command! -nargs=1 LoadCompletionFile call s:LoadWordsFromFile(<f-args>)
function! TriggerAutoComplete(mode)"加入补全列表,还有判断是否需要调用补全函数(return 0就是不需要)
let is_complete = 0
let words = ""
let l:matches = []
if expand('%:e') != 'v'
return 0
"elseif getline('.')[col('.') - 2] !~ '\w' && getline('.')[col('.') - 3] !~ ')'&& getline('.')[col('.') - 2] !~ ']'
elseif !pumvisible() && a:mode == 0
return 0
endif
if col('.') > 1
let l:line = getline('.')
let l:col = col('.')
let l:word_start = l:col - 1
while strcharpart(getline('.'),l:word_start - 1,1) =~ '\k' && l:word_start >= 0
let l:word_start -= 1
endwhile
let words = matchstr(l:line, '\k\+', l:word_start)
let l:matches = s:AutoComplete(0,words )
let l:start = s:AutoComplete(1,words)
if len(l:matches) > 0
if a:mode == 1
call complete(l:start+1,l:matches)
endif
return 1
else
return 0
endif
else
return 0
endif
endfunction
function! Verilogformat()
silent! execute '!touch tmp_format;
\verible-verilog-format %>tmp_format;
\cat tmp_format>%;
\rm tmp_format;'
redraw!
endfunction
function! LetterCount(word)
let letter_count = {}
for i in range(len(a:word))
let letter = a:word[i]
if letter =~# '^[A-Z]$'
let letter = tolower(letter)
endif
if has_key(letter_count, letter)
let letter_count[letter] += 1
else
let letter_count[letter] = 1
endif
endfor
return letter_count
endfunction
function! CheckLetterCount(arr1, arr2)
for [letter, letter_count] in items(a:arr2)
if !has_key(a:arr1, letter) || a:arr1[letter] < letter_count
return 0
endif
endfor
return 1
endfunction
function! CheckWord(mode)
let first_word = matchstr(getline('.'),'\w\+') "行首词语
let first_word_list_1 = ['input','output','inout','reg','wire']
let first_word_list_2 = ['posedge','negedge']
let l:pos = getcurpos()
let l:search_pos = search('\w\+', 'bW')
call search('\w\+','bW')
let before_word = expand('<cword>')
call setpos('.',l:pos)
if a:mode == 1
for l:word in first_word_list_1
if first_word =~ l:word
return 1
endif
endfor
return 0
elseif a:mode == 0
for l:word in first_word_list_2
if IsCursorInParens() && before_word =~ l:word || first_word =~ 'assign'
return 1
endif
endfor
return 0
else
return 0
endif
endfunction
function! IsCursorInParens()
let line = getline('.')
let col = col('.')
let before_cursor = strpart(line, 0, col-1)
let after_cursor = strpart(line, col-1)
if match(before_cursor, '[({[]') != -1 && match(after_cursor, '[)}\]]') != -1
return 1 " 光标在括号内
else
return 0 " 光标不在括号内
endif
endfunction
augroup MyAutoGroup
autocmd!
autocmd TextChangedI *.v call MyAutoFunction()
augroup END
function! MyAutoFunction()
let line = getline('.')
let col = col('.')
let char_before_cursor = strpart(line, col-2, 1)
if char_before_cursor =~ '\w' || char_before_cursor == "\b"
call TriggerAutoComplete(1)
endif
endfunction
提取模块和变量的函数verilog_module
#!/bin/fish
set input_file $argv[1]
set line_number $argv[2]
cat $input_file > tmp
perl -0777 -ne '
my $first = 1;
while (/module\s+(\S[\s\S]*?\))/g) {
my $module = $1;
if ($first) {
$first = 0;
next;
}
$module =~ s/input/./g;
$module =~ s/output/\@output\@/g;
$module =~ s/^module\s+//;
$module =~ s/\s//g;
$module =~ s/\)/()\);/g;
$module =~ s/,/(),/g;
print "$module
";
}
' tmp | sed 's/\@output\@/%/' > tmp2;
perl -0777 -ne '
s/output/./g;
s/%/ \/\*<-i | o->\*\/ ./g;
s/\@//g;
print $_;
' tmp2 | sed -E "s/.(\[[0-9:]+\])([^\(]+)\(\)/.\2()\/\*\1\*\/ /g" > tmp
cat tmp2 | sed -E 's/^([A-Za-z_0-9$]+)\(.*/\1/g'>>tmp
rm tmp2
set target_line (sed -n "$line_number p" $input_file)
set start_line (sed -n "1,$line_number p" $input_file | tac | grep -m 1 -n 'module' | cut -d: -f1)
set end_line (sed -n "$line_number,\$ p" $input_file | grep -m 1 -n 'endmodule' | cut -d: -f1)
if test -n "$start_line" -a -n "$end_line"
set start_line (math $line_number - $start_line + 1)
set end_line (math $line_number + $end_line - 1)
sed -n "$start_line,$end_line p" $input_file\
| awk '/module/{flag=1;next} /endmodule/{flag=0} flag' \
| grep -E 'input|output|reg|wire' | sed -E 's/(input|output|reg|wire)//g' \
| sed -E 's/(\[.*\])//g' \
| tr -s ';,[]' '\n' \
| awk '{print $1}' \
| sort | uniq -c \
| awk '{print $2}'>tmp_variable
sed -n "$start_line,$end_line p" $input_file\
| awk '/module/{flag=1;next} /endmodule/{flag=0} flag' \
| grep -E 'input|output|reg|wire' \
| sed -E 's/(input|output|reg|wire)//g' \
| sort | awk '{$1=$1}1' \
| grep '\[' | sed -E 's/\[.*\]//g' \
| sed -E 's/( )+//g' \
| sed -E 's/([A-Za-z$0-9]+)/\1[:]/g' \
| tr -s ',;' '\n'>>tmp_variable
else
cat $input_file \
| awk '/module/{flag=1;next} /endmodule/{flag=0} flag' \
| grep -E 'input|output|reg|wire' | sed -E 's/(input|output|reg|wire)//g' \
| sed -E 's/(\[.*\])//g' \
| tr -s ';,[]' '\n' \
| awk '{print $1}' \
| sort | uniq -c \
| awk '{print $2}'>tmp_variable
cat $input_file \
| awk '/module/{flag=1;next} /endmodule/{flag=0} flag' \
| grep -E 'input|output|reg|wire' \
| sed -E 's/(input|output|reg|wire)//g' \
| sort | awk '{$1=$1}1' \
| grep '\[' | sed -E 's/\[.*\]//g' \
| sed -E 's/( )+//g' \
| sed -E 's/([A-Za-z$0-9]+)/\1[:]/g' \
| tr -s ',;' '\n'>>tmp_variable
end
其他内容不需要修改
至于autoinstall,在写了在写了(创建文件夹ing...)
标签:插件,word,补全,module,vim,let,letter,endif,line From: https://blog.csdn.net/2401_83148007/article/details/143967620