From c2805e03c84b6e598556fd06d1ede7aaeea7ce9c Mon Sep 17 00:00:00 2001 From: Valerio Virgillito Date: Tue, 6 Mar 2012 16:17:54 -0800 Subject: Squashed commit FileIO-Build-Candidate into Master Fixing issues with HTML and CSS URLs. Adjusted RegEx logic. Also code a mirror update and undo/redo changes were merged into this request. Signed-off-by: Valerio Virgillito --- imports/codemirror/lib/util/dialog.css | 0 imports/codemirror/lib/util/dialog.js | 0 imports/codemirror/lib/util/foldcode.js | 120 +++++++++++++++++++++++ imports/codemirror/lib/util/formatting.js | 9 +- imports/codemirror/lib/util/javascript-hint.js | 67 +++++++++++-- imports/codemirror/lib/util/match-highlighter.js | 44 +++++++++ imports/codemirror/lib/util/overlay.js | 0 imports/codemirror/lib/util/runmode.js | 38 +++++-- imports/codemirror/lib/util/search.js | 0 imports/codemirror/lib/util/searchcursor.js | 0 imports/codemirror/lib/util/simple-hint.css | 0 imports/codemirror/lib/util/simple-hint.js | 0 12 files changed, 258 insertions(+), 20 deletions(-) mode change 100755 => 100644 imports/codemirror/lib/util/dialog.css mode change 100755 => 100644 imports/codemirror/lib/util/dialog.js mode change 100755 => 100644 imports/codemirror/lib/util/foldcode.js mode change 100755 => 100644 imports/codemirror/lib/util/formatting.js mode change 100755 => 100644 imports/codemirror/lib/util/javascript-hint.js create mode 100644 imports/codemirror/lib/util/match-highlighter.js mode change 100755 => 100644 imports/codemirror/lib/util/overlay.js mode change 100755 => 100644 imports/codemirror/lib/util/runmode.js mode change 100755 => 100644 imports/codemirror/lib/util/search.js mode change 100755 => 100644 imports/codemirror/lib/util/searchcursor.js mode change 100755 => 100644 imports/codemirror/lib/util/simple-hint.css mode change 100755 => 100644 imports/codemirror/lib/util/simple-hint.js (limited to 'imports/codemirror/lib/util') diff --git a/imports/codemirror/lib/util/dialog.css b/imports/codemirror/lib/util/dialog.css old mode 100755 new mode 100644 diff --git a/imports/codemirror/lib/util/dialog.js b/imports/codemirror/lib/util/dialog.js old mode 100755 new mode 100644 diff --git a/imports/codemirror/lib/util/foldcode.js b/imports/codemirror/lib/util/foldcode.js old mode 100755 new mode 100644 index 18957792..50268a8b --- a/imports/codemirror/lib/util/foldcode.js +++ b/imports/codemirror/lib/util/foldcode.js @@ -1,3 +1,110 @@ +// the tagRangeFinder function is +// Copyright (C) 2011 by Daniel Glazman +// released under the MIT license (../../LICENSE) like the rest of CodeMirror +CodeMirror.tagRangeFinder = function(cm, line) { + var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD"; + var nameChar = nameStartChar + "\-\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040"; + var xmlNAMERegExp = new RegExp("^[" + nameStartChar + "][" + nameChar + "]*"); + + var lineText = cm.getLine(line); + var found = false; + var tag = null; + var pos = 0; + while (!found) { + pos = lineText.indexOf("<", pos); + if (-1 == pos) // no tag on line + return; + if (pos + 1 < lineText.length && lineText[pos + 1] == "/") { // closing tag + pos++; + continue; + } + // ok we weem to have a start tag + if (!lineText.substr(pos + 1).match(xmlNAMERegExp)) { // not a tag name... + pos++; + continue; + } + var gtPos = lineText.indexOf(">", pos + 1); + if (-1 == gtPos) { // end of start tag not in line + var l = line + 1; + var foundGt = false; + var lastLine = cm.lineCount(); + while (l < lastLine && !foundGt) { + var lt = cm.getLine(l); + var gt = lt.indexOf(">"); + if (-1 != gt) { // found a > + foundGt = true; + var slash = lt.lastIndexOf("/", gt); + if (-1 != slash && slash < gt) { + var str = lineText.substr(slash, gt - slash + 1); + if (!str.match( /\/\s*\>/ )) // yep, that's the end of empty tag + return l+1; + } + } + l++; + } + found = true; + } + else { + var slashPos = lineText.lastIndexOf("/", gtPos); + if (-1 == slashPos) { // cannot be empty tag + found = true; + // don't continue + } + else { // empty tag? + // check if really empty tag + var str = lineText.substr(slashPos, gtPos - slashPos + 1); + if (!str.match( /\/\s*\>/ )) { // finally not empty + found = true; + // don't continue + } + } + } + if (found) { + var subLine = lineText.substr(pos + 1); + tag = subLine.match(xmlNAMERegExp); + if (tag) { + // we have an element name, wooohooo ! + tag = tag[0]; + // do we have the close tag on same line ??? + if (-1 != lineText.indexOf("", pos)) // yep + { + found = false; + } + // we don't, so we have a candidate... + } + else + found = false; + } + if (!found) + pos++; + } + + if (found) { + var startTag = "(\\<\\/" + tag + "\\>)|(\\<" + tag + "\\>)|(\\<" + tag + "\s)|(\\<" + tag + "$)"; + var startTagRegExp = new RegExp(startTag, "g"); + var endTag = ""; + var depth = 1; + var l = line + 1; + var lastLine = cm.lineCount(); + while (l < lastLine) { + lineText = cm.getLine(l); + var match = lineText.match(startTagRegExp); + if (match) { + for (var i = 0; i < match.length; i++) { + if (match[i] == endTag) + depth--; + else + depth++; + if (!depth) + return l+1; + } + } + l++; + } + return; + } +}; + CodeMirror.braceRangeFinder = function(cm, line) { var lineText = cm.getLine(line); var startChar = lineText.lastIndexOf("{"); @@ -23,6 +130,19 @@ CodeMirror.braceRangeFinder = function(cm, line) { return end; }; +CodeMirror.indentRangeFinder = function(cm, line) { + var tabSize = cm.getOption("tabSize"); + var myIndent = cm.getLineHandle(line).indentation(tabSize), last; + for (var i = line + 1, end = cm.lineCount(); i < end; ++i) { + var handle = cm.getLineHandle(i); + if (!/^\s*$/.test(handle.text)) { + if (handle.indentation(tabSize) <= myIndent) break; + last = i; + } + } + if (!last) return null; + return last + 1; +}; CodeMirror.newFoldFunction = function(rangeFinder, markText) { var folded = []; diff --git a/imports/codemirror/lib/util/formatting.js b/imports/codemirror/lib/util/formatting.js old mode 100755 new mode 100644 index 986bcb8f..15de0355 --- a/imports/codemirror/lib/util/formatting.js +++ b/imports/codemirror/lib/util/formatting.js @@ -4,7 +4,10 @@ if (!CodeMirror.modeExtensions) CodeMirror.modeExtensions = {}; // Returns the extension of the editor's current mode CodeMirror.defineExtension("getModeExt", function () { - return CodeMirror.modeExtensions[this.getOption("mode")]; + var mname = CodeMirror.resolveMode(this.getOption("mode")).name; + var ext = CodeMirror.modeExtensions[mname]; + if (!ext) throw new Error("No extensions found for mode " + mname); + return ext; }); // If the current mode is 'htmlmixed', returns the extension of a mode located at @@ -50,7 +53,7 @@ CodeMirror.defineExtension("autoIndentRange", function (from, to) { var cmInstance = this; this.operation(function () { for (var i = from.line; i <= to.line; i++) { - cmInstance.indentLine(i); + cmInstance.indentLine(i, "smart"); } }); }); @@ -70,7 +73,7 @@ CodeMirror.defineExtension("autoFormatRange", function (from, to) { var startLine = cmInstance.posFromIndex(absStart).line; var endLine = cmInstance.posFromIndex(absStart + res.length).line; for (var i = startLine; i <= endLine; i++) { - cmInstance.indentLine(i); + cmInstance.indentLine(i, "smart"); } }); }); diff --git a/imports/codemirror/lib/util/javascript-hint.js b/imports/codemirror/lib/util/javascript-hint.js old mode 100755 new mode 100644 index 4e88a7e4..2b904a51 --- a/imports/codemirror/lib/util/javascript-hint.js +++ b/imports/codemirror/lib/util/javascript-hint.js @@ -15,37 +15,81 @@ } return arr.indexOf(item) != -1; } - - CodeMirror.javascriptHint = function(editor) { + + function scriptHint(editor, keywords, getToken) { // Find the token at the cursor - var cur = editor.getCursor(), token = editor.getTokenAt(cur), tprop = token; + var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token; // If it's not a 'word-style' token, ignore the token. - if (!/^[\w$_]*$/.test(token.string)) { + if (!/^[\w$_]*$/.test(token.string)) { token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state, className: token.string == "." ? "property" : null}; } // If it is a property, find out what it is a property of. while (tprop.className == "property") { - tprop = editor.getTokenAt({line: cur.line, ch: tprop.start}); + tprop = getToken(editor, {line: cur.line, ch: tprop.start}); if (tprop.string != ".") return; - tprop = editor.getTokenAt({line: cur.line, ch: tprop.start}); + tprop = getToken(editor, {line: cur.line, ch: tprop.start}); + if (tprop.string == ')') { + var level = 1; + do { + tprop = getToken(editor, {line: cur.line, ch: tprop.start}); + switch (tprop.string) { + case ')': level++; break; + case '(': level--; break; + default: break; + } + } while (level > 0) + tprop = getToken(editor, {line: cur.line, ch: tprop.start}); + if (tprop.className == 'variable') + tprop.className = 'function'; + else return; // no clue + } if (!context) var context = []; context.push(tprop); } - return {list: getCompletions(token, context), + return {list: getCompletions(token, context, keywords), from: {line: cur.line, ch: token.start}, to: {line: cur.line, ch: token.end}}; } + CodeMirror.javascriptHint = function(editor) { + return scriptHint(editor, javascriptKeywords, + function (e, cur) {return e.getTokenAt(cur);}); + } + + function getCoffeeScriptToken(editor, cur) { + // This getToken, it is for coffeescript, imitates the behavior of + // getTokenAt method in javascript.js, that is, returning "property" + // type and treat "." as indepenent token. + var token = editor.getTokenAt(cur); + if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') { + token.end = token.start; + token.string = '.'; + token.className = "property"; + } + else if (/^\.[\w$_]*$/.test(token.string)) { + token.className = "property"; + token.start++; + token.string = token.string.replace(/\./, ''); + } + return token; + } + + CodeMirror.coffeescriptHint = function(editor) { + return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken); + } + var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " + "toUpperCase toLowerCase split concat match replace search").split(" "); var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " + "lastIndexOf every some filter forEach map reduce reduceRight ").split(" "); var funcProps = "prototype apply call bind".split(" "); - var keywords = ("break case catch continue debugger default delete do else false finally for function " + + var javascriptKeywords = ("break case catch continue debugger default delete do else false finally for function " + "if in instanceof new null return switch throw true try typeof var void while with").split(" "); + var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " + + "if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" "); - function getCompletions(token, context) { + function getCompletions(token, context, keywords) { var found = [], start = token.string; function maybeAdd(str) { if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str); @@ -67,6 +111,11 @@ base = ""; else if (obj.className == "atom") base = 1; + else if (obj.className == "function") { + if (window.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') && + (typeof jQuery == 'function')) base = jQuery(); + else if (window._ != null && (obj.string == '_') && (typeof _ == 'function')) base = _(); + } while (base != null && context.length) base = base[context.pop().string]; if (base != null) gatherCompletions(base); diff --git a/imports/codemirror/lib/util/match-highlighter.js b/imports/codemirror/lib/util/match-highlighter.js new file mode 100644 index 00000000..b70cc4cf --- /dev/null +++ b/imports/codemirror/lib/util/match-highlighter.js @@ -0,0 +1,44 @@ +// Define match-highlighter commands. Depends on searchcursor.js +// Use by attaching the following function call to the onCursorActivity event: + //myCodeMirror.matchHighlight(minChars); +// And including a special span.CodeMirror-matchhighlight css class (also optionally a separate one for .CodeMirror-focused -- see demo matchhighlighter.html) + +(function() { + var DEFAULT_MIN_CHARS = 2; + + function MatchHighlightState() { + this.marked = []; + } + function getMatchHighlightState(cm) { + return cm._matchHighlightState || (cm._matchHighlightState = new MatchHighlightState()); + } + + function clearMarks(cm) { + var state = getMatchHighlightState(cm); + for (var i = 0; i < state.marked.length; ++i) + state.marked[i].clear(); + state.marked = []; + } + + function markDocument(cm, className, minChars) { + clearMarks(cm); + minChars = (typeof minChars !== 'undefined' ? minChars : DEFAULT_MIN_CHARS); + if (cm.somethingSelected() && cm.getSelection().length >= minChars) { + var state = getMatchHighlightState(cm); + var query = cm.getSelection(); + cm.operation(function() { + if (cm.lineCount() < 2000) { // This is too expensive on big documents. + for (var cursor = cm.getSearchCursor(query); cursor.findNext();) { + //Only apply matchhighlight to the matches other than the one actually selected + if (!(cursor.from().line === cm.getCursor(true).line && cursor.from().ch === cm.getCursor(true).ch)) + state.marked.push(cm.markText(cursor.from(), cursor.to(), className)); + } + } + }); + } + } + + CodeMirror.defineExtension("matchHighlight", function(className, minChars) { + markDocument(this, className, minChars); + }); +})(); diff --git a/imports/codemirror/lib/util/overlay.js b/imports/codemirror/lib/util/overlay.js old mode 100755 new mode 100644 diff --git a/imports/codemirror/lib/util/runmode.js b/imports/codemirror/lib/util/runmode.js old mode 100755 new mode 100644 index de4a7602..fc58d857 --- a/imports/codemirror/lib/util/runmode.js +++ b/imports/codemirror/lib/util/runmode.js @@ -1,15 +1,37 @@ -CodeMirror.runMode = function(string, modespec, callback) { - var mode = CodeMirror.getMode({indentUnit: 2}, modespec); +CodeMirror.runMode = function(string, modespec, callback, options) { + var mode = CodeMirror.getMode(CodeMirror.defaults, modespec); var isNode = callback.nodeType == 1; + var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize; if (isNode) { - var node = callback, accum = []; - callback = function(string, style) { - if (string == "\n") + var node = callback, accum = [], col = 0; + callback = function(text, style) { + if (text == "\n") { accum.push("
"); - else if (style) - accum.push("" + CodeMirror.htmlEscape(string) + ""); + col = 0; + return; + } + var escaped = ""; + // HTML-escape and replace tabs + for (var pos = 0;;) { + var idx = text.indexOf("\t", pos); + if (idx == -1) { + escaped += CodeMirror.htmlEscape(text.slice(pos)); + col += text.length - pos; + break; + } else { + col += idx - pos; + escaped += CodeMirror.htmlEscape(text.slice(pos, idx)); + var size = tabSize - col % tabSize; + col += size; + for (var i = 0; i < size; ++i) escaped += " "; + pos = idx + 1; + } + } + + if (style) + accum.push("" + escaped + ""); else - accum.push(CodeMirror.htmlEscape(string)); + accum.push(escaped); } } var lines = CodeMirror.splitLines(string), state = CodeMirror.startState(mode); diff --git a/imports/codemirror/lib/util/search.js b/imports/codemirror/lib/util/search.js old mode 100755 new mode 100644 diff --git a/imports/codemirror/lib/util/searchcursor.js b/imports/codemirror/lib/util/searchcursor.js old mode 100755 new mode 100644 diff --git a/imports/codemirror/lib/util/simple-hint.css b/imports/codemirror/lib/util/simple-hint.css old mode 100755 new mode 100644 diff --git a/imports/codemirror/lib/util/simple-hint.js b/imports/codemirror/lib/util/simple-hint.js old mode 100755 new mode 100644 -- cgit v1.2.3