Posts tagged 'vim'

Smarter tag search in Vim

published on November 01, 2017.

As part of my Vim setup for PHP development, I use the vim-php-namespace plugin to add use statements in my PHP code.

vim-php-namespace uses the tags file to find the class and the namespace it belongs to, and then adds it to the rest of the use statements.

It all works great, but there are times when it shows too much possibilities.

For example, when I want to import the namespace for the Transaction class, it finds the correct Transaction class, but it also finds functions called transaction in my codebase, and then gives me a choice what I want to import:

See? One class (kind c), and two functions (kind f).

I could exclude functions from being generated in tag files, but that’s not really an option because there are times when I need the functions tags.

I dove into the vim-php-namespace source code, determined to get rid of this “functionality”.

Turns out the plugin actually uses a Vim command, called ptjump, to search the tags file and show the preview window, so the user can pick out the correct tag in case there’s more than one.

Of course there’s an option for that

Then I started reading the help pages for tags in more detail, and after a while I found the answer: tagcase.

To quote the help file:

This option specifies how case is handled when searching the tags file.

And it has the following options:

  • followic Follow the ‘ignorecase’ option
  • followscs Follow the ‘smartcase’ and ‘ignorecase’ options
  • ignore Ignore case
  • match Match case
  • smart Ignore case unless an upper case letter is used

I’ve set it to smart and, well, now it does what I want it to do:

set tagcase=smart

It correctly finds only one match for the Transaction class and the plugin inserts the use statement for it. Yey!

Happy hackin’!

Tags: php, vim, tags, namespace, plugin.
Categories: Development, Software.

Current Vim setup for PHP development

published on February 10, 2017.

I made some changes to my Vim setup for PHP development recently, so it’s time to write it all down. I’m more than sure that I’ll break it soon and won’t be able to remember all the things I did to have the current setup.

Some new plugins popped up on my radar, I tweaked some older plugins and I even wrote one for PHPStan!

Last year I wrote how I got really good tag support in Vim, so I’ll first expand on that.

Gutentags

Gutentags is probably the plugin that had the biggest impact on my workflow. It made possible many other functionalities and plugins to just work.

First thing I have configured for it is the location for the tag files:

" Where to store tag files
let g:gutentags_cache_dir = '~/.vim/gutentags'

The second is a more “aggressive” excluding of files from generating tags:

let g:gutentags_exclude = ['*.css', '*.html', '*.js', '*.json', '*.xml',
                            \ '*.phar', '*.ini', '*.rst', '*.md',
                            \ '*vendor/*/test*', '*vendor/*/Test*',
                            \ '*vendor/*/fixture*', '*vendor/*/Fixture*',
                            \ '*var/cache*', '*var/log*']

Takes out a lot of rubbish.

I also have the following in the global ~/.ctags configuration file (gutentags uses ctags under the hood to generate the tags):

--PHP-kinds=+cfit-va

This way I get tags for classes, interfaces, functions, namespaces and traits, while variables and aliases are ignored to remove the noise level.

Jump to definition

I paired CtrlP’s CtrlPTag method with gutentags tag files to get jump to definition functionality:

map <silent> <leader>jd :CtrlPTag<cr><C-\>w

My complete CtrlP settings are here.

Current PHP class and method

A combination of three Vim plugins and a PHP phar file gives me the possibility to show in the status bar the current PHP class and method.

Lightline provides the status bar, tagbar to get the current tag, tagbar-phpctags to generate the tags for the current file using phpctags.

Use the following setting to tell tagbar about the phpctags binary:

let g:tagbar_phpctags_bin='~/.vim/phpctags'

This is the tagbar line for lightline:

'tagbar': '%{tagbar#currenttag("[%s]", "", "f")}',

See here how it all fits together.

Now that I wrote it all down, I should take a look if I could use the gutentags tag files for this. Seems like an awful lot of moving parts for a relatively small feature.

PHP namespaces

The vim-php-namespace plugin provides support for inserting use statements in PHP code. It will use the tag files generated by gutentags, there’s no need to set up anything for that.

I have the following mapping to insert the use statements:

function! IPhpInsertUse()
    call PhpInsertUse()
    call feedkeys('a',  'n')
endfunction
autocmd FileType php inoremap <Leader>pnu <Esc>:call IPhpInsertUse()<CR>
autocmd FileType php noremap <Leader>pnu :call PhpInsertUse()<CR>

and this one for expanding classes to get their fully qualified names:

function! IPhpExpandClass()
    call PhpExpandClass()
    call feedkeys('a', 'n')
endfunction
autocmd FileType php inoremap <Leader>pne <Esc>:call IPhpExpandClass()<CR>
autocmd FileType php noremap <Leader>pne :call PhpExpandClass()<CR>

I also let it to automatically sort the namespaces after inserting:

let g:php_namespace_sort_after_insert=1

Linting

ALE is an Asynchronous Lint Engine and it provides linting for Vim 8. It can do linting for a bunch of languages.

My configuration for it is:

let g:ale_linters = {
\   'php': ['php'],
\}
let g:ale_lint_on_save = 1
let g:ale_lint_on_text_changed = 0

Lints PHP files on save, in the background. A must have!

A promising completion engine for PHP

php.cd finally provides useful completion for PHP. It’s still rough around the edges, misses a feature or two, but I find it a lot better than any other completion engine I used before. No need to configure anything for it, just follow their installation instructions and that’s it. ^X^O all the things!

PHPStan in Vim

PHPStan is a static analysis tool for PHP and I wrote a small plugin for it, vim-phpstan. It calls phpstan from Vim and populates Vim’s quickfix list with the errors.

For now, the only possible configuration is to set the analyse level:

let g:phpstan_analyse_level = 2

Debugging

Sadly, there is no good PHP debugging client for Vim. Or none that I know of. There are a couple of them out there, but they seem long abandoned. I work on a standalone PHP debugging client, pugdebug, but it has it’s own set of problems as well (packaging on Linux is a nightmare).

Supporting plugins

Other “supporting” plugins are 2072/PHP-Indenting-for-VIm, 2072/vim-syntax-for-PHP, sirver/ultisnips, plugins from the sniphpets organization, ddrscott/vim-side-search, robertbasic/vim-argument-swapper.

I’m pretty happy with the current setup. Do you know maybe of any interesting plugin I’m missing? Let me know!

Happy hackin’!

Search and replace in visual selection in Vim

published on January 23, 2017.

The search and replace feature is very powerful in Vim. Just do a :help :s to see all the things it can do.

One thing that always bothered me though, is that when I select something with visual, try to do a search and replace on it, Vim actually does it on the entire line, not just on the selection.

What the…? There must be a way to this, right?

Right. It’s the \%V atom.

Instead of doing :'<,'>s/foo/bar/g to replace foo with bar inside the selection, which will replace all foo occurences with bar on the entire line, the correct way is to use the \%V atom and do :'<,'>s/\%Vfoo/bar/g.

I’m using this approach in the HugoHelperLink fuction of my Vim Hugo Helper plugin.

Happy hackin’!

Tags: vim, search, replace.
Categories: Software, Blablabla.

Force Python version in Vim

published on January 12, 2017.

Vim can be compiled with Python support. Vim can be compiled with both Python 2 and Python 3 support.

At the same time.

But not really.

Vim can have both of them, but use only one at a time. If you start using one version, there is no way to switch to the other one.

The silly thing is that if you simply ask Vim which version does it support, the first one asked and supported is going to be the one loaded and used. Trying to use the other one from that point will result in an error.

if has('python')
elif has('python3')
endif

Guess which one is loaded? Python 2.

Try calling Python 3 and ka-boom!

:py3 print('hello')
E836: This Vim cannot execute :py3 after using :python

Switch the order around:

if has('python3')
elif has('python')
endif

And now? Yup, Python 3.

Why is this ridiculous? Because if you have a bunch of Vim plugins loaded, the first one that asks for a specific Python version wins! Reorder the plugins and suddenly a different Python version is loaded.

Gotta love the software development world.

Luckily, this can also be used to fix the problem itself.

How?

Force one of the Python versions from the top of your .vimrc file:

if has('python3')
endif

Now you can have a little bit of sanity and be sure what Python version is Vim going to use. Of course, doing this might break plugins written solely for Python 2, so do it at your own risk.

Happy hackin’!

Tags: vim, python, vimrc.
Categories: Development, Software.

Editing Vim macros

published on December 15, 2016.

Vim macros are a powerful thing — they let us record keystrokes and play them back later. These macros are recorded to named registers.

One thing I realised about them, is that they can be edited after they have been recorded. This is possible because macros “lives” in the register.

Say, for example, you record a macro of 20+ keystrokes, play it back, only to realize that there’s a single error in the steps. Re-recording the entire macro can be difficult. Instead, paste the contents of that register somewhere, edit it, and then yank it back to that same register.

For a simple example, let’s assume we want to add * around words. We record it to the register a by typing qa (the ^[ is the literal escape character):

bi&^[ea&^[

Play it back with @a and — oh no! that’s not a *, that’s a &!

Vim macro editing to the rescue:

:new # to open a new split
"ap # take the register named "a" and paste from it
:%s/&/*/g # replace all & with *
^v$"ay # jump to start of line, visual mode, jump to end of line, take the named register "a" and yank to it

If we now play back the macro again with @a, we see the *s wrapping the word on which the cursor was, just what we wanted.

Happy hackin’!

Tags: vim, macro, registers.
Categories: Development, Software.
Robert Basic

Robert Basic

Software engineer, consultant, open source contributor.

Let's work together!

If you require outsourcing or consulting help on your projects, I'm available!

Robert Basic © 2008 — 2018
Get the feed