📜 ⬆️ ⬇️

Some features of VimL


In this article I want to talk about some of the features of VimL, ​​often non-obvious, that a person who wants to write a good add-on for Vim needs to know. To understand the article, knowledge of vimscript is required and the presence of at least one written addition is recommended. People who do not want to write their own addition article will, for the most part, be useless.

Bindings

Reattachment


Let's start with banal and well-known things: pereapyazki. Vim has two main families of commands: *map and *noremap . The first allows you to override its right side, the second is not. In additions, only the second should be used, since it is not known which bindings the user has. Classic example:
 noremap : ; noremap ; : 
will break
 nmap <F4> :PluginToggle<CR> 
, but not
 nnoremap <F4> :PluginToggle<CR> 
. Other commands to keep in mind:
You can also note the presence of the 'remap' setting, which causes all commands of the *map to behave in the same way as their *noremap equivalents. You will not be able to use
 nnoremap <Plug>PluginAction :DoAction<CR> if !hasmapto('<Plug>PluginAction') nmap <Leader>a <Plug>PluginAction endif 
to allow users to redefine lhs and also support users who have enabled this setting, instead you have to bring all the definitions of the bindings to the form
 execute 'nnoremap '.get(g:, 'plugin_action_key', '<Leader>a').' :DoAction<CR>' 
or more compatible with older versions of vim
 if !exists('g:plugin_action_key') let g:plugin_action_key='<Leader>a' endif execute 'nnoremap '.g:plugin_action_key.' :DoAction<CR>' 

Special symbols



File (<script>) bindings


Vim provides the ability to make valid the redefinition of the right part of the bindings only those bindings that are defined in the same file. Leaving aside the limited utility (more precisely, the lack thereof) in the case when the user redefines the left part of the binding using
 nnoremap <Plug>PluginAction :DoAction<CR> if !hasmapto('<Plug>PluginAction') nmap <Leader>a <Plug>PluginAction endif 
or
 execute 'nnoremap '.get(g:, 'plugin_action_key', '<Leader>a').' :DoAction<CR>' 
There is another reason why this method should not be used: for commands
 nnoremap <script> lhs rhs 
and
 nnoremap lhs rhs 
calling maparg('lhs', 'n', 0, 1) will return the same dictionary. That is, if another developer wants, say, to temporarily make another binding with the same lhs , and then restore the old one, then the file binding will not be correctly restored.

Settings

Vim has a lot of settings that will easily ruin your life:

Compatibility Settings


The most destructive setting is 'compatible' . As a rule, the most appropriate way to deal with it is simply to refuse to download, perhaps with the output of the message:
 if &compatible finish endif 
The second most damaging effect on add-ons is to set up 'cpoptions' : with it, you can prevent the transfer of a part of a command to the next line , change the behavior of commands that create bindings, change the behavior of regular expressions, and do other bad things. This is usually partly handled by
 let s:saved_cpo=&cpo set cpo&vim <...> let &cpo=s:saved_cpo unlet s:saved_cpo 
but with changing the behavior of regular expressions you can not do anything. It is also good that it does not affect functions (I mean built-in functions like match * () , substitute () , and not user-defined).

Ignore case


Another "fun" setting is 'ignorecase' . However, unlike the compatibility settings, it is rather easy to cope with it, following simple rules:

Magic and repetition



Wild files


When using expand () , glob () or globpath () , specify one as the first of the optional arguments, otherwise the 'wildignore' and 'suffixes' settings will be taken into account, which may exclude some files from the output. However, sometimes it is, on the contrary, useful.

Other settings



Local settings


Also, it should be noted that : setlocal does not throw an exception if you are trying to change a setting that is exclusively global. Thus, before changing any settings with its help, it will not be superfluous to look into the documentation and then either abandon the use of global settings or restore them by the BufLeave event, setting its value by the BufEnter event.

Strange file names


Splitting into lines and comments

The meaning of the characters of the new line and vertical bar, as well as the possibility of using comments, strongly depends on the context:
  1. If the built-in command accepts an expression as an argument (for example ,: echo ), then a double stroke is considered the beginning of a string literal, a new line and a vertical bar separate two commands (but not if they are inside a string literal). You can not achieve this effect for your teams.
  2. But not in the case that it is a binding / reduction-expression, they actually do not accept expressions from the point of view of the parser.
  3. And not if reading from a file / creating a function using
     execute "function Abc()\n DoSomething\nendfunction" 
    , here a new line always separates two commands.
  4. If a command considers a vertical line as part of its arguments, then the newline character will also be part of its arguments (except for the cases described above).
  5. A backslash at the beginning of a new line means the transfer of a part of a command. It works exactly as if before executing the file we use the command
     %s/\n\s*\\// 
  6. But only if the file is executed. Nowhere else can I apply transfer.
  7. Commands that create bindings / abbreviations / menus are special: a double stroke is considered a part of them, but does not start a string literal, and the vertical bar, however, interrupts commands. You also can not achieve this effect for their teams.
  8. You cannot place endfunction on a separate line. The parser after the function command just stupidly cheats all the lines belonging to the functions and saves them to an array until it encounters the endfunction command found on the new line.

* Cmd

Creating correct (Buf | File) (Read | Write) Cmd is much more difficult than it seems at first glance. The fact is that vim does not provide any automatic detection of the encoding or line wrapping method, nor any easy support ++ opt. If you look at the standard add-on that reads gzip-compressed files, you will see that it uses saving the expanded content to a temporary file and then : read to read the file. This eliminates the need to use the 'fileformats' and 'fileencodings' settings to guess the way to wrap lines and encoding, but open the compressed file in KOI8-R encoding if you do not normally get fileencodings=utf8,cp1251 , in contrast to the compressed file encoded with CP1251. If you do not want this to happen with your supplement, there is v: cmdarg at your service. This variable always contains the data of the user ++ settings in a short form, so you will not have to support ++ enc and ++ encoding. An example can be found here (read, the next function is a write) (although 'fileformats' and 'fileencodings' are ignored here), but in some cases v: cmdarg can be simply combined with : read with : execute . Note that : read ignores ++ settings when reading shell command output.

Non fatal error

A person who has just read the list of commands may think that the command : echoerr is a good way to display an error. In fact, this is not the case: there is no way for the displayed error to not interrupt the execution of the program. You can make this command guaranteed to interrupt program execution, but if instead of
 try echoerr 'Error' endtry 
you write just
 echoerr 'Error' " some code here 
get ready for the fact that you will have to debug strange problems related to the fact that “some code” is executed, then not - depending on whether you put the code inside the block :try . Considering that inside the block :try you cannot put only code that will never be executed, and the user may have more than one reason to put your code exactly there, having written :echoerr you just in vain complicated your life.
If you want to display an error without interrupting the program, use
 echohl ErrorMsg echomsg 'Error' echohl None 
. If you need to interrupt the execution, there is : throw . And only if you are not at all satisfied with the error message issued by :throw , there is
 try echoerr 'Error' endtry 
. Simply :echoerr no, you must forget it.

Not really text files

Working with files and output of commands that can contain zeros or do not end in a new line, Vim can give you quite a few “pleasant” minutes if you need to maintain its correctness. Here are a few facts:

Inequality

There are six operators in Vim that allow you to check equality and the same number of operators that test the inequality:
Accordingly, the recommended rules for use:
  1. For any comparisons of scalar types, use is# , is? , isnot# or isnot? (the difference is described in the section “Settings / Ignoring the register”).
  2. For any comparisons of non-scalar types, if you want to find out the equality of value, and not identity, you should use ==# , ==? !=# or !=? .
  3. About operators == , is isnot != And isnot should be forgotten altogether.

There is another set of rules that I adhere to and which allow you to reduce the number of characters for a set:
  1. If one of the arguments is a numeric constant, and the other is used in the code only as a number, you can use == .
  2. If one of the arguments is a numeric constant, you can use is .
  3. Further use the rules from the previous list. ==# for the lines I do not apply because I do not want to think whether I should (will) use the number as a “special argument” (like 0 instead of None ).

Functions

One of the interesting features of Vim is its work with variables that reference functions. Esla you have already heard that you can get such a change with
 let Func=function("tr") 
, you probably also know that the variable name starts with a capital letter, because otherwise Vim will show an error. But there is another, less well-known, fact, because of which you should never assign a function reference to a variable: if someone somewhere defined the function “Func”, then Vim would also show an error. There are only two safe ways to use a function reference: pass it as an argument and use complex structures: a dictionary or a list:
 let d={} let d.func=function("tr") 
, and
 function Apply(func, list) return call(a:func, a:list, {}) endfunction echo Apply(function("tr"), ["abc", "a", "d"]) 
completely safe, even despite the possibility of defining the function a:func() .

Special characters!

You have seen and it seemed convenient to use the% symbol instead of the file name, for example, here:
 nnoremap <F4> :!python %<CR> 
? This is another feature of Vim that could be comfortable ... if it worked normally. It is necessary to appear in the file name as a space / stroke / dollar (* sh) and instead of the file name the interpreter in this binding can get anything. Vim has many modifiers for the current file name like %:t [ail] (leaves only the last part of the name), but the modifier %:E [scape], which would run the file name through shellescape () , is not among them. Therefore, you have to screen everything yourself, while not forgetting the context of the call: when using system (), shellescape () should be called with one argument or zero instead of the second, and when used :! , : read! , : write! and other exclamation marks - with two arguments and one as the second. Examples:
 nnoremap <F4> :execute '!python' shellescape(@%, 1)<CR> nnoremap <F5> :call system('javac '.shellescape(expand('%')))<CR> 

Regular Expression Features


Vim has many options for auto-completion, which you can use in your commands. Except for one: files and directories. Of course, if you look into the certificate, you can see it in the list -complete=dirand -complete=file, however, these arguments have little in common with auto-completion:
 command -complete=dir -nargs=1 -bar Echo :echo [<f-args>] command -nargs=1 EchoN :echo [<f-args>] 
 :Echo abc E172:       :EchoN abc ['ab c'] :Echo * E77:     :Echo $HOME ['/home/zyx'] :Echo `date` ['. . 28 17:17:47 MSK 2012'] 
.Agree, a bit is not what you expected, setting up auto-completion. Especially if the team must accept exactly the templates. Moreover, it is not described in the documentation. And does not happen with other options for auto-completion.

')

Source: https://habr.com/ru/post/149919/


All Articles