mirror of
https://github.com/IHaskell/IHaskell.git
synced 2025-04-16 11:26:08 +00:00
fixing issues with linting ordering
This commit is contained in:
parent
5ed129a079
commit
d87b8b98d9
@ -1,6 +1,5 @@
|
||||
<!-- CodeMirror component -->
|
||||
<link rel="stylesheet" href="/static/components/codemirror/addon/lint/lint.css">
|
||||
<script src="/static/components/codemirror/addon/lint/lint.js" charset="utf-8"></script>
|
||||
|
||||
<!-- Parsec widget DOM -->
|
||||
<form><textarea id="parsec-editor">Insert parser text here...</textarea></form>
|
||||
|
@ -7,6 +7,212 @@ if (initialized && window.parsecWidgetRegistered === undefined) {
|
||||
// Do not load this script again.
|
||||
window.parsecWidgetRegistered = true;
|
||||
|
||||
// Codemirror lint.js
|
||||
// Must be included here, otherwise linting cannot happen the first time the widget is loaded.
|
||||
(function() {
|
||||
"use strict";
|
||||
var GUTTER_ID = "CodeMirror-lint-markers";
|
||||
var SEVERITIES = /^(?:error|warning)$/;
|
||||
|
||||
function showTooltip(e, content) {
|
||||
var tt = document.createElement("div");
|
||||
tt.className = "CodeMirror-lint-tooltip";
|
||||
tt.appendChild(content.cloneNode(true));
|
||||
document.body.appendChild(tt);
|
||||
|
||||
function position(e) {
|
||||
if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position);
|
||||
tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + "px";
|
||||
tt.style.left = (e.clientX + 5) + "px";
|
||||
}
|
||||
CodeMirror.on(document, "mousemove", position);
|
||||
position(e);
|
||||
if (tt.style.opacity != null) tt.style.opacity = 1;
|
||||
return tt;
|
||||
}
|
||||
function rm(elt) {
|
||||
if (elt.parentNode) elt.parentNode.removeChild(elt);
|
||||
}
|
||||
function hideTooltip(tt) {
|
||||
if (!tt.parentNode) return;
|
||||
if (tt.style.opacity == null) rm(tt);
|
||||
tt.style.opacity = 0;
|
||||
setTimeout(function() { rm(tt); }, 600);
|
||||
}
|
||||
|
||||
function showTooltipFor(e, content, node) {
|
||||
var tooltip = showTooltip(e, content);
|
||||
function hide() {
|
||||
CodeMirror.off(node, "mouseout", hide);
|
||||
if (tooltip) { hideTooltip(tooltip); tooltip = null; }
|
||||
}
|
||||
var poll = setInterval(function() {
|
||||
if (tooltip) for (var n = node;; n = n.parentNode) {
|
||||
if (n == document.body) return;
|
||||
if (!n) { hide(); break; }
|
||||
}
|
||||
if (!tooltip) return clearInterval(poll);
|
||||
}, 400);
|
||||
CodeMirror.on(node, "mouseout", hide);
|
||||
}
|
||||
|
||||
function LintState(cm, options, hasGutter) {
|
||||
this.marked = [];
|
||||
this.options = options;
|
||||
this.timeout = null;
|
||||
this.hasGutter = hasGutter;
|
||||
this.onMouseOver = function(e) { onMouseOver(cm, e); };
|
||||
}
|
||||
|
||||
function parseOptions(cm, options) {
|
||||
if (options instanceof Function) return {getAnnotations: options};
|
||||
if (!options || options === true) options = {};
|
||||
if (!options.getAnnotations) options.getAnnotations = cm.getHelper(CodeMirror.Pos(0, 0), "lint");
|
||||
if (!options.getAnnotations) throw new Error("Required option 'getAnnotations' missing (lint addon)");
|
||||
return options;
|
||||
}
|
||||
|
||||
function clearMarks(cm) {
|
||||
var state = cm.state.lint;
|
||||
if (state.hasGutter) cm.clearGutter(GUTTER_ID);
|
||||
for (var i = 0; i < state.marked.length; ++i)
|
||||
state.marked[i].clear();
|
||||
state.marked.length = 0;
|
||||
}
|
||||
|
||||
function makeMarker(labels, severity, multiple, tooltips) {
|
||||
var marker = document.createElement("div"), inner = marker;
|
||||
marker.className = "CodeMirror-lint-marker-" + severity;
|
||||
if (multiple) {
|
||||
inner = marker.appendChild(document.createElement("div"));
|
||||
inner.className = "CodeMirror-lint-marker-multiple";
|
||||
}
|
||||
|
||||
if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) {
|
||||
showTooltipFor(e, labels, inner);
|
||||
});
|
||||
|
||||
return marker;
|
||||
}
|
||||
|
||||
function getMaxSeverity(a, b) {
|
||||
if (a == "error") return a;
|
||||
else return b;
|
||||
}
|
||||
|
||||
function groupByLine(annotations) {
|
||||
var lines = [];
|
||||
for (var i = 0; i < annotations.length; ++i) {
|
||||
var ann = annotations[i], line = ann.from.line;
|
||||
(lines[line] || (lines[line] = [])).push(ann);
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
function annotationTooltip(ann) {
|
||||
var severity = ann.severity;
|
||||
if (!SEVERITIES.test(severity)) severity = "error";
|
||||
var tip = document.createElement("div");
|
||||
tip.className = "CodeMirror-lint-message-" + severity;
|
||||
tip.appendChild(document.createTextNode(ann.message));
|
||||
return tip;
|
||||
}
|
||||
|
||||
function startLinting(cm) {
|
||||
var state = cm.state.lint, options = state.options;
|
||||
if (options.async)
|
||||
options.getAnnotations(cm, updateLinting, options);
|
||||
else
|
||||
updateLinting(cm, options.getAnnotations(cm.getValue(), options.options));
|
||||
}
|
||||
|
||||
function updateLinting(cm, annotationsNotSorted) {
|
||||
clearMarks(cm);
|
||||
var state = cm.state.lint, options = state.options;
|
||||
|
||||
var annotations = groupByLine(annotationsNotSorted);
|
||||
|
||||
for (var line = 0; line < annotations.length; ++line) {
|
||||
var anns = annotations[line];
|
||||
if (!anns) continue;
|
||||
|
||||
var maxSeverity = null;
|
||||
var tipLabel = state.hasGutter && document.createDocumentFragment();
|
||||
|
||||
for (var i = 0; i < anns.length; ++i) {
|
||||
var ann = anns[i];
|
||||
var severity = ann.severity;
|
||||
if (!SEVERITIES.test(severity)) severity = "error";
|
||||
maxSeverity = getMaxSeverity(maxSeverity, severity);
|
||||
|
||||
if (options.formatAnnotation) ann = options.formatAnnotation(ann);
|
||||
if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann));
|
||||
|
||||
if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, {
|
||||
className: "CodeMirror-lint-mark-" + severity,
|
||||
__annotation: ann
|
||||
}));
|
||||
}
|
||||
|
||||
if (state.hasGutter)
|
||||
cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1,
|
||||
state.options.tooltips));
|
||||
}
|
||||
if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm);
|
||||
}
|
||||
|
||||
function onChange(cm) {
|
||||
var state = cm.state.lint;
|
||||
clearTimeout(state.timeout);
|
||||
state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500);
|
||||
}
|
||||
|
||||
function popupSpanTooltip(ann, e) {
|
||||
var target = e.target || e.srcElement;
|
||||
showTooltipFor(e, annotationTooltip(ann), target);
|
||||
}
|
||||
|
||||
// When the mouseover fires, the cursor might not actually be over
|
||||
// the character itself yet. These pairs of x,y offsets are used to
|
||||
// probe a few nearby points when no suitable marked range is found.
|
||||
var nearby = [0, 0, 0, 5, 0, -5, 5, 0, -5, 0];
|
||||
|
||||
function onMouseOver(cm, e) {
|
||||
if (!/\bCodeMirror-lint-mark-/.test((e.target || e.srcElement).className)) return;
|
||||
for (var i = 0; i < nearby.length; i += 2) {
|
||||
var spans = cm.findMarksAt(cm.coordsChar({left: e.clientX + nearby[i],
|
||||
top: e.clientY + nearby[i + 1]}));
|
||||
for (var j = 0; j < spans.length; ++j) {
|
||||
var span = spans[j], ann = span.__annotation;
|
||||
if (ann) return popupSpanTooltip(ann, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function optionHandler(cm, val, old) {
|
||||
if (old && old != CodeMirror.Init) {
|
||||
clearMarks(cm);
|
||||
cm.off("change", onChange);
|
||||
CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver);
|
||||
delete cm.state.lint;
|
||||
}
|
||||
|
||||
if (val) {
|
||||
var gutters = cm.getOption("gutters"), hasLintGutter = false;
|
||||
for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true;
|
||||
var state = cm.state.lint = new LintState(cm, parseOptions(cm, val), hasLintGutter);
|
||||
cm.on("change", onChange);
|
||||
if (state.options.tooltips != false)
|
||||
CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver);
|
||||
|
||||
startLinting(cm);
|
||||
}
|
||||
}
|
||||
|
||||
CodeMirror.defineOption("lintWith", false, optionHandler); // deprecated
|
||||
CodeMirror.defineOption("lint", false, optionHandler); // deprecated
|
||||
})();
|
||||
|
||||
var parsecWidgetCounter = 0;
|
||||
|
||||
// Register the comm target.
|
||||
@ -66,8 +272,8 @@ var ParsecWidget = function (comm) {
|
||||
|
||||
ParsecWidget.prototype.handler = function(msg) {
|
||||
var data = msg.content.data;
|
||||
this.hasError = data["status"] == "error";
|
||||
console.log('handler', msg);
|
||||
this.hasError = (data["status"] == "error");
|
||||
console.log(this.hasError);
|
||||
if (this.hasError) {
|
||||
this.output.innerHTML = data["msg"];
|
||||
this.error = data;
|
||||
|
@ -42,9 +42,7 @@
|
||||
" blah |]"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {
|
||||
"hidden": false
|
||||
},
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"html": [
|
||||
@ -73,11 +71,11 @@
|
||||
"metadata": {},
|
||||
"output_type": "display_data",
|
||||
"text": [
|
||||
"/Users/silver"
|
||||
"/Users"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 3
|
||||
"prompt_number": 1
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@ -116,33 +114,129 @@
|
||||
" return (read (value ++ \".\" ++ after) :: Float)\n",
|
||||
" \n",
|
||||
" -- Parse any whitespace\n",
|
||||
" whitespace = many $ oneOf \" \\t\"\n",
|
||||
" \n",
|
||||
" whitespace = many $ oneOf \" \\t\""
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {
|
||||
"hidden": false
|
||||
},
|
||||
"outputs": [],
|
||||
"prompt_number": 1
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"parser"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"html": [
|
||||
"<div class='collapse-group'><span class='btn' href='#' id='unshowable'>Unshowable:<span class='show-type'>Parser List</span></span><span class='err-msg collapse'>No instance for (Show (Parser List)) arising from a use of `print'<br/>Possible fix: add an instance declaration for (Show (Parser List))<br/>In a stmt of an interactive GHCi command: print it</span></div><script>$('#unshowable').on('click', function(e) {\n",
|
||||
" e.preventDefault();\n",
|
||||
" var $this = $(this);\n",
|
||||
" var $collapse = $this.closest('.collapse-group').find('.err-msg');\n",
|
||||
" $collapse.collapse('toggle');\n",
|
||||
"javascript": [
|
||||
"// Only load this script once.\n",
|
||||
"var kernel = IPython.notebook.kernel;\n",
|
||||
"var initialized = kernel !== undefined && kernel != null;\n",
|
||||
"console.log(\"Initialized\", initialized);\n",
|
||||
"if (initialized && window.parsecWidgetRegistered === undefined) {\n",
|
||||
"\n",
|
||||
"// Do not load this script again.\n",
|
||||
"window.parsecWidgetRegistered = true;\n",
|
||||
"\n",
|
||||
"var parsecWidgetCounter = 0;\n",
|
||||
"\n",
|
||||
"// Register the comm target.\n",
|
||||
"var ParsecWidget = function (comm) {\n",
|
||||
" // Load linting.\n",
|
||||
" require([\"/static/components/codemirror/addon/lint/lint.js\"]);\n",
|
||||
"\n",
|
||||
" this.comm = comm;\n",
|
||||
" this.comm.on_msg($.proxy(this.handler, this));\n",
|
||||
"\n",
|
||||
" // Get the cell that was probably executed.\n",
|
||||
" // The msg_id:cell mapping will make this possible without guessing.\n",
|
||||
" this.cell = IPython.notebook.get_cell(IPython.notebook.get_selected_index()-1);\n",
|
||||
"\n",
|
||||
" // Store this widget so we can use it from callbacks.\n",
|
||||
" var widget = this;\n",
|
||||
"\n",
|
||||
" // Editor options.\n",
|
||||
" var options = {\n",
|
||||
" lineNumbers: true,\n",
|
||||
" // Show parsec errors as lint errors.\n",
|
||||
" gutters: [\"CodeMirror-lint-markers\"],\n",
|
||||
" lintWith: {\n",
|
||||
" \"getAnnotations\": function(cm, update, opts) {\n",
|
||||
" var errs = [];\n",
|
||||
" if (widget.hasError) {\n",
|
||||
" var col = widget.error[\"col\"];\n",
|
||||
" var line = widget.error[\"line\"];\n",
|
||||
" errs = [{\n",
|
||||
" from: CodeMirror.Pos(line - 1, col - 1),\n",
|
||||
" to: CodeMirror.Pos(line - 1, col),\n",
|
||||
" message: widget.error[\"msg\"],\n",
|
||||
" severity: \"error\"\n",
|
||||
" }];\n",
|
||||
" }\n",
|
||||
" update(cm, errs);\n",
|
||||
" },\n",
|
||||
" \"async\": true,\n",
|
||||
" }\n",
|
||||
" };\n",
|
||||
"\n",
|
||||
" // Create the editor.\n",
|
||||
" var out = this.cell.output_area.element;\n",
|
||||
" this.textarea = out.find(\"#parsec-editor\")[0];\n",
|
||||
" this.output = out.find(\"#parsec-output\")[0];\n",
|
||||
" // Give the elements a different name.\n",
|
||||
" this.textarea.id += parsecWidgetCounter;\n",
|
||||
" this.output.id += parsecWidgetCounter;\n",
|
||||
" parsecWidgetCounter++;\n",
|
||||
"\n",
|
||||
" var editor = CodeMirror.fromTextArea(this.textarea, options);\n",
|
||||
" var editor = editor;\n",
|
||||
"\n",
|
||||
" // Update every key press.\n",
|
||||
" editor.on(\"keyup\", function() {\n",
|
||||
" var text = editor.getDoc().getValue();\n",
|
||||
" comm.send({\"text\": text});\n",
|
||||
" });\n",
|
||||
"</script>"
|
||||
"};\n",
|
||||
"\n",
|
||||
"ParsecWidget.prototype.handler = function(msg) {\n",
|
||||
" var data = msg.content.data;\n",
|
||||
" this.hasError = (data[\"status\"] == \"error\");\n",
|
||||
" console.log(this.hasError);\n",
|
||||
" if (this.hasError) {\n",
|
||||
" this.output.innerHTML = data[\"msg\"];\n",
|
||||
" this.error = data;\n",
|
||||
" } else {\n",
|
||||
" this.output.innerHTML = data[\"result\"];\n",
|
||||
" }\n",
|
||||
"};\n",
|
||||
"\n",
|
||||
"// Register this widget.\n",
|
||||
"IPython.notebook.kernel.comm_manager.register_target('parsec', IPython.utils.always_new(ParsecWidget));\n",
|
||||
"console.log(\"Registering Parsec widget.\");\n",
|
||||
"}\n"
|
||||
],
|
||||
"metadata": {},
|
||||
"output_type": "display_data",
|
||||
"text": [
|
||||
"No instance for (Show (Parser List)) arising from a use of `print'\n",
|
||||
"Possible fix: add an instance declaration for (Show (Parser List))\n",
|
||||
"In a stmt of an interactive GHCi command: print it"
|
||||
]
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"html": [
|
||||
"<!-- CodeMirror component -->\n",
|
||||
"<link rel=\"stylesheet\" href=\"/static/components/codemirror/addon/lint/lint.css\">\n",
|
||||
"\n",
|
||||
"<!-- Parsec widget DOM -->\n",
|
||||
"<form><textarea id=\"parsec-editor\">Insert parser text here...</textarea></form>\n",
|
||||
"<pre id=\"parsec-output\"></pre>\n"
|
||||
],
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"prompt_number": 1
|
||||
"prompt_number": 2
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
|
Loading…
x
Reference in New Issue
Block a user