more syntax-aware navigation in vim - vim

I have a good amount of code which looks like this:
rule requestIntHoleTemplate {
constr:HoleCall;
y:PrimitiveIntRange;
:IntRangeHole(constr, y);
modify {
emit("Request template IntRangeHole\n");
}
}
I'd like to skip over the entire block in vim, not just to the next empty line as } does. I can accomplish it with $%, but that wouldn't work if I'm on an empty line preceding the block. I suppose I could alias }{j$%j. Are there other navigation commands I'm missing?
Thanks in advance.

You can use ]] and friends, but they only work if the opening brace is on its own line.
]] next beginning of block
[[ previous beginning of block
][ next end of block
[] previous end of block

Related

eslint enforce space after the single-line-if parentheses

I'm quite new to ESLint and I couldn't find a rule that does what I want. Consider the following code:
if(someCondition)i++;
I want to enforce a single space after the parentheses, so that we should have the following instead:
if(someCondition) i++;
However I simply couldn't find such a rule; it's not space-before-function-paren (obviously), keyword-spacing (which only affects the spacing after if) or space-before-blocks (since this is a single-line-if, there's no block). Please help. Thanks!
P.S. Same rule should apply to single-line-while as well.
https://github.com/eslint/eslint/discussions/15267#discussioncomment-1597748
I think we don't have that rule in the core.
keyword-spacing can disallow if (foo)return;, space-before-blocks can disallow if (foo){, but it seems that there is no rule that would disallow if (foo)bar; and enforce if (foo) bar;
Simple, but effective:
$ cat input
if (condition)i++;
if (condition)i--
while ( this ^ foo || bar )continue
for (true ||
true )z--
Naive solution, but probably ok.
$ cat input | busybox sed -e 's/)\([a-zA-Z_]\)/) \1/'
if (condition) i++;
if (condition) i--
while ( this ^ foo || bar ) continue
for (true ||
true ) z--
This will put a space between ) and the first letter of a variable name (a-z_).
Consider my answer here (and others') for tips on how to process all files that contain the undesired pattern:
https://unix.stackexchange.com/questions/675881/remove-trailing-spaces-from-text-files-only-when-necessary/676367#676367

perl script adds extra curly brackets

Following script, I'm using which performs everything well except it adds three extra curly brackets at the end of file.
abc.jso contains many lines where few lines have only opening/closing curly brackets (In case, this information helps)
I tried by making print $a " $var"; instead of print $a "$var";. In short I added space in front of this print & it worked.
open (my $a,'+<',"abc.jso") or die $!;
my #lines=<$a>;
seek $a,0,0;
while (#lines) {
my $var = shift #lines;
if ($var=~ /^\s*\"(netlist|filelist)\" : \".*$blk.*\",/) {
print $a " \"netlist\" : \"/t98/pnr/work/$blk"."_rk/run/dc/$blk"."_post_dft.v\",\n";
$count++;
print "Netlist got replaced\n";
}
elsif ($var=~ /^\s*\"spf\" : \".*$blk.*\"/) {
print $a " \"spf\" : \"/t98/scan/atpg/t98_1.0/spf/$blk".".scan_compress.spf\"\n";
$count++;
print "SPF got replaced\n";
}
else {
print $a "$var";
}
}
close($a);
Can someone explain, why it is happening? Is there any such corner case of text handling that I'm not aware of?
Having some sample input and output would help but let me take a guess. Try truncating the file by the seek:
truncate $a,0;
seek $a,0,0;
Without the truncate you will be overwriting what was there before. This works if you write more information than you read but not so good if you write less than you read.

How do you compare the value of an array to a variable in bash script?

I'm practicing bash and honestly, it is pretty fun. However, I'm trying to write a program that compares an array's value to a variable and if they are the same then it should print the array's value with an asterisk to the left of it.
#!/bin/bash
color[0]=red
color[1]=blue
color[2]=black
color[3]=brown
color[4]=yellow
favorite="black"
for i in {0..4};do echo ${color[$i]};
if {"$favorite"=$color[i]}; then
echo"* $color[i]"
done
output should be *black
There's few incorrect statements in your code that prevent it from doing what you ask it to. The comparison in bash is done withing square brackets, leaving space around them. You correctly use the = for string comparison, but should enclose in " the string variable. Also, while you correctly address the element array in the echo statement, you don't do so inside the comparison, where it should read ${color[$i]} as well. Same error in the asterisk print. So, here a reworked code with the fixes, but read more below.
#!/bin/bash
color[0]=red
color[1]=blue
color[2]=black
color[3]=brown
color[4]=yellow
favorite=black
for i in {0..4};do
echo ${color[$i]};
if [ "$favorite" = "${color[$i]}" ]; then
echo "* ${color[$i]}"
fi
done
While that code works now, few things that probably I like and would suggest (open to more expert input of course by the SO community): always enclose strings in ", as it makes evident it is a string variable; when looping an array, no need to use index variables; enclose variables always within ${}.
So my version of the same code would be:
#!/bin/bash
color=("red" "blue" "black" "brown" "yellow")
favorite="black"
for item in ${color[#]}; do
echo ${item}
if [ "${item}" = "${favorite}" ]; then
echo "* $item"
fi
done
And a pointer to the great Advanced Bash-Scripting Guide here: http://tldp.org/LDP/abs/html/

TCL list element in quotes followed by } instead of space

I'm trying to write an automated validation test on a small program using TCL. It should evaluate the input h1=7 and pass if the output is 7.000000. Likewise, the input h1=9 should pass if the output is 9.0000. However, I get the following error:
ERROR: list element in quotes followed by "}" instead of space
while executing
"foreach pattern $testdata {
set inputs [ lindex $pattern 0 ]
set expected [ lindex $pattern 1 ]
eval "spawn $CLIC $inputs"
expect {..."
(file "./test/clic/test-clic.exp" line 22)
Here is the code:
#!/usr/bin/expect
set tool "clic"
set CLIC "./clic "
set testdata {
{"h1=7" "7.000000"}
{"h1=9" "9.000000"}
}
# global CLIC
foreach pattern $testdata {
set inputs [ lindex $pattern 0 ]
set expected [ lindex $pattern 1 ]
eval "spawn $CLIC $inputs"
expect {
$expected { pass $inputs }
default { fail $inputs }
}
}
How do I resolve this? Thank you.
Given the error message given and the discrepancy between the line number in the error message and the number of lines in the script you told us about, I'm guessing that you've trimmed down the script a little bit before asking the question. Which would be perfectly OK (and a good thing) except that in the trimming process you removed the thing that was causing the problem! The code that you posted doesn't have the issue.
The issue is almost certainly in one of the lines of testdata that you removed. It's either that you've got malformatted list as testdata, or that it produces a malformatted script when you do the concatenations for the eval "spawn …"; unfortunately, I can't be sure which with the info you've given us. (It's also possibly an issue in the expect with it not liking taking a value from a variable when that argument is in braces; the documentation for expect isn't very clear about this case, yet it gives hints that it might do what you want.)
A good start would be to update the script to actually use the features of Tcl 8.6 (or Tcl 8.5) since you're already using that version. The key changes happen to these lines:
foreach pattern $testdata {
set inputs [ lindex $pattern 0 ]
set expected [ lindex $pattern 1 ]
eval "spawn $CLIC $inputs"
Which are much better written as:
foreach pattern $testdata {
lassign $pattern inputs expected
spawn {*}$CLIC {*}$inputs
That has far fewer ways of being misinterpreted than what you were using before, as well as being shorter. We can also wrap that all up in code to give better error handling:
foreach pattern $testdata {
if {[catch {
lassign $pattern inputs expected
spawn {*}$CLIC {*}$inputs
} msg]} {
puts stderr "Problem handling pattern '$pattern': $msg"
continue
}
If you still get the same failure at that point, the problem is almost certainly that your overall testdata is a malformed list (and it would be malformed like this: "something"{something else} with no whitespace between closing quotes and opening braces); since that's under your complete control, you'll just have to fix it…

Perl if condition parameters

I have a log file which looks like below:
4680 p4exp/v68 PJIANG-015394 25:34:19 IDLE none
8869 unnamed p4-python R integration semiconductor-project-trunktip-turbolinuxclient 01:33:52 IDLE none
8870 unnamed p4-python R integration remote-trunktip-osxclient 01:33:52
There are many such entries in the same log file such that some contains IDLE none at the end while some does not. I would like to retain the ones having "R integration" and "IDLE none" in a hash and ignore the rest. I have tried the following code but not getting the desired results.
#!/usr/bin/perl
open (FH,'/root/log.txt');
my %stat;
my ($killid, $killid_details);
while ($line = <FH>) {
if ($line =~ m/(\d+)/){
$killid = $1;
}
if ($line =~ /R integration/ and $line =~ /IDLE none/){
$killid_details = $line;
}
$stat{$killid} = {
killid => $killid_details
};
}
close (FH);
I am getting all the lines with R integration (for example I get 8869, 8870 lines) which should not be the case as 8870 should be ignored.
Please inform me if any mistake. I am still learning perl. Thank you.
I made a few changes in your program:
Always put in use strict; and use warnings;. These will catch 90% of your errors. (Although not this time).
When you open a file, you need to either use or die as in open my $fh, "<", $file or die qq(blah, blah, blah); or use use autodie; (which is now preferred). In your case, if the file didn't open, your program would have continued merrily along. You need to test whether or not the open statement worked.
Note my open statement. I use a variable for the file handle. This is preferred because it's not global, and it's easier to pass into subroutines. Also note I use the three parameter open. This way, you don't run into trouble if your file name begins with some strange character.
When you declare a variable, it's best to do it in scope. This way, variables go out of scope when you no longer need them. I moved where $killid and $killid_details to be declared inside the loop. That way, they no longer exist outside the loop.
You need to be more careful with your regular expressions. What if the phrase IDLE none appears elsewhere in your line? You only want it if its on the end of the line.
Now, for the issues you had:
You need to chomp lines when you read them. In Perl, the NL at the end of the line is read in. The chomp command removes it.
Your logic was a bit strange. You set $killid if your line had a digit in it (I modified it to look only for digits at the beginning of the line). However, you simply went on your merry way even if killid was not set. In your version, because you declared $killid outside of the loop, it had a value in each loop. Here I go to the next statement if $killid isn't defined.
You had a weird definition for your hash. You were defining a reference hash within a hash. No need for that. I made it a simple hash.
Here it is:
#! /usr/bin/env perl
use strict;
use warnings;
use feature qw(say);
use autodie;
use Data::Dumper;
open my $log_fh, '<', '/root/log.txt';
my %stat;
while (my $line = <$log_fh>) {
chomp $line;
next if not $line =~ /^(\d+)\s+/;
my $killid = $1;
if ($line =~ /R\s+integration/ and $line =~ /IDLE\s+none$/){
my $killid_details = $line;
$stat{$killid} = $killid_details;
}
}
close $log_fh;
say Dumper \%stat;
I think this is probably what you want:
while (<FH>) {
next unless /^(\d+).*R integration.*IDLE none/;
$stat{$1} = $_;
}
The regexp should be anchored to the beginning of the line, so you don't match a number anywhere on the line. There's no need to do multiple regexp matches, assuming the order of R integration and IDLE none are always as in the example. You need to use next when there's no match, so you don't process non-matching lines.
And I suspect that you just want to set the value of the hash entry to the string, not a reference to another hash.

Resources