Today I Learned

A Hashrocket project

95 posts by doriankarter @dorian_escplan

Add highlighted code from #Vim to #Apple #Keynote

Giving a talk with keynote? If you’re like me and you love Vim and Apple Keynote you might struggle with getting your highlighted, indented code over to Keynote and making it look as good as it looks in Vim.

Fret no more - vim-copy-as-rtf is a plugin that will let you do that without installing any additional libraries on your mac.

Simply select the code snippet, type :CopyRTF and the highlighted code will be copied to your clipboard ready to be pasted into Keynote. That simple.

Get it here: https://github.com/zerowidth/vim-copy-as-rtf

Persistent folds between Vim sessions

Folds are great. They help you when you have to deal with big files where compartmentalizing the logic might be of help.

The problem is that when you close Vim, your artfully folded code returns to its unfolded state.

The solution is quite simple - when you are ready to save your folds run the :mkview command. This will save your folds in the current buffer to your viewdir (:h viewdir) depending on your environment.

To load your folds use :loadview.

To automate this process add the following to your vimrc:

augroup AutoSaveFolds
  autocmd!
  autocmd BufWinLeave * mkview
  autocmd BufWinEnter * silent loadview
augroup END

The folds will be local to your machine, but if you want you can configure mkview to save folds to a file in your project directory and share them with your team.

Homebrew is eating up your harddrive

If you’ve been using Homebrew on your Mac (if you have a Mac you really should) you may not be aware that every time you upgrade your brew formulas using brew update && brew upgrade Homebrew is leaving behind a copy of the old versions.

With package updates becoming available daily you may end up with gigabytes of space being wasted away on old package versions.

To see how much space the old versions are using run brew cleanup -n. When I ran that command I got:

==> This operation would free approximately 9.2G of disk space.

Holy cannoli! zomg

If you feel like reclaiming that diskspace just run the command again without the -n: brew cleanup.

Enjoy space! 🚀

Find where anything is defined in Vim config

When your vim bundle and vimrc become a plugin soup you often need to debug where an autocmd, command, map or function are coming from.

The :verbose command can come in handy in this scenario. Here are some examples:

See where a mapping was set from:

:verbose map gY

See what happens when you enter a buffer:

:verbose autocmd BufEnter

See which file defined a command:

:verbose command Explore

Where is the abbreviation coming from:

:verbose abbrev bpry

etc…

Example output:

    Name        Args       Address   Complete  Definition
!   Explore     *    0c              dir           call netrw#Explore(<count>,0,0+<bang>0,<q-args>)
        Last set from /usr/local/Cellar/vim/7.4.1190/share/vim/vim74/plugin/netrwPlugin.vim

Happy hunting! 🔫

Missed an alert message in vim?

If you ever missed an alert message in Vim, you know the ones that show up at the bottom in the command line, you can easily view a list of all past messages by running the :messages command.

You can also add your own using :echom, which adds a persistent message.

Try it now.

NOTE this will only show persistent messages (echom), and not momentary messages set using echo.

Highlight #markdown fenced code syntax in #Vim

Up until now I was editing all my blog posts in Atom for lack of markdown fenced code block highlighting in Vim. Atom supported it out of the box. As it turns out Vim can do that too, out of the box!

If you are running a recent version of Vim (mine at time of writing 7.4.9910) you can setup highlighting for fenced code blocks in markdown.

Open your .vimrc and add the following line:

let g:markdown_fenced_languages = ['html', 'vim', 'ruby', 'python', 'bash=sh']

You can customize it to your liking and add more languages.

Note: Not all languages are supported but you can try and see if they work. To see a list of languages you have installed on Mac (with Vim installed by Homebrew) run ls -l /usr/local/Cellar/vim/7.4.1190/share/vim/vim74/syntax

screenshot

This is a game changer.

Breezy copy to system clipboard in Vim

When it’s time to get text processed in Vim out of your editor and onto a shiny blog post many Vim Warriors reach for the awkward “copy to system register” keyboard chord.

"*y[motion]

Worse is trying to copy the whole file:

gg"*yG

This feat of keyboard heroism has crushed many heroes and inflicted countless RSI wounds.

It’s time to slay the dragon 🐲 by adding these to your .vimrc:

" copy to system clipboard
map gy "*y
" copy whole file to system clipboard
nmap gY gg"*yG

Pretty Print JSON/HTML in Vim

When working with external APIs often you will get a highly netsted json, like this one, all in one line, with no spaces:

{"batters":{"batter":[{"id":"1003","type":"Blueberry"},{"id":"1004","type":"Devil's Food"}]},"id":"0001","name":"Cake","ppu":0.55,"topping":[{"id":"5002","type":"Glazed"},{"id":"5007","type":"Powdered Sugar"}],"type":"donut"}

The horror. You are not a network cable! You deserve better!

Add the following to your .vimrc file:

command! PrettyPrintJSON %!python -m json.tool
command! PrettyPrintHTML !tidy -mi -html -wrap 0 %
command! PrettyPrintXML !tidy -mi -xml -wrap 0 %

Now you can paste the json into your Vim buffer and run the :PrettyPrintJSON command.

{
    "batters": {
        "batter": [
            {
                "id": "1003",
                "type": "Blueberry"
            },
            {
                "id": "1004",
                "type": "Devil's Food"
            }
        ]
    },
    "id": "0001",
    "name": "Cake",
    "ppu": 0.55,
    "topping": [
        {
            "id": "5002",
            "type": "Glazed"
        },
        {
            "id": "5007",
            "type": "Powdered Sugar"
        }
    ],
    "type": "donut"
}

Magic.

Same goes for HTML, just run :PrettyPrintHTML.

NOTE: For these to work you need to have python and tidy installed on your machine.

Change Rails validation message completely

Rails always appends field name to validation messages, and when setting message: on a validation statement it gets appended to the humanized name of the field.

If you want to change the validation message completely use the locales file:

# config/locales/en.yml
en:
  activerecord:
    attributes:
      user:
        email: "E-mail address"
    errors:
      models:
        user:
          attributes:
            email:
              blank: "is required"

This was particularly useful with the ValidatesTimeliness gem which does not support a lambda.


🎉Happy 500 post to TIL 🎉

Custom order #Postgres #SQL union queries

Consider the following data:

insert into users (email, first, last) values ('newuser@example.com', 'New', 'User');
insert into users (email, first, last) values ('notthereallemmy@example.com', 'Lemmy', 'Kilmister');
insert into users (email, first, last) values ('lemmy@example.com', 'Lemmy', 'Kilmister');

Assuming you want to match a user to the following data:

{ email: 'lemmy@example.com', first: 'New', last: 'User' }
````

And you consider email a better indication of a match, and first and last name are a fallback. The following query will not yield the desired results despite the `where` conditions being ordered per the requirements:

select * from users where email = ‘lemmy@example.com’ or (first = ‘New’ and last = ‘User’) limit 1;


This will result in:

1 | ‘newuser@example.com’ | ‘New’ | ‘User’


To find by email first we will need to union two queries, rank the match then order by rank:

(select 1 as rank, id, email, first, last from users where email = ‘lemmy@example.com’) union (select 2 as rank, id, email, first, last from users where first = ‘New’ and last = ‘User’) order by rank limit 1;


This will yield the correct result:

3 | ‘lemmy@example.com’ | ‘Lemmy’ | ‘Kilmister’

How to use the hidden #VNC client in #Mac #OSX

OS X has a built in VNC (Screen Sharing) server, but it is a little known feature that it also has a built in VNC client. No additional software is necessary.

To setup the server go to Preferences->Sharing and check the “On” checkbox next to “Screen Sharing”. Make sure to only allow access to Administrators or a specific user/user group.

Screen Sharing

You should see your computer name on the Screen Sharing configuration screen. To connect to your computer from another one using VNC open Finder and press ⌘+k. In the Server Address enter vnc:// followed by your computer name or IP address. Connect To Server

h/t Dillon Hafer

Check if a #ruby gem is installed from bash script

If you are adding customizations to your zshrc, such as adding auto completion for a certain gem, you want to make sure that the gem is installed before performing any action.

The gem list [gemname] -i command returns a boolean representing whether a gem is installed or not.

if `gem list lunchy -i`; then 
  echo "Lunchy gem is installed!"; 
  # do some configuration here
fi

If you wish to be more granular you can check whether a specific version is installed by adding the --version [version] flag.

if `gem list lunchy -i --version 0.10.4`; then 
  echo "Lunchy v0.10.4 is installed!"; 
  # do some configuration here
fi

Quickly edit and reload #tmux configuration

When you are playing around with your tmux config you often need to repeatedly open .tmux.conf file and then source it into the current tmux session.

To make things a little faster, add the following to your .tmux.conf:

bind-key r source-file ~/.tmux.conf \; display-message "~/.tmux.conf reloaded"
bind-key M split-window -h "vim ~/.tmux.conf"

Now you can quickly open the tmux config in tmux pane using <prefix> followed by shift + M, edit your configuration, and save when you done. To reload the tmux configuration use <prefix> followed by r.

** <prefix> is C-z for hashrocket’s dotfile project (dotmatrix), if you are using tmux default configuration it would be C-b

Fix Tmux 2.1 mode-mouse error

If your tmux started displaying the following error message:

/Users/username/.tmux.conf:136: unknown option: mode-mouse
/Users/username/.tmux.conf:137: unknown option: mouse-select-pane
/Users/username/.tmux.conf:138: unknown option: mouse-resize-pane
/Users/username/.tmux.conf:139: unknown option: mouse-select-window

when you launch it, it is because the tmux 2.1 has a new syntax for turning mouse-mode on. All of the above are now combined into:

set -g mouse on

You’ll also notice that after replacing the mouse mode setting with the new one in your config you still cannot scroll up/down with your mouse wheel. To fix that use the following configuration:

bind -n WheelUpPane   select-pane -t= \; copy-mode -e \; send-keys -M
bind -n WheelDownPane select-pane -t= \;                 send-keys -M

See the source and location for bash commands

The oh-my-zsh package comes with a lot of useful plugins. Often those plugins add bash functions to the global scope.

If you want to see where the function is defined you can use the type command.

For example the new_gh/exist_gh command which creates a remote repo for a folder

$ type exist_gh
exist_gh is a shell function from /Users/dkarter/.oh-my-zsh/plugins/github/github.plugin.zsh

To see the function source use the declare command:

$ declare -f new_gh
new_gh () {
        cd "$1"
        ghuser=$( git config github.user )
        git init
        print '.*'"\n"'*~' >> .gitignore
        git add ^.*
        git commit -m 'Initial commit.'
        git remote add origin git@github.com:${ghuser}/${repo}.git
        git push -u origin master
}

Change Vim cursor in different modes

Vim’s NORMAL mode and VISUAL mode are complemented perfectly by the block cursor. When in INSERT mode however, you might want a little more precision. That’s why changing the cursor to a slim pipe shape is beneficial (you know, like in any textbox on your OS). It is also a nice reminder that you are in VISUAL mode, without having to stare at the bottom of the screen.

While we are at it, you might also want REPLACE mode to have a cursor of it’s own, for that an underscore style looks great.

To accomplish this customization add the following to your .vimrc

iTerm2 + Tmux on OS

let &t_SI = "\<Esc>Ptmux;\<Esc>\<Esc>]50;CursorShape=1\x7\<Esc>\\"
let &t_SR = "\<Esc>Ptmux;\<Esc>\<Esc>]50;CursorShape=2\x7\<Esc>\\"
let &t_EI = "\<Esc>Ptmux;\<Esc>\<Esc>]50;CursorShape=0\x7\<Esc>\\" 

iTerm2 on OS

let &t_SI = "\<Esc>]50;CursorShape=1\x7"
let &t_SR = "\<Esc>]50;CursorShape=2\x7"
let &t_EI = "\<Esc>]50;CursorShape=0\x7"

Vim startup time profiling

If you want to see why vim is taking so long, you can get a breakdown of how long each plugin took to load:

vim --startuptime startup.log

To make things a little easier, I created the following bash command, which will create the startup log, open it in vim and delete it when done.

vim --startuptime startup.log +qall && vim startup.log && rm startup.log

Graphing the data

You can use vim-plugins-profile shell script to get a better sense of which plugins are causing the biggest slowdown: https://github.com/hyiltiz/vim-plugins-profile

It will create a graph resembling the DevTools network tab: graph

and provide a summary similar to this one:

Generating vim startup profile...    
Parsing vim startup profile...     
Crunching data and generating profile plot ...    

Your plugins startup profile graph is saved     
as `profile.png` under current directory.    

==========================================    
Top 10 Plugins That Slows Down Vim Startup    
==========================================    
   1    105.13  "vim-colorschemes"    
   2    42.661  "vim-easytags"    
   3    31.173  "vim-vendetta"    
   4    22.02   "syntastic"    
   5    13.362  "vim-online-thesaurus"    
   6    7.888   "vim-easymotion"    
   7    6.931   "vim-airline"    
   8    6.608   "YankRing.vim"    
   9    5.266   "nerdcommenter"    
  10    5.017   "delimitMate"    
==========================================    
Done!

Profiling Vim

To find which plugins may be causing certain actions in vim run slowly try using the built in profiler:

:profile start profile.log
:profile func *
:profile file *

Then perform the slow action, when done run:

:profile pause
:q

You can then open the profile.log file and look at the bottom to see summary, sorted by run time, of which functions took the most time, the function name may give away which plugin/core function is causing the issue. The top of the file will contain each line of code that was run in vim during the profiling session and how long it took.

Chrome DevTools navigation and editing tools

If you ever worked with editors such as Atom/Sublime Text you will appreciate the following: Chrome DevTools now sports fuzzy finders for your script/stylesheet files and for methods within them.

To get started open dev tools and hit Cmd+p start typing a filename or part of a filename: cmd-p

Then to jump to a specific method hit Cmd+Shift+P and start typing a method name: cmd-shift-p

If you are a big fan of multiple cursors, you’ll be happy to learn that those are now available within chrome developer tools:

cmd-d [while the cursor is on a word hit Cmd+d to duplicate the cursor to the next match]

holding alt [holding alt and dragging down will allow you to edit a vertical line]

To search all files (scripts/html markup) hit Cmd+Option+f: cmd-alt-f

Change the source in dev tools and hit Cmd+s the updated code will be run the next time it is called. DevTools will indicate it has a modified version by changing the background color to bright orange: change in memory

Using awk to debug $PATH

If you ever tried printing your system PATH environment variable using echo $PATH you probably got something like this:

/usr/local/heroku/bin:/usr/local/bin:/Users/username/.rvm/gems/ruby-2.2.2/bin:/Users/username/.rvm/gems/ruby-2.2.2@global/bin:/Users/username/.rvm/rubies/ruby-2.2.2/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:.git/safe/../../bin:/Users/username/.bin:/usr/local/sbin:/Users/username/.rvm/gems/ruby-2.2.2/bin:/Users/username/.rvm/gems/ruby-2.2.2@global/bin:/Users/username/.rvm/rubies/ruby-2.2.2/bin:/Users/username/.rvm/bin:/Users/username/.rvm/bin:/Users/username/Dropbox/Developer/gocode/bin

Not a pleasant read.

I thought that would be a good opportunity to practice my awk scripting skills and came up with this:

echo $PATH | awk '{ n = split($0, paths, ":"); for (i=0; ++i <= n;) print i, paths[i] }'

It prints a numerically indexed list of the paths and prints them in separate lines.

1 /usr/local/heroku/bin
2 /usr/local/bin
3 /Users/username/.rvm/gems/ruby-2.2.2/bin
4 /Users/username/.rvm/gems/ruby-2.2.2@global/bi
5 /Users/username/.rvm/rubies/ruby-2.2.2/bin
6 /usr/local/bin
7 /usr/bin
8 /bin
9 /usr/sbin
10 /sbin
11 /opt/X11/bin
12 .git/safe/../../bin
13 /Users/username/.bin
14 /usr/local/sbin
15 /Users/username/.rvm/gems/ruby-2.2.2/bin
16 /Users/username/.rvm/gems/ruby-2.2.2@global/b
17 /Users/username/.rvm/rubies/ruby-2.2.2/bin
18 /Users/username/.rvm/bin
19 /Users/username/.rvm/bin
20 /Users/username/Dropbox/Developer/gocode/bin

You can alias this command if you use it often:

alias print-path=`echo $PATH | awk '{ n = split($0, paths, ":"); for (i=0; ++i <= n;) print i, paths[i] }'`

You may want to check out another rocketeer’s (Josh Branchaud) solution to this problem, written in Rust: https://github.com/jbranchaud/ppp

vim-surround is different for selected text

If you tried using vim-surround after selecting text in visual mode, just to get your text deselected and have nothing happen, it’s because visual mode uses a different trigger for vim-surround:

In visual mode use S, followed by your surrounding character (e.g. S)).

This is different from the normal mode way of doing it ys[text-object] (e.g. ysap{)

I like thinking of this one as “yes, surround! [my text object]” and prefer it to selecting, but some cases require visually selecting.

Spell check in vim

Don’t let typos sneak into production, you can use a spell checker right from Vim. Here’s how:

:set spell

To navigate between spelling mistakes use ]s and [s.

To correct spelling mistakes, go to the mistake and use z= to see suggestions.

P.S. if the spelling errors don’t show up, make sure to check two things:

  1. That you are not a fantastic speller and a true scholar
  2. That the file type you are checking spell on is allowed (you can test it by setting your syntax to txt :set syntax=txt)

Find (and kill) all processes listening on a port

To search for processes that listen on a specific port use the lsof or “List Open Files”. The -n argument makes the command run faster by preventing it from doing a ip to hostname conversion. Use grep to show only lines containing the word LISTEN.

lsof -n | grep LISTEN

To filter for a specific port use the following:

lsof -n -i4TCP:[PORT] | grep LISTEN

To kill all processes listening on a specific port use:

lsof -n -i4TCP:[PORT] | grep LISTEN | awk '{ print $2 }' | xargs kill

The awk command returns only the second column (PID), and the xargs executes kill on each line returned.

Add colour to your man pages

Syntax highlighting makes a programmer’s life more cheerful. Linux man pages shouldn’t be an exception.

Add the following to your zshrc to highlight arguments and commands in man pages:

export LESS_TERMCAP_mb=$(printf '\e[01;31m') # enter blinking mode – red
export LESS_TERMCAP_md=$(printf '\e[01;35m') # enter double-bright mode – bold, magenta
export LESS_TERMCAP_me=$(printf '\e[0m') # turn off all appearance modes (mb, md, so, us)
export LESS_TERMCAP_se=$(printf '\e[0m') # leave standout mode
export LESS_TERMCAP_so=$(printf '\e[01;33m') # enter standout mode – yellow
export LESS_TERMCAP_ue=$(printf '\e[0m') # leave underline mode
export LESS_TERMCAP_us=$(printf '\e[04;36m') # enter underline mode – cyan

Preview

Browse ruby gem source inside of a vim tab

When you are working with gems you often need to jump to the gem’s source. Vim has a really neat trick for that.

First make sure you have the vim-bundler plugin by Tim Pope installed: https://github.com/tpope/vim-bundler. Then you can use the following command:

:Btabedit name_of_gem

💥Boom.

Vim opens the gem’s source starting with a netrw file list in a new tab for you.

Bonus: Vim will autocomplete the gem name for you based on your Gemfile.

Never leave the home row in bash

To edit a command in bash you often need to jump around in the line and revert to using the arrow keys. As a vim/emacs user this becomes a bit of a clumsy non-ergonomic movement, here are some shortcuts to help you keep your fingers on the home row. If you are an emacs user these are going to look familiar.

  • ctrl-p - previous command entered
  • ctrl-n - next command entered
  • ctrl-a - jump to BOL
  • ctrl-e - jump to EOL
  • alt-b - jump word forward
  • alt-f - jump word backwards
  • alt-b - jump character forward
  • alt-f - jump character backwards

If these shortcuts don’t work try running set -o emacs

Alternatively you can turn on vi mode in your shell by calling set -o vi, which you can add to your .zshrc or add set editing-mode vi to your .inputrc. After setting this you can enter normal mode by hitting escape and use vi motions to edit/move.

Your shell just got upgraded. 💪💻

Use `watch` to monitor status commands in bash

If you need to monitor a status command such as monit status or service nginx status, instead of calling the command over and over use the watch command:

watch monit status

by default it will refresh the status every 2 seconds and highlight changes as they occur. You can modify the interval by using the -n switch:

watch -n 1 monit status

If your status command uses color you can turn it on by using the -c switch.

P.S. If you need to run this command on mac you will need to install the watch package using homebrew.

Use bash's Bang command to improve productivity

Bash has neat way to repeat last ran command. In your shell type !! this will put the last ran command in your prompt and allow you to edit and execute it. Use it to add sudo to any command:

$ apt-get install somepackage
Insufficient permissions
$ sudo !!
$ sudo apt-get install somepackage

If you want to go back to a specific command other than the last you have a few options:

You can execute a history command by its ID (to see all IDs run history, to clean history history -c)

$ history
1234 some really long command
1236 third command
$ !1234
$ some really long command
$!-2 # run two commands ago (not including bang commands)
$ history

You can run the last command containing a specific string:

$ foo bar
$ bar foo bazz
$ !foo # last command starting with foo
$ foo bar
$ !?bazz # last command containing the word bazz
$ bar foo bazz

Reuse last/first argument:

$ ls -la /development/reallylongnameidontwanttoretype
$ cd !$
$ cd -la /development/reallylongnameidontwanttoretype
$ $^ app
$ cd app

Best practice for event binding in JavaScript

When binding an event to a DOM element you often need a way to update your event in runtime. This presents a challenge because setting the new event will not override the existing one but instead create an additional event. In that case you need to namespace (jQuery terminology) your event which will allow you to replace it.

Problem:

$(window).on('scroll', function () { console.log('A') });

// Scroll output: 
// => A
// => A

$(window).on('scroll', function () { console.log('B') });

// Scroll output: 
// => A
// => B
// => A
// => B

Solution:

$(window).off('scroll.myPlugin').on('scroll.myPlugin', function () { console.log('A') });
$(window).off('scroll.myPlugin').on('scroll.myPlugin', function () { console.log('B') });

// Scroll output: 
// => B
// => B

Vanilla JS - when using the addEventListener use named functions (instead of anonymous..). It may be a good idea to keep an array of your event handlers in your object tree.

Solution:

var scrollHandler = function() { console.log('A') };
var scrollHandler2 = function() { console.log('B') };
window.addEventListener('scroll', scrollHandler);
window.removeEventListener('scroll', scrollHandler);
window.addEventListener('scroll', scrollHandler2);

// Scroll output: 
// => B
// => B

This is especially important when writing your own libraries to avoid collisions with user events.

ActiveRecord Dirty module

Rails provides a way to check if your model’s attributes have changed since initially loading it from database. It also provides convenient methods for checking what the values were before the change using #{attribute_name}_was as in the example below.

# A newly instantiated object is unchanged:
person = Person.find_by_name('Uncle Bob')
person.changed?       # => false
  
# Change the name:
person.name = 'Bob'
person.changed?       # => true
person.name_changed?  # => true
person.name_was       # => 'Uncle Bob'
person.name_change    # => ['Uncle Bob', 'Bob']
person.name = 'Bill'
person.name_change    # => ['Uncle Bob', 'Bill']
  
# Save the changes:
person.save
person.changed?       # => false
person.name_changed?  # => false

# Assigning the same value leaves the attribute unchanged:
person.name = 'Bill'
person.name_changed?  # => false
person.name_change    # => nil
  
# Which attributes have changed?
person.name = 'Bob'
person.changed        # => ['name']
person.changes        # => { 'name' => ['Bill', 'Bob'] }

RSpec multiple formats with different out buffers

On RSpec there is a way to use multiple formatters from the command line and pipe each into a different output buffer (file/stdout).

To do this use rspec -f p -f j --out result.json spec

-f is alias for --format which takes the arguments

[p]rogress (default - dots)
[d]ocumentation (group and example names)
[h]tml
[j]son

--out will save the last formatter mentioned to a file.

The original formatter will print to $stdout so you end up having the normal display from RSpec and a JSON file which you can use to parse with your own script.