Commit e6213acbcf26b2630dd2e11a1cb8d33881dd47d1

Golmote 2018-03-11T12:02:50

Add support for ERB. Fix #1318

diff --git a/components.js b/components.js
index 1510773..587ca83 100644
--- a/components.js
+++ b/components.js
@@ -224,6 +224,11 @@ var components = {
 			"title": "Elm",
 			"owner": "zwilias"
 		},
+		"erb": {
+			"title": "ERB",
+			"require": ["markup", "ruby"],
+			"owner": "Golmote"
+		},
 		"erlang": {
 			"title": "Erlang",
 			"owner": "Golmote"
diff --git a/components/prism-erb.js b/components/prism-erb.js
new file mode 100644
index 0000000..41f8763
--- /dev/null
+++ b/components/prism-erb.js
@@ -0,0 +1,67 @@
+(function (Prism) {
+
+	var erb_pattern = /<%=?[\s\S]+?%>/g;
+
+	Prism.languages.erb = Prism.languages.extend('markup', {
+		'erb': {
+			pattern: erb_pattern,
+			inside: {
+				'delimiter': {
+					pattern: /^<%=?|%>$/,
+					alias: 'punctuation'
+				},
+				rest: Prism.languages.ruby
+			}
+		}
+	});
+
+	// Tokenize all inline ERB expressions that are wrapped in <%= %>
+	// This allows for easy ERB + markup highlighting
+	Prism.hooks.add('before-highlight', function(env) {
+		if (env.language !== 'erb') {
+			return;
+		}
+
+		env.tokenStack = [];
+
+		env.backupCode = env.code;
+		env.code = env.code.replace(erb_pattern, function(match) {
+			var i = env.tokenStack.length;
+			// Check for existing strings
+			while (env.backupCode.indexOf('___ERB' + i + '___') !== -1)
+				++i;
+
+			// Create a sparse array
+			env.tokenStack[i] = match;
+
+			return '___ERB' + i + '___';
+		});
+	});
+
+	// Restore env.code for other plugins (e.g. line-numbers)
+	Prism.hooks.add('before-insert', function(env) {
+		if (env.language === 'erb') {
+			env.code = env.backupCode;
+			delete env.backupCode;
+		}
+	});
+
+	// Re-insert the tokens after highlighting
+	// and highlight them with defined grammar
+	Prism.hooks.add('after-highlight', function(env) {
+		if (env.language !== 'erb') {
+			return;
+		}
+
+		for (var i = 0, keys = Object.keys(env.tokenStack); i < keys.length; ++i) {
+			var k = keys[i];
+			var t = env.tokenStack[k];
+
+			// The replace prevents $$, $&, $`, $', $n, $nn from being interpreted as special patterns
+			env.highlightedCode = env.highlightedCode.replace('___ERB' + k + '___', Prism.highlight(t, env.grammar, 'erb').replace(/\$/g, '$$$$'));
+		}
+
+		env.element.innerHTML = env.highlightedCode;
+	});
+
+}(Prism));
\ No newline at end of file
diff --git a/components/prism-erb.min.js b/components/prism-erb.min.js
new file mode 100644
index 0000000..feac765
--- /dev/null
+++ b/components/prism-erb.min.js
@@ -0,0 +1 @@
+!function(e){var a=/<%=?[\s\S]+?%>/g;e.languages.erb=e.languages.extend("markup",{erb:{pattern:a,inside:{delimiter:{pattern:/^<%=?|%>$/,alias:"punctuation"},rest:e.languages.ruby}}}),e.hooks.add("before-highlight",function(e){"erb"===e.language&&(e.tokenStack=[],e.backupCode=e.code,e.code=e.code.replace(a,function(a){for(var t=e.tokenStack.length;-1!==e.backupCode.indexOf("___ERB"+t+"___");)++t;return e.tokenStack[t]=a,"___ERB"+t+"___"}))}),e.hooks.add("before-insert",function(e){"erb"===e.language&&(e.code=e.backupCode,delete e.backupCode)}),e.hooks.add("after-highlight",function(a){if("erb"===a.language){for(var t=0,n=Object.keys(a.tokenStack);t<n.length;++t){var o=n[t],r=a.tokenStack[o];a.highlightedCode=a.highlightedCode.replace("___ERB"+o+"___",e.highlight(r,a.grammar,"erb").replace(/\$/g,"$$$$"))}a.element.innerHTML=a.highlightedCode}})}(Prism);
\ No newline at end of file
diff --git a/components/prism-markup.js b/components/prism-markup.js
index 1dafd24..32b413a 100644
--- a/components/prism-markup.js
+++ b/components/prism-markup.js
@@ -4,7 +4,7 @@ Prism.languages.markup = {
 	'doctype': /<!DOCTYPE[\s\S]+?>/i,
 	'cdata': /<!\[CDATA\[[\s\S]*?]]>/i,
 	'tag': {
-		pattern: /<\/?(?!\d)[^\s>\/=$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+))?)*\s*\/?>/i,
+		pattern: /<\/?(?!\d)[^\s>\/=$<%]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+))?)*\s*\/?>/i,
 		inside: {
 			'tag': {
 				pattern: /^<\/?[^\s>\/]+/i,
diff --git a/components/prism-markup.min.js b/components/prism-markup.min.js
index 819b472..3627007 100644
--- a/components/prism-markup.min.js
+++ b/components/prism-markup.min.js
@@ -1 +1 @@
-Prism.languages.markup={comment:/<!--[\s\S]*?-->/,prolog:/<\?[\s\S]+?\?>/,doctype:/<!DOCTYPE[\s\S]+?>/i,cdata:/<!\[CDATA\[[\s\S]*?]]>/i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+)/i,inside:{punctuation:[/^=/,{pattern:/(^|[^\\])["']/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},Prism.languages.markup.tag.inside["attr-value"].inside.entity=Prism.languages.markup.entity,Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&amp;/,"&"))}),Prism.languages.xml=Prism.languages.markup,Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup;
\ No newline at end of file
+Prism.languages.markup={comment:/<!--[\s\S]*?-->/,prolog:/<\?[\s\S]+?\?>/,doctype:/<!DOCTYPE[\s\S]+?>/i,cdata:/<!\[CDATA\[[\s\S]*?]]>/i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+)/i,inside:{punctuation:[/^=/,{pattern:/(^|[^\\])["']/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},Prism.languages.markup.tag.inside["attr-value"].inside.entity=Prism.languages.markup.entity,Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&amp;/,"&"))}),Prism.languages.xml=Prism.languages.markup,Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup;
\ No newline at end of file
diff --git a/examples/prism-erb.html b/examples/prism-erb.html
new file mode 100644
index 0000000..46c0143
--- /dev/null
+++ b/examples/prism-erb.html
@@ -0,0 +1,22 @@
+<h2>Full example</h2>
+<pre><code>&lt;%# index.erb %>
+&lt;h1>Listing Books&lt;/h1>
+&lt;table>
+  &lt;tr>
+    &lt;th>Title&lt;/th>
+    &lt;th>Summary&lt;/th>
+    &lt;th>&lt;/th>
+    &lt;th>&lt;/th>
+    &lt;th>&lt;/th>
+  &lt;/tr>
+
+&lt;% @books.each do |book| %>
+  &lt;tr>
+    &lt;td>&lt;%= book.title %>&lt;/td>
+    &lt;td>&lt;%= book.content %>&lt;/td>
+    &lt;td>&lt;%= link_to "Show", book %>&lt;/td>
+    &lt;td>&lt;%= link_to "Edit", edit_book_path(book) %>&lt;/td>
+    &lt;td>&lt;%= link_to "Remove", book, method: :delete, data: { confirm: "Are you sure?" } %>&lt;/td>
+  &lt;/tr>
+&lt;% end %>
+&lt;/table></code></pre>
\ No newline at end of file
diff --git a/plugins/autoloader/prism-autoloader.js b/plugins/autoloader/prism-autoloader.js
index a401e09..a5926f7 100644
--- a/plugins/autoloader/prism-autoloader.js
+++ b/plugins/autoloader/prism-autoloader.js
@@ -4,7 +4,7 @@
 	}
 
 	// The dependencies map is built automatically with gulp
-	var lang_dependencies = /*languages_placeholder[*/{"javascript":"clike","actionscript":"javascript","arduino":"cpp","aspnet":"markup","bison":"c","c":"clike","csharp":"clike","cpp":"c","coffeescript":"javascript","crystal":"ruby","css-extras":"css","d":"clike","dart":"clike","django":"markup","fsharp":"clike","flow":"javascript","glsl":"clike","go":"clike","groovy":"clike","haml":"ruby","handlebars":"markup","haxe":"clike","java":"clike","jolie":"clike","kotlin":"clike","less":"css","markdown":"markup","n4js":"javascript","nginx":"clike","objectivec":"c","opencl":"cpp","parser":"markup","php":"clike","php-extras":"php","processing":"clike","protobuf":"clike","pug":"javascript","qore":"clike","jsx":["markup","javascript"],"tsx":["jsx","typescript"],"reason":"clike","ruby":"clike","sass":"css","scss":"css","scala":"java","smarty":"markup","swift":"clike","textile":"markup","twig":"markup","typescript":"javascript","vbnet":"basic","wiki":"markup","xeora":"markup"}/*]*/;
+	var lang_dependencies = /*languages_placeholder[*/{"javascript":"clike","actionscript":"javascript","arduino":"cpp","aspnet":"markup","bison":"c","c":"clike","csharp":"clike","cpp":"c","coffeescript":"javascript","crystal":"ruby","css-extras":"css","d":"clike","dart":"clike","django":"markup","erb":["markup","ruby"],"fsharp":"clike","flow":"javascript","glsl":"clike","go":"clike","groovy":"clike","haml":"ruby","handlebars":"markup","haxe":"clike","java":"clike","jolie":"clike","kotlin":"clike","less":"css","markdown":"markup","n4js":"javascript","nginx":"clike","objectivec":"c","opencl":"cpp","parser":"markup","php":"clike","php-extras":"php","processing":"clike","protobuf":"clike","pug":"javascript","qore":"clike","jsx":["markup","javascript"],"tsx":["jsx","typescript"],"reason":"clike","ruby":"clike","sass":"css","scss":"css","scala":"java","smarty":"markup","swift":"clike","textile":"markup","twig":"markup","typescript":"javascript","vbnet":"basic","wiki":"markup","xeora":"markup"}/*]*/;
 
 	var lang_data = {};
 
diff --git a/plugins/autoloader/prism-autoloader.min.js b/plugins/autoloader/prism-autoloader.min.js
index d51b6eb..154e6d4 100644
--- a/plugins/autoloader/prism-autoloader.min.js
+++ b/plugins/autoloader/prism-autoloader.min.js
@@ -1 +1 @@
-!function(){if("undefined"!=typeof self&&self.Prism&&self.document&&document.createElement){var e={javascript:"clike",actionscript:"javascript",arduino:"cpp",aspnet:"markup",bison:"c",c:"clike",csharp:"clike",cpp:"c",coffeescript:"javascript",crystal:"ruby","css-extras":"css",d:"clike",dart:"clike",django:"markup",fsharp:"clike",flow:"javascript",glsl:"clike",go:"clike",groovy:"clike",haml:"ruby",handlebars:"markup",haxe:"clike",java:"clike",jolie:"clike",kotlin:"clike",less:"css",markdown:"markup",n4js:"javascript",nginx:"clike",objectivec:"c",opencl:"cpp",parser:"markup",php:"clike","php-extras":"php",processing:"clike",protobuf:"clike",pug:"javascript",qore:"clike",jsx:["markup","javascript"],tsx:["jsx","typescript"],reason:"clike",ruby:"clike",sass:"css",scss:"css",scala:"java",smarty:"markup",swift:"clike",textile:"markup",twig:"markup",typescript:"javascript",vbnet:"basic",wiki:"markup",xeora:"markup"},a={},c="none",s=document.getElementsByTagName("script");s=s[s.length-1];var r="components/";if(s.hasAttribute("data-autoloader-path")){var t=s.getAttribute("data-autoloader-path").trim();t.length>0&&!/^[a-z]+:\/\//i.test(s.src)&&(r=t.replace(/\/?$/,"/"))}else/[\w-]+\.js$/.test(s.src)&&(r=s.src.replace(/[\w-]+\.js$/,"components/"));var n=Prism.plugins.autoloader={languages_path:r,use_minified:!0},s=function(e,a,c){var s=document.createElement("script");s.src=e,s.async=!0,s.onload=function(){document.body.removeChild(s),a&&a()},s.onerror=function(){document.body.removeChild(s),c&&c()},document.body.appendChild(s)},i=function(e){return n.languages_path+"prism-"+e+(n.use_minified?".min":"")+".js"},l=function(e,c){var s=a[e];s||(s=a[e]={});var r=c.getAttribute("data-dependencies");!r&&c.parentNode&&"pre"===c.parentNode.tagName.toLowerCase()&&(r=c.parentNode.getAttribute("data-dependencies")),r=r?r.split(/\s*,\s*/g):[],o(r,function(){p(e,function(){Prism.highlightElement(c)})})},o=function(e,a,c){"string"==typeof e&&(e=[e]);var s=0,r=e.length,t=function(){r>s?p(e[s],function(){s++,t()},function(){c&&c(e[s])}):s===r&&a&&a(e)};t()},p=function(c,r,t){var n=function(){var e=!1;c.indexOf("!")>=0&&(e=!0,c=c.replace("!",""));var n=a[c];if(n||(n=a[c]={}),r&&(n.success_callbacks||(n.success_callbacks=[]),n.success_callbacks.push(r)),t&&(n.error_callbacks||(n.error_callbacks=[]),n.error_callbacks.push(t)),!e&&Prism.languages[c])u(c);else if(!e&&n.error)k(c);else if(e||!n.loading){n.loading=!0;var l=i(c);s(l,function(){n.loading=!1,u(c)},function(){n.loading=!1,n.error=!0,k(c)})}},l=e[c];l&&l.length?o(l,n):n()},u=function(e){a[e]&&a[e].success_callbacks&&a[e].success_callbacks.length&&a[e].success_callbacks.forEach(function(a){a(e)})},k=function(e){a[e]&&a[e].error_callbacks&&a[e].error_callbacks.length&&a[e].error_callbacks.forEach(function(a){a(e)})};Prism.hooks.add("complete",function(e){e.element&&e.language&&!e.grammar&&e.language!==c&&l(e.language,e.element)})}}();
\ No newline at end of file
+!function(){if("undefined"!=typeof self&&self.Prism&&self.document&&document.createElement){var e={javascript:"clike",actionscript:"javascript",arduino:"cpp",aspnet:"markup",bison:"c",c:"clike",csharp:"clike",cpp:"c",coffeescript:"javascript",crystal:"ruby","css-extras":"css",d:"clike",dart:"clike",django:"markup",erb:["markup","ruby"],fsharp:"clike",flow:"javascript",glsl:"clike",go:"clike",groovy:"clike",haml:"ruby",handlebars:"markup",haxe:"clike",java:"clike",jolie:"clike",kotlin:"clike",less:"css",markdown:"markup",n4js:"javascript",nginx:"clike",objectivec:"c",opencl:"cpp",parser:"markup",php:"clike","php-extras":"php",processing:"clike",protobuf:"clike",pug:"javascript",qore:"clike",jsx:["markup","javascript"],tsx:["jsx","typescript"],reason:"clike",ruby:"clike",sass:"css",scss:"css",scala:"java",smarty:"markup",swift:"clike",textile:"markup",twig:"markup",typescript:"javascript",vbnet:"basic",wiki:"markup",xeora:"markup"},a={},c="none",r=document.getElementsByTagName("script");r=r[r.length-1];var s="components/";if(r.hasAttribute("data-autoloader-path")){var t=r.getAttribute("data-autoloader-path").trim();t.length>0&&!/^[a-z]+:\/\//i.test(r.src)&&(s=t.replace(/\/?$/,"/"))}else/[\w-]+\.js$/.test(r.src)&&(s=r.src.replace(/[\w-]+\.js$/,"components/"));var n=Prism.plugins.autoloader={languages_path:s,use_minified:!0},r=function(e,a,c){var r=document.createElement("script");r.src=e,r.async=!0,r.onload=function(){document.body.removeChild(r),a&&a()},r.onerror=function(){document.body.removeChild(r),c&&c()},document.body.appendChild(r)},i=function(e){return n.languages_path+"prism-"+e+(n.use_minified?".min":"")+".js"},l=function(e,c){var r=a[e];r||(r=a[e]={});var s=c.getAttribute("data-dependencies");!s&&c.parentNode&&"pre"===c.parentNode.tagName.toLowerCase()&&(s=c.parentNode.getAttribute("data-dependencies")),s=s?s.split(/\s*,\s*/g):[],o(s,function(){p(e,function(){Prism.highlightElement(c)})})},o=function(e,a,c){"string"==typeof e&&(e=[e]);var r=0,s=e.length,t=function(){s>r?p(e[r],function(){r++,t()},function(){c&&c(e[r])}):r===s&&a&&a(e)};t()},p=function(c,s,t){var n=function(){var e=!1;c.indexOf("!")>=0&&(e=!0,c=c.replace("!",""));var n=a[c];if(n||(n=a[c]={}),s&&(n.success_callbacks||(n.success_callbacks=[]),n.success_callbacks.push(s)),t&&(n.error_callbacks||(n.error_callbacks=[]),n.error_callbacks.push(t)),!e&&Prism.languages[c])u(c);else if(!e&&n.error)k(c);else if(e||!n.loading){n.loading=!0;var l=i(c);r(l,function(){n.loading=!1,u(c)},function(){n.loading=!1,n.error=!0,k(c)})}},l=e[c];l&&l.length?o(l,n):n()},u=function(e){a[e]&&a[e].success_callbacks&&a[e].success_callbacks.length&&a[e].success_callbacks.forEach(function(a){a(e)})},k=function(e){a[e]&&a[e].error_callbacks&&a[e].error_callbacks.length&&a[e].error_callbacks.forEach(function(a){a(e)})};Prism.hooks.add("complete",function(e){e.element&&e.language&&!e.grammar&&e.language!==c&&l(e.language,e.element)})}}();
\ No newline at end of file
diff --git a/plugins/show-language/prism-show-language.js b/plugins/show-language/prism-show-language.js
index e696274..aecc977 100644
--- a/plugins/show-language/prism-show-language.js
+++ b/plugins/show-language/prism-show-language.js
@@ -11,7 +11,7 @@ if (!Prism.plugins.toolbar) {
 }
 
 // The languages map is built automatically with gulp
-var Languages = /*languages_placeholder[*/{"html":"HTML","xml":"XML","svg":"SVG","mathml":"MathML","css":"CSS","clike":"C-like","javascript":"JavaScript","abap":"ABAP","actionscript":"ActionScript","apacheconf":"Apache Configuration","apl":"APL","applescript":"AppleScript","arff":"ARFF","asciidoc":"AsciiDoc","asm6502":"6502 Assembly","aspnet":"ASP.NET (C#)","autohotkey":"AutoHotkey","autoit":"AutoIt","basic":"BASIC","csharp":"C#","cpp":"C++","coffeescript":"CoffeeScript","csp":"Content-Security-Policy","css-extras":"CSS Extras","django":"Django/Jinja2","fsharp":"F#","glsl":"GLSL","graphql":"GraphQL","http":"HTTP","hpkp":"HTTP Public-Key-Pins","hsts":"HTTP Strict-Transport-Security","ichigojam":"IchigoJam","inform7":"Inform 7","json":"JSON","latex":"LaTeX","livescript":"LiveScript","lolcode":"LOLCODE","matlab":"MATLAB","mel":"MEL","n4js":"N4JS","nasm":"NASM","nginx":"nginx","nsis":"NSIS","objectivec":"Objective-C","ocaml":"OCaml","opencl":"OpenCL","parigp":"PARI/GP","php":"PHP","php-extras":"PHP Extras","powershell":"PowerShell","properties":".properties","protobuf":"Protocol Buffers","q":"Q (kdb+ database)","jsx":"React JSX","tsx":"React TSX","renpy":"Ren'py","rest":"reST (reStructuredText)","sas":"SAS","sass":"Sass (Sass)","scss":"Sass (Scss)","sql":"SQL","typescript":"TypeScript","vbnet":"VB.Net","vhdl":"VHDL","vim":"vim","wiki":"Wiki markup","xojo":"Xojo (REALbasic)","yaml":"YAML"}/*]*/;
+var Languages = /*languages_placeholder[*/{"html":"HTML","xml":"XML","svg":"SVG","mathml":"MathML","css":"CSS","clike":"C-like","javascript":"JavaScript","abap":"ABAP","actionscript":"ActionScript","apacheconf":"Apache Configuration","apl":"APL","applescript":"AppleScript","arff":"ARFF","asciidoc":"AsciiDoc","asm6502":"6502 Assembly","aspnet":"ASP.NET (C#)","autohotkey":"AutoHotkey","autoit":"AutoIt","basic":"BASIC","csharp":"C#","cpp":"C++","coffeescript":"CoffeeScript","csp":"Content-Security-Policy","css-extras":"CSS Extras","django":"Django/Jinja2","erb":"ERB","fsharp":"F#","glsl":"GLSL","graphql":"GraphQL","http":"HTTP","hpkp":"HTTP Public-Key-Pins","hsts":"HTTP Strict-Transport-Security","ichigojam":"IchigoJam","inform7":"Inform 7","json":"JSON","latex":"LaTeX","livescript":"LiveScript","lolcode":"LOLCODE","matlab":"MATLAB","mel":"MEL","n4js":"N4JS","nasm":"NASM","nginx":"nginx","nsis":"NSIS","objectivec":"Objective-C","ocaml":"OCaml","opencl":"OpenCL","parigp":"PARI/GP","php":"PHP","php-extras":"PHP Extras","powershell":"PowerShell","properties":".properties","protobuf":"Protocol Buffers","q":"Q (kdb+ database)","jsx":"React JSX","tsx":"React TSX","renpy":"Ren'py","rest":"reST (reStructuredText)","sas":"SAS","sass":"Sass (Sass)","scss":"Sass (Scss)","sql":"SQL","typescript":"TypeScript","vbnet":"VB.Net","vhdl":"VHDL","vim":"vim","wiki":"Wiki markup","xojo":"Xojo (REALbasic)","yaml":"YAML"}/*]*/;
 Prism.plugins.toolbar.registerButton('show-language', function(env) {
 	var pre = env.element.parentNode;
 	if (!pre || !/pre/i.test(pre.nodeName)) {
diff --git a/plugins/show-language/prism-show-language.min.js b/plugins/show-language/prism-show-language.min.js
index 9965a39..4b0952f 100644
--- a/plugins/show-language/prism-show-language.min.js
+++ b/plugins/show-language/prism-show-language.min.js
@@ -1 +1 @@
-!function(){if("undefined"!=typeof self&&self.Prism&&self.document){if(!Prism.plugins.toolbar)return console.warn("Show Languages plugin loaded before Toolbar plugin."),void 0;var e={html:"HTML",xml:"XML",svg:"SVG",mathml:"MathML",css:"CSS",clike:"C-like",javascript:"JavaScript",abap:"ABAP",actionscript:"ActionScript",apacheconf:"Apache Configuration",apl:"APL",applescript:"AppleScript",arff:"ARFF",asciidoc:"AsciiDoc",asm6502:"6502 Assembly",aspnet:"ASP.NET (C#)",autohotkey:"AutoHotkey",autoit:"AutoIt",basic:"BASIC",csharp:"C#",cpp:"C++",coffeescript:"CoffeeScript",csp:"Content-Security-Policy","css-extras":"CSS Extras",django:"Django/Jinja2",fsharp:"F#",glsl:"GLSL",graphql:"GraphQL",http:"HTTP",hpkp:"HTTP Public-Key-Pins",hsts:"HTTP Strict-Transport-Security",ichigojam:"IchigoJam",inform7:"Inform 7",json:"JSON",latex:"LaTeX",livescript:"LiveScript",lolcode:"LOLCODE",matlab:"MATLAB",mel:"MEL",n4js:"N4JS",nasm:"NASM",nginx:"nginx",nsis:"NSIS",objectivec:"Objective-C",ocaml:"OCaml",opencl:"OpenCL",parigp:"PARI/GP",php:"PHP","php-extras":"PHP Extras",powershell:"PowerShell",properties:".properties",protobuf:"Protocol Buffers",q:"Q (kdb+ database)",jsx:"React JSX",tsx:"React TSX",renpy:"Ren'py",rest:"reST (reStructuredText)",sas:"SAS",sass:"Sass (Sass)",scss:"Sass (Scss)",sql:"SQL",typescript:"TypeScript",vbnet:"VB.Net",vhdl:"VHDL",vim:"vim",wiki:"Wiki markup",xojo:"Xojo (REALbasic)",yaml:"YAML"};Prism.plugins.toolbar.registerButton("show-language",function(t){var a=t.element.parentNode;if(a&&/pre/i.test(a.nodeName)){var s=a.getAttribute("data-language")||e[t.language]||t.language.substring(0,1).toUpperCase()+t.language.substring(1),i=document.createElement("span");return i.textContent=s,i}})}}();
\ No newline at end of file
+!function(){if("undefined"!=typeof self&&self.Prism&&self.document){if(!Prism.plugins.toolbar)return console.warn("Show Languages plugin loaded before Toolbar plugin."),void 0;var e={html:"HTML",xml:"XML",svg:"SVG",mathml:"MathML",css:"CSS",clike:"C-like",javascript:"JavaScript",abap:"ABAP",actionscript:"ActionScript",apacheconf:"Apache Configuration",apl:"APL",applescript:"AppleScript",arff:"ARFF",asciidoc:"AsciiDoc",asm6502:"6502 Assembly",aspnet:"ASP.NET (C#)",autohotkey:"AutoHotkey",autoit:"AutoIt",basic:"BASIC",csharp:"C#",cpp:"C++",coffeescript:"CoffeeScript",csp:"Content-Security-Policy","css-extras":"CSS Extras",django:"Django/Jinja2",erb:"ERB",fsharp:"F#",glsl:"GLSL",graphql:"GraphQL",http:"HTTP",hpkp:"HTTP Public-Key-Pins",hsts:"HTTP Strict-Transport-Security",ichigojam:"IchigoJam",inform7:"Inform 7",json:"JSON",latex:"LaTeX",livescript:"LiveScript",lolcode:"LOLCODE",matlab:"MATLAB",mel:"MEL",n4js:"N4JS",nasm:"NASM",nginx:"nginx",nsis:"NSIS",objectivec:"Objective-C",ocaml:"OCaml",opencl:"OpenCL",parigp:"PARI/GP",php:"PHP","php-extras":"PHP Extras",powershell:"PowerShell",properties:".properties",protobuf:"Protocol Buffers",q:"Q (kdb+ database)",jsx:"React JSX",tsx:"React TSX",renpy:"Ren'py",rest:"reST (reStructuredText)",sas:"SAS",sass:"Sass (Sass)",scss:"Sass (Scss)",sql:"SQL",typescript:"TypeScript",vbnet:"VB.Net",vhdl:"VHDL",vim:"vim",wiki:"Wiki markup",xojo:"Xojo (REALbasic)",yaml:"YAML"};Prism.plugins.toolbar.registerButton("show-language",function(t){var a=t.element.parentNode;if(a&&/pre/i.test(a.nodeName)){var s=a.getAttribute("data-language")||e[t.language]||t.language.substring(0,1).toUpperCase()+t.language.substring(1),i=document.createElement("span");return i.textContent=s,i}})}}();
\ No newline at end of file
diff --git a/prism.js b/prism.js
index edff729..df45ab4 100644
--- a/prism.js
+++ b/prism.js
@@ -554,7 +554,7 @@ Prism.languages.markup = {
 	'doctype': /<!DOCTYPE[\s\S]+?>/i,
 	'cdata': /<!\[CDATA\[[\s\S]*?]]>/i,
 	'tag': {
-		pattern: /<\/?(?!\d)[^\s>\/=$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+))?)*\s*\/?>/i,
+		pattern: /<\/?(?!\d)[^\s>\/=$<%]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+))?)*\s*\/?>/i,
 		inside: {
 			'tag': {
 				pattern: /^<\/?[^\s>\/]+/i,
diff --git a/tests/languages/erb/erb_feature.test b/tests/languages/erb/erb_feature.test
new file mode 100644
index 0000000..cb86983
--- /dev/null
+++ b/tests/languages/erb/erb_feature.test
@@ -0,0 +1,36 @@
+<%# comment %>
+<%= render @products || "empty_list" %>
+<% @books.each do |book| %>
+
+----------------------------------------------------
+
+[
+	["erb", [
+		["delimiter", "<%"],
+		["comment", "# comment "],
+		["delimiter", "%>"]
+	]],
+	["erb", [
+		["delimiter", "<%="],
+		" render ",
+		["variable", "@products"],
+		["operator", "||"],
+		["string", ["\"empty_list\""]],
+		["delimiter", "%>"]
+	]],
+	["erb", [
+		["delimiter", "<%"],
+		["variable", "@books"],
+		["punctuation", "."],
+		["keyword", "each"],
+		["keyword", "do"],
+		["operator", "|"],
+		"book",
+		["operator", "|"],
+		["delimiter", "%>"]
+	]]
+]
+
+----------------------------------------------------
+
+Checks for ERB tags.
\ No newline at end of file
diff --git a/tests/languages/erb/erb_in_markup_feature.js b/tests/languages/erb/erb_in_markup_feature.js
new file mode 100644
index 0000000..a373d31
--- /dev/null
+++ b/tests/languages/erb/erb_in_markup_feature.js
@@ -0,0 +1,4 @@
+module.exports = {
+	'<div class="<%= Time.now.strftime(\'%A\') %>">': '<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span><span class="token erb"><span class="token delimiter punctuation">&lt;%=</span> <span class="token builtin">Time</span><span class="token punctuation">.</span>now<span class="token punctuation">.</span><span class="token function">strftime</span><span class="token punctuation">(</span><span class="token string">\'%A\'</span><span class="token punctuation">)</span> <span class="token delimiter punctuation">%></span></span><span class="token punctuation">"</span></span><span class="token punctuation">></span></span>',
+	'__ERB1__<%= 1 %>__ERB2__<%= 2 %>': '__ERB1__<span class="token erb"><span class="token delimiter punctuation">&lt;%=</span> <span class="token number">1</span> <span class="token delimiter punctuation">%></span></span>__ERB2__<span class="token erb"><span class="token delimiter punctuation">&lt;%=</span> <span class="token number">2</span> <span class="token delimiter punctuation">%></span></span>'
+};
\ No newline at end of file