Search and Replace with incremented values in Vim - vim

Lets say I wrote a simple CSS rule like this:
.star_10 {
background: url(stars.png) no-repeat 0 0;
}
And I need 10, so I copied it 9 times.
.star_10 {
background: url(stars.png) no-repeat 0 0;
}
.star_10 {
background: url(stars.png) no-repeat 0 0;
}
.star_10 {
background: url(stars.png) no-repeat 0 0;
}
.star_10 {
background: url(stars.png) no-repeat 0 0;
}
.star_10 {
background: url(stars.png) no-repeat 0 0;
}
etc.
Now I want to change the star_10 and 0 0 with incremented values so it looks like this:
.star_10 {
background: url(stars.png) no-repeat 0 0;
}
.star_9 {
background: url(stars.png) no-repeat 0 -18px;
}
.star_8 {
background: url(stars.png) no-repeat 0 -36px;
}
.star_7 {
background: url(stars.png) no-repeat 0 -54px;
}
and so on...
So how can I search/replace every instance, do a calculation and write it?

You can do it easily with a macro. Lets say you have only this:
.star_10 {
background: url(stars.png) no-repeat 0 0;
}
Place your cursor over the first dot (in .star10) and type the following in normal mode:
qa3yy3jp^Xjt;18^Xk0q
Explaining:
qa will start a macro recording in register "a".
3yy will yank (copy) the following 3 lines.
3j will place the cursor 3 lines down.
p will paste the past yanked text.
^X (ctrl+x) will decrement the star class number.
j will place your cursor one line down.
t; will place your cursor before the next ; in the current line.
18^X will decrement the y coordinate of backround by 18;
k will put the cursor one line up,
0 will put the cursor at the beggining of the line.
q will finish the macro recording.
After that, you may have something like this.
.star_10 {
background: url(stars.png) no-repeat 0 0;
}
.star_9 {
background: url(stars.png) no-repeat 0 -18;
}
That's it. Just place your cursor at the dot on .star_9 and press 8#a to execute the macro recorded in register a eight more times.

You can use the s/pattern/replace construct with the \= symbol in order to evaluate a function or expression, as shown:
Decrementing the .star_10:
let g:decr = 11
fu! Decr()
let g:decr = g:decr - 1
return g:decr
endfu
:%s/.star_10/\=".star_" . Decr()/
Similarly, you'd do
let g:decr_18 = 18
fu! Decr18()
let g:decr_18 = g:decr_18 - 18
return g:decr_18
endfu
and then replace the 0 0; with a
:%s/no-repeat 0 0;/\="no-repeat 0 " . Decr18() . "px"/
For both functions, a (global) variable is declared that is manipulated within the functions and returned. The functin itself is called for every line matching the pattern. the pattern is substituted with the expression following the \=.

You could probably write a function for this, but I usually do something simpler. I use a key macro involving the ^A and ^X keys (increment and decrement a number). Use qa to start recording, do your stuff, using those keys with count modifiers (e.g 18^X), and just do say, 10# afterwards.

I needed this solution but also with leading zero support. My use of the original question is more like Example 1 than what Example 2 (this was the original example).
I created a function called SearchIncr() (search, replace, and increment).
There are four required arguments: target_string, replacement_string, start_value, increment_value.
There are also two optional arguments: leading_zeros, position
leading_zeros is a positive integer value, and position is 'before' or 'after'. See example 2.
Example 1
:'<,'>call SearchIncr("0 0","new",1,5,8)
If the file looks like this:
what 0 0 post
areu 0 0 post
doin 0 0 post
You will then get:
what new00000001 post
areu new00000006 post
doin new00000011 post
Example 2
:'<,'>call SearchIncr("0;","px;",-18,-18,0,'after')
If the file looks like this:
.star_10 {
background: url(stars.png) no-repeat 0 0;
}
.star_10 {
background: url(stars.png) no-repeat 0 0;
}
.star_10 {
background: url(stars.png) no-repeat 0 0;
}
You will then get:
.star_10 {
background: url(stars.png) no-repeat 0 -18px;
}
.star_10 {
background: url(stars.png) no-repeat 0 -36px;
}
.star_10 {
background: url(stars.png) no-repeat 0 -54px;
}
The vimscript is here:
" place functions here
function! SearchIncr(a1,a2,a3,a4,...)
" patn, repl, start, increment
let target = a:a1
let repl = a:a2
let startval = a:a3
let increment = a:a4
" 1st optional argument handles leading zeros
" process optional leading zero
if a:0 >= 1
let leadingz = a:1
else
" default to 0
let leadingz = 0
endif
" 2nd optional argument handles if target string goes before or after
" default is before
if a:0 == 2
" ideally set to 'after'
let repl_pos = a:2
else
let repl_pos = 'before'
endif
" inits
let l:incr = startval - increment
let lnum = a:firstline
" cycle though selection
while lnum <= a:lastline
" the FORMATTING string
if repl_pos == 'before'
let l:incrstring = '\=printf(''%s%0'. leadingz . 'd'',repl,l:incr)'
elseif repl_pos == 'after'
let l:incrstring = '\=printf(''%0'. leadingz . 'd%s'',l:incr,repl)'
else
"default to no leading zero and before placement
let l:incrstring = '\=printf(''%s%0d'',repl,l:incr)'
endif
" only increment counter when target matches
if match(getline(lnum),target) > 0
let l:incr = l:incr + increment
endif
" the search and replace
call setline(lnum,substitute(getline(lnum),target,
\ l:incrstring,'g'))
let lnum = lnum + 1
endwhile
endfunction
Any comments to improve on the above would be greatly appreciated!

Just using pure vim resources, no scripting:
:let c=10 | g/_\zs\d\+\ze/ s//\=c/ | let c-=1
:let c=0 | g/no-repeat 0 \zs\d\+/ s//\=c/ | let c-=18

Related

SCSS linear gradient effect

I have many spans that are one next to each other and I'd like to add some linear-gradient effect - so the first one has background-color: $a, the last one background-color: $b and the spans between the "transition color from $a to $b". If I'm not making any sense, this image will help you:
I tried with lighten(), but it only uses one color.
Here's the current SCSS:
$starting_color: #177DEF;
$ending_color: #2FF0D5;
$elements: 51;
#for $i from 0 to $elements {
span:nth-child(#{$i}) {
height: random(260) + px;
background-color: lighten($starting_color, $i);
}
}
Whole fiddle on Codepen
How can I create this "effect"? Possible with some step parameter (step count = all spans)
This is quite lengthy, but it works:
//$blue: #177DEF;
$firstR: 23;
$firstG: 239;
$firstB: 125;
$blue: rgb(23, 125, 239);
//$green: #2FF0D5;
$secondR: 47;
$secondG: 240;
$secondB: 213;
$green: rgb(47, 240, 213);
body{
background-color: #000;
}
#panel {
font-size: 0;
}
span {
font-size: 16px;
display: inline-block;
vertical-align: bottom;
width: 10px;
&:not(:first-of-type) {
margin-left: 2px;
}
}
$elements: 51;
$redDiv: ($firstR - $secondR) / $elements;
#if $redDiv < 0 {
$redDiv: $redDiv * -1
}
$greenDiv: ($firstG - $secondG) / $elements;
#if $greenDiv < 0 {
$greenDiv: $greenDiv * -1
}
$blueDiv: ($firstB - $secondB) / $elements;
#if $blueDiv < 0 {
$blueDiv: $blueDiv * -1
}
#for $i from 0 to $elements {
$redValue: $redDiv * $i;
$greenValue: $greenDiv * $i;
$blueValue: $blueDiv * $i;
span:nth-child(#{$i}) {
height: random(260) + px;
background-color: rgb($firstR + $redValue, $firstG + $greenValue, $firstB + $blueValue);
}
}
I converted the hexadecimal values to RGB here, then made separate variables for each red, green, blue value in both colors.
Subtract the second value from the first then divide by how many elements (this gives you the amount of change needed each iteration).
Make sure the values aren't negative with #if.
Calculate the change by multiplying by $i and then add/subtract that change depending upon which value was lesser (first or second). If first value is less then $first + $value, if second value is less then $first - $value.
This was the only part that needs to be changed depending on the colors, the rest will work for any RGB value.
Codepen: http://codepen.io/anon/pen/ezpmXJ

jade - using if statement

I want to get following if condition in jade.
each item,count in display
if(count % 3 === 0)
{
ul.thumbnails
}
li.span6 //nested under ul
//more code nested under li
I googled searched a lot, but with no luck.
Basically, I want to make a new list for every count which is divisible by 3
I tried this:
mixin display_list
li
//code
each item,count in display
-if(count === 0 )
ul.thumbnails
mixin display_list
-else
mixin display_list
It still doesn't work!
Since Jade forces you to indent stuff that is nested, I think the only way (not sure, but it's certainly the most straightforward) is to do it like this:
- var i = 0;
- while(i < display.length)
ul.thumbnails
- var k = i + 3
- while(i < k && i < display.length) // Will repeat three times, unless display.length isn't large enough
li.span6 //nested under ul
//more code nested under li
- i++
Assuming display is an array
(This answer has been updated, the former answer was completely wrong)
Update 2: Fixed that k could be greater than display.length
I found a way but I don't think it is the correct way to do it.
a = [1,2,3,4,54,6,7,8,9,4,5]
each item, i in a
if i % 2 == 0
|<ul>
li #{item}
if (i+1) % 2 == 0
|</ul>

Make Rows with large data set in Jade Templating in Node.js

I have about 100 items that I use jade iteration to write each one of them to html. However, I'm struggling to find an elegant way to separate the items into rows of three.
To be clear, I want something like this:
.row
.item1
.item2
.item3
.row
.item1
... and so on...
I've tried things with inline javascript like this with no luck:
- var a = 0;
each item in list
- a++;
- if(a % 3 == 0)
.row-fluid
.span3(id='#{item.id}')
p #{item.id}
- else
.span3(id='#{item.id}')
p #{item.id}
note: this kills the list
while list.length > 0
.row
for item in list.splice(0, 3)
.span3(id=item.id)
p= item.id
let me know if this works as i just wrote it off the top of my head
- var i = -3;
while i <= list.length
- i += 3;
.row
each item in list.slice(i, i+3)
.span3(id='#{item.id}')

How my character stays near a block?

I have a problem with block/wall detection:
red = character
green = block/wall
Attempt: When my character touches e.g. a block/wall on the left side it should stay on the left side.
int len = blocks.size();
for (int b = 0; b < len; b++) {
Block block = block.get(i);
Rectangle r1 = red.bounds;
Rectangle r2 = block.bounds;
if((r1.lowerLeft.y + r1.height/2) > (r2.lowerLeft.y - r2.height/2)) {
...
}
if((r1.lowerLeft.y - r1.height/2) < (r2.lowerLeft.y + r2.height/2)) {
...
}
if((r1.lowerLeft.x + r1.width/2) > (r2.lowerLeft.x - r2.width/2)) {
...
}
if((r1.lowerLeft.x - r1.width/2) < (r2.lowerLeft.x + r2.width/2)) {
...
}
}
It seems as if you just had to mingle the code.
Your condition to find out if its on the top then computes what had to be done if it was on the bottom. Just exchange the code inside the conditions and you're good to go, i guess!

Flot Data Labels

I'm trying to produce a line chart using Flot, but I want the data labels to show up on the chart - meaning, I want the value of each point to appear next to that point. I feel like this should be an option, but can't find it in the API. Am I just missing something, or does someone know a workaround?
Thanks in advance.
Here is how I added the feature, including a pleasant animation effect:
var p = $.plot(...);
$.each(p.getData()[0].data, function(i, el){
var o = p.pointOffset({x: el[0], y: el[1]});
$('<div class="data-point-label">' + el[1] + '</div>').css( {
position: 'absolute',
left: o.left + 4,
top: o.top - 43,
display: 'none'
}).appendTo(p.getPlaceholder()).fadeIn('slow');
});
You can move the position and display css to a stylesheet.
The feature you want is requested here in the Flot Google group. It doesn't look like it was ever implemented (there's nothing in the API about putting any labels inside the chart itself). I think that the answer to your question is that No, it's not possible at this time to show values next to certain points on lines inside the graph.
Ole Larson, head developer on Flot, mentioned that showing labels inside the chart is different than anything else on FLot and that they would have to think about how to extend the API / plot parameters to do it.
That said, you might want to go post a question on the Flot forum or make a suggestion on the bug-tracker for the new feature. Ole Larson is actually really good at getting back to all the questions, bugs, and suggestions himself.
If anyone else is looking for a quick solution, see this plugin:
http://sites.google.com/site/petrsstuff/projects/flotvallab
Looks like the flot-valuelabels plugin is a fork of a previous flot plugin -- but the forked code renders the labels on the canvas. You can see a demo of what this looks like on the plugin's Github wiki page, here (it looks quite pleasing to the eye).
function redrawplot() {
$('.tt1').remove();
var points = plot.getData();
var graphx = $('#placeholder').offset().left;
graphx = graphx + 30; // replace with offset of canvas on graph
var graphy = $('#placeholder').offset().top;
graphy = graphy + 10; // how low you want the label to hang underneath the point
for(var k = 0; k < points.length; k++){
for(var m = 1; m < points[k].data.length-1; m++){
if(points[k].data[m][0] != null && points[k].data[m][1] != null){
if ((points[k].data[m-1][1] < points[k].data[m][1] && points[k].data[m][1] > points[k].data[m+1][1]) && (points[k].data[m-1][1] - points[k].data[m][1] < -50 || points[k].data[m][1] - points[k].data[m+1][1] > 50)) {
showTooltip1(graphx + points[k].xaxis.p2c(points[k].data[m][0]) - 15, graphy + points[k].yaxis.p2c(points[k].data[m][1]) - 35,points[k].data[m][1], points[k].color);
}
if ((points[k].data[m-1][1] > points[k].data[m][1] && points[k].data[m][1] < points[k].data[m+1][1]) && (points[k].data[m-1][1] - points[k].data[m][1] > 50 || points[k].data[m][1] - points[k].data[m+1][1] < -50)) {
showTooltip1(graphx + points[k].xaxis.p2c(points[k].data[m][0]) - 15, graphy + points[k].yaxis.p2c(points[k].data[m][1]) + 2,points[k].data[m][1], points[k].color);
}
}
}
}
}
function showTooltip1(x,y,contents, colour){
$('<div class=tt1 id="value">' + contents + '</div>').css( {
position: 'absolute',
display: 'none',
top: y,
left: x,
'border-style': 'solid',
'border-width': '2px',
'border-color': colour,
'border-radius': '5px',
'background-color': '#ffffff',
color: '#262626',
padding: '0px',
opacity: '1'
}).appendTo("body").fadeIn(200);
}

Resources