diff --git a/modules/jooby-whoops/NOTE.md b/modules/jooby-whoops/NOTE.md
index c83cc5abb8..3bf6559a96 100644
--- a/modules/jooby-whoops/NOTE.md
+++ b/modules/jooby-whoops/NOTE.md
@@ -1,9 +1,9 @@
To make a new release:
-- https://github.com/filp/whoops/releases
-- This repo used 2.7.1
+- https://github.com/filp/whoops/tags
+- This repo used 2.15.4
- Unzip the release
-- copy to test/resources/whoops/views
+- copy *.php files to test/resources/whoops/views
- Run GenerateHTML
- Verify all php lines were converted (manually)
- Run WhoopsTest
diff --git a/modules/jooby-whoops/pom.xml b/modules/jooby-whoops/pom.xml
index 5c9651a214..fcb3ed0122 100644
--- a/modules/jooby-whoops/pom.xml
+++ b/modules/jooby-whoops/pom.xml
@@ -25,6 +25,12 @@
true
+
+ org.unbescape
+ unbescape
+ 1.1.6.RELEASE
+
+
org.junit.jupiter
@@ -85,10 +91,15 @@
true
+
io.pebbletemplates:pebble
+
+
+
+
io.pebbletemplates.pebble
io.jooby.internal.pebble
diff --git a/modules/jooby-whoops/src/main/java/module-info.java b/modules/jooby-whoops/src/main/java/module-info.java
index df3275ee34..b83bb3d219 100644
--- a/modules/jooby-whoops/src/main/java/module-info.java
+++ b/modules/jooby-whoops/src/main/java/module-info.java
@@ -11,6 +11,7 @@
requires static com.github.spotbugs.annotations;
requires typesafe.config;
requires org.slf4j;
+ requires unbescape;
// SHADED: All content after this line will be removed at build time
requires static io.pebbletemplates;
diff --git a/modules/jooby-whoops/src/main/resources/io/jooby/whoops/css/prism.css b/modules/jooby-whoops/src/main/resources/io/jooby/whoops/css/prism.css
new file mode 100644
index 0000000000..a03db53d48
--- /dev/null
+++ b/modules/jooby-whoops/src/main/resources/io/jooby/whoops/css/prism.css
@@ -0,0 +1,5 @@
+/* PrismJS 1.29.0
+https://prismjs.com/download.html#themes=prism-tomorrow&languages=markup+markup-templating+php&plugins=line-highlight+line-numbers */
+code[class*=language-],pre[class*=language-]{color:#ccc;background:0 0;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#2d2d2d}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.block-comment,.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#999}.token.punctuation{color:#ccc}.token.attr-name,.token.deleted,.token.namespace,.token.tag{color:#e2777a}.token.function-name{color:#6196cc}.token.boolean,.token.function,.token.number{color:#f08d49}.token.class-name,.token.constant,.token.property,.token.symbol{color:#f8c555}.token.atrule,.token.builtin,.token.important,.token.keyword,.token.selector{color:#cc99cd}.token.attr-value,.token.char,.token.regex,.token.string,.token.variable{color:#7ec699}.token.entity,.token.operator,.token.url{color:#67cdcc}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.inserted{color:green}
+pre[data-line]{position:relative;padding:1em 0 1em 3em}.line-highlight{position:absolute;left:0;right:0;padding:inherit 0;margin-top:1em;background:hsla(24,20%,50%,.08);background:linear-gradient(to right,hsla(24,20%,50%,.1) 70%,hsla(24,20%,50%,0));pointer-events:none;line-height:inherit;white-space:pre}@media print{.line-highlight{-webkit-print-color-adjust:exact;color-adjust:exact}}.line-highlight:before,.line-highlight[data-end]:after{content:attr(data-start);position:absolute;top:.4em;left:.6em;min-width:1em;padding:0 .5em;background-color:hsla(24,20%,50%,.4);color:#f4f1ef;font:bold 65%/1.5 sans-serif;text-align:center;vertical-align:.3em;border-radius:999px;text-shadow:none;box-shadow:0 1px #fff}.line-highlight[data-end]:after{content:attr(data-end);top:auto;bottom:.4em}.line-numbers .line-highlight:after,.line-numbers .line-highlight:before{content:none}pre[id].linkable-line-numbers span.line-numbers-rows{pointer-events:all}pre[id].linkable-line-numbers span.line-numbers-rows>span:before{cursor:pointer}pre[id].linkable-line-numbers span.line-numbers-rows>span:hover:before{background-color:rgba(128,128,128,.2)}
+pre[class*=language-].line-numbers{position:relative;padding-left:3.8em;counter-reset:linenumber}pre[class*=language-].line-numbers>code{position:relative;white-space:inherit}.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:0;font-size:100%;left:-3.8em;width:3em;letter-spacing:-1px;border-right:1px solid #999;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.line-numbers-rows>span{display:block;counter-increment:linenumber}.line-numbers-rows>span:before{content:counter(linenumber);color:#999;display:block;padding-right:.8em;text-align:right}
diff --git a/modules/jooby-whoops/src/main/resources/io/jooby/whoops/css/whoops.base.css b/modules/jooby-whoops/src/main/resources/io/jooby/whoops/css/whoops.base.css
index d67499e11e..edd5cd8ec8 100644
--- a/modules/jooby-whoops/src/main/resources/io/jooby/whoops/css/whoops.base.css
+++ b/modules/jooby-whoops/src/main/resources/io/jooby/whoops/css/whoops.base.css
@@ -290,13 +290,12 @@ header {
border-radius: 6px;
background-color: rgba(255, 255, 255, .05);
}
- .frame-comment a {
- font-weight: bold;
- text-decoration: none;
- }
- .frame-comment a:hover {
- color: #4bb1b1;
- }
+
+ .frame-comment a {
+ font-weight: bold;
+ text-decoration: underline;
+ color: #c6c6c6;
+ }
.frame-comment:not(:last-child) {
border-bottom: 1px dotted rgba(0, 0, 0, .3);
@@ -372,49 +371,6 @@ header {
font: 14px "Inconsolata", "Fira Mono", "Source Code Pro", Monaco, Consolas, "Lucida Console", monospace;
}
-/* prettify code style
-Uses the Doxy theme as a base */
-pre .str, code .str { color: #BCD42A; } /* string */
-pre .kwd, code .kwd { color: #4bb1b1; font-weight: bold; } /* keyword*/
-pre .com, code .com { color: #888; font-weight: bold; } /* comment */
-pre .typ, code .typ { color: #ef7c61; } /* type */
-pre .lit, code .lit { color: #BCD42A; } /* literal */
-pre .pun, code .pun { color: #fff; font-weight: bold; } /* punctuation */
-pre .pln, code .pln { color: #e9e4e5; } /* plaintext */
-pre .tag, code .tag { color: #4bb1b1; } /* html/xml tag */
-pre .htm, code .htm { color: #dda0dd; } /* html tag */
-pre .xsl, code .xsl { color: #d0a0d0; } /* xslt tag */
-pre .atn, code .atn { color: #ef7c61; font-weight: normal;} /* html/xml attribute name */
-pre .atv, code .atv { color: #bcd42a; } /* html/xml attribute value */
-pre .dec, code .dec { color: #606; } /* decimal */
-pre.code-block, code.code-block, .frame-args.code-block, .frame-args.code-block samp {
- font-family: "Inconsolata", "Fira Mono", "Source Code Pro", Monaco, Consolas, "Lucida Console", monospace;
- background: #333;
- color: #e9e4e5;
-}
- pre.code-block {
- white-space: pre-wrap;
- }
-
- pre.code-block a, code.code-block a {
- text-decoration:none;
- }
-
- .linenums li {
- color: #A5A5A5;
- }
-
- .linenums li.current{
- background: rgba(255, 100, 100, .07);
- }
- .linenums li.current.active {
- background: rgba(255, 100, 100, .17);
- }
-
-pre:not(.prettyprinted) {
- padding-left: 60px;
-}
-
#plain-exception {
display: none;
}
diff --git a/modules/jooby-whoops/src/main/resources/io/jooby/whoops/js/prettify.min.js b/modules/jooby-whoops/src/main/resources/io/jooby/whoops/js/prettify.min.js
deleted file mode 100644
index 4827bc3f90..0000000000
--- a/modules/jooby-whoops/src/main/resources/io/jooby/whoops/js/prettify.min.js
+++ /dev/null
@@ -1,28 +0,0 @@
-var r=null;window.PR_SHOULD_USE_CONTINUATION=!0;
-(function(){function O(a){function i(d){var a=d.charCodeAt(0);if(a!==92)return a;var f=d.charAt(1);return(a=s[f])?a:"0"<=f&&f<="7"?parseInt(d.substring(1),8):f==="u"||f==="x"?parseInt(d.substring(2),16):d.charCodeAt(1)}function g(d){if(d<32)return(d<16?"\\x0":"\\x")+d.toString(16);d=String.fromCharCode(d);return d==="\\"||d==="-"||d==="]"||d==="^"?"\\"+d:d}function j(d){var a=d.substring(1,d.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),d=[],f=
-a[0]==="^",b=["["];f&&b.push("^");for(var f=f?1:0,c=a.length;f122||(e<65||h>90||d.push([Math.max(65,h)|32,Math.min(e,90)|32]),e<97||h>122||d.push([Math.max(97,h)&-33,Math.min(e,122)&-33]))}}d.sort(function(d,a){return d[0]-a[0]||a[1]-d[1]});a=[];c=[];for(f=0;fh[0]&&(h[1]+1>h[0]&&b.push("-"),b.push(g(h[1])));b.push("]");return b.join("")}function t(d){for(var a=d.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=a.length,i=[],c=0,h=0;c=2&&d==="["?a[c]=j(e):d!=="\\"&&(a[c]=e.replace(/[A-Za-z]/g,function(d){d=d.charCodeAt(0);return"["+String.fromCharCode(d&-33,d|32)+"]"}));return a.join("")}for(var z=0,w=!1,k=!1,m=0,b=a.length;m=5&&"lang-"===f.substring(0,
-5))&&!(u&&typeof u[1]==="string"))c=!1,f="src";c||(s[v]=f)}h=b;b+=v.length;if(c){c=u[1];var e=v.indexOf(c),p=e+c.length;u[2]&&(p=v.length-u[2].length,e=p-c.length);f=f.substring(5);E(k+h,v.substring(0,e),g,m);E(k+h+e,c,F(f,c),m);E(k+h+p,v.substring(p),g,m)}else m.push(k+h,f)}a.g=m}var j={},t;(function(){for(var g=a.concat(i),k=[],m={},b=0,o=g.length;b=0;)j[q.charAt(d)]=s;s=s[1];q=""+s;m.hasOwnProperty(q)||(k.push(s),m[q]=r)}k.push(/[\S\s]/);t=
-O(k)})();var z=i.length;return g}function l(a){var i=[],g=[];a.tripleQuotedStrings?i.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,r,"'\""]):a.multiLineStrings?i.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,r,"'\"`"]):i.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,r,"\"'"]);a.verbatimStrings&&
-g.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,r]);var j=a.hashComments;j&&(a.cStyleComments?(j>1?i.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,r,"#"]):i.push(["com",/^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\n\r]*)/,r,"#"]),g.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,r])):i.push(["com",/^#[^\n\r]*/,r,"#"]));a.cStyleComments&&(g.push(["com",/^\/\/[^\n\r]*/,r]),g.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,
-r]));a.regexLiterals&&g.push(["lang-regex",/^(?:^^\.?|[+-]|[!=]={0,2}|#|%=?|&&?=?|\(|\*=?|[+-]=|->|\/=?|::?|<=?|>{1,3}=?|[,;?@[{~]|\^\^?=?|\|\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(j=a.types)&&g.push(["typ",j]);a=(""+a.keywords).replace(/^ | $/g,"");a.length&&g.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),r]);i.push(["pln",/^\s+/,r," \r\n\t\u00a0"]);g.push(["lit",
-/^@[$_a-z][\w$@]*/i,r],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,r],["pln",/^[$_a-z][\w$@]*/i,r],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,r,"0123456789"],["pln",/^\\[\S\s]?/,r],["pun",/^.[^\s\w"$'./@\\`]*/,r]);return x(i,g)}function G(a,i,g){function j(a){switch(a.nodeType){case 1:if(z.test(a.className))break;if("br"===a.nodeName)t(a),a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)j(a);break;case 3:case 4:if(g){var b=
-a.nodeValue,f=b.match(n);if(f){var i=b.substring(0,f.index);a.nodeValue=i;(b=b.substring(f.index+f[0].length))&&a.parentNode.insertBefore(k.createTextNode(b),a.nextSibling);t(a);i||a.parentNode.removeChild(a)}}}}function t(a){function i(a,b){var d=b?a.cloneNode(!1):a,e=a.parentNode;if(e){var e=i(e,1),f=a.nextSibling;e.appendChild(d);for(var g=f;g;g=f)f=g.nextSibling,e.appendChild(g)}return d}for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=i(a.nextSibling,0),f;(f=a.parentNode)&&f.nodeType===
-1;)a=f;b.push(a)}for(var z=/(?:^|\s)nocode(?:\s|$)/,n=/\r\n?|\n/,k=a.ownerDocument,m=k.createElement("li");a.firstChild;)m.appendChild(a.firstChild);for(var b=[m],o=0;o=0;){var j=
-i[g];A.hasOwnProperty(j)?C.console&&console.warn("cannot override language handler %s",j):A[j]=a}}function F(a,i){if(!a||!A.hasOwnProperty(a))a=/^\s*=e&&(j+=2);g>=p&&(s+=2)}}finally{if(c)c.style.display=h}}catch(A){C.console&&console.log(A&&A.stack?A.stack:A)}}var C=window,y=["break,continue,do,else,for,if,return,while"],B=[[y,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],I=[B,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],
-J=[B,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],K=[J,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,let,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var,virtual,where"],B=[B,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],
-L=[y,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],M=[y,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],y=[y,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],N=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/,
-Q=/\S/,R=l({keywords:[I,K,B,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+L,M,y],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};n(R,["default-code"]);n(x([],[["pln",/^[^]+/],["dec",/^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",
-/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^
+
diff --git a/modules/jooby-whoops/src/test/resources/whoops/views/frame_code.html.php b/modules/jooby-whoops/src/test/resources/whoops/views/frame_code.html.php
index b7717d7a39..fd3d930e3c 100644
--- a/modules/jooby-whoops/src/test/resources/whoops/views/frame_code.html.php
+++ b/modules/jooby-whoops/src/test/resources/whoops/views/frame_code.html.php
@@ -29,7 +29,11 @@
$start = key($range) + 1;
$code = join("\n", $range);
?>
- escape($code) ?>
+ escape($code) ?>
diff --git a/modules/jooby-whoops/src/test/resources/whoops/views/layout.html.php b/modules/jooby-whoops/src/test/resources/whoops/views/layout.html.php
index 6b676cc6dd..7ad15eaedf 100644
--- a/modules/jooby-whoops/src/test/resources/whoops/views/layout.html.php
+++ b/modules/jooby-whoops/src/test/resources/whoops/views/layout.html.php
@@ -12,6 +12,7 @@
escape($page_title) ?>
+
@@ -25,7 +26,7 @@
-
+