How to make all the attributions in the css selector into one line with vim? - css

Here is my css part of css file.
body{
width:1100px;
height:800px;
}
div.main{
margin:20px auto 0 auto;
background-color:#f7f7f7;
}
I want to rewrite it as below.
body{width:1100px;height:800px;}
div.main{margin:20px auto 0 auto;background-color:#f7f7f7;}
All attritutions and values rewritten as only one line,is there a smarty vim command to do the job?

One option would be
g/{/,/}/j
which breaks down as
g start a global command
{ search for {
,/}/ for each match, set a range up until the }
j join the range
Note that this might be to naïve as-is. This doesn't take into account nested brackets. You might first want to set a visual range to the textblock you like to change.

You could use the J or gJ (alternative that doesn't add spaces) commands. They can be run in visual mode to join all selected lines, or take a count.
Alternatively, the splitjoin.vim plugin provides specific support for css rules as you are asking. With the cursor over the first line of the css block, type gJ to join the whole block into a single line.
Either way, you may want/need to run a replace to remove leading spaces before joining - :s/^\s\+// before joining the lines.
EDIT: I guess a 'smarty' way to do this, and without using plugins, would be the following macro: vf}:s/^\s\+/^MgvgJ (the ^M means pressing the enter key - you may have to enter the macro manually to get this). Use it by putting the cursor at the beginning of the line at the top of the css rule you want to rewrite.

As #romainl said, you should use a minifier. However I am going to assume what you really want is a way to glance at your css rules quickly. If that is the case then I suggest you look into folding. #Luc Hermitte gave a great answer on this subject on the post: Using vi, how can I make CSS rules into one liners?
Below is a variant of #Luc Hermitte answer. Put the following in ~/.vim/ftplugin/css_fold.vim:
let b:width = 25
" Use the following mappings to adjust the foldtext "columns"
nnoremap <silent> <buffer> >s :<c-u>let b:width+=v:count1<cr><c-l>
nnoremap <silent> <buffer> <s :<c-u>let b:width-=v:count1<cr><c-l>
if !exists('*s:CssFoldText')
function! s:CssFoldText()
let line = printf("% *s {", -1*b:width, substitute(getline(v:foldstart), "{\s*$", "", ""))
let nnum = nextnonblank(v:foldstart + 1)
let lst = []
while nnum <= v:foldend
let line = line . " " . substitute(getline(nnum), "^\s*", "", "")
let nnum += 1
endwhile
return line
endfunction
map <SID>xx <SID>xx
let s:sid = substitute(maparg("<SID>xx"),'xx$','', '')
unmap <SID>xx
endif
exe "setlocal foldtext=" . s:sid . "CssFoldText()"
setlocal foldmethod=syntax
Now you can use folding commands like zM to close all folds, zR to open all folds, and za to toggle the current fold. Vimcasts has a nice screencast on this topic, How to fold.
For more information see:
:h folds
:h 'foldtext'
:h 'foldmethod'
:h za
:h zR
:h zM

Related

How to remove double qoutes in Objective-C

Let me introduce myself.
My name is Vladimir, C++ programmer, I am from Serbia. two weeks ago I have started to learn objective-C and it was fine until tonight.
Problem:
I cant remove double quotes from my NSLog output.
NSLog(#"The best singers:%#", list.best);
Strings are joined with componentsJoinedByString:#" and "
I would like to get something like this:
The best singers: Mickey and John.
But I get this:
The best singers: ("Mickey", and "John").
I cant remove comma (,) and parentheses either.
I have tried with "replaceOccurencesOfString" but with no success. It can remove any character except qoute and comma.
Also I have used -(NSString *)description method to return string.
You are getting the raw output from your list (which I assume is an array). You will have to do your own formatting to get this to display in the format that you want. You can achieve this by building your string by iterating through your array. Note that this probably isn't the most efficient nor the most robust way to achieve this.
NSMutableString *finalString = [NSMutableString string];
BOOL first = YES;
for (NSString *nameString in list) {
if (first) {
[finalString appendString:nameString];
first = NO;
} else {
[finalString appendString:[NSString stringWithFormat:#" and %#", nameString]];
}
}

Aptana Studio 3 - How can I change this command (regex replacement)

What i want to do:
edit the CSS command tidier to include a space/tab after the selctor: #myid{...} to be #myid {...}
the file I want to edit:
format_css_singleline.rb
command "Format CSS Single-line" do |cmd|
cmd.key_binding = "M1+M2+F"
cmd.output = :replace_selection
cmd.input = :selection
cmd.scope = "source.css"
cmd.invoke do |context|
code = $stdin.read
code.gsub!(/\n{3,}/im, "\n\n")
code.gsub!(/[ \t]+/im, " ")
code.gsub!(/(?m)([;:])\s+/im) {|match| "#{$1}" } //i've tried adding a space after the {$1} here
code.gsub!(/\s*}/im, "}")
code.gsub!(/\s*{\s*/im, "{")
code.gsub!(/[ \t]*,[ \t]*/im, ", ")
code.gsub!(/#import(.*?);/im) {|match| "#import#{$1};\n\n" }
code
end
end
Commands > CSS > Edit this Bundle. It will grab down a git clone of the original CSS bundle, then generate a project inside the app for you to customize. There you can customize that command's file. Then you'll probably want to edit the following line:
code.gsub!(/\s*{\s*/im, "{") to be code.gsub!(/\s*{\s*/im, " {").
That line is collapsing all space before and after { down to no space. The modification will leave a space ahead of it.

Where does $4 come from here?

This is in the first rule of Perl:
grammar : GRAMPROG
{
PL_parser->expect = XSTATE;
}
remember stmtseq
{
newPROG(block_end($3,$4));
$$ = 0;
}
How can $4 work when there're only 3 elements on the right side?
An embedded action (the code { PL_parser->expect = XSTATE; } which occurs in the middle of the rule) counts as an element. So there are 4 elements. $1 is the terminal GRAMPROG, $2 is the embedded action, $3 is the nonterminal remember, and $4 is the nonterminal stmtseq. (The value of $2 is whatever value is assigned to $$ inside the embedded action. Currently it would be garbage.)
Under the covers, yacc only really supports actions at the end of a production. So when you interleave an action { PL_parser->expect = XSTATE; } in the middle of a production, yacc (or whatever descendent you're using) pulls out the action and sticks it at the end of an empty rule as such:
grammar: GRAMPROG $$1 remember stmtmseq
{
newPROG(block_end($3, $4));
$$ = 0;
}
$$1:
{
PL_parser->expect = XSTATE;
}
(If your yacc variant support dumping the verbose grammar and you do that, you'll see a lot of $$1, $$2, etc. rules for actions.)
In this case the interleaved action doesn't actually assign anything to $$, but if it had, the grammar rule could have accessed the value as $2.

Using Vim, how can I make CSS rules into one liners?

I would like to come up with a Vim substitution command to turn multi-line CSS rules, like this one:
#main {
padding: 0;
margin: 10px auto;
}
into compacted single-line rules, like so:
#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.
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')/
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
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.
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.
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 modify and reason about. 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 and JS minifiers like YUI Compressor instead of making the code less readable.
A convenient way of doing this transformation is to run the following
short command:
:g/{/,/}/j
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.

Looping through and combining two files in UNIX

This should be simple for those of you who have some programming knowledge... Unfortunately I don't.
I'm trying to iterate through a text file of image captions and add them as title tags to an html file. The image captions file has 105 captions (each is separated by a carriage return) and the gallery file has blank alt tags on each a tag (set up like alt="#"). The order of the captions corresponds with the order of the images in the html file.
So in other words... the psuedo code would be: "Loop through every line in captions.txt and for every alt="#" inside the gallery.html file, replace the # with the corresponding caption."
I'm on a Mac so I'd like to use UNIX.
Any help is greatly appreciated!
Thanks,
Mike
If all the alt="#" are on separate lines, you can use ed:
{
while read cap
do echo "/alt=\"#\"/ s//alt=\"$cap\"/"
done < captions.txt
echo wq
} | ed gallery.html
This assumes none of your captions contain a slash.
There are many ways to accomplish this goal. awk is the classic text manipulation program. (Well, awk and sed, for different purposes, but sed won't help here.)
awk '
BEGIN {
caps = ARGV[1]
delete ARGV[1]
}
/#/ {
getline cap < caps
gsub("#", cap)
}
{ print }
' captions.txt gallery.html
You could put it into a script to avoid having to type it more than once. Just start a plain text file with "#!/usr/bin/awk -f", put the "BEGIN ... { print }" below it, and give the file execute permissions.
This translates trivially into most scripting languages. Perl:
#!/usr/bin/perl -p
BEGIN { open CAPS, shift }
if (/#/) {
chomp($cap = <CAPS>);
s/#/$cap/g;
}
Almost the same in Ruby:
#!/usr/bin/ruby
caps = IO.readlines(ARGV.shift).each {|s| s.chomp!}
while gets
$_.gsub!(/#/, caps.shift) if $_ =~ /#/
print
end
And Python:
#!/usr/bin/python
import sys
caps = [s.strip() for s in file(sys.argv[1]).readlines()]
for f in [file(s, 'r') for s in sys.argv[2:]] or [sys.stdin]:
for s in f:
if s.find('#') > 0: s = s.replace('#', caps.pop(0))
print s,

Categories

Resources