您的位置:首页 > 其它

gvim中进行verilog语言信号追踪、显示拓扑插件

2017-02-16 20:29 337 查看
摘要: 使用python实现的一款绿色gvim插件,在gvim中实现类似verdi对verilog code 追踪信号,显示拓扑等功能。

插件使用方法及功能:

vtags 是一款在gvim下实现类似verdi的信号追踪、显示拓扑等功能的插件。vtags插件完全使用python实现,目前实现功能包括信号追踪、宏定义追踪、显示模块拓扑、快速打开文件、保存和打开gvim快照、添加断点等功能。

支持功能和快捷键:

快捷键
功能
gi
进入子模块
gu
回到上层模块
<Space><Left>
追信号源,或宏定义
<Space><Right>
追信号目的
<Space><Down>
回退
<Space><Up>
向前
<Space> + v
显示策略,和展开收回策略条目
<Space> + c
添加记录点
<Space> + b
添加基本模块
<Space> + d
删除记录点或基本模块
<Space> +h
固定当前窗口
<Space>
快速访问
<Space> + s
储存快照
gvim/vim
加载快照
详细信息看《二:开始使用及支持功能和快捷键》

注意:

(1)在code目录下通过vtags生成vtags.db后,第一次打开verilog code时需要编译生成的database,所以第一打开code比较慢,之后打开code就会非常迅速。

安装方式:

1. 下载插件代码,解压并复制到自选的安装路径下。下面以安装目录为“~/vtags-1.20/为例”

代码下载地址: (1)https://pan.baidu.com/s/1kVfRXFx

(2)http://www.vim.org/scripts/script.php?script_id=5494

2. 在linux配置文件中添加别名。

~/.cshrc 中添加:alias vtags 'python ~/vtags-1.20/vtags.py'

或 ~/.bashrc 中添加:alias=vtags 'python ~/vtags-1.20/vtags.py'

source ~/.cshrc 或 source ~/.bashre 使设置生效。

3. 在vim配置文件中加入插件。

~/.vimrc 中添加: source ~/vtags-1.20/vtags_vim_api.vim

4. 本步骤可选,可以在vtags-1.20/vim_glb_config.py中设置插件的一些全局设置,

你也可以使用vtags时生成的局部配置文件vim_local_config.py中进行设置。

5. cd 到code目录使用命令:vtags, 在code目录下生成base文件 vtags.db, 用gvim打开代码就可以使用上面定义快捷键中功能。

注: 要求python版本2.7,详情请看《用户使用指南》。

code 源码:

""" https://my.oschina.net/u/2520885 """
#===============================================================================
# Copyright (C) 2016 by Jun Cao

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#===============================================================================

# left sidebar window width
frame_window_width          = 20

# right bottom report window height
report_window_height        = 8

# max work window vtags auto opened, not include use self opened window and holded window
max_open_work_window_number = 1

# when use <Space><left>/<Space><right> the max number of history trace valid
max_roll_trace_depth        = 1000

# when <Space>c add check point, the max number of check point valid
max_his_check_point_num     = 10

# when gen the vtags database, in all verilog modules when some module called more then threshold times,
# set this module to be base module, then show topo will not list it's inst one by one
base_module_threshold       = 200

# supported verilog postfix, we only add postfix in below to data base
support_verilog_postfix     = ['v']

# open debug module or not, open debug module will print a lot debug log at vtags.db
debug_mode                  = False

# when trace source, match bigger than TraceSourceOptimizingThreshold, open opt func, mainly for signal like clk,rst ...
trace_source_optimizing_threshold   = 20

# frame fold level space, use to set pre space num, if current level is 3 ,
# and fold level space is ' ', then current line pre space is ' '*3 = '   '
frame_fold_level_space          = '    '

# weather show report or not
show_report                 = True

# weather show sidebar or not
show_sidebar                = True

""" https://my.oschina.net/u/2520885 """
#===============================================================================
# Copyright (C) 2016 by Jun Cao

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#===============================================================================
__version__ = "1.20"
__project_url__ = "https://my.oschina.net/u/2520885"

import os
import sys
import re
import pickle

#print help
help = ''
try:
help = sys.argv[1]
except:
pass
if help in ['-h','-help']:
print("(1) generate vtags at code dir, use command \"vtags\" ;"                                    )
print("(2) config vtags vim at vtags gen dir \"/vtags.db/vim_local_config.py\","                   )
print("    config items and detail look vim_local_config.py notes;"                                )
print("(3) support action in vim window:"                                                          )
print("        1) gi             : if cursor on module call, go in submodule;"                     )
print("        2) gu             : if cur module called before, go upper module;"                  )
print("        3) <Space><Left>  : trace cursor word signal source;"                               )
print("        4) <Space><Right> : trace cursor word signal dest;"                                 )
print("        5) <Space><Down>  : roll back;"                                                     )
print("        6) <Space><Up>    : go forward;"                                                    )
print("        7) <Space>v       : show current module topo "                                      )
print("                            or fold/unfold sidebar items;"                                  )
print("        8) <Space>c       : add current cursor as checkpoint, can go back directly;"        )
print("        9) <Space>b       : add current cursor module as basemodule, not show in topo;"     )
print("        10) <Space>       : in sidebar or report win, just go cursor line link;"            )
print("        11) <Space>h      : hold cursor win, will not auto close it;"                       )
print("        12) <Space>d      : in sidebar, delete valid items(base_module, checkpoint...);"    )
print("        13) <Space>s      : save current vim snapshort,"                                    )
print("                            use \"gvim/vim\" without input file to reload snapshort;"       )
exit()

def cur_file_dir():
path = sys.path[0]
if os.path.isdir(path):
return path
elif os.path.isfile(path):
return os.path.dirname(path)

vtags_install_path = cur_file_dir()
sys.path.insert(0,vtags_install_path)

sed_vtags_install_path = re.sub('/','\/',vtags_install_path)
os.system('sed -ig \'s/vtags_install_path =.*/vtags_install_path = "%s"/g\' %s/vtags_vim_api.vim' %(sed_vtags_install_path, vtags_install_path) )
os.system('sed -ig \'s/let is_vtags_installed =.*/let is_vtags_installed = 1/g\' %s/vtags_vim_api.vim' %(vtags_install_path) )

vtags_folder_path = os.getcwd() + '/vtags.db'
os.system('mkdir -p %s'%(vtags_folder_path))
if os.path.isfile(vtags_folder_path + '/vtag_gen_log.txt'):
os.system('rm -rf '+vtags_folder_path+'/vtag_gen_log.txt')

import Lib.GLB as GLB
G = GLB.G
GLB.vtags_run_log_path[0] = vtags_folder_path + '/vtags_run.log'
import Lib.Code as Code
import Lib.View as View
from Lib.Base import *

# filelist:
#     use "//" as note sign
#     support dir_path and file path mix
def get_all_verilog_files_from_filelist(filelist_path):
verilog_file_paths = []
# get ~ path
home_path = os.popen('echo ~').readlines()[0].rstrip('\n').rstrip('/')
for l in open(filelist_path,'r').readlines():
l = l.strip('\n')
l = re.sub('//.*','',l)
l = re.sub('^~', home_path, l)
if re.match('\s*$',l):
continue
path = l
if os.path.isdir(path):
c_files_path     = os.popen('find ' + dir_path + ' -type f 2>/dev/null').readlines()
c_files_path     = [ d_l.rstrip('\n') for d_l in c_files_path ]
for c_f in c_files_path:
if get_file_path_postfix(c_f) not in G['SupportVerilogPostfix']:
continue
verilog_file_paths.append(c_f)
if os.path.isfile(path):
if get_file_path_postfix(path) not in G['SupportVerilogPostfix']:
continue
verilog_file_paths.append(path)
return verilog_file_paths

# get all verilog files inf and merge
#   modules_inf  = { module_name: module_inf }
#   defines_inf  = { macro_name : [ define_inf ] }
#   files_inf    = { file_name  : file_inf }
#       module_inf    = {  'module_name'        : module_name
#                         ,'file_path'          : f
#                         ,'line_range_in_file' : (module_start_line_num, module_end_line_num)
#                         ,'sub_modules'        : sub_modules }
#       define_inf    = {  "name" : xxx
#                         ,"path" : f
#                         ,"pos"  : (line_num, colum_num)  # name first char pos
#                         ,'code_line' : `define xxx .... }
#       file_inf      = {  'glb_defines'   : [ define_inf ]
#                         ,'module_infs'   : [ module_inf ]
#                         ,'module_calls'  : [ call_sub_inf ]
#                         ,'file_edit_inf' : { 'create_time': ..., 'last_modify_time': ...}
#                       call_sub_inf  =  { 'inst_name'     : inst_name
#                                         ,'module_name'   : modu_name
#                                         ,'match_range'   : match_range }
def get_verilog_files_code_inf(paths):
# step 1/2 get all module/define inf
all_file_module_inf = {}
all_file_define_inf = {}
all_module_name     = set()
print('step 1/2:')
for i,f in enumerate(paths):
show_progress_bar( i, len(paths))
PrintDebug(f)
# gen cur module and define inf
cur_file_module_inf = get_single_verilog_file_module_inf(f)
cur_file_define_inf = get_single_verilog_file_define_inf(f)
# add to result
all_file_module_inf[f] = cur_file_module_inf
all_file_define_inf[f] = cur_file_define_inf
all_module_name        = all_module_name | set([ mi['module_name'] for mi in cur_file_module_inf])
print('')
# step 2/2 get all file sub call inf
all_file_subcall_inf = {}
patten = get_submodule_match_patten(all_module_name)
print('step 2/2:')
for i,f in enumerate(paths):
PrintDebug(f)
show_progress_bar( i, len(paths))
all_file_subcall_inf[f] = get_single_verilog_file_subcall_inf(f, patten, all_module_name)
print('')
# merge to all_file_inf
all_file_inf = {}
for i,f in enumerate(paths):
add_single_verilog_file_submodule_inf_to_module_inf( all_file_module_inf[f], all_file_subcall_inf[f] )
all_file_inf[f] = {
'glb_defines'   : all_file_define_inf[f]
,'module_infs'   : all_file_module_inf[f]
,'module_calls'  : all_file_subcall_inf[f]
,'file_edit_inf' : { 'create_time': os.path.getctime(f), 'last_modify_time': os.path.getmtime(f)}
}
modules_inf , global_defines_inf = gen_modules_and_defines_inf(all_file_inf)
return {
'files_inf'   : all_file_inf
,'modules_inf' : modules_inf
,'defines_inf' : global_defines_inf
}

#------------------------function for get module inf--------------------
filelist_path = ''
verilog_file_paths = []
if filelist_path:
verilog_file_paths = get_all_verilog_files_from_filelist(filelist_path)
else:
c_dir_path           = os.getcwd()
c_dir_files_path     = os.popen('find ' + c_dir_path + ' -type f 2>/dev/null').readlines()
c_dir_files_path     = [ d_l.rstrip('\n') for d_l in c_dir_files_path ]
for c_f in c_dir_files_path:
if get_file_path_postfix(c_f) not in G['SupportVerilogPostfix']:
continue
verilog_file_paths.append(c_f)

# get all code inf
verilog_code_inf = get_verilog_files_code_inf(verilog_file_paths)
modules_inf  = verilog_code_inf['modules_inf']
files_inf    = verilog_code_inf['files_inf'  ]
defines_inf  = verilog_code_inf['defines_inf']

# set base module
base_modules     = set()
base_threshold  = G['BaseModuleInf']['BaseModuleThreshold']
module_inst_num = {}
for m in modules_inf:
for sm in modules_inf[m]['sub_modules']:
module_name = sm['module_name']
module_inst_num.setdefault(module_name,0)
module_inst_num[module_name] += 1
for m in module_inst_num:
if module_inst_num[m] >= base_threshold:
base_modules.add(m)

# change vim HDLTags path

fp = open(vtags_folder_path + '/files_inf.py','w')
fp.write('FileInf = %s \n'%(files_inf.__str__()))
fp.write('HDLTagsActive = True \n')
fp.close()
if not os.path.isfile(vtags_folder_path + '/vim_local_config.py'):
os.system('cp %s/vim_glb_config.py %s/vim_local_config.py'%(vtags_install_path, vtags_folder_path))
if not os.path.isfile(vtags_folder_path+'/base_modules.pkl'):
output = open(vtags_folder_path+'/base_modules.pkl','wb')
pickle.dump(base_modules, output)
output.close()

"""
" https://my.oschina.net/u/2520885 """
"===============================================================================
" Copyright (C) 2016 by Jun Cao

" Permission is hereby granted, free of charge, to any person obtaining a copy
" of this software and associated documentation files (the "Software"), to deal
" in the Software without restriction, including without limitation the rights
" to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
" copies of the Software, and to permit persons to whom the Software is
" furnished to do so, subject to the following conditions:

" The above copyright notice and this permission notice shall be included in
" all copies or substantial portions of the Software.

" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
" AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
" LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
" OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
" THE SOFTWARE.
"===============================================================================

function! VimPythonExtend()
python << EOF
import os
import sys
vtags_install_path = "/mnt/hgfs/VMShare/my_tools/vtags-1.20"
if os.path.isdir(vtags_install_path):
sys.path.insert(0,vtags_install_path)
from Lib.API import *
EOF
endfunction

let is_vtags_installed = 1

if is_vtags_installed == 1
"vi_HDLTags_begin-----------------------------------
call VimPythonExtend()
map gi                   :py try_go_into_submodule()           <CR>
map gu                   :py try_go_upper_module()             <CR>
map <Space><Left>        :py try_trace_signal_sources()        <CR>
map <Space><Right>       :py try_trace_signal_destinations()   <CR>
map <Space><Down>        :py try_roll_back()                   <CR>
map <Space><Up>          :py try_go_forward()                  <CR>
map <Space>v             :py try_show_frame()                  <CR>
map <Space>c             :py try_add_check_point()             <CR>
map <Space>b             :py try_add_base_module()             <CR>
map <Space>              :py try_space_operation()             <CR>
map <Space>h             :py try_hold_current_win()            <CR>
map <Space>d             :py try_del_operation()               <CR>
map <Space>s             :py try_save_env_snapshort()          <CR>
"vi_HDLTags_end-------------------------------------
endif

""" https://my.oschina.net/u/2520885 """
#===============================================================================
# Copyright (C) 2016 by Jun Cao

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#===============================================================================

import os
import sys
# import vim, when gen vtags it will no vim,so use try
try:
import vim
except:
pass
# import normal lib
import re
import Lib.Code as Code
import Lib.View as View
PrintReport = View.PrintReport
import Lib.GLB as GLB
G = GLB.G
from Lib.Base import *

# init gen module_inf, and glb define
if G['HDLTagsActive']:
G['ModuleInf'], G['CodeDefineInf'] = gen_modules_and_defines_inf(G['FileInf'])

# open snapshort wins
if G['HDLTagsActive'] and G['EnvSnapshortWinsInf']:
OldOpenWinTrace = [p for p in G['WorkWin_Inf']['OpenWinTrace']]
G['WorkWin_Inf']['OpenWinTrace'].insert(0,vim.current.buffer.name)
for w_inf in G['EnvSnapshortWinsInf']:
c_path   = w_inf['path']
c_cursor = w_inf['cursor']
if os.path.isfile(c_path):
View.Open(c_path)
if c_path not in OldOpenWinTrace:
if G['WorkWin_Inf']['OpenWinTrace'] and G['WorkWin_Inf']['OpenWinTrace'][-1] == c_path:
del G['WorkWin_Inf']['OpenWinTrace'][-1]
else:
PrintDebug('Warning: reload file not exit ! file: %s'%(c_path))
for w_inf in G['EnvSnapshortWinsInf']:
c_size  = w_inf['size']
c_path   = w_inf['path']
if os.path.isfile(c_path):
View.Open(c_path)
vim.current.window.width   = c_size[0]
vim.current.window.height  = c_size[1]
# because base module may be changed so refresh topo and show base
if G['Frame_Inf']['Frame_Path'] in [ w.buffer.name for w in vim.windows]:
View.refresh_topo()
View.show_base_module()
PrintReport('reload snapshort finish !')
elif G['HDLTagsActive']:
# treat the first win as work win , if cur win is hdl code, and add first trace point
first_cursor_inf = View.get_cur_cursor_inf()
if first_cursor_inf['hdl_type'] == 'verilog':
G['WorkWin_Inf']['OpenWinTrace'].append(first_cursor_inf['file_path'])
View.add_trace_point()
PrintDebug('Point: initial new env finish !')

# shortcut key: gi
def go_into_submodule():
cursor_inf       = View.get_cur_cursor_inf()
cur_module_inf   = cursor_inf['cur_module_inf']
if not cur_module_inf:
PrintReport('Warning: cur cursor not in a valid module, no submodule call !')
return
call_module_name = cur_module_inf['module_name']
sub_call_inf     = Code.get_module_call_sub_module_io_inf(cursor_inf['line'], cursor_inf['pos'], cursor_inf['file_path'])
if not sub_call_inf:
PrintReport('Warning: cur cursor not on recgnized subcall !')
return
sub_module_name  = sub_call_inf['sub_module_name']
sub_module_inf   = get_module_inf(sub_module_name)
if not sub_module_inf:
PrintReport('Warning: sub module %s no module inf in database !'%(sub_module_name))
return
sub_signal_name  = sub_call_inf['sub_io_name']
sub_match_pos    = []
if sub_signal_name:
sub_match_pos    = sub_call_inf['sub_match_pos']
else:
sub_signal_name = sub_module_name
sub_match_pos   = sub_module_inf['module_pos']
call_sub_inf     = sub_call_inf['call_sub_inf']      # GLB call sub inf(atom)
sub_module_path  = sub_module_inf['file_path']
set_module_last_call_inf(sub_module_name, call_module_name, call_sub_inf['inst_name'])
View.add_trace_point()
View.go_win( sub_module_path, sub_match_pos, sub_signal_name)

def try_go_into_submodule():
if not G['HDLTagsActive']: return
if G['Debug']:
go_into_submodule()
else:
try: go_into_submodule()
except: pass

# shortcut key: gu
def go_upper_module():
cursor_inf        = View.get_cur_cursor_inf()
cur_module_inf    = cursor_inf['cur_module_inf']
if not cur_module_inf:
PrintReport('Warning: cur line not in a valid verilog module, or current module not in database !')
return
cur_last_call_inf = get_module_last_call_inf(cur_module_inf['module_name'])
if not cur_last_call_inf:
PrintReport('Warning: cur module %s not called by upper module before !'%(cur_module_inf['module_name']))
return
upper_module_name  = cur_last_call_inf['upper_module_name']
upper_call_sub_inf = cur_last_call_inf['upper_call_inf']
upper_match_pos    = upper_call_sub_inf['match_pos']
upper_inst_name    = upper_call_sub_inf['inst_name']
View.add_trace_point()
View.go_win( upper_module_name, upper_match_pos, upper_inst_name)

def try_go_upper_module():
if not G['HDLTagsActive']: return
if G['Debug']:
go_upper_module()
else:
try: go_upper_module()
except: pass

# shortcut key: <Space><Left>
def trace_signal_sources():
if G['IgnoreNextSpaceOp']:
G['IgnoreNextSpaceOp'] = False
PrintDebug('Care: not do this trace source op ,bucause <space> is come from unknow reason !')
return
cursor_inf = View.get_cur_cursor_inf()
trace_signal_name = cursor_inf['word']
if not trace_signal_name:
PrintReport("Warning: Current cursor not on signal name, can not trace source !")
return
# case0: if cur cursor on a macro, go macro define
if Code.trace_glb_define_signal('source', cursor_inf): return
# case1: if cur cursor on io signal, need cross to upper module
if Code.trace_io_signal('source', cursor_inf): return
# case2: if cur cursor on module call io line go to submodule io
if Code.trace_module_call_io_signal('source', cursor_inf): return
# case3: trace signal same as pre trace signal, just show next result
if (G['TraceInf']['LastTraceSource']['Path'] == cursor_inf['file_path']) and (G['TraceInf']['LastTraceSource']['SignalName'] == trace_signal_name) :
View.show_next_trace_result('source')
return
# case4: trace a new normal(not io, sub call io) signal
if Code.trace_normal_signal('source', cursor_inf): return

def try_trace_signal_sources():
if not G['HDLTagsActive']: return
if G['Debug']:
trace_signal_sources()
else:
try: trace_signal_sources()
except: pass

# shortcut key: <Space><Right>
def trace_signal_destinations():
if G['IgnoreNextSpaceOp']:
G['IgnoreNextSpaceOp'] = False
PrintDebug('Care: not do this trace source op ,bucause <space> is come from unknow reason !')
return
cursor_inf = View.get_cur_cursor_inf()
trace_signal_name = cursor_inf['word']
if not trace_signal_name:
PrintReport("Warning: Current cursor not on signal name, can not trace dest!")
return
# case0: if cur cursor on io signal, need cross to upper module
if Code.trace_io_signal('dest', cursor_inf): return
# case1: if cur cursor on module call io line go to submodule io
if Code.trace_module_call_io_signal('dest', cursor_inf): return
# case2: trace signal same as pre trace signal, just show next result
if (G['TraceInf']['LastTraceDest']['Path'] == cursor_inf['file_path']) and (G['TraceInf']['LastTraceDest']['SignalName'] == trace_signal_name) :
View.show_next_trace_result('dest')
return
# case3: if cur cursor on a macro, go macro define
if Code.trace_glb_define_signal('dest', cursor_inf): return
# case4: trace a new normal(not io, sub call io) signal
Code.trace_normal_signal('dest', cursor_inf)

def try_trace_signal_destinations():
if not G['HDLTagsActive']: return
if G['Debug']:
trace_signal_destinations()
else:
try: trace_signal_destinations()
except: pass

# shortcut key: <Space><Down>
def roll_back():
if G['IgnoreNextSpaceOp']:
G['IgnoreNextSpaceOp'] = False
PrintDebug('Care: not do this trace source op ,bucause <space> is come from unknow reason !')
return
cur_nonius        = G['OpTraceInf']['Nonius'] - 1
TracePoints       = G['OpTraceInf']['TracePoints']
# if reach to the oldest trace point just return
if cur_nonius < 0:
PrintReport("Warning: roll backed to the oldest trace point now !")
return
# go to the trace point
cur_point = TracePoints[cur_nonius]
G['OpTraceInf']['Nonius'] = cur_nonius
View.go_win( cur_point['path'], cur_point['pos'], cur_point['key'])
return

def try_roll_back():
if not G['HDLTagsActive']: return
if G['Debug']:
roll_back()
else:
try: roll_back()
except: pass

# shortcut key: <Space><Up>
def go_forward():
if G['IgnoreNextSpaceOp']:
G['IgnoreNextSpaceOp'] = False
PrintDebug('Care: not do this trace source op ,bucause <space> is come from unknow reason !')
return
cur_nonius        = G['OpTraceInf']['Nonius'] + 1
TracePoints       = G['OpTraceInf']['TracePoints']
if cur_nonius >= len(TracePoints):
PrintReport("Warning: go forward to the newest trace point now !")
return
cur_point = TracePoints[cur_nonius]
G['OpTraceInf']['Nonius'] = cur_nonius
View.go_win( cur_point['path'], cur_point['pos'], cur_point['key'])
return

def try_go_forward():
if not G['HDLTagsActive']: return
if G['Debug']:
go_forward()
else:
try: go_forward()
except: pass

# shortcut key: <space>
def space_operation():
if G['IgnoreNextSpaceOp']:
G['IgnoreNextSpaceOp'] = False
PrintDebug('Care: not do this trace source op ,bucause <space> is come from unknow reason !')
return
cursor_inf = View.get_cur_cursor_inf()
# if cur in Frame or Report, show file link files
if cursor_inf['file_path'] in [ G['Frame_Inf']['Frame_Path'], G['Report_Inf']['Report_Path'] ]:
cur_frame_link = G['VimBufferLineFileLink'][cursor_inf['file_path']][cursor_inf['line_num']]
View.add_trace_point()
if cur_frame_link and cur_frame_link['path']:
View.go_win( cur_frame_link['path'], cur_frame_link['pos'], cur_frame_link['key'])
View.add_trace_point()
else:
PrintReport('Warning: No file link in current line ! ')
else:
PrintReport('Warning: No space operation in current file ! ')

def try_space_operation():
if not G['HDLTagsActive']: return
if G['Debug']:
space_operation()
else:
try: space_operation()
except: pass

# shortcut key: <s-t>
def show_frame():
G["IgnoreNextSpaceOp"] = G['FixExtraSpace']
if cur_in_frame():
cursor_line = vim.current.window.cursor[0] - 1
View.frame_line_fold_operation(cursor_line)
else:
View.show_topo()
View.show_check_point(False)
View.show_base_module(False)
return

def try_show_frame():
if not G['HDLTagsActive']: return
if G['Debug']:
show_frame()
else:
try: show_frame()
except: pass
return

# shortcut key: <Space>h
def hold_current_win():
cur_path = vim.current.buffer.name
# just del current win frome work win, then will not auto close current win
for i,path in enumerate(G['WorkWin_Inf']['OpenWinTrace']):
if cur_path == path:
del G['WorkWin_Inf']['OpenWinTrace'][i]
break

def try_hold_current_win():
if not G['HDLTagsActive']: return
if G['Debug']:
hold_current_win()
else:
try: hold_current_win()
except: pass

# shortcut key: <Space>c
def add_check_point():
G["IgnoreNextSpaceOp"] = G['FixExtraSpace']
cursor_inf   = View.get_cur_cursor_inf()
level        = G['CheckPointInf']['TopFoldLevel'] + 1
key          = G['Frame_Inf']['FoldLevelSpace']*level + cursor_inf['word']
link         = {
'type'     : 'check_point'
,'key'      : cursor_inf['word']
,'pos'      : cursor_inf['pos']
,'path'     : cursor_inf['file_path']
,'fold_inf' : { 'fold_status': 'fix', 'level': level }
}
G['CheckPointInf']['CheckPoints'].insert(0, {'key': key, 'link': link })
if len(G['CheckPointInf']['CheckPoints']) > G['CheckPointInf']['MaxNum']:
del G['CheckPointInf']['CheckPoints'][-1]
View.show_check_point()

def try_add_check_point():
if not G['HDLTagsActive']: return
if G['Debug']:
add_check_point()
else:
try: add_check_point()
except: pass

# shortcut key: <Space>b
def add_base_module():
G["IgnoreNextSpaceOp"] = G['FixExtraSpace']
cursor_inf    = View.get_cur_cursor_inf()
cursor_module = cursor_inf['word']
if not cursor_module:
PrintReport('Warning: cursor not on a valid word ! ')
return
if not get_module_inf(cursor_module):
PrintReport('Warning: cursor words: %s not a recgnized module name ! will no file link ! '%(cursor_module))
if cursor_module in G['BaseModuleInf']['BaseModules']:
PrintReport('Care: module %s is already base module ! '%(cursor_module))
return
G['BaseModuleInf']['BaseModules'].add(cursor_module)
update_base_module_pickle()
View.show_base_module()
View.refresh_topo()

def try_add_base_module():
if not G['HDLTagsActive']: return
if G['Debug']:
add_base_module()
else:
try: add_base_module()
except: pass

#------------------------------
# shortcut key: <Space>d
def del_operation():
if not cur_in_frame():
PrintReport('Warning: Cur file no del function ! ')
return
cur_path      = vim.current.buffer.name
cur_line_num  = vim.current.window.cursor[0] - 1
cur_file_link = G['VimBufferLineFileLink'][cur_path][cur_line_num]
if not cur_file_link:
PrintReport('Warning: Cur line no del function ! ')
return
# delete a check point, if link has path means a valid link
if (cur_file_link['type'] == 'check_point') and (cur_file_link['fold_inf']['level'] > G['CheckPointInf']['TopFoldLevel']):
G["IgnoreNextSpaceOp"] = G['FixExtraSpace']
check_point_begin_line_num = get_frame_range_inf()['check_point_range'][0]
del_index = cur_line_num - check_point_begin_line_num - 1
del G['CheckPointInf']['CheckPoints'][ del_index ]
View.show_check_point()
return
# del a base module
if (cur_file_link['type'] == 'base_module') and (cur_file_link['fold_inf']['level'] > G['BaseModuleInf']['TopFoldLevel']):
G["IgnoreNextSpaceOp"] = G['FixExtraSpace']
G['BaseModuleInf']['BaseModules'].remove(cur_file_link['key'])
update_base_module_pickle()
View.show_base_module()
View.refresh_topo()
return
PrintReport('Warning: Cur line no del function ! ')

def try_del_operation():
if not G['HDLTagsActive']: return
if G['Debug']:
del_operation()
else:
try: del_operation()
except: pass

#----------------------------------------
# shortcut key: <Space>s
def try_save_env_snapshort():
if not G['HDLTagsActive']: return
if G['Debug']:
if G['SaveEnvSnapshort_F']():
PrintReport('save env snapshort success !')
else:
try:
if G['SaveEnvSnapshort_F']():
PrintReport('save env snapshort success !')
except: pass

""" https://my.oschina.net/u/2520885 """
#===============================================================================
# Copyright (C) 2016 by Jun Cao

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#===============================================================================

import sys
try:
import vim
except:
pass
import os
import re
import pickle
import GLB
G = GLB.G
# function to print debug
PrintDebug  = G['PrintDebug_F']

def get_valid_code( str ):
str = re.sub('(^\s*)|(\s*$)', '' ,str)
str = re.sub('//.*', '' ,str)
str = re.sub('^`.*', '' ,str)  # bug ^\s*`.*
return str

def get_valid_code_leave_head_space( str ):
str = re.sub('\s*$', '' ,str)
str = re.sub('//.*', '' ,str)
str = re.sub('^`.*', '' ,str)
return str

def cur_in_frame():
return vim.current.buffer.name == G['Frame_Inf']['Frame_Path']

def cur_in_report():
return vim.current.buffer.name == G['Report_Inf']['Report_Path']

def get_path_for_name(path_or_name):
if path_or_name == 'Frame':
return G["Frame_Inf"]["Frame_Path"]
if path_or_name == 'Report':
return G["Report_Inf"]["Report_Path"]
may_module_inf = get_module_inf(path_or_name)
if may_module_inf:
return may_module_inf['file_path']
return path_or_name

def get_file_name_from_path(path):
return re.sub('.*/','',path)

def get_full_word(line, y):
pre_part  = ( re.match('^(?P<pre>\w*)',(line[:y])[::-1]).group('pre') )[::-1]
post_part = re.match('^(?P<post>\w*)', line[y:]).group('post')
return pre_part + post_part

def get_file_path_postfix(file_path):
if type(file_path) != str:
return
split_by_dot = file_path.split('.')
if len(split_by_dot) < 2 : # which means file_path has no postfix
return ''
# post_fix = split_by_dot[-1].lower() # postfix don't care case
post_fix = split_by_dot[-1]           # postfix care case
return post_fix

def get_file_hdl_type(file_path):
postfix = get_file_path_postfix(file_path)
if postfix in G['SupportVHDLPostfix']:
return 'vhdl'
elif postfix in G['SupportVerilogPostfix']:
return 'verilog'
else:
return ''

#------------------------------------------------------------
def get_vhdl_full_line(codes, start_pos, direction):
pass

def get_verilog_pre_full_line(codes, start_pos):
pre_full_line = ''
start_x, start_y = start_pos
start_line = codes[start_x][:start_y+1]
start_line = start_line.strip('\n')
start_line = re.sub('//.*','',start_line)
colon_y    = start_line.rfind(';')
if colon_y != -1:
pre_full_line = start_line[colon_y+1:]
else:
pre_full_line = start_line
for i in range(start_x-1,-1,-1):
t_line = codes[i].strip('\n')
t_line = re.sub('//.*', '', t_line)
t_colon_y = t_line.rfind(';')
if t_colon_y != -1:
pre_full_line = t_line[t_colon_y+1:] + ' ' + pre_full_line
break
else:
pre_full_line = t_line + ' ' +pre_full_line
return pre_full_line

def get_verilog_post_full_line(codes, start_pos):
post_full_line = ''
start_x, start_y = start_pos
start_line = codes[start_x][start_y:]
start_line = start_line.strip('\n')
start_line = re.sub('//.*','',start_line)
colon_y    = start_line.find(';')
if colon_y != -1:
pre_full_line = start_line[:colon_y+1]
else:
pre_full_line = start_line
for i in range(start_x+1,len(codes)):
t_line = codes[i].strip('\n')
t_line = re.sub('//.*', '', t_line)
t_colon_y = t_line.find(';')
if t_colon_y != -1:
pre_full_line = pre_full_line + ' ' + t_line[: t_colon_y+1]
break
else:
pre_full_line = pre_full_line + ' ' + t_line
return pre_full_line

def get_verilog_full_line(codes, start_pos, direction):
if direction == -1:  # 0 <- x
return get_verilog_pre_full_line(codes, start_pos)
elif direction == 1: #      x -> n
return get_verilog_post_full_line(codes, start_pos)
elif direction == 0: # 0 <- x -> n
return get_verilog_pre_full_line(codes, start_pos) + get_verilog_post_full_line(codes, start_pos)[1:] # [1:] because start char at both part
else:
return ''

def get_full_line( codes, hdl_type, start_pos, direction = 0):
if hdl_type == 'vhdl':
return get_vhdl_full_line(codes, start_pos, direction)
elif hdl_type == 'verilog':
return get_verilog_full_line(codes, start_pos, direction)
else:
return ''

# --------------------------------------------------------
# ok
def recgnize_io_signal_line(line, line_num):
# pre check if is not io
if line.find('input') == -1 and line.find('output') == -1:
return False
line = line.strip('\n')
line = re.sub('//.*','',line) # del notes
# raw re match
re_match = re.match('\s*(input|output)\W',line)
if not re_match:
re_match = re.match('(?P<prefix>.*\(\s*)(?P<real_io>(input|output)\W.*)',line)
if re_match:
prefix       = re_match.group('prefix')
real_io_line = re_match.group('real_io')
line         = ' '*(len(prefix)) + real_io_line
else:
return False
# match used egrep io line decode function
egrep_io_line = str(line_num)+':'+line
io_inf = decode_egreped_verilog_io_line(egrep_io_line)['io_infs']
return io_inf
#      "name"        : name
#    , "io_type"     : io_type
#    , "left"        : left_index
#    , "right"       : right_index
#    , "size"        : size
#    , 'line_num'    : line_num
#    , 'name_pos'    : (line_num, colm_num)
#    , 'code_line'   : code_line
#    , 'signal_type' : signal_type }

#-----------------------------------------------------------
# ok
def search_verilog_code_use_grep(key, path, row_range = ()):
search_result = []
if not path:
path = vim.current.buffer.name
match_lines    = os.popen('egrep -n -h \'(^|\W)%s(\W|$)\' %s'%(key, path)).readlines()
for l in match_lines:
l = l.strip('\n')
split0 = l.split(':')
line_num   = int(split0[0]) - 1
code_line  = ':'.join(split0[1:])
if row_range and ( line_num not in range(row_range[0], row_range[1]+1 ) ):
continue
# del note see if has key
s0 = re.search('(?P<pre>^|\W)%s(\W|$)'%(key), re.sub('//.*','',code_line) )
if s0:
colum_num  = s0.span()[0] + len(s0.group('pre'))
match_pos  = (line_num, colum_num)
line       = code_line
search_result.append( (match_pos, line) )
return search_result

#----------------------------------------------------------
def get_fram_topo_sub_inf(topo_module, cur_level):
sub_level   = cur_level + 1
topo_prefix = G['Frame_Inf']['FoldLevelSpace'] * sub_level
topo_datas   = []
topo_links   = []
sub_func_modules, sub_base_modules = get_sub_func_base_module(topo_module)
# first deal sub func module, show "inst(module)"
sub_func_modules_inst_names = list(sub_func_modules)
sub_func_modules_inst_names.sort()
for c_sub_inst_name in sub_func_modules_inst_names:
c_call_sub_inf    = sub_func_modules[c_sub_inst_name]
c_sub_module_name = c_call_sub_inf['module_name']
# gen show data
c_str      = '%s%s(%s)'%(topo_prefix, c_sub_inst_name, c_sub_module_name)
topo_datas.append(c_str)
# gen link
c_topo_link = {
'type'           : 'topo'
,'topo_inst_name' : ''
,'key'            : ''
,'pos'            : ''
,'path'           : ''
,'fold_inf'       : {'fold_status':'off', 'level': sub_level}
}
c_sub_module_inf = get_module_inf(c_sub_module_name)
if c_sub_module_inf:
c_topo_link['topo_inst_name'] = c_sub_inst_name
c_topo_link['key'           ] = c_sub_module_name
c_topo_link['pos'           ] = c_sub_module_inf['module_pos']
c_topo_link['path'          ] = c_sub_module_inf['file_path']
# show cur module, then all submodule, last call set to cur module
set_module_last_call_inf(c_sub_module_name, topo_module, c_call_sub_inf['inst_name'])
topo_links.append(c_topo_link)
sub_base_modules_names = list(sub_base_modules)
sub_base_modules_names.sort()
if len(sub_base_modules_names) > 0:
# deal base , show "module(n)"
# add one to sep func and base
topo_datas.append(topo_prefix+'------')
c_topo_link = {
'type'           : 'topo'
,'topo_inst_name' : ''
,'key'            : ''
,'pos'            : ()
,'path'           : ''
,'fold_inf'       : {'fold_status':'on', 'level': sub_level}
}
topo_links.append(c_topo_link)
for c_sub_module_name in sub_base_modules_names:
# deal data
c_sub_inst_n = len(sub_base_modules[c_sub_module_name])
c_str = '%s%s(%d)'%(topo_prefix,c_sub_module_name,c_sub_inst_n)
topo_datas.append(c_str)
# deal link
c_topo_link = {
'type'           : 'topo'
,'topo_inst_name' : ''
,'key'            : ''
,'pos'            : ''
,'path'           : ''
,'fold_inf'       : {'fold_status':'off', 'level': sub_level}
}
c_sub_module_inf = get_module_inf(c_sub_module_name)
if c_sub_module_inf:
c_topo_link['key' ] = c_sub_module_name
c_topo_link['pos' ] = c_sub_module_inf['module_pos']
c_topo_link['path'] = c_sub_module_inf['file_path']
topo_links.append(c_topo_link)
return topo_datas, topo_links

def get_fram_check_point_inf():
datas = []
links = []
for cp in G['CheckPointInf']['CheckPoints']:
datas.append(cp['key'])
links.append(cp['link'])
return datas, links

def get_fram_base_module_inf():
datas = []
links = []
base_module_level = G['BaseModuleInf']['TopFoldLevel'] + 1
base_module_space = G['Frame_Inf']['FoldLevelSpace'] * base_module_level
base_modules      = list(G['BaseModuleInf']['BaseModules'])
base_modules.sort()
for bm in base_modules:
key  = base_module_space + bm
link = {
'type'     : 'base_module'
,'key'      : bm
,'pos'      : ''
,'path'     : ''
,'fold_inf' : { 'fold_status': 'fix', 'level': base_module_level }
}
bm_module_inf = get_module_inf(bm)
if bm_module_inf:
link['pos']  = bm_module_inf['module_pos']
link['path'] = bm_module_inf['file_path']
datas.append(key)
links.append(link)
return datas, links

###########################################################
#----------------------------------------------------------
def decode_egreped_verilog_io_line(o_io_line):
# exp:
#   365:output alu_frf_part_p0_w;
#   366:output [127:0] alu_frf_data_p0_w;
#   357:output [THR_WIDTH-1:0] alu_dst_cond_tid_w
#   368:output reg  alu_frf_part_p0_w;
#   369:output wire [127:0] alu_frf_data_p0_w;
#   370:output reg  [THR_WIDTH-1:0] alu_dst_cond_tid_w
#   388:input [width-1 : 0]  A,B;
# split by ":" |  388:input [width-1 : 0]  A,B;
# split0       |   0 ^      1        ^  2
split0    = o_io_line.split(':')
line_num  = int(split0[0]) - 1   # -1 because egrep form 1, our line from 0
code_line = ':'.join(split0[1:])
# valid code line is code_line del note, and change all \s+ to ' '
valid_code_line = re.sub('(//.*)|(^\s+)|(\s+$)','',code_line)
valid_code_line = re.sub('\s+',' ',valid_code_line)
valid_code_line = re.sub('\W*$', '',valid_code_line)# del end ";" or ","
# io type is the first word in valid_code_line
match_io_type   = re.match('(?P<io_type>\w+)\s*(?P<other>.*)',valid_code_line)
assert(match_io_type)
io_type         = match_io_type.group('io_type')
other           = match_io_type.group('other').strip(' ')
# other: [width-1 : 0]  A,B | wire [127:0] alu_frf_data_p0_w | alu_frf_part_p0_w
# get name, name is the last word or words sep by ',' ; reverse it and reverse back
# exp: A | A,B | A,B,C
match_name = re.match('\s*(?P<r_names_str>\w+(\s*,\s*\w+)*)\s*(?P<r_other>.*)',other[::-1])
assert(match_name),'%s | %s'%(other,code_line)
other      = (match_name.group('r_other')[::-1]).strip(' ')
names_str  = match_name.group('r_names_str')[::-1]
names      = re.sub('\s+','',names_str).split(',')
names_pos  = []
if len(names) == 1:
colum = re.search('\W%s(\W|$)'%(names[0]),code_line).span()[0] + 1
names_pos = [ ( line_num, colum ) ]
else:
for n in names:
colum = re.search('\W%s(\W|$)'%(n),code_line).span()[0] + 1
names_pos.append( (line_num, colum) )
# signal_type is the first word of other, maybe empty
# case0 : empty
# case1 : reg
# case2 : reg  [THR_WIDTH-1:0]
# case3 : [127:0]
signal_type  =  'wire'
if other:
match_signal_type = re.match('\s*(?P<signal_type>\w*)\s*(?P<other>.*)',other)
assert(match_signal_type)
m_signal_type = match_signal_type.group('signal_type')
if m_signal_type:
signal_type = m_signal_type
other = match_signal_type.group('other').strip(' ')
# other is empty or [a : b]
left_index   =  ''
right_index  =  ''
size         =  1
if other:
assert(other[0] == '[' and other[-1] == ']'),'%s'%(other)
indexs = other[1:-1].split(':')
if len(indexs) == 2:
left_index  = indexs[0].strip(' ')
right_index = indexs[1].strip(' ')
try:
left_index  = int(left_index)
right_index = int(left_index)
size        = right_index - left_index + 1
except:
size        = other
# may a line has mulity names
io_infs = {}
for i, name in enumerate(names):
io_infs[name] = {
"name"        : name
, "io_type"     : io_type
, "left"        : left_index
, "right"       : right_index
, "size"        : size
, 'line_num'    : line_num
, 'name_pos'    : names_pos[i]
, 'code_line'   : code_line
, 'signal_type' : signal_type
}
return {'io_infs':io_infs, 'name_list':names}

#------------------------------------------------
# for code in verilog modules, from pos to find next pair ")"
# case 0:
# if pos is "(" | ( A...B )
# pos           | ^
# rest          |  parm_line= A...B,  end_pos  = B 's pos
# case 1:
# if pos not "("| ( A...B )
# pos           |   ^
# rest          |   parm_line= A...B,  end_pos  = B 's pos
def get_str_to_next_right_bracket(module_lines, pos):
assert(0),'not used not realized '

def get_str_to_pre_left_bracket(module_lines, pos):
assert(0),'not used not realized '

#-------------------------------------------
# for situation:
# case0  : module_name inst_name (.a(A), .b(B), .c(C)) |
#        |                        ^                    | input pos
#        | ^0          ^1                              | module_range[0]
# case1  : module_name #( .a(A), .b(B), .c(C) ) inst_name ( ... )
#        |                ^                            | input pos
#        | ^                                           | module_range[0]
# case2  : module_name #( A, B, C ) inst_name ( .x(X), .y(Y) )
#        |                                      ^      | input pos
#        | ^                                           | module_range[0]
# case3  : module_name ... inst_name[a:b] ...
# case4  : module_name ... inst_name[a:b] (A,B,C)
def get_verilog_sub_module_inf_from_dot_line( pos, module_lines, module_start_line_num):
dot_line = get_valid_code(module_lines[pos[0]])
assert(dot_line[pos[1]] == '.')
module_name =  ''
inst_name   =  ''
match_range =  []
match_pos   =  ()
# first deal pre dot line
pre_line_end       = False
dot_pre_line       = dot_line[:pos[1]+1] # module_name inst_name (.
pre_next_line_num  = pos[0] - 1
search_case0       = ''
search_case12      = ''
while not pre_line_end:
semicolon_y    = dot_pre_line.find(';')
if semicolon_y != -1:
pre_line_end = True
dot_pre_line = dot_pre_line[semicolon_y + 1:]
search_case0 = re.search('(^|\W)(?P<m_name>\w+)\s+(?P<i_name>\w+(\s*\[[^\[\]]*\])?)\s*\(\s*\.$',dot_pre_line)
if search_case0:
module_name    = search_case0.group('m_name')
inst_name      = search_case0.group('i_name')
break
search_case12 = re.search('(^|\W)(?P<m_name>\w+)\s*#\s*\(', dot_pre_line)
if search_case12:
module_name    = search_case12.group('m_name')
match_case2_inst_name   = re.match('\.\s*\(\s*(?P<r_i_name>(\s*\][^\[\]]*\[\s*)?\w+)',dot_pre_line[::-1]) # inst_name ( .
if match_case2_inst_name:
inst_name      = match_case2_inst_name.group('r_i_name')[::-1]
break
if pre_next_line_num >= 0:
dot_pre_line = get_valid_code(module_lines[pre_next_line_num]) + ' ' + dot_pre_line
pre_next_line_num -= 1
else:
pre_line_end = True
# if not match anyone then unrecgize
if not (search_case0 or search_case12):
PrintDebug('Error: 0 cur dot match cannot recgnize ! line: %s , pos: %s'%(dot_line, pos.__str__()))
return False
# if no inst name need decode dot back line
if not inst_name:  # case1: module_name #( .a(A), .b(B), .c(C) ) inst_name ( ... )
back_line_end       = False
dot_back_line       = dot_line[pos[1]:] # .a(A), .b(B), .c(C))
back_next_line_num  = pos[0] + 1
search_case1_inst_name = ''
while not back_line_end:
semicolon_y    = dot_back_line.find(';')
if semicolon_y != -1:
back_line_end = True
dot_back_line = dot_back_line[:semicolon_y]
# inst_name ( .x
search_case1_inst_name = re.search('\)\s*(?P<i_name>\w+(\s*\[[^\[\]]*\])?)\s*\(',dot_back_line)
if search_case1_inst_name:
inst_name = search_case1_inst_name.group('i_name')
break
if back_next_line_num < len(module_lines):
dot_back_line = dot_back_line + ' ' +get_valid_code(module_lines[back_next_line_num])
back_next_line_num += 1
else:
back_line_end = True
if not inst_name:
PrintDebug('Error: 1 cur dot match cannot recgnize inst name ! line: %s , pos: %s'%(dot_line, pos.__str__()))
return False
match_range    = [ pre_next_line_num + 1 + module_start_line_num, -1 ]
module_y       = module_lines[pre_next_line_num + 1].find(module_name)
assert(module_y != -1)
match_pos      = ( pre_next_line_num + 1 + module_start_line_num, module_y )
return {
'inst_name'     : inst_name
,'module_name'   : module_name
,'match_range'   : match_range
,'match_pos'     : match_pos
}

# case 0: dff # (...) my_dff(a, b, c);  in only one line
def get_verilog_sub_module_inf_from_pound_line( pos, module_lines, module_start_line_num):
pound_line = get_valid_code(module_lines[pos[0]])
match_sub  = re.match('\s*(?P<module_name>\w+)\s+#\s*\(.*\)\s*(?P<inst_name>\w+)\s*\(.*\)\s*;\s*', pound_line)
if match_sub:
return {
'inst_name'   : match_sub.group('inst_name')
,'module_name' : match_sub.group('module_name')
,'match_range' : [ pos[0] + module_start_line_num, pos[0] + module_start_line_num ]
,'match_pos'   : ( pos[0] + module_start_line_num, module_lines[pos[0]].find(match_sub.group('module_name')) )
}
return False

# for current valid module lines
# find each pair           : (".xxx(...)"  ";")
# get the each pair result :{  'inst_name'     : inst_name
# ,'module_name'   : modu_name
# ,'match_range'   : match_range
# ,'match_pos'     : match_pos}
# finial result is         : [ pair_result0, pair_result1, ... ]
def get_verilog_sub_module_inf(module_lines, module_start_line_num, gen_vtags_log_path = ''):
sub_module_inf        = []
has_call_sub_not_end  = False
find_next = True
for i ,l in enumerate(module_lines):
if find_next:
assert(not has_call_sub_not_end),'already start new search, should not has unfinish subcall'
cur_sub_module_inf   = {}
cur_match_right_part = ''
if l.find('.') != -1:
l  = get_valid_code(l)
s0 = re.search('(^|\W)\.\w+\s*\(', l)
if not s0:
continue
# no matter recgnize or not , must wait next ";", continue search
find_next = False
# get dot pos
dot_colm = ''
if l[0] is '.':
dot_colm = 0
else:
dot_colm = s0.span()[0] + 1
assert(dot_colm != '')
cur_match_right_part = l[s0.span()[1]:]
# get cur sub module inf
cur_sub_module_inf = get_verilog_sub_module_inf_from_dot_line( (i, dot_colm), module_lines, module_start_line_num)
elif l.find('#') != -1:
l  = get_valid_code(l)
s1 = re.search('#\s*\(', l)
if not s1:
continue
# no matter recgnize or not , must wait next ";", continue search
find_next = False
# get dot pos
pound_colm = ''
dot_colm = s1.span()[0]
cur_match_right_part  = l[s1.span()[1]:]
# get cur sub module inf
cur_sub_module_inf = get_verilog_sub_module_inf_from_pound_line( (i, pound_colm), module_lines, module_start_line_num)
else:
continue
# find result in two way
if cur_sub_module_inf:
assert(not has_call_sub_not_end)
sub_module_inf.append(cur_sub_module_inf)
has_call_sub_not_end = True
else:
PrintDebug( 'Error : not recgnize %d: %s '%(i+module_start_line_num, l ), gen_vtags_log_path )
# no matter find or not , current back line has valid ";", continue find new match
if cur_match_right_part.find(';') != -1:
find_next = True
# if end at current line, set the call range [1]
if has_call_sub_not_end and cur_match_right_part.find(';') != -1:
sub_module_inf[-1]['match_range'][1] = i + module_start_line_num # start line and end line the same
has_call_sub_not_end = False
continue
if (not find_next) and l.find(';') != -1:
if get_valid_code(l).find(';') != -1:
# if current not find next, and match a valid ";", need continue search
find_next = True
# if has unended sub call, and find a valid ";", set last call sub range[1]
if has_call_sub_not_end:
sub_module_inf[-1]['match_range'][1] = i + module_start_line_num # end line is the first ; line
has_call_sub_not_end = False
# if has_call_sub_not_end and (not find_next) and l.find(';') != -1:
if has_call_sub_not_end and l.find(';') != -1:
if get_valid_code(l).find(';') != -1:
sub_module_inf[-1]['match_range'][1] = i + module_start_line_num # end line is the first ; line
has_call_sub_not_end = False
if has_call_sub_not_end:
PrintDebug('Error : call sub not end at end module , try module end as callsub end ! : %s'%(sub_module_inf[-1].__str__()), gen_vtags_log_path)
sub_module_inf[-1]['match_range'][1] = len(module_lines) - 1 + module_start_line_num # end line is the first ; line
return sub_module_inf

#-------------------------------------------
#   modules_inf  = { module_name: module_inf }
#   defines_inf  = { macro_name : [ define_inf ] }
#   files_inf    = { file_name  : file_inf }
#       module_inf    = {  'module_name'        : module_name
#                         ,'file_path'          : f
#                         ,'line_range_in_file' : (module_start_line_num, module_end_line_num)
#                         ,'module_pos'         : module_pos
#                         ,'sub_modules'        : sub_modules }
#       define_inf    = {  "name" : xxx
#                         ,"path" : f
#                         ,"pos"  : (line_num, colum_num)  # name first char pos
#                         ,'code_line' : `define xxx .... }
#       file_inf      = {  'glb_defines'   : [ define_inf ]
#                         ,'module_infs'   : [ module_inf ]
#                         ,'module_calls'  : [ call_sub_inf ]
#                         ,'file_edit_inf' : { 'create_time': ..., 'last_modify_time': ...}
#                       call_sub_inf  =  { 'inst_name'     : inst_name
#                                         ,'module_name'   : module_name
#                                         ,'match_range'   : match_range
#                                         ,'match_pos'     : match_pos }
def gen_modules_and_defines_inf(files_inf):
modules_inf                   = {}
global_defines_inf            = {}
for c_file_path in files_inf:
c_file_inf               = files_inf[c_file_path]
# merge defines
c_file_glb_defines       = c_file_inf['glb_defines']
for d in c_file_glb_defines:
d_name = d['name']
global_defines_inf.setdefault(d_name,[])
global_defines_inf[d_name].append(d)
# merge modules_inf
c_file_module_infs       = c_file_inf['module_infs']
for m in c_file_module_infs:
mn = m['module_name']
if mn in modules_inf:
PrintDebug('Error: module %s has multip defines ! in %s '%(mn, [ modules_inf[mn]['file_path'], m['file_path'] ].__str__() ))
else:
modules_inf.setdefault(mn, None)
modules_inf[mn] = m
return modules_inf, global_defines_inf

def updata_file_pickle_inf(path):
PrintDebug('Care: updata database, file: %s'%(path))
if get_file_path_postfix(path) not in G['SupportVerilogPostfix']:
PrintDebug('Warning: updata_file_pickle_inf: file not verilog file ! file: %s'%(path))
return False
if not os.path.isfile(path):
PrintDebug('Error: updata_file_pickle_inf: file not exit ! file: %s'%(path))
return
new_file_modules_inf = get_single_verilog_file_code_inf(path)
glb_defines          = new_file_modules_inf['glb_defines']    #[ define_inf ]
module_infs          = new_file_modules_inf['module_infs']    #[ module_inf ]
# updata files_inf
if path not in G['FileInf']:
# if add new inf just add
G['FileInf'][path] = new_file_modules_inf
# add glb_defines
for gd in glb_defines:
gd_name = gd['name']
G['CodeDefineInf'].setdefault(gd_name,[])
G['CodeDefineInf'][gd_name].append( gd )
# add module infs
for m_inf in module_infs:
m_name = m_inf['module_name']
if m_name in G['ModuleInf']:
PrintDebug('Error: module %s define twice ! used last at %s, %s'%(m_name, G['ModuleInf'][m_name]['file_path'], path))
G['ModuleInf'][m_name] = m_inf
else:
# need refresh old and add new, so just gen new inf
G['FileInf'][path] = new_file_modules_inf
G['ModuleInf'], G['CodeDefineInf'] = gen_modules_and_defines_inf(G['FileInf'])
# update pickles
if not os.path.isdir(G['VTagsPath']):
os.system('mkdir -p '+G['VTagsPath'])
fp = open(G['VTagsPath'] + '/files_inf.py','w')
fp.write('FileInf = %s \n'%(G['FileInf'].__str__()))
fp.write('HDLTagsActive = True \n')
fp.close()

def get_module_inf(module_name):
if module_name not in G['ModuleInf']:
PrintDebug('Warning:get_module_inf: "%s" not konwn module !'%(module_name) )
return False
module_inf       = G['ModuleInf'][module_name]
module_path      = module_inf['file_path']
cur_inf_time     = G['FileInf'][module_path]['file_edit_inf']['last_modify_time']
last_modify_time = os.path.getmtime(module_path)
# cur module file not modify, then inf valid and return
if cur_inf_time == last_modify_time:
return module_inf
# if cur module file modify , update Module_inf and return new
updata_file_pickle_inf(module_path)
return get_module_inf(module_name)

#----------------------------------------------------
def get_line_inf_from_cur_file_inf(line_num, file_inf):
line_module_inf   = {}
line_call_sub_inf = {}
module_infs  = file_inf['module_infs' ] #[ module_inf ]
module_calls = file_inf['module_calls'] #[ call_sub_inf ]
# first get current line module inf
for m_inf in module_infs:
c_module_range = m_inf['line_range_in_file']
if c_module_range[1] < line_num:
continue
if line_num < c_module_range[0]:
break
line_module_inf = m_inf
# second get current line call sub inf
for c_inf in module_calls:
c_call_range = c_inf['match_range']
if c_call_range[1] < line_num:
continue
if line_num < c_call_range[0]:
break
line_call_sub_inf = c_inf
return  {
'line_module_inf'   : line_module_inf
,'line_call_sub_inf' : line_call_sub_inf
}

def get_file_line_inf(line_num, path = ''):
if not path:
path = vim.current.buffer.name
if get_file_path_postfix(path) not in G['SupportVerilogPostfix']:
PrintDebug('Warning: get_file_line_inf: file not verilog file ! file: %s'%(path))
return False
if path not in G['FileInf']:
updata_file_pickle_inf(path)
if path not in G['FileInf']:
PrintDebug('Warning: get_file_line_inf: %s has no file database !'%(path) )
return False
cur_inf_time     = G['FileInf'][path]['file_edit_inf']['last_modify_time']
last_modify_time = os.path.getmtime(path)
# cur module file not modify, then inf valid and return
if cur_inf_time == last_modify_time:
return get_line_inf_from_cur_file_inf( line_num, G['FileInf'][path] )
# if cur module file modify , update Module_inf and return new
updata_file_pickle_inf(path)
return get_file_line_inf(line_num, path)

#----------------------------------------------
# { module_name:'', 'call_inf':atom}

def get_module_last_call_inf(module_name):
if module_name not in G['ModuleLastCallInf']:
return False
upper_module_name = G['ModuleLastCallInf'][module_name]['upper_module_name']
upper_inst_name   = G['ModuleLastCallInf'][module_name]['upper_inst_name']
if upper_module_name not in G['ModuleInf']:
return False
if upper_inst_name not in G['ModuleInf'][upper_module_name]['sub_calls']:
return False
upper_call_inf = G['ModuleInf'][upper_module_name]['sub_calls'][upper_inst_name]
return {'upper_module_name': upper_module_name, 'upper_call_inf': upper_call_inf}

def set_module_last_call_inf(sub_module_name, upper_module_name, upper_inst_name):
G['ModuleLastCallInf'][sub_module_name] = { 'upper_module_name': upper_module_name, 'upper_inst_name': upper_inst_name }

#----------------------------------------------
# for a module's submodule, sep function module and base module
def get_sub_func_base_module(module_name):
func_modules   = {} # inst:module
base_modules   = {} # module : [inst0,inst1...]
sub_modules    = []
if module_name in G['ModuleInf']:
sub_modules = G['ModuleInf'][module_name]['sub_modules']
for sm in sub_modules:
inst_name   =  sm['inst_name']
module_name =  sm['module_name']
if module_name in G['BaseModuleInf']['BaseModules']:
base_modules.setdefault(module_name,[])
base_modules[module_name].append(inst_name)
else:
if inst_name in func_modules: # has to same inst name, may be use `ifdefine sep
new_inst_name = inst_name+'_'+str(sm['match_range'][0])
func_modules[new_inst_name] = sm
continue
func_modules[inst_name] = sm
return func_modules, base_modules

#----------------------------------------------
# update function base information, no need added each times
def update_base_module_pickle():
pkl_output = open(G['VTagsPath'] + '/base_modules.pkl','wb')
pickle.dump(G['BaseModuleInf']['BaseModules'], pkl_output)
pkl_output.close()

#----------------------------------------------
# topo/checkpoint/basemodule line range ,in frame file
def get_frame_range_inf():
fram_file_link = G["VimBufferLineFileLink"][G['Frame_Inf']['Frame_Path']]
# get topo range , default 0,0
has_topo          = False
has_check_point   = False
has_base_module   = False
topo_range        = [0, 0]
check_point_range = [0, 0]
base_module_range = [0, 0]
for i,link in enumerate(fram_file_link):
if link and (link['type'] == 'topo'):
if not has_topo:
topo_range[0] = i
has_topo      = True
topo_range[1] = i
if link and (link['type'] == 'check_point'):
if not has_check_point:
check_point_range[0] = i
has_check_point      = True
check_point_range[1] = i
if link and (link['type'] == 'base_module'):
if not has_base_module:
base_module_range[0] = i
has_base_module      = True
base_module_range[1] = i
# if no topo ,next topo start at [0,0]
if not has_topo:
topo_range = [0, 0]
# check point initial start at topo end + 2
if not has_check_point:
check_point_range[0] = topo_range[1] + 2
check_point_range[1] = topo_range[1] + 2
# base module initial at check point end + 2
if not has_base_module:
base_module_range[0] = check_point_range[1] + 2
base_module_range[1] = check_point_range[1] + 2
return { 'topo_range'        : tuple(topo_range)
,'check_point_range' : tuple(check_point_range)
,'base_module_range' : tuple(base_module_range)
,'has_topo'          : has_topo
,'has_check_point'   : has_check_point
,'has_base_module'   : has_base_module }

#----------------------------------------------------
def get_submodule_match_patten(all_module_name):
patten_char_set_list = []
len_2_modules = {}
for m_n in all_module_name:
l = len(m_n)
len_2_modules.setdefault(l,[])
len_2_modules[l].append(m_n)
l_pattens = []
for l in len_2_modules:
l_m = len_2_modules[l]
l_patten = '(['+ (']['.join(map(''.join, map(set,zip(*l_m))))) + '])'
l_pattens.append(l_patten)
patten = '(' + '|'.join(l_pattens) + ')'
return patten

#----------------------------------------------------
def get_single_verilog_file_module_inf(f):
all_module_start_end_lines = os.popen('egrep -n -h \'^\s*(module|endmodule)\>\' %s'%(f)).readlines()
cur_file_module_inf = []
has_module_not_end  = False
i = 0
while i < len(all_module_start_end_lines):
cur_start_end_line      = all_module_start_end_lines[i]
cur_start_end_line_num  = int(cur_start_end_line.split(':')[0]) - 1
cur_start_end_line_code = ':'.join( cur_start_end_line.split(':')[1:] )
match_module_start = re.match('\s*module\s+(?P<name>(|`)\w+)', cur_start_end_line_code) # some module use macro as name so (|`)
if match_module_start:
module_name           = match_module_start.group('name')
module_start_line_num = cur_start_end_line_num
module_pos            = ( module_start_line_num, cur_start_end_line_code.find(module_name) )
# if pre module not end, set new module start pre line as pre module end line
if has_module_not_end:
PrintDebug('Error: module:"%s" in file:"%s", no "endmodule" !'%(cur_file_module_inf[-1]['module_name'],f) )
cur_file_module_inf[-1]['line_range_in_file'][1] = module_start_line_num - 1
cur_file_module_inf.append(
{  'module_name'        : module_name
,'file_path'          : f
,'line_range_in_file' : [module_start_line_num, -1]
,'sub_modules'        : None  # []
,'module_pos'         : module_pos
}
)
has_module_not_end = True
i += 1
continue
match_module_end  = re.match('\s*endmodule(\W|$)', cur_start_end_line_code)
if match_module_end:
if not has_module_not_end:
PrintDebug( 'Error: line: %s "endmodule" has no correlation module define ! file: %s '%(match_module_end,f) )
continue
module_end_line_num = cur_start_end_line_num
cur_file_module_inf[-1]['line_range_in_file'][1] = module_end_line_num
has_module_not_end  = False
i += 1
continue
i += 1
if has_module_not_end:
PrintDebug( 'Error: module:"%s" in file:"%s", no "endmodule" !'%(cur_file_module_inf[-1]['module_name'],f) )
return cur_file_module_inf

# for current file line match all patten: `define xxx ....
# patten_result = {
#     "name" : xxx
#    ,"path" : f
#    ,"pos"  : (line_num, colum_num)  # name first char pos
#    ,'code_line' : `define xxx ....
# }
# finial return [ patten_result0, patten_result1 ]
def get_single_verilog_file_define_inf(f):
global_define_inf = []
global_define_lines = os.popen('egrep -n -h \'^\s*`define\W\' %s'%(f)).readlines()
for l in global_define_lines:
split0      = l.split(':')
line_num    = int(split0[0]) - 1
code_line   = ':'.join(split0[1:])
match_name  = re.match('\s*`define\s*(?P<name>\w+)',code_line)
name        = ''
colum_num   = -1
if match_name:
name        = match_name.group('name')
colum_num   = code_line.find(name)
if colum_num != -1:
global_define_inf.append(
{ "name" : name
,"path" : f
,"pos"  : (line_num, colum_num)
,'code_line' : code_line }
)
return global_define_inf

def get_single_line_sub_call_inf(egrep_line, all_module_names):
sp     = egrep_line.split(':')
l_num  = int(sp[0]) - 1
l_code = re.sub('//.*', '', ':'.join(sp[1:]))
if l_code.find(';') == -1:
return False
# match_name = re.match('\s*(?P<m_n>(|`)\w+)\s*(?P<other>.*;)\s*$',l_code)
match_name = re.match('\s*(?P<m_n>(|`)\w+)\s*(?P<other>.*;)',l_code)
assert(match_name),'%s,%s'%(egrep_line, l_code)
module_name = match_name.group('m_n')
if module_name not in all_module_names:
return False
other  =  match_name.group('other')
inst_name_patten = '\w+((\s*\[[^\[\]]*\])|)'
search_i_n = re.search('(^(?P<i_n0>%s))|(#.*\)\s*(?P<i_n1>%s)\s*\()'%(inst_name_patten,inst_name_patten),other)
if not search_i_n:
PrintDebug( 'Warning: match module name %s, but no inst name !' )
return False
inst_name = search_i_n.group('i_n0')
if not inst_name:
inst_name = search_i_n.group('i_n1')
assert(inst_name)
return {
'module_name': module_name
,'inst_name'  : inst_name
,'match_range': [l_num, l_num]
,'match_pos'  : [l_num, l_code.find(module_name)]
}

def get_mult_line_sub_call_inf(egrep_line, f_lines, all_module_names):
sp        = egrep_line.split(':')
l_num     = int(sp[0]) - 1
code_line = re.sub('//.*', '', ':'.join(sp[1:]))
# get module name
module_name = ''
module_pos  = (-1,-1)
match_name  = re.match('^\s*(?P<m_n>(|`)\w+)\s*(?P<other>.*)',code_line)
assert(match_name)
module_name = match_name.group('m_n')
if module_name not in all_module_names:
return False
module_pos = (l_num, code_line.find(module_name))
# get inst name
inst_name = ''
inst_name_patten = '\w+((\s*\[[^\[\]]*\])|)'
other  =  match_name.group('other')
i = l_num + 1
max_i = len(f_lines)
line_end = False
while not other and i < max_i and not line_end:
next_code_line_with_semi = re.sub('((^\s+)|(^\s*`.*)|(//.*))','',f_lines[i].strip('\n'))
next_code_line_no_semi   = re.sub(';.*','',next_code_line_with_semi)
other = next_code_line_no_semi
if len(next_code_line_no_semi) != len(next_code_line_with_semi):
line_end = True
i += 1
match_inst_name_no_parm = re.match('^(?P<i_n>%s)'%(inst_name_patten),other)
if match_inst_name_no_parm:
inst_name = match_inst_name_no_parm.group('i_n')
elif other[0] != '#':
PrintDebug('Warning: un recgnize 0 module match ! %s ||| %s'%(egrep_line, other))
return False
# del has parm inst_name
search_inst_name_has_parm = re.search('#\s*\(.*\)\s*(?P<i_n>%s)\s*\('%(inst_name_patten),other)
if search_inst_name_has_parm:
inst_name = search_inst_name_has_parm.group('i_n')
while i < max_i and not line_end:
next_code_line_with_semi = re.sub('((^\s+)|(^\s*`.*)|(//.*))','',f_lines[i].strip('\n'))
next_code_line_no_semi   = re.sub(';.*','',next_code_line_with_semi)
other = other +' '+next_code_line_no_semi
if len(next_code_line_no_semi) != len(next_code_line_with_semi):
line_end = True
i += 1
search_inst_name_has_parm = re.search('#\s*\(.*\)\s*(?P<i_n>%s)\s*\('%(inst_name_patten),other)
if search_inst_name_has_parm:
inst_name = search_inst_name_has_parm.group('i_n')
break
if not inst_name:
PrintDebug('Warning: un recgnize 1 module match ! %s ||| %d ||| %s '%(egrep_line, i, str(line_end) ) )
return False
# get cur call end line
end_line_num = max_i
while i < max_i and not line_end:
next_code_line = re.sub('(^`.*)|(//.*)','',f_lines[i])
if next_code_line.find(';') != -1:
line_end = True
break
i += 1
if not line_end:
PrintDebug('Warning: cur sub call no end ";" ! %s'%(egrep_line))
else:
end_line_num = i
# return result
return {
'module_name': module_name
,'inst_name'  : inst_name
,'match_range': [l_num, end_line_num]
,'match_pos'  : module_pos
}

def get_single_verilog_file_subcall_inf(f, patten, all_module_names):
egrep_match_lines  = os.popen('egrep -n -h \'^\s*(%s)\>\' %s'%(patten,f)).readlines()
# start get sub call inf
if not egrep_match_lines:
return []
file_sub_call_infs = []
c0_cnt = 0
c1_cnt = 0
f_lines = open(f,'r').readlines()
for egrep_l in egrep_match_lines:
# case0: signal line call
c0_rst = get_single_line_sub_call_inf(egrep_l, all_module_names)
if c0_rst:
c0_cnt += 1
file_sub_call_infs.append(c0_rst)
continue
# case1: mult line call
c1_rst = get_mult_line_sub_call_inf(egrep_l, f_lines, all_module_names)
if c1_rst:
c1_cnt += 1
file_sub_call_infs.append(c1_rst)
continue
PrintDebug('subcall: one_line/mult_line = %d/%d'%( c0_cnt,c1_cnt) )
return file_sub_call_infs

def add_single_verilog_file_submodule_inf_to_module_inf( file_module_inf, file_subcall_inf ):
s_inf_i = 0
for m_inf in file_module_inf:
m_inf['sub_modules'] = []
m_inf['sub_calls'] = {}
m_range = m_inf['line_range_in_file']
while s_inf_i < len(file_subcall_inf):
s_range = file_subcall_inf[s_inf_i]['match_range']
# cur subcall in cur module
if m_range[0] <= s_range[0] and s_range[1] <= m_range[1]:
m_inf['sub_modules'].append(file_subcall_inf[s_inf_i])
m_inf['sub_calls'][file_subcall_inf[s_inf_i]['inst_name']] = file_subcall_inf[s_inf_i]
s_inf_i += 1
continue
elif s_range[0] < m_range[0]:
PrintDebug('Error: subcall %s not in valid module !'%(file_subcall_inf[s_inf_i].__str__()))
s_inf_i += 1
elif s_range[1] > m_range[1]:
if s_range[0] < m_range[0]:
PrintDebug('Error: subcall %s cross two module !'%(file_subcall_inf[s_inf_i].__str__()))
break
else:
assert(0)
return

def get_single_verilog_file_code_inf(f):
# gen cur module and define inf
new_file_module_inf = get_single_verilog_file_module_inf(f)
new_file_define_inf = get_single_verilog_file_define_inf(f)
# gen new all_module_names, del old current file add new
new_module_names    = set([ mi['module_name'] for mi in new_file_module_inf ])
old_file_module_inf = G['FileInf'][f]['module_infs']
old_module_names    = set([ mi['module_name'] for mi in old_file_module_inf ])
all_module_name     = ( set(G['ModuleInf']) - old_module_names ) | new_module_names
# get file sub call inf
patten = get_submodule_match_patten(all_module_name)
new_file_subcall_inf = get_single_verilog_file_subcall_inf(f, patten, all_module_name)
# merge to file_inf
add_single_verilog_file_submodule_inf_to_module_inf( new_file_module_inf, new_file_subcall_inf )
new_file_inf = {
'glb_defines'   : new_file_define_inf
,'module_infs'   : new_file_module_inf
,'module_calls'  : new_file_subcall_inf
,'file_edit_inf' : { 'create_time': os.path.getctime(f), 'last_modify_time': os.path.getmtime(f)}
}
return new_file_inf

def show_progress_bar( i, i_max, show_char = '#', show_width = 20):
i += 1 # count from 1
i_max_len = len(str(i_max))
i_len     = len(str(i))
i_str     = ' '*(i_max_len-i_len)+str(i)
i_max_str = str(i_max)
prefix    = '%s/%s: '%(i_str,i_max_str)
pass_str  = show_char*((i*show_width)/i_max)
empty_str = ' '*(show_width - len(pass_str))
progress_bar = '[%s%s]'%(pass_str,empty_str)
tool_len  = len(prefix) + show_width
sys.stdout.write(' '*tool_len + '\r')
sys.stdout.flush()
sys.stdout.write(prefix + progress_bar)

""" https://my.oschina.net/u/2520885 """
#===============================================================================
# Copyright (C) 2016 by Jun Cao

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#===============================================================================

import sys
import re
import os
try:
import vim
except:
pass
import GLB
G = GLB.G
from Base import*
import View
PrintReport = View.PrintReport

########################################################
def get_sub_io_signal_name_from_sub_call_line(call_line, y):
word = get_full_word(call_line, y)
# if | .xxx(xxxx)
#  y |   ^
#    |     ^    ^ // call_sub_assign_signal_str
# cur_word is sub_io_signal_name
if re.match('\w+\.', call_line[:y+1][::-1]):
call_sub_assign_signal_str = re.sub('(^\w*)|(\.\w+\(.*)', '', call_line[y:])
call_sub_signals = set( re.findall('\w+',call_sub_assign_signal_str) )
sub_call_io      = word
return { 'call_sub_signals': call_sub_signals
,'sub_call_io'     : word
,'sub_call_io_num' : None }
# if | .xxx(xxxx)
#  y |        ^
#    |     ^    ^ // call_sub_assign_signal_str
s0 = re.search('\(\s*(?P<sub_call_io>\w+)\.',call_line[:y+1][::-1])
if s0:
sub_call_io = s0.group('sub_call_io')[::-1]
call_sub_assign_and_right = call_line[y-s0.span()[0]:]
assert(call_sub_assign_and_right[0] == '(')
call_sub_assign_signal_str = re.sub('\.\w+\s*\(.*', '', call_line[y:])
call_sub_signals = set( re.findall('\w+',call_sub_assign_signal_str) )
return { 'call_sub_signals': call_sub_signals
,'sub_call_io'     : sub_call_io
,'sub_call_io_num' : None }
# if module_name #(parm) inst_name( a, b,     c)
# if module_name         inst_name( a, b,     c)
#                                      y
# call_sub_signals                     set(b)
# sub_call_io_num                      1
# sub_call_io                          ''
if word:
s1 = re.search('\)\s*\w+\s*\(',call_line[:y+1])
if not s1:
s1 = re.match('\s*\w+\s*\w+\s*\(',call_line[:y+1])
full_match_s1 = True
if s1:
pre_sub_call_signal_str = call_line[s1.span()[1]:y+1]
pre_sub_call_signals    = pre_sub_call_signal_str.split(',')
assert(pre_sub_call_signals)
for sc in pre_sub_call_signals:
if not re.match('\s*(\w+)|(\w+\s*\[[^\[\]]+\])\s*$',sc):
full_match_s1 = False
if full_match_s1:
return { 'call_sub_signals': set([word])
,'sub_call_io'     : ''
,'sub_call_io_num' : len(pre_sub_call_signals) - 1 }
return None

# if has io_name return cur io inf
# else return all io inf of current module
#io_inf =
#      "name"        : name
#    , "io_type"     : io_type
#    , "left"        : left_index
#    , "right"       : right_index
#    , "size"        : size
#    , 'line_num'    : line_num
#    , 'name_pos'    : (line_num, colm_num)
#    , 'code_line'   : code_line
#    , 'signal_type' : signal_type }
def get_io_inf(module_name, io_name = ''):
module_inf   = get_module_inf(module_name)
if not module_inf:
return False
module_path  = module_inf['file_path']
module_range = module_inf['line_range_in_file']
if io_name: # get cur io inf
io_inf       = {}
io_lines     =  os.popen('sed -n \'%d,%dp\' %s | egrep -n -h \'^\s*(input|output)\>.*\<%s\>\''%(module_range[0]+1, module_range[1]+1, module_path, io_name)).readlines()
if len(io_lines) == 0:
PrintDebug('Error: module: %s \'s io: %s define not found !'%(module_name,io_name))
return False
if len(io_lines) > 1:
l_i = 0
while l_i < len(io_lines):
if not re.search('\W%s(\W|)'%(io_name), re.sub('//.*','',io_lines[l_i])):
del io_lines[l_i]
continue
l_i += 1
continue
if len(io_lines) > 1:
PrintDebug('Error: module: %s \'s io: %s define multiple times !'%(module_name,io_name))
line = io_lines[0]
assert(line.find(io_name) != -1)
io_inf = decode_egreped_verilog_io_line(line)['io_infs']
if io_name in io_inf:
# because use "sed ... | grep ..." so the line number is not the real number need add sed started line num
io_inf[io_name]['line_num'] = io_inf[io_name]['line_num'] + module_range[0]
io_inf[io_name]['name_pos'] = ( io_inf[io_name]['line_num'], io_inf[io_name]['name_pos'][1] )
return io_inf[io_name]
else:
PrintDebug('Warning: get_io_inf, io_name is parm name ,not a io !')
return False
else: # get module all io inf
all_io_inf    = []
cur_module_code_range = module_inf['line_range_in_file']
all_io_lines  =  os.popen('sed -n \'%d,%dp\' %s | egrep -n -h \'^\s*(input|output)\>\''%(cur_module_code_range[0]+1, cur_module_code_range[1]+1, module_path)).readlines()
for line in all_io_lines:
line      = line.rstrip('\n')
egrep_io_infs = decode_egreped_verilog_io_line(line)
io_inf        = egrep_io_infs['io_infs']
name_list     = egrep_io_infs['name_list']
if not io_inf:
PrintDebug('Error: module: %s, line: %s, can not decode by decode_egreped_verilog_io_line() ! file: %s'(module_name, line, module_path))
continue
for io_name in name_list:
assert(io_name in io_inf)
c_io_inf = io_inf[io_name]
c_io_inf['line_num'] = c_io_inf['line_num'] + cur_module_code_range[0]
c_io_inf['name_pos'] = (c_io_inf['line_num'], c_io_inf['name_pos'][1])
all_io_inf.append( c_io_inf )
return all_io_inf

def get_module_call_sub_module_io_inf(call_line, io_pos, call_file_path):
call_line_num  = io_pos[0]
# if database has no this file return
if call_file_path not in G['FileInf']:
PrintDebug("Warning: get_module_call_sub_module_io_inf : cur file has not in hdltags database, file: %s !"%(call_file_path))
return False
file_line_inf     = get_file_line_inf(call_line_num, call_file_path)
line_call_sub_inf = {}
line_module_inf   = {}
if file_line_inf:
line_call_sub_inf = file_line_inf['line_call_sub_inf']
line_module_inf   = file_line_inf['line_module_inf']
# if cursor line not no sub call , return
if not line_call_sub_inf:
PrintDebug("Warning: get_module_call_sub_module_io_inf: cur line %d not on sub call ! "%(call_line_num))
return False
sub_call_signal_inf    = get_sub_io_signal_name_from_sub_call_line(call_line, io_pos[1]) # may be parm
# call module name
assert(line_module_inf),'is in sub call, must be valid mudule'
call_module_name  = line_module_inf['module_name']
# valid cursor on sub call
sub_module_name   = line_call_sub_inf['module_name']
sub_module_path   = ''
sub_module_inf    = get_module_inf(sub_module_name)
if sub_module_inf:
sub_module_path  = sub_module_inf['file_path']
# sub_match_pos means cursor call io signal in sub module io pos
sub_io_inf        = {}
call_sub_signals  = set()
if sub_call_signal_inf:
call_sub_signals = sub_call_signal_inf['call_sub_signals']
sub_call_io      = sub_call_signal_inf['sub_call_io']
sub_call_io_num  = sub_call_signal_inf['sub_call_io_num']
if sub_call_io:
sub_io_inf    = get_io_inf(sub_module_name, sub_call_io)
elif sub_call_io_num != None:
all_io_inf    = get_io_inf(sub_module_name)
assert(sub_call_io_num < len(all_io_inf))
sub_io_inf    = all_io_inf[sub_call_io_num]
sub_match_pos     = ()
sub_io_type       = ''
sub_io_line       = ''
sub_io_name       = ''
if sub_io_inf:
sub_io_name   = sub_io_inf['name']
sub_match_pos = sub_io_inf['name_pos']
sub_io_type   = sub_io_inf['io_type']
sub_io_line   = sub_io_inf['code_line']
return {
'sub_io_name'      : sub_io_name
,'sub_module_name'  : sub_module_name
,'sub_module_path'  : sub_module_path
,'sub_match_pos'    : sub_match_pos
,'sub_io_type'      : sub_io_type
,'sub_io_line'      : sub_io_line
,'sub_io_inf'       : sub_io_inf
,'call_sub_signals' : call_sub_signals
,'call_sub_inf'     : line_call_sub_inf
,'call_module_name' : call_module_name }

#########################function for trace##############################

# ok
def get_upper_module_call_io_inf(cur_module_name , cur_io_name):
cur_module_last_call_inf = get_module_last_call_inf(cur_module_name)
if not cur_module_last_call_inf:
PrintDebug("Warning: get_upper_module_call_io_inf: module %s, not called before, no upper module !"%(cur_module_name))
return False
upper_module_name  = cur_module_last_call_inf['upper_module_name']
upper_call_inf     = cur_module_last_call_inf['upper_call_inf']
upper_module_inf   = get_module_inf(upper_module_name)
assert(upper_module_inf),'upper module %s call %s before, upper should has inf in database !'%(upper_module_name, cur_module_name)
upper_module_path  = upper_module_inf['file_path']
# get upper call, match this signal pos
upper_call_lines   = open(upper_module_path,'r').readlines()
upper_call_pos     = upper_call_inf['match_pos'] # initial to call inst line
upper_matched      = False
for i in range( upper_call_inf['match_range'][0] , upper_call_inf['match_range'][1] + 1 ):
f0 = upper_call_lines[i].find(cur_io_name)
if f0 == -1:
continue
s0 = re.search('(?P<pre>^|\W)%s(\W|$)'%(cur_io_name) , re.sub('//.*','',upper_call_lines[i]))
if s0:
colum_num = s0.span()[0] + len(s0.group('pre'))
upper_call_pos = (i, colum_num)
upper_matched  = True
break
assert(upper_matched),'upper called so should be match, cur_io_name:%s, %s '%(upper_call_inf['match_range'].__str__(), cur_io_name)
upper_call_line   = upper_call_lines[upper_call_pos[0]]
return {
'module_name' : upper_module_name
,'call_pos'    : upper_call_pos
,'call_line'   : upper_call_line
,'module_path' : upper_module_path
}

def get_cur_appear_is_source_or_dest(key, code_lines, appear_pos):
a_x, a_y = appear_pos
appear_code_line = re.sub('(//.*)|(^\s*`.*)', '', code_lines[a_x] )
# case 0 cur pos in note return not source and dest
if len(appear_code_line) - 1 < a_y:
return 'None'
# case 1 is io
if (appear_code_line.find('input') != -1) or (appear_code_line.find('output') != -1):
match_io_type = re.match('\s*(?P<io_type>(input|output))\W',appear_code_line) # may input a,b,c
match_io_name = re.match('\s*[;,]?\s*(?P<r_names>\w+(\s*,\s*\w+)*)',appear_code_line[::-1]) # may input a,b,c
if match_io_type and match_io_name:
io_type  = match_io_type.group('io_type')
io_names = match_io_name.group('r_names')[::-1]
io_names = set(re.split('\s*,\s*',io_names))
if (io_type == 'input') and (key in io_names):
return 'Source'
if (io_type == 'output') and (key in io_names):
return 'Dest'
elif match_io_type:
PrintDebug('Error: recgnize_signal_assign_line: unrecgnize io line: '+appear_code_line)
return 'None'
# case 2 cur pos in case/casez/for/if (...key...) then it's dest
match_case2 = False
c2 = re.search( '(^|\W)(case|casez|for|if|while)\s*\(' , appear_code_line)
if c2:
appear_code_right_line = appear_code_line[c2.span()[1]:]
unmatch_bracket_count = 1
end_match_patten      = '^'
end_y                 = len(appear_code_right_line) - 1
all_brackets = re.findall('\(|\)', appear_code_right_line)
for b in all_brackets:
if b == '(':
unmatch_bracket_count += 1
else:
unmatch_bracket_count -= 1
end_match_patten = end_match_patten + '[^()]*\\'+b
if unmatch_bracket_count == 0:
end_y = re.search(end_match_patten, appear_code_right_line).span()[1] - 1
break
end_y = c2.span()[1] + end_y
if end_y >= a_y:
return 'Dest'
else:
# if key not in (...), then use ) right str as real appear_code_line
match_case2 = True
appear_code_line = appear_code_line[end_y + 1:]
# case 3 cur line has = at left or right
assign_patten = '([^=>!]=[^=<>])'
# ... =|<= ... key : is dest
if re.search(assign_patten, appear_code_line[:a_y + 1]):
return 'Dest'
# key ... =|<= ... : is source
if re.search(assign_patten, appear_code_line[a_y:]):
return 'Source'
# case 4 if not match case2(if match no pre line) post full line sep by ";" has =|<=, it's dest
if not match_case2:
pre_full_line = get_verilog_pre_full_line(code_lines, appear_pos)
if re.search(assign_patten, pre_full_line):
return 'Dest'
# case 5 post full line sep by ";" has =|<=, it's source
post_full_line = get_verilog_post_full_line(code_lines, appear_pos)
if re.search(assign_patten, post_full_line[:a_y + 1]):
return 'Source'
# case 6 unrecgnize treat as maybe dest/source
return 'Maybe'

# ok
def clear_last_trace_inf( trace_type ):
if trace_type in ['source','both']:
G['TraceInf']['LastTraceSource']['Maybe']      = []
G['TraceInf']['LastTraceSource']['Sure']       = []
G['TraceInf']['LastTraceSource']['ShowIndex']  = 0
G['TraceInf']['LastTraceSource']['SignalName'] = ''
G['TraceInf']['LastTraceSource']['Path']       = ''
if trace_type in ['dest','both']:
G['TraceInf']['LastTraceDest']['Maybe']        = []
G['TraceInf']['LastTraceDest']['Sure']         = []
G['TraceInf']['LastTraceDest']['ShowIndex']    = 0
G['TraceInf']['LastTraceDest']['SignalName']   = ''
G['TraceInf']['LastTraceDest']['Path']         = ''

# #-------------------trace_io_signal---------------------------
# del get_cur_module_inf
def real_trace_io_signal(trace_type, cursor_inf, io_signal_inf):
assert(trace_type in ['dest', 'source']),'only trace dest/source'
# verilog
if (trace_type is 'dest') and (io_signal_inf['io_type'] != 'output'):
PrintDebug('Warning: real_trace_io_signal: not output signal, not dest')
return False # not output signal, not dest
if (trace_type is 'source') and (io_signal_inf['io_type'] != 'input'):
PrintDebug('Warning: real_trace_io_signal: not input signal, not source')
return False # not input signal, not source
# trace a input signal
clear_last_trace_inf( trace_type )  # clear pre trace dest/source result
cur_module_inf   = cursor_inf['cur_module_inf']
if not cur_module_inf:
PrintDebug('Warning: cur file not in database, will not go upper ! file: %s'(cursor_inf['file_path']))
return True
cur_module_name  = cur_module_inf['module_name']
upper_module_call_inf = get_upper_module_call_io_inf(cur_module_name , io_signal_inf['name'])
if not upper_module_call_inf:
PrintReport('Warning: no upper module call this module before !')
return True # this dest/source but not found upper module
# has upper module go to upper module call location
upper_module_name = upper_module_call_inf['module_name']
upper_call_pos    = upper_module_call_inf['call_pos']
upper_call_line   = upper_module_call_inf['call_line']
upper_module_path = upper_module_call_inf['module_path']
show_str          = '%s %d : %s'%(upper_module_name, upper_call_pos[0]+1, upper_call_line)
file_link         = {'key':io_signal_inf['name'], 'pos': upper_call_pos, 'path': upper_module_path}
trace_result      = {'show': show_str, 'file_link': file_link}
if trace_type is 'dest':
G['TraceInf']['LastTraceDest']['Sure'].append(trace_result)
G['TraceInf']['LastTraceDest']['SignalName'] = cursor_inf['word']
G['TraceInf']['LastTraceDest']['Path']       = cursor_inf['file_path']
else :
G['TraceInf']['LastTraceSource']['Sure'].append(trace_result)
G['TraceInf']['LastTraceSource']['SignalName'] = cursor_inf['word']
G['TraceInf']['LastTraceSource']['Path']       = cursor_inf['file_path']
# show dest/source to report win, and go first trace
PrintReport(spec_case = trace_type)
View.show_next_trace_result(trace_type)
return True

# ok
def trace_io_signal(trace_type, cursor_inf):
trace_signal_name  = cursor_inf['word']
io_signal_infs     = recgnize_io_signal_line(cursor_inf['line'], cursor_inf['line_num'])
if not io_signal_infs:
PrintDebug('Warning: trace_io_signal: not io signal')
return False # not io signal
# if trace_signal_name != io_signal_inf['name']:
if trace_signal_name not in io_signal_infs:
PrintDebug('Warning: trace_io_signal: is io signal but not traced signal')
return False # is io signal but not traced signal
if trace_type in ['source','dest']:
return real_trace_io_signal(trace_type, cursor_inf, io_signal_infs[trace_signal_name])
assert(0),'unkonw tarce type %s' %(trace_type)

#-------------------------------------------------------------
# ok
def real_trace_module_call_io_signal(trace_type, sub_call_inf, cursor_inf):
assert(trace_type in ['source', 'dest'])
if trace_type == 'source' and sub_call_inf['sub_io_type'] != 'output':
return False # submodule not source, just pass
elif trace_type == 'dest' and sub_call_inf['sub_io_type'] != 'input':
return False # submodule not source, just pass
# has sub module and in submodule signal is out, then it's source
sub_module_name         = sub_call_inf['sub_module_name']
sub_module_path         = sub_call_inf['sub_module_path']
sub_module_match_pos    = sub_call_inf['sub_match_pos']
sub_module_match_line   = sub_call_inf['sub_io_line']
sub_module_signal_name  = sub_call_inf['sub_io_name']
show_str     = '%s %d : %s'%(sub_module_name, sub_module_match_pos[0]+1, sub_module_match_line)
file_link    = {'key':sub_module_signal_name, 'pos': sub_module_match_pos, 'path': sub_module_path}
trace_result = {'show': show_str, 'file_link': file_link}
if trace_type == 'source':
G['TraceInf']['LastTraceSource']['Sure'].append(trace_result)
G['TraceInf']['LastTraceSource']['SignalName'] = cursor_inf['word']
G['TraceInf']['LastTraceSource']['Path']       = cursor_inf['file_path']
else: # dest
G['TraceInf']['LastTraceDest']['Sure'].append(trace_result)
G['TraceInf']['LastTraceDest']['SignalName'] = cursor_inf['word']
G['TraceInf']['LastTraceDest']['Path']       = cursor_inf['file_path']
# go to sub module code now, so cur module is the sub module last call
cur_module_name  = sub_call_inf['call_module_name']
call_sub_inf     = sub_call_inf['call_sub_inf']
set_module_last_call_inf(sub_module_name, cur_module_name, call_sub_inf['inst_name'])
# show source to report win, and go first trace
PrintReport(spec_case = trace_type)
View.show_next_trace_result(trace_type)
return True

# ok
# del is_module_call_range
def trace_module_call_io_signal(trace_type, cursor_inf):
sub_call_inf = get_module_call_sub_module_io_inf(cursor_inf['line'], cursor_inf['pos'], cursor_inf['file_path'])
if not sub_call_inf:
PrintDebug('Warning: trace_module_call_io_signal: not in module call io')
return False # not in module call io
if sub_call_inf['sub_module_name'] == cursor_inf['word']:
PrintReport('Warning: trace key is a submodule call, module name , no source !')
return True
if not sub_call_inf['sub_io_name']:
PrintDebug('Warning: trace_module_call_io_signal: is module call ,but unrecgnize io name !')
return False
clear_last_trace_inf( trace_type )
return real_trace_module_call_io_signal(trace_type, sub_call_inf, cursor_inf)

# #---------------------------------------------------------------------
def real_trace_normal_signal(trace_type, signal_appear_pos_line, cursor_inf):
assert(trace_type in ['source', 'dest'])
clear_last_trace_inf(trace_type)
if trace_type == 'source':
G['TraceInf']['LastTraceSource']['SignalName'] = cursor_inf['word']
G['TraceInf']['LastTraceSource']['Path']       = cursor_inf['file_path']
else:
G['TraceInf']['LastTraceDest']['SignalName'] = cursor_inf['word']
G['TraceInf']['LastTraceDest']['Path']       = cursor_inf['file_path']
trace_signal_name = cursor_inf['word']
cur_module_inf    = cursor_inf['cur_module_inf'] # already qualify
cur_module_name   = cur_module_inf['module_name']
cur_module_path   = cur_module_inf['file_path']
# add optimizing for signal such like clk, used by many times, but only io, or sub call is source
input_is_only_source = False
if trace_type == 'source' and len(signal_appear_pos_line) > G['TraceInf']['TraceSourceOptimizingThreshold']:
for appear_pos, appear_line in signal_appear_pos_line:
signal_appear_line = cursor_inf['codes'][appear_pos[0]]
if signal_appear_line.find('input') == -1:
continue
dest_or_source = get_cur_appear_is_source_or_dest(trace_signal_name, [signal_appear_line], (0,appear_pos[1]) )
if dest_or_source != source:
continue
input_is_only_source = True
show_str = '%s %d : %s'%(cur_module_name, appear_pos[0]+1, appear_line)
file_link = {'key':trace_signal_name, 'pos': appear_pos, 'path': cur_module_path}
trace_result = {'show': show_str, 'file_link': file_link}
G['TraceInf']['LastTraceSource']['Sure'].append(trace_result)
break
# if found a input as source, should be the only source, clear appear pos to jump, normal search
if input_is_only_source:
signal_appear_pos_line = []
# appear_pos (line number, column), deal each match to find source
for appear_pos, appear_line in signal_appear_pos_line:
appear_dest_or_source     = False
appear_is_dest            = False
appear_is_source          = False
# module call assign range
sub_call_inf = get_module_call_sub_module_io_inf(appear_line, appear_pos, cur_module_path)
if sub_call_inf:
if trace_signal_name in sub_call_inf['call_sub_signals']:
# cur is subcall but not io name not match trace name go next
if not sub_call_inf['sub_io_type']:
appear_dest_or_source = True
elif sub_call_inf['sub_io_type'] == 'output':
appear_is_source      = True
elif sub_call_inf['sub_io_type'] == 'input':
appear_is_dest        = True
else:
PrintDebug('Warning: subcall match on sub io name, not on assign name ! %s,%s'%(appear_pos.__str__(), appear_line))
continue
else:
# not module call then check if a assign signal
dest_or_source = get_cur_appear_is_source_or_dest(trace_signal_name, cursor_inf['codes'], appear_pos)
if dest_or_source == 'Dest':
appear_is_dest = True
elif dest_or_source == 'Source':
appear_is_source = True
elif dest_or_source == 'Maybe':
appear_dest_or_source = True
else:
PrintDebug('Warning: match not source or dest ! %s : %s'%(appear_pos.__str__(), appear_line))
# finial add to source/dest
show_str = '%s %d : %s'%(cur_module_name, appear_pos[0]+1, appear_line)
file_link = {'key':trace_signal_name, 'pos': appear_pos, 'path': cur_module_path}
trace_result = {'show': show_str, 'file_link': file_link}
if trace_type == 'source':
if appear_dest_or_source:
G['TraceInf']['LastTraceSource']['Maybe'].append(trace_result)
elif appear_is_source:
G['TraceInf']['LastTraceSource']['Sure'].append(trace_result)
else: # trace dest
if appear_dest_or_source:
G['TraceInf']['LastTraceDest']['Maybe'].append(trace_result)
elif appear_is_dest:
G['TraceInf']['LastTraceDest']['Sure'].append(trace_result)
continue
# finish get all dest/source
if trace_type == 'source':
finded_source_num       = len(G['TraceInf']['LastTraceSource']['Sure'])
finded_maybe_source_num = len(G['TraceInf']['LastTraceSource']['Maybe'])
# not find signal source
if not (finded_source_num + finded_maybe_source_num):
PrintReport("Warning: Not find signal source !")
return True
else: # dest
finded_dest_num       = len(G['TraceInf']['LastTraceDest']['Sure'])
finded_maybe_dest_num = len(G['TraceInf']['LastTraceDest']['Maybe'])
# not find signal dest
if not (finded_dest_num + finded_maybe_dest_num):
PrintReport("Warning: Not find signal dest !")
return True
# show source to report win, and go first trace
PrintReport(spec_case = trace_type)
View.show_next_trace_result(trace_type)
return True

def trace_normal_signal(trace_type, cursor_inf):
cur_module_inf    = cursor_inf['cur_module_inf']
if not cur_module_inf:
PrintDebug('Warning: cur file has no module inf, may be no database or cur line not in module, file: %s '%(cursor_inf['file_path']))
return False
# just use grep get all signal appear in current file to speed up signal search
signal_appear_pos_line = search_verilog_code_use_grep( cursor_inf['word'], cursor_inf['file_path'], cur_module_inf['line_range_in_file'] )
return real_trace_normal_signal(trace_type, signal_appear_pos_line, cursor_inf)

#----------------------------------------------------
def trace_glb_define_signal(trace_type, cursor_inf):
assert(trace_type in ['dest', 'source'])
cur_line  = cursor_inf['line']
cur_word  = cursor_inf['word']
if cur_line.find('`') == -1:
return False
s0        = re.search('(?P<prefix>^|\W)%s(\W|$)'%(cur_word),cur_line)
if not s0:
return False
if s0.group('prefix') != '`':
return False
if cur_word not in G['CodeDefineInf']:
PrintReport('Warning: cur macro: \"%s\", not has find in database !'%(cur_word))
return True
cur_define_infs = G['CodeDefineInf'][cur_word]
clear_last_trace_inf(trace_type)
for inf in cur_define_infs: # {name path pos code_line}
file_name = re.sub('.*/','',inf['path'])
show_str = '%s %d : %s'%(file_name, inf['pos'][0]+1, inf['code_line'])
file_link = {'key':cur_word, 'pos': inf['pos'], 'path': inf['path']}
trace_result = {'show': show_str, 'file_link': file_link}
if trace_type == 'source':
G['TraceInf']['LastTraceSource']['SignalName'] = cursor_inf['word']
G['TraceInf']['LastTraceSource']['Path']       = cursor_inf['file_path']
G['TraceInf']['LastTraceSource']['Sure'].append(trace_result)
else: # dest
PrintReport('Warning: cur not support trace macro dest !')
return True
# show source to report win, and go first trace
PrintReport(spec_case = trace_type)
View.show_next_trace_result(trace_type)
return True

""" https://my.oschina.net/u/2520885 """
#===============================================================================
# Copyright (C) 2016 by Jun Cao

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#===============================================================================

import sys
sys.path.append('../')
import vim_glb_config as glb_config

import os
import re
import pickle

vim_start_open_file = ''
try:
import vim
vim_start_open_file = vim.current.buffer.name
except:
vim_start_open_file = '|vim_not_open|'
pass

# cur call path
cur_path = os.getcwd()

# find most resent vtags path
hdl_tags_path = ''
while cur_path and cur_path[0] == '/':
if os.path.isdir(cur_path + '/vtags.db'):
hdl_tags_path = cur_path + '/vtags.db'
break
cur_path = re.sub('/[^/]*$','',cur_path)

# get local config
config        = glb_config
try:
if hdl_tags_path:
sys.path.append(hdl_tags_path)
import vim_local_config as local_config
config = local_config
except:
pass

# get next empty frame, report,log report index, first try del Frame, Report
def del_old_logs():
ls_a_f = [ f.strip('\n') for f in os.popen('ls -a ' + hdl_tags_path).readlines() ]
used_log_index = set()
for f in ls_a_f:
match_swp = re.match('\.(Frame\.HF|Report\.HF|run\.log)(?P<idx>\d+)\.swp',f)
if match_swp:
used_log_index.add(int(match_swp.group('idx')))
ls_f   = [ f.strip('\n') for f in os.popen('ls ' + hdl_tags_path).readlines() ]
for f in ls_f:
match_idx = re.match('(Frame\.HF|Report\.HF|run\.log)(?P<idx>\d+)', f)
if not match_idx:
continue
cur_index = int(match_idx.group('idx'))
if cur_index in used_log_index:
continue
os.system('rm %s/%s'%(hdl_tags_path,f) )
return

empty_log_index = 0
if hdl_tags_path:
del_old_logs()
while os.path.isfile(hdl_tags_path + '/run.log'   + str(empty_log_index)) or \
os.path.isfile(hdl_tags_path + '/Frame.HF'  + str(empty_log_index)) or \
os.path.isfile(hdl_tags_path + '/Report.HF' + str(empty_log_index)):
empty_log_index += 1

# if in generate vtags situation, print log to vtags.db/vtags_run.log
vtags_run_log_path = ['']
# run log path
run_log_path = hdl_tags_path + '/run.log'+str(empty_log_index)
def PrintDebug( str, out_path = ''):
if vtags_run_log_path[0]:
output = open( vtags_run_log_path[0], 'a')
output.write(str+'\n')
output.close()
return
if not config.debug_mode:
return
if out_path:
output = open( out_path, 'a')
output.write(str+'\n')
output.close()
return
if hdl_tags_path:
output = open( run_log_path ,'a')
output.write(str+'\n')
output.close()

def get_file_path_postfix(file_path):
split_by_dot = file_path.split('.')
if len(split_by_dot) < 2: # which means file_path has no postfix
return ''
post_fix = split_by_dot[-1]          # postfix care case
return post_fix

HDLTagsActive = True
# if cur open a valid file, and file not verilog file not act vtags
if vim_start_open_file \
and (get_file_path_postfix(vim_start_open_file) not in config.support_verilog_postfix):
HDLTagsActive = False

# get file inf
FileInf       = {}
try:
if hdl_tags_path and HDLTagsActive:
import files_inf
HDLTagsActive = files_inf.HDLTagsActive
FileInf       = files_inf.FileInf
else:
HDLTagsActive = False
except:
HDLTagsActive = False

BaseModules   = set()
if HDLTagsActive:
# get base module inf
try:
pkl_input     = open(hdl_tags_path + '/base_modules.pkl','rb')
BaseModules   = pickle.load(pkl_input)
pkl_input.close()
except:
pass

# function -------------------------------------------------
def save_env_snapshort():
snapshort = {}
# 0: save cur dir path, used to quality opne snapshort
snapshort['snapshort_dir_path'] = os.getcwd()
# 1: save Frame
snapshort['frame_file_lines'] = []
if os.path.isfile(G['Frame_Inf']['Frame_Path']):
snapshort['frame_file_lines'] = open(G['Frame_Inf']['Frame_Path'],'r').readlines()
# 2: save Report
snapshort['report_file_lines'] = []
if os.path.isfile(G['Report_Inf']['Report_Path']):
snapshort['report_file_lines'] = open(G['Report_Inf']['Report_Path'],'r').readlines()
# 3: save G
snapshort['G'] = {}
snapshort['G']['OpTraceInf']                   = {}
snapshort['G']['OpTraceInf']['TracePoints']    = G['OpTraceInf']['TracePoints']
snapshort['G']['OpTraceInf']['Nonius'     ]    = G['OpTraceInf']['Nonius'     ]
snapshort['G']['WorkWin_Inf']                  = {}
snapshort['G']['WorkWin_Inf']['OpenWinTrace']  = G['WorkWin_Inf']['OpenWinTrace']
snapshort['G']['VimBufferLineFileLink' ]       = G["VimBufferLineFileLink" ]
snapshort['G']["TraceInf"              ]       = G['TraceInf']
snapshort['G']['CheckPointInf']                = {}
snapshort['G']['CheckPointInf']['CheckPoints'] = G['CheckPointInf']['CheckPoints']
snapshort['G']['TopoInf']                      = {}
snapshort['G']['TopoInf']['CurModule']         = G['TopoInf']['CurModule']
snapshort['G']['ModuleLastCallInf']            = G['ModuleLastCallInf']
snapshort['G']['Frame_Inf']                    = {}
snapshort['G']['Frame_Inf']['Frame_Path']      = G['Frame_Inf']['Frame_Path']
snapshort['G']['Report_Inf']                   = {}
snapshort['G']['Report_Inf']['Report_Path']    = G['Report_Inf']['Report_Path']
# 4: save act windows inf
act_win_inf = []
for w in vim.windows:
c_file_path = w.buffer.name
if c_file_path == vim.current.buffer.name:
continue
c_cursor    = w.cursor
c_size      = (w.width, w.height)
act_win_inf.append({'path': c_file_path, 'cursor': c_cursor, 'size': c_size })
# last is current window
cur_file_path  = vim.current.buffer.name
cur_cursor     = vim.current.window.cursor
cur_size       = (vim.current.window.width, vim.current.window.height)
act_win_inf.append({'path': cur_file_path, 'cursor': cur_cursor, 'size': cur_size })
snapshort['act_win_inf'] = act_win_inf
pkl_output = open(hdl_tags_path + '/env_snapshort.pkl','wb')
pickle.dump(snapshort, pkl_output)
pkl_output.close()
return True

def reload_env_snapshort(snapshort):
# 1: reload G
snapshort_G = snapshort['G']
G['OpTraceInf']['TracePoints']    = snapshort_G['OpTraceInf']['TracePoints']
G['OpTraceInf']['Nonius'     ]    = snapshort_G['OpTraceInf']['Nonius'     ]
G['WorkWin_Inf']['OpenWinTrace']  = snapshort_G['WorkWin_Inf']['OpenWinTrace']
G['VimBufferLineFileLink' ]       = snapshort_G["VimBufferLineFileLink" ]
G["TraceInf"              ]       = snapshort_G['TraceInf']
G['CheckPointInf']['CheckPoints'] = snapshort_G['CheckPointInf']['CheckPoints']
G['TopoInf']['CurModule']         = snapshort_G['TopoInf']['CurModule']
G['ModuleLastCallInf']            = snapshort_G['ModuleLastCallInf']
G['Frame_Inf']['Frame_Path']      = snapshort_G['Frame_Inf']['Frame_Path']
G['Report_Inf']['Report_Path']    = snapshort_G['Report_Inf']['Report_Path']
# 2: reload Frame
os.system('touch ' + G['Frame_Inf']['Frame_Path'])
assert(os.path.isfile(G['Frame_Inf']['Frame_Path']))
frame_fp = open(G['Frame_Inf']['Frame_Path'],'w')
for l in snapshort['frame_file_lines']:
frame_fp.write(l)
frame_fp.close()
# 3: reload Report
os.system('touch ' + G['Report_Inf']['Report_Path'])
assert(os.path.isfile(G['Report_Inf']['Report_Path']))
report_fp = open(G['Report_Inf']['Report_Path'],'w')
for l in snapshort['report_file_lines']:
report_fp.write(l)
report_fp.close()
# 4: reload act windows inf need re open at API.py
G['EnvSnapshortWinsInf'] = snapshort['act_win_inf']
return

# structure -----------------------------------------------------

# frame file_link = {
#                      'type'     : '', topo                      | check_point          | base_module
#                     'key'      : '', topo module name          | add check point word | base module name
#                     'pos'      : '', module def pos            | add pos              | module pos
#                     'path'     : '', module def file path      | add file path        | module def file path
#                     'fold_inf' :                              {}, 'fold_status': on/off/fix
#                                                                 , 'level'     : n
#
#                   }
Frame_Inf = {
"Frame_Win_x"        : config.frame_window_width      # frame window width
,"Frame_Path"         : ''
,"FoldLevelSpace"     : config.frame_fold_level_space
}
Frame_Inf['Frame_Path'] = hdl_tags_path + '/' + "Frame.HF" + str(empty_log_index)

# report file_link = {
#                      'key'   :  '' ,  signal_name
#                     'pos'   :  '' ,  match_pos
#                     'path'  :  '' ,  match_path
# }
Report_Inf = {
"Report_Win_y"       : config.report_window_height        # report window height
,"Report_Path"        : hdl_tags_path + '/' + "Report.HF"
}
Report_Inf['Report_Path'] = hdl_tags_path + '/' + "Report.HF" + str(empty_log_index)

WorkWin_Inf ={
"MaxNum"       : config.max_open_work_window_number
,"OpenWinTrace" : []
}

# all vim buffer line file link { path:[...]}
VimBufferLineFileLink = {}

TraceInf = {
'LastTraceSource' : {'Maybe':[], 'Sure':[], 'ShowIndex': 0, 'SignalName':'', 'Path':'' } # Maybe[{'show':'', 'file_link':{ 'key':'','pos':(l,c),'path':'' } }]
,'LastTraceDest'   : {'Maybe':[], 'Sure':[], 'ShowIndex': 0, 'SignalName':'', 'Path':'' }
,'TraceSourceOptimizingThreshold' : config.trace_source_optimizing_threshold
}

# operation trace
OpTraceInf = {
'TracePoints' : [] # {'path':'', "pos":(line, colum), 'key':''}
,'TraceDepth'  : config.max_roll_trace_depth
,'Nonius'      : -1  # roll nonius
}

TopoInf       = {
'CurModule'    : ''
,'TopFoldLevel' : 0
}

CheckPointInf = {
"MaxNum"         : config.max_his_check_point_num
,"CheckPoints"    : []  #{}--- key: '', link: {}
,"TopFoldLevel"   : 0
}

BaseModuleInf = {
"BaseModuleThreshold"  : config.base_module_threshold  # when module inst BaseModuleThreshold times, then default set it to base module
,"BaseModules"          : BaseModules # module name set()
,"TopFoldLevel"         : 0
}

G = {
'HDLTagsActive'         : HDLTagsActive
,'SupportVHDLPostfix'    : set([])
,'SupportVerilogPostfix' : set(config.support_verilog_postfix)
,'ModuleInf'             : {}
,'ModuleLastCallInf'     : {}           # {module_name:{ upper_module_name:'', 'upper_inst_name':inst_name} }
,'FileInf'               : FileInf
,'CodeDefineInf'         : {}           # {name: [ {name path pos code_line} ]}
,'OpTraceInf'            : OpTraceInf
,"Debug"                 : config.debug_mode    # debug mode
,"ShowReport"            : config.show_report
,"ShowFrame"             : config.show_sidebar
,"PrintDebug_F"          : PrintDebug   # function to print debug
,"Frame_Inf"             : Frame_Inf    # Frame window inf
,"Report_Inf"            : Report_Inf   # report window inf
,"WorkWin_Inf"           : WorkWin_Inf  # win config
,"VimBufferLineFileLink" : VimBufferLineFileLink
,"TraceInf"              : TraceInf
,"CheckPointInf"         : CheckPointInf
,"BaseModuleInf"         : BaseModuleInf
,'TopoInf'               : TopoInf
,"FixExtraSpace"         : True         # some situation come extra space, need do nonthing
,"IgnoreNextSpaceOp"     : False        # just flod has a else space, not do space op
,"EnvSnapshortWinsInf"   : []
,"SaveEnvSnapshort_F"    : save_env_snapshort
,"VTagsPath"             : hdl_tags_path
}

# has save history sence then just repaly it
start_with_empty_file = False
if not vim_start_open_file :
start_with_empty_file = True

EnvSnapshort  = {}
if HDLTagsActive and start_with_empty_file and os.path.isfile(hdl_tags_path + '/env_snapshort.pkl'):
pkl_input       = open(hdl_tags_path + '/env_snapshort.pkl','rb')
c_snapshort     = pickle.load(pkl_input)
if c_snapshort['snapshort_dir_path'] == os.getcwd():
os.system('echo \'do you want reload vim snapshort ? (y/n): \'')
yes_or_no = raw_input()
if yes_or_no.lower() in ['y','yes']:
EnvSnapshort  = c_snapshort
pkl_input.close()

if EnvSnapshort:
reload_env_snapshort(EnvSnapshort)

""" https://my.oschina.net/u/2520885 """
#===============================================================================
# Copyright (C) 2016 by Jun Cao

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#===============================================================================

import sys
import re
try:
import vim
except:
pass
import os
import re
from Base import *
from Win import *
import GLB
G = GLB.G

#--------------------------------------
SnapshotStack = []

def snapshort_push():
cur_cursor        = vim.current.window.cursor
cur_pos           = (cur_cursor[0]-1, cur_cursor[1]) # minus 1 because cursor start from 1, and lines start from 0
cur_line_num      = cur_pos[0]
cur_line          = vim.current.buffer[cur_line_num]
cur_word          = get_full_word(cur_line, cur_pos[1])
cur_file_path     = vim.current.buffer.name
cur_snapshort     = {"path": cur_file_path, "pos":cur_pos, "key":cur_word}
SnapshotStack.append(cur_snapshort)

def snapshort_pop():
pop_snapshort = SnapshotStack[-1]
del SnapshotStack[-1]
go_win( pop_snapshort['path'], pop_snapshort['pos'], pop_snapshort['key'])
#--------------------------------------

def Show(path): # just show frame win , and not go to that window
path    = get_path_for_name(path)
Act_Win = Cur_Act_Win()
if path not in Act_Win:
snapshort_push()
Open(path)
snapshort_pop()
return

#--------------------------------------

def add_trace_point():
cur_cursor        = vim.current.window.cursor
cur_file_path     = vim.current.buffer.name
if cur_file_path in [ G['Frame_Inf']['Frame_Path'], G['Report_Inf']['Report_Path'] ]:
PrintDebug('Warning: Frame and Report not add trace point !')
return
cur_pos           = (cur_cursor[0]-1, cur_cursor[1]) # minus 1 because cursor start from 1, and lines start from 0
cur_line_num      = cur_pos[0]
cur_line          = vim.current.buffer[cur_line_num]
cur_word          = get_full_word(cur_line, cur_pos[1])
cur_trace_point   = {"path": cur_file_path, "pos":cur_pos, "key":cur_word}
cur_nonius        = G['OpTraceInf']['Nonius']
TracePoints       = G['OpTraceInf']['TracePoints']
# when roll back, and add from middle of queue, just clear old trace point after cur insert index
# |  0  |  1  |  2  |  3  |  4  |
#                      ^           if len 5, nonius <= 3 then del 4
if cur_nonius <= (len(TracePoints) - 2):
del TracePoints[cur_nonius + 1 : ]
# add a new point to TracePoints
# if cur add is equ to pre not add
if not TracePoints:
TracePoints.append(cur_trace_point)
else:
pre_point = TracePoints[-1]
if cur_trace_point != pre_point:
TracePoints.append(cur_trace_point)
# if length bigger than TraceDepth del
TraceDepth        = G['OpTraceInf']['TraceDepth']
while (len(TracePoints) > TraceDepth):
del TracePoints[0]
# if add new point ,nonius assign to len(TracePoints)
# |  0  |  1  |  2  |  3  |  4  |
#                                 ^  because roll back will first sub 1
G['OpTraceInf']['Nonius'] = len(TracePoints)

def get_cur_cursor_inf():
cur_cursor       = vim.current.window.cursor
cur_line_num     = cur_cursor[0] - 1 # minus 1 because cursor start from 1, and lines start from 0
cur_colm_num     = cur_cursor[1]
cur_line         = vim.current.buffer[cur_line_num]
cur_word         = get_full_word(cur_line, cur_cursor[1])
cur_codes        = vim.current.buffer
cur_file_path    = vim.current.buffer.name
cur_hdl_type     = get_file_hdl_type(cur_file_path)
cur_call_sub_inf = {}
cur_module_inf   = {}
cur_line_inf     = get_file_line_inf(cur_line_num, cur_file_path)
if cur_line_inf:
cur_call_sub_inf = cur_line_inf['line_call_sub_inf']
cur_module_inf   = cur_line_inf['line_module_inf']
cur_module_name  = ''
if cur_module_inf:
cur_module_name = cur_module_inf['module_name']
else:
PrintDebug('Warning: get_cur_cursor_inf: current cursor %s not in module, file: %s ! '%(cur_cursor.__str__(), cur_file_path ))
return {  'cursor'           : cur_cursor
,'pos'              : (cur_line_num, cur_colm_num)
,'line_num'         : cur_line_num
,'colm_num'         : cur_colm_num
,'line'             : cur_line
,'word'             : cur_word
,'file_path'        : cur_file_path
,'hdl_type'         : cur_hdl_type
,'cur_call_sub_inf' : cur_call_sub_inf
,'cur_module_inf'   : cur_module_inf
,'codes'            : cur_codes }

# ok
# report file_link = {
#                      'key'   :  '' ,  signal_name
#                     'pos'   :  '' ,  match_pos
#                     'path'  :  '' ,  match_path
# }
#----for python edition 2.7 +
# def PrintReport(*show, file_link = {}, spec_case = '', mode = 'a'):
#     # normal show a string
#     show_str = ' '.join([ i.__str__() for i in show ])
#----for python edition 2.6
def PrintReport(show = '', file_link = {}, spec_case = '', mode = 'a'):
if not G['ShowReport']:
return
has_self_snap_short = False
if not cur_in_report():
snapshort_push()
Open('Report')
has_self_snap_short = True
show_str = show
if show_str:
edit_vim_buffer('Report', [show_str], file_links = [file_link], mode = mode)
# show trace source result
if spec_case == 'source':
edit_vim_buffer('Report', "---------------------------source--------------------------------")
t_data      = []
t_file_link = []
for Sure in G['TraceInf']['LastTraceSource']['Sure']:
t_data.append( Sure['show'] )
t_file_link.append( Sure['file_link'] )
edit_vim_buffer('Report', t_data, t_file_link)
edit_vim_buffer('Report', "------------------------maybe source-----------------------------")
t_data      = []
t_file_link = []
for Maybe in G['TraceInf']['LastTraceSource']['Maybe']:
t_data.append( Maybe['show'] )
t_file_link.append( Maybe['file_link'] )
edit_vim_buffer('Report', t_data, t_file_link)
edit_vim_buffer('Report', "----------------------------END----------------------------------")
edit_vim_buffer('Report', "")
# show trace dest result
if spec_case == 'dest':
edit_vim_buffer('Report', "---------------------------dest--------------------------------")
t_data      = []
t_file_link = []
for Sure in G['TraceInf']['LastTraceDest']['Sure']:
t_data.append( Sure['show'] )
t_file_link.append( Sure['file_link'] )
edit_vim_buffer('Report', t_data, t_file_link)
edit_vim_buffer('Report', "------------------------maybe dest-----------------------------")
t_data      = []
t_file_link = []
for Maybe in G['TraceInf']['LastTraceDest']['Maybe']:
t_data.append( Maybe['show'] )
t_file_link.append( Maybe['file_link'] )
edit_vim_buffer('Report', t_data, t_file_link)
edit_vim_buffer('Report', "----------------------------END----------------------------------")
edit_vim_buffer('Report', "")
# go report to the last line, and return
assert(cur_in_report())
# if mode == 'a':
vim.current.window.cursor = (len(vim.current.buffer) - 1 , 0)
vim.command('w!')
if has_self_snap_short:
snapshort_pop()

# ok
def show_next_trace_result( trace_type ):
if trace_type == 'source':
cur_show_index   = G['TraceInf']['LastTraceSource']["ShowIndex"]
sure_source_len  = len(G['TraceInf']['LastTraceSource']['Sure'])
maybe_source_len = len(G['TraceInf']['LastTraceSource']['Maybe'])
if (sure_source_len + maybe_source_len) == 0:
PrintReport('not find source !')
return
cur_file_link = {}
if cur_show_index < sure_source_len:
cur_file_link = G['TraceInf']['LastTraceSource']['Sure'][cur_show_index]['file_link']
else:
cur_file_link = G['TraceInf']['LastTraceSource']['Maybe'][cur_show_index - sure_source_len]['file_link']
G['TraceInf']['LastTraceSource']["ShowIndex"] = (cur_show_index + 1) % (sure_source_len + maybe_source_len)
add_trace_point()
go_win( cur_file_link['path'], cur_file_link['pos'], cur_file_link['key'] )
elif trace_type == 'dest':
cur_show_index   = G['TraceInf']['LastTraceDest']["ShowIndex"]
sure_dest_len  = len(G['TraceInf']['LastTraceDest']['Sure'])
maybe_dest_len = len(G['TraceInf']['LastTraceDest']['Maybe'])
if (sure_dest_len + maybe_dest_len) == 0:
PrintReport('not find dest !')
return
cur_file_link = {}
if cur_show_index < sure_dest_len:
cur_file_link = G['TraceInf']['LastTraceDest']['Sure'][cur_show_index]['file_link']
else:
cur_file_link = G['TraceInf']['LastTraceDest']['Maybe'][cur_show_index - sure_dest_len]['file_link']
G['TraceInf']['LastTraceDest']["ShowIndex"] = (cur_show_index + 1) % (sure_dest_len + maybe_dest_len)
add_trace_point()
go_win( cur_file_link['path'], cur_file_link['pos'], cur_file_link['key'])
else:
assert(0)

#--------------------------------------------------------------------------
def gen_top_topo_data_link(topo_module):
topo_datas   = []
topo_links   = []
topo_module_inf = get_module_inf(topo_module)
if not topo_module_inf:
PrintDebug('Error: get topo module name %s, should has module inf !'%(topo_module))
return topo_datas, topo_links
TopTopoLevel    = G['TopoInf']['TopFoldLevel']
TopTopoPrefix   = G['Frame_Inf']['FoldLevelSpace'] * TopTopoLevel
# add first topo line
topo_datas.append(TopTopoPrefix + 'ModuleTopo:')
topo_link = {
'type'           : 'topo'
,'topo_inst_name' : ''
,'key'            : ''
,'pos'            : ''
,'path'           : ''
,'fold_inf'       : {'fold_status':'on', 'level': TopTopoLevel - 1 }
}
topo_links.append(topo_link)
# add cur module name
topo_datas.append(TopTopoPrefix + topo_module + ':')
topo_link = {
'type'           : 'topo'
,'topo_inst_name' : ''
,'key'            : topo_module
,'pos'            : topo_module_inf['module_pos']
,'path'           : topo_module_inf['file_path']
,'fold_inf'       : {'fold_status':'on', 'level': TopTopoLevel}
}
topo_links.append(topo_link)
# gen current module sub function module, and base module topo inf
sub_module_data, sub_module_link = get_fram_topo_sub_inf(topo_module, 0)
topo_datas = topo_datas + sub_module_data
topo_links = topo_links + sub_module_link
return topo_datas, topo_links

def edit_frame(data = [], file_links = [], mode = 'a', n = 0, del_range = ()):
has_self_snap_short = False
if not cur_in_frame():
snapshort_push()
Open('Frame')
has_self_snap_short = True
edit_vim_buffer( path_or_name = 'Frame', data = data, file_links = file_links, mode = mode, n = n, del_range = del_range)
# go frame w! and go back
assert(cur_in_frame())
vim.command('w!')
if has_self_snap_short:
snapshort_pop()

#---------------------------------------
def show_base_module(fold = True):
frame_data   = []
frame_link   = []
# if frame not show ,show it
Show("Frame")
# add initial line
level        = G['BaseModuleInf']['TopFoldLevel']
key          = G['Frame_Inf']['FoldLevelSpace']*level + 'BaseModules:'
link         = {
'type'     : 'base_module'
,'key'      : ''
,'pos'      : ''
,'path'     : ''
,'fold_inf' : { 'fold_status': 'on', 'level': level }
}
frame_data.append(key)
frame_link.append(link)
# add check points
range_inf         = get_frame_range_inf()
has_base_module   = range_inf['has_base_module']
base_module_range = range_inf['base_module_range']
cp_data = []
cp_link = []
if fold:
cp_data, cp_link  = get_fram_base_module_inf()
else:
frame_link[-1]['fold_inf']['fold_status'] = 'off'
frame_data = frame_data + cp_data
frame_link = frame_link + cp_link
# del old cp, add new cp
if has_base_module: # del
edit_frame(mode = 'del', del_range = base_module_range)
edit_frame(data = frame_data, file_links = frame_link, mode = 'i', n = base_module_range[0])
return True

#-------------------------------------
def show_check_point(fold = True):
frame_data   = []
frame_link   = []
# if frame not show ,show it
Show("Frame")
# add initial line
level        = G['CheckPointInf']['TopFoldLevel']
key          = G['Frame_Inf']['FoldLevelSpace']*level + 'CheckPoints:'
link         = {
'type'     : 'check_point'
,'key'      : ''
,'pos'      : ''
,'path'     : ''
,'fold_inf' : { 'fold_status': 'on', 'level': level }
}
frame_data.append(key)
frame_link.append(link)
# add check points
range_inf         = get_frame_range_inf()
has_check_point   = range_inf['has_check_point']
check_point_range = range_inf['check_point_range']
cp_data = []
cp_link = []
if fold:
cp_data, cp_link  = get_fram_check_point_inf()
else:
frame_link[-1]['fold_inf']['fold_status'] = 'off'
frame_data = frame_data + cp_data
frame_link = frame_link + cp_link
# del old cp, add new cp
if has_check_point: # del
edit_frame(mode = 'del', del_range = check_point_range)
edit_frame(data = frame_data, file_links = frame_link, mode = 'i', n = check_point_range[0])
return True

#---------------------------------------
def show_topo(topo_module_name = ''):
if not topo_module_name:
cursor_inf      = get_cur_cursor_inf()
if cursor_inf['hdl_type'] != 'verilog':
# if not in support file type(verilog,vhdl) just return
PrintReport("Warning: Current only support verilog !")
return False
# get current module inf
cur_module_inf  = cursor_inf['cur_module_inf']
# current not at module lines, just return
if not cur_module_inf:
PrintReport("Warning: Current cursor not in valid module !")
return False
topo_module_name = cur_module_inf['module_name']
else:
if topo_module_name not in G['ModuleInf']:
PrintReport("Warning: show topo module %s not have database !"%(topo_module_name))
return False
# if frame not show ,show it
Show("Frame")
# current module must has module inf
G['TopoInf']['CurModule']  = topo_module_name  # note cur topo name for refresh
range_inf                  = get_frame_range_inf()
has_topo                   = range_inf['has_topo']
topo_range                 = range_inf['topo_range']
topo_data, topo_link       = gen_top_topo_data_link(topo_module_name)
# del old topo, add new topo
if has_topo: # del
edit_frame(mode = 'del', del_range = topo_range)
edit_frame(data = topo_data, file_links = topo_link, mode = 'i', n = topo_range[0])
return True

def iteration_fold_no_module(inst_module_pairs, base_modules):
c_frame_range_inf = get_frame_range_inf()
if not c_frame_range_inf['has_topo']:
return
frame_path   = G['Frame_Inf']['Frame_Path']
c_topo_range = c_frame_range_inf['topo_range']
c_topo_links = G['VimBufferLineFileLink'][frame_path][c_topo_range[0] : c_topo_range[1]]
for i,lk in enumerate(c_topo_links):
if not( lk and (lk['fold_inf']['fold_status'] == 'off') and lk['key'] ):
continue
if lk['topo_inst_name']:
c_inst_module_pair = (lk['topo_inst_name'], lk['key'])
if c_inst_module_pair in inst_module_pairs:
fold_frame_line(lk, i+c_topo_range[0], lk['fold_inf']['level'], 'topo')
iteration_fold_no_module(inst_module_pairs, base_modules)
return
else:
if lk['key'] in base_modules:
fold_frame_line(lk, i+c_topo_range[0], lk['fold_inf']['level'], 'topo')
iteration_fold_no_module(inst_module_pairs, base_modules)
return
return

def refresh_topo():
# get all folded module or inst pair
old_frame_range_inf = get_frame_range_inf()
if not old_frame_range_inf['has_topo']:
return
frame_path     = G['Frame_Inf']['Frame_Path']
old_topo_range = old_frame_range_inf['topo_range']
old_topo_links = G['VimBufferLineFileLink'][frame_path][old_topo_range[0] + 2 : old_topo_range[1] + 1]
old_fold_inst_module_pairs = set()
old_fold_base_modules      = set()
for lk in old_topo_links:
if not( lk and (lk['fold_inf']['fold_status'] == 'on') and lk['key'] ):
continue
if lk['topo_inst_name']:
old_fold_inst_module_pairs.add( (lk['topo_inst_name'], lk['key']) )
else:
if lk['key'] in G['BaseModuleInf']['BaseModules']:
old_fold_base_modules.add(lk['key'])
# start new topo
new_topo_module_name = G['TopoInf']['CurModule']
show_topo(new_topo_module_name)
# iteration opened old folded topo
iteration_fold_no_module(old_fold_inst_module_pairs, old_fold_base_modules)

#---------------------------------------
def unfold_frame_line(frame_links, frame_line, cur_frame_level, cur_frame_type):
assert(frame_links[frame_line]['fold_inf']['fold_status'] == 'on')
G['VimBufferLineFileLink'][ G['Frame_Inf']['Frame_Path'] ][frame_line]['fold_inf']['fold_status'] = 'off'
unfold_end_line_num =  frame_line
for i in range(frame_line+1, len(frame_links)):
# if cur not have file link, then cur is unflod end
if not frame_links[i]:
unfold_end_line_num = i - 1
break
# if has file link ,but not topo inf then unflod end
if frame_links[i]['type'] != cur_frame_type:
unfold_end_line_num = i - 1
break
# if is topo , but level <= cur level then unflod end
if frame_links[i]['fold_inf']['level'] <= cur_frame_level:
unfold_end_line_num = i - 1
break
# if cur module has no sub module then just return
if unfold_end_line_num == frame_line:
return True
# else edit the frame buffer and file link, del the unflod lines
if unfold_end_line_num > frame_line:
edit_frame(mode = 'del', del_range = (frame_line + 1, unfold_end_line_num))
return True
# else some trouble
assert(0),'shold not happen !'

def fold_frame_line(cur_line_link, frame_line, cur_frame_level, cur_frame_type):
assert(cur_line_link['fold_inf']['fold_status'] == 'off')
G['VimBufferLineFileLink'][ G['Frame_Inf']['Frame_Path'] ][frame_line]['fold_inf']['fold_status'] = 'on'
if cur_frame_type == 'topo':
# if cur is ModuleTopo: line, show refresh topo
if cur_frame_level == G['TopoInf']['TopFoldLevel'] - 1:
topo_module_name = G['TopoInf']['CurModule']
show_topo(topo_module_name)
return
# cur_line_link['key'] is the cur topo line module name
cur_module_name = cur_line_link['key']
if  not cur_module_name:
PrintReport('Warning: cur topo line has no module name !')
return
if cur_module_name not in G['ModuleInf']:
PrintReport('Warning: cur module: \"%s\" has no database !'%(cur_module_name))
return
# get cur module sub module inf
sub_topo_data, sub_topo_link = get_fram_topo_sub_inf(cur_module_name, cur_frame_level)
# add cur module topo inf to frame
edit_frame(data = sub_topo_data, file_links = sub_topo_link, mode = 'i', n = frame_line + 1)
elif cur_frame_type == 'check_point':
show_check_point()
elif cur_frame_type == 'base_module':
show_base_module()
else:
PrintReport('Warning: no operation in this line !')
return

def frame_line_fold_operation(frame_line):
frame_path     = G['Frame_Inf']['Frame_Path']
frame_links    = G['VimBufferLineFileLink'][frame_path]
cur_line_link  = frame_links[frame_line]
if not cur_line_link :
PrintReport('Warning: cur frame line no fold operation !')
return
cur_frame_type  = cur_line_link['type']
cur_frame_level = cur_line_link['fold_inf']['level']
cur_fold_state  = cur_line_link['fold_inf']['fold_status']
if cur_fold_state == 'off':
fold_frame_line(cur_line_link, frame_line, cur_frame_level, cur_frame_type)
elif cur_fold_state == 'on':
unfold_frame_line(frame_links, frame_line, cur_frame_level, cur_frame_type)
else:
PrintReport('Warning: cur frame line no fold operation !')
return

""" https://my.oschina.net/u/2520885 """
#===============================================================================
# Copyright (C) 2016 by Jun Cao

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#===============================================================================

try:
import vim
except:
pass
import sys
import re
import os
import GLB
G = GLB.G
from Base import *

def Reset_Win_Size():
cur_act_wins = Cur_Act_Win()
if G['Report_Inf']['Report_Path'] in cur_act_wins:
Jump_To_Win(G['Report_Inf']['Report_Path'])
vim.command('wincmd J')
vim.current.window.height = G['Report_Inf']['Report_Win_y']
if G['Frame_Inf']['Frame_Path'] in cur_act_wins:
Jump_To_Win(G['Frame_Inf']['Frame_Path'])
vim.command('wincmd H')
vim.current.window.width = G['Frame_Inf']['Frame_Win_x']
return

def Refresh_OpenWinTrace():
cur_act_win_path      = Cur_Act_Win()
cur_act_work_win_path = cur_act_win_path - set([ G["Report_Inf"]["Report_Path"], G["Frame_Inf"]["Frame_Path"] ])
i = 0
while i < len(G['WorkWin_Inf']['OpenWinTrace']) :
c_path = G['WorkWin_Inf']['OpenWinTrace'][i]
if c_path not in cur_act_work_win_path:
del G['WorkWin_Inf']['OpenWinTrace'][i]
else:
i += 1
return

def Cur_Act_Win():
Act_Win = set()
for w in vim.windows:
Act_Win.add(w.buffer.name)
return Act_Win

def Open(name):
path = get_path_for_name(name)
Act_Win = Cur_Act_Win()
if path in Act_Win: # win has open and just jump to than window
Jump_To_Win(path)
elif path == G['Frame_Inf']["Frame_Path"]:
Open_Frame_Win()
elif path == G['Report_Inf']["Report_Path"]:
Open_Report_Win()
else:
Open_Work_Win(path)
Reset_Win_Size()
Jump_To_Win(path)
assert(vim.current.buffer.name == path)

def Jump_To_Win(path):
cur_act_wins = Cur_Act_Win()
assert(path in cur_act_wins)
start_path = vim.current.buffer.name
if start_path == path:
return
vim.command('wincmd w')
cur_path = vim.current.buffer.name
while cur_path != start_path:
if cur_path == path:
break
vim.command("wincmd w")
cur_path = vim.current.buffer.name
assert(vim.current.buffer.name == path),'vim.current.buffer.name: %s, path: %s'%(vim.current.buffer.name, path)

def Open_Frame_Win():
G['VimBufferLineFileLink'].setdefault(G["Frame_Inf"]["Frame_Path"],[{}])
vim.command("vertical topleft sp " + G["Frame_Inf"]["Frame_Path"])

def Open_Report_Win():
G['VimBufferLineFileLink'].setdefault(G["Report_Inf"]["Report_Path"],[{}])
vim.command("bot sp " + G["Report_Inf"]["Report_Path"])
if G["Frame_Inf"]["Frame_Path"] in Cur_Act_Win():
Jump_To_Win(G["Frame_Inf"]["Frame_Path"])
vim.command('wincmd H')
Jump_To_Win(G["Report_Inf"]["Report_Path"])

def Open_Work_Win(path):
# path must valid
assert(os.path.isfile(path))
# refresh open work win trace
Refresh_OpenWinTrace()
# leave at most G['WorkWin_Inf']['MaxNum'] work win
win_num_need_to_close = len(G['WorkWin_Inf']['OpenWinTrace']) - G['WorkWin_Inf']['MaxNum']
for i in range(win_num_need_to_close):
win_path_need_close = G['WorkWin_Inf']['OpenWinTrace'][i]
Jump_To_Win(win_path_need_close)
vim.command('q')
del G['WorkWin_Inf']['OpenWinTrace'][i]
# if has work win
cur_work_win_num = len(G['WorkWin_Inf']['OpenWinTrace'])
if cur_work_win_num > 0:
# case 0: has work win, and num less than max
#         just go last work win, and vsp a new win
if cur_work_win_num < G['WorkWin_Inf']['MaxNum']:
Jump_To_Win(G['WorkWin_Inf']['OpenWinTrace'][-1])
vim.command('vsp '+path)
else: # case 1: opened all work win, just replace the oldest open work win
Jump_To_Win(G['WorkWin_Inf']['OpenWinTrace'][0])
vim.command('e '+path)
del G['WorkWin_Inf']['OpenWinTrace'][0] # replace [0], just del old
else: # cur no work win
cur_act_win_paths = Cur_Act_Win()
cur_act_hold_wins = cur_act_win_paths - set([G["Report_Inf"]["Report_Path"], G["Frame_Inf"]["Frame_Path"]])
# if has hold win, go hold win, vsp
if cur_act_hold_wins:
Jump_To_Win(list(cur_act_hold_wins)[0])
vim.command('vsp '+path)
elif G["Report_Inf"]["Report_Path"] in cur_act_win_paths:
# if no hold win, has report , go report sp new
Jump_To_Win(G["Report_Inf"]["Report_Path"])
vim.command('sp '+path)
else:
vim.command('vsp '+path)
# finial add path to trace
assert(vim.current.buffer.name == path)
G['WorkWin_Inf']['OpenWinTrace'].append(path)

def get_file_vim_buffer(path):
for i,b in enumerate(vim.buffers):
if b.name == path:
return b
# path buffer not open
vim.command("bad "+path)
assert(vim.buffers[ len(vim.buffers) - 1].name == path)
return vim.buffers[ len(vim.buffers) - 1]

# edit the vim buffer, with put data at some position
# mode : a --after     : append data after current buffer data
#        b --before    : append data before current buffer data
#        w --write     : clear old buffer data, and write data
#        i --insert    : inster list to n
#        del -- delete : delete del_range lines
#        del_range     : (start,end) del range, include end
def edit_vim_buffer(path_or_name = '', data = [], file_links = [], mode = 'a', n = 0, del_range = ()):
# weather to edit link buffer
need_edit_buffer_file_link = False
if data == [] and mode != 'del':
PrintDebug('Warning: edit_vim_buffer: edit file with empty data= [], file:%s !'%(path_or_name))
return
if type(data) is str:
data = [data]
path = get_path_for_name(path_or_name)
# some time edit other buffer, may change cur window cursor or add empty line to cur buffer file,
# so must edit current buffer
assert(vim.current.buffer.name == path),'%s,%s'%(vim.current.buffer.name, path)
if path in [G['Report_Inf']['Report_Path'], G['Frame_Inf']['Frame_Path']]:
need_edit_buffer_file_link = True
if file_links:
assert(len(data) == len(file_links))
else:
file_links = [ {} for i in range(len(data))]
# PrintDebug('edit_vim_buffer path_or_name:'+path_or_name)
# PrintDebug('edit_vim_buffer data:'+data.__str__())
# PrintDebug('edit_vim_buffer file_links:'+file_links.__str__())
# PrintDebug('edit_vim_buffer mode:'+mode.__str__())
# PrintDebug('edit_vim_buffer n:'+n.__str__())
# PrintDebug('edit_vim_buffer del_range:'+del_range.__str__())
t_buffer = get_file_vim_buffer(path)
assert(t_buffer)
if mode is 'w':
del t_buffer[:]
t_buffer.append(data)
del t_buffer[:1]
if need_edit_buffer_file_link:
G["VimBufferLineFileLink"][path] = file_links
elif mode is 'a':
t_buffer.append(data)
if need_edit_buffer_file_link:
G["VimBufferLineFileLink"].setdefault(path,[])
G["VimBufferLineFileLink"][path] = G["VimBufferLineFileLink"][path] + file_links
elif mode is 'b':
t_buffer.append(data, 0)
if need_edit_buffer_file_link:
G["VimBufferLineFileLink"].setdefault(path,[])
G["VimBufferLineFileLink"][path] = file_links + G["VimBufferLineFileLink"][path]
elif mode is 'i':
while len(t_buffer) <= n+1:
t_buffer.append('')
if need_edit_buffer_file_link:
G["VimBufferLineFileLink"][path].append({})
t_buffer.append(data, n)
if need_edit_buffer_file_link:
G["VimBufferLineFileLink"].setdefault(path,[])
G["VimBufferLineFileLink"][path] = G["VimBufferLineFileLink"][path][:n] + file_links + G["VimBufferLineFileLink"][path][n:]
elif mode is 'del':
assert(del_range != () )
if type(del_range) is int:
del t_buffer[del_range]
del G["VimBufferLineFileLink"][path][del_range]
elif type(del_range) in [ tuple, list ]:
del t_buffer[del_range[0]:del_range[1]+1]
del G["VimBufferLineFileLink"][path][del_range[0]:del_range[1]+1]
else:
assert(0)

def go_win( path_or_name = '', pos = (), search_word = ''):
if not path_or_name:
return
# path_or_name = vim.current.buffer.name
Open(path_or_name)
if re.search('\w+',search_word):
vim.current.window.cursor = (1,0) # search from top in case match to left vim warning
vim.command('/\c\<'+search_word+'\>')
if pos:
cursor = (pos[0]+1, pos[1])
vim.current.window.cursor = cursor

############################################################################
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐