Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Website: show errors in editors #294

Merged
merged 2 commits into from
Jun 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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