# spacemacs.d **Repository Path**: my2817/spacemacs-d ## Basic Information - **Project Name**: spacemacs.d - **Description**: spacemacs, focus on verilog-mode - **Primary Language**: Emacs Lisp - **License**: Not specified - **Default Branch**: master - **Homepage**: http://my2817.gitee.io/spacemacs-d - **GVP Project**: No ## Statistics - **Stars**: 216 - **Forks**: 6 - **Created**: 2017-06-03 - **Last Updated**: 2025-07-03 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README #+AUTHOR: 何云 #+title: spacemacs.d for Verilog #+OPTIONS: ^:nil * 目录 :TOC_4_gh:noexport: - [[#系统环境][系统环境]] - [[#windows][windows]] - [[#linux][linux]] - [[#terminal-之-zsh][terminal 之 zsh]] - [[#编辑器之-emacs][编辑器之 emacs]] - [[#安装][安装]] - [[#初识][初识]] - [[#启动][启动]] - [[#file-文件操作][File: 文件操作]] - [[#buffer-操作][Buffer: 操作]] - [[#project][Project:]] - [[#windows-1][Windows]] - [[#layouts][Layouts]] - [[#编辑][编辑]] - [[#帮助系统][帮助系统]] - [[#一些函数][一些函数]] - [[#regexp-正则表达式][regexp 正则表达式]] - [[#中文][中文]] - [[#字体][字体]] - [[#输入法][输入法]] - [[#awesome-modes][Awesome Modes]] - [[#verilog-mgde][Verilog-mgde]] - [[#配置][配置]] - [[#verilog-auto][verilog-auto]] - [[#auto_template][AUTO_TEMPLATE]] - [[#常用的一些功能][常用的一些功能]] - [[#autooutput][AUTOOUTPUT]] - [[#跳转][跳转]] - [[#flycheck][flycheck]] - [[#代码折叠][代码折叠]] - [[#自动只读][自动只读]] - [[#org-mode][Org-mode]] - [[#variables-or-options][variables or options]] - [[#code-sample][Code sample]] - [[#awesome-pair][awesome-pair]] - [[#citre][citre]] - [[#使用流程][使用流程]] - [[#bug][Bug]] - [[#性能][性能]] - [[#awesome-tools][Awesome Tools]] - [[#fzf][fzf]] - [[#ripegrep][ripegrep]] - [[#universal-ctag][universal-ctag]] - [[#oh-my-zsh][oh-my-zsh]] - [[#插件][插件]] - [[#autohotkey][autohotkey]] - [[#example][Example]] - [[#everything][Everything]] - [[#utools][utools]] - [[#total-commander][Total Commander]] - [[#snipaste][Snipaste]] - [[#switcheroo][Switcheroo]] - [[#xclip][xclip]] - [[#carnac][Carnac]] - [[#sumatrapdfreader][sumatrapdfreader]] - [[#性能-1][性能]] - [[#使用-profiler-start-和-profiler-report-来测试-emacs-性能][使用 profiler-start 和 profiler-report 来测试 Emacs 性能]] - [[#savehist-造成卡顿][savehist 造成卡顿]] * 系统环境 tips: 以下系统环境安装过程中,如果下载包比较慢,可以试试搜索一下其对应的国内源,说不一定可以加速 ** windows + cygwin + mysys2 + wsl: 这货要求系统是win10 ** linux 既然都选择了 linux, 您随意就好 * terminal 之 zsh 一般终端下默认的 shell 为 bash, 不妨( ~强烈推荐~ )换一个试试,比如此处提到的 zsh 。 + 各系统环境下都有自己的安装方法,都不用搜索老大哥出马,百度都能解决,再此我就给一下源码文件地址: https://sourceforge.net/projects/zsh/files/ + 只安装 zsh 的话也不堪重用,接下来给它安装插件 oh-my-zh: https://ohmyz.sh/ + 跟着其提示安装就好,其默认会把文件安装在 ~/.oh-my-zsh 下。对默认配置不满意的话可以更新 ~/.zshrc + 默认打开的插件只有 git, 见 ~/.zshrc 里的变量 plugins 的值,实际上我的插件设置如下 #+begin_example plugins=(git zsh-syntax-highlighting zsh-autosuggestions fzf z) #+end_example 其中三个插件还需要额外安装一下,工具如何使用还请看其相关文档…… - https://github.com/zsh-users/zsh-syntax-highlighting.git - https://github.com/zsh-users/zsh-autosuggestions - https://github.com/junegunn/fzf + 上一步给出的地址涉及到了 github, 这里又牵扯到版本管理工具 [[https://git-scm.com][git]], 类似于 svn, 各系统环境下请自行查找安装方法 + 不太记得前面的步骤是否会把用户登录的默认 shell 更新到 zsh, 没有的话就通过命令 chsh 自己动手改一下 * 编辑器之 emacs [[https://github.com/syl20bnr/spacemacs][The best editor is neither Emacs nor Vim, it's Emacs *and* Vim! ]] 在寻找写 verilog 代码的解决方案时接触到 [[https://www.veripool.org/wiki/verilog-mode][verilog-mode]], 然后才是 emacs, 接着便是 [[https://github.com/syl20bnr/spacemacs][spacemacs]], 最后才形成了我的 [[https://gitee.com/my2817/spacemacs-d][spacemacs.d]] ** 安装 + emacs: https://www.gnu.org/software/emacs/download.html + 以上是源码文件,安装过程中的问题都可通过搜索解决,就不啰嗦废话 + 也可通过各系统集成的包管理器安装,只是默认安装的版本可能不一样 + spacemacs: 给 emacs 套壳子 #+begin_src sh git clone https://gitee.com/mirrors/spacemacs ~/.emacs.d cd ~/.emacs.d git checkout -b develop origin/develop; #默认的master分支更新较慢 #+end_src + ~/spacemacs.d: 针对 verilog 和个人习惯做了一些配置 走到这一步,如果前面猴急,已经启动过 emacs, 请先将 "~/.emacs" 文件删除 #+begin_src sh git clone https://gitee.com/my2817/spacemacs-d ~/.spacemacs.d #+end_src + 启动 emacs 完成所有依赖的插件安装 + 终端中输入 "emacs" 启动并开始一大堆未知插件安装…… + 经验:vnc 登陆的桌面需要设置环境变量: export DISPLAY=:N.0 (其中 N 为 vnc 端口号) + 在 "~/.spacemacs.d/elpa-backup" 放了一个打包好端插件包,参考内部端说明文件使用 + 输入命令后 emacs 变为绿色,说明 oh-my-zsh 的 zsh-syntax-highlighting 插件开始工作了 + 过程中可能需要多次重启 + 注意观察终端,刚键入 "e" 时,其自动在后面补全了 "macs", 但光标位置不在词尾,说明 oh-my-zsh 的 zsh-autosuggestions 插件开始工作了 + 此时可以选择手动将后面的 "macs" 输全,再回车 + 或则按方向键 ~→~ 回车 + 本人更习惯快捷键 ~CTRL-e 回车~ + 此步骤需要联网,如果是在无网络环境上,劝退吧…… + 或者,在有网环境上先安装好,再把 "~/.emacs.d" "~/.spacemacs.d" 打包到无网络环境中…… ** 初识 emacs 中所有的操作都对应一个定义好的 function, 为了方便,已经将部分 function 绑定到特定的按键上,如后文介绍到的快捷键;一些知道名字,不知快捷键的 function 可以通过 ~Alt-x~ (同时按下 ALT 和 x 两个键),然后输入对应的 function 名字进行执行。 spacemacs 中默认安装了 evil 插件,就我的使用经历,其模拟了 vi 所有的操作方式。 *** 启动 + ~emacs~ :如果直接使用本命令启动,每次都会打开一个全新进程,速度较慢,且各进程间的操作是独立的 + ~emacsclient -c -a “”~ : ~推荐使用本命令启动~ + 第一次会启动后台守护进程,较慢 + 注意:不能关闭运行本命令的终端,个人习惯将其挪到不常用的 workspace 中 + 即使关闭当前的 frame (通过 gui 右上角的关闭按钮),也不会结束该进程,再次通过本命令(不一定在第一次启动终端里)可快速连接到守护进程,状态不会丢失 + 完全关闭:~spc q q~, 或者执行命令:kill-emacs *** File: 文件操作 + ~spc~: 指代空格键,spacemacs 中将其设置为 leader key, 敲一下它,会给出一个引导菜单,每个字母对应一个操作 + ~spc f~: 两个按键用空格分隔,表示按键序列,先敲一下 ~spc~ 后敲 ~f~,文件操作相关,下面还有二级菜单,可以都看看,都是字面意思,就不详细介绍 + ~spc f r~: 打开最近打开过的文件,通过访问历史,速度更快,似乎是我用的较多的操作 + ~ctrl-g~: 两个键中间有连字符,表示两个键同时按下;操作过程中的后悔药,中断当前操作的意思 + ~ctrl~: 这个键在 emacs 里用的比较多,同样的还有 ~alt~ ,为了偷懒,书写时:~ctrl~ == ~C~; ~alt~ == ~M~. + ~spc f f~: 过程中,浏览文件路径时,不论当前路径有多深,键入两个 ~/~, 会直接跳到文件系统的根目录,键入 ~~~, 则会跳转到用户的 HOME 目录下 + ~C-j~: 同向下方向键,同 ~C-n~ + ~C-k~: 同向上方向键,同 ~C-p~ + ~C-h~: 到上一级目录 + ~C-l~: 同回车 *** Buffer: 操作 + ~spc b~: 文件打开读入内存后就不叫文件了,叫 "buffer", 相关操作集中定义在此 + ~spc b r~: 还是最近打开过的文件 + 在 normal 模式下移动方式和 vi/vim 一致, + 上下左右:~hjkl~, + 上下滚动:~C-e~, ~C-y~ + 居中:~z z~, + 翻页: ~C-f~ ~C-b~ + insert 模式下:~spc~ 不能作为 leader key 直接呼出引导菜单了,可以用 ~M-m~ 代替 + ~Esc~: 返回 normal 模式 + ~C-l~: 光标所在行居中 + ~C-[~: 仍然返回 normal 模式 *** Project: 依赖插件:projectile. 一切皆文本,所谓 Project, 都是人为定义,这里的说一下定义 Project 的方式。 + 插件会自动识别版本管理系统,设置其根目录为 Project 的根目录,比如 git 的标志目录为 .git, SVN 的标志目录为最顶层的 .SVN + 个人习惯,任何项目根目录,先"git init" 初始化为 git 仓库 + 手动指定,在 Project 的根目录下生成文件 ".projectile", 插件识别文件后将其所在目录设置为 Project 的根目录 + 这个文件在生成 Project 的 TAG 文件时还有用,后面再说 + ~spc p~: Project 相关操作集中定义,前提是当前打开的文件已经在一个 Project 内部 + ~spc p f~: 打开 Project 内的文件 + 文件太多影响查找速度,如果是通过 git 识别 Project, 通过 .gitignore 文件内容忽略不需要查找的文件 + ~spc p b~: Project 内的 buffer 切换,限定在 Project 内部,再也不怕同时打开多个同名文件 + ~spc p r~: 打开 Project 内最近打开过的文件 + ~spc p G~: 根据语法,生成 Project 内所有源码文件的 TAGS 文件,放在 Project 的根目录下 + 本快捷键使用 spacemacs 的策略生成 tag ,目前发现 citre 更适合自己的使用习惯,请参考该插件的文档使用 + 需要外部工具 ctags 的支持,建议安装的版本是 [[https://github.com/universal-ctags/ctags][universal-ctags]] + TAGS 文件太大,影响查找速度,可以在 .projectile 里增加以下内容将用不上的目录排除,如下: #+begin_example -/digital/to_FPGA -/digital/sch -/digital/netlist #+end_example + ~C-]~: 在 TAGS 中搜索光标所在位置的 symbol, 如果只有一个则直接跳转到其定义处;如果多个,则给出候选列表 + ~C-0 C-]~: 同 ~C-]~, 但要求用户输入 symbol, 使用 “substr” 方式查询 + ~C-o~: 反向跳转 *** Windows 如下所示,最大那个框叫 frame, 一个 frame 可以分割为多个 window, 每个 wdinow 里可以打开一个独立的 buffer ( 也可以是相同的,按使用需求选用吧 ), #+begin_src artist +------------------------+--------------------------+ | | | | | | | | | | window 1 | window 2 | | | | | | | | | | +------mode line---------+--------mode line---------+ | minibuffer | +---------------------------------------------------+ - this diagram is drawed in artist-mode - don't enable line number in artist-mode - use set-mouse-color after exit artist-mode #+end_src + ~spc w /~ 左右分割 window + ~spc w -~ 上下分割 window + ~spc w d~ 关闭当前 window + ~spc w Num~ 跳转到对应编号的 window, 编号在 window 左下角, + ~spc w w~ 在 window 间循环跳转,只有两个 window 时习惯用这个,无脑切换 *** Layouts 本意是说多窗口布局吧,, 可以保存起来,多个 layout 可以比较方便的切换,而我个人习惯是将每个 Project 保存一个 layout, 方便不同 Project 间的切换,操作流程如下: + ~spc l~: + ~spc l ?~: 查看按键绑定提示,此步随意 + ~spc l 0~: 新建一个 layout, 按提示输入一个名字,按我的用法就是输入 Project 名字 + ~spc p d~: 打开 Project 的根目录 + ~spc l S~: 保存当前的 layout 到一个文件 + 选择前面输入的 Project 名字并回车确认 + 选择 "[>DONE<]" 并回车 + 选择保存 layout 文件的位置并输入文件名,我习惯放在 "~/.emacs.d/.cache/layouts" 目录下 + ~spc l L~: 打开保存好的 layout, 对于我来说是 Project *** 编辑 + ~spc x a~: align, 快捷键用于代码格式化,对齐 + ~spc j w C~: 在当前可视范围内,快速跳转到任何以字符 ~C~ 开始的 symbol 处,如果有多处,根据提示继续输入提示的按键序列 + ~spc j j C~: 同上,但不要求输入的 ~C~ 是 symbol 的开始字符 + 多位置编辑替换,对搜索列出的候选项进行编辑 + ~spc s p~ 搜索当前 Project,或者 ~spc s d~搜索当前目录 + 列出候选项后 ~C-c C-e~,会给出新的buffer,进入多处替换模式 + 在该buffer中对候选项进行编辑 + 编辑完成后,进入普通模式,按~,~ ,根据提示 + wgrep-abort-changes:放弃修改 + wgrep-finish-edit:完成修改 + wgrep-save-all-buffers:将所有修改保存到文件 + ~q~ 退出该模式 + diff 参考 ediff-* 系列命令,很好用,该系列工具会出现至少包含一个名为 "*Ediff Control Pannel*" 的窗口,只有选中它时,才能使用其相关命令: ~?~ 查看帮助说明,再次 ~?~ 隐藏帮助说明, ~# #~:比较时忽略空白符,执行此操作后再进行一次 ~!~ , 就不会受空白符的影响了 ediff-current-file: 对当前文件更改前后的内容进行比较 |------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------| | 比较项目 | 说明 | | ediff-regions-linewise, ediff-regions- | 询问两个缓冲区的名字,然后比较相应的区域。不过你只能在每一个缓冲区中选定一个区域,而不能比较一个文件缓冲区的两个区域。 | | ediff-buffers | 询问两个缓冲区的名字,然后比较 | | ediff-files | 询问两个文件的名字,加载之,然后比较 | | ediff-windows-linewise, ediff-windows-wordwise | 让你选两个窗口,然后比较窗口的内容。 -linewise- 函数比 -wordwise- 函数要快, | | | 但另一方面, -wordwise- 工作方式更好,尤其是小区域作业时。 -linewise- 一行一行地比较, -wordwise- 一个单词一个单词地比较 | |------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------| |----------------+-----------------------------------+----------------------------------------------------------------------| | 快捷键 | 命令 | 说明 | |----------------+-----------------------------------+----------------------------------------------------------------------| | q | ediff-quit | 关闭 ediff control buffer, 并退出 ediff | | Space 或 n | ediff-next-difference | 下一个差异处 | | Del 或 p | ediff-previous-difference | 上一个差异处 | | [n]j | ediff-jump-to-difference | 有数字前缀 [n] 修饰,第n个差异处,n可为负数 | | v 或 C-v | ediff-scroll-vertically | 所有缓冲区同步向下滚动 | | V 或 M-v | ediff-scroll-vertically | 所有缓冲区同步向上滚动 | | < | ediff-scroll-horizontally | 所有缓冲区同步向左滚动 | | > | ediff-scroll-horizontally | 所有缓冲区同步向右滚动 | | (vertical bar) | ediff-toggle-split | 切换缓冲区布局方式, 水平和竖直 | | m | ediff-toggle-wide-display | 在正常 frame 大小和最大化之间切换 | | a | ediff-copy-A-to-B | 把Buffer-A的内容复制到Buffer-B | | b | ediff-copy-B-to-A | 把Buffer-B的内容复制到Buffer-A | | r a 或 r b | ediff-restore-diff | 恢复 Buffer-A 或 Buffer-B 差异区域中的被修改的内容 | | A 或 B | ediff-toggle-read-only | 切换 Buffer-A 或 Buffer-B 的只读状态 | | g a 或 g b | ediff-jump-to-difference-at-point | 根据光标在缓冲区中的位置,设置一个离它们最近的差异区域为当前活动区域 | | C-l | ediff-recenter | 恢复先前的所有缓冲区比较的高亮差异区。 | | ~!~ | ediff-update-diffs | 重新比较并高亮差异区域 | | w a 或 w b | ediff-save-buffer | 保存 Buffer-A 或 Buffer-B 到磁盘 | | E | ediff-documentation | 打开 Ediff 文档 | | z | ediff-suspend | 关闭 ediff control buffer, 只是挂起,可在以后恢复 ediff 状态 | |----------------+-----------------------------------+----------------------------------------------------------------------| *** 帮助系统 + ~C-h m~: 列出当前打开的所有插件,以及对应的按键绑定 + ~C-Mouse_Right~: ctrl+鼠标右键呼出菜单 + spacemacs document: ~/.emacs.d/doc/DOCUMENTATION.org + ~C-h f~: ~spc h d f~, 查看 function 的说明文档 + ~C-h v~: ~spc h d v~, 查看 variable 的说明文档 ** 一些函数 + flush-lines: 删除匹配的行,空行的正则表达式为"^\s-?+$" (即使有空白符,也算空行) + keep-lines: 如名字,功能与上一个命令相反 + sort-lines: 对选中的行进行排序 + 使用linux的 sort 命令进行复杂排序,比如第几个字段作为关键词进行排序 + delete-duplicate-lines: 选中要操作的区域,再执行本命令(M-x delete-duplicate-lines) 或者使用以下awk命令(不需要事先排序)。原理为将要匹配的内容作为数组下标,如果该下标对应的值为 0 则打印,否则不打印。该命令中的 $0 表示行内容完全重复时,进行删除操作,相应替换为$n,则表示当第n个字段相同时,进行删除操作。 #+BEGIN_SRC awk awk '!a[$0]++{print $0}' #+END_SRC + ivy-push-view:将当前的窗口即对应的buffer信息保存起来,通过 ivy-switch-view可重新恢复该视图 + my-highlight-symbol-in-frame: 通过多个 window 打开多个不同的文件),高亮显示光标下的 symbol (在所有的文件中) + transpos-sexps: 交换光标所在位置前后两个元素,~spc x t e~,同时,还有其他 trans-* 可参考 ** regexp 正则表达式 [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Regexps.html#Regexps][regexp online doc]] 语法见相关文档: 菜单 help-> search documentation ->,提示输入关键词,输入 "regexp" 凡事提示regexp的地方,均可使用regexp, * 中文 ** 字体 + 默认的字体配置在 "~/.spacemacs.d/init.el" 中,见变量 "dotspacemacs-default-font" + 本配置中,为了达到 org-mode 中的表格对齐效果,使用了 [[https://github.com/tumashu/cnfonts][cnfonts]] 插件,如果不需要,在文件 "~/.spacemacs.d/init.el" 中,注释掉变量 my-config-packages 内的 cnfonts 即可 + 字体安装 + 下载字体文件到 "~/.fonts" 目录(仅对当前用户生效,对系统安装的话大概是 "/usr/share/fonts" 目录),并在该目录下执行以下命令: #+begin_src sh mkfontscale mkfontdir fc-cache #+end_src ** 输入法 本配置中有两个输入方案可供使用: + [[https://github.com/tumashu/pyim][pyim]] + 本方案不需要其他工具配合使用 + [[~/.spacemacs.d/layers/my-config/packages.el][配置]]文件中找到以下的代码通过使用分号注释保留自己使用的输入法即可 #+BEGIN_SRC lisp (setq pyim-default-scheme 'wubi) (setq pyim-default-scheme 'quanpin) (setq pyim-default-scheme 'xiaohe-shuangpin) #+END_SRC + [[https://github.com/DogLooksGood/emacs-rime.git][emacs-rime]] + 如文档所述,其需要外部输入工具 rime 的支持,其如何配置请自行查询 + 在目前的配置中,会把 emacs-rime 的代码下载到 "~/.emacs.d/.cache/quelpa/build/rime" 目录下,且需要手动编译(编译时还有错,安提示修改) + [[~/.spacemacs.d/layers/my-config/packages.el][配置]], 文件中需要设置 rime--module-path 变量到编译好的 librime-emacs.so 文件 + 在 emacs 中通过以下变量配置选择输入方案,在我的[[~/.spacemacs.d/layers/my-config/packages.el][配置]]中有两个地方设置了该变量,最后生效的是 emac-rime, 请根据需要选择注释其中一处 #+begin_src lisp (setq default-input-method "pyim") #+end_src * Awesome Modes ** Verilog-mgde 一般遇到的问题、需求,别人已经帮我们解决,见[[https://www.veripool.org/projects/verilog-mode/wiki/Faq][Faq]];在 verilog 模式下通过 ctrl + 鼠标右键呼出菜单,有3个 verilog 相关的菜单可关注一下 *** 配置 verilog相关插件有两个: + [[https:www.veripool.org][verilog-mode]] : 虽然emacs本身已经集成了,但不一定是最新版本(我一般是官网下载后,直接覆盖emac自带的,反正emacs都是自己安装),另外意外的从官网发现了verilator,verilog-perl,似乎都比较好玩儿 + [[file:layers/my-config/local/my-verilog/my-verilog.el][my-verilog.el]] : 这个文件的原始版本,是从网上抄过来的,现在似乎找不到出处,如有版权问题,麻烦提醒一下,谢谢! *** verilog-auto 当执行verilog-auto时,可能出现提示 "end xxxxx properties"信息,但verilog-auto并没有执行完成,使用emacs的batch mode解决 #+BEGIN_SRC sh emacs --batch file.v -f verilog-batch-auto #+END_SRC 另,在我的配置中改写了verilog-mode中的一些函数,执行以上命令可能会出错,请使用以下命令: #+BEGIN_SRC shell emacs --batch file.v -l path/to/projectile.el -f verilog-batch-auto #在spacemacs中, projectile.el位置 ~/.emacs.d/elpa路径下,请自查 #+END_SRC **** AUTO_TEMPLATE 详细说明见 ~C-h f verilog-auto-inst~ ****** 调用 lisp 处理通过正则表达式获取的字符串 以下示例中使用 ~@"{lisp_expression}"~ 的写法,双引号内部被当作 lisp 执行,使用匹配分组编号传递需要处理的,对于匹配到的字符串,还应该加上双引号,所以以下示例中包含转义后的双引号 #+begin_example /*test AUTO_TEMPLATE ( .\(.*vsync.*\) (@"(upcase \\"\1\\")"), )*/ #+end_example 在 lisp 表达式中,可以使用以下变量: - vl-name Name portion of the input/output port. - vl-bits Bus bits portion of the input/output port (`[2:0]'). - vl-mbits Multidimensional array bits for port (`[2:0][3:0]'). - vl-width Width of the input/output port (`3' for [2:0]). May be a (...) expression if bits isn't a constant. - vl-dir Direction of the pin input/output/inout/interface. - vl-memory The unpacked array part of the I/O port (`[5:0]'). - vl-modport The modport, if an interface with a modport. - vl-cell-type Module name/type of the cell (`InstModule'). - vl-cell-name Instance name of the cell (`instName'). ****** 获取 InstName, 作为信号名的一部分 以下写法中,使用变量 `vl-cell-name` 获取 InstName, 第二个 “@” 字符的默认行为是获取在 InstaName 中查找到的第一个数字 #+begin_example /*test AUTO_TEMPLATE ( .\(.*\) (@"vl-cell-name"_@_\1[]), );*/ #+end_example 如果想改变 "@" 在 InstNmae 中匹配的内容,则需要在 "AUTO_TEMPLATE" 后面(不可以换行)跟一个正则表达式,用于控制 "@" 的内容,以下示例会捕获 InstName 中最后一个数字: #+begin_example /*test AUTO_TEMPLATE "\([0-9]?*\)$" ( .\(.*\) (@"vl-cell-name"_@_\1[]), );*/ #+end_example *** 常用的一些功能 + verilog-header: 原定义在verilog-mode.el中,我做了一定修改,放在my-verilog.el中,哪天跳槽了记得要改(前面已经说过了怎么查该函数对应的快捷键) + 代码补全:基于skeleton代码片断、框架补全,输入关键字,按照列表选择,可以不用方向键, ~c-j~ : down; ~c-k~ : up; ~c-l~ : 相当于回车 本补全方式中,有时可能需要用户输入相应的信息,此时需要从minibuffer输入,此时不能使用关键字补全功能 + [[file:img/company-module.png][company-keyword-module]] + [[file:img/module-expand.png][keyword-expand-module]] + yasnippet 代码片断补全,暂时没有加入到补全后端里,需要快捷键触发: ~M-m i s~ ,always as eg: + [[file:img/yasnippet-always.png][yasnippet-always]] + [[file:img/yasnippet-always-2.png][yasnippet-always2]] : 与skeleton不同,用户输入时不会使用minibuffer,同样可以使用关键字补全功能;使用tab跳转到下一个需要输入的位置 + 自加:"var ++" 被展开为 " var <= #1 var + 1'b1;" + 自减:"var --" 被展开为 " var <= #1 var - 1'b1;" + 清零:"var clear" 被展开为 " var <= #1 {WIDTH_EXPR{1'b0}};" + 置位:"var set" 被展开为 " var <= #1 {WIDTH_EXPR{1'b1}};" + 翻转:“var toggle” 被展开为 " var <= #1 ~var;" + my-verilog-create-tb: 功能如名字所示,其会新建一个buffer,保存 ~c-x c-s~ , ~c-c c-a~ 执行verilog-auto + verilog-auto时找不到instance? Faq中已经提示过了如何解决,或者参考 【 ~c-h v verilog-library-flags~ 】 麻烦的是每次遇到这问题都得在文件尾添加该语句。 我的解决方案是利用[[https://www.gnu.org/software/emacs/manual/html_node/emacs/Directory-Variables.html#Directory-Variables][49.2.5 Per-Directory Local Variables]], 假设使用以下目录结构: #+begin_example project-root +---digital +--rtl +--sub-module-a | +--sub-module-a.v +--subm-module-b +--subm-module-b.v #+end_example 命令 ~my-project-dir-local-init~ 会在project的根目录下生成一个.dir-locals.el的文件,内容如下,将 {protject-root}/digtal/rtl 路径之下的所有包含 .v 文件的路径都加入到 verilog-auto 的搜索路径 verilog-library-directories 中,路径下的 .v 文件均可被 verilog-auto 找到,可按需修改。 #+begin_src lisp ((verilog-mode . ( (eval . (setq verilog-library-directories '(".")) ) (eval . (mapcar (lambda (file) (add-to-list 'verilog-library-directories (file-name-directory file))) (directory-files-recursively (concat (projectile-project-root) "digital/rtl") "\.[s]?v$") ) )) )) #+end_src + my-verilog-align-indent-inst-signal: 初始化代码如以下格式,其中 my-verilog-min-spc-for-align 用于控制端口和信号名之间最小的空格数量,默认值为1, 如果要关闭其默认执行,参考其帮助文档 #+begin_src verilog module top(/*autoarg*/); sub1_x u_sub1 (/*autoinst*/); sub2_xxxxx u_sub2 (/*autoinst*/); sub3 #(/*autoinstparam*/) u_sub3(/*autoinst*/); endmodule // top module sub1_x(/*autoarg*/); input aa, bb, cc; output dd; endmodule // sub1 module sub2_xxxxx(/*autoarg*/); input aa, bb, cc; output dd; endmodule // sub2 module sub3 #(parameter PAR_A = 10, PAR_BB = 20, PAR_ccc = 30 ) (/*autoarg*/); input aaxx, bbxx, cc; output dd; endmodule // sub3 // Local Variables: // my-verilog-min-spc-for-align: 20 // End: #+end_src 默认会在"verilog-auto"后自动执行本命令(如果模块实例已经例化完成<--各端口信号独占一行,也可手动执行"my-verilog-align-indent-inst-signal")。结果如下,所有实例的左括号对齐,所有端口信号对齐,注意以下示例代码结束最后几行是在设置本地变量,将 my-veriog-auto-align 的值设置为 nil, 则不会在 verilog-auto 时自动执行对齐函数 #+begin_src verilog -n module top(/*autoarg*/); sub1_x u_sub1 (/*autoinst*/ // Outputs .dd (dd), // Inputs .aa (aa), .bb (bb), .cc (cc)); sub2_xxxxx u_sub2 (/*autoinst*/ // Outputs .dd (dd), // Inputs .aa (aa), .bb (bb), .cc (cc)); sub3 #(/*autoinstparam*/ // Parameters .PAR_A (PAR_A), .PAR_ccc (PAR_ccc)) u_sub3 (/*autoinst*/ // Outputs .dd (dd), // Inputs .aaxx (aaxx), .bbxx (bbxx), .cc (cc)); endmodule // top module sub1_x(/*autoarg*/ // Outputs dd, // Inputs aa, bb, cc ); input aa, bb, cc; output dd; endmodule // sub1 module sub2_xxxxx(/*autoarg*/ // Outputs dd, // Inputs aa, bb, cc ); input aa, bb, cc; output dd; endmodule // sub2 module sub3 #(parameter PAR_A = 10, PAR_BB = 20, PAR_ccc = 30 ) (/*autoarg*/ // Outputs dd, // Inputs aaxx, bbxx, cc ); input aaxx, bbxx, cc; output dd; endmodule // sub3 // Local Variables: // my-verilog-min-spc-for-align:1 // my-verilog-auto-align:t // End: #+end_src + verilog-insert-indices:从“0”开始在当前列插入索引号;如下代码,光标移动到第一行代码的“a”后面执行本命令,按提示输入编号的最大值 #+begin_src verilog a| = b a[ 0] = b a = b a[ 1] = b a = b a[ 2] = b a = b a[ 3] = b a = b ==> insert-indices ==> a[ 4] = b a = b a[ 5] = b a = b a[ 6] = b a = b a[ 7] = b a = b a[ 8] = b #+end_src + verilog-generate-numbers:类似verilog-insert-indices #+begin_example buf buf| buf buf000 buf buf buf buf001 buf buf buf buf002 buf buf buf buf003 buf buf ==> generate-numbers ==> buf buf004 buf buf buf buf005 buf buf buf buf006 buf buf buf buf007 buf buf buf buf008" #+end_example + my-insert-indices: 功能同上两个,可以指定插入的起始值、插入格式 + my-repeat-current-line-with-indices: 重复当前行,并在光标所在列插入格式化序号 + 嵌入其他格式代码 + 本配置可识别以下格式的多行注释,其内部会被识别为 org-mode, 从而使用 org-mode 的 source code 编辑功能 #+begin_src verilog /*-- org !org --*/ #+end_src + plantuml 代码 在以下代码中嵌入了 plantuml 代码,光标在代码区域内时,通过 ~C-c C-c~ 会自动生成名为 fsm.png 的状态机转换图 #+begin_src verilog module src_test; /*-- org ,#+begin_src plantuml :file fsm.png @startuml title Main FSM of dat_pop state idle: default state wait: a transition state pop: data output idle --> idle : reset idle -down-> wait: posedge vsync wait -> pop: almose full pop -up->idle: error, need to reset @enduml ,#+end_src !org --*/ endmodule #+end_src + 字符图 利用 emacs 自带的 artist-mode, 在一个 buffer 内画好后再复制到代码中;或者在代码中插入以下格式代码,光标移动到 artist 后,按 ~C-c ‘~ ,会打开一个以 artist-mode 为 major mode 的 buffer, 画好图后 ~, c~ 确认并退出,或者 ~, k~ 进行撤销 #+begin_src verilog /*-- org ,#+begin_src artist ,#+end_src !org --*/ #+end_src + [[https://plantuml.com/][plantuml]] 需要 jre 支持 + [[http://ditaa.sourceforge.net/][ditaa]] 需要 jre 支持 + [[http://graphviz.org/][graphviz-dot]] + my-verilog-sig-width-op: 在当前 symbol 上标注信号的位宽并复制,有以下快捷键标定 + ~spc s v~ : 复制并显示 + ~C-0 spc s v~: 删除所有的位宽标注信息 *** AUTOOUTPUT 使用以下变量可将不希望出现再端口列表中的信号排除 #+begin_src verilog // // Local Variables: // verilog-auto-output-ignore-regexp:"\\(RSTN_EXT\\)" // verilog-auto-input-ignore-regexp:"\\(CREG_SPD_COMB_EN\\)" // End: // #+end_src 如果一个信号通过 autoinst 已经自动连接完成,需要强制加入到端口列表中,可以通过在适当的位置焦加入 output/input 关键字解决。 另一种情景是一个信号 A 如果已经通过 autooutput 呈现再端口列表中,端口列表的实顺序已经固定下来。此时如果将信号 A 接入到其他模块B中。信号 A 将不会自动出现再端口中,通过上面的方法的话可能改变端口顺序。此时可在例化模块 B 时,控制信号 A 的位置实现,如下代码所示,信号 A 前面没有类似 Inputs/Outputs 的关键字 #+begin_src verilog sub_B u_B ( .A (A), // Inputs .CC (CC), /*AUTOINST*/); #+end_src *** 跳转 + 通过 Project 中介绍 ctags,可跳转到 module/task/function/class 等的的定义处 + imenu: Buffer 内部 ~M-m s j~ 或者 ~SPC s j~ 提示如: [[file:./images/verilog-tag.png]] 通过 imenu 插件,其会搜索文件内的 module/inst/task/function 位置; 同时配置里改写了verilog-mode默认产生imenu的方式,verilog代码中加如类似 "//being: tagName" 的代码,将tagNmae加入到imenu中实现快速跳转到该tag, #+BEGIN_SRC verilog module sub3 #(parameter PAR_A = 10, PAR_BBBBBB = 20, PAR_ccc = 30 ) (/*autoarg*/ // Outputs dd, // Inputs aaxx, bbxx, cc ); input aaxx, bbxx, cc; output dd; localparam // begin:localparam par_af = 10, par_ad = 20; always @ ( /*AUTOSENSE*/ ) begin if (xx) begin:reset end else begin: proce end end task func_a; begin end endtask // func_a function func_a; begin end endfunction // func_a endmodule // sub3 #+END_SRC *** flycheck + 默认打开此功能,调用EDA工具对代码进行实时编译,简单低级错误可以立即提示,马上改掉。 + ~spc e v~: 大概得到如下信息,因为在我自己电脑上目前只安装了[[file:img/flycheck2.png][verilator]], 如果有多个EDA工具可用的话,可使用 ~spc e s~ 进行选择 #+begin_example Syntax checkers for buffer tb.sv in verilog-mode: verilog-irun (disabled) - may enable: Automatically disabled! - executable: Not found verilog-iverilog (disabled) - may enable: Automatically disabled! - executable: Not found verilog-leda (disabled) - may enable: Automatically disabled! - executable: Not found verilog-verilator - may enable: yes - executable: Found at /usr/local/bin/verilator_bin #+end_example + ~spc t s~ :语法检查器开关 + 自定义:参考 flycheck-define-checker 帮助文档,verilog-irun的定义在 "~/.spacemacs.d/layers/my-config/packages.el" *** 代码折叠 eamcs里代码太长的时候,可以使用下面的函数对begin-end代码进行折叠 - hs-hide-block,折叠前,光标要在begin的下一行 - hs-show-block, 展开光标所有行被折叠的代码 - 按键 tab: 先执行缩进,如果缩进没有改变光标位置,则尝试将光标区隐藏、显示 - 目前不能处理 `ifdef `ifndef 相互嵌套的情景 *** 自动只读 打开 verilog/SystemVerilog 文件后,自动在文件中搜索“Engineer : ”,并找到 user-login-name, 如果与当前用户名不一致,则将当前 buffer 设置为只读 ** Org-mode [[https://orgmode.org][Document]] [[http://doc.norang.ca/org-mode.html][Orange Your Life In Plain Text!]] 在任何 buffer 中使用插入 org 表格,使用 orgtbl-mode *** variables or options - org-export-headline-levels: 保留大纲示图的级数,默认为3, 再大的级别会在导出时转换为列表,同 #+OPTIONS: H:3 - org-export-with-sub-superscripts #+begin_src lisp ;;这2个一个是用于 export 的,一个是用于本地显示的,最好配置成一样保证一致性。 都配置成 '{}的话表示_和^后面只有像这样用才会被认为是上标/下标。 (setq org-export-with-sub-superscripts '{});; 同 #+OPTIONS: ^:{} (setq org-use-sub-superscripts '{}) #+end_src - "#+OPTIONS: ^:nil",在导出时,不将下划线转换为下标 #+begin_example ,#+HTML_HEAD: ,#+AUTHOR: 何云 ,#+title: Note of Synopsys tool chains ,#+OPTIONS: ^:nil #+end_example *** Code sample + org-babel,可以让许多不同语言的代码块一起工作 + 配置 #+BEGIN_SRC lisp (org-babel-do-load-languages 'org-babel-load-languages '((emacs-lisp . t) (ruby . t) (ditaa . t) (python . t) (sh . t) (latex . t) (plantuml . t) (dot . t) (R . t))) #+END_SRC + 示例 #+BEGIN_SRC verilog module test; input a; output b; endmodule #+END_SRC #+begin_src dot :file filename.jpg :cmdline -Kdot -Tjpg :exports code digraph G { size="8,6" ratio=expand edge [dir=both] plcnet [shape=box, label="PLC Network"] subgraph cluster_wrapline { label="Wrapline Control System" color=purple subgraph { rank=same exec sharedmem [style=filled, fillcolor=lightgrey, shape=box] } edge[style=dotted, dir=none] exec -> opserver exec -> db plc -> exec edge [style=line, dir=both] exec -> sharedmem sharedmem -> db plc -> sharedmem sharedmem -> opserver } plcnet -> plc [constraint=false] millwide [shape=box, label="Millwide System"] db -> millwide subgraph cluster_opclients { color=blue label="Operator Clients" rankdir=LR labelloc=b node[label=client] opserver -> client1 opserver -> client2 opserver -> client3 } } #+end_src #+begin_src plantuml :file 中文.png :cmdline -charset utf-8 @startuml start if ( 中文测试,这是什么 ) : bbb; endif @enduml #+end_src ** awesome-pair web:https://github.com/manateelazycat/awesome-pair.git, 其提供的 function 可方便进行成对的括号 ~()[]{}\"\"~ 插入与删除,其包含了一些边界算法。配置中的按键绑定与示例不同,见文件 ~/.spacemacs.d/layers/my-config/keybindings.el #+begin_example '|' 表示光标所在位置 before keys after ----------- ----------- ----------- fo|o bar spc m ( (foo) bar |(foo bar)| spc m { {(foo bar)} (foo |bar) spc m ) foo bar #+end_example ** citre https://github.com/universal-ctags/citre ctags required, jump to symbols' definition, include third part library 在 [[file:layers/my-config/packages.el][package.el]] 中默认将 uvm 源代码添加到 ctags 的索引目录中,见 "citre-edit-cmd-buf-default-cmd", 请按需修改。以便提供 uvm 代码相关的补全及源代码查看跳转 *** 使用流程 - spc p G : 生成、更新项目中所有代码的tags 文件 - 如果是第一次生成项目的 tags 文件。会有几个问题需要回答: - tag 文件保存在何处?没特殊讲究,就选 2 global - 后面两个问题默认指向项目的根目录,直接回车就好 - 最后,如果不需要对项目外的文件生成 tag, 按 buffer 提示,按 C-c C-c 结束;如果需要加入其他路径,在 buffer 最后按需添加文件路径即可,且必须保留一个路径 \".\", 表示当前项目的根目录 - C-]: 查找光标所在的 symbol, 如果只有一个则直接跳转到其定义处 在文件 layers/my-config/local/citre-auto-update/citre-auto-update.el:313 中定义了一个新 function,实现以下功能 - 如果当前已经选中一个区域,则将选中区域的自负串作为 ctags 的查询对象,匹配方式为 "substr" - 使用快捷键 ~C-0 C-]~, 要求用户输入需要查询的对象,使用 "substr" 进行匹配 - C-o: 反向跳转 *** Bug 在生成 imenu 时,如果 tags 文件过大(citre-tags-imenu-create-tags-file-threshold),其会在临时目录生成当前文件的临时 tags(/tmp/citre-imenu.tags) 文件, read tag 后不会删除该临时文件,其他用户对该文件没有写权限,从而导致其他用户不能更新 imenu( 得到错误的 imenu ), 通过以下修正,在临时文件名中加入登录用户名解决 #+begin_src lisp (defun citre-tags--imenu-temp-tags-file-path () "Return the temporary tags file path for imenu. This also works on a remote machine." (if (file-remote-p default-directory) (expand-file-name (concat (user-login-name) "_citre-imenu.tags") (tramp-get-remote-tmpdir (tramp-dissect-file-name default-directory))) (expand-file-name (concat (user-login-name) "_citre-imenu.tags") temporary-file-directory))) #+end_src *** 性能 ~citre-get-output-lines~ 处理较大 tags 文件时,可能卡在 ~accept-process-output~, 尝试在 ~callback~ 中对 result 长度进行判断,当达到设定值时,结束 process 处理,实际测试发现虽然返回补全列表数量并没有被控制,但卡死现象变少 [[file:./images/screenshot_20250526_111244.png]] citre-common-util.el:525 tag 文件较大,容易卡在 while, 实际此时 proc 已经退出 #+begin_src lisp (while (not finished) (accept-process-output)) #+end_src 更新为: #+begin_src lisp (while (and (not finished) (not (string= (process-status proc) "exit"))) (accept-process-out) (accept-process-out proc 0) ) (setq succes t) (setq finished t) #+end_src * Awesome Tools 本节集中罗列一下我平时用到的工具 ** fzf https://github.com/junegunn/fzf ** ripegrep https://github.com/BurntSushi/ripgrep ** universal-ctag https://github.com/universal-ctags/ctags ** oh-my-zsh https://ohmyz.sh *** 插件 #+begin_src sh plugins=(git zsh-syntax-highlighting zsh-autosuggestions fzf) #+end_src ** autohotkey https://www.autohotkey.com/ *** Example 搜索、激活窗口任务,默认绑定在大小写按键上:https://autohotkey.com/board/topic/30487-iswitchw-cosmetically-enhanced-edition/ ** Everything 快速文件搜索 ** utools https://u.tools/, 其可以集成 everything 的搜索结果,但不止与此,其还包含其他插件功能,比如聚合翻译、窗口切换( https://yuanliao.info/d/1461 可绑定快捷键到功能关键字上(比如 alt+` = winman))、迅飞ocr 文字识别。 ** Total Commander 多文件管理器,可多标签,且标签下的路径可更改(重新打激活标签后复位到原值)或固定 ** Snipaste 截图工具,两点在于可以贴图,把截图固定在桌面的最上层(可以固定多个截图) ** Switcheroo https://github.com/kvakulo/Switcheroo, 又一个窗口切换,类似于 iswitchw 和 utools 的 winman 插件, 在设置里勾选 "Activate Switcheroo with Alt+Tab", 替换 windows 默认的 Alt+Tab 功能 ** xclip copy cut file by by terminal command - https://github.com/astrand/xclip - https://github.com/larspontoppidan/clipboard-files ** Carnac 电脑实时按键展示 ** sumatrapdfreader 轻量级pdf阅读器,支持多标签页,高级选项下可直接编辑前景、背景色: https://www.sumatrapdfreader.org/ #+begin_example 豆沙绿 BackgroundColor = #c7edcb #+end_example * 性能 ** 使用 profiler-start 和 profiler-report 来测试 Emacs 性能 别是你使用 starter-kit 的时候,比如使用 spacemacs,spacemacs 最大的问题可能就是性能了,通过 profiler-start 开启之后,做半个小时的工作,然后调用 profiler-report,看看哪些地方耗时比较多吧。 我把 pangu-spacing, org-bullets, js2-refactor 全部 exclude 了,现在打开 org 文件和 js 文件提升了不少效率。 另外之前我的配置编辑 js 文件性能极低,原因竟然是因为我以前不知道从哪里 copy 了一句配置: #+BEGIN_SRC emacs-lisp ;; This line has very bad performance lose!!!!!!!!!!!!!!!!!!! (set-default 'imenu-auto-rescan t) #+END_SRC ** savehist 造成卡顿 由于未知原因,'~/.emacs.d/.cache/savehist' 文件非常大,造成保存历史记录时卡顿。退出所有 emacs 进程,删除该文件,重新启动。