Saturday, December 19, 2009

Hacking IE6 With Sass Mixins

Just recently I was raging against Internet Explorer 6 and the hacks that are required to overcome its shitty css support when it occurred to me that Sass mixins could be used to abstract away some of these hacks.

Read this raving if you use sass and rage against having to support IE6.

Bill Gates is way more awesome than Hampton Catlin (at sucking)

Good morning class, let us begin today's lesson with some quotes.

Now, I ain't gay, but let it be known that Sass is so fucking awesome that I'd definitely suck Hampton Catlin's cock. For free!
Scrooloose - 12th Dec, 2009

Many of you may be offended by the above homo-erotic sentiments and view them as inappropriate, but let me ask you: if you call those sentiments "inappropriate" then what, pray tell, the fuck would you call these:

I love Bill Gates like I love decapitated parrot heads sprinkled on cornflakes with milk and sugar. If I met him on the street I'd kidnap him and drag him back to my secret torture lab, where I would inject a delightful cocktail of fire ants, piranhas, and ninja stars into his anus. Then, I'd don my strap-on cactus and proceed to stir said cocktail with extreme force. Following this, I would feed him — cock first — to the cult of homosexual-rapist-cannibals that I harbor in my basement.

Whoa! Hold on there, thats pretty brutal! Maybe I took that last part a bit too far?? OH WAIT NO I DIDN'T, FUCK YOU BILL!
Queen Elizabeth II (after failing to get her site running in IE)

I hold Bill personally responsible for the travesty of Internet Explorer 6. Not the browser itself mind you, but the fact that it is still widely used today, even though I was still in fucking high school when it was released!*

Having to support such a buggy and incomplete css implementation is enough to make any web developer shit his pants in protest.

Sass mixins to the rescue

I only looked into these the other day, and I wish I'd done it ages ago. Mixins are basically a way to reuse chunks of css.

Check out this example:

Here we create a mixin called "ultimate-hippy-border" which takes a "thickness" parameter. When the css file is compiled, the declarations inside the mixin are evaluated and inlined into the css rules that the mixin is used in.

Check out these links for more info about mixins.

You can see how we could use this to hide css hacks. Check out these examples:

There are several benefits to doing this.

The most obvious is that we no longer have these ugly-as-fuck hacks repeated all over our code. Instead, we are left with much more symbolic mixin code. The intent of +min_height_hack(10px) is much clearer than the 3 line hack we would otherwise inline. This makes things more concise, readable and DRY, which results in some erection-inducing maintainability.

I can haz a repo on github?

I've created a repo on github with the hacks that ive been using so far which, at the time of this writing, is nothing more that what's in the gist above. Not impressed? Here, check out this ballsack:

How you like me now?

If you're still not satisfied, then you'll have to fork me and add your own hacks.

* if you are one of the people that still uses IE6 and you are not clinically dead then please correct this situation immediately. Thank you.

Tuesday, October 20, 2009

Mainframe molestation with looksee

This morning when I walked into the server room, I must have looked real serious, because our mainframe took one look at me and ran for its fucking life! I took off after it, bolting across the office and down the back steps before I caught up with the bastard in the car park, trying to steal a scooter off some school kid. I slapped that bitch down, lifted its rear end up into the air, plugged my keyboard in from behind and started hacking.

I only had time for a quicky, and here's the result (from my .irbrc):

These hacks are built on this dynamite gem called looksee that gives you a function similar to the various methods functions that exist in the ruby core, except the output contains more information and is designed for human readability. Compare these 2 screenshots:

Without looksee

With looksee, and my hacks

I practically blew a load in my pants when I saw the output from looksee, since I've frequently been frustrated by the output of methods. However, the standard usage of looksee is

lp someobject, :some => 'options'

and I don't really want to memorize another function call.

Enter the above code, which intercepts calls to methods. If the call is made directly from irb, it is forwarded on to looksee, otherwise the original methods is called. This is handy as fuck when using irb for debugging and what not, but wont screw with code that uses the standard methods function.

Related stuff - a screencast demonstrating looksee (where I first heard about it)

Sunday, September 27, 2009

Vim pr0n: ignorecase fails

Fuck The Machine, lately the only thing I've been raging against is the ignorecase option.

In practice, the only use for ignorecase is to make vims regular expressions case insensitive when searching. However, for some reason, it also affects the == operator. Check this shit out:

:set noignorecase
:echo "foo" == "FOO"
:set ignorecase
:echo "foo" == "FOO"

What the fuck!? Good job team, you just made == ambiguous, and therefore completely useless.

This means script writers can't use == unless they explicity set the ignorecase option first, otherwise they don't know how their code will behave. Since that would be retarded, we should all stop using == and start using ==# or ==?, which is exactly what I've done.

But wait! Theres more! ignorecase also changes the behaviour of these comparison operators too:

Who the fuck made this decision?! I have no idea, but Id like 5 minutes alone with that bitch so I could stab them in the face! Multiple times! WITH MY FUCKING RECTUM.

Just ask yourself: if you download someones vim script, is it really in your best interests to change how every single comparison operator in that script functions?

In my massively non-humble opinion, ignorecase should not affect any of the basic comparison operators, only specializations of those operators.


Monday, July 6, 2009

Vim pr0n: Combating long lines

The other day my boss found me locked in the server room, naked and bathing myself with dish washing liquid and toilet water. When he asked what in the flying fuck I was playing at, I told him my soul was filthy and corrupt from all the long lines I'd been committing. In reply he told me I'd better sack up and write some vimscript hacks to keep my long lines under control. So that's what I did. Later that afternoon I was so happy I proposed to my boss and we lived happily ever after.

Read this raving if long lines bug you like a colony of fire ants assaulting your prostate.

Note: this raving assumes a fair amount of knowledge about statuslines in vim. If you aren't pro at statuslines then you should read this raving first.

Reporting long lines on the statusline

I've found it quite useful to have flags on my statusline that appear when a buffer is in an undesirable state; e.g. if the file format or encoding is wrong, or there are syntax errors, or mixed indenting etc. Ive recently coded a warning for long lines into my statusline. Check out this screenshot:

Notice the [#141,m82,$162] on the statusline. This is telling us that the buffer has 141 long lines, where the median length of these lines is 82 chars and the longest is 162 chars. This notice only appears when there is at least one line that is longer than &textwidth (typically 80).

That may seem like an excessive amount of information, but when I first coded a statusline warning, I only included the length of the longest line. This turned out to be insufficient since its common for a file to have one or two crazy long lines that are acceptable or troublesome to avoid. I could have only shown the number of long lines, but then I'd be left wondering how long they were; hence the median and longest line stats. Besides, more stats means more code behind my statusline, which makes it more likely the mother fucker will become sentient and hunt down Jamis Buck.

Here's the code from my vimrc:

 1 "....
 2 set statusline+=%{StatuslineLongLineWarning()}
 3 "....
 5 "recalculate the long line warning when idle and after saving
 6 autocmd cursorhold,bufwritepost * unlet! b:statusline_long_line_warning
 8 "return a warning for "long lines" where "long" is either &textwidth or 80 (if
 9 "no &textwidth is set)
10 "
11 "return '' if no long lines
12 "return '[#x,my,$z] if long lines are found, were x is the number of long
13 "lines, y is the median length of the long lines and z is the length of the
14 "longest line
15 function! StatuslineLongLineWarning()
16     if !exists("b:statusline_long_line_warning")
17         let long_line_lens = s:LongLines()
19         if len(long_line_lens) > 0
20             let b:statusline_long_line_warning = "[" .
21                         \ '#' . len(long_line_lens) . "," .
22                         \ 'm' . s:Median(long_line_lens) . "," .
23                         \ '$' . max(long_line_lens) . "]"
24         else
25             let b:statusline_long_line_warning = ""
26         endif
27     endif
28     return b:statusline_long_line_warning
29 endfunction
31 "return a list containing the lengths of the long lines in this buffer
32 function! s:LongLines()
33     let threshold = (&tw ? &tw : 80)
34     let spaces = repeat(" ", &ts)
36     let long_line_lens = []
38     let i = 1
39     while i <= line("$")
40         let len = strlen(substitute(getline(i), '\t', spaces, 'g'))
41         if len > threshold
42             call add(long_line_lens, len)
43         endif
44         let i += 1
45     endwhile
47     return long_line_lens
48 endfunction
50 "find the median of the given array of numbers
51 function! s:Median(nums)
52     let nums = sort(a:nums)
53     let l = len(nums)
55     if l % 2 == 1
56         let i = (l-1) / 2
57         return nums[i]
58     else
59         return (nums[l/2] + nums[(l/2)-1]) / 2
60     endif
61 endfunction

Crikey dick that's a lot of code! Lets run through it.

The StatuslineLongLineWarning() function constructs and caches the flag that will appear on the statusline. The flag will be an empty string if there aren't any long lines.

The hard work is actually delegated off to the LongLines() and Median() functions. LongLines() examines every line in the buffer and returns an array containing the lengths of the long lines, where "long" is determined by the users &textwidth setting (defaulting to 80 if &textwidth is set to 0). Note that LongLines() converts tabs into spaces according to the users &tabstop setting. Median() calculates the median of a given array of numbers.

Line 2 puts the flag onto the statusline and should appear with the rest of your statusline setup code.

Line 6 clears the cached flag every time the user is idle or saves the file, thus causing the flag to be recalculated.

Highlighting the offending parts of long lines

 1 "define :HighlightLongLines command to highlight the offending parts of
 2 "lines that are longer than the specified length (defaulting to 80)
 3 command! -nargs=? HighlightLongLines call s:HighlightLongLines('<args>')
 4 function! s:HighlightLongLines(width)
 5     let targetWidth = a:width != '' ? a:width : 79
 6     if targetWidth > 0
 7         exec 'match Todo /\%>' . (targetWidth) . 'v/'
 8     else
 9         echomsg "Usage: HighlightLongLines [natural number]"
10     endif
11 endfunction

I stole line 7 above from this vim tip and wrapped it up in a the HighlightLongLines command above. When invoked, the command highlights the "long" parts of long lines. Ive found this command pretty handy when embarking on anti long line crusades.

I'd highly recommend reading that vim tip for more code to highlight long lines. Theres some pretty dynamite stuff there.


Long lines suck, here's what Abe had to say about the matter:

Peppering your code with long lines is highly recommended; right up there with "strolling into church with an entourage of scantly clad, chronically obese prostitutes" and "licking the testicles of senile old men who are not fully in control of their bladders".

Abraham Lincoln, 1862


Use the relatively passive vim script hacks above to make vim bitch at you and steer you away from using long lines. If you want a more aggressive solution, then check out the aforementioned vim tip.

Sunday, June 21, 2009

Vim pr0n: Syntax checking on the go

A couple of days ago I was in the office, hacking the mainframe with The Great Halorgium. We got to talking about our current vim setup when he told me that it would be awesome if the statusline displayed a warning flag for buffers with syntax errors.

By the end of the day we'd written a couple of ftplugins to do just that for ruby and eruby. Read this raving to find out how.

Note: although we have only done it for ruby and eruby (at the time of this writing), you could easily do the same for other syntaxes using the same technique, provided there is a command line syntax checker for that language.

Note: this raving assumes a fair amount of knowledge about statuslines in vim. If you aren't pro at statuslines then you should read this raving first.

The end result

Here is a screenshot showing the code in action:

Notice the [syntax:4] on the statusline. After this buffer was saved, our code ran it through a syntax checker which told us there was a syntax error on line 4 ZOMG! (actually its a missing bracket on line 3).

The code

Here is the code to accomplish this for the ruby filetype. It was pulled from my ~/.vim/ftplugin/ruby_stl_syntax_warning.vim.

Update (8/july/09): I've recently refactored the living shit out of this code, which has made it much simpler, and has removed much of the duplication between the syntax checkers. See my vimfiles repo for the latest hacks. Look in my vimrc (search for "syntax") and in the syntax_checkers directory.

Update (25/july/09): OK, I went completely insane and made it into a plugin with some more features, check it out here

 1 if exists("b:did_ruby_stl_syntax_warning_ftplugin") || &filetype !~ '\<ruby\>'
 2     finish
 3 endif
 4 let b:did_ruby_stl_syntax_warning_ftplugin = 1
 6 "bail if the user doesnt have ruby installed
 7 if !executable("ruby")
 8     finish
 9 endif
11 "inject the syntax warning into the statusline
12 let &l:statusline = substitute(&statusline, '\(%=\)',
13             \ '%#warningmsg#%{StatuslineRubySyntaxWarning()}%*\1', '')
15 "recalculate after saving
16 autocmd bufwritepost <buffer> unlet! b:statusline_ruby_syntax_warning
18 "run the buffer through ruby -c
19 "
20 "return '' if no syntax errors detected
21 "return '[syntax:xxx]' if errors are detected, where xxx is the line num of
22 "the first error
23 function! StatuslineRubySyntaxWarning()
24     if !exists("b:statusline_ruby_syntax_warning")
25         let b:statusline_ruby_syntax_warning = ''
26         if filereadable(expand("%"))
27             let output = system("ruby -c " . expand("%"))
28             if v:shell_error != 0
29                 let b:statusline_ruby_syntax_warning =
30                             \ '[syntax:'. s:ExtractErrorLine(output) . ']'
31             endif
32         endif
33     endif
34     return b:statusline_ruby_syntax_warning
35 endfunction
37 "extract the line num of the first syntax error for the given output
38 "from 'ruby -c'
39 function! s:ExtractErrorLine(error_msg)
40     return substitute(a:error_msg, '.\{-}:\(\d*\): syntax error,.*', '\1', '')
41 endfunction

Wow! Well I have a boner, how about you?

Lets dissect this:

Lines 1–4 contain the standard house keeping code to make sure we don't source the plugin more than once. The filetype check is needed since the eruby runtime I use sources some of the ruby runtime files, including this one.

Lines 6–9 ensure that the ruby binary is present, since we are going to use ruby -c to check the syntax.

Lines 12–13 inject the syntax warning into our statusline. We chose to put it just before the left/right alignment separator since we put buffer related info on the left and cursor related info on the right. If you don't have %= on your statusline then you'll have to put it somewhere else.

Lines 23–41 are where the party is at. The StatuslineRubySyntaxWarning() function works out what should be displayed on the statusline and caches the result in b:statusline_ruby_syntax_warning. The code shells out to ruby -c to check the syntax of the buffer, before parsing any resulting error messages and returning the statusline flag containing the line number of the first error.

Line 16 clears the cached flag every time the buffer is saved, causing the syntax to be rechecked.

The future

There are a few other filetypes that I may write syntax checkers for, like sass and haml. Php could be useful too. And bash. Fuck, a bash syntax checker could actually be really handy. Getting that horrid shit right is about as easy as jacking off while watching a bunch of kitties getting nailed to a post. Things like apache configs could be good too, instead of doing apache2 -t manually.

Ive also been thinking about using the :sign commands to flag syntax errors. This way we could put a symbol next to each line containing a syntax error.

Tuesday, February 3, 2009

Vim pr0n: Jamis Buck must die

Sometimes I see something online that makes me rage so hard I long for a nail gun and a sack of adorably cute kittens. Lately I've been seeing assloads of vimrc files with this in them:

map <leader>d :execute 'NERDTreeToggle ' . getcwd()<CR>

Awww, isn't that cute? BUT ITS WRONG!!!1

It all comes from this blog post. OMFG Jamis Buck, I will find you, and I will fuck you. Then I'm gonna shove my entire $12 keyboard into your anus and turn it sideways before I squash you into a fetal ball and use copious amounts of superglue to bind your hands to your ass, and your scrotum to your tonsils. Then I'll bowl you down a hill into a set of garbage cans and put the video on youtube.

The :NERDTreeToggle command defaults to the current working directory anyway. So, if you have the above line in your vimrc, delete it immediately and replace it with this:

nnoremap <leader>d :NERDTreeToggle<cr>