User:Suffusion of Yellow/cm-lint.js

/* * MIT License * * Copyright (C) 2017 by Marijn Haverbeke  and others * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */

// CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: https://codemirror.net/5/LICENSE

(function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS    mod(require("../../lib/codemirror"));  else if (typeof define == "function" && define.amd) // AMD    define(["../../lib/codemirror"], mod);  else // Plain browser env    mod(CodeMirror); })(function(CodeMirror) {  "use strict";  var GUTTER_ID = "CodeMirror-lint-markers";  var LINT_LINE_ID = "CodeMirror-lint-line-";

function showTooltip(cm, e, content) { var tt = document.createElement("div"); tt.className = "CodeMirror-lint-tooltip cm-s-" + cm.options.theme; tt.appendChild(content.cloneNode(true)); if (cm.state.lint.options.selfContain) cm.getWrapperElement.appendChild(tt); else document.body.appendChild(tt);

function position(e) { if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position); var top = Math.max(0, e.clientY - tt.offsetHeight - 5); var left = Math.max(0, Math.min(e.clientX + 5, tt.ownerDocument.defaultView.innerWidth - tt.offsetWidth)); tt.style.top = top + "px" tt.style.left = left + "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(cm, e, content, node) { var tooltip = showTooltip(cm, 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 && n.nodeType == 11) n = n.host;        if (n == document.body) return;        if (!n) { hide; break; }      }      if (!tooltip) return clearInterval(poll);    }, 400); CodeMirror.on(node, "mouseout", hide); }

function LintState(cm, conf, hasGutter) { this.marked = []; if (conf instanceof Function) conf = {getAnnotations: conf}; if (!conf || conf === true) conf = {}; this.options = {}; this.linterOptions = conf.options || {}; for (var prop in defaults) this.options[prop] = defaults[prop]; for (var prop in conf) { if (defaults.hasOwnProperty(prop)) { if (conf[prop] != null) this.options[prop] = conf[prop]; } else if (!conf.options) { this.linterOptions[prop] = conf[prop]; }   }    this.timeout = null; this.hasGutter = hasGutter; this.onMouseOver = function(e) { onMouseOver(cm, e); }; this.waitingFor = 0 }

var defaults = { highlightLines: false, tooltips: true, delay: 500, lintOnChange: true, getAnnotations: null, async: false, selfContain: null, formatAnnotation: null, onUpdateLinting: null }

function clearMarks(cm) { var state = cm.state.lint; if (state.hasGutter) cm.clearGutter(GUTTER_ID); if (state.options.highlightLines) clearErrorLines(cm); for (var i = 0; i < state.marked.length; ++i) state.marked[i].clear; state.marked.length = 0; }

function clearErrorLines(cm) { cm.eachLine(function(line) {     var has = line.wrapClass && /\bCodeMirror-lint-line-\w+\b/.exec(line.wrapClass);      if (has) cm.removeLineClass(line, "wrap", has[0]);    }) }

function makeMarker(cm, labels, severity, multiple, tooltips) { var marker = document.createElement("div"), inner = marker; marker.className = "CodeMirror-lint-marker CodeMirror-lint-marker-" + severity; if (multiple) { inner = marker.appendChild(document.createElement("div")); inner.className = "CodeMirror-lint-marker CodeMirror-lint-marker-multiple"; }

if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) {     showTooltipFor(cm, 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 (!severity) severity = "error"; var tip = document.createElement("div"); tip.className = "CodeMirror-lint-message CodeMirror-lint-message-" + severity; if (typeof ann.messageHTML != 'undefined') { tip.innerHTML = ann.messageHTML; } else { tip.appendChild(document.createTextNode(ann.message)); }   return tip; }

function lintAsync(cm, getAnnotations) { var state = cm.state.lint var id = ++state.waitingFor function abort { id = -1 cm.off("change", abort) }   cm.on("change", abort) getAnnotations(cm.getValue, function(annotations, arg2) {     cm.off("change", abort)      if (state.waitingFor != id) return      if (arg2 && annotations instanceof CodeMirror) annotations = arg2      cm.operation(function {updateLinting(cm, annotations)})    }, state.linterOptions, cm); }

function startLinting(cm) { var state = cm.state.lint; if (!state) return; var options = state.options; /*    * Passing rules in `options` property prevents JSHint (and other linters) from complaining * about unrecognized rules like `onUpdateLinting`, `delay`, `lintOnChange`, etc.    */ var getAnnotations = options.getAnnotations || cm.getHelper(CodeMirror.Pos(0, 0), "lint"); if (!getAnnotations) return; if (options.async || getAnnotations.async) { lintAsync(cm, getAnnotations) } else { var annotations = getAnnotations(cm.getValue, state.linterOptions, cm); if (!annotations) return; if (annotations.then) annotations.then(function(issues) {       cm.operation(function {updateLinting(cm, issues)})      }); else cm.operation(function {updateLinting(cm, annotations)}) } }

function updateLinting(cm, annotationsNotSorted) { var state = cm.state.lint; if (!state) return; var options = state.options; clearMarks(cm);

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 (!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 CodeMirror-lint-mark-" + severity, __annotation: ann }));     }      if (state.hasGutter) cm.setGutterMarker(line, GUTTER_ID, makeMarker(cm, tipLabel, maxSeverity, anns.length > 1, options.tooltips));

if (options.highlightLines) cm.addLineClass(line, "wrap", LINT_LINE_ID + maxSeverity); }   if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm); }

function onChange(cm) { var state = cm.state.lint; if (!state) return; clearTimeout(state.timeout); state.timeout = setTimeout(function{startLinting(cm);}, state.options.delay); }

function popupTooltips(cm, annotations, e) { var target = e.target || e.srcElement; var tooltip = document.createDocumentFragment; for (var i = 0; i < annotations.length; i++) { var ann = annotations[i]; tooltip.appendChild(annotationTooltip(ann)); }   showTooltipFor(cm, e, tooltip, target); }

function onMouseOver(cm, e) { var target = e.target || e.srcElement; if (!/\bCodeMirror-lint-mark-/.test(target.className)) return; var box = target.getBoundingClientRect, x = (box.left + box.right) / 2, y = (box.top + box.bottom) / 2; var spans = cm.findMarksAt(cm.coordsChar({left: x, top: y}, "client"));

var annotations = []; for (var i = 0; i < spans.length; ++i) { var ann = spans[i].__annotation; if (ann) annotations.push(ann); }   if (annotations.length) popupTooltips(cm, annotations, e); }

CodeMirror.defineOption("lint", false, function(cm, val, old) {   if (old && old != CodeMirror.Init) {      clearMarks(cm);      if (cm.state.lint.options.lintOnChange !== false)        cm.off("change", onChange);      CodeMirror.off(cm.getWrapperElement, "mouseover", cm.state.lint.onMouseOver);      clearTimeout(cm.state.lint.timeout);      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, val, hasLintGutter); if (state.options.lintOnChange) cm.on("change", onChange); if (state.options.tooltips != false && state.options.tooltips != "gutter") CodeMirror.on(cm.getWrapperElement, "mouseover", state.onMouseOver);

startLinting(cm); } });

CodeMirror.defineExtension("performLint", function {   startLinting(this);  }); });