Command line: VIM

VIM: Better grepping (in Windows)

Several times I noticed that grepping in VIM (finding in files) does not work very well comparing to Visual Studio or VSCode at least. I felt it pretty hard last time when I tried to search in a medium-size web project. It took over 23 seconds to search for files and another 55 seconds to render the list of results. I’ve never experienced something similar in any other editor.  Another think that bothered me was the quality of results which frequently showed binary files, multi-line records or everything else what I could call “rubbish” in the context of file search option:

2017-04-08_22-41-56

The first guess is that alternative editors just skip files that are not source code. And that’s the thing (at least looking at Visual Studio Code file search):

2017-04-08_22-54-55

Unfortunately there is no easy way to tell VIM grepper to exclude locations from search (at least in Windows). The default findstr (you can find more about it in my previous post) does not have such option. Nevertheless there is a way to achieve such behaviour. Just add this snippet to your $VIMRC file:

function! FastGrep(what, ...) abort
 let where = a:0
 if where == ""
    let where = "*.*"
 endif
 let command = "silent ! dir /s/b/a:-d"
 let command = command . " | findstr /v \\node_modules\\"
 let command = command . " | findstr /v \\dist\\"
 let command = command . " | findstr /v \\\.git\\"
 let command = command . " | findstr /v \.map$"
 let command = command . " | findstr /v \.swp$"
 let command = command . " | findstr /v \.ts\.html$"
 let command = command . " | findstr /v ~$"
 " add excludes here ------^
 let command = command . " > \\%home\\%\\solution_files.tmp"
 execute comma              nd
 execute "grep /f:\\%home\\%\\solution_files.tmp ".a:what." ".where
endfunction

:command! -nargs=+ -complete=command Grep2 call FastGrep()

The idea behind the snippet is the following: get list of all the files in the working folder, remove the locations you want to exclude, and then pass the list of files to “findstr” command (/f switch allows to pass the list of input files).

Here’s a quick list of tricks used in the snippet:

execute              - run vim command
!                    - execute shell command
silent               - skip "Press ENTER to continue" after running shell
dir /s/b/a:-d        - get a raw list (/b) of files only (/a:-d) 
                       in all subdirectories (/s) 
findstr /v \.git\    - find lines that does not containing "\.git\"
%home%               - user home directory (i.e. c:\users\user_1)
FastGrep(what, ...)  - function taking one named argument and array of 
                       unnamed arguments
a:0                  - first unnamed argument
:command!            - define VIM command alias
-nargs=+             - alias must have arguments (any number)
             - list of arguments passed to the alias

Now in order to execute such command you just need to run:

:Grep2 myFunction1
:Grep2 myFunction2 *.js

The same operation that took initially 23 seconds was executed in less than 1 second (with rendering results). Of course it showed less records, but only the meaningful ones (a side note: my medium-size web application contained 996 folders inside /node_modules !!).

Remember that you can extend it by your own excludes.

Advertisements
Command line: VIM

VIM: Find in files

It’s not a surprise that there is a built-in way to find in files in VIM. You can use four commands: :grep, :lgrep, :vimgrep, :lvimgrep.

2017-04-02_09-19-29

:grep will use the default “find” tool for your operating system (“grep” for linux family, “findstr” for Windows). :vimgrep will use built-in vim search (same as for “/” searching) which is slower than system search (but works if you have problems with grep/findstr/other). On the other hand vimgrep has the same syntax everywhere (:grep depends on external tool used). Search result is presented using Quickfix window (opened with :copen). :lgrep/:lvimgrep will do the same, but using location list (opened with :lopen). In practise the difference is that if you use Quickfix window (:copen) it will stick to the current editor. Location window will show in the same way, but if you select anything then the window will disappear and you will have to run :lopen again.

I guess you have to choose yourself which command you like most.  The syntax is as follows:

:grep searchpattern locationpattern

i.e.:

:grep MyMethod *.*

Will look for phrase “MyMethod” in all files in current workind directory (you can check currect directory using :pwd). By default it does not perform recursive search (it will not search in subdirectories). And here the fun part starts.

In order to search in subdirectories you would have to use **/*.* pattern. However this works for :vimgrep and :grep in linux, but does not work for Windows. In order to make it work on Windows you would need to use /S parameter (linux grep also accepts -R parameter which does the same thing). You can pass it like that:

:grep /S MyMethod *.*

This will work on Windows and will find all “MyMethod” phrases in all files in all subdirectories of current working directory. However you can still make it the default behaviour in VIM. But first you neeed to know one thing:

:set grepprg

This is a variable that controls the usage of external grep tool in VIM. Depending on your operating system you will have different results:

grepprg=findstr /n    # <--- on Windows
grepprg=grep -n $* /dev/null # <---- on Linux

So in order to use recursive search you have to modify grepprg and add a proper parameter:

grepprg=findstr /S /n                  # <--- on Windows
grepprg=grep -nR $* /dev/null          # <---- on Linux

The same way you can add more parameters or make more complex commands.

Command line: VIM

Vim for .NET – flickering omnicomplete problem

Since the beginning of my journey with vim I have experienced a problem with flickering screen. After a several tries with Google it turned out that it’s mostly about vim omnicomplete, and even more specifically Omnisharp-vim preview functionality.

In order to get rid of the flickering, you need to change the default omnisharp switch:
set completeopt=longest,menuone,preview
to:
set completeopt=longest,menuone

The consequences are that you will not see the details of selected item in preview window, but actually I have never used it (since what’s shown in the menu is enough).

Command line: VIM

Vim for .NET – Move type to another file

When I started my journey with VIM for .NET, I tried to find VIM alternatives of common shortcuts/refactorings that I used in Visual Studio. Surprisingly I noticed that most of them were already there (Searching, Go To Definition, Find usages, create class etc). The one I had a real problem with was “Move type to another file”. I really like the idea that I can create all the types in one file and then use some shortcut (with ReSharper: Alt + Enter) to distribute them to their own files. As I could not find any existing plugin (which is really strange) I took it as a good time to try myself in writing vimscript. It turned out that it was pretty easy exercise. Here you can find the script that you can append to _vimrc to enable the feature.


function! ExtractClassToFile() abort
    " copy class name
    execute "normal! ?^.*\\sclass\\s\0/class\wviwy"
    " and store for future use (filename)
    let className = getreg('"')

    " cut class code and store it inside default register
    execute "normal! ?^.*class\V/{\%x"	
    " and store for future use
    let classText = getreg('"')
   
    " copy namespace + usings
    execute "normal! ggv/namespace \/{\ly"
    let usingAndNamespace = getreg('"')
    
    " get filename for the new file
    let currFileLocation = expand('%:p:h')
    let newFileName = "\\".className.".cs"
    let newFileFullPath = currFileLocation . newFileName
   
    " open the new file
    execute "e ".newFileFullPath

    " render the file
    let failed = append(line('$'), split(usingAndNamespace, '\n'))
    let failed = append(line('$'), split(classText, '\n'))
    let failed = append(line('$'), '}')

    " remove empty line in the beginning
    execute "normal! dd"
    " save
    execute "w"
endfunction

noremap ef :call ExtractClassToFile()
Command line: VIM, Programming (back-end)

Vim for .NET – Set up

In order to start the journey with VIM for .NET you need to set up the environment and get all the plugins. There is no all-in-one standalone package thus you need to prepare it by yourself. I suggest the following configuration:

1. Install VIM

Install the newest package from (full installation minus “visual studio add-in”):
It is not so trivial as going to VIM homepage and clicking download. Vim.org contains a default compilation of vim for Windows, but compilations differ from each other significantly. VIM for Windows is distributed as GVIM which is a classic VIM for terminal + VIM wrapped up in dedicated window frame and mouse support. Both can be precompiled with different set of features (over 100), like Lua language support, Python intergration, Perl, Ruby etc. Some of these are very important (especially Python). Vim.org copy contains GVIM compiled with Python/Python3, but classic VIM not. That’s why I recommend to download the brew from here (full installation minus “visual studio add-in”): https://sourceforge.net/projects/cream/files/Vim/

Untitled

2. Install Python 2.7.x

Download: https://www.python.org/ftp/python/2.7.10/python-2.7.10.msi

Most of vim extensions are written using Python language (including our most wanted Omnisharp). In order to use it, you need to install Python. Still the most common version is not 3.x but 2.7.x. It is vital to choose the right architecture (x86 vs x64) – it must be same as VIM.
After installing it, you should be able to run

":py print 'hello world'"

in VIM.
Untitled2

3. Install pathogen-vim

cd %SYSTEMDRIVE%%HOMEPATH%\vimfiles
mkdir autoload
mkdir bundle
curl -LSso .\autoload\pathogen.vim https://tpo.pe/pathogen.vim

to %SYSTEMDRIVE%%HOMEPATH%\_vimrc add
execute pathogen#infect()
filetype plugin indent on

(you can run ":e $MYVIMRC" in VIM)

Vim is so powerful because of its extensibility. In order to use the full power of it you need a good plugin loader. Pathogen-vim automatically scans /vimfiles and loads plugins. This is a prerequisite for most of other plugins
Untitled3

4. Install Omnisharp-vim

cd %SYSTEMDRIVE%%HOMEPATH%\vimfiles\bundle
git clone https://github.com/OmniSharp/omnisharp-vim.git
cd omnisharp-vim
git submodule update --init --recursive
cd server
msbuild
cd ..\..

If (msbuild is not found, add "C:\Windows\Microsoft.NET\Framework64\v4.0.30319" to your $PATH)

Omnisharp is a tools that analyze the solution and provides metadata for our project. It’s like external Resharper engine (run as console application listenning on http). This is used to add syntax checking of our project, autocomplete, code actions and many more. In order to connect it with VIM you need a wrapper and here we have "omnisharp-vim".
Untitled4

5. Install vim-dispatch

cd %SYSTEMDRIVE%%HOMEPATH%\vimfiles\bundle
git clone git://github.com/tpope/vim-dispatch.git

It’s a plugin that automatically starts OmniSharp server when you open *.cs file. Without it you would have to run :OmniSharpStartServer manually.

6. Install syntastic

cd %SYSTEMDRIVE%%HOMEPATH%\vimfiles\bundle
git clone https://github.com/scrooloose/syntastic.git

It is something like Resharper icons next to the code (describing errors, warnings, hints, suggestions).
Untitled5

7. Install CtrlP

cd %SYSTEMDRIVE%%HOMEPATH%\vimfiles\bundle
git clone https://github.com/ctrlpvim/ctrlp.vim.git

Together with omnisharp it provides support to contextual actions, go-to-everything, buffer explorer (go to previous file) etc
Untitled6

8. Install NERDTree

cd %SYSTEMDRIVE%%HOMEPATH%\vimfiles\bundle
git clone https://github.com/scrooloose/nerdtree.git

“Solution” tree for VIM. Very useful as there is no default alternative (you would have to go to selected file with CtrlP or command line).
Untitled7

9. Install yeoman

npm install -g yo
yo install csharp-cli-app generator

It creates files/projects from template (with online template browser). There are several .NET templates as well. It’s a must for fron-end developers, but VS devs already have built in “add new” wizard (although yeoman has better support from community).
Untitled8

10. Install vim-snipmate

cd %SYSTEMDRIVE%%HOMEPATH%\vimfiles\bundle
git clone https://github.com/tomtom/tlib_vim.git
git clone https://github.com/MarcWeber/vim-addon-mw-utils.git
git clone https://github.com/garbas/vim-snipmate.git

It helps to create useful code snippets – similar to "prop", "for", "class", "wl" etc.

11. Configure _vimrc

All of the plugins above can be adjusted manually using _vimrc file. You can do this on your own or use some sample file, like mine.

That’s it.

There’s a plenty of steps, but I’d bet it’s less time consuming than installation of Visual Studio.

Command line: VIM

Why am I moving from Visual Studio to VIM?

As I mentioned in my previous post I want to use VIM instead of Visual Studio to work on my logcmd project. This would be a kind of an experiment, but I do have some fair reasons behind that decision. Why do I think VIM is a good alternative to Visual Studio?

It encourages automation

If you’ve ever worked in VIM, you know, that the most important & personal thing is _vimrc file. It’s not that all the keybindings and plugins are already there. You have to create them, customize, sometimes create scripts that boosts your development, and you do it all the time. The other things you need to run directly from console. And obviously you do not retype all the kilobytes of commands all the time. After the second try you want to automate it and have a script that works for you. Although it may sound prehistoric to some of you, it has a lot of long-term benefits. You don’t have to teach new people (or even your future “you”) how to validate JavaScript, do merging/branching, compile LESS, deploy to DEV server, upgrade release notes etc. This way you also get stronger in command line scripting.

It cures bad habits of debugging

All the people praise VS for astonishing debuggig features. It’s all true, but I think overused almost all the time. I know it allows to solve the most hardcore and unexpected behaviour that you could imagine, but on the other hand it’s like using excel for simple arithmetic. I experienced it on my own. Do you remeber one of the following:

  • running the application to check some business logic (writing unit test would take too much time (sic!))
  • fixing some hard issue after hours of debugging and forget how to debug again
  • wishing you could debug your application on PROD?

This all is because of relying on Visual Studio “debugger”. Other people not so tightly coupled with debugger invented better approach decades ago. It’s LOGGING. I’m always amazed how people solve their problems with RaspberryPi or Linux problems on discussion boards – it’s always clear after sending the logfile. Having a good habit of logging also works on “debugging” production.

It has better performace

It’s all about automation and the keyboard. Have you ever seen a hacking movie where they open “My computer -> My documents -> my hacking -> Visual Hacking studio -> create new project”? Or drag and drop viruses from “My downloads”. It’s because mouse is slower than keyboard (unless you participate in Quake 3 Arena world championship). Of course it’s slower if you started with mouse, but give it some time. You can self-check how much faster it is to use vim’s “ci(” instead of searching the starting parenthesis, selecting the text with mouse, finding the closing parenthesis and pressing BACKSPACE.
It’s also a better performance of the editor itself. Visual Studio is slow, but how can an application that takes a couple of GB on disk be fast all the time? On the contrary VIM is pretty leighweigh and blazing fast (unless you install everything you find on Github).

It’s more universal

VIM is everywhere, not only C, C++, C#, Java, JavaScript, Go, Haskel and friends. And VIM is there for years (VI released in 1976). It’s important if you hesitate about the future of Microsoft, or feel bored of .NET (or burnt).

It has the spark of extravagance

Have you seen Rob Ashton coding? Have you seen other people’s faces during that? But, that’s mixture of freak and performance.

It’s raw in a positive way

You think programming is not only about writing the code fast? It’s mainly about reading, right? Then even better, because VIM is raw. There are no codelens, different toolbars/toolboxes, variety of windows, resharper rainbow of tips and tricks. You can focus on code only.

Changing your environment is good

It opens up your mind, it’s like being polyglot programmer. In case of programming languages, if you knew C# only, you would solve each and every problem using classes. Same with environment/IDE. It’s obvious for us that using Visual Studio debugger we can set the next statement there and back. I believe other environments also has such obvious things that we are not aware of.

In the end I’d like to share some video of VIM coding in action.