I’m new to TextMate 2 grammar definitions and am trying to add a Markdown regex to identify a Markdown fenced code block like this one:
``` Vagrant.configure("2") do |config|
config.vm.box = "scotch/box" config.vm.network "private_network", ip: "192.168.33.10" config.vm.hostname = "scotchbox" config.vm.synced_folder ".", "/var/www", :mount_options => ["dmode=777", "fmode=666"]
end ```
I built this regex:
{ name = 'markup.raw.block.markdown'; begin = '(^|\G)([`]{3})'; end = '(^|\G)(^[`]{3})'; },
Which hits the starting ``` but misses the ending one. Probably because it thinks the second one is the start of a new code block rather than the end of the last one.
TextMate tangles me up some because it looks at just one line at a time for regex matches. Looked at it that way, each of the ```s is exactly the same!
What would the proper regex be?
Bob ------------------- Robert J. Rockefeller Richmond Hill, GA www.bobrockefeller.com
On Feb 9, 2015, at 4:07 PM, Robert J. Rockefeller bob@bobrockefeller.com wrote:
end = '(^|\G)(^[`]{3})';
Remember this is just one line. It can't contain two start of line (caret). No single line can do that.
You should try modelling yourself after existing bundles and existing regexen. It saves a mess of time.
m.
-- matt neuburg, phd = http://www.apeth.net/matt/ pantes anthropoi tou eidenai oregontai phusei Programming iOS 8! http://shop.oreilly.com/product/0636920034261.do iOS 7 Fundamentals! http://shop.oreilly.com/product/0636920032465.do RubyFrontier! http://www.apeth.com/RubyFrontierDocs/default.html
On 10 Feb 2015, at 7:07, Robert J. Rockefeller wrote:
I built this regex:
{ name = 'markup.raw.block.markdown'; begin = '(^|\G)([`]{3})'; end = '(^|\G)(^[`]{3})'; },
Since you always want to match from begin-of-line they should probably just be:
{ name = 'markup.raw.block.markdown'; begin = '^`{3}'; end = '^`{3}'; },
Which hits the starting ``` but misses the ending one. Probably because it thinks the second one is the start of a new code block rather than the end of the last one.
I don’t see anything wrong here. Is there perhaps more in your actual grammar that you left out of this email?
I still have something wrong.
My injected grammar (injection selector is L:text.html.markdown) looks like this:
{ patterns = ( { name = 'source.yaml.front-matter'; begin = '\A-{3}'; end = '-{3}'; patterns = ( { include = 'source.yaml'; } ); }, { name = 'text.html.markdown.classes'; begin = '{'; end = '}'; }, { name = 'markup.raw.inline.markdown'; begin = ' `'; end = '`(?=[ .,;-=+])'; }, { name = 'markup.raw.block.markdown'; begin = '^`{3}'; end = '^`{3}'; }, ); }
My Markdown text block is this:
There are a wide variety of Vagrant Boxes available on [Vagrant Cloud](https://vagrantcloud.com/boxes/search); you can search there for whatever features you need in a Vagrant Box. I found that [Scotch Box](https://github.com/scotch-io/scotch-box) works great for me because it is pre-provisioned (all the pieces are already downloaded as part of the box) and includes a full LAMP (Linux, Apache, MySQL, PHP) stack. We don't need the MySQL part for Grav, but it's there. The [Scotch Box Documention](https://box.scotch.io) provides plenty of information to get it running (just scroll their web page down).
After getting all that done, my project folder for Grav is shown on the right. My Vagrantfile is: ``` Vagrant.configure("2") do |config|
config.vm.box = "scotch/box" config.vm.network "private_network", ip: "192.168.33.10" config.vm.hostname = "scotchbox" config.vm.synced_folder ".", "/var/www", :mount_options => ["dmode=777", "fmode=666"]
end ```
When I'm ready to work, I open iTerm2 to `grav/public` and type `vagrant up`, wait a bit for Vagrant to do its thing and report that it's done, send my browser to `http://192.168.33.10%60, and go to town.
My use of Vagrant is at the low end of the complexity spectrum. There is so much more that Vagrant can do and I'm still moving slowly towards more advanced uses such as sharing the server across the local network so that other devices (my iPad and iPhone) can access the server. Or even sharing it across the Internet so that other people can see what I'm working on.
The name = 'markup.raw.block.markdown’; pattern finds the first ``` but misses the second ``` and runs to the end of the document.
Bob ------------------- Robert J. Rockefeller Richmond Hill, GA www.bobrockefeller.com
I’ve taken another failed run at this.
My patterns are now:
{ patterns = ( { name = 'source.yaml.front-matter'; begin = '\A-{3}'; end = '-{3}'; patterns = ( { include = 'source.yaml'; } ); }, { name = 'text.html.markdown.classes'; begin = '{'; end = '}'; }, { name = 'markup.raw.inline.markdown'; begin = ' `'; end = '`(?=[ .,;-=+])'; }, { name = 'markup.raw.block.markdown'; begin = '^`{3}'; while = '^[^`{3}]'; }, ); }
And I’m still trying in the same Markdown to match the code block between the ```s.
There are a wide variety of Vagrant Boxes available on [Vagrant Cloud](https://vagrantcloud.com/boxes/search https://vagrantcloud.com/boxes/search); you can search there for whatever features you need in a Vagrant Box. I found that [Scotch Box](https://github.com/scotch-io/scotch-box https://github.com/scotch-io/scotch-box) works great for me because it is pre-provisioned (all the pieces are already downloaded as part of the box) and includes a full LAMP (Linux, Apache, MySQL, PHP) stack. We don't need the MySQL part for Grav, but it's there. The [Scotch Box Documention](https://box.scotch.io https://box.scotch.io/) provides plenty of information to get it running (just scroll their web page down).
After getting all that done, my project folder for Grav is shown on the right. My Vagrantfile is: ``` Vagrant.configure("2") do |config|
config.vm.box = "scotch/box" config.vm.network "private_network", ip: "192.168.33.10" config.vm.hostname = "scotchbox" config.vm.synced_folder ".", "/var/www", :mount_options => ["dmode=777", "fmode=666"]
end ```
When I'm ready to work, I open iTerm2 to `grav/public` and type `vagrant up`, wait a bit for Vagrant to do its thing and report that it's done, send my browser to `http://192.168.33.10%60 http://192.168.33.10`, and go to town.
My use of Vagrant is at the low end of the complexity spectrum. There is so much more that Vagrant can do and I'm still moving slowly towards more advanced uses such as sharing the server across the local network so that other devices (my iPad and iPhone) can access the server. Or even sharing it across the Internet so that other people can see what I'm working on.
The name = 'markup.raw.block.markdown’ begin pattern finds the first ```.
And the while pattern matches on Vagrant.configure("2") do |config| as it should.
But the while pattern fails on the empty line (a newline) and the match stops.
Why wouldn’t ^[^`{3}] succeed in matching a newline? ^[^`{3}]|\n doesn’t match either.
How should I be setting up the patterns?
Bob ------------------- Robert J. Rockefeller Richmond Hill, GA www.bobrockefeller.com
On 10 Feb 2015, at 23:40, Robert J. Rockefeller wrote:
I still have something wrong.
My injected grammar (injection selector is L:text.html.markdown) looks like this: […]
OK, your initial hunch was correct about the end pattern being eclipsed by recursively matching a new raw block since this is an injection grammar (I thought you had simply extended the current Markdown grammar).
You can solve this by changing the injection scope selector.
To make it only inject at the root of the grammar, you can use:
L:(text.html.markdown $)
However, in your example document, the here-doc is technically inside a paragraph. I am not sure if Markdown (that support fenced code blocks) will treat it as a code block or not, but if you want to support fenced code blocks, regardless of current context, you should use this injection scope selector:
L:(text.html.markdown - markup.raw)
This will inject the grammar everywhere except markup.raw, so you will avoid the recursion.
Btw: The inline markdown and markdown block: You may want to swap the two rules, so that we always try a block first (3 backticks), and then, if it’s not a block, fallback on trying inline raw. Then remove the trailing space, and possibly add another rule (before the inline raw) to match escape sequences, so that ` is not mistaken as inline raw.
Some progress, perhaps, but still not there.
I better understand how TextMate’s standard Markdown grammar considers paragraphs and it probably makes sense for me to stick with that and separate other structures from paragraphs with a newline. So I did and my text to match is now:
After getting all that done, my project folder for Grav is shown on the right. My Vagrantfile is:
``` Vagrant.configure("2") do |config|
config.vm.box = "scotch/box" config.vm.network "private_network", ip: "192.168.33.10" config.vm.hostname = "scotchbox" config.vm.synced_folder ".", "/var/www", :mount_options => ["dmode=777", "fmode=666"]
end ```
When I'm ready to work, I open iTerm2 to `grav/public` and type `vagrant up`, wait a bit for Vagrant to do its thing and report that it's done, send my browser to `http://192.168.33.10%60, and go to town.
My use of Vagrant is at the low end of the complexity spectrum. There is so much more that Vagrant can do and I'm still moving slowly towards more advanced uses such as sharing the server across the local network so that other devices (my iPad and iPhone) can access the server. Or even sharing it across the Internet so that other people can see what I'm working on.
I switched the order of the inline and block raw rules and have this:
{ patterns = ( { name = 'source.yaml.front-matter'; begin = '\A-{3}'; end = '-{3}'; patterns = ( { include = 'source.yaml'; } ); }, { name = 'text.html.markdown.classes'; begin = '{'; end = '}'; }, { name = 'markup.raw.block.markdown'; begin = '^`{3}'; while = '^[^`{3}]|^\n'; }, { name = 'markup.raw.inline.markdown'; begin = ' `'; end = '`(?=[ .,;-=+])'; }, ); }
And I changed the injection selector to: L:(text.html.markdown $).
The raw block still begins correctly by finding and matching the first ```. But it still misses the second ``` and matches to the end of the document.
What else have I missed?
Bob ------------------- Robert J. Rockefeller Richmond Hill, GA www.bobrockefeller.com
With some coaching on the IRC, I got this working.
The trick, it appears, was a combination of using this Injection Selector: L:(text.html.markdown $)
along with this rule set (only markup.raw.* are important here):
{ patterns = ( { name = 'source.yaml.front-matter'; begin = '\A-{3}'; end = '-{3}'; patterns = ( { include = 'source.yaml'; } ); }, { name = 'text.html.markdown.classes'; begin = '{'; end = '}'; }, { name = 'markup.raw.block.markdown'; begin = '^`{3}'; end = '^`{3}'; }, { name = 'markup.raw.inline.markdown'; begin = ' `'; end = '`(?=[ .,;-=+])'; }, ); }
Bob ------------------- Robert J. Rockefeller Richmond Hill, GA www.bobrockefeller.com