Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    Vasilij Schneidermann
    @wasamasa
    It took me some time, but I've finally reported the bug with repro: comby-tools/comby#190
    Rijnard van Tonder
    @rvantonder
    Fixed in upstream. Thanks again for the report, makes it easy to check things. Will cut a release after I add a test (tomorrow or so).
    Vasilij Schneidermann
    @wasamasa
    An easier way of testing without sudo would be creating a subdirectory containing another matching line
    Lukas Werling
    @lluchs

    I'm trying to use comby for a replacement like this: GetCrew(plr, idx) to GetPlayer(plr)->GetCrew(idx). I came up with comby 'GetCrew(:[plr],:[? ]:[idx])' 'GetPlayer(:[plr])->GetCrew(:[idx])' and have two questions:

    1 - is :[? ] the best way to handle optional whitespace between arguments? The examples (e.g., the swap one on the installation page) just seem to assume that there is always a single space. Have you considered a way to strip whitespace in the replacement pattern?

    2 - The idx parameter is actually optional, and I'm not sure how to handle that with comby. So I also need to replace GetCrew(plr) with GetPlayer(plr)->GetCrew()

    Rijnard van Tonder
    @rvantonder

    Hey @lluchs :-) Good questions. For the first: since comby runs on the concrete syntax, the only way to specify an optional match in a single template is with the option you used :[? ]. Very recently, I've added regex support to comby, that you can use instead, which is perhaps more familiar and flexible for scanner/lexer kinds of matches. Unfortunately I haven't documented it on the site yet (soon!), but the basic syntax is :[thing~regex], where thing is an optional identifier name. Example on your code: https://bit.ly/315pe70. You'll need v0.18.1, I'm not sure that it is in brew yet, it may be. So, this is the best way I can see to do this, if you want to just use a single template. But:

    Have you considered a way to strip whitespace in the replacement pattern?

    If you can remove the constraint of specifying just a single template, you can strip whitespace using a rewrite rule. This example will strip the leading whitespace off of everything that matches <spaces>:[idx]: https://bit.ly/2Ycbdm2

    For question 2: There's always the possibility of doing this with two invocations. The single argument case would match something like GetCrew(:[[plr]]). There is a way to do everything in one invocation, but it's more complicated. So that said, it turned out to be a really interesting thing to try do with comby. Normally, rewrite rules can get you pretty far on their own, and that's what I tried at first: https://bit.ly/3aBSepX. The problem there is that it's not possible to assign a value to idx in a rule (and that's a need that came up in the past, but not often). It is something I may add, but it lead me to try solve this a different way.

    I came up with a way to use regex to match the first argument (assuming it is alphanumeric) , and then a rewrite rule to strip the leading commas/whitespace if it matches the idx part. It looks like this: https://bit.ly/3aDzKoU. Just expand the box to see the rules but here's a screenshot:

    Screen Shot 2020-08-18 at 11.22.28 AM.png
    Lukas Werling
    @lluchs
    Hi @rvantonder - wow, thanks for the detailed answer.
    Regex support works nicely (I downloaded the release for Linux), though the regexes might work better if they were a bit less greedy? I was trying :[~[^,]+] to match everything up to the first comma, but of course that then also matches the closing ) if there is no comma, and the whole match fails.
    Unfortunately, I cannot assume a purely alphanumeric first argument (it's often another function call), so a three-step replacement is probably the solution.
    Lukas Werling
    @lluchs
    Ah, nice - with a configuration file, I can do all three steps at once.
    But yeah, capturing values in a rewrite rule would be awesome for this use-case.
    Rijnard van Tonder
    @rvantonder

    but of course that then also matches the closing ) if there is no comma

    Yeah, that's unfortunately the main pitfall of introducing regex. And yep, I assume that if you exclude ) in the regex, like ~[^,)]+ it doesn't work for your use case because the first argument might be an expression like foo->bar() which will then also not (in general) match what you want.

    There is a way to implement the notion of "match a balanced expression but exclude <character set>, like comma", instead of "match a regex but exclude <character set>" which would address this. I'd need to introduce a syntax for that, and haven't thought about it yet :-)

    Ben Briggs
    @ben-eb
    Probably another vote for the above; I'd like to replace instances of Array.from(x).map(z) to Array.from(x, z) but not when Array.from(x, y).map(z) as that would result in Array.from(x, y, z) which would be incorrect (y and z would have to be combined through function composition). :slight_smile:
    Ben Briggs
    @ben-eb
    Maybe goes without saying but x, y and z could be any expression potentially
    Rijnard van Tonder
    @rvantonder

    Yeah, that makes a lot of sense. I've played around with something that'll match syntax for expressions like foo(x, y), so that Array.from(foo(x, y)) still matches despite the whitespace. The tricky part is also supporting something like:

    Array.from(function (...) {...})

    The function is one expression, but comby doesn't know about function being meaningful/delineating a keyword for the start of a function expression, so will just treat function as token, and the rest as structured blocks. You could use multiple templates here but obvi it's nice to have just hole syntax to match a JS expression (otherwise we wouldn't be talking about this :P). My thinking at this stage is to encode expression holes on a per-language basis so that this just works out of box.

    There's also the chance here that maybe you wouldn't want to do that replacement for something like function ... if it spans multiple lines. In which case it starts to make sense to define the syntax (subset) of expressions to match, possibly in a global form for all the patterns.
    Ben Briggs
    @ben-eb
    Yeah, I don't know how difficult that'd be to implement in a language agnostic way. Thanks for your insights!
    Rijnard van Tonder
    @rvantonder
    I think there's a way, it probably means handing over more user control/configuration over the parsing steps.
    Jason Keene
    @jasonkeene
    Hello, I just discovered Comby and am loving it! I'm looking for help trying to match the middle case in this example: http://bit.ly/33fiEL8
    It involves matching a sub expression that may or may not be nested at different levels of {} delimiters. Is there any way to match no matter how many levels the sub expression might be?
    Jason Keene
    @jasonkeene
    I was thinking I might be able to use the regex matching syntax to match { but I can't get it to work :/
    Rijnard van Tonder
    @rvantonder

    Hey @jasonkeene glad it's working for you. Right, so by default when the template contains {...} and then a pattern inside, it will only match at that top level of {...}. The only way right now to match a pattern inside {...} in a way that doesn't care about the level of matching is to use a match or rewrite rule. Here's what I think you're aiming for:

    func Test:[a](:[b] *testing.T):[c] {:[body]}

    with a rewrite rule:

    where rewrite :[body] {
    "if x == y { return:[e] }" -> "skipCond(:[b])"
    }

    Link: https://bit.ly/35jIrUL

    When a rule fires on some matched content like :[body], it doesn't care about the level of nesting (it's as if that content is extracted and then running comby only on that part). A side effect here is that you don't need to :[d] or :[f] parts which were basically 'anything' in the previous template--and also, the previous template would stop matching at the first if x == y as well, while the rule will continue and match all instances.

    This use case comes up often enough that it makes sense for me to introduce an inline notation to express 'match this expression inside these {...}at any level' so you don't need to write out a separate rule. Related tools like Coccinelle use a kind of notation like <... stuff ...> to express this, and I'm thinking about something similar in comby, something like, say,

    func func Test:[a](:[b] *testing.T):[c] {
    <... if x == y { return:[e] } ...>
    }

    where this syntax just means that the rule above is created for you :-) Still TBD

    Jason Keene
    @jasonkeene
    So awesome! Thanks for the pointers. I will do more reading on rewrite functionality.
    Stefan Buck
    @stefanbuck

    Hello, looks like comby 0.18 introduced a breaking change, but I guess this was intended . The simplify of matching for :[hole]: is causing different outputs when using comby 0.15.0 vs. 0.18.3.

    Given the follwoing input file

    <button>Single line</button>
    <button>
        Multi-line
    </button>

    You can use this bash script to compare output of comby 0.15.0 and 0.18.3.

    COMBY_M="<button>:[hole]</button>"
    COMBY_R="<button>###:[hole]###</button>"
    
    echo 'Output comby-0.15.0\n'
    comby-0.15.0 "$COMBY_M" "$COMBY_R" ./test.html -stdout
    
    echo '\n---------------------\nOutput comby-0.18.3\n'
    comby-0.18.3 "$COMBY_M" "$COMBY_R" ./test.html -stdout

    Both comby calls should produce the same output, but 0.18.3 behaves different which seems to be related to the change introduced in 0.18.0.

    Output comby-0.15.0
    
    <button>###Single line###</button>
    <button>###
        Multi-line
    ###</button>
    
    ---------------------
    Output comby-0.18.3
    
    <button>###Single line###</button>
    <button>
        Multi-line
    </button>

    I wonder how I can replicate the same output with a single match template.

    Rijnard van Tonder
    @rvantonder

    @stefanbuck Ah, you're right! Shoot, it wasn't intended to be a breaking change, I (wrongly) assumed that the single/multiline change would preserve all previous behaviors. I'm going to revert this change and make the new behavior available under a flag.

    Separately, I'll then bump the major version where this flag/behavior is enabled by default, since I do think enabling it is a better default behavior for the vast majority of use cases. The new default behavior won't better for your HTML case yet (in which case, the flag will need to be turned off if you decide to use the new major version), however I will make it work by default for the XML/HTML case at a later point, it just needs some bigger changes.

    Thanks for feedback!

    Stefan Buck
    @stefanbuck
    Cheers, thanks for the quick reply @rvantonder
    Murphy Randle
    @mrmurphy
    Hey folks! Here's a quick question. I'm trying to match everything that comes after a pattern to the end of the block. I've read the docs, and I think I'm doing it the way i'm supposed to, but it's not working how I'd expect:
    I want all these lines to be matched in blue:
    image.png
    and I thought that :[rest] would match until a closing block character, including newlines
    oh wait, I did it!
    had to increase the matching pattern to include the braces
    Volkan Unsal
    @volkanunsal
    Hi everyone. I'm trying to use the template file to process a file in the current directory. But I keep getting errors like this one: Could not read required match file in .
    This is the command I'm using comby -config . -f .js. And there is a file named index.js in the current directory.
    Rijnard van Tonder
    @rvantonder

    Hey @volkanunsal! Are you using a configuration file like this: https://comby.dev/docs/configuration

    or a directory layout like this: https://comby.dev/docs/cheat-sheet#run-multiple-search-and-replace-templates

    For configuration files, you'll have to point to -config ./your-file.toml. For directories, the directory (in this case, the current one) would need to contain a file called match with the pattern.

    Volkan Unsal
    @volkanunsal
    Ahhhh... so that's what the match file is. I totally didn't get that was the name of the file and thought perhaps it wasn't matching anything.
    After correcting the command to comby -config comby.toml -f .jsx it seems to be working. :)
    Rijnard van Tonder
    @rvantonder
    Yeah, there are two modes for that flag, so it's a bit confusing. Hope you got your pattern working now
    Monty Zukowski
    @montyz
    Hello, is comby suitable for distinguishing between different types of constants? I'd like to match a function call like setScore(:[1]) and then take different actions based on whether [:1 is a string literal, an integer, a decimal, or an expression. I see that pattern matching can use text or regex. Is there a way to dig a little deeper into comby's type of the match?
    Monty Zukowski
    @montyz
    Here's a stab at it https://bit.ly/36vdHRo. The issue right now is that I want setScore(4/3) to evaluate to true, but it matches against | ":[_~\\d+]" -> false because I guess it's matching against the prefix. Not sure how to get around that.
    Monty Zukowski
    @montyz
    This is a little better https://bit.ly/2SiuQFN I'm not so happy with how I did it, but I can't think of an alternative way.
    Rijnard van Tonder
    @rvantonder

    Hey @montyz . Casing out on syntax, like you're doing, is the only way to achieve this right now. Using a program's actual type information is something I've wanted to incorporate for a while, but depends a lot on the language. I'm curious what language you are working in, it might be a good fit for combining type info that way.

    For the rules, I think what you came up with is likely the closest you can get right now. The trouble you're having is that match will try find that pattern anywhere in the string (and like you say, matches the prefix). To control that, a helpful answer I want to give you is that you can use regex anchors ^...$ to match whether something is only digits (i.e., integer) and everything else should be checked (which seems to be what you're trying to do?). Unfortunately, that's missing from comby, but I coded up a fix here, and the rule becomes a lot simpler: https://github.com/comby-tools/comby/commit/cbdeaf8e1b4bb86557d6d60418568c0a3f1aca77#diff-f7592766e6cb7ff52ef4395d4e49389aR276-R279

    Monty Zukowski
    @montyz
    I'm working with JavaScript
    ah yeah that's helpful, thanks!
    Rijnard van Tonder
    @rvantonder
    I'll publish a release in the next day or two with the change.
    Monty Zukowski
    @montyz
    OK, thanks!
    Volkan Unsal
    @volkanunsal
    Thanks Rijnard. I got it working.
    I had another question for you, though. Is it possible to use "not" syntax in the -exclude flag. e.g.
    comby -config comby.toml -f .jsx -i -exclude '!*.comby.*'
    That is to say, don't include any files that don't have comby in the file name.
    Volkan Unsal
    @volkanunsal
    Actually, this is not so important. I can save the files with a different extension. :)