Truth to be told I always was quite an IDE guy. Mainly developing Java I praised the power of these tools that helped to get my job done. Sometimes I scratched my head when some indexing blocked the whole thing for a few seconds (or minutes), and I did not mind if some magic gone off-tracks, and had to refresh/restart the whole thing a few times to make the correct value appear. Many times it felt sluggish, but it always did the job.
Java development always seemed inevitably IDE oriented, so I did not thought much about other approaches. But many other languages, such as Scala seems different in this respect, so I started to experiment with simple, small tools, and relying extensively on the shell.
Using Unix as an IDE has some rough edges, some parts are not as nicely integrated as in a real IDE, but there are lots of little components awaiting for those who are not afraid of the power of the shell.
I think it's more of a philosophical difference rather than technological. The tools we use shape our thinking. With a full-fledged IDE you get a nice default behaviour that that you can customize, but
- that customization is usually not required, so it's rarely done, and feels uncomfortable
- always try to solve new problems to fit in the philosophy of that environment, even if it was designed with different kinds of problems in mind
- there are many different IDEs, and it's not guaranteed that your chosen platform has idiomatic/acceptable solution to a problem
- it's one huge thing, that try to do everything for you
It's rather the opposite with small programs that do only one thing. You have the freedom to assemble/hack things together from a wast library of reusable pieces according to your needs. Of course its not black and white, for example nothing stops you from using an IDE for coding while managing versions and building from the command line.
But enough of this babbling. The main reason I started to look around, is that I felt that the IDE I use is a bit slower and heavier than it should be, and it made me feel uncomfortable. So the idea is to use a lightweight and fast text editor - yes, Vim - for most of the coding, and use other command line tools and the shell for the rest of the job.
In this post I'd like to share my findings about the Vim plugins that I found useful for coding in general, and a bit about my half-baked Scala development workflow from Vim perspective that I am trying to evolve.
General plugins for coding
Vim has a bunch of ways to manage plugins. Although it can be done manually, it's important to choose a method that helps automate installs and uninstalls, as these are really common tasks, especially when experimenting. Personally I use Vundle for this, it can download plugins directly from Github, which is nice.
At first for navigation I started to use The NERD Tree. As the name suggests, it represents the directories and files in a comforting tree structure, much like things are usually represented in an IDE - feels right at home.
One can easily open files from it even in a new tab or pane. Another great feature I like is that it can show the currently opened file in the hierarchy, which is a great way to explore files inside a package.
I set up key bindings to the common operations I tend to use. The following configuration enables to
- Toggle tree view with F2
- Find the currently opened file in the tree with F3
- Peek at a file with F4
silent! nmap <C-p> :NERDTreeToggle<CR>
silent! map <F2> :NERDTreeToggle<CR>
silent! map <F3> :NERDTreeFind<CR>
Browsing the structure is great in a tree, but it can be slow to manually find a file in the project. CtrlP is a fuzzy file finder for Vim, that solves this problem. By default, if you press ctrl+p (cool name, you don't even need a manual to use it) it searches not only from the current relative directory, but it's also able to detect the root of a project based on the Version Control files and perform a search from there.
It's important to set up the appropriate file and directory exclusions for the search, as by default it finds anything, including all the derived files the compiler generates. For Maven (or SBT) projects, simply add the following line to your .vimrc.
I mainly use the terminal for Git related jobs, but there are several tasks that can be aided by the editor. Fugitive is a Git wrapper that augments it's functionality with great features. I use it for merging and patching, but there is a lot more potential in it.
For visual indicators, I use Gitgutter and Airline. Gitgutter marks the lines added, removed or changed since the last commit, while Airline enhances the statusbar with lots of useful information in an aesthetic way. Bonus, the latter can integrate with the former to display summarized information related to the numbers of the modified lines.
To enhance highlighting, I use the Rainbow Parentheses plugin which mark parentheses in different colors according to their depths. This can be really useful, as one can determine matching brackets in a flash.
And it's also nicely highlights scopes.
Neocomplete is a powerful suggestion system that enhances Vim's built in keyword completion functionality. For example it provides smart-casing, and it can be configured to automatically display suggestions as you type, which is incredibly helpful. Of course, by default it does not provide suggestions based on the analysis of the edited source file, but I find that most of the time this simple approach is good enough, and it's really fast.
Finally, when programming it's useful to be able to comment and uncomment sections of code. Nerdcommenter provides commenting commands that integrates nicely to Vim's vocabulary.
Scala specific extensions
The plugins above can provide help with almost any programming language, let's see the ones that are specific to the Scala language.
One must decide about the programming environment what are the frequent tasks that arise during development, and adjust the tools and the workflow accordingly. This is strongly related to the question of what features are important, and what are the ones that one can live without.
Nowadays, I use two terminal windows when I code, one for Vim to edit the source files, and one for the SBT console, that compiles and tests the code continuously. The only Scala related enhancement to Vim I used is syntax highlighting for the language (vim-scala).
Write some code or test, switch terminal, see if everything is OK, switch back, do some more coding. It's easy to get into the flow, as this approach is really lightweight, nothing slows down the editor and thus the coding. Also, thanks to the SBT, the incremental compilation and unit testing can happen automatically in the background.
The frequency of terminal switching would be much less, if the editor could report basic problems, such as syntax errors or even compile errors. I thought the former one is probably easier to achieve, so I tried Syntastic, which is a powerful tool to detect and report basic syntactic errors. It can even check files on save automatically. However, I found two problems with it when I started using it with Scala. First, it was really slow. Upon checking, it compiled the current file with scalac, and every time that happened, it stopped Vim for a bit. The other problem is, that it turns out Scala's syntax is really lenient, and without the type checks, there are not many potential errors that can be reported. I could have thought about that earlier, but it was really surprising to see that I was almost unable to squeeze out a meaningful error.
So I dismissed the idea of pure syntax checking, and started searching for something that can report all compile errors when I stumbled upon this post, and tried the sbt-quickfix plugin described therein. This way, the two terminal solution essentially remains the same, and all the other necessary build activities can be done in the SBT console. In the meantime, when the SBT continuously compiles and tests the code, it also generates a quickfix file with actual errors. This file can be read automatically or on demand by Vim for reporting. (I use vim-hier to visually indicate the location of the quickfix messages.)
Contrary to the syntax checking solution, it does not have performance impact on the editor, as the compilation continue to happen in a separate process, not invoked directly by the editor. So it's nicely extends the previous workflow.
Other missing pieces
There are a lot of stuff that does not feel 100% right in this setup. For example, the lack of integrated API discovery solutions (like intelligent code analysis based completion) are a mayor source of pain, not to mention refactoring tools, code templates, code formatting and linting. It's a long road ahead, but I think some of these problems are already solved, and some features are simply not required (for me, at least), and it's important to keep the benefits of the different approach in mind.