What is wrong with this simple vim function? - function

Please have a look to the below vim function which I written in my /.gvimrc file.
The function id for deleting the "n" number of last characters in each line from the range of lines specified by "start_line" and "end_line".
function RLNC (n, start_line, end_line)
execute . a:start_line . "," . a:end_line . "s/.\{" . a:n . "}$//"
endfunction
but when I make the same as a function and call it in the vim
:call RLNC(3, 128, 203)
This is the actual operation I am doing here
:start_line,end_lines/.\{n}$//
This is nothing but
:128,203s/.\{3}$//
Please help me to find what is going wrong..?
its is giving errors

The error is:
E15: Invalid expression: . a:start_line . "," . a:end_line . "s/.\{" . a:n . "}$//"
So, the first period is suspect. The :execute command takes (one or multiple) expressions. String concatenation via . is only done between strings, not at the beginning.
Just leave off the first .:
execute a:start_line . "," . a:end_line . "s/.\{" . a:n . "}$//"
The manual concatenation is tedious. Better use printf():
execute printf("%d,%ds/.\{%d}$//", a:start_line, a:end_line, a:n)
The next problem is that inside double quotes, the backslash must be escaped (doubled). Better use single quotes:
execute printf('%d,%ds/.\{%d}$//', a:start_line, a:end_line, a:n)
Finally, Vim has a special syntax to pass a range to a function. See :help function-range-example. You do not need to use this, but it makes the invocation more natural:
:128,203call RLNC(3)
However, I would probably go ahead and define a custom command wrapping the function.
:command! -range -nargs=1 RLNC call RLNC(<args>, <line1>, <line2>)
If your function isn't actually more complex, we can now inline this and get rid of the function altogether:
:command! -range -nargs=1 RLNC execute printf('%d,%ds/.\{%d}$//', <line1>, <line2>, <args>)
(Note that without a function, the last search pattern gets clobbered.)

Thank for your reply, I am new to vim function and all. So I don't know much about the ":command!" and all. So I put it as function in the /.gvimrc file like below :
function RLNC (start_line, end_line, n)
if (a:start_line <= a:end_line)
execute printf(':%d,%ds/.\{%d}$//', a:start_line, a:end_line, a:n)
else
execute printf('Start line %d is more than End line %d ', a:start_line, a:end_line)
endif
endfunction
and its working fine when I use the :call RLNC(128, 203, 3) in my gvim files.
Thanks You

Related

jq if value contains then append

This might not be the ideal way to approach this but I am working on bulk update of some Grafana dashboards. When the expr key contains value that includes something like "sum((rate" I want to append to the value another string. Is this even possible?
if (.dashboard.panels[].targets[].expr | contains("sum((rate")) then . += "TEST" end'
I've tried a few variations of then action and even removed the concatanation to see if I could get simple replace. But getting
jq: error: syntax error, unexpected end (Unix shell quoting issues?) at <top-level>, line 1:
You should be able to update-assign part of your objects:
.dashboard.panels[].targets[].expr |= if contains("sum((rate") then . + "TEST" else . end
It's also possible to do without the if conditional, by first selecting all the interesting paths and then modifying only them:
(.dashboard.panels[].targets[].expr | select(contains("sum((rate"))) += "TEST"
You always need an else branch. For readability you can also pull the target up front (otherwise . will match the previous context).
.dashboard.panels[].targets[].expr |=
if contains("sum((rate") then . + "TEST" else . end
Demo
.dashboard.panels[].targets[].expr |= . +
if contains("sum((rate") then "TEST" else "" end
Demo

remove comma in jsonpath template using bash

I have a JSON path template query.
oc get event jsonpath='{range .items[*]},{#.name}{","}{#.message}{","}{#.evenname}'{"\n"}{end}'> /tmp/test.csv
i'm redirecting it to csv.
name1,message of event one,eventname1
name2,message of,event,two,eventname2
name3,message of event three,eventname3
name4,message of, event four,eventname4
getting comma in a message from above output , i want to replace the comma with space for the second column(message) in the bash script.
Anyone has any thoughts on how can achieve this.
Expected result
name1,message of event one,eventname1
name2,message of event two,eventname2
name3,message of event three,eventname3
name4,message of event four,eventname4
Assuming you can change the field delimiter to a character known to not exist in the data (eg, |), you would now be generating:
name1|message of event one|eventname1
name2|message of,event,two|eventname2
name3|message of event three|eventname3
name4|message of, event four|eventname4
From here we can use sed to a) remove/replace , with <space> and then b) replace | with ,:
$ sed 's/[ ]*,[ ]*/,/g;s/,/ /g;s/|/,/g'
NOTE: the s/[ ]*,[ ]*/g is needed to address the additional requirement of stripping out repeating spaces (as would occur in line #4 if we replace , with <space>)
When applied to the data this generates:
name1,message of event one,eventname1
name2,message of event two,eventname2
name3,message of event three,eventname3
name4,message of event four,eventname4
Another option using awk (for OP's current data using the , as the field delimiter):
awk -F',' ' # input field delimiter = ","
{ x=$1"," # start new string as field #1 + ","
sep="" # initial separator = "" for fields 2 to (NF-1)
for (i=2;i<NF;i++) { # loop through fields 2 to (NF-1)
gsub(/^[ ]+|[ ]+$/,"",$i) # trim leading/trailing spaces
x=x sep $i # append current field to x along with sep
sep=" " # use " " as separator for rest of fields
}
printf "%s,%s\n", x, $NF # print "x" plus "," plus the last field (NF)
}'
When applied to the data this generates:
name1,message of event one,eventname1
name2,message of event two,eventname2
name3,message of event three,eventname3
name4,message of event four,eventname4

Can't pass filepath as function argument in vim

I have this function in my vimrc:
function! MyFunc(fl)
:!cat fl
" :!cat a:fl
" :!cat &fl
endfunction
command! -nargs=1 RunFunc :call MyFunc(<f-args>)
The problem is when I run :RunFunc ~/scripts/0-test in vim command, I get the error:
cat: f: No such file or directory
shell returned 1
I have looked at various websites like this, this, this, this and this, but none worked for me.
First, you don't need that colon in a scripting context:
function! MyFunc(fl)
!cat fl
endfunction
command! -nargs=1 RunFunc :call MyFunc(<f-args>)
Second, you can't pass an expressions like that. You need to concatenate the whole thing with :help :execute:
function! MyFunc(fl)
execute "!cat " .. fl
endfunction
command! -nargs=1 RunFunc :call MyFunc(<f-args>)
Third, function arguments are typed with a::
function! MyFunc(fl)
execute "!cat " .. a:fl
endfunction
command! -nargs=1 RunFunc :call MyFunc(<f-args>)
As for websites… they are useless. Vim comes with an exhaustive documentation that should be your first hit when stumbling on something and it just so happens that the user manual—which is mandatory reading—has a whole chapter on writing vimscript: :help usr_41.txt.

Strange interaction between print and the ternary conditional operator

Ran into a strange interaction between print and the ternary conditional operator that I don't understand. If we do...:
print 'foo, ' . (1 ? 'yes' : 'no') . ' bar';
...then we get the output...:
foo, yes bar
...as we would expect. However, if we do...:
print (1 ? 'yes' : 'no') . ' bar';
...then we just get the output...:
yes
Why isn't " bar" getting appended to the output in the second case?
Let's do it, but for real -- that is, with warnings on
perl -we'print (1 ? "yes" : "no") . " bar"'
It prints
print (...) interpreted as function at -e line 1.
Useless use of concatenation (.) or string in void context at -e line 1.
yes
(but no newline at the end)
So since (1 ? "yes" : "no") is taken as the argument list for the print function then the ternary is evaluated to yes and that is the argument for print and so that, alone, is printed. As this is a known "gotcha," which can easily be done in error, we are kindly given a warning for it.
Then the string " bar" is concatenated (to the return value of print which is 1), what is meaningless in void context, and for what we also get a warning.
One workaround is to prepend a +, forcing the interpretation of () as an expression
perl -we'print +(1 ? "yes" : "no") . " bar", "\n"'
Or, call the print as function properly, with full parenthesis
perl -we'print( (1 ? "yes" : "no") . " bar", "\n" )'
where I've added the newline in both cases.
See this post for a detailed discussion of a related example and precise documentation links.
If the first non-whitespace character after a function name is an opening parenthesis, then Perl will interpret that as the start of the function's parameter list and the matching closing parenthesis will be used as the end of the parameter list. This is one of the things that use warnings will tell you about.
The usual fix is to insert a + before the opening parenthesis.
$ perl -e "print (1 ? 'yes' : 'no') . ' bar'"
yes
$ perl -e "print +(1 ? 'yes' : 'no') . ' bar'"
yes bar

evaluating an expression to true in a if statement with Tcl

I'm having serious biggies trying to figure out how to evaluate an expression in a If statement using Tcl. This is what I have:
#!/bin/sh
#The next line executes wish - wherever it is \
exec wish "$0" "$#"
set apid "/var/run/apache2.pid"
set apsta [file exist $apid]
if { $apsta == 1 }
{
set result ":)"
}
else
{
set result ":("
}
label .status -text $result
pack .status
and this is what I get from the terminal:
# wan27
Error in startup script: wrong # args: no script following " $apsta == 1 " argument
while executing
"if { $apsta == 1 }"
(file "/usr/bin/wan27" line 9)
I'm just trying to output a happy smiley if Apache is running, a sad one if Apache is stopped - based upon the boolean condition whether or not the file "/var/run/apache2.pid" exists ...
The syntax of a Tcl if statement is
if condition statement else statement
which must be on one line. Braces allow continuation across lines and their placement is mandatory:
if { $apsta == 1 } {
set result ":)"
} else {
set result ":("
}
As you have it written, Tcl sees
if { $apsta == 1 }
and stops there yielding a syntax error.
MSW have already given you the correct answer but I think a little bit more explanation is needed to clear up some other confusions you are having based on your comments.
I will first explain things using non-tcl terminology since I think it is less confusing that way.
In tcl, if is not a statement. if is a function. That is the reason why the opening brace need to be on the same line: because a newline terminates the list of arguments to a function. For example, in the following code:
a b c d
e f
the Tcl interpreter will see two function calls. The first to function a with arguments b, c and d and the second to function e with a single argumrnt f. Similarly, in the following:
if a
b
Tcl sees a call to the function if with a single argument. Since if expects at least two arguments it (not the interpreter itself) throws an error complaining about wrong number of arguments.
This also explains why there must be a space between if and its first argument. It's just because in tcl names of variables and functions are literally allowed to contain almost anything including spaces, commas and non-printing characters like NUL. For example, you can define a function called a{b}:
proc a{b} {} {puts HA!}
a{b} ;# <-- prints out HA!
So if you do something like:
if{x} {y}
tcl will complain that the function if{x} is not defined.
if is not the only thing that works like this. Tcl doesn't really have keywords, just a standard library of built-in functions like for, foreach and while. The same rules apply to all of them.
not really important:
On a side, the if function in tcl works like the ternary operator in C: it returns a value. In fact you can do the following:
# It is unfortunate that this "give" function is not built in.
# We use it to return something from if without actually
# calling return:
proc give {x} {return $x}
set something [if {$x} {give "Very true indeed."} {give "Unfortunately false."}]