How can I place go-template actions with multi-line output at any indentation level? - go-templates

We're creating yaml using go-templates. In them, we have actions with multi-line output that need to be indented at specific indent level. We can use the indent function for this, but it doesn't treat the first line differently and therefor requires the action definition have no indentation level.
For example:
foo:
bar:
baz:
{{ myYamlOutputtingAction | indent 6 }} # <-- notice 0 indent level
Is there a way I can place my action definitions at an indentation level that makes sense for the context of the template?

UPDATE: sprig 2.13.0+
Just nindent instead of indent. The sprig library includes this function for exactly this use case.
The same code from above can be written as:
foo:
bar:
baz:
{{ myYamlOutputtingAction | nindent 6 }}
Old answer for sprig versions before 2.13.0
You can change this:
foo:
bar:
baz:
{{ myYamlOutputtingAction | indent 6 }} # <-- notice 0 indent level
To this:
foo:
bar:
baz:
{{- "\n"}}{{ myYamlOutputtingAction | indent 6 }} # <-- properly indented with a little bit fluff
A little explanation
This works by ensuring whatever content follows the {{- "\n"}} has 0 indentation. This means you can trade a hacky {{- "\n"}} for proper indentation whenever it makes sense. We generally think it's worth it.

Related

How do I match using :global in Raku grammar?

I'm trying to write a Raku grammar that can parse commands that ask for programming puzzles.
This is a simplified version just for my question, but the commands combine a difficulty level with an optional list of languages.
Sample valid input:
No language: easy
One language: hard javascript
Multiple languages: medium javascript python raku
I can get it to match one language, but not multiple languages. I'm not sure where to add the :g.
Here's an example of what I have so far:
grammar Command {
rule TOP { <difficulty> <languages>? }
token difficulty { 'easy' | 'medium' | 'hard' }
rule languages { <language>+ }
token language { \w+ }
}
multi sub MAIN(Bool :$test) {
use Test;
plan 5;
# These first 3 pass.
ok Command.parse('hard', :token<difficulty>), '<difficulty> can parse a difficulty';
nok Command.parse('no', :token<difficulty>), '<difficulty> should not parse random words';
# Why does this parse <languages>, but <language> fails below?
ok Command.parse('js', :rule<languages>), '<languages> can parse a language';
# These last 2 fail.
ok Command.parse('js', :token<language>), '<language> can parse a language';
# Why does this not match both words? Can I use :g somewhere?
ok Command.parse('js python', :rule<languages>), '<languages> can parse multiple languages';
}
This works, even though my test #4 fails:
my token wrd { \w+ }
'js' ~~ &wrd; #=> 「js」
Extracting multiple languages works with a regex using this syntax, but I'm not sure how to use that in a grammar:
'js python' ~~ m:g/ \w+ /; #=> (「js」 「python」)
Also, is there an ideal way to make the order unimportant so that difficulty could come anywhere in the string? Example:
rule TOP { <languages>* <difficulty> <languages>? }
Ideally, I'd like for anything that is not a difficulty to be read as a language. Example: raku python medium js should read medium as a difficulty and the rest as languages.
There are two things at issue here.
To specify a subrule in a grammar parse, the named argument is always :rule, regardless whether in the grammar it's a rule, token, method, or regex. Your first two tests are passing because they represent valid full-grammar parses (that is, TOP), as the :token named argument is ignored since it's unknown.
That gets us:
ok Command.parse('hard', :rule<difficulty>), '<difficulty> can parse a difficulty';
nok Command.parse('no', :rule<difficulty>), '<difficulty> should not parse random words';
ok Command.parse('js', :rule<languages> ), '<languages> can parse a language';
ok Command.parse('js', :rule<language> ), '<language> can parse a language';
ok Command.parse('js python', :rule<languages> ), '<languages> can parse multiple languages';
# Output
ok 1 - <difficulty> can parse a difficulty
ok 2 - <difficulty> should not parse random words
ok 3 - <languages> can parse a language
ok 4 - <language> can parse a language
not ok 5 - <languages> can parse multiple languages
The second issue is how implied whitespace is handled in a rule. In a token, the following are equivalent:
token foo { <alpha>+ }
token bar { <alpha> + }
But in a rule, they would be different. Compare the token equivalents for the following rules:
rule foo { <alpha>+ }
token foo { <alpha>+ <.ws> }
rule bar { <alpha> + }
token bar { [<alpha> <.ws>] + }
In your case, you have <language>+, and since language is \w+, it's impossible to match two (because the first one will consume all the \w). Easy solution though, just change <language>+ to <language> +.
To allow the <difficulty> token to float around, the first solution that jumps to my mind is to match it and bail in a <language> token:
token language { <!difficulty> \w+ }
<!foo> will fail if at that position, it can match <foo>. This will work almost perfect until you get a language like 'easyFoo'. The easy fix there is to ensure that the difficulty token always occurs at a word boundary:
token difficulty {
[
| easy
  | medium
| hard
]
>>
}
where >> asserts a word boundary on the right.

Opening curly brace at a newline in Kotlin

Based on Kotlin coding conventions, it is discouraged to put opening curly braces on its own line as semi-colons are optional and that might cause surprising behavior. What would the surprising behavior be if we put the opening brace on its own line?
Formatting
In most cases, Kotlin follows the Java coding conventions.
Use 4 spaces for indentation. Do not use tabs.
For curly braces, put the opening brace in the end of the line where
the construct begins, and the closing brace on a separate line aligned
horizontally with the opening construct.
if (elements != null) {
for (element in elements) {
// ...
}
}
(Note: In Kotlin, semicolons are optional, and therefore line breaks are significant. The language design assumes Java-style braces,
and you may encounter surprising behavior if you try to use a
different formatting style.)
The comment about surprising behavior is not about the curly brace, but more general. Consider this code:
val result = 1
+ 2
println(result)
you might expect this to print "3", but it prints "1" because these are 2 statements, val result = 1 and + 2
You would write it like this in Kotlin if you wanted to break the line:
val result = 1 +
2
this is a simple example, but highlights the difference that not having semicolons to determine the end of a statement makes.

IntelliJ Align arguments to opening parenthesis?

When I split arguments onto multiple lines in IntelliJ, it puts the argument at a slight indent from the line above. For example:
ClassName.staticMethod(argument1,
argument2,
argument3);
Quick, what are the arguments above? Okay, that's easy because of the example names I chose, but how about below? Which arguments are going to staticMethod below?
ClassName.staticMethod(this.instanceMethod(argument1,
argument2),
argument3);
staticMethod is taking the results of a call to instanceMethod and argment3, but with IntelliJ's default formatting, at a glance you'd completely miss the fact that argument2 is an argument for instanceMethod, not staticMethod.
This is a freaking terrible default behavior. How can I get it to properly line arguments up, as in the modified examples below?
ClassName.staticMethod(argument1,
argument2,
argument3);
ClassName.staticMethod(this.instanceMethod(argument1,
argument2),
argument3);
Settings | Editor | Code Style | Java | Wrapping and Braces | Method call arguments | [x] Align when multiline

antlr parsing fails inside a generated syntactic predicate

I have a grammar with backtrack=true similar to the following:
start:
subrules+;
subrules:
...
| rule1
...
rule1:
....
| { Type1 }?
(sentence INT amount NEW_LINE (sentence NEW_LINE)? )
.....
a valid sentence 1 12.09 \n on two lines passes but A valid sentence \n without a second line fails.
Stepping through the code while debugging, I can see it fails to match on the code section generated for (desc2=sentence NEW_LINE)?
If I comment out the corresponding lines in the generated code so it doesn't attempt to match (desc2=sentence NEW_LINE)? before going inside the rule, both sentences pass correctly. Is this expected behavior or is it likely something else in my grammar (which is currently quite complex) is causing it to behave incorrectly.
Thanks, Richard

How to turn off JSLint indentation warnings?

I find that JSLint produces lots of warnings of the form:
Expected 'foo' to have an indentation at X instead at Y.
The JSLint options documentation describes an indent option that recognizes a numerical value representing the amount of space for each level of indentation. This option allows me to say things like use 2 spaces per level of indentation. I just write something like this at the top of my JavaScript file:
/*jslint indent: 2 */
OK, great. Now JSLint knows how much to indent for each level of indentation, but JSLint seems to be hardcoded to decide what level of indentation each line should have.
Suppose I want to indent my code differently than the way JSLint prescribes. Can I do this with some JSLint option? If not, can I at least turn off the indentation warnings? I tried:
/*jslint indent: false */
but that did not cause indentation warnings to be elided; it caused a JSLint error.
What a difference that morning coffee makes:
/*jslint white: true */
If you don't want to disable JSLint, you can remove the double indentations (e.g. when defining multiple var's in a javascript file) by adjusting this setting:
Options > Editor > Formatting > Language: Javascript > Continuation Indentation - set to 4.
Now you can use ctrl shift f to format code, and JSLint doesn't freak out...