0

I have a few functions to help with adding PHP docblock tags. Suppose a block like this:

/**
 * Does a thing
 *
 * |
 */

Where | is my cursor position. I have a mapping to <localleader>@p, for instance, to insert an @package tag:

 * @package foo-bar

Function

Here's my basic function:

function! MaybeSetPackage()
    if ! exists( "g:php_package" )
        let l:package = ''
    else
        let l:package = g:php_package
    endif

    execute ':normal! a@package ' . l:package
endfunction

Expectation

When I move to a line in the docblock and type \@p, this should be the result:

/**
 * Does a thing
 *
 * @package foo-bar
 */

What sometimes happens

If I'm on a line in NORMAL mode, like:

/**
 * Does a thing
 * |
 */

And hit o, I'm here:

/**
 * Does a thing
 *
 * |
 */

And then, while still in INSERT mode, I type \@p, I get this:

/**
 * Does a thing
 *
 *@package foo-bar
 */

However, if I type o, delete the space after *, type a new space, and then do \@p, I get this:

/**
 * Does a thing
 *
 * @package foo-bar
 */

Why?

Why, after hitting o and getting

 * |

does my function seem to remove the automatically inserted space and leave me with

 *@package foo-bar

but when I delete the automatically inserted space and add my own, followed by my mapping, I get the expected result of

 * @package foo-bar

?

Update

Adding my mapping:


    autocmd FileType php inoremap <buffer> <localleader>@p <esc>:call MaybeSetPackage()<CR>

2
  • 1
    Irrelevant side note: check out the get() function
    – D. Ben Knoble
    Feb 18, 2019 at 17:38
  • @D.BenKnoble added my mapping.
    – phatskat
    Feb 19, 2019 at 4:32

1 Answer 1

3

The important part of the question is missing: The mapping. I assume the following:

inoremap <localleader>@p <C-O>:call MaybeSetPackage()<CR>

The point here is, that you are leaving insert mode (here with <C-O>) and Vim automatically removes spaces that were added by automatic indent. If you add the spaces yourself, they are not removed.

So you need to insert text without leaving insert mode.

Inserting the expression register

The "expression register" can be inserted with <C-R>=.... This is not really a register, you have to provide the expression. Your mapping might than be:

inoremap <localleader>@p @package <C-R>=exists("g:php_package")?g:php_package:''<CR>

or, if you want to keep your function:

function! MaybeSetPackage()
    if ! exists( "g:php_package" )
        let l:package = ''
    else
        let l:package = g:php_package
    endif
    " Now returns the text to insert
    return '@package ' . l:package
endfunction


inoremap <localleader>@p <C-R>=MaybeSetPackage()<CR>

See :help i_Ctrl-R_= for the details.

Map-Expressions

Another way would be to use a map-<expr>. This type of maps, maps to a Vim script expression, that returns the characters (or keystrokes) that Vim should interpret. In the following case the @package ... characters are returned and as it is a input-mapping, they are inserted in the buffer. Again, you can put the Vim script code directly into the mapping or call a function.

inoremap <expr> \@p '@package ' . (exists('g:php_package')?g:php_package:'')
inoremap <expr> \@P MaybeSetPackage()

See :help map-<expr> for details.


BTW: Using get()

@D.BenKnoble mentioned get() in the comments. This is a function to search for an entry in a dictionary. It can be used in the following way:

get(g:, 'php_package', '')

In this case g: is the dictionary of all global variables. Now get() searches for the entry php_package in this dictionary. If found the variable value is returned, else the default value ('').

So the above mapping could be written as:

inoremap <expr> \@p '@package ' . get(g:,'php_package','')

This works, is very compact and (if you know what it is doing) easy to understand.

3
  • 1
    Same comment for OP: get() simplifies some of the logic here.
    – D. Ben Knoble
    Feb 18, 2019 at 17:40
  • 1
    @D.BenKnoble See update
    – Ralf
    Feb 18, 2019 at 21:38
  • These definitely simplify the logic, I'll try them out!
    – phatskat
    Feb 19, 2019 at 4:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.