6

我想知道在使用 vim 编写代码/乳胶时,当我在某个环境中时如何触发某个动作。例如,假设我正在编写 tex 并在 align 环境中,那么我希望我输入的每个等号都转换为 &=。

我现在想的比较麻烦。这是我的 vimrc 中的伪代码。这是它的样子

Shortcut for environment opens start and end tag for align environment (Using imap)
The above action also initiates a counter variable, sets it to 1
If counter is 1, every equals sign I enter should be entered as an &=.
Shortcut to force counter to zero when I move out of the environment. (Using imap)

我想知道是否有更简单的方法来解决这个问题。这只是一个例子。这里的主要思想是让 vim 具有环境意识。

期待您的建议。

4

3 回答 3

2

这是一个非常有趣的问题,但我不确定您建议的方法是最好的方法!我尝试了一个答案,但第一次迭代可能并不完美。我假设 LaTeX 环境只是由\begin\end命令分隔(我的 LaTeX 有点生疏了!)。

首先,您需要一个函数来返回光标位置的环境。我下面的函数跳转到上一个\begin命令,然后向前跳转到匹配的\end命令,计算光标是否在该区域内,并继续该过程直到找到包含环境。它应该处理嵌套环境。如果不在 LaTeX 环境中,则返回一个空字符串。

function! GetTeXEnv()
    let pos = getpos('.')
    let win = winsaveview()
    let env = ''
    let carry_on = 1
    let search_ops = 'bWc'
    let b_start = line('.')
    while carry_on
        keepjumps let b_start = search('\\begin{',search_ops)
        let search_ops = 'bW'
        " Only accept a match at the cursor position on the
        " first cycle, otherwise we wouldn't go anywhere!
        let env = matchstr(getline('.'),'\\begin{\zs.\{-}\ze}')
        let env_esc = escape(env,'*')
        keepjumps let b_end = search('\\end{\s*' . env_esc . '\s*}','Wn')
        if b_start == 0
            " finished searching; stop
            let carry_on = 0
        elseif b_end > b_start && b_end < pos[1]
            " not inside this env; carry on
            let env = ''
        elseif b_end > b_start && b_end >= pos[1] && b_start <= pos[1]
            " found it; stop
            let carry_on = 0
        endif
    endwhile
    call setpos('.',pos)
    call winrestview(win)
    return env
endfunction

现在您可以使用 查询光标所在的环境:echo GetTeXEnv()

要更改=键的行为,您需要创建另一个&=在 align 环境中返回的函数,=否则:

function! TeXEquals()
    return GetTeXEnv() =~ 'align\*\?' ? "&=" : "="
endfunction

=然后您可以在插入模式下重新映射(仅适用于 TeX 文件)

autocmd FileType tex inoremap <silent> = <c-r>=TeXEquals()<CR>

这似乎在我的示例 LaTeX 文件中有效。如果您发现任何问题或有任何改进的想法,请告诉我。

于 2012-08-06T18:33:10.790 回答
2

我通常在事后解决这类问题。例如,我用普通=符号写它,然后在视觉上选择它的区域并使用:s/=/\&=/g. 如果您想在事后对“环境”执行多项操作,您可以创建一个函数并触发一个键来执行它。例如:

vnoremap <leader>la :call <SID>latexAlign()<cr>

function! s:latexAlign() range
  exe ":'<,'>s/=/\&=/g"
  " add more stuff here...
endfunction

但是,我认为您的解决方案会更好,以防您稍后返回并对其进行编辑。vim 中的 htmlcomplete 文件处理这种情况是这样的:

let stylestart = searchpair('<style\>', '', '<\/style\>', "bnW")
let styleend   = searchpair('<style\>', '', '<\/style\>', "nW")
if stylestart != 0 && styleend != 0
   if stylestart <= curline && styleend >= curline
      let start = col('.') - 1
      let b:csscompl = 1
      while start >= 0 && line[start - 1] =~ '\(\k\|-\)'
         let start -= 1
      endwhile
   endif
endif

您可以看到它如何使用 searchpair 来确定它是否在<style></style>标签内。有关:help searchpair()更多信息,请参阅。

于 2012-08-06T17:12:15.177 回答
0

如果您正在寻找“环境意识”,并且您的意思是“我在乳胶文件中吗?” 您可以使用autocommand.

Vim 可以识别大量文件类型,您可以通过以下方式确保默认识别您正在编辑的文件类型:

:echo &filetype

在编辑 Python 文件时,我得到python了结果。如果你只需要对 latex 使用这个并且你从那个 Vim 变量中得到了一个满意的响应,你可以设置一个autocommand使用它的,否则你可以在其中指定扩展,它看起来像这样:

autocmd BufReadPost,BufNewFile,BufEnter *.tex, *.latex call MyFunction()

RedPost、NewFile 和 Enter 是一些可能的 Vim 交互,它们会MyFunction在文件扩展名以.text或结尾时触发你.latex

如果您真正需要的是一些代码示例,可以按照您的描述进行操作,那么康纳的答案可能更适合。

于 2012-08-06T18:28:02.863 回答