views:

385

answers:

6

Example bad:

#main {
      padding:0;
      margin: 10px auto;
}

Example good:

#main {padding:0;margin:10px auto;}

I have a ton of CSS rules that are taking up too many lines. And I cannot figure out the :%s/ commands to use.

+4  A: 

Try something like this:

:%s/{\n/{/g
:%s/;\n/;/g
:%s/{\s+/{/g
:%s/;\s+/;/g

This removes the newlines after opening braces and semicolons ('{' and ';') and then removes the extra whitespace between the concatenated lines.

Lucas Oman
+10  A: 

If you are at the beginning or end of the rule, V%J will join it into a single line:

  • Go to the opening (or closing) brace
  • Hit V to enter visual mode
  • Hit % to match the other brace, selecting the whole rule
  • Hit J to join the lines
sth
+1, this is `vi` way.
Michael Krelin - hacker
this is not the *vi* way, it's the *vim* way
soulmerge
Thanks, this is really cool. Now I understand visual mode a little better.
mager
Well, soulmerge, first I wanted to say `vim` way, but then it *is* a `vi` way even if this particular command is not compatible with plain `vi` (I'm not even sure it isn't).
Michael Krelin - hacker
It's not compatible with plain `vi`. But the question is tagged as `vim` and I guess the vast majority of people normally use `vim`, so the answer should be useful.
sth
This only fixes one block at a time, though. Using :%s would fix the entire file.
Lucas Oman
sth, true, I failed to find plain vi anywhere around to check what exactly won't work there. ;-)
Michael Krelin - hacker
vi doesn't have Vim's visual mode (as noted in `:help visual`). What vi called visual mode was just another name for normal mode.
jamessan
A: 

Go to the first line of the file, and use the command gqG to run the whole file through the formatter. Assuming runs of nonempty lines should be collapsed in the whole file.

kaizer.se
+12  A: 

Here's a one-liner:

:%s/{\_.\{-}}/\=substitute(submatch(0), '\n', '', 'g')/

\_. matches any character, including a newline, and \{-} is the non-greedy version of *, so {\_.\{-}} matches everything between a matching pair of curly braces, inclusive.

The \= allows you to substitute the result of a vim expression, which we here use to strip out all the newlines '\n' from the matched text (in submatch(0)) using the substitute() function.

The inverse (converting the one-line version to multi-line) can also be done as a one liner:

:%s/{\_.\{-}}/\=substitute(submatch(0), '[{;]', '\0\r', 'g')/
rampion
Thanks a lot. This is awesome.Conversely, how would you convert a bunch of one-line CSS rules into the multiple line format?
mager
Luc Hermitte
wish I could upvote more than once!
Vijay Dev
+4  A: 

If you want to change the file, go for rampion's solution.

If you don't want (or can't) change the file, you can play with a custom folding as it permits to choose what and how to display the folded text. For instance:

" {rtp}/fold/css-fold.vim
" [-- local settings --]               {{{1
setlocal foldexpr=CssFold(v:lnum)
setlocal foldtext=CssFoldText()

let b:width1 = 20
let b:width2 = 15

nnoremap <buffer> + :let b:width2+=1<cr><c-l>
nnoremap <buffer> - :let b:width2-=1<cr><c-l>

" [-- global definitions --]           {{{1
if exists('*CssFold')
  setlocal foldmethod=expr
  " finish
endif

function! CssFold(lnum)
  let cline = getline(a:lnum)
  if     cline =~ '{\s*$'
      return 'a1'
  elseif cline =~ '}\s*$'
      return 's1'
  else
      return '='
  endif
endfunction

function! s:Complete(txt, width)
  let length = strlen(a:txt)
  if length > a:width
      return a:txt
  endif
  return a:txt . repeat(' ', a:width - length)
endfunction

function! CssFoldText()
  let lnum = v:foldstart
  let txt = s:Complete(getline(lnum), b:width1)
  let lnum += 1
  while lnum < v:foldend
      let add = s:Complete(substitute(getline(lnum), '^\s*\(\S\+\)\s*:\s*\(.\{-}\)\s*;\s*$', '\1: \2;', ''), b:width2)
      if add !~ '^\s*$'
          let txt .= ' ' . add
      endif

      let lnum += 1
  endwhile
  return txt. '}'
endfunction

I leave the sorting of the fields as exercise. Hint: get all the lines between v:foldstart+1 and v:voldend in a List, sort the list, build the string, and that's all.

Luc Hermitte
+3  A: 

I won't answer the question directly, but instead I suggest you to reconsider your needs. I think that your "bad" example is in fact the better one. It is more readable, easier to reason about and modify. Good indentation is very important not only when it comes to programming languages, but also in CSS and HTML.

You mention that CSS rules are "taking up too many lines". If you are worried about file size you should consider using CSS/JS minifier like YUI Compressor instead of making the code less readable.

Adam Byrtek