Skip to content

Commit

Permalink
Merge pull request #294 from Mingun/show-errors
Browse files Browse the repository at this point in the history
Website: show errors in editors
  • Loading branch information
hildjj authored Jun 12, 2022
2 parents 48585a5 + be9425d commit 6532a1e
Show file tree
Hide file tree
Showing 5 changed files with 468 additions and 73 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ Released: TBD
- [#206](https://github.com/peggyjs/peggy/pull/206): New output type `ast` and
an `--ast` flag for the CLI to get an internal grammar AST for investigation
(can be useful for plugin writers), from @Mingun
- [#294](https://github.com/peggyjs/peggy/pull/294) Website: show errors in the
editors, from @Mingun

### Bug Fixes

Expand Down
167 changes: 94 additions & 73 deletions docs/js/online.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,62 @@ $(document).ready(function() {
var parser;
var parserSource = null;

var buildAndParseTimer = null;
var parseTimer = null;

var oldGrammar = null;
var oldParserVar = null;
var oldOptionCache = null;
var oldInput = null;

var editor = CodeMirror.fromTextArea($("#grammar").get(0), {
lineNumbers: true,
mode: "pegjs"
mode: "pegjs",
gutters: ["CodeMirror-lint-markers"],
lint: true,
});
var input = CodeMirror.fromTextArea($("#input").get(0), {
lineNumbers: true,
mode: null,
gutters: ["CodeMirror-lint-markers"],
lint: true,
});

CodeMirror.registerHelper("lint", "pegjs", function(grammar) {
var problems = [];
buildAndParse(grammar, problems);
return problems;
});

CodeMirror.registerHelper("lint", null, function(content) {
var problems = [];
parse(content, problems);
return problems;
});

function convertLocation(location) {
return CodeMirror.Pos(location.line - 1, location.column - 1);
}

function convertError(e, problems) {
if (e.location !== undefined) {
problems.push({
severity: "error",
message: e.message,
from: convertLocation(e.location.start),
to: convertLocation(e.location.end),
});
} else {
problems.push({
severity: "error",
message: e.message,
});
}
if (e.diagnostics !== undefined) {
for (var i = 0; i < e.diagnostics.length; ++i) {
var d = e.diagnostics[i];
problems.push({
severity: "warning",
message: d.message,
from: convertLocation(d.location.start),
to: convertLocation(d.location.end),
});
}
}
}

function buildSizeAndTimeInfoHtml(title, size, time) {
return $("<span/>", {
"class": "size-and-time",
Expand All @@ -37,11 +77,16 @@ $(document).ready(function() {
: e.message;
}

function build() {
oldGrammar = getGrammar();
oldParserVar = $("#parser-var").val();
oldOptionCache = $("#option-cache").is(":checked");

/**
* Generates code from the parser, collects problems in `problems` in CodeMirror
* lint format.
*
* @param {string} grammar Grammar text
* @param {CodeMirror.lint.Annotation[]} problems List of problems of current
* grammar that editor should show
* @returns {string} Source code of the parser
*/
function build(grammar, problems) {
$('#build-message').attr("class", "message progress").text("Building the parser...");
$("#input").attr("disabled", "disabled");
$("#parse-message").attr("class", "message disabled").text("Parser not available.");
Expand All @@ -52,9 +97,26 @@ $(document).ready(function() {

try {
var timeBefore = (new Date).getTime();
parserSource = peggy.generate(getGrammar(), {
parserSource = peggy.generate(grammar, {
cache: $("#option-cache").is(":checked"),
output: "source"
output: "source",

error: function(_stage, message, location) {
problems.push({
severity: "error",
message: message,
from: convertLocation(location.start),
to: convertLocation(location.end),
});
},
warn: function(_stage, message, location) {
problems.push({
severity: "warning",
message: message,
from: convertLocation(location.start),
to: convertLocation(location.end),
});
},
});
var timeAfter = (new Date).getTime();

Expand All @@ -65,7 +127,7 @@ $(document).ready(function() {
.html("Parser built successfully.")
.append(buildSizeAndTimeInfoHtml(
"Parser build time and speed",
getGrammar().length,
grammar.length,
timeAfter - timeBefore
));
$("#input").removeAttr("disabled");
Expand All @@ -75,6 +137,7 @@ $(document).ready(function() {

var result = true;
} catch (e) {
convertError(e, problems);
$("#build-message").attr("class", "message error").text(buildErrorMessage(e));

var result = false;
Expand All @@ -84,15 +147,12 @@ $(document).ready(function() {
return result;
}

function parse() {
oldInput = input.getValue();

function parse(newInput, problems) {
$("#input").removeAttr("disabled");
$("#parse-message").attr("class", "message progress").text("Parsing the input...");
$("#output").addClass("disabled").text("Output not available.");

try {
var newInput = input.getValue();
var timeBefore = (new Date).getTime();
var output = parser.parse(newInput);
var timeAfter = (new Date).getTime();
Expand All @@ -109,6 +169,7 @@ $(document).ready(function() {

var result = true;
} catch (e) {
convertError(e, problems);
$("#parse-message").attr("class", "message error").text(buildErrorMessage(e));

var result = false;
Expand All @@ -118,44 +179,12 @@ $(document).ready(function() {
return result;
}

function buildAndParse() {
build() && parse();
}

function scheduleBuildAndParse() {
var nothingChanged = getGrammar() === oldGrammar
&& $("#parser-var").val() === oldParserVar
&& $("#option-cache").is(":checked") === oldOptionCache;
if (nothingChanged) { return; }

if (buildAndParseTimer !== null) {
clearTimeout(buildAndParseTimer);
buildAndParseTimer = null;
}
if (parseTimer !== null) {
clearTimeout(parseTimer);
parseTimer = null;
}

buildAndParseTimer = setTimeout(function() {
buildAndParse();
buildAndParseTimer = null;
}, 500);
function buildAndParse(grammar, problems) {
build(grammar, problems) && parse(input.getValue(), []);
}

function scheduleParse() {
if (input.getValue() === oldInput) { return; }
if (buildAndParseTimer !== null) { return; }

if (parseTimer !== null) {
clearTimeout(parseTimer);
parseTimer = null;
}

parseTimer = setTimeout(function() {
parse();
parseTimer = null;
}, 500);
function rebuildGrammar() {
buildAndParse(editor.getValue(), []);
}

function doLayout() {
Expand All @@ -177,22 +206,14 @@ $(document).ready(function() {
}
}

function getGrammar() {
return editor.getValue();
}

editor.on("change", scheduleBuildAndParse);

$("#parser-var, #option-cache")
.change(scheduleBuildAndParse)
.mousedown(scheduleBuildAndParse)
.mouseup(scheduleBuildAndParse)
.click(scheduleBuildAndParse)
.keydown(scheduleBuildAndParse)
.keyup(scheduleBuildAndParse)
.keypress(scheduleBuildAndParse);

input.on("change", scheduleParse);
.change(rebuildGrammar)
.mousedown(rebuildGrammar)
.mouseup(rebuildGrammar)
.click(rebuildGrammar)
.keydown(rebuildGrammar)
.keyup(rebuildGrammar)
.keypress(rebuildGrammar);

$( "#parser-download" )
.click(function(){
Expand All @@ -210,7 +231,7 @@ $(document).ready(function() {

$("#grammar, #parser-var, #option-cache").removeAttr("disabled");

buildAndParse();
rebuildGrammar();

editor.refresh();
editor.focus();
Expand Down
2 changes: 2 additions & 0 deletions docs/online.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
</script>
<![endif]-->
<link rel="stylesheet" href="vendor/codemirror/codemirror.css">
<link rel="stylesheet" href="vendor/codemirror/lint.css">
</head>

<body>
Expand Down Expand Up @@ -159,6 +160,7 @@ <h2 class="suggestion">
<script src="vendor/peggy/peggy.min.js"></script>
<script src="vendor/jsdump/jsDump.js"></script>
<script src="vendor/codemirror/codemirror.js"></script>
<script src="vendor/codemirror/lint.js"></script>
<script src="js/online.js"></script>
</body>

Expand Down
79 changes: 79 additions & 0 deletions docs/vendor/codemirror/lint.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/* The lint marker gutter */
.CodeMirror-lint-markers {
width: 16px;
}

.CodeMirror-lint-tooltip {
background-color: #ffd;
border: 1px solid black;
border-radius: 4px 4px 4px 4px;
color: black;
font-family: monospace;
font-size: 10pt;
overflow: hidden;
padding: 2px 5px;
position: fixed;
white-space: pre;
white-space: pre-wrap;
z-index: 100;
max-width: 600px;
opacity: 0;
transition: opacity .4s;
-moz-transition: opacity .4s;
-webkit-transition: opacity .4s;
-o-transition: opacity .4s;
-ms-transition: opacity .4s;
}

.CodeMirror-lint-mark {
background-position: left bottom;
background-repeat: repeat-x;
}

.CodeMirror-lint-mark-warning {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII=");
}

.CodeMirror-lint-mark-error {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==");
}

.CodeMirror-lint-marker {
background-position: center center;
background-repeat: no-repeat;
cursor: pointer;
display: inline-block;
height: 16px;
width: 16px;
vertical-align: middle;
position: relative;
}

.CodeMirror-lint-message {
padding-left: 18px;
background-position: top left;
background-repeat: no-repeat;
}

.CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII=");
}

.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII=");
}

.CodeMirror-lint-marker-multiple {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC");
background-repeat: no-repeat;
background-position: right bottom;
width: 100%; height: 100%;
}

.CodeMirror-lint-line-error {
background-color: rgba(183, 76, 81, 0.08);
}

.CodeMirror-lint-line-warning {
background-color: rgba(255, 211, 0, 0.1);
}
Loading

0 comments on commit 6532a1e

Please sign in to comment.