本文是 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...)

 

f7825aafcfed47bcabf2dc65ffdbabfb.png

 

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐