[TxMt] Re: possible format strings bug

Matt Neuburg matt at tidbits.com
Sat Apr 5 18:10:16 UTC 2014


On Apr 5, 2014, at 12:20 AM, Allan Odgaard <mailinglist at textmate.org> wrote:

> On 4 Apr 2014, at 23:31, Matt Neuburg wrote:
> 
>> […] Unfortunately one can't mix named groups with implicitly numbered groups, so it's going to be named groups all the way […]
> 
> Just to be sure I understand, the issue here is that if you use named captures in the parent match, the $1-n variables are still created and inherited.
> 

I'm not saying you should change anything! The problem is solved, and one wouldn't want to risk breakage.

Just to summarize: my difficulty was in understanding how this line from the Markdown bundle grammar works:

name = 'markup.heading.${1/(#)(#)?(#)?(#)?(#)?(#)?/${6:?6:${5:?5:${4:?4:${3:?3:${2:?2:1}}}}}/}.markdown';
begin = '(?:^|\G)(#{1,6})\s*(?=[\S[^#]])';
end = '\s*(#{1,6})?$\n?';

Looking at the format string in the "name" entry, there is a clear implication that one can use group numbers in the second half to refer to groups from the regular expression in the first half. I mean, here's the structure of the thing:

${1/...search.../...replacement.../}

Now, I know what "1/" means at the start; it refers to the first group in the "begin" regex. (Doesn't it?) The question is: what do 6, 5, 4, 3, 2, and 1 in the replacement expression refer to (in the second half)? They seem to refer to groups in the search expression (the first half).

Now, I find that surprising. It isn't documented on this page: http://blog.macromates.com/2011/format-strings/ However, it clearly does work somehow, so, at the suggestion of Michael Sheets, I set out to imitate it in the AsciiDoc bundle. For AsciiDoc, the rules are different: we use "=" instead of "#", and if there is one "=" that is a level 0 heading and so on. Well, I couldn't get it to work. That's when I started experimenting with simple find/replace expressions in a document (using the Find/Replace dialog), and I found the results incoherent.

Let's take this example. My document is:

====
hello
====

Find expression: 

   (hello)

Replace expression: 

   ${1/(hello)?/${1:?howdy:scram}/}

Now do a Replace All. Result: the document says "howdy", which is what I expect. The challenge is to get the word "scram" to appear in the document!

Revert to the original document ("hello"). Let's suppose I change the replace expression to this: 

   ${1/(hey)?/${1:?howdy:scram}/}

Now when I Replace All, I get "howdyhello". I found that mystifying, since "(hey)" is not being found. My replacement choice is between "howdy" and "scram", so I expect to see "scram".

That's when I posed my question and learned that "1" is ambiguous. It might refer to the search expression in the first half "(hey)", but it might also refer to the original Find expression "(hello)". So (since I needed the parentheses for other reasons) I tried to resolve that ambiguity by using names instead of numbers:

Find expression:

   (?<orig>hello)

Replace expression:

   ${orig/(hey)?/${1:?howdy:scram}/}

That didn't solve it. So I used names _everywhere_:

Find expression:

   (?<orig>hello)

Replace expression:

   ${orig/(?<one>hey)?/${one:?howdy:scram}/}

And now, at last, "scram" appears in my document (I get "scramhello"). So that's why I said it would have to be names throughout. I see nothing wrong with that. I like names!

One last note: I am still mystified by what happens if we _remove_ the question mark after the parentheses in the first half of the replace expression:

   ${1/(hey)/${1:?howdy:scram}/}

In that case, I can in no circumstances get "scram" to appear. I don't understand why not. The search for "(hey)" has failed, but $1 still has meaning, so I expect to see either "howdy" or "scram". I see _neither_.

m.

--
matt neuburg, phd = http://www.apeth.net/matt/
pantes anthropoi tou eidenai oregontai phusei
Programming iOS 7! http://shop.oreilly.com/product/0636920031017.do
iOS 7 Fundamentals! http://shop.oreilly.com/product/0636920032465.do
RubyFrontier! http://www.apeth.com/RubyFrontierDocs/default.html




More information about the textmate mailing list