10 Aug 2015
Every developer has been through this scenario:
- make changes, bug seems fixed
- commits everything
- refactors some bits of code
- pushes code to the remote
and everything seems fine and dandy…until Jenkins warns that you broke the build because some changes you made were in a different repository that you forgot to update.
I’ve been through that too, but fortunately with Gradle you have an easy way to avoid this. Put this in your Gradle init script (for unix-y systems, it’s ~/.gradle/init.gradle):
allprojects {
task paths << { task -> println "$task.project.projectDir" }
}
And put this script somewhere (I usually put this in ~/bin):
#!/bin/bash
# This script checks if the staging area for git directories in $1/stdin is empty
while read line; do
dir=$line
curdir=$PWD
cd $dir
gitroot=`git rev-parse --show-toplevel`
cd $gitroot
if [[ -z "$gitroot" ]]
then
echo "No git directory @ $dir!"
cd $curdir
exit 1
fi
changed=`git status -s | grep -v "^??"`
if [[ -z "$changed" ]]
then
cd $curdir
else
cd $curdir
printf "There are changed files in $dir:\n$changed"
exit 1
fi
done < "${1:-/dev/stdin}"
And add this to your pre-push hook:
echo "Checking for unstaged changes in project directories"
gradle -q path | ~/bin/git-check-empty-staging-area.sh
if [ $? -ne 0 ]
then
exit 1
fi
Of course, you can also use whatever command outputs a list of git directories instead of ‘gradle -q path’.
Feel free to update the gist with better code, and let me know!
08 Aug 2015
Small post with a fix for a (somewhat) common problem. If you use Emacs’ registers to save window or frame configurations, you probably found a small bug with the ‘:reg’ command in Evil-mode.
Fortunately, the solution is very simple, just apply this patch and it will work. Or you can just copy-paste and evaluate this code:
(defun evil-register-list ()
"Returns an alist of all registers"
(sort (append (mapcar #'(lambda (reg)
(cons reg (evil-get-register reg t)))
'(?\" ?* ?+ ?% ?# ?/ ?: ?. ?-
?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9))
(delq nil (mapcar (lambda (reg) (and (number-or-marker-p (car reg)) reg)) register-alist)) nil
nil)
#'(lambda (reg1 reg2) (< (car reg1) (car reg2)))))
16 Jul 2015
Magit’s keybindings for working with git are awesome, and the newest version has many improvements. Even though there’s magit-gh-pulls for working with Github pull requests, I’m still a fan of Github’s online interface. I use a customized version of the function presented in Endless Parentheses:
(defun endless/visit-pull-request-url (base)
"visit the current branch's pr on github and compares it against BASE."
(interactive (list (magit-read-other-branch-or-commit "Compare with")))
(browse-url
(format "%s/compare/%s...%s"
(magit-get "remote.origin.url")
base
(cdr (magit-get-remote-branch))
)))
;; I use spacemacs, so this is the incantation to bind this function to a keystroke:
(evil-leader/set-key (kbd "g P c") 'endless/visit-pull-request-url)
So whenever I’m finished with my changes, I just press Space g P c and it opens the Github PR interface in the default browser. If you want to change the browser, check the browse-url-generic-program variable in Customize.
14 Jul 2015
There is an epic post in StackOverflow explaining why vi is so great. As a longtime Emacs user, the concept of modal editing always eluded me. Having to press ‘i’ before typing, accidentally pressing ‘u’ and undoing your changes…this looks like a nightmare! Fortunately, the pain of an unexpected tendonitis forced me to find ways to type drastically less, and I decided to give vi a go (in the form of IDE plugins such as IDEAVim and VsVim).
(Obligatory disclaimer: No, I didn’t get the tendonitis from Emacs. But I have to agree that its default keymap could be more ergonomic.)
What makes vi key bindings so efficient? Terseness (a lot of complex actions are triggered with few keystrokes) and composability. Let’s take a little dive on how to do a few small tasks in Vim…
Moving around, writing some stuff
hjkl keys are used to move left,up,down,right respectively. But that’s not the way you should be moving around in a file. Let’s say we have the following code:
def i_do_something(index, otherparam):
my_thing = |grab_stuff_at(index)
my_thing.modify(otherparam)
And the ‘ |
’ represents where the cursor is in the file. How would you set the cursor: |
- following the letter ‘s’?
- after the ‘t’ in my_thing?
- at the beginning or end of the line? at the first non-whitespace character of the line?
Answers: respectively, pressing ‘fs’, ‘Tt’, ‘0’, ‘$’, ‘^’ (without quotes).
What all these operations have in common? They are toggled by one keystroke, followed by its “argument” (optional in some cases, as we’ve seen). If this looks like a function call, it is…more on that later.
What about plain old typing? How do I write, delete, change and move text around? Most people try to memorize a few vi “shortcuts”, without realizing that it follows the same pattern:
- want to insert text before the cursor? or maybe append to the character following the cursor? Or even better, Insert at the beginning or Append at the end of the current line?
- delete or change text in the current line? substitute a few characters, extract or replace them?
(Go ahead, try playing with the letters in bold while in vi normal mode, and you’ll see what I mean)
So, we’ve seen how to do basic operations in Vim, but this does not get us any more productive than any Notepad/nano user. How do you go from there to sculpting your code in a few keystrokes?
Composing commands: applying over a range, keyboard macros, repeating
Remember that vi commands look like function calls? The great thing is that they usually accept optional parameters too. Coming back to our Python example, let’s say you want to delete from cursor to the end of the line. How do you do that? Press ‘d$’, which should translate as “delete from here to the end of the line”. This works for every vi command, like the ones we’ve mentioned above.
Want to perform somewhat complex text operations? Keyboard macros to the rescue! When you press ‘q’ in normal mode, vi expects the next character to be a register to store your macro. Any alphanumeric character will do. For instance, let’s say we have the following text:
<div>
<ul>
<li>Something here</li>
<li>Another thing here</li>
</ul>
</div>
And you want to add a URL to every occurrence of the word ‘here’. Make a keyboard macro by pressing, say, ‘qq’, then type the commands: ‘/here[Enter]i<a href=”http://my.important.link.com”>[Esc]lea</a>[Esc]’. After that, press ‘@q’ to replay your recently-saved macro. The result will be:
<div>
<ul>
<li>Something <a href="http://my.important.link.com">here</a></li>
<li>Another thing <a href="http://my.important.link.com">here</a></li>
</ul>
</div>
(Want to check what is saved in your registers? Press ‘:reg’ in normal mode)
You can also “programatically” repeat a macro or command by prefixing it with a number, telling how many times you want the macro to be played.
Conclusion
These “simple” commands are the bread and butter of my daily code editing. 90% of my tasks are solved with this small set of operations and the multiple ways to combine them. And this is not even advanced Vim! We did not go through creative uses of registers, how to use marks, ex commands, calling and reading from the shell…and, in the case of my tool of choice, Spacemacs, how to create new motions and commands. Let’s leave it for another post! For now, I hope these instructions will be useful for you to be more productive with vi-like editors.