git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH 1/9] ref-filter: implement %(if), %(then), and %(else) atoms

From
Karthik Nayak <karthik.188@gmail.com>
Date
Oct 4, 2015, 13:59 UTC
Message-ID
<CAOLa=ZRXvz+sAtMOmreri7QUCfwrusDQKNme4ke_8uaTkAoqiQ@mail.gmail.com>
In-Reply-To
<vpq8u7kb89o.fsf@grenoble-inp.fr>

On Sat, Oct 3, 2015 at 3:09 PM, Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> wrote:

Show 7 quoted lines
> Karthik Nayak <karthik.188@gmail.com> writes:
>
>> Implement %(if), %(then) and %(else) atoms. Used as
>> %(if)..%(then)..%(end) or %(if)..%(then)..%(else)..%(end).
>
> I prefer ... to .., which often means "interval" as in HEAD^^..HEAD.
>
Seems good, will change.
Show 21 quoted lines
>> If there is an atom with value or string literal after the %(if)
>
> I find this explanation hard to read, and ambiguous: what does "atom
> with value" mean?
>
>> then everything after the %(then) is printed, else if the %(else) atom
>> is used, then everything after %(else) is printed. If the string
>> contains only whitespaces, then it is not considered.
>
> "the string" is ambiguous again. I guess it's "what's between %(if) and
> %(then)", but it could be clearer. And it's not clear what "not
> considered" means.
>
> My take on it:
>
> Implement %(if), %(then) and %(else) atoms. Used as
> %(if)...%(then)...%(end) or %(if)...%(then)...%(else)...%(end). If the
> format string between %(if) and %(then) expands to an empty string, or
> to only whitespaces, then the string following %(then) is printed.
> Otherwise, the string following %(else), if any, is printed.
>

This (the one you sent again after Junio's suggestion, looks better), I'll use this thanks.

Show 7 quoted lines
>> +When a scripting language specific quoting is in effect,
>
> This may not be immediately clear to the reader. I'd add explicitly:
>
> When a scripting language specific quoting is in effect (i.e. one of
> `--shell`, `--perl`, `--python`, `--tcl` is used), ...
>
Makes sense.
Show 7 quoted lines
>>  EXAMPLES
>>  --------
>
> This is just the context of the patch, but I read it as a hint that we
> could add some examples with complex --format usage to illustrate the
> theory above.
>
I was thinking about adding :

An example to show the usage of %(if)...%(then)...%(else)...%(end). This prefixes the current branch with a star.

------------ #!/bin/sh

git for-each-ref --format="%(if)%(HEAD)%(then)* %(else) %(end)%(refname:short)" refs/heads/ ------------

An example to show the usage of %(if)...%(then)...%(end). This adds a red color to authorname, if present

------------ #!/bin/sh

git for-each-ref --format="%(refname)%(if)%(authorname)%(then)%(color:red)%(end) %(authorname)" ------------

Show 40 quoted lines
>> +     if (if_then_else->condition_satisfied && if_then_else->else_atom) {
> // cs && else
>> +             strbuf_reset(&cur->output);
>> +             pop_stack_element(&cur);
>> +     } else if (if_then_else->else_atom) {
> // !cs && else
>> +             strbuf_swap(&cur->output, &prev->output);
>> +             strbuf_reset(&cur->output);
>> +             pop_stack_element(&cur);
>> +     } else if (!if_then_else->condition_satisfied)
> // !cs && !else
>> +             strbuf_reset(&cur->output);
>
> This if/else if/else if looks hard to read to me. I had to add the
> comments above as a note to myself to get the actual full condition for
> 3 branches.
>
> The reasoning would be clearer to me as:
>
> if (if_then_else->else_atom) {
>         /*
>          * There is an %(else) atom: we need to drop one state from the
>          * stack, either the %(else) branch if the condition is satisfied, or
>          * the %(then) branch if it isn't.
>          */
>         if (if_then_else->condition_satisfied) {
>                 strbuf_reset(&cur->output);
>                 pop_stack_element(&cur);
>         } else {
>                 strbuf_swap(&cur->output, &prev->output);
>                 strbuf_reset(&cur->output);
>                 pop_stack_element(&cur);
>         }
> } else if (if_then_else->condition_satisfied)
>         /*
>          * No %(else) atom: just drop the %(then) branch if the
>          * condition is not satisfied.
>          */
>         strbuf_reset(&cur->output);
>
This looks neater thanks.
Show 11 quoted lines
>> +static void if_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
>> +{
>> +     struct ref_formatting_stack *new;
>> +     struct if_then_else *if_then_else = xcalloc(sizeof(struct if_then_else), 1);
>> +
>> +     if_then_else->if_atom = 1;
>
> Do you ever use this "if_atom"? It doesn't seem so in the current patch,
> and it seems like a tautology to me: if you have a struct if_then_else,
> then you have seen the %(if).
>
Yea I'll remove that.
>> +static int is_empty(const char * s){
>
> char * s -> char *s
>
will do.
Show 13 quoted lines
>> +static void then_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
>> +{
>> +     struct ref_formatting_stack *cur = state->stack;
>> +     struct if_then_else *if_then_else = (struct if_then_else *)cur->at_end_data;
>> +
>> +     if (!if_then_else)
>> +             die(_("format: %%(then) atom used without an %%(if) atom"));
>
> You've just casted at_end_data to if_then_else. if_then_else being not
> NULL does not mean that it is properly typed. It can be the at_end_data
> of another opening atom. What happens if you use
> %(align)foo%(then)bar%(end)?
>
Nice catch, didn't see that possibility.
> One way to be safer would be to check that cur->at_end does point to
> if_then_else_handler. Or add information to struct ref_formatting_stack
> (a Boolean is_if_then_else or an enum).
>
Checking cur->at_end with if_then_else_handler seems good to me.
> Also, you need to check that if_then_else->then_atom is not 1.
>
Ah! multiple usage of the same atom.
Show 10 quoted lines
>> +static void else_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
>> +{
>> +     struct ref_formatting_stack *prev = state->stack;
>> +     struct if_then_else *if_then_else = (struct if_then_else *)state->stack->at_end_data;
>> +
>> +     if (!if_then_else)
>> +             die(_("format: %%(else) atom used without an %%(if) atom"));
>
> Same as above, I guess (not tested) %(align)...%(else) is accepted.
>
Will change.
Show 15 quoted lines
>> +     if (!if_then_else->then_atom)
>> +             die(_("format: %%(else) atom used without a %%(then) atom"));
>> +     if_then_else->else_atom = 1;
>> +     push_stack_element(&state->stack);
>
> So, while parsing the %(else)...%(end), the stack contains both the
> %(then)...%(else) part, and the %(else)...%(end).
>
> I'm wondering if we can simplify this. We already know if the condition
> is satisfied, and if it's not, we can just drop the %(then) part right
> now, and write to the top of the stack normally (the %(end) atom will
> only have to pop the string normally). But if the condition is not
> satisfied, we need to preserve the %(then) part and need to do something
> about the %(else).
>

I wanted to do something like this the problem is append_atom() and append_literal() would need to be informed about which part to ignore, and this moves the code's logic from the current handlers to append_atom() and append_literal(). Which I didn't think was a nice way of doing this.

Show 7 quoted lines
>> -     current->at_end(current);
>> +     current->at_end(&state->stack);
>> +
>> +     /*  Stack may have been popped, hence reset the current pointer */
>
> I'd say explicitly "... may have been popped within at_end, hence ..."
>
Will do.
-- 
Regards,
Karthik Nayak
Previous: Junio C HamanoNext: Karthik Nayak
Message 9 of 43 in “port branch.c to use ref-filter printing APIs”
  1. 0/9 port branch.c to use ref-filter printing APIsKarthik Nayak, Oct 2, 2015
  2. 1/9 ref-filter: implement %(if), %(then), and %(else) atomsKarthik Nayak, Oct 2, 2015
  3. Junio C HamanoOct 2, 2015
  4. Karthik NayakOct 3, 2015
  5. Matthieu MoyOct 3, 2015
  6. Junio C HamanoOct 3, 2015
  7. Matthieu MoyOct 4, 2015
  8. Junio C HamanoOct 4, 2015
  9. Karthik NayakOct 4, 2015
  10. 2/9 ref-filter: implement %(if:equals=<string>) and %(if:notequals=<string>)Karthik Nayak, Oct 2, 2015
  11. Junio C HamanoOct 2, 2015
  12. Karthik NayakOct 3, 2015
  13. 3/9 ref-filter: add support for %(path) atomKarthik Nayak, Oct 2, 2015
  14. Matthieu MoyOct 3, 2015
  15. Karthik NayakOct 4, 2015
  16. Matthieu MoyOct 4, 2015
  17. Junio C HamanoOct 4, 2015
  18. Matthieu MoyOct 5, 2015
  19. Karthik NayakOct 4, 2015
  20. 4/9 ref-filter: modify "%(objectname:short)" to take lengthKarthik Nayak, Oct 2, 2015
  21. Junio C HamanoOct 2, 2015
  22. Karthik NayakOct 3, 2015
  23. 5/9 ref-filter: adopt get_head_description() from branch.cKarthik Nayak, Oct 2, 2015
  24. 6/9 ref-filter: introduce format_ref_array_item()Karthik Nayak, Oct 2, 2015
  25. Matthieu MoyOct 3, 2015
  26. Karthik NayakOct 5, 2015
  27. Matthieu MoyOct 5, 2015
  28. Karthik NayakOct 6, 2015
  29. Matthieu MoyOct 6, 2015
  30. Karthik NayakOct 6, 2015
  31. 7/9 ref-filter: make %(upstream:track) prints "[gone]" for invalid upstreamsKarthik Nayak, Oct 2, 2015
  32. Matthieu MoyOct 3, 2015
  33. Karthik NayakOct 5, 2015
  34. 8/9 branch: use ref-filter printing APIsKarthik Nayak, Oct 2, 2015
  35. Matthieu MoyOct 3, 2015
  36. Karthik NayakOct 5, 2015
  37. Matthieu MoyOct 5, 2015
  38. Karthik NayakOct 6, 2015
  39. Matthieu MoyOct 6, 2015
  40. Karthik NayakOct 7, 2015
  41. Matthieu MoyOct 7, 2015
  42. Karthik NayakOct 7, 2015
  43. 9/9 branch: implement '--format' optionKarthik Nayak, Oct 2, 2015

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.