VIM 适用于 LOG 文件的语法高亮配置

Posted querw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VIM 适用于 LOG 文件的语法高亮配置相关的知识,希望对你有一定的参考价值。

VIM 适用于 LOG 文件的语法高亮配置
阙荣文 - Que's C++ Studio

Github 源码

1. VIM 事件
VIM 在运行过程中,随着用户动作会触发很多*事件*,包括 VIM 程序启动,退出,某个文件被加载,等等.
[:h autocmd] 可以查看所有的事件列表.
VIM 脚本通过 autocmd 命令可以告知 VIM 程序"当某个事件触发时,执行某某某操作",
比如实现当 *.c 文件被加载时,应用 c 语言语法对该文件执行语法高亮着色,类似于编程语言中的回调函数或者钩子.

2. VIM filetype
filetype 是 VIM 运行时非常重要的一个变量,其值通常由一系列预定义的 autocmd 设置.
[:h filetype] 查看详细说明

[:filetype on] 开启 filetype 文件类型检测机制,该命令实际上执行 $VIMRUNTIME/filetype.vim 脚本,里面是一组用于根据文件扩展名识别类型的 autocmd 命令
[:filetype] 可以查看当前是否已激活 filetype 机制, [:syntax on] 命令会自动开启 filetype,所以通常情况下 filetype 机制都是激活的(因为用于编程环境的 VIM 总会打开 syntax)

$VIMRUNTIME/filetype.vim 文件在设置完默认的文件类型之后,执行命令 [runtime! ftdetect/*.vim]
表示加载所有 runtime 路径(包括系统级 VIM 运行时路径 $VIMRUNTIME /usr/share/vim/vim90 和用户级运行时路径 ~/.vim, [:echo &runtimepath] 可以查看全部路径) ftdetect 子目录下所有 .vim 文件的内容.
所以当需要添加自定义 filetype 时,通常我们把自己的规则放在 ~/.vim/ftdetect 目录下:
(a). 创建自己的 'runtimepath'
    [:!mkdir ~/.vim]
    [:!mkdir ~/.vim/ftdetect]

(b). 定义自己的 filetype autocmd
    [:w ~/.vim/ftdetect/log.vim]

    " 当发生事件 BufRead/BufNewFile (文件读入或新建) 时如果文件名以 log 结尾则设置 filetype 为 "log"
    " setf 等效于 set filetype
    au BufRead,BufNewFile *.log        setf log

现在,当我们打开一个扩展名为 log 的文件时 VIM 将自动设置 &filetype 为 "log",
同时, &filetype 值的变化会使 VIM 触发名为 FileType 的事件,后续 syntax 将根据该事件应用相应的语法着色规则.

3. VIM 语法着色机制
为了对文件内容着色, VIM 需要对文件内容分组,识别哪些内容分别属于关键字组,字符串组,常量组,预处理组等等.
组名虽然可以任意取,但大多数编程语言的规则都是类似的,且目前已经有一套惯例组名,我们自定义的分组规则最好也遵循这个惯例.
因为最终颜色主题方案 colorscheme 是根据这些组名来着色的,遵循命名惯例可以很方便的应用已有的颜色主题方案.

[:h group-name] 可以查看这些惯例组名,如下:
    *Comment    any comment

    *Constant    any constant
     String        a string constant: "this is a string"
     Character    a character constant: 'c', '\\n'
     Number        a number constant: 234, 0xff
     Boolean    a boolean constant: TRUE, false
     Float        a floating point constant: 2.3e10

    *Identifier    any variable name
     Function    function name (also: methods for classes)

    *Statement    any statement
     Conditional    if, then, else, endif, switch, etc.
     Repeat        for, do, while, etc.
     Label        case, default, etc.
     Operator    "sizeof", "+", "*", etc.
     Keyword    any other keyword
     Exception    try, catch, throw

    *PreProc    generic Preprocessor
     Include    preprocessor #include
     Define        preprocessor #define
     Macro        same as Define
     PreCondit    preprocessor #if, #else, #endif, etc.

    *Type        int, long, char, etc.
     StorageClass    static, register, volatile, etc.
     Structure    struct, union, enum, etc.
     Typedef    A typedef

    *Special    any special symbol
     SpecialChar    special character in a constant
     Tag        you can use CTRL-] on this
     Delimiter    character that needs attention
     SpecialComment    special things inside a comment
     Debug        debugging statements

    *Underlined    text that stands out, html links

    *Ignore        left blank, hidden  |hl-Ignore|

    *Error        any erroneous construct

    *Todo        anything that needs extra attention; mostly the keywords TODO FIXME and XXX

[:syn] 定义分组规则,包括:
(a) 单词匹配
    [syn keywrod <group-name> <keyword1 kw2 kw3 ...>]

(b) 单行匹配
    [syn match <group-name> <pattern>]

(c) 多行匹配
    [syn region <group-name> start=<pattern> skip=<pattern> end=<pattern>]

定义 log 语法只需了解上述 3 种规则就足够了,详情请参考 [:h syntax]
完成内容分组后,还需要再指定每个分组分别着上什么颜色才可以实现语法高亮效果,
这是命令 highlight 的工作([:h highlight] 查看详细说明),例如:
    " 设置组 "String" 的颜色
    [hi String guifg=#A1A6A8 guibg=NONE guisp=NONE gui=NONE ctermfg=248 ctermbg=NONE cterm=NONE]

对前述的每个惯用组名都指定一条 hi 命令,并把这些命令集中到一个文件中就是颜色主题方案.
现有的颜色主题方案安装在 $VIMRUNTIME/colors/ 目录下,命令 [:color <tab>] 可以切换颜色主题.

总结一下 VIM 语法着色的过程:
一切始于[:syntax on],实际执行脚本 [:source $VIMRUNTIME/syntax/syntax.vim],注册 autocmd 当 FileType 事件
发生时,设置选项 &syntax 的值,同时加载对应的语法着色文件.

以加载 *.log 文件为例:
    BufRead 事件 ->
    执行 ~/.vim/ftdetect/log.vim ->
    选项 &filetype = log ->
    触发 FileType 事件 ->
    选项 &syntax = log ->
    触发 Syntax 事件 ->
    执行 ~/.vim/syntax/log.vim

我们在 ~/.vim/syntax/log.vim 定义了用于对 LOG 文件内容进行分组的规则,分组完毕后 VIM 再根据当前颜色主题对各组着色.

4. 我的 log 格式示例

    # 注释 ----------
    10/25/2022 08:26:08 - INFO - Welcome to FuturesGene v2.10.5 by Que's C++ Studio
    10/25/2022 08:26:08 - DEBUG - [1]fgnc (pid 329) started
    10/25/2022 08:26:08 - INFO - [1]"event/conf/reload" timer: "08:00:00;12:00:00;20:00:00"
    10/25/2022 08:26:08 - INFO - [1]"status/session/running" timer: "08:30:00,11:40:00;13:00:00,15:35:00;20:30:00,02:35:00"
    10/25/2022 08:26:08 - DEBUG - node[1] ctl/1/0x0000 status capture map
    10/25/2022 08:26:08 - TRACE - node[1] capture "event/conf/reload":1
    10/25/2022 08:30:00 - WARNING - [2]CTPQuotes invalid login, empty trading day, retry in 30s ...

格式为: <日期> <时间> - <日志级别> - <内容>
我的目标是对上述各个部分,以及<内容>中的字符串,数字常量分别着色,所以需要写出识别各分组的模式串(pattern),
所幸大多数规则可以参考现有的 c 或 python 语法文件,比如字符串,数字常量等模式都是相同的,直接复制过来就可以了.

编辑文件 ~/.vim/syntax/log.vim 定义分组规则:
    " 参考 c 语法文件 $VIMRUNTIME/syntax/c.vim 先自定义组名,最后再链接到惯用组名
    let s:cpo_save = &cpo
    set cpo&vim

    " 如果您的日志级别关键字与我的不同,请在此处修改
    syn keyword    logLabel        FATAL ERROR WARNING INFO DEBUG TRACE
    " FATAL ERROR 直接归类到惯用组名 "Error" 通常显示为红色
    syn keyword Error            FATAL ERROR
    " WARNING 归类到 TODO 组,通常显示为黄色
    syn keyword Todo            WARNING

    " 字符串, 数字常量的规则与 c 一致,直接复制过来
    " string charracter
    syn region    logString        start=+"+ skip=+\\\\\\\\\\|\\\\"+ end=+"+
    syn match    logCharacter    "L\\='[^\\\\]'"

    " integer number, or floating point number without a dot and with "f".
    syn match    logNumbers    display transparent "\\<\\d\\|\\.\\d" contains=logNumber,logFloat,logOctal
    syn match    logNumber    display contained "\\d\\+\\%(u\\=l\\0,2\\|ll\\=u\\)\\>"
    syn match    logNumber    display contained "0x\\x\\+\\%(u\\=l\\0,2\\|ll\\=u\\)\\>"
    syn match    logFloat    display contained "\\d\\+\\.\\d*\\%(e[-+]\\=\\d\\+\\)\\=[fl]\\="
    syn match    logFloat    display contained "\\.\\d\\+\\%(e[-+]\\=\\d\\+\\)\\=[fl]\\=\\>"
    syn match    logFloat    display contained "\\d\\+e[-+]\\=\\d\\+[fl]\\=\\>"

    " 不是很严格的 date time 模式串,可以匹配 YYYYMMDD, MM/DD/YYYY, YYYY-MM-DD, HH:MM:SS 格式的时间字符串
    syn match    logDate    "\\<\\d\\2,4[/-]\\d\\2[/-]\\d\\2,4\\>"
    syn match    logDate    "\\<[12]\\d\\3[01]\\d[0123]\\d\\>"
    syn match    logTime    "\\<\\d\\2:\\d\\2:\\d\\2\\>"

    " # 开头的单行注释,类似 cpp // 开头的注释,复制过来,把 // 改为 #
    syn region    logComment    start="^\\s*#" end="$" keepend

    " 把上述组名链接到惯用组名,方便应用到现有的颜色主题
    " 日志级别归类为 label, 类似 c 的 case, goto label
    " 日期时间归类为预处理符号,类似 c 的 #include
    hi def link logLabel        Label
    hi def link logString        String
    hi def link logCharacter    Character
    hi def link logNumbers        Number
    hi def link logNumber        Number
    hi def link logFloat        Number
    hi def link logDate            PreProc
    hi def link logTime            PreProc
    hi def link logComment        Comment

    let b:current_syntax = "log"

    let &cpo = s:cpo_save
    unlet s:cpo_save

5. 安装
(a) 复制源码包到 ~/.vim/ 即可
(b) Vim-Plug
    call plug#begin()
    Plug 'TedQue/vim_log_syntax'
    call plug#end()

6. screenshot
Ubuntu 18.04 终端默认的亮紫色背景非常费眼睛,改为前景色: #B0B0B0 背景色: #2E3436 内置调色板: Tango
VIM colorscheme 为 qpp (已包含在源码包中) 效果如下:

以上是关于VIM 适用于 LOG 文件的语法高亮配置的主要内容,如果未能解决你的问题,请参考以下文章

vim 支持 nginx配置文件 语法高亮

VIM语法高亮在保存文件后消失是怎么回事?

配置使用vim编辑Nginx配置文件时语法高亮

vim显示行号语法高亮自动缩进的设置

nginx配置文件语法高亮显示方法

拾遗:vim 配置(个人适用,仅供参考)