diff options
Diffstat (limited to 'objectapp/static/objectapp/js/Gnowmacs/src/js/.svn/text-base/ymacs-mode-js.js.svn-base')
-rw-r--r-- | objectapp/static/objectapp/js/Gnowmacs/src/js/.svn/text-base/ymacs-mode-js.js.svn-base | 431 |
1 files changed, 431 insertions, 0 deletions
diff --git a/objectapp/static/objectapp/js/Gnowmacs/src/js/.svn/text-base/ymacs-mode-js.js.svn-base b/objectapp/static/objectapp/js/Gnowmacs/src/js/.svn/text-base/ymacs-mode-js.js.svn-base new file mode 100644 index 00000000..1265bc64 --- /dev/null +++ b/objectapp/static/objectapp/js/Gnowmacs/src/js/.svn/text-base/ymacs-mode-js.js.svn-base @@ -0,0 +1,431 @@ +//> This file is part of Ymacs, an Emacs-like editor for the Web +//> http://www.ymacs.org/ +//> +//> Copyright (c) 2009-2010, Mihai Bazon, Dynarch.com. All rights reserved. +//> +//> Redistribution and use in source and binary forms, with or without +//> modification, are permitted provided that the following conditions are +//> met: +//> +//> * Redistributions of source code must retain the above copyright +//> notice, this list of conditions and the following disclaimer. +//> +//> * Redistributions in binary form must reproduce the above copyright +//> notice, this list of conditions and the following disclaimer in +//> the documentation and/or other materials provided with the +//> distribution. +//> +//> * Neither the name of Dynarch.com nor the names of its contributors +//> may be used to endorse or promote products derived from this +//> software without specific prior written permission. +//> +//> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY +//> EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +//> IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +//> PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE +//> FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +//> CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +//> SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +//> INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +//> CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +//> ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +//> THE POSSIBILITY OF SUCH DAMAGE. + +// @require ymacs-tokenizer.js + +/* -----[ This defines the tokenizer ]----- */ + +(function(){ + + var KEYWORDS = "abstract break case catch class const \ +continue debugger default delete do else \ +enum export extends final finally for \ +function goto if implements import in \ +instanceof interface native new package \ +private protected public return static \ +super switch synchronized throw \ +throws transient try typeof var void let \ +yield volatile while with".qw(); + + var KEYWORDS_TYPE = "boolean byte char double float int long short void \ +Array Date Function Math Number Object RegExp String".qw(); + + var KEYWORDS_CONST = "false null undefined Infinity NaN true arguments this".qw(); + + var KEYWORDS_BUILTIN = "Infinity NaN \ +Packages decodeURI decodeURIComponent \ +encodeURI encodeURIComponent eval isFinite isNaN parseFloat \ +parseInt undefined window document alert prototype constructor".qw(); + + var ALLOW_REGEXP_AFTER = /[\[({,;+\-*=?&|!:][\x20\t\n\xa0]*$|return\s+$|typeof\s+$/; + + function isLetter(ch) { + return ch.toLowerCase() != ch.toUpperCase(); + }; + + function isNameStart(ch) { + return ch && (isLetter(ch) || /^[_$]$/.test(ch)); + }; + + function isNameChar(ch) { + return ch && (isLetter(ch) || /^[0-9_$]$/.test(ch)); + }; + + var OPEN_PAREN = { + "(" : ")", + "{" : "}", + "[" : "]" + }; + + var CLOSE_PAREN = { + ")" : "(", + "}" : "{", + "]" : "[" + }; + + function isOpenParen(ch) { + return OPEN_PAREN[ch]; + }; + + function isCloseParen(ch) { + return CLOSE_PAREN[ch]; + }; + + function JS_PARSER(KEYWORDS, KEYWORDS_TYPE, KEYWORDS_CONST, KEYWORDS_BUILTIN, stream, tok) { + + var $cont = [], + $parens = [], + $passedParens = [], + $inComment = null, + $inString = null, + PARSER = { + next : next, + copy : copy, + indentation : indentation + }; + + function INDENT_LEVEL() { + return stream.buffer.getq("indent_level"); + }; + + function copy() { + var context = restore.context = { + cont : $cont.slice(0), + inComment : $inComment, + inString : $inString, + parens : $parens.slice(0), + passedParens : $passedParens.slice(0) + }; + function restore() { + $cont = context.cont.slice(0); + $inComment = context.inComment; + $inString = context.inString; + $parens = context.parens.slice(0); + $passedParens = context.passedParens.slice(0); + return PARSER; + }; + return restore; + }; + + function foundToken(c1, c2, type) { + tok.onToken(stream.line, c1, c2, type); + }; + + function readName() { + var col = stream.col, ch = stream.get(), + name = ch; + while (!stream.eol()) { + ch = stream.peek(); + if (!isNameChar(ch)) + break; + name += ch; + stream.nextCol(); + } + return ch && { line: stream.line, c1: col, c2: stream.col, id: name }; + }; + + function readComment() { + var line = stream.lineText(), pos = line.indexOf("*/", stream.col); + var m = /^\s*\*+/.exec(line.substr(stream.col)); + if (m) { + foundToken(stream.col, stream.col += m[0].length, "mcomment-starter"); + } + if (pos >= 0) { + $cont.pop(); + $inComment = null; + foundToken(stream.col, pos, "mcomment"); + foundToken(pos, pos += 2, "mcomment-stopper"); + stream.col = pos; + } else { + foundToken(stream.col, line.length, "mcomment"); + stream.col = line.length; + } + }; + + function readString(end, type) { + var ch, esc = false, start = stream.col; + while (!stream.eol()) { + ch = stream.peek(); + if (ch === end && !esc) { + $cont.pop(); + $inString = null; + foundToken(start, stream.col, type); + foundToken(stream.col, ++stream.col, type + "-stopper"); + return true; + } + esc = !esc && ch === "\\"; + stream.nextCol(); + } + foundToken(start, stream.col, type); + }; + + // function readLiteralRegexp() { + // var m; + // if (readString("/", "regexp") && (m = stream.lookingAt(/^[gmsiy]+/))) + // foundToken(stream.col, stream.col += m[0].length, "regexp-modifier"); + // }; + + function readLiteralRegexp() { + var ch, esc = false, inset = 0, start = stream.col; + while (!stream.eol()) { + ch = stream.peek(); + if (isOpenParen(ch) && !esc && !inset) + inset++; + if (isCloseParen(ch) && !esc) { + inset--; + if (inset < 0) + inset = 0; + } + if (ch === "/" && !esc && !inset) { + $cont.pop(); + $inString = null; + foundToken(start, stream.col, "regexp"); + foundToken(stream.col, ++stream.col, "regexp-stopper"); + var m = stream.lookingAt(/^[gmsiy]+/); + if (m) + foundToken(stream.col, stream.col += m[0].length, "regexp-modifier"); + return true; + } + esc = !esc && ch === "\\"; + stream.nextCol(); + } + foundToken(start, stream.col, "regexp"); + }; + + function next() { + stream.checkStop(); + if ($cont.length > 0) + return $cont.peek()(); + var ch = stream.peek(), m, tmp; + if (stream.lookingAt("/*")) { + $inComment = { line: stream.line, c1: stream.col }; + foundToken(stream.col, stream.col += 2, "mcomment-starter"); + $cont.push(readComment); + } + else if (stream.lookingAt("//")) { + foundToken(stream.col, stream.col += 2, "comment-starter"); + foundToken(stream.col, stream.col = stream.lineLength(), "comment"); + } + else if (ch === '"' || ch === "'") { + $inString = { line: stream.line, c1: stream.col }; + foundToken(stream.col, ++stream.col, "string-starter"); + $cont.push(readString.$C(ch, "string")); + } + else if ((m = stream.lookingAt(/^0x[0-9a-f]+|^[0-9]*\.?[0-9]+/))) { + foundToken(stream.col, stream.col += m[0].length, "number"); + } + else if (isNameStart(ch) && (tmp = readName())) { + var type = tmp.id in KEYWORDS ? "keyword" + : tmp.id in KEYWORDS_TYPE ? "type" + : tmp.id in KEYWORDS_CONST ? "constant" + : tmp.id in KEYWORDS_BUILTIN ? "builtin" + : null; + foundToken(tmp.c1, tmp.c2, type); + } + else if ((tmp = isOpenParen(ch))) { + $parens.push({ line: stream.line, col: stream.col, type: ch }); + foundToken(stream.col, ++stream.col, "open-paren"); + } + else if ((tmp = isCloseParen(ch))) { + var p = $parens.pop(); + if (!p || p.type != tmp) { + foundToken(stream.col, ++stream.col, "error"); + } else { + // circular reference; poor browsers will leak. mwuhahahaha + p.closed = { line: stream.line, col: stream.col, opened: p }; + $passedParens.push(p); + foundToken(stream.col, ++stream.col, "close-paren"); + } + } + else if (ch === "/" && ALLOW_REGEXP_AFTER.test(stream.textBefore())) { + foundToken(stream.col, ++stream.col, "regexp-starter"); + $cont.push(readLiteralRegexp); + } + else if ((m = stream.lookingAt(/^\s+$/))) { + foundToken(stream.col, stream.col += m[0].length, "trailing-whitespace"); + } + else { + foundToken(stream.col, ++stream.col, null); + } + }; + + function indentation() { + + // no indentation for continued strings + if ($inString) + return 0; + + var row = stream.line; + var currentLine = stream.lineText(); + var indent = 0; + + if ($inComment) { + var commentStartLine = stream.lineText($inComment.line); + indent = $inComment.c1 + 1; + if (!/^\s*\*/.test(currentLine)) { + // align with the first non-whitespace and non-asterisk character in the comment + var re = /[^\s*]/g; + re.lastIndex = $inComment.c1 + 1; + var m = re.exec(commentStartLine); + if (m) + indent = m.index; + } + return indent; + } + + var p = $parens.peek(); + if (p) { + // check if the current line closes the paren + var re = new RegExp("^\\s*\\" + OPEN_PAREN[p.type]); + var thisLineCloses = re.test(currentLine); + + // Check if there is text after the opening paren. If so, indent to that column. + var line = stream.lineText(p.line); + re = /\S/g; + re.lastIndex = p.col + 1; + var m = re.exec(line); + if (m) { + // but if this line closes the paren, better use the column of the open paren + indent = thisLineCloses ? p.col : m.index; + } + else { + // Otherwise we should indent to one level more than the indentation of the line + // containing the opening paren. + indent = stream.lineIndentation(p.line) + INDENT_LEVEL(); + + // but if this line closes the paren, then back one level + if (thisLineCloses) + indent -= INDENT_LEVEL(); + } + } + + // Some more adjustments for continued statements. Since we don't really have a + // rigorous parser, we have to rely on other regexps here, which sucks but will do for + // now. + + if (row > 0) { + var before = stream.textBefore(); + if (/\)\s*$/.test(before) && $passedParens.length > 0) { + // Ends in a paren, could be an if, while or for which demands smart + // indentation on the current line, let's check it out. + + // Note that the passedParen saved for that close paren is actually + // the opening one, which suits us greatly. + p = $passedParens.peek(); + var stmtLine = stream.lineText(p.line); + if (/^\s*(if|for|while)\W/.test(stmtLine)) + indent += INDENT_LEVEL(); + } + else if (/\Welse\s*$/.test(before)) { + indent += INDENT_LEVEL(); + } + } + + // switch labels use half the indent level, which is my favorite + if (/^\s*(case|default)\W/.test(currentLine)) + indent -= INDENT_LEVEL() / 2; + + return indent; + }; + + return PARSER; + + }; + + Ymacs_Tokenizer.define("js", JS_PARSER.$C( + KEYWORDS.toHash(true), + KEYWORDS_TYPE.toHash(true), + KEYWORDS_CONST.toHash(true), + KEYWORDS_BUILTIN.toHash(true) + )); + + /* -----[ DynarchLIB ]----- */ + + var DL_KEYWORDS_BUILTIN = KEYWORDS_BUILTIN.concat("\ +DEFINE_CLASS DEFINE_SINGLETON DEFINE_HIDDEN_CLASS \ +DEFAULT_ARGS DEFAULT_EVENTS \ +FIXARGS CONSTRUCT BEFORE_BASE FINISH_OBJECT_DEF \ +D P $".qw()); + + Ymacs_Tokenizer.define("js-dynarchlib", JS_PARSER.$C( + KEYWORDS.toHash(true), + KEYWORDS_TYPE.toHash(true), + KEYWORDS_CONST.toHash(true), + DL_KEYWORDS_BUILTIN.toHash(true) + )); + +})(); + +/* -----[ Keymap for C-like language mode ]----- */ + +DEFINE_SINGLETON("Ymacs_Keymap_CLanguages", Ymacs_Keymap, function(D, P){ + + D.KEYS = { + "ENTER" : "newline_and_indent", + "} && ) && ] && : && ; && { && ( && [ && *" : "c_insert_and_indent" + // "{" : "c_electric_block" + }; + +}); + +/* -----[ Mode entry point ]----- */ + +Ymacs_Buffer.newMode("javascript_mode", function(useDL) { + var tok = this.tokenizer; + var keymap = Ymacs_Keymap_CLanguages(); + this.setTokenizer(new Ymacs_Tokenizer({ buffer: this, type: useDL ? "js-dynarchlib" : "js" })); + this.pushKeymap(keymap); + var was_paren_match = this.cmd("paren_match_mode", true); + + return function() { + this.setTokenizer(tok); + this.popKeymap(keymap); + if (!was_paren_match) + this.cmd("paren_match_mode", false); + }; + +}); + +Ymacs_Buffer.newCommands({ + + javascript_dl_mode: Ymacs_Interactive(function() { + return this.cmd("javascript_mode", true); + }), + + c_electric_block: Ymacs_Interactive(function() { + this.cmd("indent_line"); + this.cmd("insert", "{\n\n}"); + this.cmd("indent_line"); + this.cmd("backward_line", 1); + this.cmd("indent_line"); + }), + + c_insert_and_indent: Ymacs_Interactive(function() { + var ret; + if ((ret = this.cmd("self_insert_command"))) { + this.cmd("indent_line"); + return ret; + } + }) + +}); |