Git provides some nice utility functionality that can make a vim development environment much nicer. With recent updates to Vim it can now execute a command for every item in the quickfix list (:cdo) and location list (:ldo). These features work together quite nicely.

This new functionality has been introduced to vim from version 7.4.858 and is therefore available in vim8 and also available in neovim.

The Old Way

Back in 2011 I wrote a post about doing search and replace across multiple files with just the basic vim functionality. It’s quite common to use the arg list because its easy to add to:

1
2
:arg *.js
:arg `git ls-files`

and it’s easy to execute commands:

1
:argdo %s/foo/bar/gc

The New Way

Now that we can execute a command from the quickfix and location lists it is much easier to make larger, more controlled edits with the help of other features or plugins.

If you use syntastic or neomake for linting, a compiler via the :make command, the built in :grep or :vimgrep commands or any number of other plugins that integrate with these lists, such as vim-fugitive, you can take advantage of :cdo and :ldo.

1
:grep foo **/*.js

Then you can execute commands like this:

1
:cdo s/foo/bar/gc

Git Is Awesome

Git is incredibly powerful and I often use a couple of features that are often overlooked:

  • git ls-files - recursively list all the files in the repo
  • git grep - grep through all the files in the repo

One of the reasons these commands are so good is because by default they will ignore the items in the .gitignore file.

I tend to work with javascript a fair bit and having an easy way to avoid those nasty node_modules directories readily available is great! Best of all, these tools are available on just about every machine I work, on including the machines of other peoples that I pair with.

My Workflow

I use ctrl-p in vim and rather than relying on yet another third party tool like ack or ag, I’ve configured crtl-p like this:

1
2
3
4
5
let g:ctrlp_user_command = [
\  '.git',
\  'cd %s && git ls-files . -co --exclude-standard',
\  'find %s -type f'
\]

It is super fast and I haven’t come across a situation where I need ctrl-p for a large enough non-git repo and find wasn’t good enough for… yet!

If you use vim-fugitive, there is also a :Ggrep command that behaves much like the builtin :grep command, but it will ignore the .gitignore items. I use this quite a lot too:

1
2
:Ggrep foo
:Ggrep foo **/*.js

Then you can execute commands in the same manner as above:

1
:cdo s/foo/bar/gc

Because I use this so often, I’ve added the following mapping to my config to automatically search for the token under my cursor:

1
map <leader>g :Ggrep!  <Bar> copen

I’m going to attempt to use netrw exclusively for a while instead of NERDTree. Mainly because not everyone has NERDTree, but everyone I work with will generally have netrw installed by default so I thought I should be become more proficient with it.

This post should provide me something I can quickly refer back to when I get stuck. Netrw has a lot of features and the help page is pretty comprehensive. It’s worth a quick look, at least at the table of contents. It’s available by typing :help netrw.

There is also a quick reference for the mapping by typing :help netrw-quickmap and one for the commands by typing :help netrw-quickcom.

Navigation

Navigating around netrw is pretty intuitive, you use the arrows (or hjkl) to move around and enter to open files or directories. These windows are just like any other window in vim so most of the usual motions, etc. work except netrw adds some default mappings. Here are the basics for navigation:

enter - Open files/directories
- - Go up one directory
u - Go back to previously visited directory (like <C-o> in vim)
U - Go forward to subsequently visited directory (like <C-i> in vim)

enter works just fine to open files and directories, but there are some other options available too:

o - Open file/directory in new horizontal split
v - Open file/directory in new vertical split
t - Open file/directory in new tab
p - Preview file without (moving the cursor from netrw)
x - Open the file/directory with the default system app

Appearance and Behaviour

One of the first things I noticed when making the switch was when you press enter on a directory, instead of displaying the contents of the sub-directory inline, it would replace the whole buffer with the contents of the sub-directory.

This is because by default netrw doesn’t use a tree to display the files/directories, its more like doing an ls but you can configure netrw to print a tree and have the same behaviour as NERDTree with this mapping:

i - Cycle between different listing modes (one of them is tree mode)

  • In normal mode, enter will move into and show the given file/directory
  • In tree mode, enter will show the contents of the sub-directory in addition

While netrw doesn’t look as nice as NERDTree, it still has a lot of options to customize the way it looks and works.

I - Toggle the banner
c - Make the browsing directory the current working directory
gn - Make the directory under the cursor the top of the tree
gh - Toggle hidden files on or off
a - Cycle between all files, not hidden files or just hidden files visible
s - Cycle sort order between name, time or filesize
r - Reverse sort order

File Operations

It’s also pretty easy to do basic file operations:

% - Create a new file
d - Create a new directory
D - Delete the file/directory under the cursor (or marked files/dirs)
R - Rename/move file/directory

Copying files however is a little more involved. You need to mark the files you want to copy, mark the destination, then execute the operation (a little tedious):

mf - Toggle whether the file/directory is marked
mt - Mark the directory under the cursor as the copy target
mc - Execute the copy operation
mu - Unmark all marked items

Commands

To open netrw is easy. You can use all the same commands you would use to open a file except give them a directory. You can use the command line with vim . or within vim with the commands below. These commands don’t even need a space between it and its arguments, so its very few keystrokes:

:e. - Open the current directory normally
:sp. - Open the current directory in a horizontal split
:vs. - Open the current directory in a vertical split
:tabe. - Open the current directory in a new tab

These will all work, unless you have installed an alternative explorer plugin (like NERDTree), in which case you can explicitly open netrw with :Ntree.

Netrw also provides a lot of different ways to launch an explorer window. The most common command is :Explore which will open netrw in the directory of the currently open file, much like the :NERDTreeFind command. Here are some variations of that command:

:Ex - Use current buffer if available, otherwise split horizontally
:Ex! - Use current buffer if available, otherwise split vertically

:Sex! - Horizontal split
:Hex - Horizontal split
:Hex! - Horizontal split (opposite side)

:Sex - Vertical split
:Vex - Vertical split
:Vex! - Vertical split (opposite side)

:Tex - New tab, directory of currently open buffer

There is another variation that doesn’t use the directory of currently open buffer but uses the current working directory. This is one is the most similar to the default :NERDTree command.

:Lex - Vertical split full height, current working directory
:Lex! - Vertical split, current working directory (opposite side)

All these commands can also take a directory as an argument.

Basic Configuration

I didn’t want to customize too much because that would defeat the purpose of the learning the defaults, but I did want to turn off that banner (it was handy having the basic operations on display, but I don’t think I need it anymore).

1
2
3
let g:netrw_banner=0
let g:netrw_list_hide = '\(^\|\s\s\)\zs\.\S\+,\(^\|\s\s\)ntuser\.\S\+'
autocmd FileType netrw set nolist

More Features

There is more to explore with netrw, such as working with bookmarks and pattern listings, but this post should have enough of the basics to be productive. Checkout :help netrw for more features.

Git v2.8 introduced a new configuration option called user.useconfigonly. This option prevents git from trying to guess your email address to use for the author metadata for a commit and forces you to have configured one.

This is great news because with a good workflow in place you can be sure you always have the correct email addresses on your commits.

Global Configuration

If user.useconfigonly is set to true, you will need to configure an email address. The simplest way is with this command:

1
2
git config --global user.name 'Steve Occhipinti'
git config --global user.email steve@example.com

Which will result in a configuration like this saved in ~/.gitconfig:

1
2
3
[user]
  name = Steve Occhipinti
  email = steve@example.com

This is great, but what if you want to work on personal projects and work projects on the same machine?

Per Repository Configuration

Instead of using the global config in the home directory, git will first look for a local configuration in ./.git/config. To set per repository configuration, all you have to do is cd to the repo and run the same commands but without the --global flag:

1
2
git config user.name 'Steve Occhipinti'
git config user.email steve@example.com

Mixing Work And Personal

If you have a global configuration, all repositories will use that as a default unless you remember to set a per-repository config. If you don’t set a global config, git will normally guess what your email is and use that if its valid.

If you set the useconfigonly option and remove your global config, git will not allow you to make a commit until you’ve setup your user details and this will prevent accidentally using your work email address on a personal project or vice-versa.

However, I do leave my name configured globally as that is not going to change between repositories.

Visual Queues

Having that error appear when you haven’t setup an email address is great, but rather than waiting for me to make a mistake, I added an exclamation mark indicator to my shell prompt to remind me to set up the user details.

The basic idea is something like this:

1
2
3
local noauthor
git config user.email > /dev/null || noauthor="!"
export $PS1="$noauthor${PS1}"

Quicker Configuration

If this is something that I will have to do for every repo I create or clone, I want to it be pain free. Git makes it really easy to create new sub commands simply by putting a script named git-xxxx in the path, where xxxx is the sub command name.

I created a git-author script like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash
set -e

email_list_file="$HOME/.config/git/author-emails"
has_pecorb=$(type pecorb > /dev/null 2>&1)

echo "Current author: $(git config user.name) <$(git config user.email)>"

if [ -f $email_list_file ] && $has_pecorb; then
  email=$(pecorb $email_list_file)
else
  echo -n "Enter a new email address: "
  read email
fi

git config user.email $email

Now when go to a repo and I see my ! indicator, all I have to do is run git author.

This allows me to put all my email addresses in a file and then select the one I want from a nice menu. Note, I’m using pecorb here which is a gem I wrote to generate selectable menus on the command line, but there are plenty of alternatives or you could just use read in bash and type it in (which my script falls back to).

My Bash Prompt

The prompt I use may not be the tidiest, but its available here.

The Machine

My gaming computer runs Microsoft Windows 10 and has the following hardware:

Case: Corsair Carbide Air 240
CPU: Intel Core i5 4690
Motherboard: ASUS Z97M-PLUS
RAM: Corsair Vengence Pro 1600C9R (2x4GB)
GPU: Sapphire R9 280X Dual-X OC 3GB
PSU: Silverstone Strider Gold 750w ST75F-GS
SSD: Corsair Force LS 120GB
Cooler: Corsair H100i
Fans: Corsair AIR SP120 Twin Pack

The Problem

Sometimes my computer would turn it self on at some random time. It wasn’t at a particular repeatable time, but just every now and then.

What I Tried

  • Disabling the Fast Boot app
  • Uninstalling the Fast Boot app
  • Experimenting with various BIOS settings
  • Disabling boot from network (from BIOS boot priorities)
  • Power options -> power-plan -> advanced -> PCIe -> link state power management
  • (… and a few more that I can’t remember)

But after all that, it would still turn on every couple of days.

The Solution

Eventually I found and disabled Windows Fast Start:

  • Power options -> system (choose buttons) -> fast startup

This turned out to be the culprit and now my computer and I can both stop working through the night!

Following on from a previous post about rewriting indentation for an entire git repo, another reason to rewrite the history of a whole repo is to change the email address or name mentioned in commits.

Once again, be aware that rewriting history will cause problems if other people have clones of the repo so make sure you understand the risks before doing this!

To change the author name and email address for every commit, you can run this:

1
2
3
4
5
6
git filter-branch -f --env-filter "
  GIT_AUTHOR_NAME='YOUR_NAME'
  GIT_AUTHOR_EMAIL='YOUR_EMAIL'
  GIT_COMMITTER_NAME='YOUR_NAME'
  GIT_COMMITTER_EMAIL='YOUR_EMAIL'
" HEAD

This will blindly replace all the commits with the details given, but if other people have contributed, you may need to be a bit more careful and only replace your own:

1
2
3
4
5
6
7
8
9
10
11
12
git filter-branch --commit-filter "
  if [ "$GIT_COMMITTER_NAME" = 'YOUR_ORIGINAL_NAME'];
  then
    GIT_AUTHOR_NAME='YOUR_NEW_NAME'
    GIT_AUTHOR_EMAIL='YOUR_NEW_EMAIL'
    GIT_COMMITTER_NAME='YOUR_NEW_NAME'
    GIT_COMMITTER_EMAIL='YOUR_NEW_EMAIL'
    git commit-tree "$@";
  else
    git commit-tree "$@";
  fi
" HEAD

If you understand the risks of rewriting history for a shared repository, you can force push with the -f flag:

1
git push -f

Then, to ensure future commits don’t use the wrong name and email, you can set it explicity for this particular repo (instead of globally) with these commands:

1
2
git config user.email "your_email@example.com"
git config user.email "your_email@example.com"

Keep in mind this will only work for this particular clone as the details will be stored locally in .git/config.

By default, the sudo command does not pass your current shell environment to the new process.

I’ve added the function below to my bash configuration which will gives me an esudo command. This command works much like sudo but it will pass my current environment to the new process.

1
function esudo { sudo -E bash -c "$*"; }

If you use a ruby version manager, you’ll know that they generally rely on environment variables, so rvm provide the rvmsudo command for this purpose. I’ve since switched to chruby and I couldn’t seem to find an equivalent, but this has solved the issue for me.

I have a fairly terrible memory but I’ve found writing and referring back to cheatsheets to be a pretty effective way to memorize things.

I ended up referring back to my previous cheatsheet on git reset quite a few times soon after I wrote it, so when I came across this great post on regex features in ruby I thought I’d share the lookarounds section because I always forget those too!

Syntax Description Example Result
(?=X) Positive lookahead "Ruby"[/.(?=b)/] "u"
(?!X) Negative lookahead "Ruby"[/.(?!u)/] "u"
(?<=X) Positive lookbehind "Ruby"[/(?<=u)./] "b"
(?<!X) Negative lookbehind "Ruby"[/(?<!R|^)./] "b"

Checkout the original blog post for the rest of the regex tips or the Idiosyncratic Ruby site for more ruby tips!

It seems the JavaScript community is divided into two camps when it comes to indentation conventions: two spaces or four?

I personally prefer two spaces mainly because its what I’m used to in Ruby, I find it easier on the eyes and just that little bit easier to keep my lines under 80 characters long (yes, I still think this is good practice).

Our team had come to a general consensus for using two spaces, but when we were starting a new project based on an existing project that used four spaces, we thought it would be nice to fix all the whitespace in one go.

In a rush, we made a commit that literally replaced all the whitespace with the following command:

1
find . -type f -exec sed -i "" "s/    /  /g" {} \;

The problem with this approach is that it makes going through commit messages harder. It means that when you use git annotate, every line with indentation is going to have the whitespace fix as the last commit, so then you would have to jump back another commit to get the actual commit message for that line, which can be fairly annoying.

Luckily, if you are forking an existing repository for a new project you have the luxury of being able to rewrite history without causing any pain to others as no one else would have checked it out yet.

Git provides a powerful command called filter-branch. It is designed to rewrite large amounts of history in one go. This can be useful to purge sensitive information from every commit or update an email address in the commit data, etc. The only problem with this is, just like rebasing, any existing checkouts will not be able to simply use git pull cleanly after the history has been rewritten upstream, but this isn’t a problem for new projects.

In order to execute the command above for every commit in our repo, we can make use of the --tree-filter option like this:

1
git filter-branch --tree-filter 'find . -type f -exec sed -i "" "s/    /  /g" {} \;' HEAD

Please note, this can take quite some time, especially for large repositories. You should also make sure there are no files that specifically need four spaces (like markdown files, etc.), otherwise you may want to restrict the find command to only effect files you know are safe to change (*.js for example).

For more information on rewriting history and git filter-branch, see this article and the documentation.

We all know that if you are going to be rendering user provided content on a HTML page, it should be sanitized just in case they include a nasty script tag or something.

React will automatically sanitize any string being rendered to the screen unless you jump through hoops first - which is great because making this difficult means its somewhat harder to inadvertently create a XSS vulnerability.

However, if you get a string from a human source and want to display that in a div tag while maintaining its newlines, this becomes a little harder because you don’t want to replace all \n characters with <br /> tags because this would mean you would also need to disable the sanitizing.

There are some libraries to deal with this sort of thing that implement white listing of tags, etc.
Another alternative would be using something like Markdown.
Even a simple <pre> tag will get you pretty far, but today I read an article that shows how you can achieve this with a little CSS:

1
2
3
.pre {
  white-space: pre-line;
}

For more details, I recommend having a read of this article.

If you ever needed to circumvent the browsers Same Origin Policy (SOP) so you don’t need to add Cross Origin Resource Sharing (CORS) headers just to test out an idea, here is a quick little hack to open a new instance of Chrome that will not enforce these security features:

1
alias unsafe-chrome='/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --user-data-dir=~/Library/Application\ Support/Google/UnsafeChrome --disable-web-security 2> /dev/null'

The important options here are:

--disable-web-security - This will disable the Same Origin Policy
--user-data-dir=... - This launches a separate instance, with its own user data directory.
This prevents you from needing to close any current instances of chrome, otherwise running this command will just bring the existing instance into focus.

Another good thing about giving this instance its own user-data-dir is that you can give this instance its own settings. For example, this instance is not signed into my Google account and I’ve configured a bright red theme so I can easily tell the difference between my normal Chrome and my insecure Chrome!