From b91f4d09413e73ae317ea0d5c025fae47082c94a Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Mon, 15 Nov 2010 12:45:07 +0000 Subject: [PATCH 01/90] adjusting paths to use ace/ rather than ./ --- lib/ace/background_tokenizer.js | 4 +-- lib/ace/commands/default_commands.js | 2 +- lib/ace/document.js | 12 ++++----- lib/ace/editor.js | 20 +++++++-------- lib/ace/event_emitter.js | 2 +- lib/ace/keybinding.js | 12 ++++----- lib/ace/layer/cursor.js | 2 +- lib/ace/layer/marker.js | 2 +- lib/ace/layer/text.js | 6 ++--- lib/ace/lib/dom.js | 2 +- lib/ace/lib/event.js | 3 +-- lib/ace/mode/css.js | 10 ++++---- lib/ace/mode/css_highlight_rules.js | 6 ++--- lib/ace/mode/doc_comment_highlight_rules.js | 4 +-- lib/ace/mode/html.js | 12 ++++----- lib/ace/mode/html_highlight_rules.js | 8 +++--- lib/ace/mode/javascript.js | 12 ++++----- lib/ace/mode/javascript_highlight_rules.js | 8 +++--- lib/ace/mode/matching_brace_outdent.js | 2 +- lib/ace/mode/text.js | 4 +-- lib/ace/mode/xml.js | 8 +++--- lib/ace/mode/xml_highlight_rules.js | 4 +-- lib/ace/renderloop.js | 2 +- lib/ace/scrollbar.js | 10 ++++---- lib/ace/search.js | 6 ++--- lib/ace/selection.js | 8 +++--- lib/ace/textinput.js | 2 +- lib/ace/theme/clouds.js | 2 +- lib/ace/theme/clouds_mignight.js | 2 +- lib/ace/theme/cobalt.js | 2 +- lib/ace/theme/dawn.js | 2 +- lib/ace/theme/eclipse.js | 6 ++--- lib/ace/theme/idle_fingers.js | 2 +- lib/ace/theme/kr_theme.js | 2 +- lib/ace/theme/mono_industrial.js | 2 +- lib/ace/theme/monokai.js | 2 +- lib/ace/theme/textmate.js | 6 ++--- lib/ace/theme/twilight.js | 2 +- lib/ace/virtual_renderer.js | 28 ++++++++++----------- tool/theme.tmpl.js | 2 +- 40 files changed, 115 insertions(+), 118 deletions(-) diff --git a/lib/ace/background_tokenizer.js b/lib/ace/background_tokenizer.js index d3d6828f..35f73f9d 100644 --- a/lib/ace/background_tokenizer.js +++ b/lib/ace/background_tokenizer.js @@ -37,8 +37,8 @@ define(function(require, exports, module) { -var oop = require("./lib/oop"); -var MEventEmitter = require("./event_emitter"); +var oop = require("ace/lib/oop"); +var MEventEmitter = require("ace/event_emitter"); var BackgroundTokenizer = function(tokenizer, editor) { this.running = false; diff --git a/lib/ace/commands/default_commands.js b/lib/ace/commands/default_commands.js index 8d6a221a..a83a464b 100644 --- a/lib/ace/commands/default_commands.js +++ b/lib/ace/commands/default_commands.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var PluginManager = require("../plugin_manager"); +var PluginManager = require("ace/plugin_manager"); PluginManager.registerCommand("selectall", function(editor, selection) { selection.selectAll(); diff --git a/lib/ace/document.js b/lib/ace/document.js index f265ea73..4e6e21a5 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -37,12 +37,12 @@ define(function(require, exports, module) { -var oop = require("./lib/oop"); -var lang = require("./lib/lang"); -var MEventEmitter = require("./event_emitter"); -var Selection = require("./selection"); -var TextMode = require("./mode/text"); -var Range = require("./range"); +var oop = require("ace/lib/oop"); +var lang = require("ace/lib/lang"); +var MEventEmitter = require("ace/event_emitter"); +var Selection = require("ace/selection"); +var TextMode = require("ace/mode/text"); +var Range = require("ace/range"); var Document = function(text, mode) { this.modified = true; diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 20b7f249..fb8993ce 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -37,16 +37,16 @@ define(function(require, exports, module) { -var oop = require("./lib/oop"); -var event = require("./lib/event"); -var lang = require("./lib/lang"); -var TextInput = require("./textinput"); -var KeyBinding = require("./keybinding"); -var Document = require("./document"); -var Search = require("./search"); -var BackgroundTokenizer = require("./background_tokenizer"); -var Range = require("./range"); -var MEventEmitter = require("./event_emitter"); +var oop = require("ace/lib/oop"); +var event = require("ace/lib/event"); +var lang = require("ace/lib/lang"); +var TextInput = require("ace/textinput"); +var KeyBinding = require("ace/keybinding"); +var Document = require("ace/document"); +var Search = require("ace/search"); +var BackgroundTokenizer = require("ace/background_tokenizer"); +var Range = require("ace/range"); +var MEventEmitter = require("ace/event_emitter"); var Editor =function(renderer, doc) { var container = renderer.getContainerElement(); diff --git a/lib/ace/event_emitter.js b/lib/ace/event_emitter.js index ee73b3c1..29b0b170 100644 --- a/lib/ace/event_emitter.js +++ b/lib/ace/event_emitter.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { - var lang = require("./lib/lang"); + var lang = require("ace/lib/lang"); var MEventEmitter = {} diff --git a/lib/ace/keybinding.js b/lib/ace/keybinding.js index 1adc4886..94f7e072 100644 --- a/lib/ace/keybinding.js +++ b/lib/ace/keybinding.js @@ -37,12 +37,12 @@ define(function(require, exports, module) { -var core = require("./lib/core"); -var event = require("./lib/event"); -var default_mac = require("./conf/keybindings/default_mac"); -var default_win = require("./conf/keybindings/default_win"); -var PluginManager = require("./plugin_manager"); -require("./commands/default_commands"); +var core = require("ace/lib/core"); +var event = require("ace/lib/event"); +var default_mac = require("ace/conf/keybindings/default_mac"); +var default_win = require("ace/conf/keybindings/default_win"); +var PluginManager = require("ace/plugin_manager"); +require("ace/commands/default_commands"); var KeyBinding = function(element, editor, config) { this.setConfig(config); diff --git a/lib/ace/layer/cursor.js b/lib/ace/layer/cursor.js index f1f99916..04402481 100644 --- a/lib/ace/layer/cursor.js +++ b/lib/ace/layer/cursor.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var dom = require("../lib/dom"); +var dom = require("ace/lib/dom"); var Cursor = function(parentEl) { this.element = document.createElement("div"); diff --git a/lib/ace/layer/marker.js b/lib/ace/layer/marker.js index 0c304915..0466f4be 100644 --- a/lib/ace/layer/marker.js +++ b/lib/ace/layer/marker.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var Range = require("../range"); +var Range = require("ace/range"); var Marker = function(parentEl) { this.element = document.createElement("div"); diff --git a/lib/ace/layer/text.js b/lib/ace/layer/text.js index 1c1a6264..eb632a68 100644 --- a/lib/ace/layer/text.js +++ b/lib/ace/layer/text.js @@ -37,9 +37,9 @@ define(function(require, exports, module) { -var oop = require("../lib/oop"); -var dom = require("../lib/dom"); -var MEventEmitter = require("../event_emitter"); +var oop = require("ace/lib/oop"); +var dom = require("ace/lib/dom"); +var MEventEmitter = require("ace/event_emitter"); var Text = function(parentEl) { this.element = document.createElement("div"); diff --git a/lib/ace/lib/dom.js b/lib/ace/lib/dom.js index 86cd1e4b..069a2bd9 100644 --- a/lib/ace/lib/dom.js +++ b/lib/ace/lib/dom.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var lang = require("./lang"); + var lang = require("ace/lib/lang"); var dom = {}; diff --git a/lib/ace/lib/event.js b/lib/ace/lib/event.js index 33176db2..a1561184 100644 --- a/lib/ace/lib/event.js +++ b/lib/ace/lib/event.js @@ -37,8 +37,7 @@ define(function(require, exports, module) { - -var core = require("./core"); + var core = require("ace/lib/core"); var event = {}; event.addListener = function(elem, type, callback) { diff --git a/lib/ace/mode/css.js b/lib/ace/mode/css.js index 91819a91..a869fd8b 100644 --- a/lib/ace/mode/css.js +++ b/lib/ace/mode/css.js @@ -37,11 +37,11 @@ define(function(require, exports, module) { -var oop = require("../lib/oop"); -var TextMode = require("./text"); -var Tokenizer = require("../tokenizer"); -var CssHighlightRules = require("./css_highlight_rules"); -var MatchingBraceOutdent = require("./matching_brace_outdent"); +var oop = require("ace/lib/oop"); +var TextMode = require("ace/mode/text"); +var Tokenizer = require("ace/tokenizer"); +var CssHighlightRules = require("ace/mode/css_highlight_rules"); +var MatchingBraceOutdent = require("ace/mode/matching_brace_outdent"); var Css = function() { this.$tokenizer = new Tokenizer(new CssHighlightRules().getRules()); diff --git a/lib/ace/mode/css_highlight_rules.js b/lib/ace/mode/css_highlight_rules.js index 938b9bca..992850a5 100644 --- a/lib/ace/mode/css_highlight_rules.js +++ b/lib/ace/mode/css_highlight_rules.js @@ -37,9 +37,9 @@ define(function(require, exports, module) { -var oop = require("../lib/oop"); -var lang = require("../lib/lang"); -var TextHighlightRules = require("./text_highlight_rules"); +var oop = require("ace/lib/oop"); +var lang = require("ace/lib/lang"); +var TextHighlightRules = require("ace/mode/text_highlight_rules"); var CssHighlightRules = function() { diff --git a/lib/ace/mode/doc_comment_highlight_rules.js b/lib/ace/mode/doc_comment_highlight_rules.js index 5db3a5d1..ad156c1d 100644 --- a/lib/ace/mode/doc_comment_highlight_rules.js +++ b/lib/ace/mode/doc_comment_highlight_rules.js @@ -37,8 +37,8 @@ define(function(require, exports, module) { -var oop = require("../lib/oop"); -var TextHighlightRules = require("./text_highlight_rules"); +var oop = require("ace/lib/oop"); +var TextHighlightRules = require("ace/mode/text_highlight_rules"); var DocCommentHighlightRules = function() { diff --git a/lib/ace/mode/html.js b/lib/ace/mode/html.js index 8694b00a..15e9cea1 100644 --- a/lib/ace/mode/html.js +++ b/lib/ace/mode/html.js @@ -37,12 +37,12 @@ define(function(require, exports, module) { -var oop = require("../lib/oop"); -var TextMode = require("./text"); -var JavaScriptMode = require("./javascript"); -var CssMode = require("./css"); -var Tokenizer = require("../tokenizer"); -var HtmlHighlightRules = require("./html_highlight_rules"); +var oop = require("ace/lib/oop"); +var TextMode = require("ace/mode/text"); +var JavaScriptMode = require("ace/mode/javascript"); +var CssMode = require("ace/mode/css"); +var Tokenizer = require("ace/tokenizer"); +var HtmlHighlightRules = require("ace/mode/html_highlight_rules"); var Html = function() { this.$tokenizer = new Tokenizer(new HtmlHighlightRules().getRules()); diff --git a/lib/ace/mode/html_highlight_rules.js b/lib/ace/mode/html_highlight_rules.js index c914b112..63eae027 100644 --- a/lib/ace/mode/html_highlight_rules.js +++ b/lib/ace/mode/html_highlight_rules.js @@ -37,10 +37,10 @@ define(function(require, exports, module) { -var oop = require("../lib/oop"); -var CssHighlightRules = require("./css_highlight_rules"); -var JavaScriptHighlightRules = require("./javascript_highlight_rules"); -var TextHighlightRules = require("./text_highlight_rules"); +var oop = require("ace/lib/oop"); +var CssHighlightRules = require("ace/mode/css_highlight_rules"); +var JavaScriptHighlightRules = require("ace/mode/javascript_highlight_rules"); +var TextHighlightRules = require("ace/mode/text_highlight_rules"); var HtmlHighlightRules = function() { diff --git a/lib/ace/mode/javascript.js b/lib/ace/mode/javascript.js index 92cd117d..828bf3c4 100644 --- a/lib/ace/mode/javascript.js +++ b/lib/ace/mode/javascript.js @@ -37,12 +37,12 @@ define(function(require, exports, module) { -var oop = require("../lib/oop"); -var TextMode = require("./text"); -var Tokenizer = require("../tokenizer"); -var JavaScriptHighlightRules = require("./javascript_highlight_rules"); -var MatchingBraceOutdent = require("./matching_brace_outdent"); -var Range = require("../range"); +var oop = require("ace/lib/oop"); +var TextMode = require("ace/mode/text"); +var Tokenizer = require("ace/tokenizer"); +var JavaScriptHighlightRules = require("ace/mode/javascript_highlight_rules"); +var MatchingBraceOutdent = require("ace/mode/matching_brace_outdent"); +var Range = require("ace/range"); var JavaScript = function() { this.$tokenizer = new Tokenizer(new JavaScriptHighlightRules().getRules()); diff --git a/lib/ace/mode/javascript_highlight_rules.js b/lib/ace/mode/javascript_highlight_rules.js index 039422c4..893e762f 100644 --- a/lib/ace/mode/javascript_highlight_rules.js +++ b/lib/ace/mode/javascript_highlight_rules.js @@ -37,10 +37,10 @@ define(function(require, exports, module) { -var oop = require("../lib/oop"); -var lang = require("../lib/lang"); -var DocCommentHighlightRules = require("./doc_comment_highlight_rules"); -var TextHighlightRules = require("./text_highlight_rules"); +var oop = require("ace/lib/oop"); +var lang = require("ace/lib/lang"); +var DocCommentHighlightRules = require("ace/mode/doc_comment_highlight_rules"); +var TextHighlightRules = require("ace/mode/text_highlight_rules"); JavaScriptHighlightRules = function() { diff --git a/lib/ace/mode/matching_brace_outdent.js b/lib/ace/mode/matching_brace_outdent.js index 82777425..3c871a14 100644 --- a/lib/ace/mode/matching_brace_outdent.js +++ b/lib/ace/mode/matching_brace_outdent.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var Range = require("../range"); +var Range = require("ace/range"); var MatchingBraceOutdent = function() {}; diff --git a/lib/ace/mode/text.js b/lib/ace/mode/text.js index 7cf04cb8..3ee899d1 100644 --- a/lib/ace/mode/text.js +++ b/lib/ace/mode/text.js @@ -37,8 +37,8 @@ define(function(require, exports, module) { -var Tokenizer = require("../tokenizer"); -var TextHighlightRules = require("./text_highlight_rules"); +var Tokenizer = require("ace/tokenizer"); +var TextHighlightRules = require("ace/mode/text_highlight_rules"); var Text = function() { this.$tokenizer = new Tokenizer(new TextHighlightRules().getRules()); diff --git a/lib/ace/mode/xml.js b/lib/ace/mode/xml.js index a64eeac7..545e487e 100644 --- a/lib/ace/mode/xml.js +++ b/lib/ace/mode/xml.js @@ -37,10 +37,10 @@ define(function(require, exports, module) { -var oop = require("../lib/oop"); -var TextMode = require("./text"); -var Tokenizer = require("../tokenizer"); -var XmlHighlightRules = require("./xml_highlight_rules"); +var oop = require("ace/lib/oop"); +var TextMode = require("ace/mode/text"); +var Tokenizer = require("ace/tokenizer"); +var XmlHighlightRules = require("ace/mode/xml_highlight_rules"); var Xml = function() { this.$tokenizer = new Tokenizer(new XmlHighlightRules().getRules()); diff --git a/lib/ace/mode/xml_highlight_rules.js b/lib/ace/mode/xml_highlight_rules.js index 69e7b691..b1421791 100644 --- a/lib/ace/mode/xml_highlight_rules.js +++ b/lib/ace/mode/xml_highlight_rules.js @@ -37,8 +37,8 @@ define(function(require, exports, module) { -var oop = require("../lib/oop"); -var TextHighlightRules = require("./text_highlight_rules"); +var oop = require("ace/lib/oop"); +var TextHighlightRules = require("ace/mode/text_highlight_rules"); var XmlHighlightRules = function() { diff --git a/lib/ace/renderloop.js b/lib/ace/renderloop.js index 2adcdf03..df54e8e0 100644 --- a/lib/ace/renderloop.js +++ b/lib/ace/renderloop.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var event = require("./lib/event") +var event = require("ace/lib/event") var RenderLoop = function(onRender) { this.onRender = onRender; diff --git a/lib/ace/scrollbar.js b/lib/ace/scrollbar.js index ec7f0197..ba7acd0d 100644 --- a/lib/ace/scrollbar.js +++ b/lib/ace/scrollbar.js @@ -37,11 +37,11 @@ define(function(require, exports, module) { -var oop = require("./lib/oop"); -var lang = require("./lib/lang"); -var dom = require("./lib/dom"); -var event = require("./lib/event"); -var MEventEmitter = require("./event_emitter"); +var oop = require("ace/lib/oop"); +var lang = require("ace/lib/lang"); +var dom = require("ace/lib/dom"); +var event = require("ace/lib/event"); +var MEventEmitter = require("ace/event_emitter"); var ScrollBar = function(parent) { this.element = document.createElement("div"); diff --git a/lib/ace/search.js b/lib/ace/search.js index e3f040c4..d751e399 100644 --- a/lib/ace/search.js +++ b/lib/ace/search.js @@ -37,9 +37,9 @@ define(function(require, exports, module) { -var lang = require("./lib/lang"); -var oop = require("./lib/oop"); -var Range = require("./range"); +var lang = require("ace/lib/lang"); +var oop = require("ace/lib/oop"); +var Range = require("ace/range"); var Search = function() { this.$options = { diff --git a/lib/ace/selection.js b/lib/ace/selection.js index 7af93630..8a7f9c19 100644 --- a/lib/ace/selection.js +++ b/lib/ace/selection.js @@ -37,10 +37,10 @@ define(function(require, exports, module) { -var oop = require("./lib/oop"); -var lang = require("./lib/lang"); -var MEventEmitter = require("./event_emitter"); -var Range = require("./range"); +var oop = require("ace/lib/oop"); +var lang = require("ace/lib/lang"); +var MEventEmitter = require("ace/event_emitter"); +var Range = require("ace/range"); var Selection = function(doc) { this.doc = doc; diff --git a/lib/ace/textinput.js b/lib/ace/textinput.js index 4bcf479f..629c0e95 100644 --- a/lib/ace/textinput.js +++ b/lib/ace/textinput.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var event = require("./lib/event"); +var event = require("ace/lib/event"); var TextInput = function(parentNode, host) { diff --git a/lib/ace/theme/clouds.js b/lib/ace/theme/clouds.js index 9489d9ea..2b8436e1 100644 --- a/lib/ace/theme/clouds.js +++ b/lib/ace/theme/clouds.js @@ -1,6 +1,6 @@ define(function(require, exports, module) { -var dom = require("../lib/dom"); +var dom = require("ace/lib/dom"); var cssText = ".ace-clouds .ace_editor {\ border: 2px solid rgb(159, 159, 159);\ diff --git a/lib/ace/theme/clouds_mignight.js b/lib/ace/theme/clouds_mignight.js index 93c3f99d..b42978c8 100644 --- a/lib/ace/theme/clouds_mignight.js +++ b/lib/ace/theme/clouds_mignight.js @@ -1,6 +1,6 @@ define(function(require, exports, module) { -var dom = require("../lib/dom"); +var dom = require("ace/lib/dom"); var cssText = ".ace-clouds-midnight .ace_editor {\ border: 2px solid rgb(159, 159, 159);\ diff --git a/lib/ace/theme/cobalt.js b/lib/ace/theme/cobalt.js index def66f11..433214b3 100644 --- a/lib/ace/theme/cobalt.js +++ b/lib/ace/theme/cobalt.js @@ -1,6 +1,6 @@ define(function(require, exports, module) { -var dom = require("../lib/dom"); +var dom = require("ace/lib/dom"); var cssText = ".ace-cobalt .ace_editor {\ diff --git a/lib/ace/theme/dawn.js b/lib/ace/theme/dawn.js index 247336da..ed6d33f1 100644 --- a/lib/ace/theme/dawn.js +++ b/lib/ace/theme/dawn.js @@ -1,6 +1,6 @@ define(function(require, exports, module) { -var dom = require("../lib/dom"); +var dom = require("ace/lib/dom"); var cssText = ".ace-dawn .ace_editor {\ border: 2px solid rgb(159, 159, 159);\ diff --git a/lib/ace/theme/eclipse.js b/lib/ace/theme/eclipse.js index 8cee6e9e..4bc7b13d 100644 --- a/lib/ace/theme/eclipse.js +++ b/lib/ace/theme/eclipse.js @@ -1,7 +1,7 @@ -define(["require", "exports", "module", "text!ace/theme/eclipse.css", "../lib/dom"], - function(require, exports, module, cssText) { +define(function(require, exports, module) { - var dom = require("../lib/dom"); +var dom = require("ace/lib/dom"); +var cssText = require("text!ace/theme/eclipse.css"); // import CSS once dom.importCssString(cssText); diff --git a/lib/ace/theme/idle_fingers.js b/lib/ace/theme/idle_fingers.js index 6975a87d..f922c9fa 100644 --- a/lib/ace/theme/idle_fingers.js +++ b/lib/ace/theme/idle_fingers.js @@ -1,6 +1,6 @@ define(function(require, exports, module) { -var dom = require("../lib/dom"); +var dom = require("ace/lib/dom"); var cssText = ".ace-idle-fingers .ace_editor {\ diff --git a/lib/ace/theme/kr_theme.js b/lib/ace/theme/kr_theme.js index 406f159b..684fd02e 100644 --- a/lib/ace/theme/kr_theme.js +++ b/lib/ace/theme/kr_theme.js @@ -1,6 +1,6 @@ define(function(require, exports, module) { -var dom = require("../lib/dom"); +var dom = require("ace/lib/dom"); var cssText = ".ace-kr-theme .ace_editor {\ diff --git a/lib/ace/theme/mono_industrial.js b/lib/ace/theme/mono_industrial.js index 842f7ec3..1463ec4a 100644 --- a/lib/ace/theme/mono_industrial.js +++ b/lib/ace/theme/mono_industrial.js @@ -1,6 +1,6 @@ define(function(require, exports, module) { -var dom = require("../lib/dom"); +var dom = require("ace/lib/dom"); var cssText = ".ace-mono-industrial .ace_editor {\ diff --git a/lib/ace/theme/monokai.js b/lib/ace/theme/monokai.js index d20ac5d5..e7122013 100644 --- a/lib/ace/theme/monokai.js +++ b/lib/ace/theme/monokai.js @@ -1,6 +1,6 @@ define(function(require, exports, module) { -var dom = require("../lib/dom"); +var dom = require("ace/lib/dom"); var cssText = ".ace-monokai .ace_editor {\ diff --git a/lib/ace/theme/textmate.js b/lib/ace/theme/textmate.js index a28c2d6e..4ad77e77 100644 --- a/lib/ace/theme/textmate.js +++ b/lib/ace/theme/textmate.js @@ -1,7 +1,7 @@ -define(["require", "exports", "module", "text!ace/theme/tm.css", "../lib/dom"], - function(require, exports, module, cssText) { +define(function(require, exports, module) { - var dom = require("../lib/dom"); + var dom = require("ace/lib/dom"); + var cssText = require("text!ace/theme/tm.css"); // import CSS once dom.importCssString(cssText); diff --git a/lib/ace/theme/twilight.js b/lib/ace/theme/twilight.js index 1f3d61d5..42b636ed 100644 --- a/lib/ace/theme/twilight.js +++ b/lib/ace/theme/twilight.js @@ -1,6 +1,6 @@ define(function(require, exports, module) { -var dom = require("../lib/dom"); +var dom = require("ace/lib/dom"); var cssText = ".ace-twilight .ace_editor {\ border: 2px solid rgb(159, 159, 159);\ diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index f0e93fbc..8f3544a7 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -35,22 +35,20 @@ * * ***** END LICENSE BLOCK ***** */ -define(["require", "exports", "module", "text!ace/css/editor.css", "./lib/oop", "./lib/oop", - "./lib/event", "./layer/gutter", "./layer/marker", "./layer/text", - "./layer/cursor", "./scrollbar", "./renderloop", "./event_emitter"], - function(require, exports, module, editorCss) { +define(function(require, exports, module) { -var oop = require("./lib/oop"); -var lang = require("./lib/lang"); -var dom = require("./lib/dom"); -var event = require("./lib/event"); -var GutterLayer = require("./layer/gutter"); -var MarkerLayer = require("./layer/marker"); -var TextLayer = require("./layer/text"); -var CursorLayer = require("./layer/cursor"); -var ScrollBar = require("./scrollbar"); -var RenderLoop = require("./renderloop"); -var MEventEmitter = require("./event_emitter"); +var oop = require("ace/lib/oop"); +var lang = require("ace/lib/lang"); +var dom = require("ace/lib/dom"); +var event = require("ace/lib/event"); +var GutterLayer = require("ace/layer/gutter"); +var MarkerLayer = require("ace/layer/marker"); +var TextLayer = require("ace/layer/text"); +var CursorLayer = require("ace/layer/cursor"); +var ScrollBar = require("ace/scrollbar"); +var RenderLoop = require("ace/renderloop"); +var MEventEmitter = require("ace/event_emitter"); +var editorCss = require("text!ace/css/editor.css"); // import CSS once dom.importCssString(editorCss); diff --git a/tool/theme.tmpl.js b/tool/theme.tmpl.js index b4eed087..d7cd7f73 100644 --- a/tool/theme.tmpl.js +++ b/tool/theme.tmpl.js @@ -1,5 +1,5 @@ define(function(require, exports, module) { - var dom = require("./lib/dom"); + var dom = require("ace/lib/dom"); var cssText = %css%; // import CSS once From 57f1c2bf95bb4f111db9d72cb0743eb82a60548e Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Mon, 15 Nov 2010 12:59:24 +0000 Subject: [PATCH 02/90] upgrade to requirejs - warning the copy in demo is only a partial upgrade to fix the immediate text loading issue --- demo/require.js | 94 +++++++++++++++++++++++++++-------------------- support/requirejs | 2 +- 2 files changed, 56 insertions(+), 40 deletions(-) diff --git a/demo/require.js b/demo/require.js index 29462455..1f94622e 100644 --- a/demo/require.js +++ b/demo/require.js @@ -13,16 +13,20 @@ setInterval: false, importScripts: false, jQuery: false */ var require, define; (function () { //Change this version number for each release. - var version = "0.14.5", + var version = "0.14.5+", empty = {}, s, i, defContextName = "_", contextLoads = [], scripts, script, rePkg, src, m, dataMain, cfg = {}, setReadyState, - readyRegExp = /^(complete|loaded)$/, commentRegExp = /(\/\*([\s\S]*?)\*\/|\/\/(.*)$)/mg, - cjsRequireRegExp = /require\(["']([\w-_\.\/]+)["']\)/g, + cjsRequireRegExp = /require\(["']([\w\!\-_\.\/]+)["']\)/g, main, isBrowser = !!(typeof window !== "undefined" && navigator && document), isWebWorker = !isBrowser && typeof importScripts !== "undefined", + //PS3 indicates loaded and complete, but need to wait for complete + //specifically. Sequence is "loading", "loaded", execution, + // then "complete". The UA check is unfortunate, but not sure how + //to feature test w/o causing perf issues. + readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ? /^complete$/ : /^(complete|loaded)$/, ostring = Object.prototype.toString, ap = Array.prototype, aps = ap.slice, scrollIntervalId, req, baseElement, @@ -882,12 +886,12 @@ var require, define; } contextName = contextName || s.ctxName; - var ret, context = s.contexts[contextName]; + var ret, context = s.contexts[contextName], nameProps; //Normalize module name, if it contains . or .. - moduleName = req.normalizeName(moduleName, relModuleName, context); + nameProps = req.splitPrefix(moduleName, relModuleName, context); - ret = context.defined[moduleName]; + ret = context.defined[nameProps.name]; if (ret === undefined) { req.onError(new Error("require: module name '" + moduleName + @@ -940,7 +944,7 @@ var require, define; } }; - req.jsExtRegExp = /\.js$/; + req.jsExtRegExp = /^\/|:|\?|\.js$/; /** * Given a relative module name, like ./something, normalize it to @@ -955,37 +959,44 @@ var require, define; //Adjust any relative paths. var part; if (name.charAt(0) === ".") { - if (!baseName) { - req.onError(new Error("Cannot normalize module name: " + - name + - ", no relative module name available.")); - } - - if (context.config.packages[baseName]) { - //If the baseName is a package name, then just treat it as one - //name to concat the name with. - baseName = [baseName]; - } else { - //Convert baseName to array, and lop off the last part, - //so that . matches that "directory" and not name of the baseName's - //module. For instance, baseName of "one/two/three", maps to - //"one/two/three.js", but we want the directory, "one/two" for - //this normalization. - baseName = baseName.split("/"); - baseName = baseName.slice(0, baseName.length - 1); - } - - name = baseName.concat(name.split("/")); - for (i = 0; (part = name[i]); i++) { - if (part === ".") { - name.splice(i, 1); - i -= 1; - } else if (part === "..") { - name.splice(i - 1, 2); - i -= 2; + //If have a base name, try to normalize against it, + //otherwise, assume it is a top-level require that will + //be relative to baseUrl in the end. + if (baseName) { + if (context.config.packages[baseName]) { + //If the baseName is a package name, then just treat it as one + //name to concat the name with. + baseName = [baseName]; + } else { + //Convert baseName to array, and lop off the last part, + //so that . matches that "directory" and not name of the baseName's + //module. For instance, baseName of "one/two/three", maps to + //"one/two/three.js", but we want the directory, "one/two" for + //this normalization. + baseName = baseName.split("/"); + baseName = baseName.slice(0, baseName.length - 1); } + + name = baseName.concat(name.split("/")); + for (i = 0; (part = name[i]); i++) { + if (part === ".") { + name.splice(i, 1); + i -= 1; + } else if (part === "..") { + if (i === 1) { + //End of the line. Keep at least one non-dot + //path segment at the front so it can be mapped + //correctly to disk. Otherwise, there is likely + //no path mapping for '..'. + break; + } else if (i > 1) { + name.splice(i - 1, 2); + i -= 2; + } + } + } + name = name.join("/"); } - name = name.join("/"); } return name; }; @@ -1035,7 +1046,7 @@ var require, define; //If a colon is in the URL, it indicates a protocol is used and it is just //an URL to a file, or if it starts with a slash or ends with .js, it is just a plain file. //The slash is important for protocol-less URLs as well as full paths. - if (moduleName.indexOf(":") !== -1 || moduleName.charAt(0) === '/' || req.jsExtRegExp.test(moduleName)) { + if (req.jsExtRegExp.test(moduleName)) { //Just a plain path, not module name lookup, so just return it. //Add extension if it is included. This is a bit wonky, only non-.js things pass //an extension, this method probably needs to be reworked. @@ -1078,6 +1089,11 @@ var require, define; config.urlArgs) : url; }; + //In async environments, checkLoaded can get called a few times in the same + //call stack. Allow only one to do the finishing work. Set to false + //for sync environments. + req.blockCheckLoaded = true; + /** * Checks if all modules for a context are loaded, and if so, evaluates the * new ones in right dependency order. @@ -1119,7 +1135,7 @@ var require, define; //by calling a waiting callback that then calls require and then this function //should not proceed. At the end of this function, if there are still things //waiting, then checkLoaded will be called again. - context.isCheckLoaded = true; + context.isCheckLoaded = req.blockCheckLoaded; //Grab waiting and loaded lists here, since it could have changed since //this function was first called. @@ -2477,4 +2493,4 @@ var require, define; }()); //Target build file for a require.js that has all of require's functionality, -//and includes specific plugins: i18n and text. \ No newline at end of file +//and includes specific plugins: i18n and text. diff --git a/support/requirejs b/support/requirejs index 819c4e7b..0095dc02 160000 --- a/support/requirejs +++ b/support/requirejs @@ -1 +1 @@ -Subproject commit 819c4e7b9b1e6e5f99696b5c9f2805891a9e7cfd +Subproject commit 0095dc028d0e6f3d40587071fa67622930aa880e From 6b7af71614a9091d485f99353d70a198c77f1d51 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Mon, 15 Nov 2010 13:05:01 +0000 Subject: [PATCH 03/90] moving and repointing editor paths so it will load via file:// --- demo/editor.html => editor.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename demo/editor.html => editor.html (98%) diff --git a/demo/editor.html b/editor.html similarity index 98% rename from demo/editor.html rename to editor.html index 1d5c1718..0488bb74 100644 --- a/demo/editor.html +++ b/editor.html @@ -48,7 +48,7 @@ } - +
@@ -92,7 +92,7 @@ - + @@ -134,7 +134,7 @@ + +
@@ -131,191 +151,5 @@ - - \ No newline at end of file diff --git a/plugins/pilot/lib/console.js b/plugins/pilot/lib/console.js new file mode 100644 index 00000000..b1fe5190 --- /dev/null +++ b/plugins/pilot/lib/console.js @@ -0,0 +1,76 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Joe Walker (jwalker@mozilla.com) + * Patrick Walton (pwalton@mozilla.com) + * Julian Viereck (jviereck@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +define(function(require, exports, module) { + +/** + * This object represents a "safe console" object that forwards debugging + * messages appropriately without creating a dependency on Firebug in Firefox. + */ + +var noop = function() {}; + +// These are the functions that are available in Chrome 4/5, Safari 4 +// and Firefox 3.6. Don't add to this list without checking browser support +var NAMES = [ + "assert", "count", "debug", "dir", "dirxml", "error", "group", "groupEnd", + "info", "log", "profile", "profileEnd", "time", "timeEnd", "trace", "warn" +]; + +if (typeof(window) === 'undefined') { + // We're in a web worker. Forward to the main thread so the messages + // will show up. + NAMES.forEach(function(name) { + exports[name] = function() { + var args = Array.prototype.slice.call(arguments); + var msg = { op: 'log', method: name, args: args }; + postMessage(JSON.stringify(msg)); + }; + }); +} else { + // For each of the console functions, copy them if they exist, stub if not + NAMES.forEach(function(name) { + if (window.console && window.console[name]) { + exports[name] = window.console[name].bind(window.console); + } else { + exports[name] = noop; + } + }); +} + +}); diff --git a/plugins/pilot/lib/index.js b/plugins/pilot/lib/index.js new file mode 100644 index 00000000..995afb8a --- /dev/null +++ b/plugins/pilot/lib/index.js @@ -0,0 +1,147 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Kevin Dangoor (kdangoor@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +exports.startup = function(data, reason) { + // Narwhal's shim for ES5 defineProperty + // ES5 15.2.3.6 + if (!Object.defineProperty) { + Object.defineProperty = function(object, property, descriptor) { + var has = Object.prototype.hasOwnProperty; + if (typeof descriptor == "object" && object.__defineGetter__) { + if (has.call(descriptor, "value")) { + if (!object.__lookupGetter__(property) && !object.__lookupSetter__(property)) { + // data property defined and no pre-existing accessors + object[property] = descriptor.value; + } + if (has.call(descriptor, "get") || has.call(descriptor, "set")) { + // descriptor has a value property but accessor already exists + throw new TypeError("Object doesn't support this action"); + } + } + // fail silently if "writable", "enumerable", or "configurable" + // are requested but not supported + /* + // alternate approach: + if ( // can't implement these features; allow false but not true + !(has.call(descriptor, "writable") ? descriptor.writable : true) || + !(has.call(descriptor, "enumerable") ? descriptor.enumerable : true) || + !(has.call(descriptor, "configurable") ? descriptor.configurable : true) + ) + throw new RangeError( + "This implementation of Object.defineProperty does not " + + "support configurable, enumerable, or writable." + ); + */ + else if (typeof descriptor.get == "function") { + object.__defineGetter__(property, descriptor.get); + } + if (typeof descriptor.set == "function") { + object.__defineSetter__(property, descriptor.set); + } + } + return object; + }; + } + + // ES5 15.2.3.7 + if (!Object.defineProperties) { + Object.defineProperties = function(object, properties) { + for (var property in properties) { + if (Object.prototype.hasOwnProperty.call(properties, property)) { + Object.defineProperty(object, property, properties[property]); + } + } + return object; + }; + } + + + + /** + * Array detector. + * Firefox 3.5 and Safari 4 have this already. Chrome 4 however ... + * Note to Dojo - your isArray is still broken: instanceof doesn't work with + * Arrays taken from a different frame/window. + */ + if (!Array.isArray) { + Array.isArray = function(data) { + return data && Object.prototype.toString.call(data) === "[object Array]"; + }; + } + + /** + * Retrieves the list of keys on an object. + */ + if (!Object.keys) { + Object.keys = function(obj) { + var k, ret = []; + for (k in obj) { + if (obj.hasOwnProperty(k)) { + ret.push(k); + } + } + return ret; + }; + } + + if (!Function.prototype.bind) { + // From Narwhal + Function.prototype.bind = function () { + var args = Array.prototype.slice.call(arguments); + var self = this; + var bound = function () { + return self.call.apply( + self, + args.concat( + Array.prototype.slice.call(arguments) + ) + ); + }; + bound.name = this.name; + bound.displayName = this.displayName; + bound.length = this.length; + bound.unbound = self; + return bound; + }; + } + + exports.globalsLoaded = true; +}; + +}); \ No newline at end of file diff --git a/plugins/pilot/lib/plugin_manager.js b/plugins/pilot/lib/plugin_manager.js new file mode 100644 index 00000000..75fceb61 --- /dev/null +++ b/plugins/pilot/lib/plugin_manager.js @@ -0,0 +1,149 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Kevin Dangoor (kdangoor@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +var Promise = require("pilot/promise").Promise; + +exports.REASONS = { + APP_STARTUP: 1, + APP_SHUTDOWN: 2, + PLUGIN_ENABLE: 3, + PLUGIN_DISABLE: 4, + PLUGIN_INSTALL: 5, + PLUGIN_UNINSTALL: 6, + PLUGIN_UPGRADE: 7, + PLUGIN_DOWNGRADE: 8 +}; + +exports.Plugin = function(name) { + this.name = name; + this.status = this.INSTALLED; +}; + +exports.Plugin.prototype = { + /** + * constants for the state + */ + NEW: 0, + INSTALLED: 1, + STARTED: 2, + SHUTDOWN: 3, + + install: function(data, reason) { + var pr = new Promise(); + if (this.status > this.NEW) { + pr.resolve(this); + return pr; + } + require([this.name], function(pluginModule) { + if (pluginModule.install) { + pluginModule.install(data, reason); + } + this.status = this.INSTALLED; + pr.resolve(this); + }.bind(this)); + return pr; + }, + + startup: function(data, reason) { + var pr = new Promise(); + if (this.status != this.INSTALLED) { + pr.resolve(this); + return pr; + } + require([this.name], function(pluginModule) { + if (pluginModule.startup) { + pluginModule.startup(data, reason); + } + this.status = this.STARTED; + pr.resolve(this); + }.bind(this)); + return pr; + }, + + shutdown: function(data, reason) { + if (this.status != this.STARTED) { + return; + } + pluginModule = require(this.name); + if (pluginModule.shutdown) { + pluginModule.shutdown(data, reason); + } + } +}; + +exports.PluginCatalog = function() { + this.plugins = {}; +}; + +exports.PluginCatalog.prototype = { + registerPlugins: function(pluginList) { + pluginList.forEach(function(pluginName) { + var plugin = this.plugins[pluginName]; + if (plugin === undefined) { + plugin = new exports.Plugin(pluginName); + this.plugins[pluginName] = plugin; + } + }.bind(this)); + }, + + startupPlugins: function(data, reason) { + var startupPromises = []; + for (var pluginName in this.plugins) { + var plugin = this.plugins[pluginName]; + startupPromises.push(plugin.startup(data, reason)); + } + return Promise.group(startupPromises); + } +}; + +exports.catalog = new exports.PluginCatalog(); + +// TODO the code below is temporary to bootstrap while setting up the new command system +var PluginManager = { + commands : {}, + + registerCommand : function(name, command) { + this.commands[name] = command; + } +}; + +exports.PluginManager = PluginManager; + + +}); diff --git a/plugins/pilot/lib/promise.js b/plugins/pilot/lib/promise.js new file mode 100644 index 00000000..8bd9f971 --- /dev/null +++ b/plugins/pilot/lib/promise.js @@ -0,0 +1,264 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Joe Walker (jwalker@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +var console = require("pilot/console"); +var Trace = require('pilot/stacktrace').Trace; + +/** + * A promise can be in one of 2 states. + * The ERROR and SUCCESS states are terminal, the PENDING state is the only + * start state. + */ +var ERROR = -1; +var PENDING = 0; +var SUCCESS = 1; + +/** + * We give promises and ID so we can track which are outstanding + */ +var _nextId = 0; + +/** + * Debugging help if 2 things try to complete the same promise. + * This can be slow (especially on chrome due to the stack trace unwinding) so + * we should leave this turned off in normal use. + */ +var _traceCompletion = false; + +/** + * Outstanding promises. Handy list for debugging only. + */ +var _outstanding = []; + +/** + * Recently resolved promises. Also for debugging only. + */ +var _recent = []; + +/** + * Create an unfulfilled promise + */ +Promise = function () { + this._status = PENDING; + this._value = undefined; + this._onSuccessHandlers = []; + this._onErrorHandlers = []; + + // Debugging help + this._id = _nextId++; + //this._createTrace = new Trace(new Error()); + _outstanding[this._id] = this; +}; + +/** + * Yeay for RTTI. + */ +Promise.prototype.isPromise = true; + +/** + * Have we either been resolve()ed or reject()ed? + */ +Promise.prototype.isComplete = function() { + return this._status != PENDING; +}; + +/** + * Have we resolve()ed? + */ +Promise.prototype.isResolved = function() { + return this._status == SUCCESS; +}; + +/** + * Have we reject()ed? + */ +Promise.prototype.isRejected = function() { + return this._status == ERROR; +}; + +/** + * Take the specified action of fulfillment of a promise, and (optionally) + * a different action on promise rejection. + */ +Promise.prototype.then = function(onSuccess, onError) { + if (typeof onSuccess === 'function') { + if (this._status === SUCCESS) { + onSuccess.call(null, this._value); + } else if (this._status === PENDING) { + this._onSuccessHandlers.push(onSuccess); + } + } + + if (typeof onError === 'function') { + if (this._status === ERROR) { + onError.call(null, this._value); + } else if (this._status === PENDING) { + this._onErrorHandlers.push(onError); + } + } + + return this; +}; + +/** + * Like then() except that rather than returning this we return + * a promise which + */ +Promise.prototype.chainPromise = function(onSuccess) { + var chain = new Promise(); + chain._chainedFrom = this; + this.then(function(data) { + try { + chain.resolve(onSuccess(data)); + } catch (ex) { + chain.reject(ex); + } + }, function(ex) { + chain.reject(ex); + }); + return chain; +}; + +/** + * Supply the fulfillment of a promise + */ +Promise.prototype.resolve = function(data) { + return this._complete(this._onSuccessHandlers, SUCCESS, data, 'resolve'); +}; + +/** + * Renege on a promise + */ +Promise.prototype.reject = function(data) { + return this._complete(this._onErrorHandlers, ERROR, data, 'reject'); +}; + +/** + * Internal method to be called on resolve() or reject(). + * @private + */ +Promise.prototype._complete = function(list, status, data, name) { + // Complain if we've already been completed + if (this._status != PENDING) { + console.group('Promise already closed'); + console.error('Attempted ' + name + '() with ', data); + console.error('Previous status = ', this._status, + ', previous value = ', this._value); + console.trace(); + + if (this._completeTrace) { + console.error('Trace of previous completion:'); + this._completeTrace.log(5); + } + console.groupEnd(); + return this; + } + + if (_traceCompletion) { + this._completeTrace = new Trace(new Error()); + } + + this._status = status; + this._value = data; + + // Call all the handlers, and then delete them + list.forEach(function(handler) { + handler.call(null, this._value); + }, this); + this._onSuccessHandlers.length = 0; + this._onErrorHandlers.length = 0; + + // Remove the given {promise} from the _outstanding list, and add it to the + // _recent list, pruning more than 20 recent promises from that list. + delete _outstanding[this._id]; + _recent.push(this); + while (_recent.length > 20) { + _recent.shift(); + } + + return this; +}; + +/** + * Takes an array of promises and returns a promise that that is fulfilled once + * all the promises in the array are fulfilled + * @param group The array of promises + * @return the promise that is fulfilled when all the array is fulfilled + */ +Promise.group = function(promiseList) { + if (!(promiseList instanceof Array)) { + promiseList = Array.prototype.slice.call(arguments); + } + + // If the original array has nothing in it, return now to avoid waiting + if (promiseList.length === 0) { + return new Promise().resolve([]); + } + + var groupPromise = new Promise(); + var results = []; + var fulfilled = 0; + + var onSuccessFactory = function(index) { + return function(data) { + results[index] = data; + fulfilled++; + // If the group has already failed, silently drop extra results + if (groupPromise._status !== ERROR) { + if (fulfilled === promiseList.length) { + groupPromise.resolve(results); + } + } + }; + }; + + promiseList.forEach(function(promise, index) { + var onSuccess = onSuccessFactory(index); + var onError = groupPromise.reject.bind(groupPromise); + promise.then(onSuccess, onError); + }); + + return groupPromise; +}; + +exports.Promise = Promise; +exports._outstanding = _outstanding; +exports._recent = _recent; + +}); diff --git a/plugins/pilot/lib/proxy.js b/plugins/pilot/lib/proxy.js new file mode 100644 index 00000000..c2675dd0 --- /dev/null +++ b/plugins/pilot/lib/proxy.js @@ -0,0 +1,82 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Julian Viereck (jviereck@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +define(function(require, exports, module) { + +var Promise = require('pilot/promise').Promise; + +exports.xhr = function(method, url, async, beforeSendCallback) { + var pr = new Promise(); + + if (!skywriter.proxy || !skywriter.proxy.xhr) { + var req = new XMLHttpRequest(); + req.onreadystatechange = function() { + if (req.readyState !== 4) { + return; + } + + var status = req.status; + if (status !== 0 && status !== 200) { + var error = new Error(req.responseText + ' (Status ' + req.status + ")"); + error.xhr = req; + pr.reject(error); + return; + } + + pr.resolve(req.responseText); + }.bind(this); + + req.open("GET", url, async); + if (beforeSendCallback) { + beforeSendCallback(req); + } + req.send(); + } else { + skywriter.proxy.xhr.call(this, method, url, async, beforeSendCallback, pr); + } + + return pr; +}; + +exports.Worker = function(url) { + if (!skywriter.proxy || !skywriter.proxy.worker) { + return new Worker(url); + } else { + return new skywriter.proxy.worker(url); + } +}; + +}); diff --git a/plugins/pilot/lib/stacktrace.js b/plugins/pilot/lib/stacktrace.js new file mode 100644 index 00000000..961d88cc --- /dev/null +++ b/plugins/pilot/lib/stacktrace.js @@ -0,0 +1,332 @@ +define(function(require, exports, module) { + +var util = require("pilot/util"); +var console = require('pilot/console'); + +// Changed to suit the specific needs of running within Skywriter + +// Domain Public by Eric Wendelin http://eriwen.com/ (2008) +// Luke Smith http://lucassmith.name/ (2008) +// Loic Dachary (2008) +// Johan Euphrosine (2008) +// Øyvind Sean Kinsey http://kinsey.no/blog +// +// Information and discussions +// http://jspoker.pokersource.info/skin/test-printstacktrace.html +// http://eriwen.com/javascript/js-stack-trace/ +// http://eriwen.com/javascript/stacktrace-update/ +// http://pastie.org/253058 +// http://browsershots.org/http://jspoker.pokersource.info/skin/test-printstacktrace.html +// + +// +// guessFunctionNameFromLines comes from firebug +// +// Software License Agreement (BSD License) +// +// Copyright (c) 2007, Parakey Inc. +// All rights reserved. +// +// Redistribution and use of this software 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 Parakey Inc. nor the names of its +// contributors may be used to endorse or promote products +// derived from this software without specific prior +// written permission of Parakey Inc. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 OWNER OR +// CONTRIBUTORS 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. + + + +/** + * Different browsers create stack traces in different ways. + * Feature Browser detection baby ;). + */ +var mode = (function() { + + // We use SC's browser detection here to avoid the "break on error" + // functionality provided by Firebug. Firebug tries to do the right + // thing here and break, but it happens every time you load the page. + // bug 554105 + if (util.isMozilla) { + return 'firefox'; + } else if (util.isOpera) { + return 'opera'; + } else if (util.isSafari) { + return 'other'; + } + + // SC doesn't do any detection of Chrome at this time. + + // this is the original feature detection code that is used as a + // fallback. + try { + (0)(); + } catch (e) { + if (e.arguments) { + return 'chrome'; + } + if (e.stack) { + return 'firefox'; + } + if (window.opera && !('stacktrace' in e)) { //Opera 9- + return 'opera'; + } + } + return 'other'; +})(); + +/** + * + */ +function stringifyArguments(args) { + for (var i = 0; i < args.length; ++i) { + var argument = args[i]; + if (typeof argument == 'object') { + args[i] = '#object'; + } else if (typeof argument == 'function') { + args[i] = '#function'; + } else if (typeof argument == 'string') { + args[i] = '"' + argument + '"'; + } + } + return args.join(','); +} + +/** + * Extract a stack trace from the format emitted by each browser. + */ +var decoders = { + chrome: function(e) { + var stack = e.stack; + if (!stack) { + console.log(e); + return []; + } + return stack.replace(/^.*?\n/, ''). + replace(/^.*?\n/, ''). + replace(/^.*?\n/, ''). + replace(/^[^\(]+?[\n$]/gm, ''). + replace(/^\s+at\s+/gm, ''). + replace(/^Object.\s*\(/gm, '{anonymous}()@'). + split('\n'); + }, + + firefox: function(e) { + var stack = e.stack; + if (!stack) { + console.log(e); + return []; + } + // stack = stack.replace(/^.*?\n/, ''); + stack = stack.replace(/(?:\n@:0)?\s+$/m, ''); + stack = stack.replace(/^\(/gm, '{anonymous}('); + return stack.split('\n'); + }, + + // Opera 7.x and 8.x only! + opera: function(e) { + var lines = e.message.split('\n'), ANON = '{anonymous}', + lineRE = /Line\s+(\d+).*?script\s+(http\S+)(?:.*?in\s+function\s+(\S+))?/i, i, j, len; + + for (i = 4, j = 0, len = lines.length; i < len; i += 2) { + if (lineRE.test(lines[i])) { + lines[j++] = (RegExp.$3 ? RegExp.$3 + '()@' + RegExp.$2 + RegExp.$1 : ANON + '()@' + RegExp.$2 + ':' + RegExp.$1) + + ' -- ' + + lines[i + 1].replace(/^\s+/, ''); + } + } + + lines.splice(j, lines.length - j); + return lines; + }, + + // Safari, Opera 9+, IE, and others + other: function(curr) { + var ANON = '{anonymous}', fnRE = /function\s*([\w\-$]+)?\s*\(/i, stack = [], j = 0, fn, args; + + var maxStackSize = 10; + while (curr && stack.length < maxStackSize) { + fn = fnRE.test(curr.toString()) ? RegExp.$1 || ANON : ANON; + args = Array.prototype.slice.call(curr['arguments']); + stack[j++] = fn + '(' + stringifyArguments(args) + ')'; + + //Opera bug: if curr.caller does not exist, Opera returns curr (WTF) + if (curr === curr.caller && window.opera) { + //TODO: check for same arguments if possible + break; + } + curr = curr.caller; + } + return stack; + } +}; + +/** + * + */ +function NameGuesser() { +} + +NameGuesser.prototype = { + + sourceCache: {}, + + ajax: function(url) { + var req = this.createXMLHTTPObject(); + if (!req) { + return; + } + req.open('GET', url, false); + req.setRequestHeader('User-Agent', 'XMLHTTP/1.0'); + req.send(''); + return req.responseText; + }, + + createXMLHTTPObject: function() { + // Try XHR methods in order and store XHR factory + var xmlhttp, XMLHttpFactories = [ + function() { + return new XMLHttpRequest(); + }, function() { + return new ActiveXObject('Msxml2.XMLHTTP'); + }, function() { + return new ActiveXObject('Msxml3.XMLHTTP'); + }, function() { + return new ActiveXObject('Microsoft.XMLHTTP'); + } + ]; + for (var i = 0; i < XMLHttpFactories.length; i++) { + try { + xmlhttp = XMLHttpFactories[i](); + // Use memoization to cache the factory + this.createXMLHTTPObject = XMLHttpFactories[i]; + return xmlhttp; + } catch (e) {} + } + }, + + getSource: function(url) { + if (!(url in this.sourceCache)) { + this.sourceCache[url] = this.ajax(url).split('\n'); + } + return this.sourceCache[url]; + }, + + guessFunctions: function(stack) { + for (var i = 0; i < stack.length; ++i) { + var reStack = /{anonymous}\(.*\)@(\w+:\/\/([-\w\.]+)+(:\d+)?[^:]+):(\d+):?(\d+)?/; + var frame = stack[i], m = reStack.exec(frame); + if (m) { + var file = m[1], lineno = m[4]; //m[7] is character position in Chrome + if (file && lineno) { + var functionName = this.guessFunctionName(file, lineno); + stack[i] = frame.replace('{anonymous}', functionName); + } + } + } + return stack; + }, + + guessFunctionName: function(url, lineNo) { + try { + return this.guessFunctionNameFromLines(lineNo, this.getSource(url)); + } catch (e) { + return 'getSource failed with url: ' + url + ', exception: ' + e.toString(); + } + }, + + guessFunctionNameFromLines: function(lineNo, source) { + var reFunctionArgNames = /function ([^(]*)\(([^)]*)\)/; + var reGuessFunction = /['"]?([0-9A-Za-z_]+)['"]?\s*[:=]\s*(function|eval|new Function)/; + // Walk backwards from the first line in the function until we find the line which + // matches the pattern above, which is the function definition + var line = '', maxLines = 10; + for (var i = 0; i < maxLines; ++i) { + line = source[lineNo - i] + line; + if (line !== undefined) { + var m = reGuessFunction.exec(line); + if (m) { + return m[1]; + } + else { + m = reFunctionArgNames.exec(line); + } + if (m && m[1]) { + return m[1]; + } + } + } + return '(?)'; + } +}; + +var guesser = new NameGuesser(); + +var frameIgnorePatterns = [ + /http:\/\/localhost:4020\/sproutcore.js:/ +]; + +exports.ignoreFramesMatching = function(regex) { + frameIgnorePatterns.push(regex); +}; + +/** + * Create a stack trace from an exception + * @param ex {Error} The error to create a stacktrace from (optional) + * @param guess {Boolean} If we should try to resolve the names of anonymous functions + */ +exports.Trace = function Trace(ex, guess) { + this._ex = ex; + this._stack = decoders[mode](ex); + + if (guess) { + this._stack = guesser.guessFunctions(this._stack); + } +}; + +/** + * Log to the console a number of lines (default all of them) + * @param lines {number} Maximum number of lines to wrote to console + */ +exports.Trace.prototype.log = function(lines) { + if (lines <= 0) { + // You aren't going to have more lines in your stack trace than this + // and it still fits in a 32bit integer + lines = 999999999; + } + + var printed = 0; + for (var i = 0; i < this._stack.length && printed < lines; i++) { + var frame = this._stack[i]; + var display = true; + frameIgnorePatterns.forEach(function(regex) { + if (regex.test(frame)) { + display = false; + } + }); + if (display) { + console.debug(frame); + printed++; + } + } +}; + +}); diff --git a/plugins/pilot/lib/util.js b/plugins/pilot/lib/util.js new file mode 100644 index 00000000..5a138a20 --- /dev/null +++ b/plugins/pilot/lib/util.js @@ -0,0 +1,659 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Skywriter Team (skywriter@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +/** + * Create an object representing a de-serialized query section of a URL. + * Query keys with multiple values are returned in an array. + *

Example: The input "foo=bar&foo=baz&thinger=%20spaces%20=blah&zonk=blarg&" + * Produces the output object: + *

{
+ *   foo: [ "bar", "baz" ],
+ *   thinger: " spaces =blah",
+ *   zonk: "blarg"
+ * }
+ * 
+ *

Note that spaces and other urlencoded entities are correctly handled + * @see dojo.queryToObject() + * While dojo.queryToObject() is mainly for URL query strings, this version + * allows to specify a separator character + */ +exports.queryToObject = function(str, seperator) { + var ret = {}; + var qp = str.split(seperator || "&"); + var dec = decodeURIComponent; + qp.forEach(function(item) { + if (item.length) { + var parts = item.split("="); + var name = dec(parts.shift()); + var val = dec(parts.join("=")); + if (exports.isString(ret[name])){ + ret[name] = [ret[name]]; + } + if (Array.isArray(ret[name])){ + ret[name].push(val); + } else { + ret[name] = val; + } + } + }); + return ret; +}; + +/** + * Takes a name/value mapping object and returns a string representing a + * URL-encoded version of that object for use in a GET request + *

For example, given the input: + * { blah: "blah", multi: [ "thud", "thonk" ] } + * The following string would be returned: + * "blah=blah&multi=thud&multi=thonk" + * @param map {Object} The object to convert + * @return {string} A URL-encoded version of the input + */ +exports.objectToQuery = function(map) { + // FIXME: need to implement encodeAscii!! + var enc = encodeURIComponent; + var pairs = []; + var backstop = {}; + for (var name in map) { + var value = map[name]; + if (value != backstop[name]) { + var assign = enc(name) + "="; + if (value.isArray) { + for (var i = 0; i < value.length; i++) { + pairs.push(assign + enc(value[i])); + } + } else { + pairs.push(assign + enc(value)); + } + } + } + return pairs.join("&"); +}; + +/** + * Holds the count to keep a unique value for setTimeout + * @private See rateLimit() + */ +var nextRateLimitId = 0; + +/** + * Holds the timeouts so they can be cleared later + * @private See rateLimit() + */ +var rateLimitTimeouts = {}; + +/** + * Delay calling some function to check that it's not called again inside a + * maxRate. The real function is called after maxRate ms unless the return + * value of this function is called before, in which case the clock is restarted + */ +exports.rateLimit = function(maxRate, scope, func) { + if (maxRate) { + var rateLimitId = nextRateLimitId++; + + return function() { + if (rateLimitTimeouts[rateLimitId]) { + clearTimeout(rateLimitTimeouts[rateLimitId]); + } + + rateLimitTimeouts[rateLimitId] = setTimeout(function() { + func.apply(scope, arguments); + delete rateLimitTimeouts[rateLimitId]; + }, maxRate); + }; + } +}; + +/** + * Return true if it is a String + */ +exports.isString = function(it) { + return (typeof it == "string" || it instanceof String); +}; + +/** + * Returns true if it is a Boolean. + */ +exports.isBoolean = function(it) { + return (typeof it == 'boolean'); +}; + +/** + * Returns true if it is a Number. + */ +exports.isNumber = function(it) { + return (typeof it == 'number' && isFinite(it)); +}; + +/** + * Hack copied from dojo. + */ +exports.isObject = function(it) { + return it !== undefined && + (it === null || typeof it == "object" || + Array.isArray(it) || exports.isFunction(it)); +}; + +/** + * Is the passed object a function? + * From dojo.isFunction() + */ +exports.isFunction = (function() { + var _isFunction = function(it) { + var t = typeof it; // must evaluate separately due to bizarre Opera bug. See #8937 + //Firefox thinks object HTML element is a function, so test for nodeType. + return it && (t == "function" || it instanceof Function) && !it.nodeType; // Boolean + }; + + return exports.isSafari ? + // only slow this down w/ gratuitious casting in Safari (not WebKit) + function(/*anything*/ it) { + if (typeof it == "function" && it == "[object NodeList]") { + return false; + } + return _isFunction(it); // Boolean + } : _isFunction; +})(); + +/** + * A la Prototype endsWith(). Takes a regex excluding the '$' end marker + */ +exports.endsWith = function(str, end) { + if (!str) { + return false; + } + return str.match(new RegExp(end + "$")); +}; + +/** + * A la Prototype include(). + */ +exports.include = function(array, item) { + return array.indexOf(item) > -1; +}; + +/** + * Like include, but useful when you're checking for a specific + * property on each object in the list... + * + * Returns null if the item is not in the list, otherwise + * returns the index of the item. + */ +exports.indexOfProperty = function(array, propertyName, item) { + for (var i = 0; i < array.length; i++) { + if (array[i][propertyName] == item) { + return i; + } + } + return null; +}; + +/** + * A la Prototype last(). + */ +exports.last = function(array) { + if (Array.isArray(array)) { + return array[array.length - 1]; + } +}; + +/** + * Knock off any undefined items from the end of an array + */ +exports.shrinkArray = function(array) { + var newArray = []; + + var stillAtBeginning = true; + array.reverse().forEach(function(item) { + if (stillAtBeginning && item === undefined) { + return; + } + + stillAtBeginning = false; + + newArray.push(item); + }); + + return newArray.reverse(); +}; + +/** + * Create an array + * @param number The size of the new array to create + * @param character The item to put in the array, defaults to ' ' + */ +exports.makeArray = function(number, character) { + if (number < 1) { + return []; // give us a normal number please! + } + if (!character){character = ' ';} + + var newArray = []; + for (var i = 0; i < number; i++) { + newArray.push(character); + } + return newArray; +}; + +/** + * Repeat a string a given number of times. + * @param string String to repeat + * @param repeat Number of times to repeat + */ +exports.repeatString = function(string, repeat) { + var newstring = ''; + + for (var i = 0; i < repeat; i++) { + newstring += string; + } + + return newstring; +}; + +/** + * Given a row, find the number of leading spaces. + * E.g. an array with the string " aposjd" would return 2 + * @param row The row to hunt through + */ +exports.leadingSpaces = function(row) { + var numspaces = 0; + for (var i = 0; i < row.length; i++) { + if (row[i] == ' ' || row[i] == '' || row[i] === undefined) { + numspaces++; + } else { + return numspaces; + } + } + return numspaces; +}; + +/** + * Given a row, find the number of leading tabs. + * E.g. an array with the string " aposjd" would return 2 + * @param row The row to hunt through + */ +exports.leadingTabs = function(row) { + var numtabs = 0; + for (var i = 0; i < row.length; i++) { + if (row[i] == ' ' || row[i] == '' || row[i] === undefined) { + numtabs++; + } else { + return numtabs; + } + } + return numtabs; +}; + +/** + * Given a row, extract a copy of the leading spaces or tabs. + * E.g. an array with the string " aposjd" would return an array with the + * string " ". + * @param row The row to hunt through + */ +exports.leadingWhitespace = function(row) { + var leading = []; + for (var i = 0; i < row.length; i++) { + if (row[i] == ' ' || row[i] == ' ' || row[i] == '' || row[i] === undefined) { + leading.push(row[i]); + } else { + return leading; + } + } + return leading; +}; + +/** + * Given a camelCaseWord convert to "Camel Case Word" + */ +exports.englishFromCamel = function(camel) { + camel.replace(/([A-Z])/g, function(str) { + return " " + str.toLowerCase(); + }).trim(); +}; + +/** + * I hate doing this, but we need some way to determine if the user is on a Mac + * The reason is that users have different expectations of their key combinations. + * + * Take copy as an example, Mac people expect to use CMD or APPLE + C + * Windows folks expect to use CTRL + C + */ +exports.OS = { + LINUX: 'LINUX', + MAC: 'MAC', + WINDOWS: 'WINDOWS' +}; + +var ua = navigator.userAgent; +var av = navigator.appVersion; + +/** Is the user using a browser that identifies itself as Linux */ +exports.isLinux = av.indexOf("Linux") >= 0; + +/** Is the user using a browser that identifies itself as Windows */ +exports.isWindows = av.indexOf("Win") >= 0; + +/** Is the user using a browser that identifies itself as WebKit */ +exports.isWebKit = parseFloat(ua.split("WebKit/")[1]) || undefined; + +/** Is the user using a browser that identifies itself as Chrome */ +exports.isChrome = parseFloat(ua.split("Chrome/")[1]) || undefined; + +/** Is the user using a browser that identifies itself as Mac OS */ +exports.isMac = av.indexOf("Macintosh") >= 0; + +/* Is this Firefox or related? */ +exports.isMozilla = av.indexOf('Gecko/') >= 0; + +if (ua.indexOf("AdobeAIR") >= 0) { + exports.isAIR = 1; +} + +/** + * Is the user using a browser that identifies itself as Safari + * See also: + * - http://developer.apple.com/internet/safari/faq.html#anchor2 + * - http://developer.apple.com/internet/safari/uamatrix.html + */ +var index = Math.max(av.indexOf("WebKit"), av.indexOf("Safari"), 0); +if (index && !exports.isChrome) { + // try to grab the explicit Safari version first. If we don't get + // one, look for less than 419.3 as the indication that we're on something + // "Safari 2-ish". + exports.isSafari = parseFloat(av.split("Version/")[1]); + if (!exports.isSafari || parseFloat(av.substr(index + 7)) <= 419.3) { + exports.isSafari = 2; + } +} + +if (ua.indexOf("Gecko") >= 0 && !exports.isWebKit) { + exports.isMozilla = parseFloat(av); +} + +/** + * Return a exports.OS constant + */ +exports.getOS = function() { + if (exports.isMac) { + return exports.OS['MAC']; + } else if (exports.isLinux) { + return exports.OS['LINUX']; + } else { + return exports.OS['WINDOWS']; + } +}; + +/** Returns true if the DOM element "b" is inside the element "a". */ +if (typeof(document) !== 'undefined' && document.compareDocumentPosition) { + exports.contains = function(a, b) { + return a.compareDocumentPosition(b) & 16; + }; +} else { + exports.contains = function(a, b) { + return a !== b && (a.contains ? a.contains(b) : true); + }; +} + +/** + * Prevents propagation and clobbers the default action of the passed event + */ +exports.stopEvent = function(ev) { + ev.preventDefault(); + ev.stopPropagation(); +}; + +/** + * Create a random password of the given length (default 16 chars) + */ +exports.randomPassword = function(length) { + length = length || 16; + var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; + var pass = ""; + for (var x = 0; x < length; x++) { + var charIndex = Math.floor(Math.random() * chars.length); + pass += chars.charAt(charIndex); + } + return pass; +}; + +/** + * Is the passed object free of members, i.e. are there any enumerable + * properties which the objects claims as it's own using hasOwnProperty() + */ +exports.isEmpty = function(object) { + for (var x in object) { + if (object.hasOwnProperty(x)) { + return false; + } + } + return true; +}; + +/** + * Does the name of a project indicate that it is owned by someone else + * TODO: This is a major hack. We really should have a File object that include + * separate owner information. + */ +exports.isMyProject = function(project) { + return project.indexOf("+") == -1; +}; + +/** + * Format a date as dd MMM yyyy + */ +exports.formatDate = function (date) { + if (!date) { + return "Unknown"; + } + return date.getDate() + " " + + exports.formatDate.shortMonths[date.getMonth()] + " " + + date.getFullYear(); +}; + +/** + * Month data for exports.formatDate + */ +exports.formatDate.shortMonths = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]; + +/** + * Add a CSS class to the list of classes on the given node + */ +exports.addClass = function(node, className) { + var parts = className.split(/\s+/); + var cls = " " + node.className + " "; + for (var i = 0, len = parts.length, c; i < len; ++i) { + c = parts[i]; + if (c && cls.indexOf(" " + c + " ") < 0) { + cls += c + " "; + } + } + node.className = cls.trim(); +}; + +/** + * Remove a CSS class from the list of classes on the given node + */ +exports.removeClass = function(node, className) { + var cls; + if (className !== undefined) { + var parts = className.split(/\s+/); + cls = " " + node.className + " "; + for (var i = 0, len = parts.length; i < len; ++i) { + cls = cls.replace(" " + parts[i] + " ", " "); + } + cls = cls.trim(); + } else { + cls = ""; + } + if (node.className != cls) { + node.className = cls; + } +}; + +/** + * Add or remove a CSS class from the list of classes on the given node + * depending on the value of include + */ +exports.setClass = function(node, className, include) { + if (include) { + exports.addClass(node, className); + } else { + exports.removeClass(node, className); + } +}; + +/** + * Is the passed object either null or undefined (using ===) + */ +exports.none = function(obj) { + return obj === null || obj === undefined; +}; + +/** + * Creates a clone of the passed object. This function can take just about + * any type of object and create a clone of it, including primitive values + * (which are not actually cloned because they are immutable). + * If the passed object implements the clone() method, then this function + * will simply call that method and return the result. + * + * @param object {Object} the object to clone + * @param deep {Boolean} do a deep clone? + * @returns {Object} the cloned object + */ +exports.clone = function(object, deep) { + if (Array.isArray(object) && !deep) { + return object.slice(); + } + + if (typeof object === 'object' || Array.isArray(object)) { + if (object === null) { + return null; + } + + var reply = (Array.isArray(object) ? [] : {}); + for (var key in object) { + if (deep && (typeof object[key] === 'object' + || Array.isArray(object[key]))) { + reply[key] = exports.clone(object[key], true); + } else { + reply[key] = object[key]; + } + } + return reply; + } + + if (object && typeof(object.clone) === 'function') { + return object.clone(); + } + + // That leaves numbers, booleans, undefined. Doesn't it? + return object; +}; + + +/** + * Helper method for extending one object with another + * Copies all properties from source to target. Returns the extended target + * object. + * Taken from John Resig, http://ejohn.org/blog/javascript-getters-and-setters/. + */ +exports.mixin = function(a, b) { + for (var i in b) { + var g = b.__lookupGetter__(i); + var s = b.__lookupSetter__(i); + + if (g || s) { + if (g) { + a.__defineGetter__(i, g); + } + if (s) { + a.__defineSetter__(i, s); + } + } else { + a[i] = b[i]; + } + } + + return a; +}; + +/** + * Basically taken from Sproutcore. + * Replaces the count items from idx with objects. + */ +exports.replace = function(arr, idx, amt, objects) { + return arr.slice(0, idx).concat(objects).concat(arr.slice(idx + amt)); +}; + +/** + * Return true if the two frames match. You can also pass only points or sizes. + * @param r1 {Rect} the first rect + * @param r2 {Rect} the second rect + * @param delta {Float} an optional delta that allows for rects that do not match exactly. Defaults to 0.1 + * @returns {Boolean} true if rects match + */ +exports.rectsEqual = function(r1, r2, delta) { + if (!r1 || !r2) { + return r1 == r2; + } + + if (!delta && delta !== 0) { + delta = 0.1; + } + + if ((r1.y != r2.y) && (Math.abs(r1.y - r2.y) > delta)) { + return false; + } + + if ((r1.x != r2.x) && (Math.abs(r1.x - r2.x) > delta)) { + return false; + } + + if ((r1.width != r2.width) && (Math.abs(r1.width - r2.width) > delta)) { + return false; + } + + if ((r1.height != r2.height) && (Math.abs(r1.height - r2.height) > delta)) { + return false; + } + + return true; +}; + +}); From d074c6b279e8d6e41ef6a53764bce473502c8f14 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Thu, 18 Nov 2010 13:33:31 +0000 Subject: [PATCH 19/90] basic conversion to new command structure --- lib/ace/commands/default_commands.js | 196 +++++++++++++-------------- lib/ace/document.js | 14 +- lib/ace/keybinding.js | 3 +- lib/ace/plugin_manager.js | 2 +- 4 files changed, 108 insertions(+), 107 deletions(-) diff --git a/lib/ace/commands/default_commands.js b/lib/ace/commands/default_commands.js index 7a40b833..38b2f328 100644 --- a/lib/ace/commands/default_commands.js +++ b/lib/ace/commands/default_commands.js @@ -39,156 +39,156 @@ define(function(require, exports, module) { var PluginManager = require("ace/plugin_manager").PluginManager; -PluginManager.registerCommand("selectall", function(editor, selection) { - selection.selectAll(); +PluginManager.registerCommand("selectall", function(env, args, request) { + env.selection.selectAll(); }); -PluginManager.registerCommand("removeline", function(editor, selection) { - editor.removeLines(); +PluginManager.registerCommand("removeline", function(env, args, request) { + env.editor.removeLines(); }); -PluginManager.registerCommand("gotoline", function(editor, selection) { +PluginManager.registerCommand("gotoline", function(env, args, request) { var line = parseInt(prompt("Enter line number:")); if (!isNaN(line)) { - editor.gotoLine(line); + env.editor.gotoLine(line); } }); -PluginManager.registerCommand("togglecomment", function(editor, selection) { - editor.toggleCommentLines(); +PluginManager.registerCommand("togglecomment", function(env, args, request) { + env.editor.toggleCommentLines(); }); -PluginManager.registerCommand("findnext", function(editor, selection) { - editor.findNext(); +PluginManager.registerCommand("findnext", function(env, args, request) { + env.editor.findNext(); }); -PluginManager.registerCommand("findprevious", function(editor, selection) { - editor.findPrevious(); +PluginManager.registerCommand("findprevious", function(env, args, request) { + env.editor.findPrevious(); }); -PluginManager.registerCommand("find", function(editor, selection) { +PluginManager.registerCommand("find", function(env, args, request) { var needle = prompt("Find:"); - editor.find(needle); + env.editor.find(needle); }); -PluginManager.registerCommand("undo", function(editor, selection) { - editor.undo(); +PluginManager.registerCommand("undo", function(env, args, request) { + env.editor.undo(); }); -PluginManager.registerCommand("redo", function(editor, selection) { - editor.redo(); +PluginManager.registerCommand("redo", function(env, args, request) { + env.editor.redo(); }); -PluginManager.registerCommand("redo", function(editor, selection) { - editor.redo(); +PluginManager.registerCommand("redo", function(env, args, request) { + env.editor.redo(); }); -PluginManager.registerCommand("overwrite", function(editor, selection) { - editor.toggleOverwrite(); +PluginManager.registerCommand("overwrite", function(env, args, request) { + env.editor.toggleOverwrite(); }); -PluginManager.registerCommand("copylinesup", function(editor, selection) { - editor.copyLinesUp(); +PluginManager.registerCommand("copylinesup", function(env, args, request) { + env.editor.copyLinesUp(); }); -PluginManager.registerCommand("movelinesup", function(editor, selection) { - editor.moveLinesUp(); +PluginManager.registerCommand("movelinesup", function(env, args, request) { + env.editor.moveLinesUp(); }); -PluginManager.registerCommand("selecttostart", function(editor, selection) { - selection.selectFileStart(); +PluginManager.registerCommand("selecttostart", function(env, args, request) { + env.selection.selectFileStart(); }); -PluginManager.registerCommand("gotostart", function(editor, selection) { - editor.navigateFileStart(); +PluginManager.registerCommand("gotostart", function(env, args, request) { + env.editor.navigateFileStart(); }); -PluginManager.registerCommand("selectup", function(editor, selection) { - selection.selectUp(); +PluginManager.registerCommand("selectup", function(env, args, request) { + env.selection.selectUp(); }); -PluginManager.registerCommand("golineup", function(editor, selection) { - editor.navigateUp(); +PluginManager.registerCommand("golineup", function(env, args, request) { + env.editor.navigateUp(); }); -PluginManager.registerCommand("copylinesdown", function(editor, selection) { - editor.copyLinesDown(); +PluginManager.registerCommand("copylinesdown", function(env, args, request) { + env.editor.copyLinesDown(); }); -PluginManager.registerCommand("movelinesdown", function(editor, selection) { - editor.moveLinesDown(); +PluginManager.registerCommand("movelinesdown", function(env, args, request) { + env.editor.moveLinesDown(); }); -PluginManager.registerCommand("selecttoend", function(editor, selection) { - selection.selectFileEnd(); +PluginManager.registerCommand("selecttoend", function(env, args, request) { + env.selection.selectFileEnd(); }); -PluginManager.registerCommand("gotoend", function(editor, selection) { - editor.navigateFileEnd(); +PluginManager.registerCommand("gotoend", function(env, args, request) { + env.editor.navigateFileEnd(); }); -PluginManager.registerCommand("selectdown", function(editor, selection) { - selection.selectDown(); +PluginManager.registerCommand("selectdown", function(env, args, request) { + env.selection.selectDown(); }); -PluginManager.registerCommand("godown", function(editor, selection) { - editor.navigateDown(); +PluginManager.registerCommand("godown", function(env, args, request) { + env.editor.navigateDown(); }); -PluginManager.registerCommand("selectwordleft", function(editor, selection) { - selection.selectWordLeft(); +PluginManager.registerCommand("selectwordleft", function(env, args, request) { + env.selection.selectWordLeft(); }); -PluginManager.registerCommand("gotowordleft", function(editor, selection) { - editor.navigateWordLeft(); +PluginManager.registerCommand("gotowordleft", function(env, args, request) { + env.editor.navigateWordLeft(); }); -PluginManager.registerCommand("selecttolinestart", function(editor, selection) { - selection.selectLineStart(); +PluginManager.registerCommand("selecttolinestart", function(env, args, request) { + env.selection.selectLineStart(); }); -PluginManager.registerCommand("gotolinestart", function(editor, selection) { - editor.navigateLineStart(); +PluginManager.registerCommand("gotolinestart", function(env, args, request) { + env.editor.navigateLineStart(); }); -PluginManager.registerCommand("selectleft", function(editor, selection) { - selection.selectLeft(); +PluginManager.registerCommand("selectleft", function(env, args, request) { + env.selection.selectLeft(); }); -PluginManager.registerCommand("gotoleft", function(editor, selection) { - editor.navigateLeft(); +PluginManager.registerCommand("gotoleft", function(env, args, request) { + env.editor.navigateLeft(); }); -PluginManager.registerCommand("selectwordright", function(editor, selection) { - selection.selectWordRight(); +PluginManager.registerCommand("selectwordright", function(env, args, request) { + env.selection.selectWordRight(); }); -PluginManager.registerCommand("gotowordright", function(editor, selection) { - editor.navigateWordRight(); +PluginManager.registerCommand("gotowordright", function(env, args, request) { + env.editor.navigateWordRight(); }); -PluginManager.registerCommand("selecttolineend", function(editor, selection) { - selection.selectLineEnd(); +PluginManager.registerCommand("selecttolineend", function(env, args, request) { + env.selection.selectLineEnd(); }); -PluginManager.registerCommand("gotolineend", function(editor, selection) { - editor.navigateLineEnd(); +PluginManager.registerCommand("gotolineend", function(env, args, request) { + env.editor.navigateLineEnd(); }); -PluginManager.registerCommand("selectright", function(editor, selection) { - selection.selectRight(); +PluginManager.registerCommand("selectright", function(env, args, request) { + env.selection.selectRight(); }); -PluginManager.registerCommand("gotoright", function(editor, selection) { - editor.navigateRight(); +PluginManager.registerCommand("gotoright", function(env, args, request) { + env.editor.navigateRight(); }); -PluginManager.registerCommand("selectpagedown", function(editor, selection) { - editor.selectPageDown(); +PluginManager.registerCommand("selectpagedown", function(env, args, request) { + env.editor.selectPageDown(); }); -PluginManager.registerCommand("pagedown", function(editor, selection) { - editor.scrollPageDown(); +PluginManager.registerCommand("pagedown", function(env, args, request) { + env.editor.scrollPageDown(); }); -PluginManager.registerCommand("gotopagedown", function(editor, selection) { - editor.gotoPageDown(); +PluginManager.registerCommand("gotopagedown", function(env, args, request) { + env.editor.gotoPageDown(); }); -PluginManager.registerCommand("selectpageup", function(editor, selection) { - editor.selectPageUp(); +PluginManager.registerCommand("selectpageup", function(env, args, request) { + env.editor.selectPageUp(); }); -PluginManager.registerCommand("pageup", function(editor, selection) { - editor.scrollPageUp(); +PluginManager.registerCommand("pageup", function(env, args, request) { + env.editor.scrollPageUp(); }); -PluginManager.registerCommand("gotopageup", function(editor, selection) { - editor.gotoPageUp(); +PluginManager.registerCommand("gotopageup", function(env, args, request) { + env.editor.gotoPageUp(); }); -PluginManager.registerCommand("selectlinestart", function(editor, selection) { - selection.selectLineStart(); +PluginManager.registerCommand("selectlinestart", function(env, args, request) { + env.selection.selectLineStart(); }); -PluginManager.registerCommand("gotolinestart", function(editor, selection) { - editor.navigateLineStart(); +PluginManager.registerCommand("gotolinestart", function(env, args, request) { + env.editor.navigateLineStart(); }); -PluginManager.registerCommand("selectlineend", function(editor, selection) { - selection.selectLineEnd(); +PluginManager.registerCommand("selectlineend", function(env, args, request) { + env.selection.selectLineEnd(); }); -PluginManager.registerCommand("gotolineend", function(editor, selection) { - editor.navigateLineEnd(); +PluginManager.registerCommand("gotolineend", function(env, args, request) { + env.editor.navigateLineEnd(); }); -PluginManager.registerCommand("del", function(editor, selection) { - editor.removeRight(); +PluginManager.registerCommand("del", function(env, args, request) { + env.editor.removeRight(); }); -PluginManager.registerCommand("backspace", function(editor, selection) { - editor.removeLeft(); +PluginManager.registerCommand("backspace", function(env, args, request) { + env.editor.removeLeft(); }); -PluginManager.registerCommand("outdent", function(editor, selection) { - editor.blockOutdent(); +PluginManager.registerCommand("outdent", function(env, args, request) { + env.editor.blockOutdent(); }); -PluginManager.registerCommand("indent", function(editor, selection) { - editor.indent(); +PluginManager.registerCommand("indent", function(env, args, request) { + env.editor.indent(); }); }); \ No newline at end of file diff --git a/lib/ace/document.js b/lib/ace/document.js index ee02000b..903b8e51 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -73,13 +73,13 @@ var Document = function(text, mode) { return text.split(/\r\n|\r|\n/); }; - this.setValue = function(text) { - var args = [0, this.lines.length]; - args.push.apply(args, this.$split(text)); - this.lines.splice.apply(this.lines, args); - this.modified = true; - this.fireChangeEvent(0); - }; + this.setValue = function(text) { + var args = [0, this.lines.length]; + args.push.apply(args, this.$split(text)); + this.lines.splice.apply(this.lines, args); + this.modified = true; + this.fireChangeEvent(0); + }; this.toString = function() { return this.lines.join(this.$getNewLineCharacter()); diff --git a/lib/ace/keybinding.js b/lib/ace/keybinding.js index 2a3ba8ec..afea13ab 100644 --- a/lib/ace/keybinding.js +++ b/lib/ace/keybinding.js @@ -58,7 +58,8 @@ var KeyBinding = function(element, editor, config) { var command = PluginManager.commands[commandName]; if (command) { - command(editor, editor.getSelection()); + var env = { editor: editor, selection: editor.getSelection() }; + command(env); return event.stopEvent(e); } }); diff --git a/lib/ace/plugin_manager.js b/lib/ace/plugin_manager.js index eeffd15a..5446a69f 100644 --- a/lib/ace/plugin_manager.js +++ b/lib/ace/plugin_manager.js @@ -46,4 +46,4 @@ var PluginManager = { }; exports.PluginManager = PluginManager; -}); \ No newline at end of file +}); From fe109276db8a805e302a11a0a43b469d79d857a4 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Fri, 19 Nov 2010 12:33:22 +0000 Subject: [PATCH 20/90] convert to use the plugin_manager in pilot --- lib/ace/commands/default_commands.js | 2 +- lib/ace/keybinding.js | 2 +- lib/ace/plugin_manager.js | 49 ---------------------------- 3 files changed, 2 insertions(+), 51 deletions(-) delete mode 100644 lib/ace/plugin_manager.js diff --git a/lib/ace/commands/default_commands.js b/lib/ace/commands/default_commands.js index 38b2f328..1c813871 100644 --- a/lib/ace/commands/default_commands.js +++ b/lib/ace/commands/default_commands.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var PluginManager = require("ace/plugin_manager").PluginManager; +var PluginManager = require("pilot/plugin_manager").PluginManager; PluginManager.registerCommand("selectall", function(env, args, request) { env.selection.selectAll(); diff --git a/lib/ace/keybinding.js b/lib/ace/keybinding.js index afea13ab..6de40556 100644 --- a/lib/ace/keybinding.js +++ b/lib/ace/keybinding.js @@ -41,7 +41,7 @@ var core = require("ace/lib/core").core; var event = require("ace/lib/event").event; var default_mac = require("ace/conf/keybindings/default_mac").bindings; var default_win = require("ace/conf/keybindings/default_win").bindings; -var PluginManager = require("ace/plugin_manager").PluginManager; +var PluginManager = require("pilot/plugin_manager").PluginManager; require("ace/commands/default_commands"); var KeyBinding = function(element, editor, config) { diff --git a/lib/ace/plugin_manager.js b/lib/ace/plugin_manager.js deleted file mode 100644 index 5446a69f..00000000 --- a/lib/ace/plugin_manager.js +++ /dev/null @@ -1,49 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Ajax.org Code Editor (ACE). - * - * The Initial Developer of the Original Code is - * Ajax.org Services B.V. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Fabian Jakobs - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -define(function(require, exports, module) { - -var PluginManager = { - commands : {}, - - registerCommand : function(name, command) { - this.commands[name] = command; - } -}; - -exports.PluginManager = PluginManager; -}); From 5564b2fd86edcb5fc79ad12c414fb3182fb0f06b Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Fri, 19 Nov 2010 15:48:45 +0000 Subject: [PATCH 21/90] addition of types to pilot from skywriter --- plugins/pilot/lib/types.js | 149 ++++++++++++++++++++++ plugins/pilot/lib/types/basic.js | 206 +++++++++++++++++++++++++++++++ 2 files changed, 355 insertions(+) create mode 100644 plugins/pilot/lib/types.js create mode 100644 plugins/pilot/lib/types/basic.js diff --git a/plugins/pilot/lib/types.js b/plugins/pilot/lib/types.js new file mode 100644 index 00000000..52a5381a --- /dev/null +++ b/plugins/pilot/lib/types.js @@ -0,0 +1,149 @@ +// TODO this file can likely be deleted. The useful functionality has moved to +// index.js + + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Joe Walker (jwalker@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +define(function(require, exports, module) { + +/** + * Most of our types are 'static' e.g. there is only one type of 'text', however + * some types like 'selection' and 'deferred' are customizable. The basic + * Type type isn't useful, but does provide documentation about what types do. + * + */ +function Type() { +}; + +Type.prototype = { + /** + * Is the passed value an acceptable instance of this type? + * @return true|false to indicate the validity of value + */ + isValid: function(value) { throw new Error("not implemented"); }, + + /** + * Convert the given value to a string representation. + * Where possible, there should be round-tripping between values and their + * string representations. + */ + toString: function(value) { throw new Error("not implemented"); }, + + /** + * Convert the given str to an instance of this type. + * Where possible, there should be round-tripping between values and their + * string representations. + */ + fromString: function(str) { throw new Error("not implemented"); }, + + /** + * The plug-in system, and other things need to know what this type is + * called. This is called simpleName because this name alone is not + * enough to specify a type. Types like 'selection' and 'deferred' need + * extra data, however this function returns only the name, not the extra + * data. + */ + name: "unknown", + + // Methods from the original type system that we might need, but not now. + + /** + * All types have a JSON representation used in command parameter + * declarations and settings. This allows access to that representation as + * an object rather than as a string + */ + /* + getTypeSpec: function() { }, + */ + + /** + * 2 typeSpecs are considered equal if their simple names are the same. + */ + /* + equals: function(that) { } + */ +}; + +exports.Type = Type; + +/** + * Private registry of types + * Invariant: types[name] = type.name + */ +var types = {}; + +/** + * Add a new type to the list available to the system + */ +exports.registerType = function(type) { + types[type.name] = type; +} + +/** + * Remove a type from the list available to the system + */ +exports.deregisterType = function(type) { + delete types[type.name]; +} + +/** + * Find a type, previously registered using #registerType() + */ +exports.getType = function(typeSpec) { + var type; + if (typeof typeSpec === 'string') { + type = types[typeSpec]; + } + + if (typeof typeSpec == 'object') { + if (!typeSpec.name) { + throw new Error('Missing \'name\' member to typeSpec'); + } + + type = types[typeSpec.name]; + } + + if (type instanceof Type) { + return type; + } + + if (typeof type === 'function') { + return type(typeSpec); + } +} + +}); diff --git a/plugins/pilot/lib/types/basic.js b/plugins/pilot/lib/types/basic.js new file mode 100644 index 00000000..86c2460a --- /dev/null +++ b/plugins/pilot/lib/types/basic.js @@ -0,0 +1,206 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Joe Walker (jwalker@mozilla.com) + * Kevin Dangoor (kdangoor@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +var types = require("types"); + +/** + * These are the basic types that we accept. They are vaguely based on the + * Jetpack settings system (https://wiki.mozilla.org/Labs/Jetpack/JEP/24) + * although clearly more restricted. + * + *

In addition to these types, Jetpack also accepts range, member, password + * that we are thinking of adding. + * + *

This module probably should not be accessed directly, but instead used + * through types.js + */ + +/** + * 'text' is the default if no type is given. + */ +var text = new types.Type(); + +text.isValid = function(value) { + return typeof value == 'string'; +}; + +text.toString = function(value) { + return value; +}; + +text.fromString = function(value) { + return value; +}; + +text.name = 'text'; + +/** + * We don't currently plan to distinguish between integers and floats + */ +var number = new types.Type(); + +number.isValid = function(value) { + if (isNaN(value)) { + return false; + } + if (value === null) { + return false; + } + if (value === undefined) { + return false; + } + if (value === Infinity) { + return false; + } + return typeof value == 'number';// && !isNaN(value); +}; + +number.toString = function(value) { + if (!value) { + return null; + } + return '' + value; +}; + +number.fromString = function(value) { + if (!value) { + return null; + } + var reply = parseInt(value, 10); + if (isNaN(reply)) { + throw new Error('Can\'t convert "' + value + '" to a number.'); + } + return reply; +}; + +number.name = 'number'; + +/** + * true/false values + */ +var bool = new types.Type(); + +bool.isValid = function(value) { + return typeof value == 'boolean'; +}; + +bool.toString = function(value) { + return '' + value; +}; + +bool.fromString = function(value) { + if (value === null) { + return null; + } + + if (!value.toLowerCase) { + return !!value; + } + + var lower = value.toLowerCase(); + if (lower == 'true') { + return true; + } else if (lower == 'false') { + return false; + } + + return !!value; +}; + +bool.name = 'bool'; + +/** + * One of a known set of options + */ +function SelectionType(data) { + this._data = data; +}; + +SelectionType.prototype = new types.Type(); + +SelectionType.prototype.isValid = function(value) { + if (typeof value != 'string') { + return false; + } + + if (!this._data) { + console.error('Missing data on selection type extension. Skipping'); + return true; + } + + var data = (typeof(this._data) === "function") ? this._data() : this._data; + + var match = false; + data.forEach(function(option) { + if (value == option) { + match = true; + } + }); + + return match; +}; + +SelectionType.prototype.toString = function(value) { + return value; +}; + +SelectionType.prototype.fromString = function(value) { + // TODO: should we validate and return null if invalid? + return value; +}; + +SelectionType.prototype.name = 'selection'; + + +exports.startup = function() { + types.registerType(text); + types.registerType(number); + types.registerType(bool); + types.registerType(SelectionType); +}; + +exports.shutdown = function() { + types.unregisterType(text); + types.unregisterType(number); + types.unregisterType(bool); + types.unregisterType(SelectionType); +}; + +}); From fca0eeb1ff6327e9ecdd743362b541aa04f1be97 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Tue, 23 Nov 2010 12:28:29 +0000 Subject: [PATCH 22/90] Minor tidyups --- demo/boot.js | 14 +++++++------- plugins/pilot/lib/types.js | 14 +++++--------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/demo/boot.js b/demo/boot.js index d21535de..d932871e 100644 --- a/demo/boot.js +++ b/demo/boot.js @@ -47,9 +47,9 @@ var setupPlugins = function(config, callback) { config.pluginDirs["../plugins"] = { packages: ["pilot"] }; - + var knownPlugins = []; - + var pluginPackageInfo = { "../lib": [ { @@ -58,11 +58,11 @@ var setupPlugins = function(config, callback) { } ] }; - + var paths = {}; var i; var location; - + // we need to ensure that the core plugin directory is loaded first var pluginDirs = []; var pluginDir; @@ -76,13 +76,13 @@ var setupPlugins = function(config, callback) { return 1; } else if (a < b) { return -1; - } else if (b < a) { + } else if (b < a) { return 1; } else { return 0; } }); - + // set up RequireJS to know that our plugins all have a main module called "index" for (var dirNum = 0; dirNum < pluginDirs.length; dirNum++) { pluginDir = pluginDirs[dirNum]; @@ -109,7 +109,7 @@ var setupPlugins = function(config, callback) { } } } - + require({ packagePaths: pluginPackageInfo, paths: paths diff --git a/plugins/pilot/lib/types.js b/plugins/pilot/lib/types.js index 52a5381a..984d0f75 100644 --- a/plugins/pilot/lib/types.js +++ b/plugins/pilot/lib/types.js @@ -1,7 +1,3 @@ -// TODO this file can likely be deleted. The useful functionality has moved to -// index.js - - /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -44,7 +40,7 @@ define(function(require, exports, module) { * Most of our types are 'static' e.g. there is only one type of 'text', however * some types like 'selection' and 'deferred' are customizable. The basic * Type type isn't useful, but does provide documentation about what types do. - * + * */ function Type() { }; @@ -77,7 +73,7 @@ Type.prototype = { * extra data, however this function returns only the name, not the extra * data. */ - name: "unknown", + name: "unknown" // Methods from the original type system that we might need, but not now. @@ -111,14 +107,14 @@ var types = {}; */ exports.registerType = function(type) { types[type.name] = type; -} +}; /** * Remove a type from the list available to the system */ exports.deregisterType = function(type) { delete types[type.name]; -} +}; /** * Find a type, previously registered using #registerType() @@ -144,6 +140,6 @@ exports.getType = function(typeSpec) { if (typeof type === 'function') { return type(typeSpec); } -} +}; }); From af278fa573c87096d7bd064eefe34ebac9c06cbb Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Tue, 23 Nov 2010 12:29:02 +0000 Subject: [PATCH 23/90] add settings from skywriter --- plugins/pilot/lib/commands/settings.js | 104 ++++++++ plugins/pilot/lib/settings.js | 351 +++++++++++++++++++++++++ 2 files changed, 455 insertions(+) create mode 100644 plugins/pilot/lib/commands/settings.js create mode 100644 plugins/pilot/lib/settings.js diff --git a/plugins/pilot/lib/commands/settings.js b/plugins/pilot/lib/commands/settings.js new file mode 100644 index 00000000..3f781839 --- /dev/null +++ b/plugins/pilot/lib/commands/settings.js @@ -0,0 +1,104 @@ +require.def(['require', 'exports', 'module', + 'skywriter/plugins', + 'settings/environment', + 'settings/settings' +], function(require, exports, module, + plugins, + environment, + settingsMod +) { + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Skywriter Team (skywriter@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +var catalog = plugins.catalog; +var env = environment.env; + +var settings = settingsMod.settings; + +/** + * 'set' command + */ +exports.setCommand = function(args, request) { + var html; + + if (!args.setting) { + var settingsList = settings._list(); + html = ''; + // first sort the settingsList based on the key + settingsList.sort(function(a, b) { + if (a.key < b.key) { + return -1; + } else if (a.key == b.key) { + return 0; + } else { + return 1; + } + }); + + settingsList.forEach(function(setting) { + html += '' + + setting.key + + ' = ' + + setting.value + + '
'; + }); + } else { + if (args.value === undefined) { + html = '' + args.setting + ' = ' + settings.get(args.setting); + } else { + html = 'Setting: ' + args.setting + ' = ' + args.value; + settings.set(args.setting, args.value); + } + } + + request.done(html); +}; + +/** + * 'unset' command + */ +exports.unsetCommand = function(args, request) { + settings.resetValue(args.setting); + request.done('Reset ' + args.setting + ' to default: ' + settings.get(args.setting)); +}; + +}); diff --git a/plugins/pilot/lib/settings.js b/plugins/pilot/lib/settings.js new file mode 100644 index 00000000..9f6af921 --- /dev/null +++ b/plugins/pilot/lib/settings.js @@ -0,0 +1,351 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Joe Walker (jwalker@mozilla.com) + * Julian Viereck (jviereck@mozilla.com) + * Kevin Dangoor (kdangoor@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/** + * This plug-in manages settings. + */ + +define(function(require, exports, module) { + +var console = require("util/console"); +var types = require("types"); +var Event = require("events").Event; + +exports.startup = function(data, reason) { + // TODO add extension point in new style + // catalog.addExtensionPoint("setting", { + // "description": + // "A setting is something that the application offers as a way to customize how it works", + // "register": "index#addSetting", + // "indexOn": "name" + // }); + // catalog.addExtensionPoint("settingChange", { + // "description": + // "A settingChange is a way to be notified of changes to a setting" + // }); + + // TODO add commands in new style + // catalog.connect("command", module.id, { + // "name": "set", + // "params": [ + // { + // "name": "setting", + // "type": { + // "name": "selection", + // "pointer": "settings:index#getSettings" + // }, + // "description": "The name of the setting to display or alter", + // "defaultValue": null + // }, + // { + // "name": "value", + // "type": { + // "name": "deferred", + // "pointer": "settings:index#getTypeSpecFromAssignment" + // }, + // "description": "The new value for the chosen setting", + // "defaultValue": null + // } + // ], + // "description": "define and show settings", + // "pointer": "commands#setCommand" + // }); + // catalog.connect("command", module.id, { + // "name": "unset", + // "params": [ + // { + // "name": "setting", + // "type": { + // "name": "selection", + // "pointer": "settings:index#getSettings" + // }, + // "description": "The name of the setting to return to defaults" + // } + // ], + // "description": "unset a setting entirely", + // "pointer": "commands#unsetCommand" + // }); +}; + +exports.shutdown = function(data, reason) { +}; + + +/** + * A base class for all the various methods of storing settings. + *

Usage: + *

+ * // Create manually, or require 'settings' from the container.
+ * // This is the manual version:
+ * var settings = plugins.catalog.getObject('settings');
+ * // Add a new setting
+ * settings.addSetting({ name:'foo', ... });
+ * // Display the default value
+ * alert(settings.get('foo'));
+ * // Alter the value, which also publishes the change etc.
+ * settings.set('foo', 'bar');
+ * // Reset the value to the default
+ * settings.resetValue('foo');
+ * 
+ * @constructor + */ +function Settings(persister) { + /** + * Storage for deactivated values + */ + this._deactivated = {}; + + /** + * Storage for the setting values + */ + this._values = {}; + + this._settings = {}; + + if (persister) { + this.setPersister(persister); + } + + /** + * Event that tells people when a setting has changed. + */ + // TODO: Fix events + // this.settingChange = new Event({ keyElement: 0 }); +}; + +Settings.prototype = { + /** + * Function to add to the list of available settings. + *

Example usage: + *

+     * var settings = plugins.catalog.getObject('settings');
+     * settings.addSetting({
+     *     name: 'tabsize', // For use in settings.get('X')
+     *     type: 'number',  // To allow value checking.
+     *     defaultValue: 4  // Default value for use when none is directly set
+     * });
+     * 
+ * @param {object} settingSpec Object containing name/type/defaultValue members. + */ + addSetting: function(settingSpec) { + if (!settingSpec.name) { + console.error('Setting.name == undefined. Ignoring.', settingSpec); + return; + } + + if (!settingSpec.defaultValue === undefined) { + console.error('Setting.defaultValue == undefined', settingSpec); + return; + } + + var type = types.getType(settingSpec.type); + if (!type) { + console.error('Missing type', settingSpec); + return; + } + + /* + // The value can be + // 1) the value of a setting that is not activated at the moment + // OR + // 2) the defaultValue of the setting. + var value = this._deactivated[settingSpec.name] || + settingSpec.defaultValue; + */ + + var setting = { type: type, spec: settingSpec }; + this._settings[settingSpec.name] = setting; + }, + + removeSetting: function(name) { + delete this._settings[name]; + }, + + getSettingNames: function() { + return Object.keys(this._settings); + }, + + /** + * A Persister is able to store settings. It is an object that defines + * two functions: + * loadInitialValues(settings) and persistValue(settings, key, value). + */ + setPersister: function(persister) { + this._persister = persister; + if (persister) { + persister.loadInitialValues(this); + } + }, + + /** + * Read accessor + */ + get: function(key) { + return this._values[key]; + }, + + /** + * Override observable.set(key, value) to provide type conversion and + * validation. + */ + set: function(key, value) { + var setting = this._settings[key]; + if (!setting) { + console.warn('Setting not defined: ', key, value); + } + + this._values[key] = value; + if (persister) { + persister.persistValue(this, key, value); + } + + // Inform subscriptions of the change + // TODO: fix events + // this.settingChange(key, converted); + return this; + }, + + /** + * Reset the value of the key setting to it's default + */ + resetValue: function(key) { + var setting = this._settings[key]; + if (setting) { + this.set(key, setting.spec.defaultValue); + } else { + console.log('ignore resetValue on ', key); + } + }, + + resetAll: function() { + this.getSettingNames().forEach(function(key) { + this.resetValue(key); + }.bind(this)); + }, + + /** + * Retrieve a list of the known settings and their values + */ + _list: function() { + var reply = []; + this.getSettingNames().forEach(function(setting) { + reply.push({ + 'key': setting, + 'value': this.get(setting) + }); + }.bind(this)); + return reply; + }, + + /** + * Prime the local cache with the defaults. + */ + _loadDefaultValues: function() { + this._loadFromObject(this._getDefaultValues()); + }, + + /** + * Utility to load settings from an object + */ + _loadFromObject: function(data) { + // We iterate over data rather than keys so we don't forget values + // which don't have a setting yet. + for (var key in data) { + if (data.hasOwnProperty(key)) { + var setting = this._settings[key]; + if (setting) { + var value = setting.type.fromString(data[key]); + this.set(key, value); + } else { + this.set(key, data[key]); + } + } + } + }, + + /** + * Utility to grab all the settings and export them into an object + */ + _saveToObject: function() { + return this.getSettingNames().map(function(key) { + return this._settings[key].type.toString(this.get(key)); + }.bind(this)); + }, + + /** + * The default initial settings + */ + _getDefaultValues: function() { + return this.getSettingNames().map(function(key) { + return this._settings[key].spec.defaultValue; + }.bind(this)); + } +}; + +exports.settings = new Settings(new MemoryPersister()); + +/** + * Save the settings in a cookie + * This code has not been tested since reboot + * @constructor + */ +function CookiePersister() { +}; + +CookiePersister.prototype = { + loadInitialValues: function(settings) { + settings._loadDefaultValues(); + var data = cookie.get('settings'); + settings._loadFromObject(JSON.parse(data)); + }, + + persistValue: function(settings, key, value) { + try { + var stringData = JSON.stringify(settings._saveToObject()); + cookie.set('settings', stringData); + } catch (ex) { + console.error('Unable to JSONify the settings! ' + ex); + return; + } + } +}; + +exports.CookiePersister = CookiePersister; + +}); From 45e64eeca04b8bb7e876c1efb4a9205cf1ac3b5f Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Tue, 23 Nov 2010 12:32:31 +0000 Subject: [PATCH 24/90] add canon from skywriter --- plugins/pilot/lib/canon.js | 262 +++++++++++++++++++++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 plugins/pilot/lib/canon.js diff --git a/plugins/pilot/lib/canon.js b/plugins/pilot/lib/canon.js new file mode 100644 index 00000000..bdb98558 --- /dev/null +++ b/plugins/pilot/lib/canon.js @@ -0,0 +1,262 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Joe Walker (jwalker@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +var console = require('util/console'); +var Trace = require('util/stacktrace').Trace; +var Event = require('events').Event; +var history = require('canon/history'); + +exports.startup = function(data, reason) { + var settings = data.env.settings; + // TODO register these using new registration functionality + + // catalog.addExtensionPoint("command", { + // "description": + // "A command is a bit of functionality with optional typed arguments which can do something small like moving the cursor around the screen, or large like cloning a project from VCS.", + // "indexOn": "name" + // }); + // catalog.addExtensionPoint("addedRequestOutput", { + // "description": + // "An extension point to be called whenever a new command begins output." + // }); + // catalog.addExtensionPoint("dimensionsChanged", { + // "description": + // "A dimensionsChanged is a way to be notified of changes to the dimension of Skywriter" + // }); + settings.addSetting({ + "name": "historyLength", + "description": "How many typed commands do we recall for reference?", + "type": "number", + "defaultValue": 50 + }); +}; + +exports.shutdown = function(data, reason) { + var settings = data.env.settings; + settings.removeSetting('historyLength'); +}; + +exports.Canon = function() { + this._commands = {}; +}; + +exports.Canon.prototype = { + addCommand: function(options) { + if (!options.name) { + throw new Error("All registered commands must have a name"); + } + this._commands[name] = options; + }, + + removeCommand: function(name) { + delete this._commands[name]; + } +}; + +exports.addedRequestOutput = new Event(); + +/** + * Current requirements are around displaying the command line, and provision + * of a 'history' command and cursor up|down navigation of history. + *

Future requirements could include: + *

    + *
  • Multiple command lines + *
  • The ability to recall key presses (i.e. requests with no output) which + * will likely be needed for macro recording or similar + *
  • The ability to store the command history either on the server or in the + * browser local storage. + *
+ *

The execute() command doesn't really live here, except as part of that + * last future requirement, and because it doesn't really have anywhere else to + * live. + */ + +/** + * The array of requests that wish to announce their presence + */ +exports.requests = []; + +/** + * How many requests do we store? + */ +var maxRequestLength = 100; + +/** + * Called by Request instances when some output (or a cell to async() happens) + */ +exports.addRequestOutput = function(request) { + exports.requests.push(request); + // This could probably be optimized with some maths, but 99.99% of the + // time we will only be off by one, and I'm feeling lazy. + while (exports.requests.length > maxRequestLength) { + exports.requests.shiftObject(); + } + + exports.addedRequestOutput(request); +}; + +/** + * Execute a new command. + * This is basically an error trapping wrapper around request.command(...) + */ +exports.execute = function(args, request) { + // Check the function pointed to in the meta-data exists + if (!request.command) { + request.doneWithError('Command not found.'); + return; + } + + try { + request.command(args, request); + } catch (ex) { + var trace = new Trace(ex, true); + console.group('Error executing command \'' + request.typed + '\''); + console.log('command=', request.commandExt); + console.log('args=', args); + console.error(ex); + trace.log(3); + console.groupEnd(); + + request.doneWithError(ex); + } +}; + +/** + * To create an invocation, you need to do something like this (all the ctor + * args are optional): + *

+ * var request = new Request({
+ *     command: command,
+ *     commandExt: commandExt,
+ *     args: args,
+ *     typed: typed
+ * });
+ * 
+ */ +exports.Request = function(options) { + options = options || {}; + + // Will be used in the keyboard case and the cli case + this.command = options.command; + this.commandExt = options.commandExt; + + // Will be used only in the cli case + this.args = options.args; + this.typed = options.typed; + + // Have we been initialized? + this._begunOutput = false; + + this.start = new Date(); + this.end = null; + this.completed = false; + this.error = false; + + this.changed = new Event(); +}; + +/** + * Lazy init to register with the history should only be done on output. + * init() is expensive, and won't be used in the majority of cases + */ +exports.Request.prototype._beginOutput = function() { + this._begunOutput = true; + this.outputs = []; + + history.addRequestOutput(this); +}; + +/** + * Sugar for: + *
request.error = true; request.done(output);
+ */ +exports.Request.prototype.doneWithError = function(content) { + this.error = true; + this.done(content); +}; + +/** + * Declares that this function will not be automatically done when + * the command exits + */ +exports.Request.prototype.async = function() { + if (!this._begunOutput) { + this._beginOutput(); + } +}; + +/** + * Complete the currently executing command with successful output. + * @param output Either DOM node, an SproutCore element or something that + * can be used in the content of a DIV to create a DOM node. + */ +exports.Request.prototype.output = function(content) { + if (!this._begunOutput) { + this._beginOutput(); + } + + if (typeof content !== 'string' && !(content instanceof Node)) { + content = content.toString(); + } + + this.outputs.push(content); + this.changed(); + + return this; +}; + +/** + * All commands that do output must call this to indicate that the command + * has finished execution. + */ +exports.Request.prototype.done = function(content) { + this.completed = true; + this.end = new Date(); + this.duration = this.end.getTime() - this.start.getTime(); + + if (content) { + this.output(content); + } else { + this.changed(); + } +}; + + + +}); From 1de0d557591eb428436ad06eae73053b8d03bc9b Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Tue, 23 Nov 2010 12:33:20 +0000 Subject: [PATCH 25/90] move old browser fixes to a separate file, and have way to startup/shutdown other modules --- plugins/pilot/lib/fixoldbrowsers.js | 147 ++++++++++++++++++++++++++++ plugins/pilot/lib/index.js | 118 +++------------------- 2 files changed, 158 insertions(+), 107 deletions(-) create mode 100644 plugins/pilot/lib/fixoldbrowsers.js diff --git a/plugins/pilot/lib/fixoldbrowsers.js b/plugins/pilot/lib/fixoldbrowsers.js new file mode 100644 index 00000000..995afb8a --- /dev/null +++ b/plugins/pilot/lib/fixoldbrowsers.js @@ -0,0 +1,147 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Kevin Dangoor (kdangoor@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +exports.startup = function(data, reason) { + // Narwhal's shim for ES5 defineProperty + // ES5 15.2.3.6 + if (!Object.defineProperty) { + Object.defineProperty = function(object, property, descriptor) { + var has = Object.prototype.hasOwnProperty; + if (typeof descriptor == "object" && object.__defineGetter__) { + if (has.call(descriptor, "value")) { + if (!object.__lookupGetter__(property) && !object.__lookupSetter__(property)) { + // data property defined and no pre-existing accessors + object[property] = descriptor.value; + } + if (has.call(descriptor, "get") || has.call(descriptor, "set")) { + // descriptor has a value property but accessor already exists + throw new TypeError("Object doesn't support this action"); + } + } + // fail silently if "writable", "enumerable", or "configurable" + // are requested but not supported + /* + // alternate approach: + if ( // can't implement these features; allow false but not true + !(has.call(descriptor, "writable") ? descriptor.writable : true) || + !(has.call(descriptor, "enumerable") ? descriptor.enumerable : true) || + !(has.call(descriptor, "configurable") ? descriptor.configurable : true) + ) + throw new RangeError( + "This implementation of Object.defineProperty does not " + + "support configurable, enumerable, or writable." + ); + */ + else if (typeof descriptor.get == "function") { + object.__defineGetter__(property, descriptor.get); + } + if (typeof descriptor.set == "function") { + object.__defineSetter__(property, descriptor.set); + } + } + return object; + }; + } + + // ES5 15.2.3.7 + if (!Object.defineProperties) { + Object.defineProperties = function(object, properties) { + for (var property in properties) { + if (Object.prototype.hasOwnProperty.call(properties, property)) { + Object.defineProperty(object, property, properties[property]); + } + } + return object; + }; + } + + + + /** + * Array detector. + * Firefox 3.5 and Safari 4 have this already. Chrome 4 however ... + * Note to Dojo - your isArray is still broken: instanceof doesn't work with + * Arrays taken from a different frame/window. + */ + if (!Array.isArray) { + Array.isArray = function(data) { + return data && Object.prototype.toString.call(data) === "[object Array]"; + }; + } + + /** + * Retrieves the list of keys on an object. + */ + if (!Object.keys) { + Object.keys = function(obj) { + var k, ret = []; + for (k in obj) { + if (obj.hasOwnProperty(k)) { + ret.push(k); + } + } + return ret; + }; + } + + if (!Function.prototype.bind) { + // From Narwhal + Function.prototype.bind = function () { + var args = Array.prototype.slice.call(arguments); + var self = this; + var bound = function () { + return self.call.apply( + self, + args.concat( + Array.prototype.slice.call(arguments) + ) + ); + }; + bound.name = this.name; + bound.displayName = this.displayName; + bound.length = this.length; + bound.unbound = self; + return bound; + }; + } + + exports.globalsLoaded = true; +}; + +}); \ No newline at end of file diff --git a/plugins/pilot/lib/index.js b/plugins/pilot/lib/index.js index 995afb8a..f4a0327d 100644 --- a/plugins/pilot/lib/index.js +++ b/plugins/pilot/lib/index.js @@ -37,111 +37,15 @@ define(function(require, exports, module) { -exports.startup = function(data, reason) { - // Narwhal's shim for ES5 defineProperty - // ES5 15.2.3.6 - if (!Object.defineProperty) { - Object.defineProperty = function(object, property, descriptor) { - var has = Object.prototype.hasOwnProperty; - if (typeof descriptor == "object" && object.__defineGetter__) { - if (has.call(descriptor, "value")) { - if (!object.__lookupGetter__(property) && !object.__lookupSetter__(property)) { - // data property defined and no pre-existing accessors - object[property] = descriptor.value; - } - if (has.call(descriptor, "get") || has.call(descriptor, "set")) { - // descriptor has a value property but accessor already exists - throw new TypeError("Object doesn't support this action"); - } - } - // fail silently if "writable", "enumerable", or "configurable" - // are requested but not supported - /* - // alternate approach: - if ( // can't implement these features; allow false but not true - !(has.call(descriptor, "writable") ? descriptor.writable : true) || - !(has.call(descriptor, "enumerable") ? descriptor.enumerable : true) || - !(has.call(descriptor, "configurable") ? descriptor.configurable : true) - ) - throw new RangeError( - "This implementation of Object.defineProperty does not " + - "support configurable, enumerable, or writable." - ); - */ - else if (typeof descriptor.get == "function") { - object.__defineGetter__(property, descriptor.get); - } - if (typeof descriptor.set == "function") { - object.__defineSetter__(property, descriptor.set); - } - } - return object; - }; - } + exports.startup = function(data, reason) { + require("fixoldbrowsers").startup(data, reason); + require("types/basic").startup(data, reason); + require("canon").startup(data, reason); + }; - // ES5 15.2.3.7 - if (!Object.defineProperties) { - Object.defineProperties = function(object, properties) { - for (var property in properties) { - if (Object.prototype.hasOwnProperty.call(properties, property)) { - Object.defineProperty(object, property, properties[property]); - } - } - return object; - }; - } - - - - /** - * Array detector. - * Firefox 3.5 and Safari 4 have this already. Chrome 4 however ... - * Note to Dojo - your isArray is still broken: instanceof doesn't work with - * Arrays taken from a different frame/window. - */ - if (!Array.isArray) { - Array.isArray = function(data) { - return data && Object.prototype.toString.call(data) === "[object Array]"; - }; - } - - /** - * Retrieves the list of keys on an object. - */ - if (!Object.keys) { - Object.keys = function(obj) { - var k, ret = []; - for (k in obj) { - if (obj.hasOwnProperty(k)) { - ret.push(k); - } - } - return ret; - }; - } - - if (!Function.prototype.bind) { - // From Narwhal - Function.prototype.bind = function () { - var args = Array.prototype.slice.call(arguments); - var self = this; - var bound = function () { - return self.call.apply( - self, - args.concat( - Array.prototype.slice.call(arguments) - ) - ); - }; - bound.name = this.name; - bound.displayName = this.displayName; - bound.length = this.length; - bound.unbound = self; - return bound; - }; - } - - exports.globalsLoaded = true; -}; - -}); \ No newline at end of file + exports.shutdown(data, reason) { + require("fixoldbrowsers").shutdown(data, reason); + require("types/basic").shutdown(data, reason); + require("canon").shutdown(data, reason); + }; +}); From 8d71e5481dfa78e5c83134822533e3da608a926e Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Tue, 23 Nov 2010 12:35:25 +0000 Subject: [PATCH 26/90] comment out urlArgs because it broke debugging. Maybe we should find a way to make this optional? --- editor.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor.html b/editor.html index 1c6703bf..3c3ee2c7 100644 --- a/editor.html +++ b/editor.html @@ -50,7 +50,7 @@ From 504acb230c1f4bfa2678d10dfcd4ab7e69e7225e Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Tue, 23 Nov 2010 13:29:26 +0000 Subject: [PATCH 27/90] fix loading it appears that modules with a shutdown cause a load failure ??? --- plugins/pilot/lib/canon.js | 16 +++++++------ plugins/pilot/lib/index.js | 39 +++++++++++++++++++++++--------- plugins/pilot/lib/types/basic.js | 6 ++--- 3 files changed, 40 insertions(+), 21 deletions(-) diff --git a/plugins/pilot/lib/canon.js b/plugins/pilot/lib/canon.js index bdb98558..d9fd2b57 100644 --- a/plugins/pilot/lib/canon.js +++ b/plugins/pilot/lib/canon.js @@ -37,12 +37,14 @@ define(function(require, exports, module) { -var console = require('util/console'); -var Trace = require('util/stacktrace').Trace; -var Event = require('events').Event; -var history = require('canon/history'); +var console = require('pilot/console'); +var Trace = require('pilot/stacktrace').Trace; +//var Event = require('events').Event; exports.startup = function(data, reason) { + if (!data.env || !data.env.settings) { + return; + } var settings = data.env.settings; // TODO register these using new registration functionality @@ -89,7 +91,7 @@ exports.Canon.prototype = { } }; -exports.addedRequestOutput = new Event(); +// exports.addedRequestOutput = new Event(); /** * Current requirements are around displaying the command line, and provision @@ -188,7 +190,7 @@ exports.Request = function(options) { this.completed = false; this.error = false; - this.changed = new Event(); +// this.changed = new Event(); }; /** @@ -199,7 +201,7 @@ exports.Request.prototype._beginOutput = function() { this._begunOutput = true; this.outputs = []; - history.addRequestOutput(this); + exports.addRequestOutput(this); }; /** diff --git a/plugins/pilot/lib/index.js b/plugins/pilot/lib/index.js index f4a0327d..ecc1df10 100644 --- a/plugins/pilot/lib/index.js +++ b/plugins/pilot/lib/index.js @@ -35,17 +35,34 @@ * * ***** END LICENSE BLOCK ***** */ -define(function(require, exports, module) { +var deps = [ + "pilot/fixoldbrowsers", + "pilot/types/basic", + "pilot/canon" +]; - exports.startup = function(data, reason) { - require("fixoldbrowsers").startup(data, reason); - require("types/basic").startup(data, reason); - require("canon").startup(data, reason); - }; +var packages = deps.slice(); +packages.unshift("require", "exports", "module"); - exports.shutdown(data, reason) { - require("fixoldbrowsers").shutdown(data, reason); - require("types/basic").shutdown(data, reason); - require("canon").shutdown(data, reason); - }; +define(packages, function(require, exports, module) { + +exports.startup = function(data, reason) { + deps.forEach(function(dep) { + console.log("test startup for " + dep); + var module = require(dep); + if (typeof module.startup === "function") { + module.startup(data, reason); + } + }); +}; +/* +exports.shutdown(data, reason) { + deps.forEach(function(dep) { + var module = require(dep); + if (typeof module.shutdown === "function") { + module.shutdown(data, reason); + } + }); +}; +*/ }); diff --git a/plugins/pilot/lib/types/basic.js b/plugins/pilot/lib/types/basic.js index 86c2460a..b301f039 100644 --- a/plugins/pilot/lib/types/basic.js +++ b/plugins/pilot/lib/types/basic.js @@ -38,16 +38,16 @@ define(function(require, exports, module) { -var types = require("types"); +var types = require("pilot/types"); /** * These are the basic types that we accept. They are vaguely based on the * Jetpack settings system (https://wiki.mozilla.org/Labs/Jetpack/JEP/24) * although clearly more restricted. - * + * *

In addition to these types, Jetpack also accepts range, member, password * that we are thinking of adding. - * + * *

This module probably should not be accessed directly, but instead used * through types.js */ From 82143b473b0e8869b218254d2a1dac6118f0260f Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Tue, 23 Nov 2010 14:27:16 +0000 Subject: [PATCH 28/90] move core into pilot --- lib/ace/keybinding.js | 2 +- lib/ace/lib/event.js | 6 +++--- {lib/ace => plugins/pilot}/lib/core.js | 0 3 files changed, 4 insertions(+), 4 deletions(-) rename {lib/ace => plugins/pilot}/lib/core.js (100%) diff --git a/lib/ace/keybinding.js b/lib/ace/keybinding.js index 6de40556..82259692 100644 --- a/lib/ace/keybinding.js +++ b/lib/ace/keybinding.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var core = require("ace/lib/core").core; +var core = require("pilot/core").core; var event = require("ace/lib/event").event; var default_mac = require("ace/conf/keybindings/default_mac").bindings; var default_win = require("ace/conf/keybindings/default_win").bindings; diff --git a/lib/ace/lib/event.js b/lib/ace/lib/event.js index d0569a63..97a3318e 100644 --- a/lib/ace/lib/event.js +++ b/lib/ace/lib/event.js @@ -38,7 +38,7 @@ define(function(require, exports, module) { -var core = require("ace/lib/core").core; +var core = require("pilot/core").core; var event = {}; event.addListener = function(elem, type, callback) { @@ -114,7 +114,7 @@ var core = require("ace/lib/core").core; return Math.max(e.button - 1, 2) } }; - + if (document.documentElement.setCapture) { event.capture = function(el, eventHandler, releaseCaptureHandler) { function onMouseMove(e) { @@ -202,7 +202,7 @@ var core = require("ace/lib/core").core; }, timeout || 600); } - if (event.getButton(e) != button + if (event.getButton(e) != button || Math.abs(e.clientX - startX) > 5 || Math.abs(e.clientY - startY) > 5) clicks = 0; diff --git a/lib/ace/lib/core.js b/plugins/pilot/lib/core.js similarity index 100% rename from lib/ace/lib/core.js rename to plugins/pilot/lib/core.js From 87a15aaa5a46c11652281857fb4016f892c4ce10 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Tue, 23 Nov 2010 14:27:44 +0000 Subject: [PATCH 29/90] move dom.js into pilot --- build.js | 20 +++++++++--------- lib/ace/layer/cursor.js | 4 ++-- lib/ace/layer/text.js | 4 ++-- lib/ace/scrollbar.js | 2 +- lib/ace/theme/clouds.js | 6 +++--- lib/ace/theme/clouds_mignight.js | 6 +++--- lib/ace/theme/cobalt.js | 6 +++--- lib/ace/theme/dawn.js | 6 +++--- lib/ace/theme/eclipse.js | 4 ++-- lib/ace/theme/idle_fingers.js | 6 +++--- lib/ace/theme/kr_theme.js | 6 +++--- lib/ace/theme/mono_industrial.js | 6 +++--- lib/ace/theme/monokai.js | 6 +++--- lib/ace/theme/textmate.js | 4 ++-- lib/ace/theme/twilight.js | 6 +++--- lib/ace/virtual_renderer.js | 30 +++++++++++++-------------- {lib/ace => plugins/pilot}/lib/dom.js | 0 tool/theme.tmpl.js | 6 +++--- 18 files changed, 64 insertions(+), 64 deletions(-) rename {lib/ace => plugins/pilot}/lib/dom.js (100%) diff --git a/build.js b/build.js index 41dfa4a6..522bd244 100644 --- a/build.js +++ b/build.js @@ -29,40 +29,40 @@ "ace/document", "ace/undomanager", "ace/virtual_renderer", - + "ace/mode/javascript", "ace/theme/textmate" ], includeRequire: false }, - - { - name: "ace/theme/eclipse", + + { + name: "ace/theme/eclipse", exclude: [ "ace/lib/lang", - "ace/lib/dom", + "pilot/dom", "ace/lib/oop" ] }, - { + { name: "ace/mode/xml", exclude: [ "ace/lib/oop", "ace/tokenizer", - "ace/mode/text" + "ace/mode/text" ] }, - { + { name: "ace/mode/css", exclude: [ "ace/lib/oop", "ace/lib/lang", "ace/tokenizer", "ace/range", - "ace/mode/text" + "ace/mode/text" ] }, - { + { name: "ace/mode/html", exclude: [ "ace/lib/oop", diff --git a/lib/ace/layer/cursor.js b/lib/ace/layer/cursor.js index 63df911b..57ffc7f7 100644 --- a/lib/ace/layer/cursor.js +++ b/lib/ace/layer/cursor.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var dom = require("ace/lib/dom").dom; +var dom = require("pilot/dom").dom; var Cursor = function(parentEl) { this.element = document.createElement("div"); @@ -120,7 +120,7 @@ var Cursor = function(parentEl) { this.update = function(config) { if (!this.position) return; - + this.config = config; var cursorLeft = Math.round(this.position.column * config.characterWidth); diff --git a/lib/ace/layer/text.js b/lib/ace/layer/text.js index bd610b52..be8d9dd2 100644 --- a/lib/ace/layer/text.js +++ b/lib/ace/layer/text.js @@ -38,7 +38,7 @@ define(function(require, exports, module) { var oop = require("ace/lib/oop").oop; -var dom = require("ace/lib/dom").dom; +var dom = require("pilot/dom").dom; var MEventEmitter = require("ace/event_emitter").MEventEmitter; var Text = function(parentEl) { @@ -154,7 +154,7 @@ var Text = function(parentEl) { this.tokenizer.getTokens(first, last, function(tokens) { for ( var i = first; i <= last; i++) { var lineElement = lineElements[i - layerConfig.firstRow]; - if (!lineElement) + if (!lineElement) continue; var html = []; diff --git a/lib/ace/scrollbar.js b/lib/ace/scrollbar.js index 8072f65c..5d39c77b 100644 --- a/lib/ace/scrollbar.js +++ b/lib/ace/scrollbar.js @@ -39,7 +39,7 @@ define(function(require, exports, module) { var oop = require("ace/lib/oop").oop; var lang = require("ace/lib/lang").lang; -var dom = require("ace/lib/dom").dom; +var dom = require("pilot/dom").dom; var event = require("ace/lib/event").event; var MEventEmitter = require("ace/event_emitter").MEventEmitter; diff --git a/lib/ace/theme/clouds.js b/lib/ace/theme/clouds.js index 5af60b1c..6f1fa494 100644 --- a/lib/ace/theme/clouds.js +++ b/lib/ace/theme/clouds.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { - var dom = require("ace/lib/dom").dom; + var dom = require("pilot/dom").dom; var cssText = ".ace-clouds .ace_editor {\ border: 2px solid rgb(159, 159, 159);\ @@ -187,9 +187,9 @@ define(function(require, exports, module) { .ace-clouds .ace_xml_pe {\ \ }"; - + // import CSS once dom.importCssString(cssText); - + exports.cssClass = "ace-clouds"; }); diff --git a/lib/ace/theme/clouds_mignight.js b/lib/ace/theme/clouds_mignight.js index 130af6f4..d73350f2 100644 --- a/lib/ace/theme/clouds_mignight.js +++ b/lib/ace/theme/clouds_mignight.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { - var dom = require("ace/lib/dom").dom; + var dom = require("pilot/dom").dom; var cssText = ".ace-clouds-midnight .ace_editor {\ border: 2px solid rgb(159, 159, 159);\ @@ -188,9 +188,9 @@ background-color:#E92E2E;\ .ace-clouds-midnight .ace_xml_pe {\ \ }"; - + // import CSS once dom.importCssString(cssText); - + exports.cssClass = "ace-clouds-midnight"; }); diff --git a/lib/ace/theme/cobalt.js b/lib/ace/theme/cobalt.js index 13e95a90..5ae45ca1 100644 --- a/lib/ace/theme/cobalt.js +++ b/lib/ace/theme/cobalt.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { - var dom = require("ace/lib/dom").dom; + var dom = require("pilot/dom").dom; var cssText = ".ace-cobalt .ace_editor {\ border: 2px solid rgb(159, 159, 159);\ @@ -189,9 +189,9 @@ color:#0088FF;\ .ace-cobalt .ace_xml_pe {\ \ }"; - + // import CSS once dom.importCssString(cssText); - + exports.cssClass = "ace-cobalt"; }); diff --git a/lib/ace/theme/dawn.js b/lib/ace/theme/dawn.js index 638ad9c4..02a46140 100644 --- a/lib/ace/theme/dawn.js +++ b/lib/ace/theme/dawn.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { - var dom = require("ace/lib/dom").dom; + var dom = require("pilot/dom").dom; var cssText = ".ace-dawn .ace_editor {\ border: 2px solid rgb(159, 159, 159);\ @@ -193,9 +193,9 @@ color:#5A525F;\ .ace-dawn .ace_xml_pe {\ \ }"; - + // import CSS once dom.importCssString(cssText); - + exports.cssClass = "ace-dawn"; }); diff --git a/lib/ace/theme/eclipse.js b/lib/ace/theme/eclipse.js index 9a03f9e9..9545a5eb 100644 --- a/lib/ace/theme/eclipse.js +++ b/lib/ace/theme/eclipse.js @@ -37,9 +37,9 @@ define(function(require, exports, module) { - var dom = require("ace/lib/dom").dom; + var dom = require("pilot/dom").dom; var cssText = require("text!ace/theme/eclipse.css"); - + // import CSS once dom.importCssString(cssText); diff --git a/lib/ace/theme/idle_fingers.js b/lib/ace/theme/idle_fingers.js index a236413b..c0e3733a 100644 --- a/lib/ace/theme/idle_fingers.js +++ b/lib/ace/theme/idle_fingers.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { - var dom = require("ace/lib/dom").dom; + var dom = require("pilot/dom").dom; var cssText = ".ace-idle-fingers .ace_editor {\ border: 2px solid rgb(159, 159, 159);\ @@ -189,9 +189,9 @@ color:#BC9458;\ .ace-idle-fingers .ace_xml_pe {\ \ }"; - + // import CSS once dom.importCssString(cssText); - + exports.cssClass = "ace-idle-fingers"; }); diff --git a/lib/ace/theme/kr_theme.js b/lib/ace/theme/kr_theme.js index 07ddfb0c..164232d7 100644 --- a/lib/ace/theme/kr_theme.js +++ b/lib/ace/theme/kr_theme.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { - var dom = require("ace/lib/dom").dom; + var dom = require("pilot/dom").dom; var cssText = ".ace-kr-theme .ace_editor {\ border: 2px solid rgb(159, 159, 159);\ @@ -189,9 +189,9 @@ color:#706D5B;\ .ace-kr-theme .ace_xml_pe {\ \ }"; - + // import CSS once dom.importCssString(cssText); - + exports.cssClass = "ace-kr-theme"; }); diff --git a/lib/ace/theme/mono_industrial.js b/lib/ace/theme/mono_industrial.js index d9ac5845..20a0efbb 100644 --- a/lib/ace/theme/mono_industrial.js +++ b/lib/ace/theme/mono_industrial.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { - var dom = require("ace/lib/dom").dom; + var dom = require("pilot/dom").dom; var cssText = ".ace-mono-industrial .ace_editor {\ border: 2px solid rgb(159, 159, 159);\ @@ -189,9 +189,9 @@ background-color:#151C19;\ .ace-mono-industrial .ace_xml_pe {\ \ }"; - + // import CSS once dom.importCssString(cssText); - + exports.cssClass = "ace-mono-industrial"; }); diff --git a/lib/ace/theme/monokai.js b/lib/ace/theme/monokai.js index 5bb1f5f5..3e116bc6 100644 --- a/lib/ace/theme/monokai.js +++ b/lib/ace/theme/monokai.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { - var dom = require("ace/lib/dom").dom; + var dom = require("pilot/dom").dom; var cssText = ".ace-monokai .ace_editor {\ border: 2px solid rgb(159, 159, 159);\ @@ -189,9 +189,9 @@ background-color:#AE81FF;\ .ace-monokai .ace_xml_pe {\ \ }"; - + // import CSS once dom.importCssString(cssText); - + exports.cssClass = "ace-monokai"; }); diff --git a/lib/ace/theme/textmate.js b/lib/ace/theme/textmate.js index 30689c83..19d65d27 100644 --- a/lib/ace/theme/textmate.js +++ b/lib/ace/theme/textmate.js @@ -37,11 +37,11 @@ define(function(require, exports, module) { - var dom = require("ace/lib/dom").dom; + var dom = require("pilot/dom").dom; var cssText = require("text!ace/theme/tm.css"); // import CSS once dom.importCssString(cssText); - + exports.cssClass = "ace-tm"; }); diff --git a/lib/ace/theme/twilight.js b/lib/ace/theme/twilight.js index 74e3ff90..dba0f7a4 100644 --- a/lib/ace/theme/twilight.js +++ b/lib/ace/theme/twilight.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { - var dom = require("ace/lib/dom").dom; + var dom = require("pilot/dom").dom; var cssText = ".ace-twilight .ace_editor {\ border: 2px solid rgb(159, 159, 159);\ @@ -191,9 +191,9 @@ color:#5F5A60;\ .ace-twilight .ace_xml_pe {\ color:#494949;\ }"; - + // import CSS once dom.importCssString(cssText); - + exports.cssClass = "ace-twilight"; }); diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index a24c7080..b2be79e3 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -39,7 +39,7 @@ define(function(require, exports, module) { var oop = require("ace/lib/oop").oop; var lang = require("ace/lib/lang").lang; -var dom = require("ace/lib/dom").dom; +var dom = require("pilot/dom").dom; var event = require("ace/lib/event").event; var GutterLayer = require("ace/layer/gutter").Gutter; var MarkerLayer = require("ace/layer/marker").Marker; @@ -113,7 +113,7 @@ var VirtualRenderer = function(container, theme) { this.$loop = new RenderLoop(lang.bind(this.$renderChanges, this)); this.$loop.schedule(this.CHANGE_FULL); - + this.$updatePrintMargin(); this.setPadding(4); }; @@ -260,7 +260,7 @@ var VirtualRenderer = function(container, theme) { this.getPrintMarginColumn = function() { return this.$printMarginColumn; }; - + this.setShowGutter = function(show){ this.$gutter.style.display = show ? "block" : "none"; this.showGutter = show; @@ -293,18 +293,18 @@ var VirtualRenderer = function(container, theme) { this.getFirstVisibleRow = function() { return (this.layerConfig || {}).firstRow || 0; }; - + this.getFirstFullyVisibleRow = function(){ if (!this.layerConfig) return 0; - + return this.layerConfig.firstRow + (this.layerConfig.offset == 0 ? 0 : 1); } this.getLastFullyVisibleRow = function() { if (!this.layerConfig) return 0; - + var flint = Math.floor((this.layerConfig.height + this.layerConfig.offset) / this.layerConfig.lineHeight); return this.layerConfig.firstRow - 1 + flint; } @@ -376,8 +376,8 @@ var VirtualRenderer = function(container, theme) { this.showGutter && this.$gutterLayer.update(this.layerConfig); } else if (changes & this.CHANGE_LINES) { - this.$updateLines(); - this.$updateScrollBar(); + this.$updateLines(); + this.$updateScrollBar(); } else if (changes & this.CHANGE_SCROLL) { this.$textLayer.scrollLines(this.layerConfig); @@ -477,17 +477,17 @@ var VirtualRenderer = function(container, theme) { this.$markerLayer.removeMarker(markerId); this.$loop.schedule(this.CHANGE_MARKER); }; - + this.addGutterDecoration = function(row, className){ this.$gutterLayer.addGutterDecoration(row, className); this.$loop.schedule(this.CHANGE_GUTTER); } - + this.removeGutterDecoration = function(row, className){ this.$gutterLayer.removeGutterDecoration(row, className); this.$loop.schedule(this.CHANGE_GUTTER); } - + this.setBreakpoints = function(rows) { this.$gutterLayer.setBreakpoints(rows); this.$loop.schedule(this.CHANGE_GUTTER); @@ -535,7 +535,7 @@ var VirtualRenderer = function(container, theme) { this.getScrollTop = function() { return this.scrollTop; }; - + this.getScrollLeft = function() { return this.scroller.scrollLeft; }; @@ -557,7 +557,7 @@ var VirtualRenderer = function(container, theme) { this.$loop.schedule(this.CHANGE_SCROLL); } }; - + this.scrollToX = function(scrollLeft) { if (scrollLeft <= this.$padding) scrollLeft = 0; @@ -586,10 +586,10 @@ var VirtualRenderer = function(container, theme) { this.textToScreenCoordinates = function(row, column) { var canvasPos = this.scroller.getBoundingClientRect(); - + var x = this.padding + Math.round(this.doc.documentToScreenColumn(row, column) * this.characterWidth); var y = row * this.lineHeight; - + return { pageX: canvasPos.left + x - this.getScrollLeft(), pageY: canvasPos.top + y - this.getScrollTop() diff --git a/lib/ace/lib/dom.js b/plugins/pilot/lib/dom.js similarity index 100% rename from lib/ace/lib/dom.js rename to plugins/pilot/lib/dom.js diff --git a/tool/theme.tmpl.js b/tool/theme.tmpl.js index d7cd7f73..38a23553 100644 --- a/tool/theme.tmpl.js +++ b/tool/theme.tmpl.js @@ -1,10 +1,10 @@ define(function(require, exports, module) { - var dom = require("ace/lib/dom"); + var dom = require("pilot/dom"); var cssText = %css%; - + // import CSS once dom.importCssString(cssText); - + return { cssClass: "%cssClass%" }; From 0977c392f1e679c187b6aadfd2bee01b44517c7c Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Tue, 23 Nov 2010 14:33:38 +0000 Subject: [PATCH 30/90] move event.js into pilot --- demo/demo_startup.js | 26 +++++++++++------------ demo/editor-build.html | 2 +- lib/ace/editor.js | 28 ++++++++++++------------- lib/ace/keybinding.js | 2 +- lib/ace/renderloop.js | 14 ++++++------- lib/ace/scrollbar.js | 2 +- lib/ace/textinput.js | 2 +- lib/ace/virtual_renderer.js | 2 +- {lib/ace => plugins/pilot}/lib/event.js | 0 9 files changed, 39 insertions(+), 39 deletions(-) rename {lib/ace => plugins/pilot}/lib/event.js (100%) diff --git a/demo/demo_startup.js b/demo/demo_startup.js index 177b5e06..b0630077 100644 --- a/demo/demo_startup.js +++ b/demo/demo_startup.js @@ -40,8 +40,8 @@ define(function(require, exports, module) { exports.launch = function() { - - var eventMod = require("ace/lib/event"); + + var eventMod = require("pilot/event"); var editorMod = require("ace/editor"); var renderMod = require("ace/virtual_renderer"); var theme = require("ace/theme/textmate"); @@ -83,7 +83,7 @@ exports.launch = function() { function onDocChange() { var doc = getDoc(); editor.setDocument(doc); - + var mode = doc.getMode(); if (mode instanceof JavaScriptMode) { modeEl.value = "javascript" @@ -100,7 +100,7 @@ exports.launch = function() { else { modeEl.value = "text" } - + editor.focus(); } docEl.onchange = onDocChange; @@ -123,7 +123,7 @@ exports.launch = function() { }; function getMode() { - return modes[modeEl.value]; + return modes[modeEl.value]; } var themeEl = document.getElementById("theme"); @@ -160,8 +160,8 @@ exports.launch = function() { function onResize() { container.style.width = (document.documentElement.clientWidth - 4) + "px"; - container.style.height = (document.documentElement.clientHeight - 55 - 4) + "px"; - editor.resize(); + container.style.height = (document.documentElement.clientHeight - 55 - 4) + "px"; + editor.resize(); }; window.onresize = onResize; @@ -177,12 +177,12 @@ exports.launch = function() { } catch(e) { return event.stopEvent(); } - + if (window.FileReader) { var reader = new FileReader(); reader.onload = function(e) { editor.getSelection().selectAll(); - + var mode = "text"; if (/^.*\.js$/i.test(file.name)) { mode = "javascript"; @@ -193,15 +193,15 @@ exports.launch = function() { } else if (/^.*\.css$/i.test(file.name)) { mode = "css"; } - + editor.onTextInput(reader.result); - - modeEl.value = mode; + + modeEl.value = mode; editor.getDocument().setMode(modes[mode]); } reader.readAsText(file); } - + return event.preventDefault(e); }); }; diff --git a/demo/editor-build.html b/demo/editor-build.html index 637b672c..deac861c 100644 --- a/demo/editor-build.html +++ b/demo/editor-build.html @@ -137,7 +137,7 @@ require( { baseUrl: "../build" }, [ - "ace/lib/event", + "pilot/event", "ace/editor", "ace/virtual_renderer", "ace/theme/textmate", diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 0b4ab4c1..01faa5c0 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -38,7 +38,7 @@ define(function(require, exports, module) { var oop = require("ace/lib/oop").oop; -var event = require("ace/lib/event").event; +var event = require("pilot/event").event; var lang = require("ace/lib/lang").lang; var TextInput = require("ace/textinput").TextInput; var KeyBinding = require("ace/keybinding").KeyBinding; @@ -301,7 +301,7 @@ var Editor =function(renderer, doc) { var pos = this.renderer.screenToTextCoordinates(pageX, pageY); pos.row = Math.max(0, Math.min(pos.row, this.doc.getLength()-1)); - + if (event.getButton(e) != 0) { if (this.selection.isEmpty()) { this.moveCursorToPosition(pos); @@ -436,7 +436,7 @@ var Editor =function(renderer, doc) { return; } */ - + _self.bgTokenizer.getState(cursor.row, function(lineState) { // multi line insert if (cursor.row !== end.row) { @@ -450,7 +450,7 @@ var Editor =function(renderer, doc) { for (var i = 0; i < line.length; ++i) if (line.charAt(i) == '\t') indent += size; - else if (line.charAt(i) == ' ') + else if (line.charAt(i) == ' ') indent += 1; else break; @@ -469,7 +469,7 @@ var Editor =function(renderer, doc) { _self.doc.replace(new Range(row, 0, row, line.length), line.substr(i)); } end.column += _self.doc.indentRows( - new Range(cursor.row + 1, 0, end.row, end.column), + new Range(cursor.row + 1, 0, end.row, end.column), lineIndent); } else { if (shouldOutdent) { @@ -603,19 +603,19 @@ var Editor =function(renderer, doc) { return; var range = this.getSelectionRange(); - + if (range.start.row < range.end.row || range.start.column < range.end.column) { var count = this.doc.indentRows(this.getSelectionRange(), "\t"); - + this.selection.shiftSelection(count); } else { var indentString; - + if (this.doc.getUseSoftTabs()) { var size = this.doc.getTabSize(), count = (size - this.getCursorPosition().column % size); - + indentString = lang.stringRepeat(" ", count); } else indentString = "\t"; @@ -629,7 +629,7 @@ var Editor =function(renderer, doc) { var selection = this.doc.getSelection(), range = this.doc.outdentRows(selection.getRange()); - + selection.setSelectionRange(range, selection.isBackwards()); this.$updateDesiredColumn(); }; @@ -793,7 +793,7 @@ var Editor =function(renderer, doc) { var row = this.getPageDownRow(), column = Math.min(this.getCursorPosition().column, this.doc.getLine(row).length); - + this.scrollToRow(row); this.getSelection().moveCursorTo(row, column); }; @@ -802,7 +802,7 @@ var Editor =function(renderer, doc) { var row = this.getPageUpRow(), column = Math.min(this.getCursorPosition().column, this.doc.getLine(row).length); - + this.scrollToRow(row); this.getSelection().moveCursorTo(row, column); }; @@ -846,7 +846,7 @@ var Editor =function(renderer, doc) { this.gotoLine = function(lineNumber, row) { this.selection.clearSelection(); - + this.$blockScrolling = true; this.moveCursorTo(lineNumber-1, row || 0); this.$blockScrolling = false; @@ -944,7 +944,7 @@ var Editor =function(renderer, doc) { this.replace = function(replacement, options) { if (options) this.$search.set(options); - + var range = this.$search.find(this.doc); this.$tryReplace(range, replacement); if (range !== null) diff --git a/lib/ace/keybinding.js b/lib/ace/keybinding.js index 82259692..78212755 100644 --- a/lib/ace/keybinding.js +++ b/lib/ace/keybinding.js @@ -38,7 +38,7 @@ define(function(require, exports, module) { var core = require("pilot/core").core; -var event = require("ace/lib/event").event; +var event = require("pilot/event").event; var default_mac = require("ace/conf/keybindings/default_mac").bindings; var default_win = require("ace/conf/keybindings/default_win").bindings; var PluginManager = require("pilot/plugin_manager").PluginManager; diff --git a/lib/ace/renderloop.js b/lib/ace/renderloop.js index 7f1639e4..f43efcc1 100644 --- a/lib/ace/renderloop.js +++ b/lib/ace/renderloop.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var event = require("ace/lib/event").event; +var event = require("pilot/event").event; var RenderLoop = function(onRender) { this.onRender = onRender; @@ -61,11 +61,11 @@ var RenderLoop = function(onRender) { }) } }; - + if (window.postMessage) { - + this.messageName = "zero-timeout-message"; - + this.setTimeoutZero = function(callback) { if (!this.attached) { var _self = this; @@ -80,14 +80,14 @@ var RenderLoop = function(onRender) { this.callback = callback; window.postMessage(this.messageName, "*"); } - + } else { - + this.setTimeoutZero = function(callback) { setTimeout(callback, 0); } } - + }).call(RenderLoop.prototype); exports.RenderLoop = RenderLoop; diff --git a/lib/ace/scrollbar.js b/lib/ace/scrollbar.js index 5d39c77b..7bc741e8 100644 --- a/lib/ace/scrollbar.js +++ b/lib/ace/scrollbar.js @@ -40,7 +40,7 @@ define(function(require, exports, module) { var oop = require("ace/lib/oop").oop; var lang = require("ace/lib/lang").lang; var dom = require("pilot/dom").dom; -var event = require("ace/lib/event").event; +var event = require("pilot/event").event; var MEventEmitter = require("ace/event_emitter").MEventEmitter; var ScrollBar = function(parent) { diff --git a/lib/ace/textinput.js b/lib/ace/textinput.js index 88f84dd5..d4abdc96 100644 --- a/lib/ace/textinput.js +++ b/lib/ace/textinput.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var event = require("ace/lib/event").event; +var event = require("pilot/event").event; var TextInput = function(parentNode, host) { diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index b2be79e3..46b45caa 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -40,7 +40,7 @@ define(function(require, exports, module) { var oop = require("ace/lib/oop").oop; var lang = require("ace/lib/lang").lang; var dom = require("pilot/dom").dom; -var event = require("ace/lib/event").event; +var event = require("pilot/event").event; var GutterLayer = require("ace/layer/gutter").Gutter; var MarkerLayer = require("ace/layer/marker").Marker; var TextLayer = require("ace/layer/text").Text; diff --git a/lib/ace/lib/event.js b/plugins/pilot/lib/event.js similarity index 100% rename from lib/ace/lib/event.js rename to plugins/pilot/lib/event.js From 5f3beef482a5e4d7b2c864474e631f990eac33ca Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Tue, 23 Nov 2010 14:35:01 +0000 Subject: [PATCH 31/90] move lang.js into pilot --- build.js | 6 +++--- lib/ace/document.js | 2 +- lib/ace/editor.js | 2 +- lib/ace/event_emitter.js | 2 +- lib/ace/mode/css_highlight_rules.js | 2 +- lib/ace/mode/javascript_highlight_rules.js | 2 +- lib/ace/scrollbar.js | 2 +- lib/ace/search.js | 2 +- lib/ace/selection.js | 2 +- lib/ace/virtual_renderer.js | 2 +- plugins/pilot/lib/dom.js | 2 +- {lib/ace => plugins/pilot}/lib/lang.js | 0 12 files changed, 13 insertions(+), 13 deletions(-) rename {lib/ace => plugins/pilot}/lib/lang.js (100%) diff --git a/build.js b/build.js index 522bd244..0f2eef83 100644 --- a/build.js +++ b/build.js @@ -39,7 +39,7 @@ { name: "ace/theme/eclipse", exclude: [ - "ace/lib/lang", + "pilot/lang", "pilot/dom", "ace/lib/oop" ] @@ -56,7 +56,7 @@ name: "ace/mode/css", exclude: [ "ace/lib/oop", - "ace/lib/lang", + "pilot/lang", "ace/tokenizer", "ace/range", "ace/mode/text" @@ -66,7 +66,7 @@ name: "ace/mode/html", exclude: [ "ace/lib/oop", - "ace/lib/lang", + "pilot/lang", "ace/tokenizer", "ace/range", "ace/mode/text", diff --git a/lib/ace/document.js b/lib/ace/document.js index 903b8e51..40c67ab1 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -38,7 +38,7 @@ define(function(require, exports, module) { var oop = require("ace/lib/oop").oop; -var lang = require("ace/lib/lang").lang; +var lang = require("pilot/lang").lang; var MEventEmitter = require("ace/event_emitter").MEventEmitter; var Selection = require("ace/selection").Selection; var TextMode = require("ace/mode/text").Text; diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 01faa5c0..7fc87d25 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -39,7 +39,7 @@ define(function(require, exports, module) { var oop = require("ace/lib/oop").oop; var event = require("pilot/event").event; -var lang = require("ace/lib/lang").lang; +var lang = require("pilot/lang").lang; var TextInput = require("ace/textinput").TextInput; var KeyBinding = require("ace/keybinding").KeyBinding; var Document = require("ace/document").Document; diff --git a/lib/ace/event_emitter.js b/lib/ace/event_emitter.js index 3bfb8277..d7b1a14c 100644 --- a/lib/ace/event_emitter.js +++ b/lib/ace/event_emitter.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { - var lang = require("ace/lib/lang").lang; + var lang = require("pilot/lang").lang; var MEventEmitter = {} diff --git a/lib/ace/mode/css_highlight_rules.js b/lib/ace/mode/css_highlight_rules.js index b06199ff..e5f79e8e 100644 --- a/lib/ace/mode/css_highlight_rules.js +++ b/lib/ace/mode/css_highlight_rules.js @@ -38,7 +38,7 @@ define(function(require, exports, module) { var oop = require("ace/lib/oop").oop; -var lang = require("ace/lib/lang").lang; +var lang = require("pilot/lang").lang; var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules; var CssHighlightRules = function() { diff --git a/lib/ace/mode/javascript_highlight_rules.js b/lib/ace/mode/javascript_highlight_rules.js index 0a054e5f..a7a6ad0d 100644 --- a/lib/ace/mode/javascript_highlight_rules.js +++ b/lib/ace/mode/javascript_highlight_rules.js @@ -38,7 +38,7 @@ define(function(require, exports, module) { var oop = require("ace/lib/oop").oop; -var lang = require("ace/lib/lang").lang; +var lang = require("pilot/lang").lang; var DocCommentHighlightRules = require("ace/mode/doc_comment_highlight_rules").DocCommentHighlightRules; var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules; diff --git a/lib/ace/scrollbar.js b/lib/ace/scrollbar.js index 7bc741e8..da10d301 100644 --- a/lib/ace/scrollbar.js +++ b/lib/ace/scrollbar.js @@ -38,7 +38,7 @@ define(function(require, exports, module) { var oop = require("ace/lib/oop").oop; -var lang = require("ace/lib/lang").lang; +var lang = require("pilot/lang").lang; var dom = require("pilot/dom").dom; var event = require("pilot/event").event; var MEventEmitter = require("ace/event_emitter").MEventEmitter; diff --git a/lib/ace/search.js b/lib/ace/search.js index 1f700e9a..815c5cd4 100644 --- a/lib/ace/search.js +++ b/lib/ace/search.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var lang = require("ace/lib/lang").lang; +var lang = require("pilot/lang").lang; var oop = require("ace/lib/oop").oop; var Range = require("ace/range").Range; diff --git a/lib/ace/selection.js b/lib/ace/selection.js index 51c0a9b4..82d1af65 100644 --- a/lib/ace/selection.js +++ b/lib/ace/selection.js @@ -38,7 +38,7 @@ define(function(require, exports, module) { var oop = require("ace/lib/oop").oop; -var lang = require("ace/lib/lang").lang; +var lang = require("pilot/lang").lang; var MEventEmitter = require("ace/event_emitter").MEventEmitter; var Range = require("ace/range").Range; diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index 46b45caa..6cbdd48e 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -38,7 +38,7 @@ define(function(require, exports, module) { var oop = require("ace/lib/oop").oop; -var lang = require("ace/lib/lang").lang; +var lang = require("pilot/lang").lang; var dom = require("pilot/dom").dom; var event = require("pilot/event").event; var GutterLayer = require("ace/layer/gutter").Gutter; diff --git a/plugins/pilot/lib/dom.js b/plugins/pilot/lib/dom.js index 4dac3cb1..f1021241 100644 --- a/plugins/pilot/lib/dom.js +++ b/plugins/pilot/lib/dom.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { - var lang = require("ace/lib/lang").lang; + var lang = require("pilot/lang").lang; var dom = {}; diff --git a/lib/ace/lib/lang.js b/plugins/pilot/lib/lang.js similarity index 100% rename from lib/ace/lib/lang.js rename to plugins/pilot/lib/lang.js From be9b8a0f3fffecb744fe9f1c544bcdefcbcf9d72 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Tue, 23 Nov 2010 14:36:12 +0000 Subject: [PATCH 32/90] move oop.js into pilot --- build.js | 8 ++++---- lib/ace/background_tokenizer.js | 2 +- lib/ace/document.js | 2 +- lib/ace/editor.js | 2 +- lib/ace/layer/text.js | 2 +- lib/ace/mode/css.js | 2 +- lib/ace/mode/css_highlight_rules.js | 2 +- lib/ace/mode/doc_comment_highlight_rules.js | 2 +- lib/ace/mode/html.js | 2 +- lib/ace/mode/html_highlight_rules.js | 2 +- lib/ace/mode/javascript.js | 2 +- lib/ace/mode/javascript_highlight_rules.js | 2 +- lib/ace/mode/xml.js | 2 +- lib/ace/mode/xml_highlight_rules.js | 2 +- lib/ace/scrollbar.js | 2 +- lib/ace/search.js | 2 +- lib/ace/selection.js | 2 +- lib/ace/test/event_emitter_test.js | 2 +- lib/ace/virtual_renderer.js | 2 +- {lib/ace => plugins/pilot}/lib/oop.js | 0 20 files changed, 22 insertions(+), 22 deletions(-) rename {lib/ace => plugins/pilot}/lib/oop.js (100%) diff --git a/build.js b/build.js index 0f2eef83..0dff8958 100644 --- a/build.js +++ b/build.js @@ -41,13 +41,13 @@ exclude: [ "pilot/lang", "pilot/dom", - "ace/lib/oop" + "pilot/oop" ] }, { name: "ace/mode/xml", exclude: [ - "ace/lib/oop", + "pilot/oop", "ace/tokenizer", "ace/mode/text" ] @@ -55,7 +55,7 @@ { name: "ace/mode/css", exclude: [ - "ace/lib/oop", + "pilot/oop", "pilot/lang", "ace/tokenizer", "ace/range", @@ -65,7 +65,7 @@ { name: "ace/mode/html", exclude: [ - "ace/lib/oop", + "pilot/oop", "pilot/lang", "ace/tokenizer", "ace/range", diff --git a/lib/ace/background_tokenizer.js b/lib/ace/background_tokenizer.js index 21539d69..642ffb7a 100644 --- a/lib/ace/background_tokenizer.js +++ b/lib/ace/background_tokenizer.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var oop = require("ace/lib/oop").oop; +var oop = require("pilot/oop").oop; var MEventEmitter = require("ace/event_emitter").MEventEmitter; var BackgroundTokenizer = function(tokenizer, editor) { diff --git a/lib/ace/document.js b/lib/ace/document.js index 40c67ab1..51def67b 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var oop = require("ace/lib/oop").oop; +var oop = require("pilot/oop").oop; var lang = require("pilot/lang").lang; var MEventEmitter = require("ace/event_emitter").MEventEmitter; var Selection = require("ace/selection").Selection; diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 7fc87d25..4953330c 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var oop = require("ace/lib/oop").oop; +var oop = require("pilot/oop").oop; var event = require("pilot/event").event; var lang = require("pilot/lang").lang; var TextInput = require("ace/textinput").TextInput; diff --git a/lib/ace/layer/text.js b/lib/ace/layer/text.js index be8d9dd2..7fef701e 100644 --- a/lib/ace/layer/text.js +++ b/lib/ace/layer/text.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var oop = require("ace/lib/oop").oop; +var oop = require("pilot/oop").oop; var dom = require("pilot/dom").dom; var MEventEmitter = require("ace/event_emitter").MEventEmitter; diff --git a/lib/ace/mode/css.js b/lib/ace/mode/css.js index 743f5863..4c6bd198 100644 --- a/lib/ace/mode/css.js +++ b/lib/ace/mode/css.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var oop = require("ace/lib/oop").oop; +var oop = require("pilot/oop").oop; var TextMode = require("ace/mode/text").Text; var Tokenizer = require("ace/tokenizer").Tokenizer; var CssHighlightRules = require("ace/mode/css_highlight_rules").CssHighlightRules; diff --git a/lib/ace/mode/css_highlight_rules.js b/lib/ace/mode/css_highlight_rules.js index e5f79e8e..a4445f41 100644 --- a/lib/ace/mode/css_highlight_rules.js +++ b/lib/ace/mode/css_highlight_rules.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var oop = require("ace/lib/oop").oop; +var oop = require("pilot/oop").oop; var lang = require("pilot/lang").lang; var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules; diff --git a/lib/ace/mode/doc_comment_highlight_rules.js b/lib/ace/mode/doc_comment_highlight_rules.js index ac9dda55..48812aed 100644 --- a/lib/ace/mode/doc_comment_highlight_rules.js +++ b/lib/ace/mode/doc_comment_highlight_rules.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var oop = require("ace/lib/oop").oop; +var oop = require("pilot/oop").oop; var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules; var DocCommentHighlightRules = function() { diff --git a/lib/ace/mode/html.js b/lib/ace/mode/html.js index b078fcd6..f6587676 100644 --- a/lib/ace/mode/html.js +++ b/lib/ace/mode/html.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var oop = require("ace/lib/oop").oop; +var oop = require("pilot/oop").oop; var TextMode = require("ace/mode/text").Text; var JavaScriptMode = require("ace/mode/javascript").JavaScript; var CssMode = require("ace/mode/css").Css; diff --git a/lib/ace/mode/html_highlight_rules.js b/lib/ace/mode/html_highlight_rules.js index 4ba538c6..be441552 100644 --- a/lib/ace/mode/html_highlight_rules.js +++ b/lib/ace/mode/html_highlight_rules.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var oop = require("ace/lib/oop").oop; +var oop = require("pilot/oop").oop; var CssHighlightRules = require("ace/mode/css_highlight_rules").CssHighlightRules; var JavaScriptHighlightRules = require("ace/mode/javascript_highlight_rules").JavaScriptHighlightRules; var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules; diff --git a/lib/ace/mode/javascript.js b/lib/ace/mode/javascript.js index 64a86d1b..d39bb846 100644 --- a/lib/ace/mode/javascript.js +++ b/lib/ace/mode/javascript.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var oop = require("ace/lib/oop").oop; +var oop = require("pilot/oop").oop; var TextMode = require("ace/mode/text").Text; var Tokenizer = require("ace/tokenizer").Tokenizer; var JavaScriptHighlightRules = require("ace/mode/javascript_highlight_rules").JavaScriptHighlightRules; diff --git a/lib/ace/mode/javascript_highlight_rules.js b/lib/ace/mode/javascript_highlight_rules.js index a7a6ad0d..0cbad802 100644 --- a/lib/ace/mode/javascript_highlight_rules.js +++ b/lib/ace/mode/javascript_highlight_rules.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var oop = require("ace/lib/oop").oop; +var oop = require("pilot/oop").oop; var lang = require("pilot/lang").lang; var DocCommentHighlightRules = require("ace/mode/doc_comment_highlight_rules").DocCommentHighlightRules; var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules; diff --git a/lib/ace/mode/xml.js b/lib/ace/mode/xml.js index a8fb60ca..0a83adb1 100644 --- a/lib/ace/mode/xml.js +++ b/lib/ace/mode/xml.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var oop = require("ace/lib/oop").oop; +var oop = require("pilot/oop").oop; var TextMode = require("ace/mode/text").Text; var Tokenizer = require("ace/tokenizer").Tokenizer; var XmlHighlightRules = require("ace/mode/xml_highlight_rules").XmlHighlightRules; diff --git a/lib/ace/mode/xml_highlight_rules.js b/lib/ace/mode/xml_highlight_rules.js index 923a092e..b1c6e874 100644 --- a/lib/ace/mode/xml_highlight_rules.js +++ b/lib/ace/mode/xml_highlight_rules.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var oop = require("ace/lib/oop").oop; +var oop = require("pilot/oop").oop; var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules; var XmlHighlightRules = function() { diff --git a/lib/ace/scrollbar.js b/lib/ace/scrollbar.js index da10d301..042e2e0c 100644 --- a/lib/ace/scrollbar.js +++ b/lib/ace/scrollbar.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var oop = require("ace/lib/oop").oop; +var oop = require("pilot/oop").oop; var lang = require("pilot/lang").lang; var dom = require("pilot/dom").dom; var event = require("pilot/event").event; diff --git a/lib/ace/search.js b/lib/ace/search.js index 815c5cd4..3ea5eba0 100644 --- a/lib/ace/search.js +++ b/lib/ace/search.js @@ -38,7 +38,7 @@ define(function(require, exports, module) { var lang = require("pilot/lang").lang; -var oop = require("ace/lib/oop").oop; +var oop = require("pilot/oop").oop; var Range = require("ace/range").Range; var Search = function() { diff --git a/lib/ace/selection.js b/lib/ace/selection.js index 82d1af65..062d5077 100644 --- a/lib/ace/selection.js +++ b/lib/ace/selection.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var oop = require("ace/lib/oop").oop; +var oop = require("pilot/oop").oop; var lang = require("pilot/lang").lang; var MEventEmitter = require("ace/event_emitter").MEventEmitter; var Range = require("ace/range").Range; diff --git a/lib/ace/test/event_emitter_test.js b/lib/ace/test/event_emitter_test.js index 05881cdd..a5ee56ee 100644 --- a/lib/ace/test/event_emitter_test.js +++ b/lib/ace/test/event_emitter_test.js @@ -38,7 +38,7 @@ define(function(require, exports, module) { var MEventEmitter = require("ace/event_emitter").MEventEmitter; -var oop = require("ace/lib/oop").oop; +var oop = require("pilot/oop").oop; var EventEmitter = function() {}; diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index 6cbdd48e..2c3e74e7 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var oop = require("ace/lib/oop").oop; +var oop = require("pilot/oop").oop; var lang = require("pilot/lang").lang; var dom = require("pilot/dom").dom; var event = require("pilot/event").event; diff --git a/lib/ace/lib/oop.js b/plugins/pilot/lib/oop.js similarity index 100% rename from lib/ace/lib/oop.js rename to plugins/pilot/lib/oop.js From 81cb24ef17932cb4c86063dea66199dcd516850f Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Tue, 23 Nov 2010 14:40:07 +0000 Subject: [PATCH 33/90] minor tidyups --- demo/demo_startup.js | 51 +++++++++++++++----------------------- lib/ace/event_emitter.js | 2 +- plugins/pilot/lib/event.js | 8 +++--- 3 files changed, 25 insertions(+), 36 deletions(-) diff --git a/demo/demo_startup.js b/demo/demo_startup.js index b0630077..adf0d5cf 100644 --- a/demo/demo_startup.js +++ b/demo/demo_startup.js @@ -41,30 +41,19 @@ define(function(require, exports, module) { exports.launch = function() { - var eventMod = require("pilot/event"); - var editorMod = require("ace/editor"); - var renderMod = require("ace/virtual_renderer"); + var event = require("pilot/event").event; + var Editor = require("ace/editor").Editor; + var Renderer = require("ace/virtual_renderer").VirtualRenderer; var theme = require("ace/theme/textmate"); - var docMod = require("ace/document"); - var jsMod = require("ace/mode/javascript"); - var cssMod = require("ace/mode/css"); - var htmlMod = require("ace/mode/html"); - var xmlMod = require("ace/mode/xml"); - var textMod = require("ace/mode/text"); - var undoMod = require("ace/undomanager"); + var Document = require("ace/document").Document; + var JavaScriptMode = require("ace/mode/javascript").JavaScript; + var CssMode = require("ace/mode/css").Css; + var HtmlMode = require("ace/mode/html").Html; + var XmlMode = require("ace/mode/xml").Xml; + var TextMode = require("ace/mode/text").Text; + var UndoManager = require("ace/undomanager").UndoManager; - var event = eventMod.event; - var Editor = editorMod.Editor; - var Renderer = renderMod.VirtualRenderer; - var Document = docMod.Document; - var JavaScriptMode = jsMod.JavaScript; - var CssMode = cssMod.Css; - var HtmlMode = htmlMod.Html; - var XmlMode = xmlMod.Xml; - var TextMode = textMod.Text; - var UndoManager = undoMod.UndoManager; - - var docs = {} + var docs = {}; docs.js = new Document(document.getElementById("jstext").innerHTML); docs.js.setMode(new JavaScriptMode()); @@ -86,19 +75,19 @@ exports.launch = function() { var mode = doc.getMode(); if (mode instanceof JavaScriptMode) { - modeEl.value = "javascript" + modeEl.value = "javascript"; } else if (mode instanceof CssMode) { - modeEl.value = "css" + modeEl.value = "css"; } else if (mode instanceof HtmlMode) { - modeEl.value = "html" + modeEl.value = "html"; } else if (mode instanceof XmlMode) { - modeEl.value = "xml" + modeEl.value = "xml"; } else { - modeEl.value = "text" + modeEl.value = "text"; } editor.focus(); @@ -150,13 +139,13 @@ exports.launch = function() { onDocChange(); window.jump = function() { - var jump = document.getElementById("jump") - var cursor = editor.getCursorPosition() + var jump = document.getElementById("jump"); + var cursor = editor.getCursorPosition(); var pos = editor.renderer.textToScreenCoordinates(cursor.row, cursor.column); jump.style.left = pos.pageX + "px"; jump.style.top = pos.pageY + "px"; jump.style.display = "block"; - } + }; function onResize() { container.style.width = (document.documentElement.clientWidth - 4) + "px"; @@ -198,7 +187,7 @@ exports.launch = function() { modeEl.value = mode; editor.getDocument().setMode(modes[mode]); - } + }; reader.readAsText(file); } diff --git a/lib/ace/event_emitter.js b/lib/ace/event_emitter.js index d7b1a14c..2ebe0803 100644 --- a/lib/ace/event_emitter.js +++ b/lib/ace/event_emitter.js @@ -39,7 +39,7 @@ define(function(require, exports, module) { var lang = require("pilot/lang").lang; - var MEventEmitter = {} + var MEventEmitter = {}; MEventEmitter.$dispatchEvent = function(eventName, e) { this.$eventRegistry = this.$eventRegistry || {}; diff --git a/plugins/pilot/lib/event.js b/plugins/pilot/lib/event.js index 97a3318e..033b9136 100644 --- a/plugins/pilot/lib/event.js +++ b/plugins/pilot/lib/event.js @@ -37,8 +37,7 @@ define(function(require, exports, module) { - -var core = require("pilot/core").core; + var core = require("pilot/core").core; var event = {}; event.addListener = function(elem, type, callback) { @@ -111,7 +110,7 @@ var core = require("pilot/core").core; } // old IE else { - return Math.max(e.button - 1, 2) + return Math.max(e.button - 1, 2); } }; @@ -239,4 +238,5 @@ var core = require("pilot/core").core; }; exports.event = event; -}); \ No newline at end of file + +}); From 3d3cef1a6fe9878a5dbd93dc0156180d86862587 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Tue, 23 Nov 2010 15:38:32 +0000 Subject: [PATCH 34/90] make canon and settings use EventEmitter --- plugins/pilot/lib/canon.js | 18 ++++++++---------- plugins/pilot/lib/settings.js | 19 +++++++------------ 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/plugins/pilot/lib/canon.js b/plugins/pilot/lib/canon.js index d9fd2b57..ce822a6b 100644 --- a/plugins/pilot/lib/canon.js +++ b/plugins/pilot/lib/canon.js @@ -39,7 +39,7 @@ define(function(require, exports, module) { var console = require('pilot/console'); var Trace = require('pilot/stacktrace').Trace; -//var Event = require('events').Event; +var MEventEmitter = require("pilot/event_emitter").MEventEmitter; exports.startup = function(data, reason) { if (!data.env || !data.env.settings) { @@ -91,7 +91,7 @@ exports.Canon.prototype = { } }; -// exports.addedRequestOutput = new Event(); +oop.implement(exports, MEventEmitter); /** * Current requirements are around displaying the command line, and provision @@ -130,7 +130,7 @@ exports.addRequestOutput = function(request) { exports.requests.shiftObject(); } - exports.addedRequestOutput(request); + exports.$dispatchEvent('addedRequestOutput', { request: request }); }; /** @@ -189,10 +189,10 @@ exports.Request = function(options) { this.end = null; this.completed = false; this.error = false; - -// this.changed = new Event(); }; +oop.implement(exports.Request.prototype, MEventEmitter); + /** * Lazy init to register with the history should only be done on output. * init() is expensive, and won't be used in the majority of cases @@ -238,7 +238,7 @@ exports.Request.prototype.output = function(content) { } this.outputs.push(content); - this.changed(); + this.$dispatchEvent('changed', {}); return this; }; @@ -254,11 +254,9 @@ exports.Request.prototype.done = function(content) { if (content) { this.output(content); - } else { - this.changed(); } + + this.$dispatchEvent('changed', {}); }; - - }); diff --git a/plugins/pilot/lib/settings.js b/plugins/pilot/lib/settings.js index 9f6af921..94f8bcbd 100644 --- a/plugins/pilot/lib/settings.js +++ b/plugins/pilot/lib/settings.js @@ -43,9 +43,10 @@ define(function(require, exports, module) { -var console = require("util/console"); -var types = require("types"); -var Event = require("events").Event; +var console = require("pilot/console"); +var oop = require("pilot/oop").oop; +var types = require("pilot/types"); +var MEventEmitter = require("pilot/event_emitter").MEventEmitter; exports.startup = function(data, reason) { // TODO add extension point in new style @@ -141,12 +142,6 @@ function Settings(persister) { if (persister) { this.setPersister(persister); } - - /** - * Event that tells people when a setting has changed. - */ - // TODO: Fix events - // this.settingChange = new Event({ keyElement: 0 }); }; Settings.prototype = { @@ -235,9 +230,7 @@ Settings.prototype = { persister.persistValue(this, key, value); } - // Inform subscriptions of the change - // TODO: fix events - // this.settingChange(key, converted); + this.$dispatchEvent('settingChange', { key: key, value: value }); return this; }, @@ -318,6 +311,8 @@ Settings.prototype = { } }; +oop.implement(Settings.prototype, MEventEmitter); + exports.settings = new Settings(new MemoryPersister()); /** From bd2a2bff98915b292389e80099c0dbbae6d6e220 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Tue, 23 Nov 2010 15:46:59 +0000 Subject: [PATCH 35/90] move event_emitter into pilot --- lib/ace/background_tokenizer.js | 2 +- lib/ace/document.js | 2 +- lib/ace/editor.js | 2 +- lib/ace/layer/text.js | 2 +- lib/ace/scrollbar.js | 2 +- lib/ace/selection.js | 2 +- lib/ace/test/event_emitter_test.js | 2 +- lib/ace/virtual_renderer.js | 2 +- {lib/ace => plugins/pilot/lib}/event_emitter.js | 0 9 files changed, 8 insertions(+), 8 deletions(-) rename {lib/ace => plugins/pilot/lib}/event_emitter.js (100%) diff --git a/lib/ace/background_tokenizer.js b/lib/ace/background_tokenizer.js index 642ffb7a..dc064ea5 100644 --- a/lib/ace/background_tokenizer.js +++ b/lib/ace/background_tokenizer.js @@ -38,7 +38,7 @@ define(function(require, exports, module) { var oop = require("pilot/oop").oop; -var MEventEmitter = require("ace/event_emitter").MEventEmitter; +var MEventEmitter = require("pilot/event_emitter").MEventEmitter; var BackgroundTokenizer = function(tokenizer, editor) { this.running = false; diff --git a/lib/ace/document.js b/lib/ace/document.js index 51def67b..62ba15d8 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -39,7 +39,7 @@ define(function(require, exports, module) { var oop = require("pilot/oop").oop; var lang = require("pilot/lang").lang; -var MEventEmitter = require("ace/event_emitter").MEventEmitter; +var MEventEmitter = require("pilot/event_emitter").MEventEmitter; var Selection = require("ace/selection").Selection; var TextMode = require("ace/mode/text").Text; var Range = require("ace/range").Range; diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 4953330c..47ebe733 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -46,7 +46,7 @@ var Document = require("ace/document").Document; var Search = require("ace/search").Search; var BackgroundTokenizer = require("ace/background_tokenizer").BackgroundTokenizer; var Range = require("ace/range").Range; -var MEventEmitter = require("ace/event_emitter").MEventEmitter; +var MEventEmitter = require("pilot/event_emitter").MEventEmitter; var Editor =function(renderer, doc) { var container = renderer.getContainerElement(); diff --git a/lib/ace/layer/text.js b/lib/ace/layer/text.js index 7fef701e..dfa9c0ed 100644 --- a/lib/ace/layer/text.js +++ b/lib/ace/layer/text.js @@ -39,7 +39,7 @@ define(function(require, exports, module) { var oop = require("pilot/oop").oop; var dom = require("pilot/dom").dom; -var MEventEmitter = require("ace/event_emitter").MEventEmitter; +var MEventEmitter = require("pilot/event_emitter").MEventEmitter; var Text = function(parentEl) { this.element = document.createElement("div"); diff --git a/lib/ace/scrollbar.js b/lib/ace/scrollbar.js index 042e2e0c..cc69fd44 100644 --- a/lib/ace/scrollbar.js +++ b/lib/ace/scrollbar.js @@ -41,7 +41,7 @@ var oop = require("pilot/oop").oop; var lang = require("pilot/lang").lang; var dom = require("pilot/dom").dom; var event = require("pilot/event").event; -var MEventEmitter = require("ace/event_emitter").MEventEmitter; +var MEventEmitter = require("pilot/event_emitter").MEventEmitter; var ScrollBar = function(parent) { this.element = document.createElement("div"); diff --git a/lib/ace/selection.js b/lib/ace/selection.js index 062d5077..69f46d79 100644 --- a/lib/ace/selection.js +++ b/lib/ace/selection.js @@ -39,7 +39,7 @@ define(function(require, exports, module) { var oop = require("pilot/oop").oop; var lang = require("pilot/lang").lang; -var MEventEmitter = require("ace/event_emitter").MEventEmitter; +var MEventEmitter = require("pilot/event_emitter").MEventEmitter; var Range = require("ace/range").Range; var Selection = function(doc) { diff --git a/lib/ace/test/event_emitter_test.js b/lib/ace/test/event_emitter_test.js index a5ee56ee..fe83c263 100644 --- a/lib/ace/test/event_emitter_test.js +++ b/lib/ace/test/event_emitter_test.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var MEventEmitter = require("ace/event_emitter").MEventEmitter; +var MEventEmitter = require("pilot/event_emitter").MEventEmitter; var oop = require("pilot/oop").oop; var EventEmitter = function() {}; diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index 2c3e74e7..58b011a8 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -47,7 +47,7 @@ var TextLayer = require("ace/layer/text").Text; var CursorLayer = require("ace/layer/cursor").Cursor; var ScrollBar = require("ace/scrollbar").ScrollBar; var RenderLoop = require("ace/renderloop").RenderLoop; -var MEventEmitter = require("ace/event_emitter").MEventEmitter; +var MEventEmitter = require("pilot/event_emitter").MEventEmitter; var editorCss = require("text!ace/css/editor.css"); // import CSS once diff --git a/lib/ace/event_emitter.js b/plugins/pilot/lib/event_emitter.js similarity index 100% rename from lib/ace/event_emitter.js rename to plugins/pilot/lib/event_emitter.js From 7974ef5a7110d7b7cb78b17bf0739fdf0af9f914 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Tue, 23 Nov 2010 15:49:02 +0000 Subject: [PATCH 36/90] s/MEventEmitter/EventEmitter/g --- lib/ace/background_tokenizer.js | 4 ++-- lib/ace/document.js | 4 ++-- lib/ace/editor.js | 4 ++-- lib/ace/layer/text.js | 4 ++-- lib/ace/scrollbar.js | 4 ++-- lib/ace/selection.js | 4 ++-- lib/ace/test/event_emitter_test.js | 4 ++-- lib/ace/virtual_renderer.js | 4 ++-- plugins/pilot/lib/canon.js | 6 +++--- plugins/pilot/lib/event_emitter.js | 12 ++++++------ plugins/pilot/lib/settings.js | 4 ++-- 11 files changed, 27 insertions(+), 27 deletions(-) diff --git a/lib/ace/background_tokenizer.js b/lib/ace/background_tokenizer.js index dc064ea5..7e1cc2fe 100644 --- a/lib/ace/background_tokenizer.js +++ b/lib/ace/background_tokenizer.js @@ -38,7 +38,7 @@ define(function(require, exports, module) { var oop = require("pilot/oop").oop; -var MEventEmitter = require("pilot/event_emitter").MEventEmitter; +var EventEmitter = require("pilot/event_emitter").EventEmitter; var BackgroundTokenizer = function(tokenizer, editor) { this.running = false; @@ -82,7 +82,7 @@ var BackgroundTokenizer = function(tokenizer, editor) { (function(){ - oop.implement(this, MEventEmitter); + oop.implement(this, EventEmitter); this.setTokenizer = function(tokenizer) { this.tokenizer = tokenizer; diff --git a/lib/ace/document.js b/lib/ace/document.js index 62ba15d8..b2544601 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -39,7 +39,7 @@ define(function(require, exports, module) { var oop = require("pilot/oop").oop; var lang = require("pilot/lang").lang; -var MEventEmitter = require("pilot/event_emitter").MEventEmitter; +var EventEmitter = require("pilot/event_emitter").EventEmitter; var Selection = require("ace/selection").Selection; var TextMode = require("ace/mode/text").Text; var Range = require("ace/range").Range; @@ -65,7 +65,7 @@ var Document = function(text, mode) { (function() { - oop.implement(this, MEventEmitter); + oop.implement(this, EventEmitter); this.$undoManager = null; diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 47ebe733..26bdb04f 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -46,7 +46,7 @@ var Document = require("ace/document").Document; var Search = require("ace/search").Search; var BackgroundTokenizer = require("ace/background_tokenizer").BackgroundTokenizer; var Range = require("ace/range").Range; -var MEventEmitter = require("pilot/event_emitter").MEventEmitter; +var EventEmitter = require("pilot/event_emitter").EventEmitter; var Editor =function(renderer, doc) { var container = renderer.getContainerElement(); @@ -84,7 +84,7 @@ var Editor =function(renderer, doc) { (function(){ - oop.implement(this, MEventEmitter); + oop.implement(this, EventEmitter); this.$forwardEvents = { gutterclick: 1, diff --git a/lib/ace/layer/text.js b/lib/ace/layer/text.js index dfa9c0ed..24727915 100644 --- a/lib/ace/layer/text.js +++ b/lib/ace/layer/text.js @@ -39,7 +39,7 @@ define(function(require, exports, module) { var oop = require("pilot/oop").oop; var dom = require("pilot/dom").dom; -var MEventEmitter = require("pilot/event_emitter").MEventEmitter; +var EventEmitter = require("pilot/event_emitter").EventEmitter; var Text = function(parentEl) { this.element = document.createElement("div"); @@ -52,7 +52,7 @@ var Text = function(parentEl) { (function() { - oop.implement(this, MEventEmitter); + oop.implement(this, EventEmitter); this.EOF_CHAR = "¶"; this.EOL_CHAR = "¬"; diff --git a/lib/ace/scrollbar.js b/lib/ace/scrollbar.js index cc69fd44..019d0ce9 100644 --- a/lib/ace/scrollbar.js +++ b/lib/ace/scrollbar.js @@ -41,7 +41,7 @@ var oop = require("pilot/oop").oop; var lang = require("pilot/lang").lang; var dom = require("pilot/dom").dom; var event = require("pilot/event").event; -var MEventEmitter = require("pilot/event_emitter").MEventEmitter; +var EventEmitter = require("pilot/event_emitter").EventEmitter; var ScrollBar = function(parent) { this.element = document.createElement("div"); @@ -59,7 +59,7 @@ var ScrollBar = function(parent) { }; (function() { - oop.implement(this, MEventEmitter); + oop.implement(this, EventEmitter); this.onScroll = function() { this.$dispatchEvent("scroll", {data: this.element.scrollTop}); diff --git a/lib/ace/selection.js b/lib/ace/selection.js index 69f46d79..849aaad6 100644 --- a/lib/ace/selection.js +++ b/lib/ace/selection.js @@ -39,7 +39,7 @@ define(function(require, exports, module) { var oop = require("pilot/oop").oop; var lang = require("pilot/lang").lang; -var MEventEmitter = require("pilot/event_emitter").MEventEmitter; +var EventEmitter = require("pilot/event_emitter").EventEmitter; var Range = require("ace/range").Range; var Selection = function(doc) { @@ -54,7 +54,7 @@ var Selection = function(doc) { (function() { - oop.implement(this, MEventEmitter); + oop.implement(this, EventEmitter); this.isEmpty = function() { return (!this.selectionAnchor || diff --git a/lib/ace/test/event_emitter_test.js b/lib/ace/test/event_emitter_test.js index fe83c263..2b6329f5 100644 --- a/lib/ace/test/event_emitter_test.js +++ b/lib/ace/test/event_emitter_test.js @@ -37,12 +37,12 @@ define(function(require, exports, module) { -var MEventEmitter = require("pilot/event_emitter").MEventEmitter; +var EventEmitter = require("pilot/event_emitter").EventEmitter; var oop = require("pilot/oop").oop; var EventEmitter = function() {}; -oop.implement(EventEmitter.prototype, MEventEmitter); +oop.implement(EventEmitter.prototype, EventEmitter); var EventEmitterTest = new TestCase("EventEmitterTest", { "test: dispatch event with no data" : function() { diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index 58b011a8..5d28ff0b 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -47,7 +47,7 @@ var TextLayer = require("ace/layer/text").Text; var CursorLayer = require("ace/layer/cursor").Cursor; var ScrollBar = require("ace/scrollbar").ScrollBar; var RenderLoop = require("ace/renderloop").RenderLoop; -var MEventEmitter = require("pilot/event_emitter").MEventEmitter; +var EventEmitter = require("pilot/event_emitter").EventEmitter; var editorCss = require("text!ace/css/editor.css"); // import CSS once @@ -131,7 +131,7 @@ var VirtualRenderer = function(container, theme) { this.CHANGE_SIZE = 64; this.CHANGE_FULL = 128; - oop.implement(this, MEventEmitter); + oop.implement(this, EventEmitter); this.setDocument = function(doc) { this.lines = doc.lines; diff --git a/plugins/pilot/lib/canon.js b/plugins/pilot/lib/canon.js index ce822a6b..7286f8a5 100644 --- a/plugins/pilot/lib/canon.js +++ b/plugins/pilot/lib/canon.js @@ -39,7 +39,7 @@ define(function(require, exports, module) { var console = require('pilot/console'); var Trace = require('pilot/stacktrace').Trace; -var MEventEmitter = require("pilot/event_emitter").MEventEmitter; +var EventEmitter = require("pilot/event_emitter").EventEmitter; exports.startup = function(data, reason) { if (!data.env || !data.env.settings) { @@ -91,7 +91,7 @@ exports.Canon.prototype = { } }; -oop.implement(exports, MEventEmitter); +oop.implement(exports, EventEmitter); /** * Current requirements are around displaying the command line, and provision @@ -191,7 +191,7 @@ exports.Request = function(options) { this.error = false; }; -oop.implement(exports.Request.prototype, MEventEmitter); +oop.implement(exports.Request.prototype, EventEmitter); /** * Lazy init to register with the history should only be done on output. diff --git a/plugins/pilot/lib/event_emitter.js b/plugins/pilot/lib/event_emitter.js index 2ebe0803..8143cf09 100644 --- a/plugins/pilot/lib/event_emitter.js +++ b/plugins/pilot/lib/event_emitter.js @@ -39,9 +39,9 @@ define(function(require, exports, module) { var lang = require("pilot/lang").lang; - var MEventEmitter = {}; + var EventEmitter = {}; - MEventEmitter.$dispatchEvent = function(eventName, e) { + EventEmitter.$dispatchEvent = function(eventName, e) { this.$eventRegistry = this.$eventRegistry || {}; var listeners = this.$eventRegistry[eventName]; @@ -55,8 +55,8 @@ define(function(require, exports, module) { } }; - MEventEmitter.on = - MEventEmitter.addEventListener = function(eventName, callback) { + EventEmitter.on = + EventEmitter.addEventListener = function(eventName, callback) { this.$eventRegistry = this.$eventRegistry || {}; var listeners = this.$eventRegistry[eventName]; @@ -68,7 +68,7 @@ define(function(require, exports, module) { } }; - MEventEmitter.removeEventListener = function(eventName, callback) { + EventEmitter.removeEventListener = function(eventName, callback) { this.$eventRegistry = this.$eventRegistry || {}; var listeners = this.$eventRegistry[eventName]; @@ -81,5 +81,5 @@ define(function(require, exports, module) { } }; - exports.MEventEmitter = MEventEmitter; + exports.EventEmitter = EventEmitter; }); diff --git a/plugins/pilot/lib/settings.js b/plugins/pilot/lib/settings.js index 94f8bcbd..83cfc429 100644 --- a/plugins/pilot/lib/settings.js +++ b/plugins/pilot/lib/settings.js @@ -46,7 +46,7 @@ define(function(require, exports, module) { var console = require("pilot/console"); var oop = require("pilot/oop").oop; var types = require("pilot/types"); -var MEventEmitter = require("pilot/event_emitter").MEventEmitter; +var EventEmitter = require("pilot/event_emitter").EventEmitter; exports.startup = function(data, reason) { // TODO add extension point in new style @@ -311,7 +311,7 @@ Settings.prototype = { } }; -oop.implement(Settings.prototype, MEventEmitter); +oop.implement(Settings.prototype, EventEmitter); exports.settings = new Settings(new MemoryPersister()); From 10843ba7e6a2dd9726eaa7e7c57c2063993b41d5 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Tue, 23 Nov 2010 15:52:44 +0000 Subject: [PATCH 37/90] remove $ function and property from EventEmitter --- lib/ace/background_tokenizer.js | 2 +- lib/ace/document.js | 16 +++---- lib/ace/editor.js | 4 +- lib/ace/layer/text.js | 2 +- lib/ace/scrollbar.js | 2 +- lib/ace/selection.js | 10 ++--- lib/ace/test/event_emitter_test.js | 2 +- lib/ace/virtual_renderer.js | 2 +- plugins/pilot/lib/canon.js | 6 +-- plugins/pilot/lib/event_emitter.js | 71 +++++++++++++++--------------- plugins/pilot/lib/settings.js | 2 +- 11 files changed, 60 insertions(+), 59 deletions(-) diff --git a/lib/ace/background_tokenizer.js b/lib/ace/background_tokenizer.js index 7e1cc2fe..811eeb8d 100644 --- a/lib/ace/background_tokenizer.js +++ b/lib/ace/background_tokenizer.js @@ -103,7 +103,7 @@ var BackgroundTokenizer = function(tokenizer, editor) { first: firstRow, last: lastRow }; - this.$dispatchEvent("update", {data: data}); + this._dispatchEvent("update", {data: data}); }; this.start = function(startRow) { diff --git a/lib/ace/document.js b/lib/ace/document.js index b2544601..20623309 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -94,7 +94,7 @@ var Document = function(text, mode) { firstRow: firstRow, lastRow: lastRow }; - this.$dispatchEvent("change", { data: data}); + this._dispatchEvent("change", { data: data}); }; this.setUndoManager = function(undoManager) { @@ -153,7 +153,7 @@ var Document = function(text, mode) { this.modified = true; this.$tabSize = tabSize; - this.$dispatchEvent("changeTabSize"); + this._dispatchEvent("changeTabSize"); }; this.getTabSize = function() { @@ -169,22 +169,22 @@ var Document = function(text, mode) { for (var i=0; i Date: Tue, 23 Nov 2010 15:54:10 +0000 Subject: [PATCH 38/90] fix startup issue where a require of oop was missing from canon --- plugins/pilot/lib/canon.js | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/pilot/lib/canon.js b/plugins/pilot/lib/canon.js index 22f1ee4c..3bea5b30 100644 --- a/plugins/pilot/lib/canon.js +++ b/plugins/pilot/lib/canon.js @@ -39,6 +39,7 @@ define(function(require, exports, module) { var console = require('pilot/console'); var Trace = require('pilot/stacktrace').Trace; +var oop = require("pilot/oop").oop; var EventEmitter = require("pilot/event_emitter").EventEmitter; exports.startup = function(data, reason) { From cd03bfcda856a9db46dfb6e283d4037e0080b193 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Wed, 24 Nov 2010 10:03:22 +0000 Subject: [PATCH 39/90] minor tidy-up --- plugins/pilot/lib/event.js | 4 ++-- plugins/pilot/lib/proxy.js | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/pilot/lib/event.js b/plugins/pilot/lib/event.js index 033b9136..c2f6be72 100644 --- a/plugins/pilot/lib/event.js +++ b/plugins/pilot/lib/event.js @@ -48,7 +48,7 @@ define(function(require, exports, module) { var wrapper = function() { callback(window.event); }; - callback.$$wrapper = wrapper; + callback._wrapper = wrapper; elem.attachEvent("on" + type, wrapper); } }; @@ -58,7 +58,7 @@ define(function(require, exports, module) { return elem.removeEventListener(type, callback, false); } if (elem.detachEvent) { - elem.detachEvent("on" + type, callback.$$wrapper || callback); + elem.detachEvent("on" + type, callback._wrapper || callback); } }; diff --git a/plugins/pilot/lib/proxy.js b/plugins/pilot/lib/proxy.js index c2675dd0..88d76a54 100644 --- a/plugins/pilot/lib/proxy.js +++ b/plugins/pilot/lib/proxy.js @@ -34,8 +34,9 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ + define(function(require, exports, module) { - + var Promise = require('pilot/promise').Promise; exports.xhr = function(method, url, async, beforeSendCallback) { From 0f6cc173407f3dbcb911d948235bddabab8871b9 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Wed, 24 Nov 2010 14:14:05 +0000 Subject: [PATCH 40/90] hacking startup to setup an environment with settings --- demo/boot.js | 5 +++-- editor.html | 9 +++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/demo/boot.js b/demo/boot.js index d932871e..369d216d 100644 --- a/demo/boot.js +++ b/demo/boot.js @@ -114,12 +114,13 @@ var setupPlugins = function(config, callback) { packagePaths: pluginPackageInfo, paths: paths }); - require(["pilot/plugin_manager"], function() { + require(["pilot/plugin_manager", "pilot/settings"], function() { var pluginsModule = require("pilot/plugin_manager"); + var settings = require("pilot/settings").settings; var catalog = pluginsModule.catalog; catalog.registerPlugins(knownPlugins); if (callback) { - callback(pluginsModule); + callback(pluginsModule, settings); } }); }; diff --git a/editor.html b/editor.html index 3c3ee2c7..70cf92f4 100644 --- a/editor.html +++ b/editor.html @@ -62,8 +62,13 @@ singleFiles: ["demo_startup"] } } - }, function(plugin_manager) { - plugin_manager.catalog.startupPlugins({}, plugin_manager.REASONS.APP_STARTUP).then(function() { + }, function(plugin_manager, settings) { + var data = { + env: { + settings: settings + } + }; + plugin_manager.catalog.startupPlugins(data, plugin_manager.REASONS.APP_STARTUP).then(function() { var demo_startup = require("demo_startup"); demo_startup.launch(); }); From b92164036f335e6be12a62f2290118b8a600cb38 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Wed, 24 Nov 2010 14:14:18 +0000 Subject: [PATCH 41/90] fix startup process, remove Canon object and expose registration functions directly --- plugins/pilot/lib/canon.js | 95 ++++++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 39 deletions(-) diff --git a/plugins/pilot/lib/canon.js b/plugins/pilot/lib/canon.js index 3bea5b30..c9cd67e4 100644 --- a/plugins/pilot/lib/canon.js +++ b/plugins/pilot/lib/canon.js @@ -37,61 +37,78 @@ define(function(require, exports, module) { + var console = require('pilot/console'); var Trace = require('pilot/stacktrace').Trace; var oop = require("pilot/oop").oop; var EventEmitter = require("pilot/event_emitter").EventEmitter; +var catalog = require("pilot/catalog"); + +/* +// TODO: this doesn't belong here - or maybe anywhere? +var dimensionsChangedExtensionSpec = { + name: "dimensionsChanged", + description: "A dimensionsChanged is a way to be notified of " + + "changes to the dimension of Skywriter" +}; +exports.startup = function(data, reason) { + catalog.addExtensionSpec(commandExtensionSpec); +}; +exports.shutdown = function(data, reason) { + catalog.removeExtensionSpec(commandExtensionSpec); +}; +*/ + +var commandExtensionSpec = { + name: "command", + description: "A command is a bit of functionality with optional " + + "typed arguments which can do something small like moving " + + "the cursor around the screen, or large like cloning a " + + "project from VCS.", + indexOn: "name" +}; exports.startup = function(data, reason) { - if (!data.env || !data.env.settings) { - return; - } - var settings = data.env.settings; - // TODO register these using new registration functionality - - // catalog.addExtensionPoint("command", { - // "description": - // "A command is a bit of functionality with optional typed arguments which can do something small like moving the cursor around the screen, or large like cloning a project from VCS.", - // "indexOn": "name" - // }); - // catalog.addExtensionPoint("addedRequestOutput", { - // "description": - // "An extension point to be called whenever a new command begins output." - // }); - // catalog.addExtensionPoint("dimensionsChanged", { - // "description": - // "A dimensionsChanged is a way to be notified of changes to the dimension of Skywriter" - // }); - settings.addSetting({ - "name": "historyLength", - "description": "How many typed commands do we recall for reference?", - "type": "number", - "defaultValue": 50 - }); + catalog.addExtensionSpec(commandExtensionSpec); }; exports.shutdown = function(data, reason) { - var settings = data.env.settings; - settings.removeSetting('historyLength'); + catalog.removeExtensionSpec(commandExtensionSpec); }; -exports.Canon = function() { - this._commands = {}; +/** + * Manage a list of commands in the current canon + */ +var commands = {}; + +exports.addCommand = function(command) { + if (!command.name) { + throw new Error("All registered commands must have a name"); + } + commands[command.name] = command; }; -exports.Canon.prototype = { - addCommand: function(options) { - if (!options.name) { - throw new Error("All registered commands must have a name"); - } - this._commands[name] = options; - }, - - removeCommand: function(name) { - delete this._commands[name]; +exports.removeCommand = function(command) { + if (typeof command === "string") { + delete commands[command]; + } + else { + delete commands[command.name]; } }; +exports.getCommand = function(name) { + return commands[name]; +}; + +exports.getCommands = function() { + return Object.keys(commands); +}; + +/** + * We publish a 'addedRequestOutput' event whenever new command begins output + * TODO: make this more obvious + */ oop.implement(exports, EventEmitter); /** From 98a711fa5107a1214ec92726e25415a787147950 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Wed, 24 Nov 2010 14:14:31 +0000 Subject: [PATCH 42/90] rationalize set|unset commands into a commandSpec and startup|shutdown config --- plugins/pilot/lib/commands/settings.js | 176 +++++++++++++++++-------- plugins/pilot/lib/settings.js | 71 ++-------- 2 files changed, 135 insertions(+), 112 deletions(-) diff --git a/plugins/pilot/lib/commands/settings.js b/plugins/pilot/lib/commands/settings.js index 3f781839..cfc5edd1 100644 --- a/plugins/pilot/lib/commands/settings.js +++ b/plugins/pilot/lib/commands/settings.js @@ -1,13 +1,3 @@ -require.def(['require', 'exports', 'module', - 'skywriter/plugins', - 'settings/environment', - 'settings/settings' -], function(require, exports, module, - plugins, - environment, - settingsMod -) { - /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -45,60 +35,136 @@ require.def(['require', 'exports', 'module', * * ***** END LICENSE BLOCK ***** */ -var catalog = plugins.catalog; -var env = environment.env; - -var settings = settingsMod.settings; +define(function(require, exports, module) { /** - * 'set' command + * Something of a hack to allow the set command to give a clearer definition + * of the type to the command line. */ -exports.setCommand = function(args, request) { - var html; +var valueDeferredType = { + name: "deferred", + undeferType: function(typeSpec, env) { + var assignments = typeSpec.assignments; + var replacement = 'text'; - if (!args.setting) { - var settingsList = settings._list(); - html = ''; - // first sort the settingsList based on the key - settingsList.sort(function(a, b) { - if (a.key < b.key) { - return -1; - } else if (a.key == b.key) { - return 0; - } else { - return 1; + if (assignments) { + // Find the assignment for 'setting' so we can get it's value + var settingAssignment = null; + assignments.forEach(function(assignment) { + if (assignment.param.name === 'setting') { + settingAssignment = assignment; + } + }); + + if (settingAssignment) { + var settingName = settingAssignment.value; + if (settingName && settingName !== '') { + var settingExt = settings[settingName]; + if (settingExt) { + replacement = settingExt.type; + } + } } - }); - - settingsList.forEach(function(setting) { - html += '' + - setting.key + - ' = ' + - setting.value + - '
'; - }); - } else { - if (args.value === undefined) { - html = '' + args.setting + ' = ' + settings.get(args.setting); - } else { - html = 'Setting: ' + args.setting + ' = ' + args.value; - settings.set(args.setting, args.value); } + + return replacement; } - - request.done(html); }; -/** - * 'unset' command - */ -exports.unsetCommand = function(args, request) { - settings.resetValue(args.setting); - request.done('Reset ' + args.setting + ' to default: ' + settings.get(args.setting)); +var setCommandSpec = { + name: "set", + params: [ + { + name: "setting", + type: { + name: "selection", + getOptions: function(env) { + return env.settings.getSettingNames(); + } + }, + description: "The name of the setting to display or alter", + defaultValue: null + }, + { + name: "value", + type: valueDeferredType, + description: "The new value for the chosen setting", + defaultValue: null + } + ], + description: "define and show settings", + exec: function(env, args, request) { + var html; + if (!args.setting) { + var settingsList = env.settings._list(); + html = ''; + // first sort the settingsList based on the key + settingsList.sort(function(a, b) { + if (a.key < b.key) { + return -1; + } else if (a.key == b.key) { + return 0; + } else { + return 1; + } + }); + var url = "https://wiki.mozilla.org/Labs/Skywriter/Settings#" + + setting.key; + settingsList.forEach(function(setting) { + html += '' + + setting.key + + ' = ' + + setting.value + + '
'; + }); + } else { + if (args.value === undefined) { + html = '' + args.setting + ' = ' + + env.settings.get(args.setting); + } else { + html = 'Setting: ' + args.setting + ' = ' + + args.value; + env.settings.set(args.setting, args.value); + } + } + request.done(html); + } }; +var unsetCommandSpec = { + name: "unset", + params: [ + { + name: "setting", + type: { + name: "selection", + pointer: "settings:index#getSettings" + }, + description: "The name of the setting to return to defaults" + } + ], + description: "unset a setting entirely", + exec: function(env, args, request) { + env.settings.resetValue(args.setting); + request.done('Reset ' + args.setting + ' to default: ' + + env.settings.get(args.setting)); + } +}; + +var canon = require('pilot/canon'); + +exports.startup = function(data, reason) { + canon.addCommand(setCommandSpec); + canon.addCommand(unsetCommandSpec); +}; + +exports.shutdown = function(data, reason) { + canon.removeCommand(setCommandSpec); + canon.removeCommand(unsetCommandSpec); +}; + + }); diff --git a/plugins/pilot/lib/settings.js b/plugins/pilot/lib/settings.js index d0d0210b..1f7ed2ea 100644 --- a/plugins/pilot/lib/settings.js +++ b/plugins/pilot/lib/settings.js @@ -37,77 +37,34 @@ * * ***** END LICENSE BLOCK ***** */ +define(function(require, exports, module) { + /** * This plug-in manages settings. */ -define(function(require, exports, module) { - var console = require("pilot/console"); var oop = require("pilot/oop").oop; var types = require("pilot/types"); var EventEmitter = require("pilot/event_emitter").EventEmitter; +var catalog = require("pilot/catalog"); + +var settingExtensionSpec = { + name: "setting", + description: "A setting is something that the application offers as a " + + "way to customize how it works", + register: "env.settings.addSetting", + indexOn: "name" +}; exports.startup = function(data, reason) { - // TODO add extension point in new style - // catalog.addExtensionPoint("setting", { - // "description": - // "A setting is something that the application offers as a way to customize how it works", - // "register": "index#addSetting", - // "indexOn": "name" - // }); - // catalog.addExtensionPoint("settingChange", { - // "description": - // "A settingChange is a way to be notified of changes to a setting" - // }); - - // TODO add commands in new style - // catalog.connect("command", module.id, { - // "name": "set", - // "params": [ - // { - // "name": "setting", - // "type": { - // "name": "selection", - // "pointer": "settings:index#getSettings" - // }, - // "description": "The name of the setting to display or alter", - // "defaultValue": null - // }, - // { - // "name": "value", - // "type": { - // "name": "deferred", - // "pointer": "settings:index#getTypeSpecFromAssignment" - // }, - // "description": "The new value for the chosen setting", - // "defaultValue": null - // } - // ], - // "description": "define and show settings", - // "pointer": "commands#setCommand" - // }); - // catalog.connect("command", module.id, { - // "name": "unset", - // "params": [ - // { - // "name": "setting", - // "type": { - // "name": "selection", - // "pointer": "settings:index#getSettings" - // }, - // "description": "The name of the setting to return to defaults" - // } - // ], - // "description": "unset a setting entirely", - // "pointer": "commands#unsetCommand" - // }); + catalog.addExtensionSpec(settingExtensionSpec); }; exports.shutdown = function(data, reason) { + catalog.removeExtensionSpec(settingExtensionSpec); }; - /** * A base class for all the various methods of storing settings. *

Usage: @@ -313,7 +270,7 @@ Settings.prototype = { oop.implement(Settings.prototype, EventEmitter); -exports.settings = new Settings(new MemoryPersister()); +exports.settings = new Settings(); /** * Save the settings in a cookie From ad335b2ccefe6f96c66f99258d35096468f3b193 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Wed, 24 Nov 2010 14:14:40 +0000 Subject: [PATCH 43/90] add extra modules to startup sequence --- plugins/pilot/lib/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/pilot/lib/index.js b/plugins/pilot/lib/index.js index ecc1df10..1951c9fc 100644 --- a/plugins/pilot/lib/index.js +++ b/plugins/pilot/lib/index.js @@ -38,7 +38,9 @@ var deps = [ "pilot/fixoldbrowsers", "pilot/types/basic", - "pilot/canon" + "pilot/canon", + "pilot/commands/settings", + "pilot/settings/canon" ]; var packages = deps.slice(); From 1772e7eab59df24ae4680e4809a93bf0595b1710 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Wed, 24 Nov 2010 14:21:25 +0000 Subject: [PATCH 44/90] add basic extension catalog --- plugins/pilot/lib/catalog.js | 65 ++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 plugins/pilot/lib/catalog.js diff --git a/plugins/pilot/lib/catalog.js b/plugins/pilot/lib/catalog.js new file mode 100644 index 00000000..5acb69e5 --- /dev/null +++ b/plugins/pilot/lib/catalog.js @@ -0,0 +1,65 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Julian Viereck (jviereck@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + + +var extensionSpecs = {}; + +exports.addExtensionSpec = function(extensionSpec) { + extensionSpecs[extensionSpec.name] = extensionSpec; +}; + +exports.removeExtensionSpec = function(extensionSpec) { + if (typeof extensionSpec === "string") { + delete extensionSpecs[extensionSpec]; + } + else { + delete extensionSpecs[extensionSpec.name]; + } +}; + +exports.getExtensionSpec = function(name) { + return extensionSpecs[name]; +}; + +exports.getExtensionSpecs = function() { + return Object.keys(extensionSpecs); +}; + + +}); From f61550c8620f9989d7ef4ae6cf3476e410923206 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Wed, 24 Nov 2010 14:21:50 +0000 Subject: [PATCH 45/90] adding historyLength setting --- plugins/pilot/lib/settings/canon.js | 57 +++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 plugins/pilot/lib/settings/canon.js diff --git a/plugins/pilot/lib/settings/canon.js b/plugins/pilot/lib/settings/canon.js new file mode 100644 index 00000000..5ad36d50 --- /dev/null +++ b/plugins/pilot/lib/settings/canon.js @@ -0,0 +1,57 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Joe Walker (jwalker@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + + +var historyLengthSetting = { + name: "historyLength", + description: "How many typed commands do we recall for reference?", + type: "number", + defaultValue: 50 +}; + +exports.startup = function(data, reason) { + data.env.settings.addSetting(historyLengthSetting); +}; + +exports.shutdown = function(data, reason) { + data.env.settings.removeSetting(historyLengthSetting); +}; + + +}); From 9ee72169ac26f0b774d0a94a52c830e44caf75aa Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Wed, 24 Nov 2010 15:56:31 +0000 Subject: [PATCH 46/90] more startup hackery to populate the environment --- demo/demo_startup.js | 33 +++++++++++++++++---------------- editor.html | 2 +- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/demo/demo_startup.js b/demo/demo_startup.js index adf0d5cf..8c2ba458 100644 --- a/demo/demo_startup.js +++ b/demo/demo_startup.js @@ -39,7 +39,7 @@ define(function(require, exports, module) { -exports.launch = function() { +exports.launch = function(env) { var event = require("pilot/event").event; var Editor = require("ace/editor").Editor; @@ -69,9 +69,12 @@ exports.launch = function() { var docEl = document.getElementById("doc"); + var container = document.getElementById("editor"); + env.editor = new Editor(new Renderer(container, theme)); + function onDocChange() { var doc = getDoc(); - editor.setDocument(doc); + env.editor.setDocument(doc); var mode = doc.getMode(); if (mode instanceof JavaScriptMode) { @@ -90,7 +93,7 @@ exports.launch = function() { modeEl.value = "text"; } - editor.focus(); + env.editor.focus(); } docEl.onchange = onDocChange; @@ -100,7 +103,7 @@ exports.launch = function() { var modeEl = document.getElementById("mode"); modeEl.onchange = function() { - editor.getDocument().setMode(modes[modeEl.value] || modes.text); + env.editor.getDocument().setMode(modes[modeEl.value] || modes.text); }; var modes = { @@ -117,31 +120,29 @@ exports.launch = function() { var themeEl = document.getElementById("theme"); themeEl.onchange = function() { - editor.setTheme(themeEl.value); + env.editor.setTheme(themeEl.value); }; var selectEl = document.getElementById("select_style"); selectEl.onchange = function() { if (selectEl.checked) { - editor.setSelectionStyle("line"); + env.editor.setSelectionStyle("line"); } else { - editor.setSelectionStyle("text"); + env.editor.setSelectionStyle("text"); } }; var activeEl = document.getElementById("highlight_active"); activeEl.onchange = function() { - editor.setHighlightActiveLine(!!activeEl.checked); + env.editor.setHighlightActiveLine(!!activeEl.checked); }; - var container = document.getElementById("editor"); - var editor = new Editor(new Renderer(container, theme)); onDocChange(); window.jump = function() { var jump = document.getElementById("jump"); - var cursor = editor.getCursorPosition(); - var pos = editor.renderer.textToScreenCoordinates(cursor.row, cursor.column); + var cursor = env.editor.getCursorPosition(); + var pos = env.editor.renderer.textToScreenCoordinates(cursor.row, cursor.column); jump.style.left = pos.pageX + "px"; jump.style.top = pos.pageY + "px"; jump.style.display = "block"; @@ -150,7 +151,7 @@ exports.launch = function() { function onResize() { container.style.width = (document.documentElement.clientWidth - 4) + "px"; container.style.height = (document.documentElement.clientHeight - 55 - 4) + "px"; - editor.resize(); + env.editor.resize(); }; window.onresize = onResize; @@ -170,7 +171,7 @@ exports.launch = function() { if (window.FileReader) { var reader = new FileReader(); reader.onload = function(e) { - editor.getSelection().selectAll(); + env.editor.getSelection().selectAll(); var mode = "text"; if (/^.*\.js$/i.test(file.name)) { @@ -183,10 +184,10 @@ exports.launch = function() { mode = "css"; } - editor.onTextInput(reader.result); + env.editor.onTextInput(reader.result); modeEl.value = mode; - editor.getDocument().setMode(modes[mode]); + env.editor.getDocument().setMode(modes[mode]); }; reader.readAsText(file); } diff --git a/editor.html b/editor.html index 70cf92f4..bedc4d8d 100644 --- a/editor.html +++ b/editor.html @@ -70,7 +70,7 @@ }; plugin_manager.catalog.startupPlugins(data, plugin_manager.REASONS.APP_STARTUP).then(function() { var demo_startup = require("demo_startup"); - demo_startup.launch(); + demo_startup.launch(data.env); }); }); From f6fa5107082e72fd19f14030a49fb030c6a64e9f Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Wed, 24 Nov 2010 15:56:42 +0000 Subject: [PATCH 47/90] beef up the canon for exec commands and the knowledge of the environment --- plugins/pilot/lib/canon.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/plugins/pilot/lib/canon.js b/plugins/pilot/lib/canon.js index c9cd67e4..f5bcee2c 100644 --- a/plugins/pilot/lib/canon.js +++ b/plugins/pilot/lib/canon.js @@ -68,7 +68,11 @@ var commandExtensionSpec = { indexOn: "name" }; +var env; + exports.startup = function(data, reason) { + // TODO: this is probably all kinds of evil, but we need something working + env = data.env; catalog.addExtensionSpec(commandExtensionSpec); }; @@ -105,6 +109,16 @@ exports.getCommands = function() { return Object.keys(commands); }; +exports.exec = function(name) { + var command = commands[name]; + if (command) { + env.selection = env.editor.getSelection(); + command.exec(env); + return true; + } + return false; +}; + /** * We publish a 'addedRequestOutput' event whenever new command begins output * TODO: make this more obvious From efa5909c765d7e12fb787f6d2b53da5d6d117adf Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Wed, 24 Nov 2010 15:56:52 +0000 Subject: [PATCH 48/90] morph ace commands to more closely resemble skywriter commands --- lib/ace/commands/default_commands.js | 259 ++++++++++++++++----------- 1 file changed, 156 insertions(+), 103 deletions(-) diff --git a/lib/ace/commands/default_commands.js b/lib/ace/commands/default_commands.js index 1c813871..4e7d66b1 100644 --- a/lib/ace/commands/default_commands.js +++ b/lib/ace/commands/default_commands.js @@ -37,158 +37,211 @@ define(function(require, exports, module) { -var PluginManager = require("pilot/plugin_manager").PluginManager; +var canon = require("pilot/canon"); -PluginManager.registerCommand("selectall", function(env, args, request) { - env.selection.selectAll(); +canon.addCommand({ + name: "selectall", + exec: function(env, args, request) { env.selection.selectAll(); } }); -PluginManager.registerCommand("removeline", function(env, args, request) { - env.editor.removeLines(); +canon.addCommand({ + name: "removeline", + exec: function(env, args, request) { env.editor.removeLines(); } }); -PluginManager.registerCommand("gotoline", function(env, args, request) { - var line = parseInt(prompt("Enter line number:")); - if (!isNaN(line)) { - env.editor.gotoLine(line); +canon.addCommand({ + name: "gotoline", + exec: function(env, args, request) { + var line = parseInt(prompt("Enter line number:")); + if (!isNaN(line)) { + env.editor.gotoLine(line); + } } }); -PluginManager.registerCommand("togglecomment", function(env, args, request) { - env.editor.toggleCommentLines(); +canon.addCommand({ + name: "togglecomment", + exec: function(env, args, request) { env.editor.toggleCommentLines(); } }); -PluginManager.registerCommand("findnext", function(env, args, request) { - env.editor.findNext(); +canon.addCommand({ + name: "findnext", + exec: function(env, args, request) { env.editor.findNext(); } }); -PluginManager.registerCommand("findprevious", function(env, args, request) { - env.editor.findPrevious(); +canon.addCommand({ + name: "findprevious", + exec: function(env, args, request) { env.editor.findPrevious(); } }); -PluginManager.registerCommand("find", function(env, args, request) { - var needle = prompt("Find:"); - env.editor.find(needle); +canon.addCommand({ + name: "find", + exec: function(env, args, request) { + var needle = prompt("Find:"); + env.editor.find(needle); + } }); -PluginManager.registerCommand("undo", function(env, args, request) { - env.editor.undo(); +canon.addCommand({ + name: "undo", + exec: function(env, args, request) { env.editor.undo(); } }); -PluginManager.registerCommand("redo", function(env, args, request) { - env.editor.redo(); +canon.addCommand({ + name: "redo", + exec: function(env, args, request) { env.editor.redo(); } }); -PluginManager.registerCommand("redo", function(env, args, request) { - env.editor.redo(); +canon.addCommand({ + name: "redo", + exec: function(env, args, request) { env.editor.redo(); } }); -PluginManager.registerCommand("overwrite", function(env, args, request) { - env.editor.toggleOverwrite(); +canon.addCommand({ + name: "overwrite", + exec: function(env, args, request) { env.editor.toggleOverwrite(); } }); -PluginManager.registerCommand("copylinesup", function(env, args, request) { - env.editor.copyLinesUp(); +canon.addCommand({ + name: "copylinesup", + exec: function(env, args, request) { env.editor.copyLinesUp(); } }); -PluginManager.registerCommand("movelinesup", function(env, args, request) { - env.editor.moveLinesUp(); +canon.addCommand({ + name: "movelinesup", + exec: function(env, args, request) { env.editor.moveLinesUp(); } }); -PluginManager.registerCommand("selecttostart", function(env, args, request) { - env.selection.selectFileStart(); +canon.addCommand({ + name: "selecttostart", + exec: function(env, args, request) { env.selection.selectFileStart(); } }); -PluginManager.registerCommand("gotostart", function(env, args, request) { - env.editor.navigateFileStart(); +canon.addCommand({ + name: "gotostart", + exec: function(env, args, request) { env.editor.navigateFileStart(); } }); -PluginManager.registerCommand("selectup", function(env, args, request) { - env.selection.selectUp(); +canon.addCommand({ + name: "selectup", + exec: function(env, args, request) { env.selection.selectUp(); } }); -PluginManager.registerCommand("golineup", function(env, args, request) { - env.editor.navigateUp(); +canon.addCommand({ + name: "golineup", + exec: function(env, args, request) { env.editor.navigateUp(); } }); -PluginManager.registerCommand("copylinesdown", function(env, args, request) { - env.editor.copyLinesDown(); +canon.addCommand({ + name: "copylinesdown", + exec: function(env, args, request) { env.editor.copyLinesDown(); } }); -PluginManager.registerCommand("movelinesdown", function(env, args, request) { - env.editor.moveLinesDown(); +canon.addCommand({ + name: "movelinesdown", + exec: function(env, args, request) { env.editor.moveLinesDown(); } }); -PluginManager.registerCommand("selecttoend", function(env, args, request) { - env.selection.selectFileEnd(); +canon.addCommand({ + name: "selecttoend", + exec: function(env, args, request) { env.selection.selectFileEnd(); } }); -PluginManager.registerCommand("gotoend", function(env, args, request) { - env.editor.navigateFileEnd(); +canon.addCommand({ + name: "gotoend", + exec: function(env, args, request) { env.editor.navigateFileEnd(); } }); -PluginManager.registerCommand("selectdown", function(env, args, request) { - env.selection.selectDown(); +canon.addCommand({ + name: "selectdown", + exec: function(env, args, request) { env.selection.selectDown(); } }); -PluginManager.registerCommand("godown", function(env, args, request) { - env.editor.navigateDown(); +canon.addCommand({ + name: "godown", + exec: function(env, args, request) { env.editor.navigateDown(); } }); -PluginManager.registerCommand("selectwordleft", function(env, args, request) { - env.selection.selectWordLeft(); +canon.addCommand({ + name: "selectwordleft", + exec: function(env, args, request) { env.selection.selectWordLeft(); } }); -PluginManager.registerCommand("gotowordleft", function(env, args, request) { - env.editor.navigateWordLeft(); +canon.addCommand({ + name: "gotowordleft", + exec: function(env, args, request) { env.editor.navigateWordLeft(); } }); -PluginManager.registerCommand("selecttolinestart", function(env, args, request) { - env.selection.selectLineStart(); +canon.addCommand({ + name: "selecttolinestart", + exec: function(env, args, request) { env.selection.selectLineStart(); } }); -PluginManager.registerCommand("gotolinestart", function(env, args, request) { - env.editor.navigateLineStart(); +canon.addCommand({ + name: "gotolinestart", + exec: function(env, args, request) { env.editor.navigateLineStart(); } }); -PluginManager.registerCommand("selectleft", function(env, args, request) { - env.selection.selectLeft(); +canon.addCommand({ + name: "selectleft", + exec: function(env, args, request) { env.selection.selectLeft(); } }); -PluginManager.registerCommand("gotoleft", function(env, args, request) { - env.editor.navigateLeft(); +canon.addCommand({ + name: "gotoleft", + exec: function(env, args, request) { env.editor.navigateLeft(); } }); -PluginManager.registerCommand("selectwordright", function(env, args, request) { - env.selection.selectWordRight(); +canon.addCommand({ + name: "selectwordright", + exec: function(env, args, request) { env.selection.selectWordRight(); } }); -PluginManager.registerCommand("gotowordright", function(env, args, request) { - env.editor.navigateWordRight(); +canon.addCommand({ + name: "gotowordright", + exec: function(env, args, request) { env.editor.navigateWordRight(); } }); -PluginManager.registerCommand("selecttolineend", function(env, args, request) { - env.selection.selectLineEnd(); +canon.addCommand({ + name: "selecttolineend", + exec: function(env, args, request) { env.selection.selectLineEnd(); } }); -PluginManager.registerCommand("gotolineend", function(env, args, request) { - env.editor.navigateLineEnd(); +canon.addCommand({ + name: "gotolineend", + exec: function(env, args, request) { env.editor.navigateLineEnd(); } }); -PluginManager.registerCommand("selectright", function(env, args, request) { - env.selection.selectRight(); +canon.addCommand({ + name: "selectright", + exec: function(env, args, request) { env.selection.selectRight(); } }); -PluginManager.registerCommand("gotoright", function(env, args, request) { - env.editor.navigateRight(); +canon.addCommand({ + name: "gotoright", + exec: function(env, args, request) { env.editor.navigateRight(); } }); -PluginManager.registerCommand("selectpagedown", function(env, args, request) { - env.editor.selectPageDown(); +canon.addCommand({ + name: "selectpagedown", + exec: function(env, args, request) { env.editor.selectPageDown(); } }); -PluginManager.registerCommand("pagedown", function(env, args, request) { - env.editor.scrollPageDown(); +canon.addCommand({ + name: "pagedown", + exec: function(env, args, request) { env.editor.scrollPageDown(); } }); -PluginManager.registerCommand("gotopagedown", function(env, args, request) { - env.editor.gotoPageDown(); +canon.addCommand({ + name: "gotopagedown", + exec: function(env, args, request) { env.editor.gotoPageDown(); } }); -PluginManager.registerCommand("selectpageup", function(env, args, request) { - env.editor.selectPageUp(); +canon.addCommand({ + name: "selectpageup", + exec: function(env, args, request) { env.editor.selectPageUp(); } }); -PluginManager.registerCommand("pageup", function(env, args, request) { - env.editor.scrollPageUp(); +canon.addCommand({ + name: "pageup", + exec: function(env, args, request) { env.editor.scrollPageUp(); } }); -PluginManager.registerCommand("gotopageup", function(env, args, request) { - env.editor.gotoPageUp(); +canon.addCommand({ + name: "gotopageup", + exec: function(env, args, request) { env.editor.gotoPageUp(); } }); -PluginManager.registerCommand("selectlinestart", function(env, args, request) { - env.selection.selectLineStart(); +canon.addCommand({ + name: "selectlinestart", + exec: function(env, args, request) { env.selection.selectLineStart(); } }); -PluginManager.registerCommand("gotolinestart", function(env, args, request) { - env.editor.navigateLineStart(); +canon.addCommand({ + name: "gotolinestart", + exec: function(env, args, request) { env.editor.navigateLineStart(); } }); -PluginManager.registerCommand("selectlineend", function(env, args, request) { - env.selection.selectLineEnd(); +canon.addCommand({ + name: "selectlineend", + exec: function(env, args, request) { env.selection.selectLineEnd(); } }); -PluginManager.registerCommand("gotolineend", function(env, args, request) { - env.editor.navigateLineEnd(); +canon.addCommand({ + name: "gotolineend", + exec: function(env, args, request) { env.editor.navigateLineEnd(); } }); -PluginManager.registerCommand("del", function(env, args, request) { - env.editor.removeRight(); +canon.addCommand({ + name: "del", + exec: function(env, args, request) { env.editor.removeRight(); } }); -PluginManager.registerCommand("backspace", function(env, args, request) { - env.editor.removeLeft(); +canon.addCommand({ + name: "backspace", + exec: function(env, args, request) { env.editor.removeLeft(); } }); -PluginManager.registerCommand("outdent", function(env, args, request) { - env.editor.blockOutdent(); +canon.addCommand({ + name: "outdent", + exec: function(env, args, request) { env.editor.blockOutdent(); } }); -PluginManager.registerCommand("indent", function(env, args, request) { - env.editor.indent(); +canon.addCommand({ + name: "indent", + exec: function(env, args, request) { env.editor.indent(); } }); -}); \ No newline at end of file +}); From a2cca9118e7d87cb44fd4efffb7869a1f9fa2698 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Wed, 24 Nov 2010 15:56:52 +0000 Subject: [PATCH 49/90] make keybindings use the canon --- lib/ace/keybinding.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/ace/keybinding.js b/lib/ace/keybinding.js index 78212755..31df2ee3 100644 --- a/lib/ace/keybinding.js +++ b/lib/ace/keybinding.js @@ -41,7 +41,7 @@ var core = require("pilot/core").core; var event = require("pilot/event").event; var default_mac = require("ace/conf/keybindings/default_mac").bindings; var default_win = require("ace/conf/keybindings/default_win").bindings; -var PluginManager = require("pilot/plugin_manager").PluginManager; +var canon = require("pilot/canon"); require("ace/commands/default_commands"); var KeyBinding = function(element, editor, config) { @@ -55,11 +55,9 @@ var KeyBinding = function(element, editor, config) { var commandName = (_self.config.reverse[hashId] || {})[(key || String.fromCharCode(e.keyCode)).toLowerCase()]; - var command = PluginManager.commands[commandName]; - if (command) { - var env = { editor: editor, selection: editor.getSelection() }; - command(env); + var success = canon.exec(commandName); + if (success) { return event.stopEvent(e); } }); From 7b2bee9d4938928b18420621b207aa6f0cfc96de Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Wed, 24 Nov 2010 15:56:53 +0000 Subject: [PATCH 50/90] remove command support from the plugin manager, and tidy up --- plugins/pilot/lib/plugin_manager.js | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/plugins/pilot/lib/plugin_manager.js b/plugins/pilot/lib/plugin_manager.js index 75fceb61..79b5b4cc 100644 --- a/plugins/pilot/lib/plugin_manager.js +++ b/plugins/pilot/lib/plugin_manager.js @@ -63,7 +63,7 @@ exports.Plugin.prototype = { INSTALLED: 1, STARTED: 2, SHUTDOWN: 3, - + install: function(data, reason) { var pr = new Promise(); if (this.status > this.NEW) { @@ -79,7 +79,7 @@ exports.Plugin.prototype = { }.bind(this)); return pr; }, - + startup: function(data, reason) { var pr = new Promise(); if (this.status != this.INSTALLED) { @@ -95,7 +95,7 @@ exports.Plugin.prototype = { }.bind(this)); return pr; }, - + shutdown: function(data, reason) { if (this.status != this.STARTED) { return; @@ -121,7 +121,7 @@ exports.PluginCatalog.prototype = { } }.bind(this)); }, - + startupPlugins: function(data, reason) { var startupPromises = []; for (var pluginName in this.plugins) { @@ -134,16 +134,4 @@ exports.PluginCatalog.prototype = { exports.catalog = new exports.PluginCatalog(); -// TODO the code below is temporary to bootstrap while setting up the new command system -var PluginManager = { - commands : {}, - - registerCommand : function(name, command) { - this.commands[name] = command; - } -}; - -exports.PluginManager = PluginManager; - - }); From ab25eee135e8d0d54e1d85bc1b4f340f702132fb Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Fri, 26 Nov 2010 12:04:27 +0000 Subject: [PATCH 51/90] Add greatly simplified Requisition and Assignment from old bespin --- plugins/pilot/lib/canon.js | 161 ++++++++++++++++++++++++++++++++++--- 1 file changed, 152 insertions(+), 9 deletions(-) diff --git a/plugins/pilot/lib/canon.js b/plugins/pilot/lib/canon.js index f5bcee2c..15bd8c24 100644 --- a/plugins/pilot/lib/canon.js +++ b/plugins/pilot/lib/canon.js @@ -83,6 +83,24 @@ exports.shutdown = function(data, reason) { /** * Manage a list of commands in the current canon */ + +/** + * A Command is a discrete action optionally with a set of ways to customize + * how it happens. This is here for documentation purposes. + * TODO: Document better + */ +var Command = { + name: "thing", + description: "thing is an example command", + params: [{ + name: "param1", + description: "an example parameter", + type: "text", + defaultValue: null + }], + exec: function(env, args, request) { } +}; + var commands = {}; exports.addCommand = function(command) { @@ -109,22 +127,144 @@ exports.getCommands = function() { return Object.keys(commands); }; -exports.exec = function(name) { +/** + * Entry point for keyboard accelerators or anything else that knows + * everything it needs to about the command params + */ +exports.exec = function(name, args) { var command = commands[name]; if (command) { + // TODO: Ugg. really? env.selection = env.editor.getSelection(); - command.exec(env); + var request = new Request(); + command.exec(env, args || {}, request); return true; } return false; }; +/** + * Entry point for users that need to collect parameters from textual input + */ +exports.execRequisition = function(requisition) { + var request = new Request(); + requisition.command.exec(env, requisition.args, request); +}; + /** * We publish a 'addedRequestOutput' event whenever new command begins output * TODO: make this more obvious */ oop.implement(exports, EventEmitter); +/** + * A Requisition collects the information needed to execute a command. + * There is no point in a requisition for parameter-less commands because there + * is no information to collect. A Requisition is a collection of assignments + * of values to parameters, each handled by an instance of Assignment. + * @constructor + */ +function Requisition(command) { + this.command = command; + this.assignments = {}; + command.params.forEach(function(param) { + this.assignment[param.name] = new Assignment(param); + }); +} +Requisition.prototype = { + /** + * The command that we are about to execute. + * @readonly + */ + command: undefined, + + /** + * The set of values that we are assigning to parameters in the command + * @readonly + */ + assignments: undefined +}; +exports.Requisition = Requisition; + + +/** + * A link between a parameter and the data for that parameter. + * The data for the parameter is available as in the preferred type and in + * the string representation of that type. + *

We also record validity information and cli offset data where applicable. + *

For values, null and undefined have distinct definitions. null means + * that a value has been provided, undefined means that it has not. + * Thus, null is a valid default value, and common because it identifies an + * parameter that is optional. undefined means there is no value from + * the command line. + * TODO: think about this distinction some more, particularly this line: + * ass.setValue(undefined); ass.value -> param.defaultValue?; + * @constructor + */ +function Assignment(param) { + this.param = param; + this.setValue(param.defaultValue); +}; +Assignment.prototype = { + /** + * The parameter that we are assigning to + * @readonly + */ + param: undefined, + + /** + * The current value (i.e. not the string representation) + * @readonly - use setValue() to mutate + */ + value: undefined, + setValue: function(value) { + if (this.value === value) { + return; + } + if (value === undefined) { + value = this.param.defaultValue; + } + this.text = this.param.type.toString(value); + this.value = value; + this.status = Status.VALID; + this.message = ""; + this._dispatchEvent('change', { assignment: this }); + }, + + /** + * The textual representation of the current value + * @readonly - use setValue() to mutate + */ + text: undefined, + setText: function(text) { + if (this.text === text) { + return; + } + var conversion = this.param.type.fromString(text); + this.text = text; + this.value = conversion.value; + this.status = conversion.status; + this.message = conversion.message; + this._dispatchEvent('change', { assignment: this }); + }, + + /** + * Report on the status of the last fromString() conversion. + * @see types.Conversion + */ + status: undefined, + message: undefined, + + /** + * Read-write value which records the offset of this text into a command + * line. This is a convenience provided to the command line, but which + * probably won't be used elsewhere. + */ + offset: undefined +}; +oop.implement(Assignment, EventEmitter); +exports.Assignment = Assignment; + /** * Current requirements are around displaying the command line, and provision * of a 'history' command and cursor up|down navigation of history. @@ -202,8 +342,9 @@ exports.execute = function(args, request) { * typed: typed * }); * + * @constructor */ -exports.Request = function(options) { +function Request(options) { options = options || {}; // Will be used in the keyboard case and the cli case @@ -223,13 +364,13 @@ exports.Request = function(options) { this.error = false; }; -oop.implement(exports.Request.prototype, EventEmitter); +oop.implement(Request.prototype, EventEmitter); /** * Lazy init to register with the history should only be done on output. * init() is expensive, and won't be used in the majority of cases */ -exports.Request.prototype._beginOutput = function() { +Request.prototype._beginOutput = function() { this._begunOutput = true; this.outputs = []; @@ -240,7 +381,7 @@ exports.Request.prototype._beginOutput = function() { * Sugar for: *

request.error = true; request.done(output);
*/ -exports.Request.prototype.doneWithError = function(content) { +Request.prototype.doneWithError = function(content) { this.error = true; this.done(content); }; @@ -249,7 +390,7 @@ exports.Request.prototype.doneWithError = function(content) { * Declares that this function will not be automatically done when * the command exits */ -exports.Request.prototype.async = function() { +Request.prototype.async = function() { if (!this._begunOutput) { this._beginOutput(); } @@ -260,7 +401,7 @@ exports.Request.prototype.async = function() { * @param output Either DOM node, an SproutCore element or something that * can be used in the content of a DIV to create a DOM node. */ -exports.Request.prototype.output = function(content) { +Request.prototype.output = function(content) { if (!this._begunOutput) { this._beginOutput(); } @@ -279,7 +420,7 @@ exports.Request.prototype.output = function(content) { * All commands that do output must call this to indicate that the command * has finished execution. */ -exports.Request.prototype.done = function(content) { +Request.prototype.done = function(content) { this.completed = true; this.end = new Date(); this.duration = this.end.getTime() - this.start.getTime(); @@ -290,5 +431,7 @@ exports.Request.prototype.done = function(content) { this._dispatchEvent('changed', {}); }; +exports.Request = Request; + }); From 022f3b240db9350acd1c5ae289d556fdc1d7a6d4 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Fri, 26 Nov 2010 12:04:34 +0000 Subject: [PATCH 52/90] make fromString return a conversion object. rather than the converted value --- plugins/pilot/lib/types.js | 114 +++++++++++++++------ plugins/pilot/lib/types/basic.js | 164 +++++++++++++++---------------- 2 files changed, 159 insertions(+), 119 deletions(-) diff --git a/plugins/pilot/lib/types.js b/plugins/pilot/lib/types.js index 984d0f75..d98fcaed 100644 --- a/plugins/pilot/lib/types.js +++ b/plugins/pilot/lib/types.js @@ -11,7 +11,7 @@ * for the specific language governing rights and limitations under the * License. * - * The Original Code is Mozilla Skywriter. + * The Original Code is Skywriter. * * The Initial Developer of the Original Code is * Mozilla. @@ -34,8 +34,81 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ + define(function(require, exports, module) { +/** + * Some types can detect validity, that is to say they can distinguish between + * valid and invalid values. + */ +var Status = { + /** + * The conversion process worked without any problem, and the value is + * valid. There are a number of failure states, so the best way to check + * for failure is (x !== Status.VALID) + */ + VALID: 1, + + /** + * The conversion process did not work, the value should be null and a + * reason for failure should have been provided. In addition some completion + * values may be available. + * @see Status.INCOMPLETE + */ + INVALID: 2, + + /** + * The conversion process did not work like Status.INVALID, however it was + * noted that the string provided to 'fromString()' could be VALID by + * the addition of more characters, so the typing may not be actually + * incorrect yet, just unfinished. + * @see Status.INVALID + */ + INCOMPLETE: 3 +}; +exports.Status = Status; + +/** + * The type.fromString() method returns a Conversion to inform the user about + * not only the result of a Conversion but also about what went wrong. + * We could use an exception, and throw if the conversion failed, but that + * seems to violate the idea that exceptions should be exceptional. Typos are + * not. Also in order to store both a status and a message we'd still need + * some sort of exception type... + */ +function Conversion(value, status, message, predictions) { + /** + * The result of the conversion process. Will be null if status != VALID + */ + this.value = value; + + /** + * The status of the conversion. + * @see Status + */ + this.status = status || Status.VALID; + + /** + * A message to go with the conversion. This could be present for any status + * including VALID in the case where we want to note a warning for example. + * I18N: On the one hand this nasty and un-internationalized, however with + * a command line it is hard to know where to start. + */ + this.message = message; + + /** + * A array of strings which are the systems best guess at better inputs than + * the one presented. + * We generally expect there to be about 7 predictions (to match human list + * comprehension ability) however it is valid to provide up to about 20, + * or less. It is the job of the predictor to decide a smart cut-off. + * For example if there are 4 very good matches and 4 very poor ones, + * probably only the 4 very good matches should be presented. + */ + this.predictions = predictions || []; +} +exports.Conversion = Conversion; + /** * Most of our types are 'static' e.g. there is only one type of 'text', however * some types like 'selection' and 'deferred' are customizable. The basic @@ -44,14 +117,7 @@ define(function(require, exports, module) { */ function Type() { }; - Type.prototype = { - /** - * Is the passed value an acceptable instance of this type? - * @return true|false to indicate the validity of value - */ - isValid: function(value) { throw new Error("not implemented"); }, - /** * Convert the given value to a string representation. * Where possible, there should be round-tripping between values and their @@ -63,37 +129,20 @@ Type.prototype = { * Convert the given str to an instance of this type. * Where possible, there should be round-tripping between values and their * string representations. + * @return Conversion */ fromString: function(str) { throw new Error("not implemented"); }, /** * The plug-in system, and other things need to know what this type is - * called. This is called simpleName because this name alone is not - * enough to specify a type. Types like 'selection' and 'deferred' need - * extra data, however this function returns only the name, not the extra - * data. + * called. The name alone is not enough to fully specify a type. Types like + * 'selection' and 'deferred' need extra data, however this function returns + * only the name, not the extra data. + *

In old bespin, equality was based on the name. This may turn out to be + * important in Ace too. */ - name: "unknown" - - // Methods from the original type system that we might need, but not now. - - /** - * All types have a JSON representation used in command parameter - * declarations and settings. This allows access to that representation as - * an object rather than as a string - */ - /* - getTypeSpec: function() { }, - */ - - /** - * 2 typeSpecs are considered equal if their simple names are the same. - */ - /* - equals: function(that) { } - */ + name: undefined }; - exports.Type = Type; /** @@ -142,4 +191,5 @@ exports.getType = function(typeSpec) { } }; + }); diff --git a/plugins/pilot/lib/types/basic.js b/plugins/pilot/lib/types/basic.js index b301f039..f7ad2859 100644 --- a/plugins/pilot/lib/types/basic.js +++ b/plugins/pilot/lib/types/basic.js @@ -39,6 +39,8 @@ define(function(require, exports, module) { var types = require("pilot/types"); +var Type = types.Type; +var Conversion = types.Conversion; /** * These are the basic types that we accept. They are vaguely based on the @@ -55,18 +57,17 @@ var types = require("pilot/types"); /** * 'text' is the default if no type is given. */ -var text = new types.Type(); - -text.isValid = function(value) { - return typeof value == 'string'; -}; +var text = new Type(); text.toString = function(value) { return value; }; text.fromString = function(value) { - return value; + if (typeof value != 'string') { + throw new Error('non-string passed to text.fromString()'); + } + return new Conversion(value); }; text.name = 'text'; @@ -74,23 +75,7 @@ text.name = 'text'; /** * We don't currently plan to distinguish between integers and floats */ -var number = new types.Type(); - -number.isValid = function(value) { - if (isNaN(value)) { - return false; - } - if (value === null) { - return false; - } - if (value === undefined) { - return false; - } - if (value === Infinity) { - return false; - } - return typeof value == 'number';// && !isNaN(value); -}; +var number = new Type(); number.toString = function(value) { if (!value) { @@ -100,52 +85,21 @@ number.toString = function(value) { }; number.fromString = function(value) { - if (!value) { - return null; + if (typeof value != 'string') { + throw new Error('non-string passed to number.fromString()'); } - var reply = parseInt(value, 10); - if (isNaN(reply)) { - throw new Error('Can\'t convert "' + value + '" to a number.'); + + var reply = new Conversion(parseInt(value, 10)); + if (isNaN(reply.value)) { + reply.status = Status.INVALID; + reply.message = 'Can\'t convert "' + value + '" to a number.'; } + return reply; }; number.name = 'number'; -/** - * true/false values - */ -var bool = new types.Type(); - -bool.isValid = function(value) { - return typeof value == 'boolean'; -}; - -bool.toString = function(value) { - return '' + value; -}; - -bool.fromString = function(value) { - if (value === null) { - return null; - } - - if (!value.toLowerCase) { - return !!value; - } - - var lower = value.toLowerCase(); - if (lower == 'true') { - return true; - } else if (lower == 'false') { - return false; - } - - return !!value; -}; - -bool.name = 'bool'; - /** * One of a known set of options */ @@ -153,42 +107,77 @@ function SelectionType(data) { this._data = data; }; -SelectionType.prototype = new types.Type(); - -SelectionType.prototype.isValid = function(value) { - if (typeof value != 'string') { - return false; - } - - if (!this._data) { - console.error('Missing data on selection type extension. Skipping'); - return true; - } - - var data = (typeof(this._data) === "function") ? this._data() : this._data; - - var match = false; - data.forEach(function(option) { - if (value == option) { - match = true; - } - }); - - return match; -}; +SelectionType.prototype = new Type(); SelectionType.prototype.toString = function(value) { return value; }; SelectionType.prototype.fromString = function(value) { - // TODO: should we validate and return null if invalid? - return value; + if (typeof value != 'string') { + throw new Error('non-string passed to fromString()'); + } + if (!this._data) { + throw new Error('Missing data on selection type extension.'); + } + var data = (typeof(this._data) === "function") ? this._data() : this._data; + + var match = false; + var completions = []; + data.forEach(function(option) { + if (value == option) { + match = true; + } + else if (option.indexOf(value) === 0) { + completions.push(option); + } + }); + + if (match) { + return new Conversion(value); + } + else { + var status = completions.length > 0 ? Status.INCOMPLETE : Status.INVALID; + + // TODO: better error message - include options? + // TODO: better completions - we're just using the extensions + return new Conversion(null, + status, + 'Can\'t convert "' + value + '" to a selection.', + completions); + } }; SelectionType.prototype.name = 'selection'; +/** + * true/false values + */ +var bool = new SelectionType([ 'true', 'false' ]); + +bool.toString = function(value) { + return '' + value; +}; + +bool.fromString = function(value) { + var conversion = SelectionType.prototype.fromString(value); + + if (conversion.value === 'true') { + conversion.value = true; + } + if (conversion.value === 'false') { + conversion.value = false; + } + + return conversion; +}; + +bool.name = 'bool'; + +/** + * Registration and de-registration. + */ exports.startup = function() { types.registerType(text); types.registerType(number); @@ -203,4 +192,5 @@ exports.shutdown = function() { types.unregisterType(SelectionType); }; + }); From 3fd894954bf7ee45d71b4d8bfaf7aaba62733788 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Fri, 26 Nov 2010 16:11:40 +0000 Subject: [PATCH 53/90] minor tidy-up --- plugins/pilot/lib/lang.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/pilot/lib/lang.js b/plugins/pilot/lib/lang.js index 01045cfa..f99d7a04 100644 --- a/plugins/pilot/lib/lang.js +++ b/plugins/pilot/lib/lang.js @@ -45,9 +45,9 @@ define(function(require, exports, module) { }; lang.stringRepeat = function (string, count) { - return new Array(count + 1).join(string); - } - + return new Array(count + 1).join(string); + }; + if (Array.prototype.indexOf) { lang.arrayIndexOf = function(array, searchElement) { return array.indexOf(searchElement); From 8dc758dcc1f33107cb5d038f20cfe2fa1cff62a9 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Fri, 26 Nov 2010 16:12:10 +0000 Subject: [PATCH 54/90] ton of work porting input.js from old bespin --- plugins/pilot/lib/canon.js | 17 +- plugins/pilot/lib/cli.js | 466 +++++++++++++++++++++++++++++++++++++ 2 files changed, 480 insertions(+), 3 deletions(-) create mode 100644 plugins/pilot/lib/cli.js diff --git a/plugins/pilot/lib/canon.js b/plugins/pilot/lib/canon.js index 15bd8c24..a68458c6 100644 --- a/plugins/pilot/lib/canon.js +++ b/plugins/pilot/lib/canon.js @@ -123,7 +123,7 @@ exports.getCommand = function(name) { return commands[name]; }; -exports.getCommands = function() { +exports.getCommandNames = function() { return Object.keys(commands); }; @@ -148,7 +148,7 @@ exports.exec = function(name, args) { */ exports.execRequisition = function(requisition) { var request = new Request(); - requisition.command.exec(env, requisition.args, request); + requisition.command.exec(env, requisition.getArgs(), request); }; /** @@ -182,7 +182,18 @@ Requisition.prototype = { * The set of values that we are assigning to parameters in the command * @readonly */ - assignments: undefined + assignments: undefined, + + /** + * + */ + getArgs: function() { + var args = {}; + Object.keys(assignments).forEach(function(name) { + args[name] = getCommand(name); + }); + return args; + } }; exports.Requisition = Requisition; diff --git a/plugins/pilot/lib/cli.js b/plugins/pilot/lib/cli.js new file mode 100644 index 00000000..b47aff0f --- /dev/null +++ b/plugins/pilot/lib/cli.js @@ -0,0 +1,466 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Joe Walker (jwalker@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + + +var console = require('skywriter/console'); +var util = require('pilot/util'); + +var keyboard = require('keyboard/keyboard'); +var Status = require('pilot/canon').Status; +var Requisition = require('pilot/canon').Requisition; + +var typehint = require('command_line/typehint'); + +/** + * The information required to tell the user there is a problem with their + * input. + * TODO: Consider formalizing alternatives + */ +function Hint(status, message, start, end) { + this.status = status; + this.message = message; + this.start = start; + this.end = end; +} +Hint.prototype = { + +}; +exports.Hint = Hint; + + +/** + * An object used during command line parsing to hold the various intermediate + * data steps. + *

The 'output' of the parse is held in 2 objects: input.hints which is an + * array of hints to display to the user. In the future this will become a + * single value. + *

The other output value is input.requisition which gives access to an + * args object for use in executing the final command. + * @param typed {string} The instruction as typed by the user so far + * @param options {object} A list of optional named parameters. Can be any of: + * flags: Flags for us to check against the predicates specified with the + * commands. Defaulted to keyboard.buildFlags({ }); + * if not specified. + * @constructor + */ +function Input(typed, options) { + if (util.none(typed)) { + throw new Error('Input requires something \'typed\' to work on'); + } + this.typed = typed; + this.hints = []; + + options = options || {}; + + // TODO: We were using a default of keyboard.buildFlags({ }); + // I think this allowed us to have commands that only existed in certain + // contexts - i.e. Javascript specific commands. + this.flags = options.flags || {}; + + // Once tokenize() has been called, we have the #typed string cut up into + // #_parts + this._parts = []; + + // Once split has been called we have #_parts split into #_unparsedArgs and + // #_command (if there is a matching command). + this._unparsedArgs = undefined; + + // Once we know what the command is, we can fire up a Requisition + this.requisition = undefined; + + // Assign matches #_unparsedArgs to the params declared by the #_command + // A list of arguments in _command.params order + this._assignments = undefined; + + this._tokenize(); +}; + +/** + * Implementation of Input. + * The majority of the functions in this class are called in sequence by the + * constructor. Their task is to add to hints fill out the requisition. + *

The general sequence is:

    + *
  • _tokenize(): convert _typed into _parts + *
  • _split(): convert _parts into _command and _unparsedArgs + *
  • _assign(): convert _unparsedArgs into _assignments + *
+ */ +Input.prototype = { + /** + * Split up the input taking into account ' and " + */ + _tokenize: function() { + if (!this.typed || this.typed === '') { + // We would like to put some initial help here, but for anyone but + // a complete novice a 'type help' message is very annoying, so we + // need to find a way to only display this message once, or for + // until the user click a 'close' button or similar + this.hints.push(new Hint(Status.INCOMPLETE)); + return; + } + + // replace(/^\s\s*/, '') = trimLeft() + var incoming = this.typed.replace(/^\s\s*/, '').split(/\s+/); + + var nextToken; + while (true) { + nextToken = incoming.shift(); + if (util.none(nextToken)) { + break; + } + if (nextToken[0] == '"' || nextToken[0] == '\'') { + // It's quoting time + var eaten = [ nextToken.substring(1, nextToken.length) ]; + var eataway; + while (true) { + eataway = incoming.shift(); + if (!eataway) { + break; + } + if (eataway[eataway.length - 1] == '"' || + eataway[eataway.length - 1] == '\'') { + // End quoting time + eaten.push(eataway.substring(0, eataway.length - 1)); + break; + } else { + eaten.push(eataway); + } + } + this._parts.push(eaten.join(' ')); + } else { + this._parts.push(nextToken); + } + } + + // Split the command from the args + this._split(); + }, + + /** + * Looks in the canon for a command extension that matches what has been + * typed at the command line. + */ + _split: function() { + this._unparsedArgs = this._parts.slice(); // aka clone() + var initial = this._unparsedArgs.shift(); + var command; + + while (true) { + command = canon.getCommand(initial); + + if (!command) { + // Not found. break with command == null + break; + } + + if (!keyboard.flagsMatch(command.predicates, this.flags)) { + // If the predicates say 'no match' then go LA LA LA + command = null; + break; + } + + if (command.exec) { + // Valid command, break with command valid + break; + } + + // command, but no exec - this must be a sub-command + initial += ' ' + this._unparsedArgs.shift(); + } + + // Do we know what the command is. + if (!command) { + // We don't know what the command is + // TODO: We should probably cache this + var commands = []; + canon.getCommandNames().forEach(function(name) { + var command = canon.getCommand(name); + if (keyboard.flagsMatch(command.predicates, this.flags) && + command.description) { + commands.push(command); + } + }.bind(this)); + + // TODO: make this a hint + var hintSpec = { + param: { + type: { name: 'selection', data: commands }, + description: 'Commands' + }, + value: this.typed + }; + + return; + } + + // The user hasn't started to type any params + if (this._parts.length === 1) { + if (this.typed == command.name || + !command.params || + command.params.length === 0) { + this.hints.push(documentCommand(command, this.typed)); + } + } + + this.requisition = new Requisition(command); + + // Assign input to declared parameters + this._assign(); + }, + + /** + * Work out which arguments are applicable to which parameters. + *

This takes #_command.params and #_unparsedArgs and creates a map of + * param names to 'assignment' objects, which have the following properties: + *

    + *
  • param - The matching parameter. + *
  • index - Zero based index into where the match came from on the input + *
  • value - The matching input + *
+ * The resulting #_assignments member created by this function is a list of + * assignments of arguments in command.params order. + * TODO: _unparsedArgs should be a list of objects that contain the + * following values: name, param (when assigned) and maybe hints? + */ + _assign: function() { + // TODO: something smarter than just assuming that they are all in order + this._assignments = []; + var params = this.requisition.command.params; + var unparsedArgs = this._unparsedArgs; + var message; + + // Create an error if the command does not take parameters, but we have + // been given them ... + if (!params || params.length === 0) { + // No problem if we're passed nothing or an empty something + var argCount = 0; + unparsedArgs.forEach(function(unparsedArg) { + if (unparsedArg.trim() !== '') { + argCount++; + } + }); + + if (argCount !== 0) { + message = this.requisition.command.name + ' does not take any parameters'; + this.hints.push(new Hint(Status.INVALID, message)); + } + + return; + } + + // Special case: if there is only 1 parameter, and that's of type + // text we put all the params into the first param + if (params.length == 1 && params[0].type == 'text') { + // Warning: There is some potential problem here if spaces are + // significant. It might be better to chop the command of the + // start of this.typed? But that's not easy because there could + // be multiple spaces in the command if we're doing sub-commands + this._assignments[0] = { + value: unparsedArgs.length === 0 ? null : unparsedArgs.join(' '), + param: params[0] + }; + } else { + // The normal case where we have to assign params individually + var index = 0; + var used = []; + params.forEach(function(param) { + this._assignParam(param, index++, used); + }.bind(this)); + + // Check there are no params that don't fit + var unparsed = false; + unparsedArgs.forEach(function(unparsedArg) { + if (used.indexOf(unparsedArg) == -1) { + message = 'Parameter \'' + unparsedArg + '\' makes no sense.'; + this.hints.push(new Hint(Status.INVALID, message)); + unparsed = true; + } + }.bind(this)); + + if (unparsed) { + return; + } + } + + // Show a hint for the last parameter + if (this._parts.length > 1) { + var assignment = this._getAssignmentForLastArg(); + + // HACK! deferred types need to have some parameters + // by which to determine which type they should defer to + // so we hack in the assignments so the deferrer can work + assignment.param.type.assignments = this._assignments; + + if (assignment) { + this.hints.push(typehint.getHint(this, assignment)); + } + } + + // Convert input into declared types + this._convertTypes(); + }, + + /** + * Extract a value from the set of inputs for a given param. + * @param param The param that we are providing a value for. This is taken + * from the command meta-data for the command in question. + * @param index The number of the param - i.e. the index of param + * into the original params array. + */ + _assignParam: function(param, index, used) { + var message; + // Look for '--param X' style inputs + for (var i = 0; i < this._unparsedArgs.length; i++) { + var unparsedArg = this._unparsedArgs[i]; + + if ('--' + param.name == unparsedArg) { + used.push(unparsedArg); + // boolean parameters don't have values, they default to false + if (param.type.name === 'boolean') { + this._assignments[index] = { + value: true, + param: param + }; + } else { + if (i + 1 < this._unparsedArgs.length) { + message = 'Missing parameter: ' + param.name; + // Missing value for this param + this.hints.push(new Hint(Status.INCOMPLETE, message)); + } else { + used.push(this._unparsedArgs[i + 1]); + } + } + return; + } + } + + var value = null; + if (this._unparsedArgs.length > index) { + value = this._unparsedArgs[index]; + used.push(this._unparsedArgs[index]); + } + + // null is a valid default value, and common because it identifies an + // parameter that is optional. undefined means there is no value from + // the command line + if (value !== undefined) { + this._assignments[index] = { value: value, param: param }; + } else { + this._assignments[index] = { param: param }; + + if (param.defaultValue === undefined) { + // There is no default, and we've not supplied one so far + message = 'Missing parameter: ' + param.name; + this.hints.push(new Hint(Status.INCOMPLETE, message)); + } + } + } +}; +exports.Input = Input; + +/** + * Provide some documentation for a command. + * TODO: this should return a hint + */ +function documentCommand(cmdExt, typed) { + var docs = []; + docs.push('

' + cmdExt.name + '

'); + docs.push('

Summary

'); + docs.push('

' + cmdExt.description + '

'); + + if (cmdExt.manual) { + docs.push('

Description

'); + docs.push('

' + cmdExt.description + '

'); + } + + if (cmdExt.params && cmdExt.params.length > 0) { + docs.push('

Synopsis

'); + docs.push('
');
+        docs.push(cmdExt.name);
+        var optionalParamCount = 0;
+        cmdExt.params.forEach(function(param) {
+            if (param.defaultValue === undefined) {
+                docs.push(' ');
+                docs.push(param.name);
+                docs.push('');
+            } else if (param.defaultValue === null) {
+                docs.push(' [');
+                docs.push(param.name);
+                docs.push(']');
+            } else {
+                optionalParamCount++;
+            }
+        });
+        if (optionalParamCount > 3) {
+            docs.push(' [options]');
+        } else if (optionalParamCount > 0) {
+            cmdExt.params.forEach(function(param) {
+                if (param.defaultValue) {
+                    docs.push(' [--');
+                    docs.push(param.name);
+                    if (param.type.name === 'boolean') {
+                        docs.push('');
+                    } else {
+                        docs.push(' ' + param.type.name);
+                    }
+                    docs.push(']');
+                }
+            });
+        }
+        docs.push('
'); + + docs.push('

Parameters

'); + cmdExt.params.forEach(function(param) { + docs.push('

' + param.name + '

'); + docs.push('

' + param.description + '

'); + if (param.type.defaultValue) { + docs.push('

Default: ' + param.type.defaultValue + '

'); + } + }); + } + + return { + param: { type: 'text', description: docs.join('') }, + value: typed + }; +}; +exports.documentCommand = documentCommand; + + +}); From ea0b9e3c92d54e33fd17e9bb77e6e48db75d08da Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Wed, 17 Nov 2010 18:24:55 +0100 Subject: [PATCH 55/90] fix default theme --- lib/ace/virtual_renderer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index e117b093..b23afff5 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -616,7 +616,7 @@ var VirtualRenderer = function(container, theme) { this.setTheme = function(theme) { var _self = this; if (!theme || typeof theme == "string") { - theme = theme || "ace/theme/TextMate"; + theme = theme || "ace/theme/textmate"; require([theme], function(theme) { afterLoad(theme); }); From ab016923141d4f6ba3c89cf9a214c5fbc3f065f4 Mon Sep 17 00:00:00 2001 From: feisty Date: Wed, 10 Nov 2010 10:27:10 +0800 Subject: [PATCH 56/90] fixing typo --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index a911bf39..fd9544bc 100644 --- a/Readme.md +++ b/Readme.md @@ -1,4 +1,4 @@ -ACE (Ajax.org Code Ediror) +ACE (Ajax.org Code Editor) ========================== ACE is a standalone code editor written in JavaScript. It can be easily embedded in any web page and JavaScript application. It is currently used as the editor component of the [Cloud9 IDE](http://cloud9ide.com). From 014e5c39f57bdcdcb66eff5a25e100664a5b556c Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Thu, 25 Nov 2010 10:11:50 +0100 Subject: [PATCH 57/90] fix render update when scrolling and text changes happen at the same time --- lib/ace/virtual_renderer.js | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index b23afff5..78aee384 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -355,18 +355,13 @@ var VirtualRenderer = function(container, theme) { // scrolling if (changes & this.CHANGE_SCROLL) { - if (changes & this.CHANGE_TEXT || changes & this.CHANGE_LINES) { - this.$textLayer.scrollLines(this.layerConfig); - this.showGutter && this.$gutterLayer.update(this.layerConfig); - this.$markerLayer.update(this.layerConfig); - this.$cursorLayer.update(this.layerConfig); - } - else { + if (changes & this.CHANGE_TEXT || changes & this.CHANGE_LINES) this.$textLayer.update(this.layerConfig); - this.showGutter && this.$gutterLayer.update(this.layerConfig); - this.$markerLayer.update(this.layerConfig); - this.$cursorLayer.update(this.layerConfig); - } + else + this.$textLayer.scrollLines(this.layerConfig); + this.showGutter && this.$gutterLayer.update(this.layerConfig); + this.$markerLayer.update(this.layerConfig); + this.$cursorLayer.update(this.layerConfig); this.$updateScrollBar(); return; } From abb53c3faa1f46da8e353466934243403c4984a1 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Thu, 25 Nov 2010 12:11:38 +0100 Subject: [PATCH 58/90] fix editor rendering bugs --- lib/ace/layer/text.js | 2 ++ lib/ace/virtual_renderer.js | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/ace/layer/text.js b/lib/ace/layer/text.js index 61c35d0c..d1dfe4bc 100644 --- a/lib/ace/layer/text.js +++ b/lib/ace/layer/text.js @@ -145,6 +145,7 @@ var Text = function(parentEl) { this.updateLines = function(layerConfig, firstRow, lastRow) { this.$computeTabString(); + this.config = layerConfig; var first = Math.max(firstRow, layerConfig.firstRow); var last = Math.min(lastRow, layerConfig.lastRow); @@ -234,6 +235,7 @@ var Text = function(parentEl) { this.update = function(config) { this.$computeTabString(); + this.config = config; var html = []; var _self = this; diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index 78aee384..5c42d185 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -59,14 +59,14 @@ var VirtualRenderer = function(container, theme) { this.setTheme(theme); - this.scroller = document.createElement("div"); - this.scroller.className = "ace_scroller"; - this.container.appendChild(this.scroller); - this.$gutter = document.createElement("div"); this.$gutter.className = "ace_gutter"; this.container.appendChild(this.$gutter); + this.scroller = document.createElement("div"); + this.scroller.className = "ace_scroller"; + this.container.appendChild(this.scroller); + this.content = document.createElement("div"); this.content.style.position = "absolute"; this.scroller.appendChild(this.content); From 215cfbf4bf235844a2ca42f49c6bed9dd69c139f Mon Sep 17 00:00:00 2001 From: Eddy Bruel Date: Wed, 24 Nov 2010 13:27:38 +0100 Subject: [PATCH 59/90] Fixed a bug in single line tabbing that caused the tab length not being taken into account. Added DOM emulation to the unit tests so that they can be run from node. Extended the Mockrenderer for the unit tests. Made the majority of the unit tests work again (barring those for moveLinesUp, see below). Fixed a bug in moveLinesUp that caused an empty line to be inserted. However, this fix causes the editor to break (need to look at this). --- .gitmodules | 9 ++ lib/ace/document.js | 10 +- lib/ace/editor.js | 21 +-- lib/ace/mode/javascript.js | 9 +- lib/ace/test/assertions.js | 30 ++-- lib/ace/test/change_document_test.js | 81 ++++++----- lib/ace/test/document_test.js | 193 ++++++++++++++------------ lib/ace/test/event_emitter_test.js | 23 +-- lib/ace/test/mockrenderer.js | 11 +- lib/ace/test/navigation_test.js | 87 ++++++------ lib/ace/test/range_test.js | 105 +++++++------- lib/ace/test/search_test.js | 119 ++++++++-------- lib/ace/test/selection_test.js | 107 +++++++------- lib/ace/test/text_edit_test.js | 186 +++++++++++++------------ lib/ace/test/virtual_renderer_test.js | 35 ++--- support/async | 1 + support/jsdom | 1 + support/node-htmlparser | 1 + 18 files changed, 555 insertions(+), 474 deletions(-) create mode 160000 support/async create mode 160000 support/jsdom create mode 160000 support/node-htmlparser diff --git a/.gitmodules b/.gitmodules index 0498a164..346eb6aa 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,12 @@ [submodule "support/node-o3-xml"] path = support/node-o3-xml url = git://github.com/ajaxorg/node-o3-xml.git +[submodule "support/async"] + path = support/async + url = git://github.com/fjakobs/async.js.git +[submodule "support/jsdom"] + path = support/jsdom + url = git://github.com/tmpvar/jsdom.git +[submodule "support/node-htmlparser"] + path = support/node-htmlparser + url = git://github.com/tautologistics/node-htmlparser.git diff --git a/lib/ace/document.js b/lib/ace/document.js index 20623309..201431cc 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -45,6 +45,7 @@ var TextMode = require("ace/mode/text").Text; var Range = require("ace/range").Range; var Document = function(text, mode) { + this.modified = true; this.lines = []; this.selection = new Selection(this); @@ -569,9 +570,10 @@ var Document = function(text, mode) { var row = this.getLine(firstRow).substring(0, range.start.column) + this.getLine(lastRow).substring(range.end.column); - this.lines.splice(firstRow, lastRow - firstRow + 1, row); - - + if (row != "") + this.lines.splice(firstRow, lastRow - firstRow + 1, row); + else + this.lines.splice(firstRow, lastRow - firstRow + 1, ""); return range.start; }; @@ -664,7 +666,7 @@ var Document = function(text, mode) { var removed = this.lines.slice(firstRow, lastRow + 1); this.$remove(new Range(firstRow, 0, lastRow + 1, 0)); this.$insertLines(firstRow - 1, removed); - + this.fireChangeEvent(firstRow - 1, lastRow); return -1; }; diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 487857ef..1561d21d 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -427,7 +427,7 @@ var Editor =function(renderer, doc) { var shouldOutdent = _self.mode.checkOutdent(lineState, _self.doc.getLine(cursor.row), text); var line = _self.doc.getLine(cursor.row), lineIndent = _self.mode.getNextLineIndent(lineState, line, _self.doc.getTabString()); - var end = _self.doc.insert(cursor, text); + var end = _self.doc.insert(cursor, text); /* TODO: This shortcut is somehow broken if (!shouldOutdent && line != _self.doc.getLine(row) && text != "\n") { @@ -457,6 +457,7 @@ var Editor =function(renderer, doc) { if (/[^\s]$/.test(line)) minIndent = Math.min(indent, minIndent); } + for (var row = cursor.row + 1; row <= end.row; ++row) { var outdent = minIndent; @@ -602,19 +603,22 @@ var Editor =function(renderer, doc) { if (this.$readOnly) return; - var range = this.getSelectionRange(); + var doc = this.doc, + range = this.getSelectionRange(); if (range.start.row < range.end.row || range.start.column < range.end.column) { - var count = this.doc.indentRows(this.getSelectionRange(), "\t"); + var count = doc.indentRows(this.getSelectionRange(), "\t"); this.selection.shiftSelection(count); } else { var indentString; if (this.doc.getUseSoftTabs()) { - var size = this.doc.getTabSize(), - count = (size - this.getCursorPosition().column % size); + var size = doc.getTabSize(), + position = this.getCursorPosition(), + column = doc.documentToScreenColumn(position.row, position.column), + count = (size - column % size); indentString = lang.stringRepeat(" ", count); } else @@ -623,7 +627,7 @@ var Editor =function(renderer, doc) { } }; - this.blockOutdent = function(indentString) { + this.blockOutdent = function() { if (this.$readOnly) return; @@ -956,13 +960,14 @@ var Editor =function(renderer, doc) { if (options) { this.$search.set(options); } - this.clearSelection(); - this.selection.moveCursorTo(0, 0); var ranges = this.$search.findAll(this.doc); if (!ranges.length) return; + this.clearSelection(); + this.selection.moveCursorTo(0, 0); + for (var i = ranges.length - 1; i >= 0; --i) this.$tryReplace(ranges[i], replacement); if (ranges[0] !== null) diff --git a/lib/ace/mode/javascript.js b/lib/ace/mode/javascript.js index d39bb846..2153f710 100644 --- a/lib/ace/mode/javascript.js +++ b/lib/ace/mode/javascript.js @@ -91,7 +91,7 @@ oop.inherits(JavaScript, TextMode); if (tokens.length && tokens[tokens.length-1].type == "comment") { return indent; } - + if (state == "start") { var match = line.match(/^.*[\{\(\[]\s*$/); if (match) { @@ -107,7 +107,12 @@ oop.inherits(JavaScript, TextMode); indent += " "; } indent += "* "; - } + }{ + if (match[1]) { + indent += " "; + } + indent += "* "; + } } return indent; diff --git a/lib/ace/test/assertions.js b/lib/ace/test/assertions.js index 9e9d18cc..1bccf3da 100644 --- a/lib/ace/test/assertions.js +++ b/lib/ace/test/assertions.js @@ -35,20 +35,32 @@ * * ***** END LICENSE BLOCK ***** */ -require.def([], function() { +define(function(require, exports, module) { -window.assertPosition = function(row, column, cursor) { - assertEquals(row, cursor.row); - assertEquals(column, cursor.column); +var assert = require("assert"); + +assert.position = function(cursor, row, column) { + assert.equal(cursor.row, row); + assert.equal(cursor.column, column); }; -window.assertRange = function(startRow, startColumn, endRow, endColumn, range) { - assertPosition(startRow, startColumn, range.start); - assertPosition(endRow, endColumn, range.end); +assert.range = function(range, startRow, startColumn, endRow, endColumn) { + assert.position(range.start, startRow, startColumn); + assert.position(range.end, endRow, endColumn); }; -window.assertJsonEquals = function(expectedJson, foundJson) { - assertEquals(JSON.stringify(expectedJson), JSON.stringify(foundJson)); +assert.true = function(value) { + assert.equal(value, true); +} + +assert.false = function(value) { + assert.equal(value, false); +} + +exports.jsonEquals = function(foundJson, expectedJson) { + assert.equal(JSON.stringify(foundJson), JSON.stringify(expectedJson)); }; +module.exports = assert; + }); \ No newline at end of file diff --git a/lib/ace/test/change_document_test.js b/lib/ace/test/change_document_test.js index 6b5c7f63..90ca741f 100644 --- a/lib/ace/test/change_document_test.js +++ b/lib/ace/test/change_document_test.js @@ -35,23 +35,25 @@ * * ***** END LICENSE BLOCK ***** */ -require.def([ - "ace/Document", - "ace/Editor", - "ace/mode/Text", - "ace/mode/JavaScript", - "ace/test/MockRenderer" - ], function( - Document, - Editor, - textMod, - jsMod, - MockRenderer - ) { +require("../../../support/paths"); -var TextMode = textMod.Text; -var JavaScriptMode = jsMod.JavaScript; -var ChangeDocumentTest = new TestCase("ChangeDocumentTest", { +var dom = require('jsdom/level2/html').dom.level2.html; +var browser = require('jsdom/browser/index').windowAugmentation(dom); + +global.document = browser.document; +global.window = browser.window; +global.self = browser.self; +global.navigator = browser.navigator; +global.location = browser.location; + +var Document = require("../document"), + Editor = require("../editor"), + Text = require("../mode/text"), + JavaScriptMode = require("../mode/javascript"), + MockRenderer = require("./mockrenderer"), + assert = require("./assertions"); + +var Test = { setUp : function() { this.doc1 = new Document(["abc", "def"].join("\n")); this.doc2 = new Document(["ghi", "jkl"].join("\n")); @@ -60,10 +62,10 @@ var ChangeDocumentTest = new TestCase("ChangeDocumentTest", { "test: change document" : function() { this.editor.setDocument(this.doc1); - assertEquals(this.doc1, this.editor.getDocument()); + assert.equal(this.editor.getDocument(), this.doc1); this.editor.setDocument(this.doc2); - assertEquals(this.doc2, this.editor.getDocument()); + assert.equal(this.editor.getDocument(), this.doc2); }, "test: only changes to the new document should have effect" : function() { @@ -76,10 +78,10 @@ var ChangeDocumentTest = new TestCase("ChangeDocumentTest", { this.editor.setDocument(this.doc2); this.doc1.duplicateLines(0, 0); - assertFalse(called); + assert.false(called); this.doc2.duplicateLines(0, 0); - assertTrue(called); + assert.true(called); }, "test: should use cursor of new document" : function() { @@ -87,10 +89,10 @@ var ChangeDocumentTest = new TestCase("ChangeDocumentTest", { this.doc2.getSelection().moveCursorTo(1, 0); this.editor.setDocument(this.doc1); - assertPosition(0, 1, this.editor.getCursorPosition()); + assert.position(this.editor.getCursorPosition(), 0, 1); this.editor.setDocument(this.doc2); - assertPosition(1, 0, this.editor.getCursorPosition()); + assert.position(this.editor.getCursorPosition(), 1, 0); }, "test: only changing the cursor of the new doc should not have an effect" : function() { @@ -100,16 +102,16 @@ var ChangeDocumentTest = new TestCase("ChangeDocumentTest", { this.editor.setDocument(this.doc1); this.editor.setDocument(this.doc2); - assertPosition(0, 0, this.editor.getCursorPosition()); + assert.position(this.editor.getCursorPosition(), 0, 0); var called = false; this.doc1.getSelection().moveCursorTo(0, 1); - assertPosition(0, 0, this.editor.getCursorPosition()); - assertFalse(called); + assert.position(this.editor.getCursorPosition(), 0, 0); + assert.false(called); this.doc2.getSelection().moveCursorTo(1, 1); - assertPosition(1, 1, this.editor.getCursorPosition()); - assertTrue(called); + assert.position(this.editor.getCursorPosition(), 1, 1); + assert.true(called); }, "test: should use selection of new document" : function() { @@ -117,10 +119,10 @@ var ChangeDocumentTest = new TestCase("ChangeDocumentTest", { this.doc2.getSelection().selectTo(1, 0); this.editor.setDocument(this.doc1); - assertPosition(0, 1, this.editor.getSelection().getSelectionLead()); + assert.position(this.editor.getSelection().getSelectionLead(), 0, 1); this.editor.setDocument(this.doc2); - assertPosition(1, 0, this.editor.getSelection().getSelectionLead()); + assert.position(this.editor.getSelection().getSelectionLead(), 1, 0); }, "test: only changing the selection of the new doc should not have an effect" : function() { @@ -130,16 +132,16 @@ var ChangeDocumentTest = new TestCase("ChangeDocumentTest", { this.editor.setDocument(this.doc1); this.editor.setDocument(this.doc2); - assertPosition(0, 0, this.editor.getSelection().getSelectionLead()); + assert.position(this.editor.getSelection().getSelectionLead(), 0, 0); var called = false; this.doc1.getSelection().selectTo(0, 1); - assertPosition(0, 0, this.editor.getSelection().getSelectionLead()); - assertFalse(called); + assert.position(this.editor.getSelection().getSelectionLead(), 0, 0); + assert.false(called); this.doc2.getSelection().selectTo(1, 1); - assertPosition(1, 1, this.editor.getSelection().getSelectionLead()); - assertTrue(called); + assert.position(this.editor.getSelection().getSelectionLead(), 1, 1); + assert.true(called); }, "test: should use mode of new document" : function() { @@ -151,11 +153,14 @@ var ChangeDocumentTest = new TestCase("ChangeDocumentTest", { var called = false; this.doc1.setMode(new Text()); - assertFalse(called); + assert.false(called); this.doc2.setMode(new JavaScriptMode()); - assertTrue(called); + assert.true(called); } -}); +}; -}); \ No newline at end of file +module.exports = require("async/test").testcase(Test); + +if (module === require.main) + module.exports.exec() diff --git a/lib/ace/test/document_test.js b/lib/ace/test/document_test.js index 394c1929..6ae725da 100644 --- a/lib/ace/test/document_test.js +++ b/lib/ace/test/document_test.js @@ -35,229 +35,240 @@ * * ***** END LICENSE BLOCK ***** */ -require.def([ - "ace/Document", - "ace/UndoManager", - "ace/Editor", - "ace/test/MockRenderer" - ], function( - Document, - UndoManager, - Editor, - MockRenderer - ) { +require("../../../support/paths"); -var TextDocumentTest = new TestCase("TextDocumentTest", { +var Document = require("../document"), + UndoManager = require("../undomanager"), + //Editor = require("../editor"), + MockRenderer = require("./mockrenderer"), + Range = require("../range"), + assert = require("./assertions"), + async = require("async"); + +var Test = { "test: find matching opening bracket" : function() { var doc = new Document(["(()(", "())))"]); - assertPosition(0, 1, doc.findMatchingBracket({row: 0, column: 3})); - assertPosition(1, 0, doc.findMatchingBracket({row: 1, column: 2})); - assertPosition(0, 3, doc.findMatchingBracket({row: 1, column: 3})); - assertPosition(0, 0, doc.findMatchingBracket({row: 1, column: 4})); - assertEquals(null, doc.findMatchingBracket({row: 1, column: 5})); + assert.position(doc.findMatchingBracket({row: 0, column: 3}), 0, 1); + assert.position(doc.findMatchingBracket({row: 1, column: 2}), 1, 0); + assert.position(doc.findMatchingBracket({row: 1, column: 3}), 0, 3); + assert.position(doc.findMatchingBracket({row: 1, column: 4}), 0, 0); + assert.equal(doc.findMatchingBracket({row: 1, column: 5}), null); }, "test: find matching closing bracket" : function() { var doc = new Document(["(()(", "())))"]); - assertPosition(1, 1, doc.findMatchingBracket({row: 1, column: 1})); - assertPosition(1, 1, doc.findMatchingBracket({row: 1, column: 1})); - assertPosition(1, 2, doc.findMatchingBracket({row: 0, column: 4})); - assertPosition(0, 2, doc.findMatchingBracket({row: 0, column: 2})); - assertPosition(1, 3, doc.findMatchingBracket({row: 0, column: 1})); - assertEquals(null, doc.findMatchingBracket({row: 0, column: 0})); + assert.position(doc.findMatchingBracket({row: 1, column: 1}), 1, 1); + assert.position(doc.findMatchingBracket({row: 1, column: 1}), 1, 1); + assert.position(doc.findMatchingBracket({row: 0, column: 4}), 1, 2); + assert.position(doc.findMatchingBracket({row: 0, column: 2}), 0, 2); + assert.position(doc.findMatchingBracket({row: 0, column: 1}), 1, 3); + assert.equal(doc.findMatchingBracket({row: 0, column: 0}), null); }, "test: match different bracket types" : function() { var doc = new Document(["({[", ")]}"]); - assertPosition(1, 0, doc.findMatchingBracket({row: 0, column: 1})); - assertPosition(1, 2, doc.findMatchingBracket({row: 0, column: 2})); - assertPosition(1, 1, doc.findMatchingBracket({row: 0, column: 3})); + assert.position(doc.findMatchingBracket({row: 0, column: 1}), 1, 0); + assert.position(doc.findMatchingBracket({row: 0, column: 2}), 1, 2); + assert.position(doc.findMatchingBracket({row: 0, column: 3}), 1, 1); - assertPosition(0, 0, doc.findMatchingBracket({row: 1, column: 1})); - assertPosition(0, 2, doc.findMatchingBracket({row: 1, column: 2})); - assertPosition(0, 1, doc.findMatchingBracket({row: 1, column: 3})); + assert.position(doc.findMatchingBracket({row: 1, column: 1}), 0, 0); + assert.position(doc.findMatchingBracket({row: 1, column: 2}), 0, 2); + assert.position(doc.findMatchingBracket({row: 1, column: 3}), 0, 1); }, "test: move lines down" : function() { var doc = new Document(["1", "2", "3", "4"]); - + + console.log(doc.toString().replace(/\n/g, "\\n")); doc.moveLinesDown(0, 1); - assertEquals(["3", "1", "2", "4"].join("\n"), doc.toString()); - + console.log(doc.toString().replace(/\n/g, "\\n")); + assert.equal(doc.toString(), ["3", "1", "2", "4"].join("\n")); + doc.moveLinesDown(1, 2); - assertEquals(["3", "4", "1", "2"].join("\n"), doc.toString()); - + assert.equal(doc.toString(), ["3", "4", "1", "2"].join("\n")); + doc.moveLinesDown(2, 3); - assertEquals(["3", "4", "1", "2"].join("\n"), doc.toString()); - + assert.equal(doc.toString(), ["3", "4", "1", "2"].join("\n")); + doc.moveLinesDown(2, 2); - assertEquals(["3", "4", "2", "1"].join("\n"), doc.toString()); + assert.equal(doc.toString(), ["3", "4", "2", "1"].join("\n")); }, - "test: move lines up" : function() { + "__test: move lines up" : function() { var doc = new Document(["1", "2", "3", "4"]); + console.log(doc.toString().replace(/\n/g, "\\n")); doc.moveLinesUp(2, 3); - assertEquals(["1", "3", "4", "2"].join("\n"), doc.toString()); - + console.log(doc.toString().replace(/\n/g, "\\n")); + assert.equal(doc.toString(), ["1", "3", "4", "2"].join("\n")); + doc.moveLinesUp(1, 2); - assertEquals(["3", "4", "1", "2"].join("\n"), doc.toString()); - + assert.equal(doc.toString(), ["3", "4", "1", "2"].join("\n")); + doc.moveLinesUp(0, 1); - assertEquals(["3", "4", "1", "2"].join("\n"), doc.toString()); - + assert.equal(doc.toString(), ["3", "4", "1", "2"].join("\n")); + doc.moveLinesUp(2, 2); - assertEquals(["3", "1", "4", "2"].join("\n"), doc.toString()); + assert.equal(doc.toString(), ["3", "1", "4", "2"].join("\n")); }, "test: duplicate lines" : function() { var doc = new Document(["1", "2", "3", "4"]); doc.duplicateLines(1, 2); - assertEquals(["1", "2", "3", "2", "3", "4"].join("\n"), doc.toString()); + assert.equal(doc.toString(), ["1", "2", "3", "2", "3", "4"].join("\n")); }, "test: duplicate last line" : function() { var doc = new Document(["1", "2", "3"]); doc.duplicateLines(2, 2); - assertEquals(["1", "2", "3", "3"].join("\n"), doc.toString()); + assert.equal(doc.toString(), ["1", "2", "3", "3"].join("\n")); }, "test: duplicate first line" : function() { var doc = new Document(["1", "2", "3"]); doc.duplicateLines(0, 0); - assertEquals(["1", "1", "2", "3"].join("\n"), doc.toString()); + assert.equal(doc.toString(), ["1", "1", "2", "3"].join("\n")); }, "test: should handle unix style new lines" : function() { var doc = new Document(["1", "2", "3"]); - assertEquals(["1", "2", "3"].join("\n"), doc.toString()); + + assert.equal(doc.toString(), ["1", "2", "3"].join("\n")); }, "test: should handle windows style new lines" : function() { var doc = new Document(["1", "2", "3"].join("\r\n")); + doc.setNewLineMode("unix"); - assertEquals(["1", "2", "3"].join("\n"), doc.toString()); + assert.equal(doc.toString(), ["1", "2", "3"].join("\n")); }, "test: set new line mode to 'windows' should use '\r\n' as new lines": function() { var doc = new Document(["1", "2", "3"].join("\n")); doc.setNewLineMode("windows"); - assertEquals(["1", "2", "3"].join("\r\n"), doc.toString()); + assert.equal(doc.toString(), ["1", "2", "3"].join("\r\n")); }, "test: set new line mode to 'unix' should use '\n' as new lines": function() { var doc = new Document(["1", "2", "3"].join("\r\n")); + doc.setNewLineMode("unix"); - assertEquals(["1", "2", "3"].join("\n"), doc.toString()); + assert.equal(doc.toString(), ["1", "2", "3"].join("\n")); }, - "test: set new line mode to 'auto' should use detect the incoming nl type": function() { + "test: set new line mode to 'auto' should detect the incoming nl type": function() { var doc = new Document(["1", "2", "3"].join("\n")); + doc.setNewLineMode("auto"); - assertEquals(["1", "2", "3"].join("\n"), doc.toString()); + assert.equal(doc.toString(), ["1", "2", "3"].join("\n")); var doc = new Document(["1", "2", "3"].join("\r\n")); + doc.setNewLineMode("auto"); - assertEquals(["1", "2", "3"].join("\r\n"), doc.toString()); + assert.equal(doc.toString(), ["1", "2", "3"].join("\r\n")); doc.replace(new Range(0, 0, 2, 1), ["4", "5", "6"].join("\n")); - assertEquals(["4", "5", "6"].join("\n"), doc.toString()); + assert.equal(["4", "5", "6"].join("\n"), doc.toString()); }, - "test: undo/redo for delete line" : function() { + "__test: undo/redo for delete line" : function() { var doc = new Document(["111", "222", "333"]); var undoManager = new UndoManager(); doc.setUndoManager(undoManager); var initialText = doc.toString(); + var editor = new Editor(new MockRenderer(), doc); editor.removeLines(); var step1 = doc.toString(); - assertEquals("222\n333", step1); + assert.equal(step1, "222\n333"); doc.$informUndoManager.call(); editor.removeLines(); var step2 = doc.toString(); - assertEquals("333", step2); + assert.equal(step2, "333"); doc.$informUndoManager.call(); editor.removeLines(); var step3 = doc.toString(); - assertEquals("", step3); + assert.equal(step3, ""); doc.$informUndoManager.call(); undoManager.undo(); doc.$informUndoManager.call(); - assertEquals(step2, doc.toString()); + assert.equal(doc.toString(), step2); undoManager.undo(); doc.$informUndoManager.call(); - assertEquals(step1, doc.toString()); + assert.equal(doc.toString(), step1); undoManager.undo(); doc.$informUndoManager.call(); - assertEquals(initialText, doc.toString()); + assert.equal(doc.toString(), initialText); undoManager.undo(); doc.$informUndoManager.call(); - assertEquals(initialText, doc.toString()); + assert.equal(doc.toString(), initialText); }, "test: convert document to screen coordinates" : function() { var doc = new Document("01234\t567890\t1234"); doc.setTabSize(4); - assertEquals(0, doc.documentToScreenColumn(0, 0)); - assertEquals(4, doc.documentToScreenColumn(0, 4)); - assertEquals(5, doc.documentToScreenColumn(0, 5)); - assertEquals(9, doc.documentToScreenColumn(0, 6)); - assertEquals(15, doc.documentToScreenColumn(0, 12)); - assertEquals(19, doc.documentToScreenColumn(0, 13)); + assert.equal(doc.documentToScreenColumn(0, 0), 0); + assert.equal(doc.documentToScreenColumn(0, 4), 4); + assert.equal(doc.documentToScreenColumn(0, 5), 5); + assert.equal(doc.documentToScreenColumn(0, 6), 9); + assert.equal(doc.documentToScreenColumn(0, 12), 15); + assert.equal(doc.documentToScreenColumn(0, 13), 19); doc.setTabSize(2); - assertEquals(0, doc.documentToScreenColumn(0, 0)); - assertEquals(4, doc.documentToScreenColumn(0, 4)); - assertEquals(5, doc.documentToScreenColumn(0, 5)); - assertEquals(7, doc.documentToScreenColumn(0, 6)); - assertEquals(13, doc.documentToScreenColumn(0, 12)); - assertEquals(15, doc.documentToScreenColumn(0, 13)); + assert.equal(doc.documentToScreenColumn(0, 0), 0); + assert.equal(doc.documentToScreenColumn(0, 4), 4); + assert.equal(doc.documentToScreenColumn(0, 5), 5); + assert.equal(doc.documentToScreenColumn(0, 6), 7); + assert.equal(doc.documentToScreenColumn(0, 12), 13); + assert.equal(doc.documentToScreenColumn(0, 13), 15); }, "test: convert document to scrren coordinates with leading tabs": function() { var doc = new Document("\t\t123"); doc.setTabSize(4); - assertEquals(0, doc.documentToScreenColumn(0, 0)); - assertEquals(4, doc.documentToScreenColumn(0, 1)); - assertEquals(8, doc.documentToScreenColumn(0, 2)); - assertEquals(9, doc.documentToScreenColumn(0, 3)); + assert.equal(doc.documentToScreenColumn(0, 0), 0); + assert.equal(doc.documentToScreenColumn(0, 1), 4); + assert.equal(doc.documentToScreenColumn(0, 2), 8); + assert.equal(doc.documentToScreenColumn(0, 3), 9); }, "test: convert screen to document coordinates" : function() { var doc = new Document("01234\t567890\t1234"); doc.setTabSize(4); - assertEquals(0, doc.screenToDocumentColumn(0, 0)); - assertEquals(4, doc.screenToDocumentColumn(0, 4)); - assertEquals(5, doc.screenToDocumentColumn(0, 5)); - assertEquals(5, doc.screenToDocumentColumn(0, 6)); - assertEquals(5, doc.screenToDocumentColumn(0, 7)); - assertEquals(5, doc.screenToDocumentColumn(0, 8)); - assertEquals(6, doc.screenToDocumentColumn(0, 9)); - assertEquals(12, doc.screenToDocumentColumn(0, 15)); - assertEquals(13, doc.screenToDocumentColumn(0, 19)); + assert.equal(doc.screenToDocumentColumn(0, 0), 0); + assert.equal(doc.screenToDocumentColumn(0, 4), 4); + assert.equal(doc.screenToDocumentColumn(0, 5), 5); + assert.equal(doc.screenToDocumentColumn(0, 6), 5); + assert.equal(doc.screenToDocumentColumn(0, 7), 5); + assert.equal(doc.screenToDocumentColumn(0, 8), 5); + assert.equal(doc.screenToDocumentColumn(0, 9), 6); + assert.equal(doc.screenToDocumentColumn(0, 15), 12); + assert.equal(doc.screenToDocumentColumn(0, 19), 13); } -}); +}; -}); \ No newline at end of file +module.exports = require("async/test").testcase(Test) + +if (module === require.main) + module.exports.exec() diff --git a/lib/ace/test/event_emitter_test.js b/lib/ace/test/event_emitter_test.js index 460b23f7..e140d15b 100644 --- a/lib/ace/test/event_emitter_test.js +++ b/lib/ace/test/event_emitter_test.js @@ -35,28 +35,33 @@ * * ***** END LICENSE BLOCK ***** */ -define(function(require, exports, module) { +require("../../../support/paths"); + +var oop = require("../lib/oop"); + MEventEmitter = require("../event_emitter"), + assert = require("./assertions"); -var EventEmitter = require("pilot/event_emitter").EventEmitter; -var oop = require("pilot/oop").oop; var EventEmitter = function() {}; oop.implement(EventEmitter.prototype, EventEmitter); -var EventEmitterTest = new TestCase("EventEmitterTest", { +var Test = { "test: dispatch event with no data" : function() { var emitter = new EventEmitter(); var called = false; emitter.addEventListener("juhu", function(e) { called = true; - assertEquals("juhu", e.type); + assert.equal(e.type, "juhu"); }); - emitter._dispatchEvent("juhu"); - assertTrue(called); + emitter.$dispatchEvent("juhu"); + assert.true(called); } -}); +}; -}); \ No newline at end of file +module.exports = require("async/test").testcase(Test) + +if (module === require.main) + module.exports.exec() diff --git a/lib/ace/test/mockrenderer.js b/lib/ace/test/mockrenderer.js index 69b1f79e..6a3f51a1 100644 --- a/lib/ace/test/mockrenderer.js +++ b/lib/ace/test/mockrenderer.js @@ -35,7 +35,7 @@ * * ***** END LICENSE BLOCK ***** */ -require.def([], function() { +define(function(require, exports, module) { MockRenderer = function(visibleRowCount) { this.container = document.createElement("div"); @@ -113,5 +113,14 @@ MockRenderer.prototype.addMarker = function() { MockRenderer.prototype.setBreakpoints = function() { }; +MockRenderer.prototype.updateFull = function() { +}; + +MockRenderer.prototype.showCursor = function() { +}; + +MockRenderer.prototype.visualizeFocus = function() { +}; + return MockRenderer; }); diff --git a/lib/ace/test/navigation_test.js b/lib/ace/test/navigation_test.js index f4c2a2b2..63e519e8 100644 --- a/lib/ace/test/navigation_test.js +++ b/lib/ace/test/navigation_test.js @@ -35,18 +35,24 @@ * * ***** END LICENSE BLOCK ***** */ -require.def([ - "ace/Document", - "ace/Editor", - "ace/test/MockRenderer" - ], function( - Document, - Editor, - MockRenderer - ) { +require("../../../support/paths"); -var NavigationTest = TestCase("NavigationTest", -{ +var dom = require('jsdom/level2/html').dom.level2.html; +var browser = require('jsdom/browser/index').windowAugmentation(dom); + +global.document = browser.document; +global.window = browser.window; +global.self = browser.self; +global.navigator = browser.navigator; +global.location = browser.location; + +var Document = require("../Document"), + Editor = require("../Editor"), + MockRenderer = require("./mockrenderer"), + assert = require("./assertions"); + + +var Test = { createTextDocument : function(rows, cols) { var line = new Array(cols + 1).join("a"); var text = new Array(rows).join(line + "\n") + line; @@ -60,8 +66,8 @@ var NavigationTest = TestCase("NavigationTest", editor.navigateFileEnd(); var cursor = editor.getCursorPosition(); - assertTrue(editor.getFirstVisibleRow() <= cursor.row); - assertTrue(editor.getLastVisibleRow() >= cursor.row); + assert.true(editor.getFirstVisibleRow() <= cursor.row); + assert.true(editor.getLastVisibleRow() >= cursor.row); }, "test: navigate to start of file should scroll the first row into view" : function() { @@ -71,7 +77,7 @@ var NavigationTest = TestCase("NavigationTest", editor.moveCursorTo(editor.getLastVisibleRow() + 20); editor.navigateFileStart(); - assertEquals(0, editor.getFirstVisibleRow()); + assert.equal(editor.getFirstVisibleRow(), 0); }, "test: goto hidden line should scroll the line into the middle of the viewport" : function() { @@ -79,33 +85,33 @@ var NavigationTest = TestCase("NavigationTest", editor.navigateTo(0, 0); editor.gotoLine(101); - assertPosition(100, 0, editor.getCursorPosition()); - assertEquals(90, editor.getFirstVisibleRow()); + assert.position(editor.getCursorPosition(), 100, 0); + assert.equal(editor.getFirstVisibleRow(), 90); editor.navigateTo(100, 0); editor.gotoLine(11); - assertPosition(10, 0, editor.getCursorPosition()); - assertEquals(0, editor.getFirstVisibleRow()); + assert.position(editor.getCursorPosition(), 10, 0); + assert.equal(editor.getFirstVisibleRow(), 0); editor.navigateTo(100, 0); editor.gotoLine(6); - assertPosition(5, 0, editor.getCursorPosition()); - assertEquals(0, editor.getFirstVisibleRow()); + assert.position(editor.getCursorPosition(), 5, 0); + assert.equal(0, editor.getFirstVisibleRow(), 0); editor.navigateTo(100, 0); editor.gotoLine(1); - assertPosition(0, 0, editor.getCursorPosition()); - assertEquals(0, editor.getFirstVisibleRow()); + assert.position(editor.getCursorPosition(), 0, 0); + assert.equal(editor.getFirstVisibleRow(), 0); editor.navigateTo(0, 0); editor.gotoLine(191); - assertPosition(190, 0, editor.getCursorPosition()); - assertEquals(180, editor.getFirstVisibleRow()); + assert.position(editor.getCursorPosition(), 190, 0); + assert.equal(editor.getFirstVisibleRow(), 180); editor.navigateTo(0, 0); editor.gotoLine(196); - assertPosition(195, 0, editor.getCursorPosition()); - assertEquals(180, editor.getFirstVisibleRow()); + assert.position(editor.getCursorPosition(), 195, 0); + assert.equal(editor.getFirstVisibleRow(), 180); }, "test: goto visible line should only move the cursor and not scroll": function() { @@ -113,43 +119,46 @@ var NavigationTest = TestCase("NavigationTest", editor.navigateTo(0, 0); editor.gotoLine(12); - assertPosition(11, 0, editor.getCursorPosition()); - assertEquals(0, editor.getFirstVisibleRow()); + assert.position(editor.getCursorPosition(), 11, 0); + assert.equal(editor.getFirstVisibleRow(), 0); editor.navigateTo(30, 0); editor.gotoLine(33); - assertPosition(32, 0, editor.getCursorPosition()); - assertEquals(30, editor.getFirstVisibleRow()); + assert.position(editor.getCursorPosition(), 32, 0); + assert.equal(editor.getFirstVisibleRow(), 30); }, "test: navigate from the end of a long line down to a short line and back should maintain the curser column": function() { var editor = new Editor(new MockRenderer(), new Document(["123456", "1"])); editor.navigateTo(0, 6); - assertPosition(0, 6, editor.getCursorPosition()); + assert.position(editor.getCursorPosition(), 0, 6); editor.navigateDown(); - assertPosition(1, 1, editor.getCursorPosition()); + assert.position(editor.getCursorPosition(), 1, 1); editor.navigateUp(); - assertPosition(0, 6, editor.getCursorPosition()); + assert.position(editor.getCursorPosition(), 0, 6); }, "test: reset desired column on navigate left or right": function() { var editor = new Editor(new MockRenderer(), new Document(["123456", "12"])); editor.navigateTo(0, 6); - assertPosition(0, 6, editor.getCursorPosition()); + assert.position(editor.getCursorPosition(), 0, 6); editor.navigateDown(); - assertPosition(1, 2, editor.getCursorPosition()); + assert.position(editor.getCursorPosition(), 1, 2); editor.navigateLeft(); - assertPosition(1, 1, editor.getCursorPosition()); + assert.position(editor.getCursorPosition(), 1, 1); editor.navigateUp(); - assertPosition(0, 1, editor.getCursorPosition()); + assert.position(editor.getCursorPosition(), 0, 1); } -}); +}; -}); \ No newline at end of file +module.exports = require("async/test").testcase(Test) + +if (module === require.main) + module.exports.exec() diff --git a/lib/ace/test/range_test.js b/lib/ace/test/range_test.js index 639f6f10..3aa1cc72 100644 --- a/lib/ace/test/range_test.js +++ b/lib/ace/test/range_test.js @@ -35,118 +35,119 @@ * * ***** END LICENSE BLOCK ***** */ -require.def([ - "ace/Range" - ], function( - Range - ) { +require("../../../support/paths"); -RangeTest = new TestCase("RangeTest", { +var Range = require("../range"), + assert = require("./assertions"); +var Test = { "test: create range": function() { var range = new Range(1,2,3,4); - assertEquals(1, range.start.row); - assertEquals(2, range.start.column); - assertEquals(3, range.end.row); - assertEquals(4, range.end.column); + assert.equal(range.start.row, 1); + assert.equal(range.start.column, 2); + assert.equal(range.end.row, 3); + assert.equal(range.end.column, 4); }, "test: create from points": function() { var range = Range.fromPoints({row: 1, column: 2}, {row:3, column:4}); - assertEquals(1, range.start.row); - assertEquals(2, range.start.column); - assertEquals(3, range.end.row); - assertEquals(4, range.end.column); + assert.equal(range.start.row, 1); + assert.equal(range.start.column, 2); + assert.equal(range.end.row, 3); + assert.equal(range.end.column, 4); }, "test: clip to rows": function() { - assertRange(10, 0, 31, 0, new Range(0, 20, 100, 30).clipRows(10, 30)); - assertRange(10, 0, 30, 10, new Range(0, 20, 30, 10).clipRows(10, 30)); + assert.range(new Range(0, 20, 100, 30).clipRows(10, 30), 10, 0, 31, 0); + assert.range(new Range(0, 20, 30, 10).clipRows(10, 30), 10, 0, 30, 10); var range = new Range(0, 20, 3, 10); var range = range.clipRows(10, 30); - assertTrue(range.isEmpty()); - assertRange(10, 0, 10, 0, range); + assert.true(range.isEmpty()); + assert.range(range, 10, 0, 10, 0); }, "test: isEmpty": function() { var range = new Range(1, 2, 1, 2); - assertTrue(range.isEmpty()); + assert.true(range.isEmpty()); var range = new Range(1, 2, 1, 6); - assertFalse(range.isEmpty()); + assert.false(range.isEmpty()); }, "test: is multi line": function() { var range = new Range(1, 2, 1, 6); - assertFalse(range.isMultiLine()); + assert.false(range.isMultiLine()); var range = new Range(1, 2, 2, 6); - assertTrue(range.isMultiLine()); + assert.true(range.isMultiLine()); }, "test: clone": function() { var range = new Range(1, 2, 3, 4); var clone = range.clone(); - assertPosition(1, 2, clone.start); - assertPosition(3, 4, clone.end); + assert.position(clone.start, 1, 2); + assert.position(clone.end, 3, 4); clone.start.column = 20; - assertPosition(1, 2, range.start); + assert.position(range.start, 1, 2); clone.end.column = 20; - assertPosition(3, 4, range.end); + assert.position(range.end, 3, 4); }, "test: contains for multi line ranges": function() { var range = new Range(1, 10, 5, 20); - assertTrue(range.contains(1, 10)); - assertTrue(range.contains(2, 0)); - assertTrue(range.contains(3, 100)); - assertTrue(range.contains(5, 19)); - assertTrue(range.contains(5, 20)); + assert.true(range.contains(1, 10)); + assert.true(range.contains(2, 0)); + assert.true(range.contains(3, 100)); + assert.true(range.contains(5, 19)); + assert.true(range.contains(5, 20)); - assertFalse(range.contains(1, 9)); - assertFalse(range.contains(0, 0)); - assertFalse(range.contains(5, 21)); + assert.false(range.contains(1, 9)); + assert.false(range.contains(0, 0)); + assert.false(range.contains(5, 21)); }, "test: contains for single line ranges": function() { var range = new Range(1, 10, 1, 20); - assertTrue(range.contains(1, 10)); - assertTrue(range.contains(1, 15)); - assertTrue(range.contains(1, 20)); + assert.true(range.contains(1, 10)); + assert.true(range.contains(1, 15)); + assert.true(range.contains(1, 20)); - assertFalse(range.contains(0, 9)); - assertFalse(range.contains(2, 9)); - assertFalse(range.contains(1, 9)); - assertFalse(range.contains(1, 21)); + assert.false(range.contains(0, 9)); + assert.false(range.contains(2, 9)); + assert.false(range.contains(1, 9)); + assert.false(range.contains(1, 21)); }, "test: extend range": function() { var range = new Range(2, 10, 2, 30); var range = range.extend(2, 5); - assertRange(2, 5, 2, 30, range); - + assert.range(range, 2, 5, 2, 30); + var range = range.extend(2, 35); - assertRange(2, 5, 2, 35, range); - + assert.range(range, 2, 5, 2, 35); + var range = range.extend(2, 15); - assertRange(2, 5, 2, 35, range); - + assert.range(range, 2, 5, 2, 35); + var range = range.extend(1, 4); - assertRange(1, 4, 2, 35, range); - + assert.range(range, 1, 4, 2, 35); + var range = range.extend(6, 10); - assertRange(1, 4, 6, 10, range); + assert.range(range, 1, 4, 6, 10); } -}); +}; -}); \ No newline at end of file +module.exports = require("async/test").testcase(Test); + +if (module === require.main) + module.exports.exec() diff --git a/lib/ace/test/search_test.js b/lib/ace/test/search_test.js index 7d95da79..ba9b6e10 100644 --- a/lib/ace/test/search_test.js +++ b/lib/ace/test/search_test.js @@ -35,16 +35,13 @@ * * ***** END LICENSE BLOCK ***** */ -require.def([ - "ace/Document", - "ace/Search" - ], function( - Document, - Search - ) { +require("../../../support/paths"); -var SearchTest = new TestCase("SearchTest", { +var Document = require("../document"), + Search = require("../search"), + assert = require("./assertions"); +var Test = { "test: configure the search object" : function() { var search = new Search(); search.set({ @@ -60,8 +57,8 @@ var SearchTest = new TestCase("SearchTest", { }); var range = search.find(doc); - assertPosition(0, 5, range.start); - assertPosition(0, 12, range.end); + assert.position(range.start, 0, 5); + assert.position(range.end, 0, 12); }, "test: find simple text in next line" : function() { @@ -71,8 +68,8 @@ var SearchTest = new TestCase("SearchTest", { }); var range = search.find(doc); - assertPosition(1, 5, range.start); - assertPosition(1, 12, range.end); + assert.position(range.start, 1, 5); + assert.position(range.end, 1, 12); }, "test: find text starting at cursor position" : function() { @@ -83,8 +80,8 @@ var SearchTest = new TestCase("SearchTest", { }); var range = search.find(doc); - assertPosition(1, 5, range.start); - assertPosition(1, 12, range.end); + assert.position(range.start, 1, 5); + assert.position(range.end, 1, 12); }, "test: wrap search is off by default" : function() { @@ -95,7 +92,7 @@ var SearchTest = new TestCase("SearchTest", { needle: "kinners" }); - assertEquals(null, search.find(doc)); + assert.equal(search.find(doc), null); }, "test: wrap search should wrap at file end" : function() { @@ -108,8 +105,8 @@ var SearchTest = new TestCase("SearchTest", { }); var range = search.find(doc); - assertPosition(1, 5, range.start); - assertPosition(1, 12, range.end); + assert.position(range.start, 1, 5); + assert.position(range.end, 1, 12); }, "test: wrap search with no match should return 'null'": function() { @@ -121,7 +118,7 @@ var SearchTest = new TestCase("SearchTest", { wrap: true }); - assertEquals(null, search.find(doc)); + assert.equal(search.find(doc), null); }, "test: case sensitive is by default off": function() { @@ -131,7 +128,7 @@ var SearchTest = new TestCase("SearchTest", { needle: "JUHU" }); - assertEquals(null, search.find(doc)); + assert.range(search.find(doc), 1, 0, 1, 4); }, "test: case sensitive search": function() { @@ -143,8 +140,7 @@ var SearchTest = new TestCase("SearchTest", { }); var range = search.find(doc); - assertPosition(1, 5, range.start); - assertPosition(1, 12, range.end); + assert.equal(range, null); }, "test: whole word search should not match inside of words": function() { @@ -156,8 +152,8 @@ var SearchTest = new TestCase("SearchTest", { }); var range = search.find(doc); - assertPosition(1, 5, range.start); - assertPosition(1, 12, range.end); + assert.position(range.start, 1, 5); + assert.position(range.end, 1, 12); }, "test: find backwards": function() { @@ -169,8 +165,8 @@ var SearchTest = new TestCase("SearchTest", { }); var range = search.find(doc); - assertPosition(0, 5, range.start); - assertPosition(0, 9, range.end); + assert.position(range.start, 0, 5); + assert.position(range.end, 0, 9); }, "test: find in selection": function() { @@ -185,15 +181,15 @@ var SearchTest = new TestCase("SearchTest", { }); var range = search.find(doc); - assertPosition(1, 0, range.start); - assertPosition(1, 4, range.end); + assert.position(range.start, 1, 0); + assert.position(range.end, 1, 4); doc.getSelection().setSelectionAnchor(0, 2); doc.getSelection().selectTo(3, 2); var range = search.find(doc); - assertPosition(1, 0, range.start); - assertPosition(1, 4, range.end); + assert.position(range.start, 1, 0); + assert.position(range.end, 1, 4); }, "test: find backwards in selection": function() { @@ -210,13 +206,13 @@ var SearchTest = new TestCase("SearchTest", { doc.getSelection().selectTo(3, 2); var range = search.find(doc); - assertPosition(2, 0, range.start); - assertPosition(2, 4, range.end); + assert.position(range.start, 2, 0); + assert.position(range.end, 2, 4); doc.getSelection().setSelectionAnchor(0, 2); doc.getSelection().selectTo(1, 2); - assertEquals(null, search.find(doc)); + assert.equal(search.find(doc), null); }, "test: edge case - match directly before the cursor" : function() { @@ -230,8 +226,8 @@ var SearchTest = new TestCase("SearchTest", { doc.getSelection().moveCursorTo(2, 5); var range = search.find(doc); - assertPosition(2, 0, range.start); - assertPosition(2, 4, range.end); + assert.position(range.start, 2, 0); + assert.position(range.end, 2, 4); }, "test: edge case - match backwards directly after the cursor" : function() { @@ -246,8 +242,8 @@ var SearchTest = new TestCase("SearchTest", { doc.getSelection().moveCursorTo(2, 0); var range = search.find(doc); - assertPosition(2, 0, range.start); - assertPosition(2, 4, range.end); + assert.position(range.start, 2, 0); + assert.position(range.end, 2, 4); }, "test: find using a regular expression" : function() { @@ -259,8 +255,8 @@ var SearchTest = new TestCase("SearchTest", { }); var range = search.find(doc); - assertPosition(0, 3, range.start); - assertPosition(0, 6, range.end); + assert.position(range.start, 0, 3); + assert.position(range.end, 0, 6); }, "test: find using a regular expression and whole word" : function() { @@ -273,8 +269,8 @@ var SearchTest = new TestCase("SearchTest", { }); var range = search.find(doc); - assertPosition(0, 7, range.start); - assertPosition(0, 10, range.end); + assert.position(range.start, 0, 7); + assert.position(range.end, 0, 10); }, "test: use regular expressions with capture groups": function() { @@ -286,8 +282,8 @@ var SearchTest = new TestCase("SearchTest", { }); var range = search.find(doc); - assertPosition(0, 6, range.start); - assertPosition(0, 8, range.end); + assert.position(range.start, 0, 6); + assert.position(range.end, 0, 8); }, "test: find all matches in selection" : function() { @@ -304,11 +300,11 @@ var SearchTest = new TestCase("SearchTest", { var ranges = search.findAll(doc); - assertEquals(2, ranges.length); - assertPosition(1, 1, ranges[0].start); - assertPosition(1, 3, ranges[0].end); - assertPosition(2, 1, ranges[1].start); - assertPosition(2, 3, ranges[1].end); + assert.equal(ranges.length, 2); + assert.position(ranges[0].start, 1, 1); + assert.position(ranges[0].end, 1, 3); + assert.position(ranges[1].start, 2, 1); + assert.position(ranges[1].end, 2, 3); }, "test: replace() should return the replacement if the input matches the needle" : function() { @@ -316,9 +312,9 @@ var SearchTest = new TestCase("SearchTest", { needle: "juhu" }); - assertEquals("kinners", search.replace("juhu", "kinners")); - assertEquals(null, search.replace("", "kinners")); - assertEquals(null, search.replace(" juhu", "kinners")); + assert.equal(search.replace("juhu", "kinners"), "kinners"); + assert.equal(search.replace("", "kinners"), null); + assert.equal(search.replace(" juhu", "kinners"), null); // regexp replacement }, @@ -329,11 +325,11 @@ var SearchTest = new TestCase("SearchTest", { regExp: true }); - assertEquals("kinners", search.replace("123", "kinners")); - assertEquals("kinners", search.replace("01234", "kinners")); - assertEquals(null, search.replace("", "kinners")); - assertEquals(null, search.replace("a12", "kinners")); - assertEquals(null, search.replace("12a", "kinners")); + assert.equal(search.replace("123", "kinners"), "kinners"); + assert.equal(search.replace("01234", "kinners"), "kinners"); + assert.equal(search.replace("", "kinners"), null); + assert.equal(search.replace("a12", "kinners"), null); + assert.equal(search.replace("12a", "kinners"), null); }, "test: replace with RegExp match and capture groups" : function() { @@ -342,10 +338,13 @@ var SearchTest = new TestCase("SearchTest", { regExp: true }); - assertEquals("cd12", search.replace("ab12", "cd$1")); - assertEquals("-ab12-", search.replace("ab12", "-$&-")); - assertEquals("$", search.replace("ab12", "$$")); + assert.equal(search.replace("ab12", "cd$1"), "cd12"); + assert.equal(search.replace("ab12", "-$&-"), "-ab12-"); + assert.equal(search.replace("ab12", "$$"), "$"); } -}); +}; -}); \ No newline at end of file +module.exports = require("async/test").testcase(Test) + +if (module === require.main) + module.exports.exec(); diff --git a/lib/ace/test/selection_test.js b/lib/ace/test/selection_test.js index aa38336a..407fd3bf 100644 --- a/lib/ace/test/selection_test.js +++ b/lib/ace/test/selection_test.js @@ -35,14 +35,12 @@ * * ***** END LICENSE BLOCK ***** */ -require.def([ - "ace/Document" - ], function( - Document - ) { +require("../../../support/paths"); -var SelectionTest = TestCase("SelectionTest", -{ +var Document = require("../document"), + assert = require("./assertions"); + +var Test = { createTextDocument : function(rows, cols) { var line = new Array(cols + 1).join("a"); var text = new Array(rows).join(line + "\n") + line; @@ -54,7 +52,7 @@ var SelectionTest = TestCase("SelectionTest", var selection = doc.getSelection(); selection.moveCursorFileEnd(); - assertPosition(199, 10, selection.getCursor()); + assert.position(selection.getCursor(), 199, 10); }, "test: moveCursor to start of file should place the cursor on the first row and column" : function() { @@ -62,7 +60,7 @@ var SelectionTest = TestCase("SelectionTest", var selection = doc.getSelection(); selection.moveCursorFileStart(); - assertPosition(0, 0, selection.getCursor()); + assert.position(selection.getCursor(), 0, 0); }, "test: move selection lead to end of file" : function() { @@ -74,8 +72,8 @@ var SelectionTest = TestCase("SelectionTest", var range = selection.getRange(); - assertPosition(100, 5, range.start); - assertPosition(199, 10, range.end); + assert.position(range.start, 100, 5); + assert.position(range.end, 199, 10); }, "test: move selection lead to start of file" : function() { @@ -87,8 +85,8 @@ var SelectionTest = TestCase("SelectionTest", var range = selection.getRange(); - assertPosition(0, 0, range.start); - assertPosition(100, 5, range.end); + assert.position(range.start, 0, 0); + assert.position(range.end, 100, 5); }, "test: move cursor word right" : function() { @@ -97,38 +95,38 @@ var SelectionTest = TestCase("SelectionTest", var selection = doc.getSelection(); selection.moveCursorDown(); - assertPosition(1, 0, selection.getCursor()); + assert.position(selection.getCursor(), 1, 0); selection.moveCursorWordRight(); - assertPosition(1, 1, selection.getCursor()); + assert.position(selection.getCursor(), 1, 1); selection.moveCursorWordRight(); - assertPosition(1, 5, selection.getCursor()); + assert.position(selection.getCursor(), 1, 5); selection.moveCursorWordRight(); - assertPosition(1, 6, selection.getCursor()); + assert.position(selection.getCursor(), 1, 6); selection.moveCursorWordRight(); - assertPosition(1, 13, selection.getCursor()); + assert.position(selection.getCursor(), 1, 13); selection.moveCursorWordRight(); - assertPosition(1, 15, selection.getCursor()); + assert.position(selection.getCursor(), 1, 15); selection.moveCursorWordRight(); - assertPosition(1, 18, selection.getCursor()); + assert.position(selection.getCursor(), 1, 18); selection.moveCursorWordRight(); - assertPosition(1, 20, selection.getCursor()); + assert.position(selection.getCursor(), 1, 20); selection.moveCursorWordRight(); - assertPosition(1, 22, selection.getCursor()); + assert.position(selection.getCursor(), 1, 22); selection.moveCursorWordRight(); - assertPosition(1, 23, selection.getCursor()); + assert.position(selection.getCursor(), 1, 23); // wrap line selection.moveCursorWordRight(); - assertPosition(2, 0, selection.getCursor()); + assert.position(selection.getCursor(), 2, 0); }, "test: select word right if cursor in word" : function() { @@ -138,7 +136,7 @@ var SelectionTest = TestCase("SelectionTest", selection.moveCursorTo(0, 2); selection.moveCursorWordRight(); - assertPosition(0, 4, selection.getCursor()); + assert.position(selection.getCursor(), 0, 4); }, "test: moveCursor word left" : function() { @@ -148,38 +146,38 @@ var SelectionTest = TestCase("SelectionTest", selection.moveCursorDown(); selection.moveCursorLineEnd(); - assertPosition(1, 23, selection.getCursor()); + assert.position(selection.getCursor(), 1, 23); selection.moveCursorWordLeft(); - assertPosition(1, 22, selection.getCursor()); + assert.position(selection.getCursor(), 1, 22); selection.moveCursorWordLeft(); - assertPosition(1, 20, selection.getCursor()); + assert.position(selection.getCursor(), 1, 20); selection.moveCursorWordLeft(); - assertPosition(1, 18, selection.getCursor()); + assert.position(selection.getCursor(), 1, 18); selection.moveCursorWordLeft(); - assertPosition(1, 15, selection.getCursor()); + assert.position(selection.getCursor(), 1, 15); selection.moveCursorWordLeft(); - assertPosition(1, 13, selection.getCursor()); + assert.position(selection.getCursor(), 1, 13); selection.moveCursorWordLeft(); - assertPosition(1, 6, selection.getCursor()); + assert.position(selection.getCursor(), 1, 6); selection.moveCursorWordLeft(); - assertPosition(1, 5, selection.getCursor()); + assert.position(selection.getCursor(), 1, 5); selection.moveCursorWordLeft(); - assertPosition(1, 1, selection.getCursor()); + assert.position(selection.getCursor(), 1, 1); selection.moveCursorWordLeft(); - assertPosition(1, 0, selection.getCursor()); + assert.position(selection.getCursor(), 1, 0); // wrap line selection.moveCursorWordLeft(); - assertPosition(0, 2, selection.getCursor()); + assert.position(selection.getCursor(), 0, 2); }, "test: select word left if cursor in word" : function() { @@ -189,7 +187,7 @@ var SelectionTest = TestCase("SelectionTest", selection.moveCursorTo(0, 8); selection.moveCursorWordLeft(); - assertPosition(0, 5, selection.getCursor()); + assert.position(selection.getCursor(), 0, 5); }, "test: select word right and select" : function() { @@ -201,8 +199,8 @@ var SelectionTest = TestCase("SelectionTest", var range = selection.getRange(); - assertPosition(0, 0, range.start); - assertPosition(0, 4, range.end); + assert.position(range.start, 0, 0); + assert.position(range.end, 0, 4); }, "test: select word left and select" : function() { @@ -214,8 +212,8 @@ var SelectionTest = TestCase("SelectionTest", var range = selection.getRange(); - assertPosition(0, 0, range.start); - assertPosition(0, 3, range.end); + assert.position(range.start, 0, 0); + assert.position(range.end, 0, 3); }, "test: select word with cursor in word should select the word" : function() { @@ -226,8 +224,8 @@ var SelectionTest = TestCase("SelectionTest", selection.selectWord(); var range = selection.getRange(); - assertPosition(0, 5, range.start); - assertPosition(0, 12, range.end); + assert.position(range.start, 0, 5); + assert.position(range.end, 0, 12); }, "test: select word with cursor betwen white space and word should select the word" : function() { @@ -238,15 +236,15 @@ var SelectionTest = TestCase("SelectionTest", selection.selectWord(); var range = selection.getRange(); - assertPosition(0, 0, range.start); - assertPosition(0, 4, range.end); + assert.position(range.start, 0, 0); + assert.position(range.end, 0, 4); selection.moveCursorTo(0, 5); selection.selectWord(); var range = selection.getRange(); - assertPosition(0, 5, range.start); - assertPosition(0, 12, range.end); + assert.position(range.start, 0, 5); + assert.position(range.end, 0, 12); }, "test: select word with cursor in white space should select white space" : function() { @@ -257,8 +255,8 @@ var SelectionTest = TestCase("SelectionTest", selection.selectWord(); var range = selection.getRange(); - assertPosition(0, 4, range.start); - assertPosition(0, 6, range.end); + assert.position(range.start, 0, 4); + assert.position(range.end, 0, 6); }, "test: moving cursor should fire a 'changeCursor' event" : function() { @@ -273,7 +271,7 @@ var SelectionTest = TestCase("SelectionTest", }); selection.moveCursorTo(0, 6); - assertTrue(called); + assert.true(called); }, "test: calling setCursor with the same position should not fire an event": function() { @@ -288,8 +286,11 @@ var SelectionTest = TestCase("SelectionTest", }); selection.moveCursorTo(0, 5); - assertFalse(called); + assert.false(called); } -}); +}; -}); \ No newline at end of file +module.exports = require("async/test").testcase(Test); + +if (module === require.main) + module.exports.exec() diff --git a/lib/ace/test/text_edit_test.js b/lib/ace/test/text_edit_test.js index 2087a838..0b319376 100644 --- a/lib/ace/test/text_edit_test.js +++ b/lib/ace/test/text_edit_test.js @@ -35,21 +35,24 @@ * * ***** END LICENSE BLOCK ***** */ -require.def([ - "ace/Document", - "ace/Editor", - "ace/mode/JavaScript", - "ace/test/MockRenderer" - ], function( - Document, - Editor, - jsMod, - MockRenderer - ) { +require("../../../support/paths"); -var JavaScriptMode = jsMod.JavaScript; -var TextEditTest = TestCase("TextEditTest", -{ +var dom = require('jsdom/level2/html').dom.level2.html; +var browser = require('jsdom/browser/index').windowAugmentation(dom); + +global.document = browser.document; +global.window = browser.window; +global.self = browser.self; +global.navigator = browser.navigator; +global.location = browser.location; + +var Document = require("../document"), + Editor = require("../editor"), + JavaScriptMode = require("../mode/javascript"), + MockRenderer = require("./mockrenderer"), + assert = require("./assertions"); + +var Test = { "test: delete line from the middle" : function() { var doc = new Document(["a", "b", "c", "d"].join("\n")); var editor = new Editor(new MockRenderer(), doc); @@ -57,23 +60,23 @@ var TextEditTest = TestCase("TextEditTest", editor.moveCursorTo(1, 1); editor.removeLines(); - assertEquals("a\nc\nd", doc.toString()); - assertPosition(1, 0, editor.getCursorPosition()); + assert.equal(doc.toString(), "a\nc\nd"); + assert.position(editor.getCursorPosition(), 1, 0); editor.removeLines(); - assertEquals("a\nd", doc.toString()); - assertPosition(1, 0, editor.getCursorPosition()); + assert.equal(doc.toString(), "a\nd"); + assert.position(editor.getCursorPosition(), 1, 0); editor.removeLines(); - assertEquals("a\n", doc.toString()); - assertPosition(1, 0, editor.getCursorPosition()); + assert.equal(doc.toString(), "a\n"); + assert.position(editor.getCursorPosition(), 1, 0); editor.removeLines(); - assertEquals("a\n", doc.toString()); - assertPosition(1, 0, editor.getCursorPosition()); + assert.equal(doc.toString(), "a\n"); + assert.position(editor.getCursorPosition(), 1, 0); }, "test: delete multiple selected lines" : function() { @@ -84,8 +87,8 @@ var TextEditTest = TestCase("TextEditTest", editor.getSelection().selectDown(); editor.removeLines(); - assertEquals("a\nd", doc.toString()); - assertPosition(1, 0, editor.getCursorPosition()); + assert.equal(doc.toString(), "a\nd"); + assert.position(editor.getCursorPosition(), 1, 0); }, "test: delete first line" : function() { @@ -94,8 +97,8 @@ var TextEditTest = TestCase("TextEditTest", editor.removeLines(); - assertEquals("b\nc", doc.toString()); - assertPosition(0, 0, editor.getCursorPosition()); + assert.equal(doc.toString(), "b\nc"); + assert.position(editor.getCursorPosition(), 0, 0); }, "test: delete last" : function() { @@ -105,11 +108,11 @@ var TextEditTest = TestCase("TextEditTest", editor.moveCursorTo(2, 1); editor.removeLines(); - assertEquals("a\nb\n", doc.toString()); - assertPosition(2, 0, editor.getCursorPosition()); + assert.equal(doc.toString(), "a\nb\n"); + assert.position(editor.getCursorPosition(), 2, 0); }, - "test: indent block" : function() { + "__test: indent block" : function() { var doc = new Document(["a12345", "b12345", "c12345"].join("\n")); var editor = new Editor(new MockRenderer(), doc); @@ -118,18 +121,18 @@ var TextEditTest = TestCase("TextEditTest", editor.blockIndent(" "); - assertEquals(["a12345", " b12345", " c12345"].join("\n"), + assert.equal(["a12345", " b12345", " c12345"].join("\n"), doc.toString()); - assertPosition(2, 7, editor.getCursorPosition()); + assert.position(editor.getCursorPosition(), 2, 7); var range = editor.getSelectionRange(); - assertPosition(1, 7, range.start); - assertPosition(2, 7, range.end); + assert.position(range.start, 1, 7); + assert.position(range.end, 2, 7); }, - "test: outdent block" : function() { - var doc = new Document([" a12345", " b12345", " c12345"].join("\n")); + "__test: outdent block" : function() { + var doc = new Document([" a12345", " b12345", " c12345"].join("\n")); var editor = new Editor(new MockRenderer(), doc); editor.moveCursorTo(0, 3); @@ -137,23 +140,21 @@ var TextEditTest = TestCase("TextEditTest", editor.getSelection().selectDown(); editor.blockOutdent(" "); - assertEquals([" a12345", "b12345", " c12345"].join("\n"), - doc.toString()); + assert.equal(doc.toString(), [" a12345", "b12345", " c12345"].join("\n")); - assertPosition(2, 1, editor.getCursorPosition()); + assert.position(editor.getCursorPosition(), 2, 0); var range = editor.getSelectionRange(); - assertPosition(0, 1, range.start); - assertPosition(2, 1, range.end); + assert.position(range.start, 0, 1); + assert.position(range.end, 2, 1); editor.blockOutdent(" "); - assertEquals([" a12345", "b12345", " c12345"].join("\n"), - doc.toString()); + assert.equal(doc.toString(), ["a12345", "b12345", "c12345"].join("\n")); var range = editor.getSelectionRange(); - assertPosition(0, 1, range.start); - assertPosition(2, 1, range.end); + assert.position(range.start, 0, 1); + assert.position(range.end, 2, 1); }, "test: outent without a selection should update cursor" : function() { @@ -163,8 +164,8 @@ var TextEditTest = TestCase("TextEditTest", editor.moveCursorTo(0, 3); editor.blockOutdent(" "); - assertEquals(" 12", doc.toString()); - assertPosition(0, 1, editor.getCursorPosition()); + assert.equal(doc.toString(), " 12"); + assert.position(editor.getCursorPosition(), 0, 0); }, "test: comment lines should perserve selection" : function() { @@ -176,11 +177,11 @@ var TextEditTest = TestCase("TextEditTest", editor.toggleCommentLines(); - assertEquals(["// abc", "//cde"].join("\n"), doc.toString()); + assert.equal(["// abc", "//cde"].join("\n"), doc.toString()); var selection = editor.getSelectionRange(); - assertPosition(0, 4, selection.start); - assertPosition(1, 4, selection.end); + assert.position(selection.start, 0, 4); + assert.position(selection.end, 1, 4); }, "test: uncomment lines should perserve selection" : function() { @@ -194,8 +195,8 @@ var TextEditTest = TestCase("TextEditTest", editor.toggleCommentLines(); - assertEquals([" abc", "cde"].join("\n"), doc.toString()); - assertRange(0, 0, 1, 1, editor.getSelectionRange()); + assert.equal([" abc", "cde"].join("\n"), doc.toString()); + assert.range(editor.getSelectionRange(), 0, 0, 1, 1); }, "test: comment lines - if the selection end is at the line start it should stay there": function() { @@ -207,7 +208,7 @@ var TextEditTest = TestCase("TextEditTest", editor.getSelection().selectDown(); editor.toggleCommentLines(); - assertRange(0, 2, 1, 0, editor.getSelectionRange()); + assert.range(editor.getSelectionRange(), 0, 2, 1, 0); // select up var doc = new Document(["abc", "cde"].join("\n"), new JavaScriptMode()); @@ -217,7 +218,7 @@ var TextEditTest = TestCase("TextEditTest", editor.getSelection().selectUp(); editor.toggleCommentLines(); - assertRange(0, 2, 1, 0, editor.getSelectionRange()); + assert.range(editor.getSelectionRange(), 0, 2, 1, 0); }, "test: move lines down should select moved lines" : function() { @@ -228,26 +229,26 @@ var TextEditTest = TestCase("TextEditTest", editor.getSelection().selectDown(); editor.moveLinesDown(); - assertEquals(["33", "11", "22", "44"].join("\n"), doc.toString()); - assertPosition(1, 0, editor.getCursorPosition()); - assertPosition(3, 0, editor.getSelection().getSelectionAnchor()); - assertPosition(1, 0, editor.getSelection().getSelectionLead()); + assert.equal(["33", "11", "22", "44"].join("\n"), doc.toString()); + assert.position(editor.getCursorPosition(), 1, 0); + assert.position(editor.getSelection().getSelectionAnchor(), 3, 0); + assert.position(editor.getSelection().getSelectionLead(), 1, 0); editor.moveLinesDown(); - assertEquals(["33", "44", "11", "22"].join("\n"), doc.toString()); - assertPosition(2, 0, editor.getCursorPosition()); - assertPosition(3, 2, editor.getSelection().getSelectionAnchor()); - assertPosition(2, 0, editor.getSelection().getSelectionLead()); + assert.equal(["33", "44", "11", "22"].join("\n"), doc.toString()); + assert.position(editor.getCursorPosition(), 2, 0); + assert.position(editor.getSelection().getSelectionAnchor(), 3, 2); + assert.position(editor.getSelection().getSelectionLead(), 2, 0); // moving again should have no effect editor.moveLinesDown(); - assertEquals(["33", "44", "11", "22"].join("\n"), doc.toString()); - assertPosition(2, 0, editor.getCursorPosition()); - assertPosition(3, 2, editor.getSelection().getSelectionAnchor()); - assertPosition(2, 0, editor.getSelection().getSelectionLead()); + assert.equal(["33", "44", "11", "22"].join("\n"), doc.toString()); + assert.position(editor.getCursorPosition(), 2, 0); + assert.position(editor.getSelection().getSelectionAnchor(), 3, 2); + assert.position(editor.getSelection().getSelectionLead(), 2, 0); }, - "test: move lines up should select moved lines" : function() { + "__test: move lines up should select moved lines" : function() { var doc = new Document(["11", "22", "33", "44"].join("\n")); var editor = new Editor(new MockRenderer(), doc); @@ -255,16 +256,16 @@ var TextEditTest = TestCase("TextEditTest", editor.getSelection().selectDown(); editor.moveLinesUp(); - assertEquals(["11", "33", "44", "22"].join("\n"), doc.toString()); - assertPosition(1, 0, editor.getCursorPosition()); - assertPosition(3, 0, editor.getSelection().getSelectionAnchor()); - assertPosition(1, 0, editor.getSelection().getSelectionLead()); + assert.equal(doc.toString(), ["11", "33", "44", "22"].join("\n")); + assert.position(editor.getCursorPosition(), 1, 0); + assert.position(editor.getSelection().getSelectionAnchor(), 3, 0); + assert.position(editor.getSelection().getSelectionLead(), 1, 0); editor.moveLinesUp(); - assertEquals(["33", "44", "11", "22"].join("\n"), doc.toString()); - assertPosition(0, 0, editor.getCursorPosition()); - assertPosition(2, 0, editor.getSelection().getSelectionAnchor()); - assertPosition(0, 0, editor.getSelection().getSelectionLead()); + assert.equal(doc.toString(), ["33", "44", "11", "22"].join("\n")); + assert.position(editor.getCursorPosition(), 0, 0); + assert.position(editor.getSelection().getSelectionAnchor(), 2, 0); + assert.position(editor.getSelection().getSelectionLead(), 0, 0); }, "test: move line without active selection should move cursor to start of the moved line" : function() @@ -276,14 +277,14 @@ var TextEditTest = TestCase("TextEditTest", editor.clearSelection(); editor.moveLinesDown(); - assertEquals(["11", "33", "22", "44"].join("\n"), doc.toString()); - assertPosition(2, 0, editor.getCursorPosition()); + assert.equal(["11", "33", "22", "44"].join("\n"), doc.toString()); + assert.position(editor.getCursorPosition(), 2, 0); editor.clearSelection(); editor.moveLinesUp(); - assertEquals(["11", "22", "33", "44"].join("\n"), doc.toString()); - assertPosition(1, 0, editor.getCursorPosition()); + assert.equal(["11", "22", "33", "44"].join("\n"), doc.toString()); + assert.position(editor.getCursorPosition(), 1, 0); }, "test: copy lines down should select lines and place cursor at the selection start" : function() { @@ -294,11 +295,11 @@ var TextEditTest = TestCase("TextEditTest", editor.getSelection().selectDown(); editor.copyLinesDown(); - assertEquals(["11", "22", "33", "22", "33", "44"].join("\n"), doc.toString()); + assert.equal(["11", "22", "33", "22", "33", "44"].join("\n"), doc.toString()); - assertPosition(3, 0, editor.getCursorPosition()); - assertPosition(5, 0, editor.getSelection().getSelectionAnchor()); - assertPosition(3, 0, editor.getSelection().getSelectionLead()); + assert.position(editor.getCursorPosition(), 3, 0); + assert.position(editor.getSelection().getSelectionAnchor(), 5, 0); + assert.position(editor.getSelection().getSelectionLead(), 3, 0); }, "test: copy lines up should select lines and place cursor at the selection start" : function() { @@ -309,11 +310,11 @@ var TextEditTest = TestCase("TextEditTest", editor.getSelection().selectDown(); editor.copyLinesUp(); - assertEquals(["11", "22", "33", "22", "33", "44"].join("\n"), doc.toString()); + assert.equal(["11", "22", "33", "22", "33", "44"].join("\n"), doc.toString()); - assertPosition(1, 0, editor.getCursorPosition()); - assertPosition(3, 0, editor.getSelection().getSelectionAnchor()); - assertPosition(1, 0, editor.getSelection().getSelectionLead()); + assert.position(editor.getCursorPosition(), 1, 0); + assert.position(editor.getSelection().getSelectionAnchor(), 3, 0); + assert.position(editor.getSelection().getSelectionLead(), 1, 0); }, "test: input a tab with soft tab should convert it to spaces" : function() { @@ -324,11 +325,11 @@ var TextEditTest = TestCase("TextEditTest", doc.setUseSoftTabs(true); editor.onTextInput("\t"); - assertEquals(" ", doc.toString()); + assert.equal(doc.toString(), " "); doc.setTabSize(5); editor.onTextInput("\t"); - assertEquals(" ", doc.toString()); + assert.equal(doc.toString(), " "); }, "test: input tab without soft tabs should keep the tab character" : function() { @@ -338,8 +339,11 @@ var TextEditTest = TestCase("TextEditTest", doc.setUseSoftTabs(false); editor.onTextInput("\t"); - assertEquals("\t", doc.toString()); + assert.equal(doc.toString(), "\t"); } -}); +}; -}); \ No newline at end of file +module.exports = require("async/test").testcase(Test); + +if (module === require.main) + module.exports.exec() diff --git a/lib/ace/test/virtual_renderer_test.js b/lib/ace/test/virtual_renderer_test.js index a7ea6d23..8ff64670 100644 --- a/lib/ace/test/virtual_renderer_test.js +++ b/lib/ace/test/virtual_renderer_test.js @@ -35,16 +35,14 @@ * * ***** END LICENSE BLOCK ***** */ -require.def([ - "ace/Document", - "ace/VirtualRenderer" - ], function( - Document, - VirtualRenderer - ) { -var VirtualRendererTest = new TestCase("VirtualRendererTest", { +require("../../../support/paths"); +var Document = "../document", + VirtualRenderer = "../virtual_renderer", + assert = "../assertions"; + +var Test = { "test: screen2text the column should be rounded to the next character edge" : function() { var el = document.createElement("div"); el.style.left = "0px"; @@ -61,17 +59,20 @@ var VirtualRendererTest = new TestCase("VirtualRendererTest", { renderer.characterWidth = 10; renderer.lineHeight = 15; - assertPosition(0, 0, renderer.screenToTextCoordinates(0, 0)); - assertPosition(0, 0, renderer.screenToTextCoordinates(4, 0)); - assertPosition(0, 1, renderer.screenToTextCoordinates(5, 0)); - assertPosition(0, 1, renderer.screenToTextCoordinates(9, 0)); - assertPosition(0, 1, renderer.screenToTextCoordinates(10, 0)); - assertPosition(0, 1, renderer.screenToTextCoordinates(14, 0)); - assertPosition(0, 2, renderer.screenToTextCoordinates(15, 0)); + assert.position(renderer.screenToTextCoordinates(0, 0), 0, 0); + assert.position(renderer.screenToTextCoordinates(4, 0), 0, 0); + assert.position(renderer.screenToTextCoordinates(5, 0), 0, 1); + assert.position(renderer.screenToTextCoordinates(9, 0), 0, 1); + assert.position(renderer.screenToTextCoordinates(10, 0), 0, 1); + assert.position(renderer.screenToTextCoordinates(14, 0), 0, 1); + assert.position(renderer.screenToTextCoordinates(15, 0), 0, 2); document.body.removeChild(el); } // change tab size after setDocument (for text layer) -}); +}; -}); \ No newline at end of file +module.exports = require("async/test").testcase(Test); + +if (module === require.main) + module.exports.exec() diff --git a/support/async b/support/async new file mode 160000 index 00000000..6da80763 --- /dev/null +++ b/support/async @@ -0,0 +1 @@ +Subproject commit 6da8076355fc9f06191d39b8f5989159dc8a162c diff --git a/support/jsdom b/support/jsdom new file mode 160000 index 00000000..48675596 --- /dev/null +++ b/support/jsdom @@ -0,0 +1 @@ +Subproject commit 486755962dc0b69c60bfd04869ff1e0093406bae diff --git a/support/node-htmlparser b/support/node-htmlparser new file mode 160000 index 00000000..60d64db4 --- /dev/null +++ b/support/node-htmlparser @@ -0,0 +1 @@ +Subproject commit 60d64db4a9a8b1a26bd099bc34f657bf096c4f39 From b9982435f75f70fe9a23b7d7a7209ff8281a8525 Mon Sep 17 00:00:00 2001 From: wittemann Date: Wed, 24 Nov 2010 20:57:57 +0800 Subject: [PATCH 60/90] Fixed win key bindings. --- lib/ace/conf/keybindings/default_win.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ace/conf/keybindings/default_win.js b/lib/ace/conf/keybindings/default_win.js index 7f546f2d..3ae134b9 100644 --- a/lib/ace/conf/keybindings/default_win.js +++ b/lib/ace/conf/keybindings/default_win.js @@ -63,13 +63,13 @@ exports.bindings = { "godown": "Down", "selectwordleft": "Ctrl-Shift-Left", "gotowordleft": "Ctrl-Left", - "selecttolinestart": "Ctrl-Shift-Left", + "selecttolinestart": "Alt-Shift-Left", "gotolinestart": "Alt-Left|Home", "selectleft": "Shift-Left", "gotoleft": "Left", "selectwordright": "Ctrl-Shift-Right", "gotowordright": "Ctrl-Right", - "selecttolineend": "Ctrl-Shift-Right", + "selecttolineend": "Alt-Shift-Right", "gotolineend": "Alt-Right|End", "selectright": "Shift-Right", "gotoright": "Right", From e63a3fb496bc58e8b8ae76adeb8bcae367b4013d Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Thu, 2 Dec 2010 10:59:09 +0000 Subject: [PATCH 61/90] lots of new unit tests --- plugins/pilot/lib/test/assert.js | 317 ++++++++++++++++++++++++++++++ plugins/pilot/lib/test/testCli.js | 185 +++++++++++++++++ 2 files changed, 502 insertions(+) create mode 100644 plugins/pilot/lib/test/assert.js create mode 100644 plugins/pilot/lib/test/testCli.js diff --git a/plugins/pilot/lib/test/assert.js b/plugins/pilot/lib/test/assert.js new file mode 100644 index 00000000..d0d1b93a --- /dev/null +++ b/plugins/pilot/lib/test/assert.js @@ -0,0 +1,317 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Joe Walker (jwalker@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +var test = { + + success: function(message) { + console.log(message); + }, + + fail: function(message) { + test._recordThrow("fail", arguments); + }, + + assertTrue: function(value) { + if (!value) { + test._recordThrow("assertTrue", arguments); + } + }, + + verifyTrue: function(value) { + if (!value) { + test._recordTrace("verifyTrue", arguments); + } + }, + + assertFalse: function(value) { + if (value) { + test._recordThrow("assertFalse", arguments); + } + }, + + verifyFalse: function(value) { + if (value) { + test._recordTrace("verifyFalse", arguments); + } + }, + + assertNull: function(value) { + if (value !== null) { + test._recordThrow("assertNull", arguments); + } + }, + + verifyNull: function(value) { + if (value !== null) { + test._recordTrace("verifyNull", arguments); + } + }, + + assertNotNull: function(value) { + if (value === null) { + test._recordThrow("assertNotNull", arguments); + } + }, + + verifyNotNull: function(value) { + if (value === null) { + test._recordTrace("verifyNotNull", arguments); + } + }, + + assertUndefined: function(value) { + if (value !== undefined) { + test._recordThrow("assertUndefined", arguments); + } + }, + + verifyUndefined: function(value) { + if (value !== undefined) { + test._recordTrace("verifyUndefined", arguments); + } + }, + + assertNotUndefined: function(value) { + if (value === undefined) { + test._recordThrow("assertNotUndefined", arguments); + } + }, + + verifyNotUndefined: function(value) { + if (value === undefined) { + test._recordTrace("verifyNotUndefined", arguments); + } + }, + + assertNaN: function(value) { + if (!isNaN(value)) { + test._recordThrow("assertNaN", arguments); + } + }, + + verifyNaN: function(value) { + if (!isNaN(value)) { + test._recordTrace("verifyNaN", arguments); + } + }, + + assertNotNaN: function(value) { + if (isNaN(value)) { + test._recordThrow("assertNotNaN", arguments); + } + }, + + verifyNotNaN: function(value) { + if (isNaN(value)) { + test._recordTrace("verifyNotNaN", arguments); + } + }, + + assertEqual: function(expected, actual) { + if (!test._isEqual(expected, actual)) { + test._recordThrow("assertEqual", arguments); + } + }, + + verifyEqual: function(expected, actual) { + if (!test._isEqual(expected, actual)) { + test._recordTrace("verifyEqual", arguments); + } + }, + + assertNotEqual: function(expected, actual) { + if (test._isEqual(expected, actual)) { + test._recordThrow("assertNotEqual", arguments); + } + }, + + verifyNotEqual: function(expected, actual) { + if (test._isEqual(expected, actual)) { + test._recordTrace("verifyNotEqual", arguments); + } + }, + + assertSame: function(expected, actual) { + if (expected !== actual) { + test._recordThrow("assertSame", arguments); + } + }, + + verifySame: function(expected, actual) { + if (expected !== actual) { + test._recordTrace("verifySame", arguments); + } + }, + + assertNotSame: function(expected, actual) { + if (expected !== actual) { + test._recordThrow("assertNotSame", arguments); + } + }, + + verifyNotSame: function(expected, actual) { + if (expected !== actual) { + test._recordTrace("verifyNotSame", arguments); + } + }, + + _recordTrace: function() { + test._record.apply(this, arguments); + console.trace(); + }, + + _recordThrow: function() { + test._record.apply(this, arguments); + throw new Error(); + }, + + _record: function() { + console.error(arguments); + var message = arguments[0] + "("; + var data = arguments[1]; + if (typeof data == "string") { + message += data; + } + else { + for (var i = 0; i < data.length; i++) { + if (i != 0){message += ", ";} + message += data[i]; + } + } + message += ")"; + console.log(message); + }, + + _isEqual: function(expected, actual, depth) { + if (!depth){depth = 0;} + // Rather than failing we assume that it works! + if (depth > 10) { + return true; + } + + if (expected == null) { + if (actual != null) { + console.log("expected: null, actual non-null: ", actual); + return false; + } + return true; + } + + if (typeof(expected) == "number" && isNaN(expected)) { + if (!(typeof(actual) == "number" && isNaN(actual))) { + console.log("expected: NaN, actual non-NaN: ", actual); + return false; + } + return true; + } + + if (actual == null) { + if (expected != null) { + console.log("actual: null, expected non-null: ", expected); + return false; + } + return true; // we wont get here of course ... + } + + if (typeof expected == "object") { + if (!(typeof actual == "object")) { + console.log("expected object, actual not an object"); + return false; + } + + var actualLength = 0; + for (var prop in actual) { + if (typeof actual[prop] != "function" || + typeof expected[prop] != "function") { + var nest = test._isEqual(actual[prop], expected[prop], depth + 1); + if (typeof nest != "boolean" || !nest) { + console.log("element '" + prop + "' does not match: " + nest); + return false; + } + } + actualLength++; + } + + // need to check length too + var expectedLength = 0; + for (prop in expected) expectedLength++; + if (actualLength != expectedLength) { + console.log("expected object size = " + expectedLength + + ", actual object size = " + actualLength); + return false; + } + return true; + } + + if (actual != expected) { + console.log("expected = " + expected + " (type=" + typeof expected + "), " + + "actual = " + actual + " (type=" + typeof actual + ")"); + return false; + } + + if (expected instanceof Array) { + if (!(actual instanceof Array)) { + console.log("expected array, actual not an array"); + return false; + } + if (actual.length != expected.length) { + console.log("expected array length = " + expected.length + + ", actual array length = " + actual.length); + return false; + } + for (var i = 0; i < actual.length; i++) { + var inner = test._isEqual(actual[i], expected[i], depth + 1); + if (typeof inner != "boolean" || !inner) { + console.log("element " + i + " does not match: " + inner); + return false; + } + } + + return true; + } + + return true; + } +}; + + +exports.test = test; + + +}); diff --git a/plugins/pilot/lib/test/testCli.js b/plugins/pilot/lib/test/testCli.js new file mode 100644 index 00000000..875a8f04 --- /dev/null +++ b/plugins/pilot/lib/test/testCli.js @@ -0,0 +1,185 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Joe Walker (jwalker@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + + +var test = require('pilot/test/assert').test; +var cli = require('pilot/cli'); +var Status = require('pilot/types').Status; + +exports.testAll = function() { + exports.testTokenize(); + exports.testSplit(); + exports.testInput(); + return "testAll Completed"; +}; + +exports.testSplit = function() { + var args = cli._tokenize('s'); + var command = cli._split(args); + test.verifyEqual(1, args.length); + test.verifyEqual('s', args[0].text); + test.verifyUndefined(command); + + var args = cli._tokenize('set'); + var command = cli._split(args); + test.verifyEqual([], args); + test.verifyEqual('set', command.name); + + var args = cli._tokenize('set a b'); + var command = cli._split(args); + test.verifyEqual('set', command.name); + test.verifyEqual(2, args.length); + test.verifyEqual('a', args[0].text); + test.verifyEqual('b', args[1].text); + + // TODO: add tests for sub commands + return "testSplit Completed"; +}; + +exports.testTokenize = function() { + var args = cli._tokenize(''); + test.verifyEqual(0, args.length); + + args = cli._tokenize('s'); + test.verifyEqual(1, args.length); + test.verifyEqual('s', args[0].text); + test.verifyEqual(0, args[0].start); + test.verifyEqual(1, args[0].end); + test.verifyEqual('', args[0].priorSpace); + + args = cli._tokenize('s s'); + test.verifyEqual(2, args.length); + test.verifyEqual('s', args[0].text); + test.verifyEqual(0, args[0].start); + test.verifyEqual(1, args[0].end); + test.verifyEqual('', args[0].priorSpace); + test.verifyEqual('s', args[1].text); + test.verifyEqual(2, args[1].start); + test.verifyEqual(3, args[1].end); + test.verifyEqual(' ', args[1].priorSpace); + + args = cli._tokenize(' 1234 \'12 34\''); + test.verifyEqual(2, args.length); + test.verifyEqual('1234', args[0].text); + test.verifyEqual(1, args[0].start); + test.verifyEqual(5, args[0].end); + test.verifyEqual(' ', args[0].priorSpace); + test.verifyEqual('12 34', args[1].text); + test.verifyEqual(8, args[1].start); + test.verifyEqual(13, args[1].end); + test.verifyEqual(' ', args[1].priorSpace); + + args = cli._tokenize('12\'34 "12 34" \\'); // 12'34 "12 34" \ + test.verifyEqual(3, args.length); + test.verifyEqual('12\'34', args[0].text); + test.verifyEqual(0, args[0].start); + test.verifyEqual(5, args[0].end); + test.verifyEqual('', args[0].priorSpace); + test.verifyEqual('12 34', args[1].text); + test.verifyEqual(7, args[1].start); + test.verifyEqual(12, args[1].end); + test.verifyEqual(' ', args[1].priorSpace); + test.verifyEqual('\\', args[2].text); + test.verifyEqual(14, args[2].start); + test.verifyEqual(15, args[2].end); + test.verifyEqual(' ', args[2].priorSpace); + + args = cli._tokenize('a\\ b \\t\\n\\r \\\'x\\\" \'d'); // a_b \t\n\r \'x\" 'd + test.verifyEqual(4, args.length); + test.verifyEqual('a b', args[0].text); + test.verifyEqual(0, args[0].start); + test.verifyEqual(3, args[0].end); + test.verifyEqual('', args[0].priorSpace); + test.verifyEqual('\t\n\r', args[1].text); + test.verifyEqual(4, args[1].start); + test.verifyEqual(7, args[1].end); + test.verifyEqual(' ', args[1].priorSpace); + test.verifyEqual('\'x"', args[2].text); + test.verifyEqual(8, args[2].start); + test.verifyEqual(11, args[2].end); + test.verifyEqual(' ', args[2].priorSpace); + test.verifyEqual('d', args[3].text); + test.verifyEqual(13, args[3].start); + test.verifyEqual(14, args[3].end); + test.verifyEqual(' ', args[3].priorSpace); + + return "testTokenize Completed"; +}; + +exports.testInput = function() { + var input = new cli.Input(); + input.parse(''); + + test.verifyEqual(1, input.hints.length); + test.verifyEqual(Status.INCOMPLETE, input.hints[0].status); + test.verifyNull(input.requisition.command); + + input.parse('s'); + test.verifyEqual(1, input.hints.length); + test.verifyEqual(Status.INCOMPLETE, input.hints[0].status); + test.verifyNotEqual(-1, input.hints[0].message.indexOf('possibilities')); + test.verifyTrue(input.hints[0].predictions.length > 0); + // This is slightly fragile because it depends on the configuration + test.verifyTrue(input.hints[0].predictions.length < 20); + test.verifyNotEqual(-1, input.hints[0].predictions.indexOf('set')); + test.verifyNull(input.requisition.command); + + input.parse('set'); + test.verifyEqual(1, input.hints.length); + test.verifyEqual('set', input.requisition.command.name); + + input.parse('set '); + test.verifyEqual(1, input.hints.length); + test.verifyEqual('set', input.requisition.command.name); + + input.parse('set h'); +console.log(input); + test.verifyEqual(1, input.hints.length); + test.verifyEqual(Status.INCOMPLETE, input.hints[0].status); + test.verifyEqual('set', input.requisition.command.name); + test.verifyEqual('h', input.requisition.getAssignment('setting').text); + test.verifyEqual(undefined, input.requisition.getAssignment('setting').value); + + return "testInput Completed"; +}; + +window.testCli = exports; + + +}); From e5b1a59c5e0fa7876c452e6adc9369fe5e709854 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Thu, 2 Dec 2010 10:59:18 +0000 Subject: [PATCH 62/90] make addCommand convert parameters types to Types, make exec work on commands as well as command names, and thus remove execRequisition. Move Requisition and Assignment into canon, and lots of tidyup --- plugins/pilot/lib/canon.js | 241 ++++++++++--------------------------- 1 file changed, 61 insertions(+), 180 deletions(-) diff --git a/plugins/pilot/lib/canon.js b/plugins/pilot/lib/canon.js index a68458c6..6bf03793 100644 --- a/plugins/pilot/lib/canon.js +++ b/plugins/pilot/lib/canon.js @@ -40,16 +40,18 @@ define(function(require, exports, module) { var console = require('pilot/console'); var Trace = require('pilot/stacktrace').Trace; -var oop = require("pilot/oop").oop; -var EventEmitter = require("pilot/event_emitter").EventEmitter; -var catalog = require("pilot/catalog"); +var oop = require('pilot/oop').oop; +var EventEmitter = require('pilot/event_emitter').EventEmitter; +var catalog = require('pilot/catalog'); +var Status = require('pilot/types').Status; +var types = require('pilot/types'); /* // TODO: this doesn't belong here - or maybe anywhere? var dimensionsChangedExtensionSpec = { - name: "dimensionsChanged", - description: "A dimensionsChanged is a way to be notified of " + - "changes to the dimension of Skywriter" + name: 'dimensionsChanged', + description: 'A dimensionsChanged is a way to be notified of ' + + 'changes to the dimension of Skywriter' }; exports.startup = function(data, reason) { catalog.addExtensionSpec(commandExtensionSpec); @@ -60,12 +62,12 @@ exports.shutdown = function(data, reason) { */ var commandExtensionSpec = { - name: "command", - description: "A command is a bit of functionality with optional " + - "typed arguments which can do something small like moving " + - "the cursor around the screen, or large like cloning a " + - "project from VCS.", - indexOn: "name" + name: 'command', + description: 'A command is a bit of functionality with optional ' + + 'typed arguments which can do something small like moving ' + + 'the cursor around the screen, or large like cloning a ' + + 'project from VCS.', + indexOn: 'name' }; var env; @@ -89,29 +91,55 @@ exports.shutdown = function(data, reason) { * how it happens. This is here for documentation purposes. * TODO: Document better */ -var Command = { - name: "thing", - description: "thing is an example command", +var thingCommand = { + name: 'thing', + description: 'thing is an example command', params: [{ - name: "param1", - description: "an example parameter", - type: "text", + name: 'param1', + description: 'an example parameter', + type: 'text', defaultValue: null }], - exec: function(env, args, request) { } + exec: function(env, args, request) { + thing(); + } }; var commands = {}; +/** + * This registration method isn't like other Ace registration methods because + * it doesn't return a decorated command because there is no functional + * decoration to be done. + * TODO: Are we sure that in the future there will be no such decoration? + */ exports.addCommand = function(command) { if (!command.name) { - throw new Error("All registered commands must have a name"); + throw new Error('All registered commands must have a name'); } + if (command.params == null) { + command.params = []; + } + if (!Array.isArray(command.params)) { + throw new Error('command.params must be an array in ' + command.name); + } + // Replace the type + command.params.forEach(function(param) { + if (!param.name) { + throw new Error('In ' + command.name + ': all params must have a name'); + } + var lookup = param.type; + param.type = types.getType(lookup); + if (param.type == null) { + throw new Error('In ' + command.name + '/' + param.name + + ': can\'t find type for: ' + JSON.stringify(lookup)); + } + }, this); commands[command.name] = command; }; exports.removeCommand = function(command) { - if (typeof command === "string") { + if (typeof command === 'string') { delete commands[command]; } else { @@ -130,25 +158,22 @@ exports.getCommandNames = function() { /** * Entry point for keyboard accelerators or anything else that knows * everything it needs to about the command params + * @param command Either a command, or the name of one */ -exports.exec = function(name, args) { - var command = commands[name]; - if (command) { - // TODO: Ugg. really? - env.selection = env.editor.getSelection(); - var request = new Request(); - command.exec(env, args || {}, request); - return true; +exports.exec = function(command, args) { + if (typeof name === 'string') { + command = commands[command]; + } + if (!command) { + // TODO: Should we complain more than returning false? + return false; } - return false; -}; -/** - * Entry point for users that need to collect parameters from textual input - */ -exports.execRequisition = function(requisition) { + // TODO: Ugg. really? + env.selection = env.editor.getSelection(); var request = new Request(); - requisition.command.exec(env, requisition.getArgs(), request); + command.exec(env, args || {}, request); + return true; }; /** @@ -157,124 +182,6 @@ exports.execRequisition = function(requisition) { */ oop.implement(exports, EventEmitter); -/** - * A Requisition collects the information needed to execute a command. - * There is no point in a requisition for parameter-less commands because there - * is no information to collect. A Requisition is a collection of assignments - * of values to parameters, each handled by an instance of Assignment. - * @constructor - */ -function Requisition(command) { - this.command = command; - this.assignments = {}; - command.params.forEach(function(param) { - this.assignment[param.name] = new Assignment(param); - }); -} -Requisition.prototype = { - /** - * The command that we are about to execute. - * @readonly - */ - command: undefined, - - /** - * The set of values that we are assigning to parameters in the command - * @readonly - */ - assignments: undefined, - - /** - * - */ - getArgs: function() { - var args = {}; - Object.keys(assignments).forEach(function(name) { - args[name] = getCommand(name); - }); - return args; - } -}; -exports.Requisition = Requisition; - - -/** - * A link between a parameter and the data for that parameter. - * The data for the parameter is available as in the preferred type and in - * the string representation of that type. - *

We also record validity information and cli offset data where applicable. - *

For values, null and undefined have distinct definitions. null means - * that a value has been provided, undefined means that it has not. - * Thus, null is a valid default value, and common because it identifies an - * parameter that is optional. undefined means there is no value from - * the command line. - * TODO: think about this distinction some more, particularly this line: - * ass.setValue(undefined); ass.value -> param.defaultValue?; - * @constructor - */ -function Assignment(param) { - this.param = param; - this.setValue(param.defaultValue); -}; -Assignment.prototype = { - /** - * The parameter that we are assigning to - * @readonly - */ - param: undefined, - - /** - * The current value (i.e. not the string representation) - * @readonly - use setValue() to mutate - */ - value: undefined, - setValue: function(value) { - if (this.value === value) { - return; - } - if (value === undefined) { - value = this.param.defaultValue; - } - this.text = this.param.type.toString(value); - this.value = value; - this.status = Status.VALID; - this.message = ""; - this._dispatchEvent('change', { assignment: this }); - }, - - /** - * The textual representation of the current value - * @readonly - use setValue() to mutate - */ - text: undefined, - setText: function(text) { - if (this.text === text) { - return; - } - var conversion = this.param.type.fromString(text); - this.text = text; - this.value = conversion.value; - this.status = conversion.status; - this.message = conversion.message; - this._dispatchEvent('change', { assignment: this }); - }, - - /** - * Report on the status of the last fromString() conversion. - * @see types.Conversion - */ - status: undefined, - message: undefined, - - /** - * Read-write value which records the offset of this text into a command - * line. This is a convenience provided to the command line, but which - * probably won't be used elsewhere. - */ - offset: undefined -}; -oop.implement(Assignment, EventEmitter); -exports.Assignment = Assignment; /** * Current requirements are around displaying the command line, and provision @@ -316,32 +223,6 @@ exports.addRequestOutput = function(request) { exports._dispatchEvent('addedRequestOutput', { request: request }); }; -/** - * Execute a new command. - * This is basically an error trapping wrapper around request.command(...) - */ -exports.execute = function(args, request) { - // Check the function pointed to in the meta-data exists - if (!request.command) { - request.doneWithError('Command not found.'); - return; - } - - try { - request.command(args, request); - } catch (ex) { - var trace = new Trace(ex, true); - console.group('Error executing command \'' + request.typed + '\''); - console.log('command=', request.commandExt); - console.log('args=', args); - console.error(ex); - trace.log(3); - console.groupEnd(); - - request.doneWithError(ex); - } -}; - /** * To create an invocation, you need to do something like this (all the ctor * args are optional): From f256175f712a7dcc34b61a6551f1924f1f168c91 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Thu, 2 Dec 2010 10:59:19 +0000 Subject: [PATCH 63/90] A ton of fixes from the creation of unit tests. Addition of ConversionHint and Argument and classes from canon. Also Input is a lot flatter than it was (easier testing) --- plugins/pilot/lib/cli.js | 850 ++++++++++++++++++++++++++------------- 1 file changed, 573 insertions(+), 277 deletions(-) diff --git a/plugins/pilot/lib/cli.js b/plugins/pilot/lib/cli.js index b47aff0f..928af610 100644 --- a/plugins/pilot/lib/cli.js +++ b/plugins/pilot/lib/cli.js @@ -38,31 +38,99 @@ define(function(require, exports, module) { -var console = require('skywriter/console'); +var console = require('pilot/console'); var util = require('pilot/util'); +var oop = require('pilot/oop').oop; -var keyboard = require('keyboard/keyboard'); -var Status = require('pilot/canon').Status; -var Requisition = require('pilot/canon').Requisition; +//var keyboard = require('keyboard/keyboard'); +var Status = require('pilot/types').Status; +var canon = require('pilot/canon'); +var types = require('pilot/types'); -var typehint = require('command_line/typehint'); +var commandType; +exports.startup = function(data, reason) { + commandType = types.getType('command'); +}; /** * The information required to tell the user there is a problem with their * input. - * TODO: Consider formalizing alternatives */ function Hint(status, message, start, end) { this.status = status; this.message = message; - this.start = start; - this.end = end; + + if (typeof start === 'number') { + this.start = start; + this.end = end; + } + else { + var arg = start; + this.start = arg.start; + this.end = arg.end; + } } Hint.prototype = { - }; exports.Hint = Hint; +/** + * A Hint that arose as a result of a Conversion + */ +function ConversionHint(conversion, arg) { + this.status = conversion.status; + this.message = conversion.message; + if (arg) { + this.start = arg.start; + this.end = arg.end; + } + else { + this.start = 0; + this.end = 0; + } + this.predictions = conversion.predictions; +}; +oop.inherits(ConversionHint, Hint); + + +/** + * We record where in the input string an argument comes so we can report errors + * against those string positions. + * @constructor + */ +function Argument(text, start, end, priorSpace) { + this.text = text; + this.start = start; + this.end = end; + this.priorSpace = priorSpace; +} +Argument.prototype = { + /** + * Return the result of merging these arguments + */ + merge: function(following) { + return new Argument( + this.text + following.priorSpace + following.text, + this.start, following.end, + this.priorSpace); + } +}; +/** + * Merge an array of arguments into a single argument. + */ +Argument.mergeAll = function(argArray) { + var joined; + argArray.forEach(function(arg) { + if (!joined) { + joined = arg; + } + else { + joined = joined.merge(arg); + } + }); + return joined; +}; + /** * An object used during command line parsing to hold the various intermediate @@ -72,6 +140,15 @@ exports.Hint = Hint; * single value. *

The other output value is input.requisition which gives access to an * args object for use in executing the final command. + * + * The majority of the functions in this class are called in sequence by the + * constructor. Their task is to add to hints fill out the requisition. + *

The general sequence is:

    + *
  • _tokenize(): convert _typed into _parts + *
  • _split(): convert _parts into _command and _unparsedArgs + *
  • _assign(): convert _unparsedArgs into requisition + *
+ * * @param typed {string} The instruction as typed by the user so far * @param options {object} A list of optional named parameters. Can be any of: * flags: Flags for us to check against the predicates specified with the @@ -79,169 +156,85 @@ exports.Hint = Hint; * if not specified. * @constructor */ -function Input(typed, options) { - if (util.none(typed)) { - throw new Error('Input requires something \'typed\' to work on'); +function Input(options) { + if (options) { + if (options.flags) { + this.flags = options.flags; + } + if (options.input) { + // TODO: implement + this.useAsInput(options.input); + } } - this.typed = typed; - this.hints = []; - - options = options || {}; - - // TODO: We were using a default of keyboard.buildFlags({ }); - // I think this allowed us to have commands that only existed in certain - // contexts - i.e. Javascript specific commands. - this.flags = options.flags || {}; - - // Once tokenize() has been called, we have the #typed string cut up into - // #_parts - this._parts = []; - - // Once split has been called we have #_parts split into #_unparsedArgs and - // #_command (if there is a matching command). - this._unparsedArgs = undefined; - - // Once we know what the command is, we can fire up a Requisition - this.requisition = undefined; - - // Assign matches #_unparsedArgs to the params declared by the #_command - // A list of arguments in _command.params order - this._assignments = undefined; - - this._tokenize(); -}; - -/** - * Implementation of Input. - * The majority of the functions in this class are called in sequence by the - * constructor. Their task is to add to hints fill out the requisition. - *

The general sequence is:

    - *
  • _tokenize(): convert _typed into _parts - *
  • _split(): convert _parts into _command and _unparsedArgs - *
  • _assign(): convert _unparsedArgs into _assignments - *
- */ + this.requisition = new Requisition(); +} Input.prototype = { /** - * Split up the input taking into account ' and " + * TODO: We were using a default of keyboard.buildFlags({ }); + * I think this allowed us to have commands that only existed in certain + * contexts - i.e. Javascript specific commands. */ - _tokenize: function() { - if (!this.typed || this.typed === '') { + flags: {}, + + /** + * + */ + parse: function(typed) { + if (util.none(typed)) { + this.requisition.setCommand(null); + return; + } + + this.typed = typed; + this.hints = []; + + var args = _tokenize(this.typed); + if (args.length === 0) { // We would like to put some initial help here, but for anyone but // a complete novice a 'type help' message is very annoying, so we // need to find a way to only display this message once, or for // until the user click a 'close' button or similar - this.hints.push(new Hint(Status.INCOMPLETE)); + this._addHint(Status.INCOMPLETE, '', 0, 0); + this.requisition.setCommand(null); return; } - // replace(/^\s\s*/, '') = trimLeft() - var incoming = this.typed.replace(/^\s\s*/, '').split(/\s+/); + var command = _split(args); - var nextToken; - while (true) { - nextToken = incoming.shift(); - if (util.none(nextToken)) { - break; - } - if (nextToken[0] == '"' || nextToken[0] == '\'') { - // It's quoting time - var eaten = [ nextToken.substring(1, nextToken.length) ]; - var eataway; - while (true) { - eataway = incoming.shift(); - if (!eataway) { - break; - } - if (eataway[eataway.length - 1] == '"' || - eataway[eataway.length - 1] == '\'') { - // End quoting time - eaten.push(eataway.substring(0, eataway.length - 1)); - break; - } else { - eaten.push(eataway); - } - } - this._parts.push(eaten.join(' ')); - } else { - this._parts.push(nextToken); - } + if (!command) { + // No command found - bail helpfully. + var conversion = commandType.parse(typed); + var arg = Argument.mergeAll(args); + this._addHint(new ConversionHint(conversion, arg)); + + this.requisition.setCommand(null); } + else { + // The user hasn't started to type any arguments + if (args.length === 0) { + var message = documentCommand(command); + this._addHint(Status.VALID, message, 0, typed.length); + } - // Split the command from the args - this._split(); + this.requisition.setCommand(command); + this._assign(args); + this.addHints(this.requisition.getHints()); + } }, /** - * Looks in the canon for a command extension that matches what has been - * typed at the command line. + * Some sugar around: 'this.hints.push(new Hint(...));' */ - _split: function() { - this._unparsedArgs = this._parts.slice(); // aka clone() - var initial = this._unparsedArgs.shift(); - var command; - - while (true) { - command = canon.getCommand(initial); - - if (!command) { - // Not found. break with command == null - break; - } - - if (!keyboard.flagsMatch(command.predicates, this.flags)) { - // If the predicates say 'no match' then go LA LA LA - command = null; - break; - } - - if (command.exec) { - // Valid command, break with command valid - break; - } - - // command, but no exec - this must be a sub-command - initial += ' ' + this._unparsedArgs.shift(); + _addHint: function(status, message, start, end) { + if (status instanceof Hint) { + this.hints.push(status); } - - // Do we know what the command is. - if (!command) { - // We don't know what the command is - // TODO: We should probably cache this - var commands = []; - canon.getCommandNames().forEach(function(name) { - var command = canon.getCommand(name); - if (keyboard.flagsMatch(command.predicates, this.flags) && - command.description) { - commands.push(command); - } - }.bind(this)); - - // TODO: make this a hint - var hintSpec = { - param: { - type: { name: 'selection', data: commands }, - description: 'Commands' - }, - value: this.typed - }; - - return; + else if (Array.isArray(status)) { + this.hints.push.apply(this.hints, status); } - - // The user hasn't started to type any params - if (this._parts.length === 1) { - if (this.typed == command.name || - !command.params || - command.params.length === 0) { - this.hints.push(documentCommand(command, this.typed)); - } + else { + this.hints.push(new Hint(status, message, start, end)); } - - this.requisition = new Requisition(command); - - // Assign input to declared parameters - this._assign(); }, /** @@ -253,168 +246,293 @@ Input.prototype = { *
  • index - Zero based index into where the match came from on the input *
  • value - The matching input * - * The resulting #_assignments member created by this function is a list of - * assignments of arguments in command.params order. - * TODO: _unparsedArgs should be a list of objects that contain the - * following values: name, param (when assigned) and maybe hints? */ - _assign: function() { - // TODO: something smarter than just assuming that they are all in order - this._assignments = []; - var params = this.requisition.command.params; - var unparsedArgs = this._unparsedArgs; - var message; + _assign: function(args) { + if (args.length === 0) { + this.requisition.setDefaultValues(); + return; + } // Create an error if the command does not take parameters, but we have // been given them ... - if (!params || params.length === 0) { - // No problem if we're passed nothing or an empty something - var argCount = 0; - unparsedArgs.forEach(function(unparsedArg) { - if (unparsedArg.trim() !== '') { - argCount++; - } - }); - - if (argCount !== 0) { - message = this.requisition.command.name + ' does not take any parameters'; - this.hints.push(new Hint(Status.INVALID, message)); - } - + if (this.requisition.assignmentCount === 0) { + // TODO: previously we were doing some extra work to avoid this if + // we determined that we had args that were all whitespace, but + // probably given our tighter tokenize() this won't be an issue? + this._addHint(Status.INVALID, + this.requisition.command.name + ' does not take any parameters', + Argument.mergeAll(args)); return; } // Special case: if there is only 1 parameter, and that's of type // text we put all the params into the first param - if (params.length == 1 && params[0].type == 'text') { - // Warning: There is some potential problem here if spaces are - // significant. It might be better to chop the command of the - // start of this.typed? But that's not easy because there could - // be multiple spaces in the command if we're doing sub-commands - this._assignments[0] = { - value: unparsedArgs.length === 0 ? null : unparsedArgs.join(' '), - param: params[0] - }; - } else { - // The normal case where we have to assign params individually - var index = 0; - var used = []; - params.forEach(function(param) { - this._assignParam(param, index++, used); - }.bind(this)); - - // Check there are no params that don't fit - var unparsed = false; - unparsedArgs.forEach(function(unparsedArg) { - if (used.indexOf(unparsedArg) == -1) { - message = 'Parameter \'' + unparsedArg + '\' makes no sense.'; - this.hints.push(new Hint(Status.INVALID, message)); - unparsed = true; - } - }.bind(this)); - - if (unparsed) { + if (this.requisition.assignmentCount == 1) { + var assignment = this.requisition.getAssignment(0); + if (assignment.param.type.name === 'text') { + assignment.setText(Argument.mergeAll(args).text); return; } } - // Show a hint for the last parameter - if (this._parts.length > 1) { - var assignment = this._getAssignmentForLastArg(); + var assignments = this.requisition.cloneAssignments(); + var names = this.requisition.getParameterNames(); - // HACK! deferred types need to have some parameters - // by which to determine which type they should defer to - // so we hack in the assignments so the deferrer can work - assignment.param.type.assignments = this._assignments; + // Extract all the named parameters + var used = []; + assignments.forEach(function(assignment) { + var namedArgText = '--' + assignment.name; - if (assignment) { - this.hints.push(typehint.getHint(this, assignment)); - } - } + var i = 0; + while (true) { + var arg = args[i]; + if (namedArgText !== arg.text) { + i++; + if (i >= args.length) { + break; + } + continue; + } - // Convert input into declared types - this._convertTypes(); - }, - - /** - * Extract a value from the set of inputs for a given param. - * @param param The param that we are providing a value for. This is taken - * from the command meta-data for the command in question. - * @param index The number of the param - i.e. the index of param - * into the original params array. - */ - _assignParam: function(param, index, used) { - var message; - // Look for '--param X' style inputs - for (var i = 0; i < this._unparsedArgs.length; i++) { - var unparsedArg = this._unparsedArgs[i]; - - if ('--' + param.name == unparsedArg) { - used.push(unparsedArg); - // boolean parameters don't have values, they default to false - if (param.type.name === 'boolean') { - this._assignments[index] = { - value: true, - param: param - }; + // boolean parameters don't have values, default to false + if (assignment.param.type.name === 'boolean') { + assignment.setValue(true); } else { - if (i + 1 < this._unparsedArgs.length) { - message = 'Missing parameter: ' + param.name; + if (i + 1 < args.length) { // Missing value for this param - this.hints.push(new Hint(Status.INCOMPLETE, message)); + this._addHint(Status.INCOMPLETE, + 'Missing value for: ' + namedArgText, + args[i]); } else { - used.push(this._unparsedArgs[i + 1]); + args.splice(i + 1, 1); + assignment.setText(args[i + 1].text); } } - return; + + util.arrayRemove(names, assignment.name); + args.splice(i, 1); + // We don't need to i++ if we splice } - } + }, this); - var value = null; - if (this._unparsedArgs.length > index) { - value = this._unparsedArgs[index]; - used.push(this._unparsedArgs[index]); - } - - // null is a valid default value, and common because it identifies an - // parameter that is optional. undefined means there is no value from - // the command line - if (value !== undefined) { - this._assignments[index] = { value: value, param: param }; - } else { - this._assignments[index] = { param: param }; - - if (param.defaultValue === undefined) { - // There is no default, and we've not supplied one so far - message = 'Missing parameter: ' + param.name; - this.hints.push(new Hint(Status.INCOMPLETE, message)); + // What's left are positional parameters assign in order + var i = 0; + names.forEach(function(name) { + var assignment = this.requisition.getAssignment(name); + if (i >= args.length) { + // No more values + assignment.setValue(undefined); // i.e. default } + else { + var arg = args[i]; + args.splice(i, 1); + assignment.setText(arg.text); + } + + i++; + }, this); + + if (args.length > 0) { + var remaining = Argument.mergeAll(args); + this._addHint(Status.INVALID, + 'Input \'' + remaining.text + '\' makes no sense.', + remaining); } } }; exports.Input = Input; +/** + * Split up the input taking into account ' and " + */ +function _tokenize(typed) { + var OUTSIDE = 1; // The last character was whitespace + var IN_SIMPLE = 2; // The last character was part of a parameter + var IN_SINGLE_Q = 3; // We're inside a single quote: ' + var IN_DOUBLE_Q = 4; // We're inside double quotes: " + + var mode = OUTSIDE; + + // First we un-escape. This list was taken from: + // https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Core_Language_Features#Unicode + // We are generally converting to their real values except for \', \" + // and '\ ' which we are converting to unicode private characters so we + // can distinguish them from ', " and ' ', which have special meaning. + // They need swapping back post-split. + typed = typed + .replace(/\\\\/g, '\\') + .replace(/\\b/g, '\b') + .replace(/\\f/g, '\f') + .replace(/\\n/g, '\n') + .replace(/\\r/g, '\r') + .replace(/\\t/g, '\t') + .replace(/\\v/g, '\v') + .replace(/\\n/g, '\n') + .replace(/\\r/g, '\r') + .replace(/\\ /g, '\uF000') + .replace(/\\'/g, '\uF001') + .replace(/\\"/g, '\uF002'); + + var i = 0; + var start = 0; // Where did this section start? + var priorSpace = ''; + var args = []; + + while (true) { + if (i >= typed.length) { + // There is no more - tidy up + if (mode !== OUTSIDE) { + var str = typed.substring(start, i); + args.push(new Argument(str, start, i, priorSpace)); + } + break; + } + + var c = typed[i]; + switch (mode) { + case OUTSIDE: + if (c === '\'') { + priorSpace = typed.substring(start, i); + mode = IN_SINGLE_Q; + start = i + 1; + } + else if (c === '"') { + priorSpace = typed.substring(start, i); + mode = IN_DOUBLE_Q; + start = i + 1; + } + else if (/ /.test(c)) { + // Still whitespace, do nothing + } + else { + priorSpace = typed.substring(start, i); + mode = IN_SIMPLE; + start = i; + } + break; + + case IN_SIMPLE: + // There is an edge case of xx'xx which we are assuming to be + // a single parameter (and same with ") + if (c === ' ') { + var str = typed.substring(start, i); + args.push(new Argument(str, start, i, priorSpace)); + mode = OUTSIDE; + start = i; + priorSpace = ''; + } + break; + + case IN_SINGLE_Q: + if (c === '\'') { + var str = typed.substring(start, i); + args.push(new Argument(str, start, i, priorSpace)); + mode = OUTSIDE; + start = i + 1; + priorSpace = ''; + } + break; + + case IN_DOUBLE_Q: + if (c === '"') { + var str = typed.substring(start, i); + args.push(new Argument(str, start, i, priorSpace)); + mode = OUTSIDE; + start = i + 1; + priorSpace = ''; + } + break; + } + + i++; + } + + args.forEach(function(arg) { + arg.text = arg.text + .replace(/\uF000/g, ' ') + .replace(/\uF001/g, '\'') + .replace(/\uF002/g, '"'); + }); + + return args; +} +exports._tokenize = _tokenize; + +/** + * Looks in the canon for a command extension that matches what has been + * typed at the command line. + */ +function _split(args) { + if (args.length === 0) { + return undefined; + } + + var argsUsed = 0; + var lookup = ''; + var command; + + while (true) { + argsUsed++; + lookup += args.map(function(arg) { + return arg.text; + }).slice(0, argsUsed).join(' '); + command = canon.getCommand(lookup); + + if (!command) { + // Not found. break with command == null + return undefined; + } + + /* + // Previously we needed a way to hide commands depending context. + // We have not resurrected that feature yet. + if (!keyboard.flagsMatch(command.predicates, this.flags)) { + // If the predicates say 'no match' then go LA LA LA + command = null; + break; + } + */ + + if (command.exec) { + // Valid command, break with command valid + break; + } + + // command, but no exec - this must be a sub-command + lookup += ' '; + } + + // Remove the used args + for (var i = 0; i < argsUsed; i++) { + args.shift(); + } + + return command; +} +exports._split = _split; + + /** * Provide some documentation for a command. * TODO: this should return a hint */ -function documentCommand(cmdExt, typed) { +function documentCommand(command) { var docs = []; - docs.push('

    ' + cmdExt.name + '

    '); + docs.push('

    ' + command.name + '

    '); docs.push('

    Summary

    '); - docs.push('

    ' + cmdExt.description + '

    '); + docs.push('

    ' + command.description + '

    '); - if (cmdExt.manual) { + if (command.manual) { docs.push('

    Description

    '); - docs.push('

    ' + cmdExt.description + '

    '); + docs.push('

    ' + command.description + '

    '); } - if (cmdExt.params && cmdExt.params.length > 0) { + if (command.params && command.params.length > 0) { docs.push('

    Synopsis

    '); docs.push('
    ');
    -        docs.push(cmdExt.name);
    +        docs.push(command.name);
             var optionalParamCount = 0;
    -        cmdExt.params.forEach(function(param) {
    +        command.params.forEach(function(param) {
                 if (param.defaultValue === undefined) {
                     docs.push(' ');
                     docs.push(param.name);
    @@ -430,7 +548,7 @@ function documentCommand(cmdExt, typed) {
             if (optionalParamCount > 3) {
                 docs.push(' [options]');
             } else if (optionalParamCount > 0) {
    -            cmdExt.params.forEach(function(param) {
    +            command.params.forEach(function(param) {
                     if (param.defaultValue) {
                         docs.push(' [--');
                         docs.push(param.name);
    @@ -446,7 +564,7 @@ function documentCommand(cmdExt, typed) {
             docs.push('
    '); docs.push('

    Parameters

    '); - cmdExt.params.forEach(function(param) { + command.params.forEach(function(param) { docs.push('

    ' + param.name + '

    '); docs.push('

    ' + param.description + '

    '); if (param.type.defaultValue) { @@ -455,12 +573,190 @@ function documentCommand(cmdExt, typed) { }); } - return { - param: { type: 'text', description: docs.join('') }, - value: typed - }; + return docs.join(''); }; exports.documentCommand = documentCommand; +/** + * A Requisition collects the information needed to execute a command. + * There is no point in a requisition for parameter-less commands because there + * is no information to collect. A Requisition is a collection of assignments + * of values to parameters, each handled by an instance of Assignment. + * @constructor + */ +function Requisition() { +} +Requisition.prototype = { + /** + * The command that we are about to execute. + * @readonly + */ + command: undefined, + + /** + * The count of assignments + * @readonly + */ + assignmentCount: undefined, + + /** + * Set a new command. We make no attempt to convert the args in the old + * command to args in the new command. The assignments need to be + * re-entered. + */ + setCommand: function(command) { + if (this.command === command) { + return; + } + + this.command = command; + this._assignments = {}; + + if (command) { + command.params.forEach(function(param) { + this._assignments[param.name] = new Assignment(param); + }, this); + } + + this.assignmentCount = Object.keys(this._assignments); + }, + + /** + * Assignments have an order, so we need to store them in an array. + * But we also need named access ... + */ + getAssignment: function(nameOrNumber) { + var name = (typeof nameOrNumber === 'string') ? + nameOrNumber : + Object.keys(this._assignments)[nameOrNumber]; + return this._assignments[name]; + }, + + /** + * Where parameter name == assignment names - they are the same. + */ + getParameterNames: function() { + return Object.keys(this._assignments); + }, + + /** + * A *shallow* clone of the assignments. + * This is useful for systems that wish to go over all the assignments + * finding values one way or another and wish to trim an array as they go. + */ + cloneAssignments: function() { + return Object.keys(this._assignments).map(function(name) { + return this._assignments[name]; + }, this); + }, + + /** + * Collect the statuses from the Assignments + */ + getHints: function() { + + }, + + /** + * Extract the names and values of all the assignments, and return as + * an object. + */ + getArgs: function() { + var args = {}; + Object.keys(this._assignments).forEach(function(name) { + args[name] = getCommand(name); + }, this); + return args; + }, + + /** + * Reset all the assignments to their default values + */ + setDefaultValues: function() { + Object.keys(this._assignments).forEach(function(name) { + this._assignments[name].setValue(undefined); + }, this); + }, + + /** + * Helper to call canon.exec + */ + exec: function() { + exports.exec(this.command, this.getArgs()); + } +}; +exports.Requisition = Requisition; + + +/** + * A link between a parameter and the data for that parameter. + * The data for the parameter is available as in the preferred type and as + * an Argument for the CLI. + *

    We also record validity information where applicable. + *

    For values, null and undefined have distinct definitions. null means + * that a value has been provided, undefined means that it has not. + * Thus, null is a valid default value, and common because it identifies an + * parameter that is optional. undefined means there is no value from + * the command line. + * @constructor + */ +function Assignment(param) { + this.param = param; + this.setValue(param.defaultValue); +}; +Assignment.prototype = { + /** + * The parameter that we are assigning to + * @readonly + */ + param: undefined, + + /** + * The current value (i.e. not the string representation) + * @readonly - use setValue() to mutate + */ + value: undefined, + setValue: function(value) { + if (this.value === value) { + return; + } + if (value === undefined) { + value = this.param.defaultValue; + } + this.text = (value === null) ? '' : this.param.type.stringify(value); + this.value = value; + this.status = Status.VALID; + this.message = ''; + //this._dispatchEvent('change', { assignment: this }); + }, + + /** + * The textual representation of the current value + * @readonly - use setValue() to mutate + */ + text: undefined, + setText: function(text) { + if (this.text === text) { + return; + } + var conversion = this.param.type.parse(text); + this.text = text; + this.value = conversion.value; + this.status = conversion.status; + this.message = conversion.message; + //this._dispatchEvent('change', { assignment: this }); + }, + + /** + * Report on the status of the last parse() conversion. + * @see types.Conversion + */ + status: undefined, + message: undefined +}; +oop.implement(Assignment, EventEmitter); +exports.Assignment = Assignment; + + }); From b44e8c83b6c2596cba2977de597e7457855918a8 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Thu, 2 Dec 2010 10:59:19 +0000 Subject: [PATCH 64/90] minor tweaks --- plugins/pilot/lib/commands/settings.js | 48 ++------------------------ plugins/pilot/lib/event_emitter.js | 2 +- 2 files changed, 4 insertions(+), 46 deletions(-) diff --git a/plugins/pilot/lib/commands/settings.js b/plugins/pilot/lib/commands/settings.js index cfc5edd1..e336fb97 100644 --- a/plugins/pilot/lib/commands/settings.js +++ b/plugins/pilot/lib/commands/settings.js @@ -37,57 +37,18 @@ define(function(require, exports, module) { -/** - * Something of a hack to allow the set command to give a clearer definition - * of the type to the command line. - */ -var valueDeferredType = { - name: "deferred", - undeferType: function(typeSpec, env) { - var assignments = typeSpec.assignments; - var replacement = 'text'; - - if (assignments) { - // Find the assignment for 'setting' so we can get it's value - var settingAssignment = null; - assignments.forEach(function(assignment) { - if (assignment.param.name === 'setting') { - settingAssignment = assignment; - } - }); - - if (settingAssignment) { - var settingName = settingAssignment.value; - if (settingName && settingName !== '') { - var settingExt = settings[settingName]; - if (settingExt) { - replacement = settingExt.type; - } - } - } - } - - return replacement; - } -}; - var setCommandSpec = { name: "set", params: [ { name: "setting", - type: { - name: "selection", - getOptions: function(env) { - return env.settings.getSettingNames(); - } - }, + type: "setting", description: "The name of the setting to display or alter", defaultValue: null }, { name: "value", - type: valueDeferredType, + type: "settingValue", description: "The new value for the chosen setting", defaultValue: null } @@ -139,10 +100,7 @@ var unsetCommandSpec = { params: [ { name: "setting", - type: { - name: "selection", - pointer: "settings:index#getSettings" - }, + type: "setting", description: "The name of the setting to return to defaults" } ], diff --git a/plugins/pilot/lib/event_emitter.js b/plugins/pilot/lib/event_emitter.js index a458dd43..c7ddf1cd 100644 --- a/plugins/pilot/lib/event_emitter.js +++ b/plugins/pilot/lib/event_emitter.js @@ -37,7 +37,7 @@ define(function(require, exports, module) { -var lang = require("pilot/lang").lang; +var lang = require('pilot/lang').lang; var EventEmitter = {}; From 84a174f9d7fbf32ea751a3fbc9beb52d44a588b7 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Thu, 2 Dec 2010 10:59:19 +0000 Subject: [PATCH 65/90] make sure new settings and commands are registered properly --- plugins/pilot/lib/index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/pilot/lib/index.js b/plugins/pilot/lib/index.js index 1951c9fc..553e36d5 100644 --- a/plugins/pilot/lib/index.js +++ b/plugins/pilot/lib/index.js @@ -38,9 +38,13 @@ var deps = [ "pilot/fixoldbrowsers", "pilot/types/basic", + "pilot/types/command", + "pilot/types/settings", "pilot/canon", "pilot/commands/settings", - "pilot/settings/canon" + "pilot/settings/canon", + "pilot/cli", + "pilot/test/testCli" ]; var packages = deps.slice(); From e544ad30fc83d6e5172d9cb838330339f90492e1 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Thu, 2 Dec 2010 10:59:20 +0000 Subject: [PATCH 66/90] rename Type methods: s/toString/stringify and s/fromString/parse to avoid clash with built in meaning for toString. Also add lots of documentation, a new DeferredType, and lots more checks to how types are created --- plugins/pilot/lib/settings.js | 4 +- plugins/pilot/lib/types.js | 90 +++++++++++++++++++++-------- plugins/pilot/lib/types/basic.js | 97 +++++++++++++++++++++++--------- 3 files changed, 137 insertions(+), 54 deletions(-) diff --git a/plugins/pilot/lib/settings.js b/plugins/pilot/lib/settings.js index 1f7ed2ea..b427b2af 100644 --- a/plugins/pilot/lib/settings.js +++ b/plugins/pilot/lib/settings.js @@ -240,7 +240,7 @@ Settings.prototype = { if (data.hasOwnProperty(key)) { var setting = this._settings[key]; if (setting) { - var value = setting.type.fromString(data[key]); + var value = setting.type.parse(data[key]); this.set(key, value); } else { this.set(key, data[key]); @@ -254,7 +254,7 @@ Settings.prototype = { */ _saveToObject: function() { return this.getSettingNames().map(function(key) { - return this._settings[key].type.toString(this.get(key)); + return this._settings[key].type.stringify(this.get(key)); }.bind(this)); }, diff --git a/plugins/pilot/lib/types.js b/plugins/pilot/lib/types.js index d98fcaed..a0e76cd2 100644 --- a/plugins/pilot/lib/types.js +++ b/plugins/pilot/lib/types.js @@ -49,28 +49,41 @@ var Status = { */ VALID: 1, + /** + * The conversion process did not work like Status.INVALID, however it was + * noted that the string provided to 'parse()' could be VALID by the + * addition of more characters, so the typing may not be actually incorrect + * yet, just unfinished. + * @see Status.INVALID + */ + INCOMPLETE: 2, + /** * The conversion process did not work, the value should be null and a * reason for failure should have been provided. In addition some completion * values may be available. * @see Status.INCOMPLETE */ - INVALID: 2, + INVALID: 3, /** - * The conversion process did not work like Status.INVALID, however it was - * noted that the string provided to 'fromString()' could be VALID by - * the addition of more characters, so the typing may not be actually - * incorrect yet, just unfinished. - * @see Status.INVALID + * A combined status is the worser of the provided statuses */ - INCOMPLETE: 3 + combine: function(statuses) { + var combined = Status.VALID; + for (var i = 0; i < arguments; i++) { + if (arguments[i] > combined) { + combined = arguments[i]; + } + } + return combined; + } }; exports.Status = Status; /** - * The type.fromString() method returns a Conversion to inform the user about - * not only the result of a Conversion but also about what went wrong. + * The type.parse() method returns a Conversion to inform the user about not + * only the result of a Conversion but also about what went wrong. * We could use an exception, and throw if the conversion failed, but that * seems to violate the idea that exceptions should be exceptional. Typos are * not. Also in order to store both a status and a message we'd still need @@ -123,7 +136,7 @@ Type.prototype = { * Where possible, there should be round-tripping between values and their * string representations. */ - toString: function(value) { throw new Error("not implemented"); }, + stringify: function(value) { throw new Error("not implemented"); }, /** * Convert the given str to an instance of this type. @@ -131,7 +144,7 @@ Type.prototype = { * string representations. * @return Conversion */ - fromString: function(str) { throw new Error("not implemented"); }, + parse: function(str) { throw new Error("not implemented"); }, /** * The plug-in system, and other things need to know what this type is @@ -152,10 +165,35 @@ exports.Type = Type; var types = {}; /** - * Add a new type to the list available to the system + * Add a new type to the list available to the system. + * You can pass 2 things to this function - either an instance of Type, in + * which case we return this instance when #getType() is called with a 'name' + * that matches type.name. + * Also you can pass in a constructor (i.e. function) in which case when + * #getType() is called with a 'name' that matches Type.prototype.name we will + * pass the typeSpec into this constructor. See #reconstituteType(). */ exports.registerType = function(type) { - types[type.name] = type; + if (typeof type === 'object') { + if (type instanceof Type) { + if (!type.name) { + throw new Error('All registered types must have a name'); + } + types[type.name] = type; + } + else { + throw new Error('Can\'t registerType using: ' + type); + } + } + else if (typeof type === 'function') { + if (!type.prototype.name) { + throw new Error('All registered types must have a name'); + } + types[type.prototype.name] = type; + } + else { + throw new Error('Unknown type: ' + type); + } }; /** @@ -165,30 +203,34 @@ exports.deregisterType = function(type) { delete types[type.name]; }; +/** + * See description of #exports.registerType() + */ +function reconstituteType(name, typeSpec) { + var type = types[name]; + if (typeof type === 'function') { + // TODO: should we complain if typeSpec is a string? + type = new type(typeSpec); + } + return type; +} + /** * Find a type, previously registered using #registerType() */ exports.getType = function(typeSpec) { - var type; if (typeof typeSpec === 'string') { - type = types[typeSpec]; + return reconstituteType(typeSpec, typeSpec); } if (typeof typeSpec == 'object') { if (!typeSpec.name) { throw new Error('Missing \'name\' member to typeSpec'); } - - type = types[typeSpec.name]; + return reconstituteType(typeSpec.name, typeSpec); } - if (type instanceof Type) { - return type; - } - - if (typeof type === 'function') { - return type(typeSpec); - } + throw new Error('Can\'t extract type from ' + typeSpec); }; diff --git a/plugins/pilot/lib/types/basic.js b/plugins/pilot/lib/types/basic.js index f7ad2859..52b4c215 100644 --- a/plugins/pilot/lib/types/basic.js +++ b/plugins/pilot/lib/types/basic.js @@ -41,6 +41,7 @@ define(function(require, exports, module) { var types = require("pilot/types"); var Type = types.Type; var Conversion = types.Conversion; +var Status = types.Status; /** * These are the basic types that we accept. They are vaguely based on the @@ -59,13 +60,13 @@ var Conversion = types.Conversion; */ var text = new Type(); -text.toString = function(value) { +text.stringify = function(value) { return value; }; -text.fromString = function(value) { +text.parse = function(value) { if (typeof value != 'string') { - throw new Error('non-string passed to text.fromString()'); + throw new Error('non-string passed to text.parse()'); } return new Conversion(value); }; @@ -77,16 +78,16 @@ text.name = 'text'; */ var number = new Type(); -number.toString = function(value) { +number.stringify = function(value) { if (!value) { return null; } return '' + value; }; -number.fromString = function(value) { +number.parse = function(value) { if (typeof value != 'string') { - throw new Error('non-string passed to number.fromString()'); + throw new Error('non-string passed to number.parse()'); } var reply = new Conversion(parseInt(value, 10)); @@ -103,24 +104,29 @@ number.name = 'number'; /** * One of a known set of options */ -function SelectionType(data) { - this._data = data; +function SelectionType(typeSpec) { + if (!Array.isArray(typeSpec.data) && typeof typeSpec.data !== 'function') { + throw new Error('instances of SelectionType need typeSpec.data to be an array or function that returns an array:' + JSON.stringify(typeSpec)); + } + Object.keys(typeSpec).forEach(function(key) { + this[key] = typeSpec[key]; + }, this); }; SelectionType.prototype = new Type(); -SelectionType.prototype.toString = function(value) { +SelectionType.prototype.stringify = function(value) { return value; }; -SelectionType.prototype.fromString = function(value) { +SelectionType.prototype.parse = function(value) { if (typeof value != 'string') { - throw new Error('non-string passed to fromString()'); + throw new Error('non-string passed to parse()'); } - if (!this._data) { + if (!this.data) { throw new Error('Missing data on selection type extension.'); } - var data = (typeof(this._data) === "function") ? this._data() : this._data; + var data = (typeof(this.data) === "function") ? this.data() : this.data; var match = false; var completions = []; @@ -143,37 +149,70 @@ SelectionType.prototype.fromString = function(value) { // TODO: better completions - we're just using the extensions return new Conversion(null, status, - 'Can\'t convert "' + value + '" to a selection.', + 'Can\'t convert \'' + value + '\' to a selection.', completions); } }; SelectionType.prototype.name = 'selection'; +/** + * SelectionType is a base class for other types + */ +exports.SelectionType = SelectionType; /** * true/false values */ -var bool = new SelectionType([ 'true', 'false' ]); +var bool = new SelectionType({ + name: 'bool', + data: [ 'true', 'false' ], + stringify: function(value) { + return '' + value; + }, + parse: function(value) { + var conversion = SelectionType.prototype.parse(value); -bool.toString = function(value) { - return '' + value; + if (conversion.value === 'true') { + conversion.value = true; + } + if (conversion.value === 'false') { + conversion.value = false; + } + + return conversion; + } +}); + + +/** + * One of a known set of options + */ +function DeferredType(typeSpec) { + if (typeof typeSpec.defer !== 'function') { + throw new Error('Instances of DeferredType need typeSpec.defer to be a function that returns a type'); + } + Object.keys(typeSpec).forEach(function(key) { + this[key] = typeSpec[key]; + }, this); }; -bool.fromString = function(value) { - var conversion = SelectionType.prototype.fromString(value); +DeferredType.prototype = new Type(); - if (conversion.value === 'true') { - conversion.value = true; - } - if (conversion.value === 'false') { - conversion.value = false; - } - - return conversion; +DeferredType.prototype.stringify = function(value) { + return this.defer.stringify(value); }; -bool.name = 'bool'; +DeferredType.prototype.parse = function(value) { + return this.defer.parse(value); +}; + +DeferredType.prototype.name = 'deferred'; + +/** + * DeferredType is a base class for other types + */ +exports.DeferredType = DeferredType; /** * Registration and de-registration. @@ -183,6 +222,7 @@ exports.startup = function() { types.registerType(number); types.registerType(bool); types.registerType(SelectionType); + types.registerType(DeferredType); }; exports.shutdown = function() { @@ -190,6 +230,7 @@ exports.shutdown = function() { types.unregisterType(number); types.unregisterType(bool); types.unregisterType(SelectionType); + types.unregisterType(DeferredType); }; From c3d74828dcaf8f63cbac7f2e81b26cc454fc7c00 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Thu, 2 Dec 2010 10:59:20 +0000 Subject: [PATCH 67/90] new arrayRemove method --- plugins/pilot/lib/util.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/plugins/pilot/lib/util.js b/plugins/pilot/lib/util.js index 5a138a20..e0cd4bb3 100644 --- a/plugins/pilot/lib/util.js +++ b/plugins/pilot/lib/util.js @@ -36,7 +36,7 @@ * ***** END LICENSE BLOCK ***** */ define(function(require, exports, module) { - + /** * Create an object representing a de-serialized query section of a URL. * Query keys with multiple values are returned in an array. @@ -656,4 +656,16 @@ exports.rectsEqual = function(r1, r2, delta) { return true; }; +/** + * splice out of 'array' anything that === 'value' + */ +exports.arrayRemove = function(array, value) { + for (var i = 0; i <= array.length; i++) { + if (value === array[i]) { + array.splice(i, 1); + } + } +}; + + }); From d0fc416e01695d71fc2bb4570349e34f4ad341b4 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Thu, 2 Dec 2010 10:59:20 +0000 Subject: [PATCH 68/90] addition of a new commandType that we use to generate completion hints --- plugins/pilot/lib/types/command.js | 82 ++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 plugins/pilot/lib/types/command.js diff --git a/plugins/pilot/lib/types/command.js b/plugins/pilot/lib/types/command.js new file mode 100644 index 00000000..b53fc19d --- /dev/null +++ b/plugins/pilot/lib/types/command.js @@ -0,0 +1,82 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Joe Walker (jwalker@mozilla.com) + * Kevin Dangoor (kdangoor@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +var canon = require("pilot/canon"); +var SelectionType = require("pilot/types/basic").SelectionType; +var types = require("pilot/types"); + + +/** + * Select from the available commands + */ +var command = new SelectionType({ + name: 'command', + data: function() { + return canon.getCommandNames(); + }, + stringify: function(command) { + return command.name; + }, + parse: function(value) { + var conversion = SelectionType.prototype.parse.call(this, value); + if (conversion.value) { + conversion.value = canon.getCommand(conversion.value); + } + else { + conversion.message = 'Several possibilities for \'' + value + '\''; + } + return conversion; + } +}); + + +/** + * Registration and de-registration. + */ +exports.startup = function() { + types.registerType(command); +}; + +exports.shutdown = function() { + types.unregisterType(command); +}; + + +}); From 5ba1d3f75e97e8d54ab61a99639dcdbb217b6860 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Thu, 2 Dec 2010 11:00:15 +0000 Subject: [PATCH 69/90] Move types from commands/settings.js into types/settings.js --- plugins/pilot/lib/types/settings.js | 100 ++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 plugins/pilot/lib/types/settings.js diff --git a/plugins/pilot/lib/types/settings.js b/plugins/pilot/lib/types/settings.js new file mode 100644 index 00000000..7a7ba881 --- /dev/null +++ b/plugins/pilot/lib/types/settings.js @@ -0,0 +1,100 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Joe Walker (jwalker@mozilla.com) + * Kevin Dangoor (kdangoor@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +var SelectionType = require("pilot/types/basic").SelectionType; +var DeferredType = require("pilot/types/basic").DeferredType; +var types = require("pilot/types"); + + +/** + * EVIL: This relies on us using settingValue in the same event as setting + * The alternative is to have some central place where we store the current + * command line, but this might be a lesser evil for now. + */ +var lastSetting; + +/** + * Select from the available settings + */ +var setting = new SelectionType({ + name: 'setting', + data: function() { + return env.settings.getSettingNames(); + }, + stringify: function(value) { + lastSetting = value; + return SelectionType.prototype.stringify.call(this, value); + }, + parse: function(value) { + lastSetting = value; + return SelectionType.prototype.parse.call(this, value); + } +}); + +/** + * Something of a hack to allow the set command to give a clearer definition + * of the type to the command line. + */ +var settingValue = new DeferredType({ + name: "settingValue", + defer: function() { + return env.settings.getSetting(lastSetting).type; + } +}); + +var env; + +/** + * Registration and de-registration. + */ +exports.startup = function(data, reason) { + // TODO: this is probably all kinds of evil, but we need something working + env = data.env; + types.registerType(setting); + types.registerType(settingValue); +}; + +exports.shutdown = function(data, reason) { + types.unregisterType(setting); + types.unregisterType(settingValue); +}; + + +}); From 59794db155c6a6386ab550c9764d2c253cf59c2e Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Thu, 2 Dec 2010 12:22:50 +0000 Subject: [PATCH 70/90] convert Assignment from using plain text to using an Argument --- plugins/pilot/lib/cli.js | 64 +++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/plugins/pilot/lib/cli.js b/plugins/pilot/lib/cli.js index 928af610..9d8421ba 100644 --- a/plugins/pilot/lib/cli.js +++ b/plugins/pilot/lib/cli.js @@ -41,16 +41,13 @@ define(function(require, exports, module) { var console = require('pilot/console'); var util = require('pilot/util'); var oop = require('pilot/oop').oop; +var EventEmitter = require('pilot/event_emitter').EventEmitter; //var keyboard = require('keyboard/keyboard'); var Status = require('pilot/types').Status; var canon = require('pilot/canon'); var types = require('pilot/types'); -var commandType; -exports.startup = function(data, reason) { - commandType = types.getType('command'); -}; /** * The information required to tell the user there is a problem with their @@ -113,6 +110,10 @@ Argument.prototype = { this.text + following.priorSpace + following.text, this.start, following.end, this.priorSpace); + }, + + setText: function(text) { + this.text = text; } }; /** @@ -202,7 +203,9 @@ Input.prototype = { var command = _split(args); if (!command) { + // TODO: Should we use this technique in split? // No command found - bail helpfully. + var commandType = types.getType('command'); var conversion = commandType.parse(typed); var arg = Argument.mergeAll(args); this._addHint(new ConversionHint(conversion, arg)); @@ -218,14 +221,18 @@ Input.prototype = { this.requisition.setCommand(command); this._assign(args); - this.addHints(this.requisition.getHints()); + this._addHint(this.requisition.getHints()); } }, /** - * Some sugar around: 'this.hints.push(new Hint(...));' + * Some sugar around: 'this.hints.push(new Hint(...));', but you can also + * pass in an array of Hints or the parameters to create a hint */ _addHint: function(status, message, start, end) { + if (status == null) { + return; + } if (status instanceof Hint) { this.hints.push(status); } @@ -270,7 +277,7 @@ Input.prototype = { if (this.requisition.assignmentCount == 1) { var assignment = this.requisition.getAssignment(0); if (assignment.param.type.name === 'text') { - assignment.setText(Argument.mergeAll(args).text); + assignment.setArgument(Argument.mergeAll(args)); return; } } @@ -305,7 +312,7 @@ Input.prototype = { args[i]); } else { args.splice(i + 1, 1); - assignment.setText(args[i + 1].text); + assignment.setArgument(args[i + 1]); } } @@ -326,7 +333,7 @@ Input.prototype = { else { var arg = args[i]; args.splice(i, 1); - assignment.setText(arg.text); + assignment.setArgument(arg); } i++; @@ -358,7 +365,7 @@ function _tokenize(typed) { // We are generally converting to their real values except for \', \" // and '\ ' which we are converting to unicode private characters so we // can distinguish them from ', " and ' ', which have special meaning. - // They need swapping back post-split. + // They need swapping back post-split - see unescape() typed = typed .replace(/\\\\/g, '\\') .replace(/\\b/g, '\b') @@ -373,6 +380,13 @@ function _tokenize(typed) { .replace(/\\'/g, '\uF001') .replace(/\\"/g, '\uF002'); + function unescape(str) { + return str + .replace(/\uF000/g, ' ') + .replace(/\uF001/g, '\'') + .replace(/\uF002/g, '"'); + } + var i = 0; var start = 0; // Where did this section start? var priorSpace = ''; @@ -382,7 +396,7 @@ function _tokenize(typed) { if (i >= typed.length) { // There is no more - tidy up if (mode !== OUTSIDE) { - var str = typed.substring(start, i); + var str = unescape(typed.substring(start, i)); args.push(new Argument(str, start, i, priorSpace)); } break; @@ -415,7 +429,7 @@ function _tokenize(typed) { // There is an edge case of xx'xx which we are assuming to be // a single parameter (and same with ") if (c === ' ') { - var str = typed.substring(start, i); + var str = unescape(typed.substring(start, i)); args.push(new Argument(str, start, i, priorSpace)); mode = OUTSIDE; start = i; @@ -425,7 +439,7 @@ function _tokenize(typed) { case IN_SINGLE_Q: if (c === '\'') { - var str = typed.substring(start, i); + var str = unescape(typed.substring(start, i)); args.push(new Argument(str, start, i, priorSpace)); mode = OUTSIDE; start = i + 1; @@ -435,7 +449,7 @@ function _tokenize(typed) { case IN_DOUBLE_Q: if (c === '"') { - var str = typed.substring(start, i); + var str = unescape(typed.substring(start, i)); args.push(new Argument(str, start, i, priorSpace)); mode = OUTSIDE; start = i + 1; @@ -447,13 +461,6 @@ function _tokenize(typed) { i++; } - args.forEach(function(arg) { - arg.text = arg.text - .replace(/\uF000/g, ' ') - .replace(/\uF001/g, '\'') - .replace(/\uF002/g, '"'); - }); - return args; } exports._tokenize = _tokenize; @@ -724,7 +731,10 @@ Assignment.prototype = { if (value === undefined) { value = this.param.defaultValue; } - this.text = (value === null) ? '' : this.param.type.stringify(value); + var text = (value === null) ? '' : this.param.type.stringify(value); + if (this.arg) { + this.arg.setText(text); + } this.value = value; this.status = Status.VALID; this.message = ''; @@ -735,13 +745,13 @@ Assignment.prototype = { * The textual representation of the current value * @readonly - use setValue() to mutate */ - text: undefined, - setText: function(text) { - if (this.text === text) { + arg: undefined, + setArgument: function(arg) { + if (this.arg === arg) { return; } - var conversion = this.param.type.parse(text); - this.text = text; + var conversion = this.param.type.parse(arg.text); + this.arg = arg; this.value = conversion.value; this.status = conversion.status; this.message = conversion.message; From f8af72dd0798040f0888fa4479264c0ccd0f3a95 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Thu, 2 Dec 2010 12:43:11 +0000 Subject: [PATCH 71/90] fix hints, now all cli tests pass --- plugins/pilot/lib/cli.js | 35 +++++++++++++++++++++---------- plugins/pilot/lib/test/testCli.js | 3 +-- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/plugins/pilot/lib/cli.js b/plugins/pilot/lib/cli.js index 9d8421ba..a747678f 100644 --- a/plugins/pilot/lib/cli.js +++ b/plugins/pilot/lib/cli.js @@ -44,9 +44,10 @@ var oop = require('pilot/oop').oop; var EventEmitter = require('pilot/event_emitter').EventEmitter; //var keyboard = require('keyboard/keyboard'); -var Status = require('pilot/types').Status; -var canon = require('pilot/canon'); var types = require('pilot/types'); +var Status = require('pilot/types').Status; +var Conversion = require('pilot/types').Conversion; +var canon = require('pilot/canon'); /** @@ -662,7 +663,14 @@ Requisition.prototype = { * Collect the statuses from the Assignments */ getHints: function() { - + var hints = []; + Object.keys(this._assignments).map(function(name) { + var hint = this._assignments[name].getHint(); + if (hint) { + hints.push(hint); + } + }, this); + return hints; }, /** @@ -736,8 +744,7 @@ Assignment.prototype = { this.arg.setText(text); } this.value = value; - this.status = Status.VALID; - this.message = ''; + this.conversion = new Conversion(value, Status.VALID, '', []); //this._dispatchEvent('change', { assignment: this }); }, @@ -750,20 +757,26 @@ Assignment.prototype = { if (this.arg === arg) { return; } - var conversion = this.param.type.parse(arg.text); this.arg = arg; - this.value = conversion.value; - this.status = conversion.status; - this.message = conversion.message; + this.conversion = this.param.type.parse(arg.text); + this.value = this.conversion.value; //this._dispatchEvent('change', { assignment: this }); }, + getHint: function() { + if (this.conversion.status === Status.VALID && + this.conversion.message === '') { + return undefined; + } + + return new ConversionHint(this.conversion, this.arg); + }, + /** * Report on the status of the last parse() conversion. * @see types.Conversion */ - status: undefined, - message: undefined + conversion: undefined }; oop.implement(Assignment, EventEmitter); exports.Assignment = Assignment; diff --git a/plugins/pilot/lib/test/testCli.js b/plugins/pilot/lib/test/testCli.js index 875a8f04..b6d2223b 100644 --- a/plugins/pilot/lib/test/testCli.js +++ b/plugins/pilot/lib/test/testCli.js @@ -169,11 +169,10 @@ exports.testInput = function() { test.verifyEqual('set', input.requisition.command.name); input.parse('set h'); -console.log(input); test.verifyEqual(1, input.hints.length); test.verifyEqual(Status.INCOMPLETE, input.hints[0].status); test.verifyEqual('set', input.requisition.command.name); - test.verifyEqual('h', input.requisition.getAssignment('setting').text); + test.verifyEqual('h', input.requisition.getAssignment('setting').arg.text); test.verifyEqual(undefined, input.requisition.getAssignment('setting').value); return "testInput Completed"; From 3dbb9d4c65fc3eef0b26c3193f852aa177602ce3 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Fri, 3 Dec 2010 15:38:13 +0000 Subject: [PATCH 72/90] Have Status use string constants in place of numbers for easy debugging for now --- plugins/pilot/lib/types.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/pilot/lib/types.js b/plugins/pilot/lib/types.js index a0e76cd2..0452b0a6 100644 --- a/plugins/pilot/lib/types.js +++ b/plugins/pilot/lib/types.js @@ -40,6 +40,7 @@ define(function(require, exports, module) { /** * Some types can detect validity, that is to say they can distinguish between * valid and invalid values. + * TODO: Change these constants to be numbers for more performance? */ var Status = { /** @@ -47,7 +48,7 @@ var Status = { * valid. There are a number of failure states, so the best way to check * for failure is (x !== Status.VALID) */ - VALID: 1, + VALID: 'VALID', /** * The conversion process did not work like Status.INVALID, however it was @@ -56,7 +57,7 @@ var Status = { * yet, just unfinished. * @see Status.INVALID */ - INCOMPLETE: 2, + INCOMPLETE: 'INCOMPLETE', /** * The conversion process did not work, the value should be null and a @@ -64,7 +65,7 @@ var Status = { * values may be available. * @see Status.INCOMPLETE */ - INVALID: 3, + INVALID: 'INVALID', /** * A combined status is the worser of the provided statuses From 2c4bfd431010e02eb4d095fa992a59017da70ae9 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Fri, 3 Dec 2010 15:38:14 +0000 Subject: [PATCH 73/90] Lots of work to flesh out the cli test suite --- plugins/pilot/lib/test/testCli.js | 161 +++++++++++++++++++++++++----- 1 file changed, 137 insertions(+), 24 deletions(-) diff --git a/plugins/pilot/lib/test/testCli.js b/plugins/pilot/lib/test/testCli.js index b6d2223b..1b69c78e 100644 --- a/plugins/pilot/lib/test/testCli.js +++ b/plugins/pilot/lib/test/testCli.js @@ -41,11 +41,12 @@ define(function(require, exports, module) { var test = require('pilot/test/assert').test; var cli = require('pilot/cli'); var Status = require('pilot/types').Status; +var settings = require('pilot/settings').settings; exports.testAll = function() { exports.testTokenize(); exports.testSplit(); - exports.testInput(); + exports.testCli(); return "testAll Completed"; }; @@ -142,40 +143,152 @@ exports.testTokenize = function() { return "testTokenize Completed"; }; -exports.testInput = function() { - var input = new cli.Input(); +var hints; +var hint0; +var requisition; +var sel = { start: -1, end: -1 }; +var settingAssignment; +var valueAssignment; +mockCliUi = { + getSelection: function() { + return sel; + }, + + setHints: function(h) { + hints = h; + hint0 = (h.length !== 0) ? h[0] : undefined; + + if (requisition && requisition.command && requisition.command.name === 'set') { + settingAssignment = requisition.getAssignment('setting'); + valueAssignment = requisition.getAssignment('value'); + } + else { + settingAssignment = undefined; + valueAssignment = undefined; + } + }, + + setRequisition: function(r) { + requisition = r; + } +}; + +exports.testCli = function() { + var historyLengthSetting = settings.getSetting('historyLength'); + + var input = new cli.Cli(mockCliUi); + input.parse(''); + test.verifyEqual(1, hints.length); + test.verifyEqual(Status.INCOMPLETE, hint0.status); + test.verifyEqual(0, hint0.start); + test.verifyEqual(0, hint0.end); + test.verifyNull(requisition.command); - test.verifyEqual(1, input.hints.length); - test.verifyEqual(Status.INCOMPLETE, input.hints[0].status); - test.verifyNull(input.requisition.command); - + sel.start = sel.end = 1; input.parse('s'); - test.verifyEqual(1, input.hints.length); - test.verifyEqual(Status.INCOMPLETE, input.hints[0].status); - test.verifyNotEqual(-1, input.hints[0].message.indexOf('possibilities')); - test.verifyTrue(input.hints[0].predictions.length > 0); + test.verifyEqual(1, hints.length); + test.verifyEqual(Status.INCOMPLETE, hint0.status); + test.verifyNotEqual(-1, hint0.message.indexOf('possibilities')); + test.verifyEqual(0, hint0.start); + test.verifyEqual(1, hint0.end); + test.verifyTrue(hint0.predictions.length > 0); // This is slightly fragile because it depends on the configuration - test.verifyTrue(input.hints[0].predictions.length < 20); - test.verifyNotEqual(-1, input.hints[0].predictions.indexOf('set')); - test.verifyNull(input.requisition.command); + test.verifyTrue(hint0.predictions.length < 20); + test.verifyNotEqual(-1, hint0.predictions.indexOf('set')); + test.verifyNull(requisition.command); input.parse('set'); - test.verifyEqual(1, input.hints.length); - test.verifyEqual('set', input.requisition.command.name); + test.verifyEqual(1, hints.length); + test.verifyEqual(Status.VALID, hint0.status); + test.verifyEqual(0, hint0.start); + test.verifyEqual(3, hint0.end); + test.verifyEqual('set', requisition.command.name); input.parse('set '); - test.verifyEqual(1, input.hints.length); - test.verifyEqual('set', input.requisition.command.name); + test.verifyEqual(1, hints.length); + test.verifyEqual(Status.VALID, hint0.status); + test.verifyEqual(0, hint0.start); + // Technically the command ends at 3, but we're returning 4 currently. + // This is caused by us using the whole input to determine the length. + // Maybe one day we should fix this? + //test.verifyEqual(3, hint0.end); + test.verifyEqual('set', requisition.command.name); + sel.start = sel.end = 5; input.parse('set h'); - test.verifyEqual(1, input.hints.length); - test.verifyEqual(Status.INCOMPLETE, input.hints[0].status); - test.verifyEqual('set', input.requisition.command.name); - test.verifyEqual('h', input.requisition.getAssignment('setting').arg.text); - test.verifyEqual(undefined, input.requisition.getAssignment('setting').value); + test.verifyEqual(1, hints.length); + test.verifyEqual(Status.INCOMPLETE, hint0.status); + test.verifyTrue(hint0.predictions.length > 0); + test.verifyEqual(4, hint0.start); + test.verifyEqual(5, hint0.end); + test.verifyNotEqual(-1, hint0.predictions.indexOf('historyLength')); + test.verifyEqual('set', requisition.command.name); + test.verifyEqual('h', settingAssignment.arg.text); + test.verifyEqual(undefined, settingAssignment.value); - return "testInput Completed"; + sel.start = sel.end = 16; + input.parse('set historyLengt'); + test.verifyEqual(1, hints.length); + test.verifyEqual(Status.INCOMPLETE, hint0.status); + test.verifyEqual(1, hint0.predictions.length); + test.verifyEqual(4, hint0.start); + test.verifyEqual(16, hint0.end); + test.verifyEqual('historyLength', hint0.predictions[0]); + test.verifyEqual('set', requisition.command.name); + test.verifyEqual('historyLengt', settingAssignment.arg.text); + test.verifyEqual(undefined, settingAssignment.value); + + sel.start = sel.end = 1; + input.parse('set historyLengt'); + test.verifyEqual(1, hints.length); + test.verifyEqual(Status.INVALID, hint0.status); + test.verifyEqual(4, hint0.start); + test.verifyEqual(16, hint0.end); + test.verifyEqual(1, hint0.predictions.length); + test.verifyEqual('historyLength', hint0.predictions[0]); + test.verifyEqual('set', requisition.command.name); + test.verifyEqual('historyLengt', settingAssignment.arg.text); + test.verifyEqual(undefined, settingAssignment.value); + + sel.start = sel.end = 17; + input.parse('set historyLengt '); + test.verifyEqual(1, hints.length); + test.verifyEqual(Status.INVALID, hint0.status); + test.verifyEqual(4, hint0.start); + test.verifyEqual(16, hint0.end); + test.verifyEqual(1, hint0.predictions.length); + test.verifyEqual('historyLength', hint0.predictions[0]); + test.verifyEqual('set', requisition.command.name); + test.verifyEqual('historyLengt', settingAssignment.arg.text); + test.verifyEqual(undefined, settingAssignment.value); + + input.parse('set historyLength'); + test.verifyEqual(0, hints.length); + test.verifyEqual('set', requisition.command.name); + test.verifyEqual('historyLength', settingAssignment.arg.text); + test.verifyEqual(historyLengthSetting, settingAssignment.value); + + input.parse('set historyLength '); + test.verifyEqual(0, hints.length); + test.verifyEqual('set', requisition.command.name); + test.verifyEqual('historyLength', settingAssignment.arg.text); + test.verifyEqual(historyLengthSetting, settingAssignment.value); + + input.parse('set historyLength 6'); + test.verifyEqual(0, hints.length); + test.verifyEqual('set', requisition.command.name); + test.verifyEqual('historyLength', settingAssignment.arg.text); + test.verifyEqual(historyLengthSetting, settingAssignment.value); + test.verifyEqual('6', valueAssignment.arg.text); + test.verifyEqual(6, valueAssignment.value); + test.verifyEqual('number', typeof valueAssignment.value); + + // TODO: Add test to see that a command without mandatory param causes INVALID + + console.log(input); + + return "testCli Completed"; }; window.testCli = exports; From 0930c37675928ad3abe9c963d776f711dcd0ea92 Mon Sep 17 00:00:00 2001 From: Joe Walker Date: Fri, 3 Dec 2010 15:38:35 +0000 Subject: [PATCH 74/90] Rename Input to Cli. Extract CliUi as an interface. Add knowledge of cursor positioning to convert INCOMPLETE hints to INVALID if the cursor isnt in that hint. Many tidyups and tweaks as we create a test suite --- plugins/pilot/lib/cli.js | 169 +++++++++++++++++++++++++++------------ 1 file changed, 117 insertions(+), 52 deletions(-) diff --git a/plugins/pilot/lib/cli.js b/plugins/pilot/lib/cli.js index a747678f..b7bb1419 100644 --- a/plugins/pilot/lib/cli.js +++ b/plugins/pilot/lib/cli.js @@ -97,7 +97,7 @@ oop.inherits(ConversionHint, Hint); * @constructor */ function Argument(text, start, end, priorSpace) { - this.text = text; + this.setText(text); this.start = start; this.end = end; this.priorSpace = priorSpace; @@ -114,26 +114,55 @@ Argument.prototype = { }, setText: function(text) { + if (text == null) { + throw new Error('Illegal text for Argument: ' + text); + } this.text = text; } }; /** * Merge an array of arguments into a single argument. */ -Argument.mergeAll = function(argArray) { +Argument.merge = function(argArray, start, end) { + start = (start === undefined) ? 0 : start; + end = (end === undefined) ? argArray.length : end; + var joined; - argArray.forEach(function(arg) { + for (var i = start; i < end; i++) { + var arg = argArray[i]; if (!joined) { joined = arg; } else { joined = joined.merge(arg); } - }); + } return joined; }; +/** + * CLI / UI Interface + * The Cli interacts with the UI via an instance of CliUi. + * This implementation is designed as a template rather than to be used. + * It is expected that we will have a number of implementations of this: + * - A firebug/webkit inspector cli shim + * - A simple input[type=text] version + * - A possible Cloud9 UI version + * - A possible Skywriter UI version + * This class will probably need refactoring as time goes on. + * + * TODO: Who should own the Requisition? + */ +function CliUi() { +} +CliUi.prototype = { + getSelection: function() {}, + setHints: function() {}, + setRequisition: function() {} +}; + + /** * An object used during command line parsing to hold the various intermediate * data steps. @@ -143,7 +172,7 @@ Argument.mergeAll = function(argArray) { *

    The other output value is input.requisition which gives access to an * args object for use in executing the final command. * - * The majority of the functions in this class are called in sequence by the + *

    The majority of the functions in this class are called in sequence by the * constructor. Their task is to add to hints fill out the requisition. *

    The general sequence is:

    */ - _assign: function(args) { + CliRequisition.prototype._assign = function(args) { if (args.length === 0) { - this.requisition.setDefaultValues(); + this.setDefaultValues(); return; } // Create an error if the command does not take parameters, but we have // been given them ... - if (this.requisition.assignmentCount === 0) { + if (this.assignmentCount === 0) { // TODO: previously we were doing some extra work to avoid this if // we determined that we had args that were all whitespace, but // probably given our tighter tokenize() this won't be an issue? this._addHint(Status.INVALID, - this.requisition.command.name + ' does not take any parameters', + this.command.name + ' does not take any parameters', Argument.merge(args)); return; } // Special case: if there is only 1 parameter, and that's of type // text we put all the params into the first param - if (this.requisition.assignmentCount == 1) { - var assignment = this.requisition.getAssignment(0); + if (this.assignmentCount == 1) { + var assignment = this.getAssignment(0); if (assignment.param.type.name === 'text') { assignment.setArgument(Argument.merge(args)); return; } } - var assignments = this.requisition.cloneAssignments(); - var names = this.requisition.getParameterNames(); + var assignments = this.cloneAssignments(); + var names = this.getParameterNames(); // Extract all the named parameters var used = []; @@ -376,7 +554,7 @@ Cli.prototype = { // What's left are positional parameters assign in order names.forEach(function(name) { - var assignment = this.requisition.getAssignment(name); + var assignment = this.getAssignment(name); if (args.length === 0) { // No more values assignment.setValue(undefined); // i.e. default @@ -394,9 +572,10 @@ Cli.prototype = { 'Input \'' + remaining.text + '\' makes no sense.', remaining); } - } -}; -exports.Cli = Cli; + }; + +})(); +exports.CliRequisition = CliRequisition; /** * Split up the input taking into account ' and " @@ -637,214 +816,6 @@ function documentCommand(command) { exports.documentCommand = documentCommand; -/** - * A Requisition collects the information needed to execute a command. - * There is no point in a requisition for parameter-less commands because there - * is no information to collect. A Requisition is a collection of assignments - * of values to parameters, each handled by an instance of Assignment. - * @constructor - */ -function Requisition() { -} -Requisition.prototype = { - /** - * The command that we are about to execute. - * @readonly - */ - command: undefined, - - /** - * The count of assignments - * @readonly - */ - assignmentCount: undefined, - - /** - * Set a new command. We make no attempt to convert the args in the old - * command to args in the new command. The assignments need to be - * re-entered. - */ - setCommand: function(command) { - if (this.command === command) { - return; - } - - this.command = command; - this._assignments = {}; - - if (command) { - command.params.forEach(function(param) { - this._assignments[param.name] = new Assignment(param); - }, this); - } - - this.assignmentCount = Object.keys(this._assignments); - }, - - /** - * Assignments have an order, so we need to store them in an array. - * But we also need named access ... - */ - getAssignment: function(nameOrNumber) { - var name = (typeof nameOrNumber === 'string') ? - nameOrNumber : - Object.keys(this._assignments)[nameOrNumber]; - return this._assignments[name]; - }, - - /** - * Where parameter name == assignment names - they are the same. - */ - getParameterNames: function() { - return Object.keys(this._assignments); - }, - - /** - * A *shallow* clone of the assignments. - * This is useful for systems that wish to go over all the assignments - * finding values one way or another and wish to trim an array as they go. - */ - cloneAssignments: function() { - return Object.keys(this._assignments).map(function(name) { - return this._assignments[name]; - }, this); - }, - - /** - * Collect the statuses from the Assignments - */ - getHints: function() { - var hints = []; - Object.keys(this._assignments).map(function(name) { - // Append the assignments hints to our list - hints.push.apply(hints, this._assignments[name].getHints()); - }, this); - return hints; - }, - - /** - * Extract the names and values of all the assignments, and return as - * an object. - */ - getArgs: function() { - var args = {}; - Object.keys(this._assignments).forEach(function(name) { - args[name] = getCommand(name); - }, this); - return args; - }, - - /** - * Reset all the assignments to their default values - */ - setDefaultValues: function() { - Object.keys(this._assignments).forEach(function(name) { - this._assignments[name].setValue(undefined); - }, this); - }, - - /** - * Helper to call canon.exec - */ - exec: function() { - exports.exec(this.command, this.getArgs()); - } -}; -exports.Requisition = Requisition; - - -/** - * A link between a parameter and the data for that parameter. - * The data for the parameter is available as in the preferred type and as - * an Argument for the CLI. - *

    We also record validity information where applicable. - *

    For values, null and undefined have distinct definitions. null means - * that a value has been provided, undefined means that it has not. - * Thus, null is a valid default value, and common because it identifies an - * parameter that is optional. undefined means there is no value from - * the command line. - * @constructor - */ -function Assignment(param) { - this.param = param; - this.setValue(param.defaultValue); -}; -Assignment.prototype = { - /** - * The parameter that we are assigning to - * @readonly - */ - param: undefined, - - /** - * The current value (i.e. not the string representation) - * Use setValue() to mutate - */ - value: undefined, - setValue: function(value) { - if (this.value === value) { - return; - } - if (value === undefined) { - value = this.param.defaultValue; - } - this.value = value; - - var text = (value == null) ? '' : this.param.type.stringify(value); - if (this.arg) { - this.arg.setText(text); - } - - this.conversion = undefined; - //this._dispatchEvent('change', { assignment: this }); - }, - - /** - * The textual representation of the current value - * Use setValue() to mutate - */ - arg: undefined, - setArgument: function(arg) { - if (this.arg === arg) { - return; - } - this.arg = arg; - this.conversion = this.param.type.parse(arg.text); - this.value = this.conversion.value; - //this._dispatchEvent('change', { assignment: this }); - }, - - /** - * Create a list of this hints associated with this parameter assignment - */ - getHints: function() { - var hints = []; - if (this.conversion != null && - (this.conversion.status !== Status.VALID || - this.conversion.message)) { - hints.push(new ConversionHint(this.conversion, this.arg)); - } - - var argProvided = this.arg != null && this.arg.text !== ''; - var dataProvided = this.value !== undefined || argProvided; - - if (this.param.defaultValue === undefined && !dataProvided) { - // If the there is no data provided, we have no start/end. Use -1 - hints.push(new Hint(Status.INVALID, - 'Argument for ' + param.name + ' is required' - -1, -1)); - } - return hints; - }, - - /** - * Report on the status of the last parse() conversion. - * @see types.Conversion - */ - conversion: undefined -}; -oop.implement(Assignment, EventEmitter); -exports.Assignment = Assignment; }); diff --git a/plugins/cockpit/lib/index.js b/plugins/cockpit/lib/index.js new file mode 100644 index 00000000..beacc28f --- /dev/null +++ b/plugins/cockpit/lib/index.js @@ -0,0 +1,59 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Kevin Dangoor (kdangoor@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +exports.startup = function(data, reason) { + + window.testCli = require('cockpit/test/testCli'); + + var plain = require('cockpit/ui/plain'); + plain.startup(data, reason); + +}; + +/* +exports.shutdown(data, reason) { + deps.forEach(function(dep) { + var module = require(dep); + if (typeof module.shutdown === "function") { + module.shutdown(data, reason); + } + }); +}; +*/ +}); diff --git a/plugins/pilot/lib/test/assert.js b/plugins/cockpit/lib/test/assert.js similarity index 100% rename from plugins/pilot/lib/test/assert.js rename to plugins/cockpit/lib/test/assert.js diff --git a/plugins/pilot/lib/test/testCli.js b/plugins/cockpit/lib/test/testCli.js similarity index 78% rename from plugins/pilot/lib/test/testCli.js rename to plugins/cockpit/lib/test/testCli.js index 1b69c78e..bace956e 100644 --- a/plugins/pilot/lib/test/testCli.js +++ b/plugins/cockpit/lib/test/testCli.js @@ -38,10 +38,13 @@ define(function(require, exports, module) { -var test = require('pilot/test/assert').test; -var cli = require('pilot/cli'); +var test = require('cockpit/test/assert').test; var Status = require('pilot/types').Status; var settings = require('pilot/settings').settings; +var tokenize = require('cockpit/cli')._tokenize; +var split = require('cockpit/cli')._split; +var CliRequisition = require('cockpit/cli').CliRequisition; + exports.testAll = function() { exports.testTokenize(); @@ -50,41 +53,18 @@ exports.testAll = function() { return "testAll Completed"; }; -exports.testSplit = function() { - var args = cli._tokenize('s'); - var command = cli._split(args); - test.verifyEqual(1, args.length); - test.verifyEqual('s', args[0].text); - test.verifyUndefined(command); - - var args = cli._tokenize('set'); - var command = cli._split(args); - test.verifyEqual([], args); - test.verifyEqual('set', command.name); - - var args = cli._tokenize('set a b'); - var command = cli._split(args); - test.verifyEqual('set', command.name); - test.verifyEqual(2, args.length); - test.verifyEqual('a', args[0].text); - test.verifyEqual('b', args[1].text); - - // TODO: add tests for sub commands - return "testSplit Completed"; -}; - exports.testTokenize = function() { - var args = cli._tokenize(''); + var args = tokenize(''); test.verifyEqual(0, args.length); - args = cli._tokenize('s'); + args = tokenize('s'); test.verifyEqual(1, args.length); test.verifyEqual('s', args[0].text); test.verifyEqual(0, args[0].start); test.verifyEqual(1, args[0].end); test.verifyEqual('', args[0].priorSpace); - args = cli._tokenize('s s'); + args = tokenize('s s'); test.verifyEqual(2, args.length); test.verifyEqual('s', args[0].text); test.verifyEqual(0, args[0].start); @@ -95,7 +75,7 @@ exports.testTokenize = function() { test.verifyEqual(3, args[1].end); test.verifyEqual(' ', args[1].priorSpace); - args = cli._tokenize(' 1234 \'12 34\''); + args = tokenize(' 1234 \'12 34\''); test.verifyEqual(2, args.length); test.verifyEqual('1234', args[0].text); test.verifyEqual(1, args[0].start); @@ -106,7 +86,7 @@ exports.testTokenize = function() { test.verifyEqual(13, args[1].end); test.verifyEqual(' ', args[1].priorSpace); - args = cli._tokenize('12\'34 "12 34" \\'); // 12'34 "12 34" \ + args = tokenize('12\'34 "12 34" \\'); // 12'34 "12 34" \ test.verifyEqual(3, args.length); test.verifyEqual('12\'34', args[0].text); test.verifyEqual(0, args[0].start); @@ -121,7 +101,7 @@ exports.testTokenize = function() { test.verifyEqual(15, args[2].end); test.verifyEqual(' ', args[2].priorSpace); - args = cli._tokenize('a\\ b \\t\\n\\r \\\'x\\\" \'d'); // a_b \t\n\r \'x\" 'd + args = tokenize('a\\ b \\t\\n\\r \\\'x\\\" \'d'); // a_b \t\n\r \'x\" 'd test.verifyEqual(4, args.length); test.verifyEqual('a b', args[0].text); test.verifyEqual(0, args[0].start); @@ -143,50 +123,60 @@ exports.testTokenize = function() { return "testTokenize Completed"; }; -var hints; -var hint0; -var requisition; -var sel = { start: -1, end: -1 }; -var settingAssignment; -var valueAssignment; -mockCliUi = { - getSelection: function() { - return sel; - }, +exports.testSplit = function() { + var args = tokenize('s'); + var command = split(args); + test.verifyEqual(1, args.length); + test.verifyEqual('s', args[0].text); + test.verifyUndefined(command); - setHints: function(h) { - hints = h; - hint0 = (h.length !== 0) ? h[0] : undefined; + var args = tokenize('set'); + var command = split(args); + test.verifyEqual([], args); + test.verifyEqual('set', command.name); - if (requisition && requisition.command && requisition.command.name === 'set') { - settingAssignment = requisition.getAssignment('setting'); - valueAssignment = requisition.getAssignment('value'); + var args = tokenize('set a b'); + var command = split(args); + test.verifyEqual('set', command.name); + test.verifyEqual(2, args.length); + test.verifyEqual('a', args[0].text); + test.verifyEqual('b', args[1].text); + + // TODO: add tests for sub commands + return "testSplit Completed"; +}; + +exports.testCli = function() { + var hints; + var hint0; + var settingAssignment; + var valueAssignment; + var cli = new CliRequisition(); + + function update(input) { + cli.update(input); + hints = cli.getHints(); + hint0 = (hints.length !== 0) ? hints[0] : undefined; + if (cli.command && cli.command.name === 'set') { + settingAssignment = cli.getAssignment('setting'); + valueAssignment = cli.getAssignment('value'); } else { settingAssignment = undefined; valueAssignment = undefined; } - }, - - setRequisition: function(r) { - requisition = r; } -}; -exports.testCli = function() { var historyLengthSetting = settings.getSetting('historyLength'); - var input = new cli.Cli(mockCliUi); - - input.parse(''); + update({ typed: '', cursor: { start: 0, end: 0 } }); test.verifyEqual(1, hints.length); test.verifyEqual(Status.INCOMPLETE, hint0.status); test.verifyEqual(0, hint0.start); test.verifyEqual(0, hint0.end); - test.verifyNull(requisition.command); + test.verifyNull(cli.command); - sel.start = sel.end = 1; - input.parse('s'); + update({ typed: 's', cursor: { start: 1, end: 1 } }); test.verifyEqual(1, hints.length); test.verifyEqual(Status.INCOMPLETE, hint0.status); test.verifyNotEqual(-1, hint0.message.indexOf('possibilities')); @@ -196,16 +186,16 @@ exports.testCli = function() { // This is slightly fragile because it depends on the configuration test.verifyTrue(hint0.predictions.length < 20); test.verifyNotEqual(-1, hint0.predictions.indexOf('set')); - test.verifyNull(requisition.command); + test.verifyNull(cli.command); - input.parse('set'); + update({ typed: 'set', cursor: { start: 3, end: 3 } }); test.verifyEqual(1, hints.length); test.verifyEqual(Status.VALID, hint0.status); test.verifyEqual(0, hint0.start); test.verifyEqual(3, hint0.end); - test.verifyEqual('set', requisition.command.name); + test.verifyEqual('set', cli.command.name); - input.parse('set '); + update({ typed: 'set ', cursor: { start: 4, end: 4 } }); test.verifyEqual(1, hints.length); test.verifyEqual(Status.VALID, hint0.status); test.verifyEqual(0, hint0.start); @@ -213,71 +203,67 @@ exports.testCli = function() { // This is caused by us using the whole input to determine the length. // Maybe one day we should fix this? //test.verifyEqual(3, hint0.end); - test.verifyEqual('set', requisition.command.name); + test.verifyEqual('set', cli.command.name); - sel.start = sel.end = 5; - input.parse('set h'); + update({ typed: 'set h', cursor: { start: 5, end: 5 } }); test.verifyEqual(1, hints.length); test.verifyEqual(Status.INCOMPLETE, hint0.status); test.verifyTrue(hint0.predictions.length > 0); test.verifyEqual(4, hint0.start); test.verifyEqual(5, hint0.end); test.verifyNotEqual(-1, hint0.predictions.indexOf('historyLength')); - test.verifyEqual('set', requisition.command.name); + test.verifyEqual('set', cli.command.name); test.verifyEqual('h', settingAssignment.arg.text); test.verifyEqual(undefined, settingAssignment.value); - sel.start = sel.end = 16; - input.parse('set historyLengt'); + update({ typed: 'set historyLengt', cursor: { start: 16, end: 16 } }); test.verifyEqual(1, hints.length); test.verifyEqual(Status.INCOMPLETE, hint0.status); test.verifyEqual(1, hint0.predictions.length); test.verifyEqual(4, hint0.start); test.verifyEqual(16, hint0.end); test.verifyEqual('historyLength', hint0.predictions[0]); - test.verifyEqual('set', requisition.command.name); + test.verifyEqual('set', cli.command.name); test.verifyEqual('historyLengt', settingAssignment.arg.text); test.verifyEqual(undefined, settingAssignment.value); - sel.start = sel.end = 1; - input.parse('set historyLengt'); + update({ typed: 'set historyLengt', cursor: { start: 1, end: 1 } }); test.verifyEqual(1, hints.length); test.verifyEqual(Status.INVALID, hint0.status); test.verifyEqual(4, hint0.start); test.verifyEqual(16, hint0.end); test.verifyEqual(1, hint0.predictions.length); test.verifyEqual('historyLength', hint0.predictions[0]); - test.verifyEqual('set', requisition.command.name); + test.verifyEqual('set', cli.command.name); test.verifyEqual('historyLengt', settingAssignment.arg.text); test.verifyEqual(undefined, settingAssignment.value); - sel.start = sel.end = 17; - input.parse('set historyLengt '); + update({ typed: 'set historyLengt ', cursor: { start: 17, end: 17 } }); test.verifyEqual(1, hints.length); test.verifyEqual(Status.INVALID, hint0.status); test.verifyEqual(4, hint0.start); test.verifyEqual(16, hint0.end); test.verifyEqual(1, hint0.predictions.length); test.verifyEqual('historyLength', hint0.predictions[0]); - test.verifyEqual('set', requisition.command.name); + test.verifyEqual('set', cli.command.name); test.verifyEqual('historyLengt', settingAssignment.arg.text); test.verifyEqual(undefined, settingAssignment.value); - input.parse('set historyLength'); + update({ typed: 'set historyLength', cursor: { start: 17, end: 17 } }); test.verifyEqual(0, hints.length); - test.verifyEqual('set', requisition.command.name); + test.verifyEqual('set', cli.command.name); test.verifyEqual('historyLength', settingAssignment.arg.text); test.verifyEqual(historyLengthSetting, settingAssignment.value); - input.parse('set historyLength '); + update({ typed: 'set historyLength ', cursor: { start: 18, end: 18 } }); test.verifyEqual(0, hints.length); - test.verifyEqual('set', requisition.command.name); + test.verifyEqual('set', cli.command.name); test.verifyEqual('historyLength', settingAssignment.arg.text); test.verifyEqual(historyLengthSetting, settingAssignment.value); - input.parse('set historyLength 6'); + update({ typed: 'set historyLength 6', cursor: { start: 19, end: 19 } }); test.verifyEqual(0, hints.length); - test.verifyEqual('set', requisition.command.name); + test.verifyEqual('set', cli.command.name); test.verifyEqual('historyLength', settingAssignment.arg.text); test.verifyEqual(historyLengthSetting, settingAssignment.value); test.verifyEqual('6', valueAssignment.arg.text); @@ -286,12 +272,8 @@ exports.testCli = function() { // TODO: Add test to see that a command without mandatory param causes INVALID - console.log(input); - return "testCli Completed"; }; -window.testCli = exports; - }); diff --git a/plugins/cockpit/lib/test/testNothing.js b/plugins/cockpit/lib/test/testNothing.js new file mode 100644 index 00000000..567b575a --- /dev/null +++ b/plugins/cockpit/lib/test/testNothing.js @@ -0,0 +1,40 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Joe Walker (jwalker@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +}); diff --git a/plugins/cockpit/lib/ui/plain.css b/plugins/cockpit/lib/ui/plain.css new file mode 100644 index 00000000..85c55ff1 --- /dev/null +++ b/plugins/cockpit/lib/ui/plain.css @@ -0,0 +1,2 @@ + +#cockpit { color: red; } diff --git a/plugins/cockpit/lib/ui/plain.js b/plugins/cockpit/lib/ui/plain.js new file mode 100644 index 00000000..445a7864 --- /dev/null +++ b/plugins/cockpit/lib/ui/plain.js @@ -0,0 +1,98 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Joe Walker (jwalker@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +var editorCss = require("text!cockpit/ui/plain.css"); +var dom = require("pilot/dom").dom; +dom.importCssString(editorCss); + +var CliRequisition = require('cockpit/cli').CliRequisition; +var keyutil = require('pilot/keyboard/keyutil'); + +exports.startup = function(data, reason) { + // TODO: we should have a better way to specify command lines??? + this.input = document.getElementById('cockpit'); + if (!this.input) { + console.log('No element with an id of cockpit. Bailing on plain cli'); + return; + } + + var cli = new CliRequisition(); + + /* + // All this does is to kill TABs normal use. I wonder if we can train + // people to use right arrow? Probably not? but ... + keyutil.addKeyDownListener(input, function(ev) { + // env.commandLine = this; + // var handled = keyboardManager.processKeyEvent(ev, this, { + // isCommandLine: true, isKeyUp: false + // }); + if (ev.keyCode === keyutil.KeyHelper.KEY.TAB) { + return true; + } + //return handled; + }.bind(this)); + */ + + this.input.addEventListener('keyup', function(ev) { + /* + var handled = keyboardManager.processKeyEvent(ev, this, { + isCommandLine: true, isKeyUp: true + }); + */ + + if (ev.keyCode === keyutil.KeyHelper.KEY.RETURN) { + cli.exec(); + this.input.value = ''; + } else { + cli.update({ + typed: this.input.value, + cursor: { + start: this.input.selectionStart, + end: this.input.selectionEnd + } + }); + console.log(JSON.stringify(cli.getHints())); + } + + // return handled; + }.bind(this), true); +}; + + +}); diff --git a/plugins/pilot/lib/canon.js b/plugins/pilot/lib/canon.js index 6bf03793..aa308f49 100644 --- a/plugins/pilot/lib/canon.js +++ b/plugins/pilot/lib/canon.js @@ -161,7 +161,7 @@ exports.getCommandNames = function() { * @param command Either a command, or the name of one */ exports.exec = function(command, args) { - if (typeof name === 'string') { + if (typeof command === 'string') { command = commands[command]; } if (!command) { diff --git a/plugins/pilot/lib/index.js b/plugins/pilot/lib/index.js index 553e36d5..73262d42 100644 --- a/plugins/pilot/lib/index.js +++ b/plugins/pilot/lib/index.js @@ -40,11 +40,9 @@ var deps = [ "pilot/types/basic", "pilot/types/command", "pilot/types/settings", - "pilot/canon", "pilot/commands/settings", "pilot/settings/canon", - "pilot/cli", - "pilot/test/testCli" + "pilot/canon" ]; var packages = deps.slice(); @@ -52,6 +50,7 @@ packages.unshift("require", "exports", "module"); define(packages, function(require, exports, module) { +console.log(packages); exports.startup = function(data, reason) { deps.forEach(function(dep) { console.log("test startup for " + dep); diff --git a/plugins/pilot/lib/keyboard/index.js b/plugins/pilot/lib/keyboard/index.js new file mode 100644 index 00000000..87e6281f --- /dev/null +++ b/plugins/pilot/lib/keyboard/index.js @@ -0,0 +1,459 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Skywriter Team (skywriter@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(request, exports, module) { + +var console = require('pilot/console'); +var Trace = require('pilot/stacktrace').Trace; +var keyutil = require('pilot/keyboard/keyutil'); +var history = require('canon/history'); +var Request = require('canon/request').Request; +var env = require('environment').env; + +exports.keymappings = {}; + +exports.addKeymapping = function(mapping) { + exports.keymappings[mapping.name] = mapping; +}; + +exports.removeKeymapping = function(name) { + delete exports.keymapping[name]; +}; + +exports.startup = function(data, reason) { + var settings = data.env.settings; + // TODO register this + // catalog.addExtensionSpec("keymapping", { + // "description": "A keymapping defines how keystrokes are interpreted.", + // "params": [ + // { + // "name": "states", + // "required": true, + // "description": + // "Holds the states and all the informations about the keymapping. See docs: pluginguide/keymapping" + // } + // ] + // }); + settings.settingChange.add({ + match: "customKeymapping", + ref: exports.keyboardManager, + func: exports.keyboardManager._customKeymappingChanged + .bind(exports.keyboardManager) + }); +}; + +exports.shutdown = function(data, reason) { + var settings = data.env.settings; + settings.settingChange.remove(exports.keyboardManager); +}; + + +/* + * Things to do to sanitize this code: + * - 'no command' is a bizarre special value at the very least it should be a + * constant to make typos more obvious, but it would be better to refactor + * so that a natural value like null worked. + * - sender seems to be totally customized to the editor case, and the functions + * that we assume that it has make no sense for the commandLine case. We + * should either document and implement the same function set for both cases + * or admit that the cases are different enough to have separate + * implementations. + * - remove remaining sproutcore-isms + * - fold buildFlags into processKeyEvent or something better, preferably the + * latter. We don't want the environment to become a singleton + */ + +/** + * Every time we call processKeyEvent, we pass in some flags that require the + * same processing to set them up. This function can be called to do that + * setup. + * @param env Probably environment.env + * @param flags Probably {} (but check other places where this is called) + */ +exports.buildFlags = function(flags) { + flags.context = env.contexts[0]; + return flags; +}; + +/** + * The canon, or the repository of commands, contains functions to process + * events and dispatch command messages to targets. + * @class + */ +var KeyboardManager = function() { }; + +KeyboardManager.prototype = { + _customKeymappingCache: { states: {} }, + + /** + * Searches through the command canon for an event matching the given flags + * with a key equivalent matching the given SproutCore event, and, if the + * command is found, sends a message to the appropriate target. + * + * This will get a couple of upgrades in the not-too-distant future: + * 1. caching in the Canon for fast lookup based on key + * 2. there will be an extra layer in between to allow remapping via + * user preferences and keyboard mapping plugins + * + * @return True if a matching command was found, false otherwise. + */ + processKeyEvent: function(evt, sender, flags) { + // Use our modified commandCodes function to detect the meta key in + // more circumstances than SproutCore alone does. + var symbolicName = keyutil.commandCodes(evt, true)[0]; + if (util.none(symbolicName)) { + return false; + } + + // TODO: Maybe it should be the job of our caller to do this? + exports.buildFlags(flags); + + flags.isCommandKey = true; + return this._matchCommand(symbolicName, sender, flags); + }, + + _matchCommand: function(symbolicName, sender, flags) { + var match = this._findCommandExtension(symbolicName, sender, flags); + if (match && match.commandExt !== 'no command') { + if (flags.isTextView) { + sender.resetKeyBuffers(); + } + + var commandExt = match.commandExt; + commandExt.load(function(command) { + var request = new Request({ + command: command, + commandExt: commandExt + }); + history.execute(match.args, request); + }); + return true; + } + + // 'no command' is returned if a keyevent is handled but there is no + // command executed (for example when switchting the keyboard state). + if (match && match.commandExt === 'no command') { + return true; + } else { + return false; + } + }, + + _buildBindingsRegex: function(bindings) { + // Escape a given Regex string. + bindings.forEach(function(binding) { + if (!util.none(binding.key)) { + binding.key = new RegExp('^' + binding.key + '$'); + } else if (Array.isArray(binding.regex)) { + binding.key = new RegExp('^' + binding.regex[1] + '$'); + binding.regex = new RegExp(binding.regex.join('') + '$'); + } else { + binding.regex = new RegExp(binding.regex + '$'); + } + }); + }, + + /** + * Build the RegExp from the keymapping as RegExp can't stored directly + * in the metadata JSON and as the RegExp used to match the keys/buffer + * need to be adapted. + */ + _buildKeymappingRegex: function(keymapping) { + for (state in keymapping.states) { + this._buildBindingsRegex(keymapping.states[state]); + } + keymapping._convertedRegExp = true; + }, + + /** + * Loop through the commands in the canon, looking for something that + * matches according to #_commandMatches, and return that. + */ + _findCommandExtension: function(symbolicName, sender, flags) { + // If the flags indicate that we handle the textView's input then take + // a look at keymappings as well. + if (flags.isTextView) { + var currentState = sender._keyState; + + // Don't add the symbolic name to the key buffer if the alt_ key is + // part of the symbolic name. If it starts with alt_, this means + // that the user hit an alt keycombo and there will be a single, + // new character detected after this event, which then will be + // added to the buffer (e.g. alt_j will result in ∆). + if (!flags.isCommandKey || symbolicName.indexOf('alt_') === -1) { + sender._keyBuffer += + symbolicName.replace(/ctrl_meta|meta/,'ctrl'); + sender._keyMetaBuffer += symbolicName; + } + + // List of all the keymappings to look at. + var ak = [ this._customKeymappingCache ]; + + // Get keymapping extension points. + ak = ak.concat(catalog.getExtensions('keymapping')); + + for (var i = 0; i < ak.length; i++) { + // Check if the keymapping has the current state. + if (util.none(ak[i].states[currentState])) { + continue; + } + + if (util.none(ak[i]._convertedRegExp)) { + this._buildKeymappingRegex(ak[i]); + } + + // Try to match the current mapping. + var result = this._bindingsMatch( + symbolicName, + flags, + sender, + ak[i]); + + if (!util.none(result)) { + return result; + } + } + } + + var commandExts = catalog.getExtensions('command'); + var reply = null; + var args = {}; + + symbolicName = symbolicName.replace(/ctrl_meta|meta/,'ctrl'); + + commandExts.some(function(commandExt) { + if (this._commandMatches(commandExt, symbolicName, flags)) { + reply = commandExt; + return true; + } + return false; + }.bind(this)); + + return util.none(reply) ? null : { commandExt: reply, args: args }; + }, + + + /** + * Checks if the given parameters fit to one binding in the given bindings. + * Returns the command and arguments if a command was matched. + */ + _bindingsMatch: function(symbolicName, flags, sender, keymapping) { + var match; + var commandExt = null; + var args = {}; + var bufferToUse; + + if (!util.none(keymapping.hasMetaKey)) { + bufferToUse = sender._keyBuffer; + } else { + bufferToUse = sender._keyMetaBuffer; + } + + // Add the alt_key to the buffer as we don't want it to be in the buffer + // that is saved but for matching, it needs to be there. + if (symbolicName.indexOf('alt_') === 0 && flags.isCommandKey) { + bufferToUse += symbolicName; + } + + // Loop over all the bindings of the keymapp until a match is found. + keymapping.states[sender._keyState].some(function(binding) { + // Check if the key matches. + if (binding.key && !binding.key.test(symbolicName)) { + return false; + } + + // Check if the regex matches. + if (binding.regex && !(match = binding.regex.exec(bufferToUse))) { + return false; + } + + // Check for disallowed matches. + if (binding.disallowMatches) { + for (var i = 0; i < binding.disallowMatches.length; i++) { + if (!!match[binding.disallowMatches[i]]) { + return true; + } + } + } + + // Check predicates. + if (!exports.flagsMatch(binding.predicates, flags)) { + return false; + } + + // If there is a command to execute, then figure out the + // comand and the arguments. + if (binding.exec) { + // Get the command. + commandExt = catalog.getExtensionByKey('command', binding.exec); + if (util.none(commandExt)) { + throw new Error('Can\'t find command ' + binding.exec + + ' in state=' + sender._keyState + + ', symbolicName=' + symbolicName); + } + + // Bulid the arguments. + if (binding.params) { + var value; + binding.params.forEach(function(param) { + if (!util.none(param.match) && !util.none(match)) { + value = match[param.match] || param.defaultValue; + } else { + value = param.defaultValue; + } + + if (param.type === 'number') { + value = parseInt(value, 10); + } + + args[param.name] = value; + }); + } + sender.resetKeyBuffers(); + } + + // Handle the 'then' property. + if (binding.then) { + sender._keyState = binding.then; + sender.resetKeyBuffers(); + } + + // If there is no command matched now, then return a 'false' + // command to stop matching. + if (util.none(commandExt)) { + commandExt = 'no command'; + } + + return true; + }); + + if (util.none(commandExt)) { + return null; + } + + return { commandExt: commandExt, args: args }; + }, + + /** + * Check that the given command fits the given key name and flags. + */ + _commandMatches: function(commandExt, symbolicName, flags) { + var mappedKeys = commandExt.key; + if (!mappedKeys) { + return false; + } + + // Check predicates + if (!exports.flagsMatch(commandExt.predicates, flags)) { + return false; + } + + if (typeof(mappedKeys) === 'string') { + if (mappedKeys != symbolicName) { + return false; + } + return true; + } + + if (!Array.isArray(mappedKeys)) { + mappedKeys = [mappedKeys]; + commandExt.key = mappedKeys; + } + + for (var i = 0; i < mappedKeys.length; i++) { + var keymap = mappedKeys[i]; + if (typeof(keymap) === 'string') { + if (keymap == symbolicName) { + return true; + } + continue; + } + + if (keymap.key != symbolicName) { + continue; + } + + return exports.flagsMatch(keymap.predicates, flags); + } + return false; + }, + + /** + * Build a cache of custom keymappings whenever the associated setting + * changes. + */ + _customKeymappingChanged: function(settingName, value) { + var ckc = this._customKeymappingCache = + JSON.parse(value); + + ckc.states = ckc.states || {}; + + for (state in ckc.states) { + this._buildBindingsRegex(ckc.states[state]); + } + ckc._convertedRegExp = true; + } +}; + +/** + * + */ +exports.flagsMatch = function(predicates, flags) { + if (util.none(predicates)) { + return true; + } + + if (!flags) { + return false; + } + + for (var flagName in predicates) { + if (flags[flagName] !== predicates[flagName]) { + return false; + } + } + + return true; +}; + +/** + * The global exported KeyboardManager + */ +exports.keyboardManager = new KeyboardManager(); + + +}); diff --git a/plugins/pilot/lib/keyboard/keyutil.js b/plugins/pilot/lib/keyboard/keyutil.js new file mode 100644 index 00000000..bbc0ac5a --- /dev/null +++ b/plugins/pilot/lib/keyboard/keyutil.js @@ -0,0 +1,273 @@ +/*! @license +========================================================================== +SproutCore -- JavaScript Application Framework +copyright 2006-2009, Sprout Systems Inc., Apple Inc. and contributors. + +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. + +SproutCore and the SproutCore logo are trademarks of Sprout Systems, Inc. + +For more information about SproutCore, visit http://www.sproutcore.com + + +========================================================================== +@license */ + +// Most of the following code is taken from SproutCore with a few changes. + +define(function(require, exports, module) { + +var util = require('pilot/util'); + + +/** + * Helper functions and hashes for key handling. + */ +exports.KeyHelper = function() { + var ret = { + MODIFIER_KEYS: { + 16: 'shift', 17: 'ctrl', 18: 'alt', 224: 'meta' + }, + + FUNCTION_KEYS : { + 8: 'backspace', 9: 'tab', 13: 'return', 19: 'pause', + 27: 'escape', 33: 'pageup', 34: 'pagedown', 35: 'end', + 36: 'home', 37: 'left', 38: 'up', 39: 'right', + 40: 'down', 44: 'printscreen', 45: 'insert', 46: 'delete', + 112: 'f1', 113: 'f2', 114: 'f3', 115: 'f4', + 116: 'f5', 117: 'f7', 119: 'f8', 120: 'f9', + 121: 'f10', 122: 'f11', 123: 'f12', 144: 'numlock', + 145: 'scrolllock' + }, + + PRINTABLE_KEYS: { + 32: ' ', 48: '0', 49: '1', 50: '2', 51: '3', 52: '4', 53: '5', + 54: '6', 55: '7', 56: '8', 57: '9', 59: ';', 61: '=', 65: 'a', + 66: 'b', 67: 'c', 68: 'd', 69: 'e', 70: 'f', 71: 'g', 72: 'h', + 73: 'i', 74: 'j', 75: 'k', 76: 'l', 77: 'm', 78: 'n', 79: 'o', + 80: 'p', 81: 'q', 82: 'r', 83: 's', 84: 't', 85: 'u', 86: 'v', + 87: 'w', 88: 'x', 89: 'y', 90: 'z', 107: '+', 109: '-', 110: '.', + 188: ',', 190: '.', 191: '/', 192: '`', 219: '[', 220: '\\', + 221: ']', 222: '\"' + }, + + /** + * Create the lookup table for Firefox to convert charCodes to keyCodes + * in the keyPress event. + */ + PRINTABLE_KEYS_CHARCODE: {}, + + /** + * Allow us to lookup keyCodes by symbolic name rather than number + */ + KEY: {} + }; + + // Create the PRINTABLE_KEYS_CHARCODE hash. + for (var i in ret.PRINTABLE_KEYS) { + var k = ret.PRINTABLE_KEYS[i]; + ret.PRINTABLE_KEYS_CHARCODE[k.charCodeAt(0)] = i; + if (k.toUpperCase() != k) { + ret.PRINTABLE_KEYS_CHARCODE[k.toUpperCase().charCodeAt(0)] = i; + } + } + + // A reverse map of FUNCTION_KEYS + for (i in ret.FUNCTION_KEYS) { + var name = ret.FUNCTION_KEYS[i].toUpperCase(); + ret.KEY[name] = parseInt(i, 10); + } + + return ret; +}(); + +/** + * Determines if the keyDown event is a non-printable or function key. + * These kinds of events are processed as keyboard shortcuts. + * If no shortcut handles the event, then it will be sent as a regular + * keyDown event. + * @private + */ +var isFunctionOrNonPrintableKey = function(evt) { + return !!(evt.altKey || evt.ctrlKey || evt.metaKey || + ((evt.charCode !== evt.which) && + exports.KeyHelper.FUNCTION_KEYS[evt.which])); +}; + +/** + * Returns character codes for the event. + * The first value is the normalized code string, with any Shift or Ctrl + * characters added to the beginning. + * The second value is the char string by itself. + * @return {Array} + */ +exports.commandCodes = function(evt, dontIgnoreMeta) { + var code = evt._keyCode || evt.keyCode; + var charCode = (evt._charCode === undefined ? evt.charCode : evt._charCode); + var ret = null; + var key = null; + var modifiers = ''; + var lowercase; + var allowShift = true; + + // Absent a value for 'keyCode' or 'which', we can't compute the + // command codes. Bail out. + if (code === 0 && evt.which === 0) { + return false; + } + + // If the charCode is not zero, then we do not handle a command key + // here. Bail out. + if (charCode !== 0) { + return false; + } + + // Check for modifier keys. + if (exports.KeyHelper.MODIFIER_KEYS[charCode]) { + return [exports.KeyHelper.MODIFIER_KEYS[charCode], null]; + } + + // handle function keys. + if (code) { + ret = exports.KeyHelper.FUNCTION_KEYS[code]; + if (!ret && (evt.altKey || evt.ctrlKey || evt.metaKey)) { + ret = exports.KeyHelper.PRINTABLE_KEYS[code]; + // Don't handle the shift key if the combo is + // (meta_|ctrl_) + // This is necessary for the French keyboard. On that keyboard, + // you have to hold down the shift key to access the number + // characters. + if (code > 47 && code < 58) { + allowShift = evt.altKey; + } + } + + if (ret) { + if (evt.altKey) { + modifiers += 'alt_'; + } + if (evt.ctrlKey) { + modifiers += 'ctrl_'; + } + if (evt.metaKey) { + modifiers += 'meta_'; + } + } else if (evt.ctrlKey || evt.metaKey) { + return false; + } + } + + // otherwise just go get the right key. + if (!ret) { + code = evt.which; + key = ret = String.fromCharCode(code); + lowercase = ret.toLowerCase(); + + if (evt.metaKey) { + modifiers = 'meta_'; + ret = lowercase; + + } else ret = null; + } + + if (evt.shiftKey && ret && allowShift) { + modifiers += 'shift_'; + } + + if (ret) { + ret = modifiers + ret; + } + + if (!dontIgnoreMeta && ret) { + ret = ret.replace(/ctrl_meta|meta/,'ctrl'); + } + + return [ret, key]; +}; + +// Note: Most of the following code is taken from SproutCore with a few changes. + +/** + * Firefox sends a few key events twice: the first time to the keydown event + * and then later again to the keypress event. To handle them correct, they + * should be processed only once. Due to this, we will skip these events + * in keydown and handle them then in keypress. + */ +exports.addKeyDownListener = function(element, boundFunction) { + + var handleBoundFunction = function(ev) { + var handled = boundFunction(ev); + // If the boundFunction returned true, then stop the event. + if (handled) { + util.stopEvent(ev); + } + return handled; + }; + + element.addEventListener('keydown', function(ev) { + if (util.isMozilla) { + // Check for function keys (like DELETE, TAB, LEFT, RIGHT...) + if (exports.KeyHelper.FUNCTION_KEYS[ev.keyCode]) { + return true; + // Check for command keys (like ctrl_c, ctrl_z...) + } else if ((ev.ctrlKey || ev.metaKey) && + exports.KeyHelper.PRINTABLE_KEYS[ev.keyCode]) { + return true; + } + } + + if (isFunctionOrNonPrintableKey(ev)) { + return handleBoundFunction(ev); + } + + return true; + }, false); + + element.addEventListener('keypress', function(ev) { + if (util.isMozilla) { + // If this is a function key, we have to use the keyCode. + if (exports.KeyHelper.FUNCTION_KEYS[ev.keyCode]) { + return handleBoundFunction(ev); + } else if ((ev.ctrlKey || ev.metaKey) && + exports.KeyHelper.PRINTABLE_KEYS_CHARCODE[ev.charCode]){ + // Check for command keys (like ctrl_c, ctrl_z...). + // For command keys have to convert the charCode to a keyCode + // as it has been sent from the keydown event to be in line + // with the other browsers implementations. + + // FF does not allow let you change the keyCode or charCode + // property. Store to a custom keyCode/charCode variable. + // The getCommandCodes() function takes care of these + // special variables. + ev._keyCode = exports.KeyHelper.PRINTABLE_KEYS_CHARCODE[ev.charCode]; + ev._charCode = 0; + return handleBoundFunction(ev); + } + } + + // normal processing: send keyDown for printable keys. + if (ev.charCode !== undefined && ev.charCode === 0) { + return true; + } + + return handleBoundFunction(ev); + }, false); +}; + +}); diff --git a/plugins/pilot/lib/keyboard/tests/testKeyboard.js b/plugins/pilot/lib/keyboard/tests/testKeyboard.js new file mode 100644 index 00000000..17918935 --- /dev/null +++ b/plugins/pilot/lib/keyboard/tests/testKeyboard.js @@ -0,0 +1,99 @@ +require.def(['require', 'exports', 'module', + 'keyboard/keyboard', + 'keyboard/tests/plugindev' +], function(require, exports, module, + keyboard, + t +) { + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Skywriter Team (skywriter@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + + + +exports.testKeyMatching = function() { + var km = keyboard.keyboardManager; + var command = {}; + t.equal(km._commandMatches(command, 'meta_z', {}), false, + 'no keymapping means false'); + + command = { + key: 'meta_z' + }; + t.equal(km._commandMatches(command, 'meta_z', {}), true, + 'matching keys, simple string'); + t.equal(km._commandMatches(command, 'meta_a', {}), false, + 'not matching key, simple string'); + + command = { + key: {key: 'meta_z', predicates: {isGreen: true}} + }; + t.equal(km._commandMatches(command, 'meta_z', {}), false, + 'object with not matching predicate'); + t.equal(km._commandMatches(command, 'meta_z', {isGreen: true}), true, + 'object with matching key and predicate'); + t.equal(km._commandMatches(command, 'meta_a', {isGreen: true}), false, + 'object with not matching key'); + t.equal(km._commandMatches(command, 'meta_a', {isGreen: false}), false, + 'object with neither matching'); + t.equal(km._commandMatches(command, 'meta_z', {isGreen: false}), false, + 'object with matching key and but different predicate'); + + command = { + key: ['meta_b', {key: 'meta_z', predicates: {isGreen: true}}, + {key: 'meta_c'}] + }; + t.equal(km._commandMatches(command, 'meta_z', {}), false, + 'list: object with not matching predicate'); + t.equal(km._commandMatches(command, 'meta_z', {isGreen: true}), true, + 'list: object with matching key and predicate'); + t.equal(km._commandMatches(command, 'meta_a', {isGreen: true}), false, + 'list: object with not matching key'); + t.equal(km._commandMatches(command, 'meta_a', {isGreen: false}), false, + 'list: object with neither matching'); + t.equal(km._commandMatches(command, 'meta_z', {isGreen: false}), false, + 'list: object with matching key and but different predicate'); + t.equal(km._commandMatches(command, 'meta_b'), true, + 'list: simple key match'); + t.equal(km._commandMatches(command, 'meta_c'), true, + 'list: object without predicate match'); + t.equal(km._commandMatches(command, 'meta_c', {isGreen: false}), true, + 'list: flags don\'t matter without predicates'); +}; + +}); diff --git a/plugins/pilot/lib/rangeutils.js b/plugins/pilot/lib/rangeutils.js new file mode 100644 index 00000000..b4714f7b --- /dev/null +++ b/plugins/pilot/lib/rangeutils.js @@ -0,0 +1,185 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Patrick Walton (pwalton@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +var util = require("util/util"); + +/** + * Returns the result of adding the two positions. + */ +exports.addPositions = function(a, b) { + return { row: a.row + b.row, col: a.col + b.col }; +}; + +/** Returns a copy of the given range. */ +exports.cloneRange = function(range) { + var oldStart = range.start, oldEnd = range.end; + var newStart = { row: oldStart.row, col: oldStart.col }; + var newEnd = { row: oldEnd.row, col: oldEnd.col }; + return { start: newStart, end: newEnd }; +}; + +/** + * Given two positions a and b, returns a negative number if a < b, 0 if a = b, + * or a positive number if a > b. + */ +exports.comparePositions = function(positionA, positionB) { + var rowDiff = positionA.row - positionB.row; + return rowDiff === 0 ? positionA.col - positionB.col : rowDiff; +}; + +/** + * Returns true if the two ranges are equal and false otherwise. + */ +exports.equal = function(rangeA, rangeB) { + return (exports.comparePositions(rangeA.start, rangeB.start) === 0 && + exports.comparePositions(rangeA.end, rangeB.end) === 0); +}; + +exports.extendRange = function(range, delta) { + var end = range.end; + return { + start: range.start, + end: { + row: end.row + delta.row, + col: end.col + delta.col + } + }; +}; + +/** + * Given two sets of ranges, returns the ranges of characters that exist in one + * of the sets but not both. + */ +exports.intersectRangeSets = function(setA, setB) { + var stackA = util.clone(setA), stackB = util.clone(setB); + var result = []; + while (stackA.length > 0 && stackB.length > 0) { + var rangeA = stackA.shift(), rangeB = stackB.shift(); + var startDiff = exports.comparePositions(rangeA.start, rangeB.start); + var endDiff = exports.comparePositions(rangeA.end, rangeB.end); + + if (exports.comparePositions(rangeA.end, rangeB.start) < 0) { + // A is completely before B + result.push(rangeA); + stackB.unshift(rangeB); + } else if (exports.comparePositions(rangeB.end, rangeA.start) < 0) { + // B is completely before A + result.push(rangeB); + stackA.unshift(rangeA); + } else if (startDiff < 0) { // A starts before B + result.push({ start: rangeA.start, end: rangeB.start }); + stackA.unshift({ start: rangeB.start, end: rangeA.end }); + stackB.unshift(rangeB); + } else if (startDiff === 0) { // A and B start at the same place + if (endDiff < 0) { // A ends before B + stackB.unshift({ start: rangeA.end, end: rangeB.end }); + } else if (endDiff > 0) { // A ends after B + stackA.unshift({ start: rangeB.end, end: rangeA.end }); + } + } else if (startDiff > 0) { // A starts after B + result.push({ start: rangeB.start, end: rangeA.start }); + stackA.unshift(rangeA); + stackB.unshift({ start: rangeA.start, end: rangeB.end }); + } + } + return result.concat(stackA, stackB); +}; + +exports.isZeroLength = function(range) { + return range.start.row === range.end.row && + range.start.col === range.end.col; +}; + +/** + * Returns the greater of the two positions. + */ +exports.maxPosition = function(a, b) { + return exports.comparePositions(a, b) > 0 ? a : b; +}; + +/** + * Converts a range with swapped 'end' and 'start' values into one with the + * values in the correct order. + * + * TODO: Unit test. + */ +exports.normalizeRange = function(range) { + return this.comparePositions(range.start, range.end) < 0 ? range : + { start: range.end, end: range.start }; +}; + +/** + * Returns a single range that spans the entire given set of ranges. + */ +exports.rangeSetBoundaries = function(rangeSet) { + return { + start: rangeSet[0].start, + end: rangeSet[rangeSet.length - 1].end + }; +}; + +exports.toString = function(range) { + var start = range.start, end = range.end; + return '[ ' + start.row + ', ' + start.col + ' ' + end.row + ',' + + end.col +' ]'; +}; + +/** + * Returns the union of the two ranges. + */ +exports.unionRanges = function(a, b) { + return { + start: a.start.row < b.start.row || + (a.start.row === b.start.row && a.start.col < b.start.col) ? + a.start : b.start, + end: a.end.row > b.end.row || + (a.end.row === b.end.row && a.end.col > b.end.col) ? + a.end : b.end + }; +}; + +exports.isPosition = function(pos) { + return !util.none(pos) && !util.none(pos.row) && !util.none(pos.col); +}; + +exports.isRange = function(range) { + return (!util.none(range) && exports.isPosition(range.start) && + exports.isPosition(range.end)); +}; + +}); \ No newline at end of file diff --git a/plugins/pilot/lib/tests/testRangeutils.js b/plugins/pilot/lib/tests/testRangeutils.js new file mode 100644 index 00000000..d96c43a4 --- /dev/null +++ b/plugins/pilot/lib/tests/testRangeutils.js @@ -0,0 +1,163 @@ +require.def(['require', 'exports', 'module', + 'rangeutils/tests/plugindev', + 'rangeutils/tests/utils/range' +], function(require, exports, module, + t, + Range +) { + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Skywriter Team (skywriter@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + + + +exports.testAddPositions = function() { + t.deepEqual(Range.addPositions({ row: 0, col: 0 }, + { row: 0, col: 0 }), { row: 0, col: 0 }, '0,0 + 0,0 and 0,0'); + t.deepEqual(Range.addPositions({ row: 1, col: 0 }, + { row: 2, col: 0 }), { row: 3, col: 0 }, '1,0 + 2,0 and 3,0'); + t.deepEqual(Range.addPositions({ row: 0, col: 1 }, + { row: 0, col: 1 }), { row: 0, col: 2 }, '0,1 + 0,1 and 0,2'); + t.deepEqual(Range.addPositions({ row: 1, col: 2 }, + { row: -1, col: -2 }), { row: 0, col: 0 }, '1,2 + -1,-2 and 0,0'); +}; + +exports.testCloneRange = function() { + var oldRange = { start: { row: 1, col: 2 }, end: { row: 3, col: 4 } }; + var newRange = Range.cloneRange(oldRange); + t.deepEqual(oldRange, newRange, "the old range and the new range"); + t.ok(oldRange.start !== newRange.start, "the old range's start position " + + "is distinct from the new range's start position"); + t.ok(oldRange.end !== newRange.end, "the old range's end position is " + + "distinct from the new range's end position"); + t.ok(oldRange !== newRange, "the old range is distinct from the new " + + "range"); +}; + +exports.testComparePositions = function() { + t.equal(Range.comparePositions({ row: 0, col: 0 }, + { row: 0, col: 0 }), 0, '0,0 = 0,0'); + t.ok(Range.comparePositions({ row: 0, col: 0 }, + { row: 1, col: 0 }) < 0, '0,0 < 1,0'); + t.ok(Range.comparePositions({ row: 0, col: 0 }, + { row: 0, col: 1 }) < 0, '0,0 < 0,1'); + t.ok(Range.comparePositions({ row: 1, col: 0 }, + { row: 0, col: 0 }) > 0, '1,0 > 0,0'); + t.ok(Range.comparePositions({ row: 0, col: 1 }, + { row: 0, col: 0 }) > 0, '0,1 > 0,0'); +}; + +exports.testExtendRange = function() { + t.deepEqual(Range.extendRange({ + start: { row: 1, col: 2 }, + end: { row: 3, col: 4 } + }, { row: 5, col: 6 }), { + start: { row: 1, col: 2 }, + end: { row: 8, col: 10 } + }, '[ 1,2 3,4 ] extended by 5,6 = [ 1,2 8,10 ]'); + t.deepEqual(Range.extendRange({ + start: { row: 7, col: 8 }, + end: { row: 9, col: 10 } + }, { row: 0, col: 0 }), { + start: { row: 7, col: 8 }, + end: { row: 9, col: 10 } + }, '[ 7,8 9,10 ] extended by 0,0 remains the same'); +}; + +exports.testMaxPosition = function() { + t.deepEqual(Range.maxPosition({ row: 0, col: 0 }, + { row: 0, col: 0 }), { row: 0, col: 0 }, 'max(0,0 0,0) = 0,0'); + t.deepEqual(Range.maxPosition({ row: 0, col: 0 }, + { row: 1, col: 0 }), { row: 1, col: 0 }, 'max(0,0 1,0) = 1,0'); + t.deepEqual(Range.maxPosition({ row: 0, col: 0 }, + { row: 0, col: 1 }), { row: 0, col: 1 }, 'max(0,0 0,1) = 0,1'); + t.deepEqual(Range.maxPosition({ row: 1, col: 0 }, + { row: 0, col: 0 }), { row: 1, col: 0 }, 'max(1,0 0,0) = 1,0'); + t.deepEqual(Range.maxPosition({ row: 0, col: 1 }, + { row: 0, col: 0 }), { row: 0, col: 1 }, 'max(0,1 0,0) = 0,1'); +}; + +exports.testNormalizeRange = function() { + t.deepEqual(Range.normalizeRange({ + start: { row: 0, col: 0 }, + end: { row: 0, col: 0 } + }), { + start: { row: 0, col: 0 }, + end: { row: 0, col: 0 } + }, 'normalize(0,0 0,0) and (0,0 0,0)'); + t.deepEqual(Range.normalizeRange({ + start: { row: 1, col: 2 }, + end: { row: 3, col: 4 } + }), { + start: { row: 1, col: 2 }, + end: { row: 3, col: 4 } + }, 'normalize(1,2 3,4) and (1,2 3,4)'); + t.deepEqual(Range.normalizeRange({ + start: { row: 4, col: 3 }, + end: { row: 2, col: 1 } + }), { + start: { row: 2, col: 1 }, + end: { row: 4, col: 3 } + }, 'normalize(4,3 2,1) and (2,1 4,3)'); +}; + +exports.testUnionRanges = function() { + t.deepEqual(Range.unionRanges({ + start: { row: 1, col: 2 }, + end: { row: 3, col: 4 } + }, { + start: { row: 5, col: 6 }, + end: { row: 7, col: 8 } + }), { + start: { row: 1, col: 2 }, + end: { row: 7, col: 8 } + }, '[ 1,2 3,4 ] union [ 5,6 7,8 ] = [ 1,2 7,8 ]'); + t.deepEqual(Range.unionRanges({ + start: { row: 4, col: 4 }, + end: { row: 5, col: 5 } + }, { + start: { row: 3, col: 3 }, + end: { row: 4, col: 5 } + }), { + start: { row: 3, col: 3 }, + end: { row: 5, col: 5 } + }, '[ 4,4 5,5 ] union [ 3,3 4,5 ] = [ 3,3 5,5 ]'); +}; + + +}); From 921bbe894968877f3f6c050aec13298e646ce21a Mon Sep 17 00:00:00 2001 From: Colin Gourlay Date: Thu, 9 Dec 2010 06:34:56 +0800 Subject: [PATCH 77/90] Added Python syntax support --- lib/ace/mode/Python.js | 87 ++++++++++++++++ lib/ace/mode/PythonHighlightRules.js | 147 +++++++++++++++++++++++++++ 2 files changed, 234 insertions(+) create mode 100644 lib/ace/mode/Python.js create mode 100644 lib/ace/mode/PythonHighlightRules.js diff --git a/lib/ace/mode/Python.js b/lib/ace/mode/Python.js new file mode 100644 index 00000000..a5df5c02 --- /dev/null +++ b/lib/ace/mode/Python.js @@ -0,0 +1,87 @@ +/** + * Ajax.org Code Editor (ACE) + * + * @copyright 2010, Ajax.org Services B.V. + * @license LGPLv3 + * @author Fabian Jakobs + */ +require.def("ace/mode/Python", + [ + "ace/lib/oop", + "ace/mode/Text", + "ace/Tokenizer", + "ace/mode/PythonHighlightRules", + "ace/mode/MatchingBraceOutdent", + "ace/Range" + ], function(oop, TextMode, Tokenizer, PythonHighlightRules, MatchingBraceOutdent, Range) { + +var Python = function() { + this.$tokenizer = new Tokenizer(new PythonHighlightRules().getRules()); + this.$outdent = new MatchingBraceOutdent(); +}; +oop.inherits(Python, TextMode); + +(function() { + + this.toggleCommentLines = function(state, doc, range) { + var outdent = true; + var outentedRows = []; + var re = /^(\s*)#/; + + for (var i=range.start.row; i<= range.end.row; i++) { + if (!re.test(doc.getLine(i))) { + outdent = false; + break; + } + } + + if (outdent) { + var deleteRange = new Range(0, 0, 0, 0); + for (var i=range.start.row; i<= range.end.row; i++) + { + var line = doc.getLine(i).replace(re, "$1"); + deleteRange.start.row = i; + deleteRange.end.row = i; + deleteRange.end.column = line.length + 2; + doc.replace(deleteRange, line); + } + return -2; + } + else { + return doc.indentRows(range, "#"); + } + }; + + this.getNextLineIndent = function(state, line, tab) { + var indent = this.$getIndent(line); + + var tokenizedLine = this.$tokenizer.getLineTokens(line, state); + var tokens = tokenizedLine.tokens; + var endState = tokenizedLine.state; + + if (tokens.length && tokens[tokens.length-1].type == "comment") { + return indent; + } + + if (state == "start") { + var match = line.match(/^.*[\{\(\[\:]\s*$/); + if (match) { + indent += tab; + } + } + + return indent; + }; + + this.checkOutdent = function(state, line, input) { + return this.$outdent.checkOutdent(line, input); + }; + + this.autoOutdent = function(state, doc, row) { + return this.$outdent.autoOutdent(doc, row); + }; + +}).call(Python.prototype); + +return Python; +}); diff --git a/lib/ace/mode/PythonHighlightRules.js b/lib/ace/mode/PythonHighlightRules.js new file mode 100644 index 00000000..aa5797cb --- /dev/null +++ b/lib/ace/mode/PythonHighlightRules.js @@ -0,0 +1,147 @@ +/** + * Ajax.org Code Editor (ACE) + * + * @copyright 2010, Ajax.org Services B.V. + * @license LGPLv3 + * @author Fabian Jakobs + * + * TODO: python delimiters + */ +require.def("ace/mode/PythonHighlightRules", + [ + "ace/lib/oop", + "ace/lib/lang", + "ace/mode/TextHighlightRules" + ], function(oop, lang, TextHighlightRules) { + + +PythonHighlightRules = function() { + + var keywords = lang.arrayToMap( + ("and|as|assert|break|class|continue|def|del|elif|else|except|exec|" + + "finally|for|from|global|if|import|in|is|lambda|not|or|pass|print|" + + "raise|return|try|while|with|yield").split("|") + ); + + var builtinConstants = lang.arrayToMap( + ("True|False|None|NotImplemented|Ellipsis|__debug__").split("|") + ); + + var builtinFunctions = lang.arrayToMap( + ("abs|divmod|input|open|staticmethod|all|enumerate|int|ord|str|any|" + + "eval|isinstance|pow|sum|basestring|execfile|issubclass|print|super|" + + "binfile|iter|property|tuple|bool|filter|len|range|type|bytearray|" + + "float|list|raw_input|unichr|callable|format|locals|reduce|unicode|" + + "chr|frozenset|long|reload|vars|classmethod|getattr|map|repr|xrange|" + + "cmp|globals|max|reversed|zip|compile|hasattr|memoryview|round|" + + "__import__|complex|hash|min|set|apply|delattr|help|next|setattr|" + + "buffer|dict|hex|object|slice|coerce|dir|id|oct|sorted|intern").split("|") + ); + + var futureReserved = lang.arrayToMap( + ("").split("|") + ); + + var strPre = "(?:(?:[rubRUB])|(?:[ubUB][rR]))?"; + + var decimalInteger = "(?:(?:[1-9]\\d*)|(?:0))"; + var octInteger = "(?:0[oO]?[0-7]+)"; + var hexInteger = "(?:0[xX][\\dA-Fa-f]+)"; + var binInteger = "(?:0[bB][01]+)"; + var integer = "(?:" + decimalInteger + "|" + octInteger + "|" + hexInteger + "|" + binInteger + ")"; + + var exponent = "(?:[eE][+-]?\\d+)"; + var fraction = "(?:\\.\\d+)"; + var intPart = "(?:\\d+)"; + var pointFloat = "(?:(?:" + intPart + "?" + fraction + ")|(?:" + intPart + "\\.))"; + var exponentFloat = "(?:(?:" + pointFloat + "|" + intPart + ")" + exponent + ")"; + var floatNumber = "(?:" + exponentFloat + "|" + pointFloat + ")"; + + this.$rules = { + "start" : [ { + token : "comment", + regex : "#.*$" + }, { + token : "string", // """ string + regex : strPre + '"{3}(?:(?:.)|(?:^"{3}))*?"{3}' + }, { + token : "string", // multi line """ string start + regex : strPre + '"{3}.*$', + next : "qqstring" + }, { + token : "string", // " string + regex : strPre + '"(?:(?:\\\\.)|(?:[^"\\\\]))*?"' + }, { + token : "string", // ''' string + regex : strPre + "'{3}(?:(?:.)|(?:^'{3}))*?'{3}" + }, { + token : "string", // multi line ''' string start + regex : strPre + "'{3}.*$", + next : "qstring" + }, { + token : "string", // ' string + regex : strPre + "'(?:(?:\\\\.)|(?:[^'\\\\]))*?'" + }, { + token : "constant.numeric", // imaginary + regex : "(?:" + floatNumber + "|\\d+)[jJ]\\b" + }, { + token : "constant.numeric", // float + regex : floatNumber + }, { + token : "constant.numeric", // long integer + regex : integer + "[lL]\\b" + }, { + token : "constant.numeric", // integer + regex : integer + "\\b" + }, { + token : function(value) { + if (keywords[value]) + return "keyword"; + else if (builtinConstants[value]) + return "constant.language"; + else if (futureReserved[value]) + return "invalid.illegal"; + else if (builtinFunctions[value]) + return "support.function"; + else if (value == "debugger") + return "invalid.deprecated"; + else + return "identifier"; + }, + regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" + }, { + token : "keyword.operator", + regex : "\\+|\\-|\\*|\\*\\*|\\/|\\/\\/|%|<<|>>|&|\\||\\^|~|<|>|<=|=>|==|!=|<>|=" + }, { + token : "lparen", + regex : "[\\[\\(\\{]" + }, { + token : "rparen", + regex : "[\\]\\)\\}]" + }, { + token : "text", + regex : "\\s+" + } ], + "qqstring" : [ { + token : "string", // multi line """ string end + regex : '(?:^"{3})*?"{3}', + next : "start" + }, { + token : "string", + regex : '.+' + } ], + "qstring" : [ { + token : "string", // multi line ''' string end + regex : "(?:^'{3})*?'{3}", + next : "start" + }, { + token : "string", + regex : '.+' + } ] + }; +}; + +oop.inherits(PythonHighlightRules, TextHighlightRules); + +return PythonHighlightRules; +}); \ No newline at end of file From d566212191baa230507d9884d6a51ce4a7fd5134 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Thu, 9 Dec 2010 10:36:43 +0100 Subject: [PATCH 78/90] use lower case file names step #1 --- lib/ace/mode/Python.js | 87 ------------- lib/ace/mode/_python.js | 116 ++++++++++++++++++ ...ightRules.js => python_highlight_rules.js} | 53 ++++++-- 3 files changed, 157 insertions(+), 99 deletions(-) delete mode 100644 lib/ace/mode/Python.js create mode 100644 lib/ace/mode/_python.js rename lib/ace/mode/{PythonHighlightRules.js => python_highlight_rules.js} (71%) diff --git a/lib/ace/mode/Python.js b/lib/ace/mode/Python.js deleted file mode 100644 index a5df5c02..00000000 --- a/lib/ace/mode/Python.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * Ajax.org Code Editor (ACE) - * - * @copyright 2010, Ajax.org Services B.V. - * @license LGPLv3 - * @author Fabian Jakobs - */ -require.def("ace/mode/Python", - [ - "ace/lib/oop", - "ace/mode/Text", - "ace/Tokenizer", - "ace/mode/PythonHighlightRules", - "ace/mode/MatchingBraceOutdent", - "ace/Range" - ], function(oop, TextMode, Tokenizer, PythonHighlightRules, MatchingBraceOutdent, Range) { - -var Python = function() { - this.$tokenizer = new Tokenizer(new PythonHighlightRules().getRules()); - this.$outdent = new MatchingBraceOutdent(); -}; -oop.inherits(Python, TextMode); - -(function() { - - this.toggleCommentLines = function(state, doc, range) { - var outdent = true; - var outentedRows = []; - var re = /^(\s*)#/; - - for (var i=range.start.row; i<= range.end.row; i++) { - if (!re.test(doc.getLine(i))) { - outdent = false; - break; - } - } - - if (outdent) { - var deleteRange = new Range(0, 0, 0, 0); - for (var i=range.start.row; i<= range.end.row; i++) - { - var line = doc.getLine(i).replace(re, "$1"); - deleteRange.start.row = i; - deleteRange.end.row = i; - deleteRange.end.column = line.length + 2; - doc.replace(deleteRange, line); - } - return -2; - } - else { - return doc.indentRows(range, "#"); - } - }; - - this.getNextLineIndent = function(state, line, tab) { - var indent = this.$getIndent(line); - - var tokenizedLine = this.$tokenizer.getLineTokens(line, state); - var tokens = tokenizedLine.tokens; - var endState = tokenizedLine.state; - - if (tokens.length && tokens[tokens.length-1].type == "comment") { - return indent; - } - - if (state == "start") { - var match = line.match(/^.*[\{\(\[\:]\s*$/); - if (match) { - indent += tab; - } - } - - return indent; - }; - - this.checkOutdent = function(state, line, input) { - return this.$outdent.checkOutdent(line, input); - }; - - this.autoOutdent = function(state, doc, row) { - return this.$outdent.autoOutdent(doc, row); - }; - -}).call(Python.prototype); - -return Python; -}); diff --git a/lib/ace/mode/_python.js b/lib/ace/mode/_python.js new file mode 100644 index 00000000..d1e9a6bd --- /dev/null +++ b/lib/ace/mode/_python.js @@ -0,0 +1,116 @@ +/* ***** BEGIN LICENSE BLOCK ***** +* Version: MPL 1.1/GPL 2.0/LGPL 2.1 +* +* The contents of this file are subject to the Mozilla Public License Version +* 1.1 (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" basis, +* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +* for the specific language governing rights and limitations under the +* License. +* +* The Original Code is Ajax.org Code Editor (ACE). +* +* The Initial Developer of the Original Code is +* Ajax.org Services B.V. +* Portions created by the Initial Developer are Copyright (C) 2010 +* the Initial Developer. All Rights Reserved. +* +* Contributor(s): +* Fabian Jakobs +* +* Alternatively, the contents of this file may be used under the terms of +* either the GNU General Public License Version 2 or later (the "GPL"), or +* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +* in which case the provisions of the GPL or the LGPL are applicable instead +* of those above. If you wish to allow use of your version of this file only +* under the terms of either the GPL or the LGPL, and not to allow others to +* use your version of this file under the terms of the MPL, indicate your +* decision by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL or the LGPL. If you do not delete +* the provisions above, a recipient may use your version of this file under +* the terms of any one of the MPL, the GPL or the LGPL. +* +* ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +var oop = require("../lib/oop"); +var TextMode = require("./text"); +var Tokenizer = require("../tokenizer"); +var PythonHighlightRules = require("./python_highlight_rules"); +var MatchingBraceOutdent = require("./matching_brace_outdent"); +var Range = require("../range"); + +var Python = function() { + this.$tokenizer = new Tokenizer(new PythonHighlightRules().getRules()); + this.$outdent = new MatchingBraceOutdent(); +}; +oop.inherits(Python, TextMode); + +(function() { + + this.toggleCommentLines = function(state, doc, range) { + var outdent = true; + var outentedRows = []; + var re = /^(\s*)#/; + + for (var i=range.start.row; i<= range.end.row; i++) { + if (!re.test(doc.getLine(i))) { + outdent = false; + break; + } + } + + if (outdent) { + var deleteRange = new Range(0, 0, 0, 0); + for (var i=range.start.row; i<= range.end.row; i++) + { + var line = doc.getLine(i).replace(re, "$1"); + deleteRange.start.row = i; + deleteRange.end.row = i; + deleteRange.end.column = line.length + 2; + doc.replace(deleteRange, line); + } + return -2; + } + else { + return doc.indentRows(range, "#"); + } + }; + + this.getNextLineIndent = function(state, line, tab) { + var indent = this.$getIndent(line); + + var tokenizedLine = this.$tokenizer.getLineTokens(line, state); + var tokens = tokenizedLine.tokens; + var endState = tokenizedLine.state; + + if (tokens.length && tokens[tokens.length-1].type == "comment") { + return indent; + } + + if (state == "start") { + var match = line.match(/^.*[\{\(\[\:]\s*$/); + if (match) { + indent += tab; + } + } + + return indent; + }; + + this.checkOutdent = function(state, line, input) { + return this.$outdent.checkOutdent(line, input); + }; + + this.autoOutdent = function(state, doc, row) { + return this.$outdent.autoOutdent(doc, row); + }; + +}).call(Python.prototype); + +return Python; +}); diff --git a/lib/ace/mode/PythonHighlightRules.js b/lib/ace/mode/python_highlight_rules.js similarity index 71% rename from lib/ace/mode/PythonHighlightRules.js rename to lib/ace/mode/python_highlight_rules.js index aa5797cb..57053e8c 100644 --- a/lib/ace/mode/PythonHighlightRules.js +++ b/lib/ace/mode/python_highlight_rules.js @@ -1,19 +1,48 @@ -/** - * Ajax.org Code Editor (ACE) +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Ajax.org Code Editor (ACE). + * + * The Initial Developer of the Original Code is + * Ajax.org Services B.V. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Fabian Jakobs + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** * - * @copyright 2010, Ajax.org Services B.V. - * @license LGPLv3 - * @author Fabian Jakobs - * * TODO: python delimiters */ -require.def("ace/mode/PythonHighlightRules", - [ - "ace/lib/oop", - "ace/lib/lang", - "ace/mode/TextHighlightRules" - ], function(oop, lang, TextHighlightRules) { +define(function(require, exports, module) { + +var oop = require("../lib/oop"); +var lang = require("../lib/lang"); +var TextHighlightRules = require("./text_highlight_rules"); PythonHighlightRules = function() { From 14593ac1549c1b16ccb7d8129fc20f6b2bf43bc5 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Thu, 9 Dec 2010 10:37:13 +0100 Subject: [PATCH 79/90] use lower case file names step #2 --- lib/ace/mode/{_python.js => python.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/ace/mode/{_python.js => python.js} (100%) diff --git a/lib/ace/mode/_python.js b/lib/ace/mode/python.js similarity index 100% rename from lib/ace/mode/_python.js rename to lib/ace/mode/python.js From 2f36e65d43266648fc3aef8b25074758ea1db6aa Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Thu, 9 Dec 2010 10:59:57 +0100 Subject: [PATCH 80/90] update editor demo to add python mode --- demo/editor-build.html | 34 ++++++++++++++++++++++++++++++++-- demo/editor.html | 32 +++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/demo/editor-build.html b/demo/editor-build.html index 7f791814..8ebcdf9e 100644 --- a/demo/editor-build.html +++ b/demo/editor-build.html @@ -62,6 +62,7 @@ + @@ -72,6 +73,7 @@ + @@ -132,10 +134,30 @@ + + + + + + +

    Juhu Kinners

    diff --git a/lib/ace/mode/python.js b/lib/ace/mode/python.js index d1e9a6bd..1e7c9796 100644 --- a/lib/ace/mode/python.js +++ b/lib/ace/mode/python.js @@ -37,12 +37,12 @@ define(function(require, exports, module) { -var oop = require("../lib/oop"); -var TextMode = require("./text"); -var Tokenizer = require("../tokenizer"); -var PythonHighlightRules = require("./python_highlight_rules"); -var MatchingBraceOutdent = require("./matching_brace_outdent"); -var Range = require("../range"); +var oop = require("pilot/oop").oop; +var TextMode = require("./text").Text; +var Tokenizer = require("../tokenizer").Tokenizer; +var PythonHighlightRules = require("./python_highlight_rules").PythonHighlightRules; +var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; +var Range = require("../range").Range; var Python = function() { this.$tokenizer = new Tokenizer(new PythonHighlightRules().getRules()); @@ -112,5 +112,5 @@ oop.inherits(Python, TextMode); }).call(Python.prototype); -return Python; +exports.Python = Python; }); diff --git a/lib/ace/mode/python_highlight_rules.js b/lib/ace/mode/python_highlight_rules.js index 57053e8c..0a48fcd3 100644 --- a/lib/ace/mode/python_highlight_rules.js +++ b/lib/ace/mode/python_highlight_rules.js @@ -40,9 +40,9 @@ define(function(require, exports, module) { -var oop = require("../lib/oop"); -var lang = require("../lib/lang"); -var TextHighlightRules = require("./text_highlight_rules"); +var oop = require("pilot/oop").oop; +var lang = require("pilot/lang").lang; +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; PythonHighlightRules = function() { @@ -172,5 +172,5 @@ PythonHighlightRules = function() { oop.inherits(PythonHighlightRules, TextHighlightRules); -return PythonHighlightRules; +exports.PythonHighlightRules = PythonHighlightRules; }); \ No newline at end of file diff --git a/support/requirejs b/support/requirejs index 0095dc02..819c4e7b 160000 --- a/support/requirejs +++ b/support/requirejs @@ -1 +1 @@ -Subproject commit 0095dc028d0e6f3d40587071fa67622930aa880e +Subproject commit 819c4e7b9b1e6e5f99696b5c9f2805891a9e7cfd From 5224b0cf97b22f03c115ab48cffada84ea2a2327 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Fri, 10 Dec 2010 17:26:14 +0100 Subject: [PATCH 86/90] add python file to the demo --- editor.html | 41 ++++++++++++++++++++++------------------- lib/ace/scrollbar.js | 2 +- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/editor.html b/editor.html index cb2919cb..81ceef48 100644 --- a/editor.html +++ b/editor.html @@ -87,6 +87,7 @@ + @@ -97,6 +98,7 @@ + @@ -136,8 +138,7 @@ font-family: Monaco, "Courier New", monospace; font-size: 12px; cursor: text; -} - +} + - +# If no arguments were given, print a helpful message +if len(sys.argv)==1: + print 'Usage: celsius temp1 temp2 ...' + sys.exit(0) - - -

    Juhu Kinners

    - - - +# Loop over the arguments +for i in sys.argv[1:]: + try: + fahrenheit=float(string.atoi(i)) + except string.atoi_error: + print repr(i), "not a numeric value" + else: + celsius=(fahrenheit-32)*5.0/9.0 + print '%i\260F = %i\260C' % (int(fahrenheit), int(celsius+.5)) + - + \ No newline at end of file diff --git a/lib/ace/scrollbar.js b/lib/ace/scrollbar.js index 8ff25a14..67411c15 100644 --- a/lib/ace/scrollbar.js +++ b/lib/ace/scrollbar.js @@ -62,7 +62,7 @@ var ScrollBar = function(parent) { oop.implement(this, EventEmitter); this.onScroll = function() { - this.$dispatchEvent("scroll", {data: this.element.scrollTop}); + this._dispatchEvent("scroll", {data: this.element.scrollTop}); }; this.getWidth = function() { From cbb621514583cf84fb82d383699466c54c03d210 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Fri, 10 Dec 2010 18:07:06 +0100 Subject: [PATCH 87/90] rename all language mode classes to 'Mode'. --- demo/demo_startup.js | 12 ++++++------ lib/ace/document.js | 2 +- lib/ace/mode/css.js | 10 +++++----- lib/ace/mode/html.js | 14 +++++++------- lib/ace/mode/javascript.js | 10 +++++----- lib/ace/mode/python.js | 10 +++++----- lib/ace/mode/text.js | 6 +++--- lib/ace/mode/xml.js | 10 +++++----- lib/ace/test/mode/css_test.js | 15 +++++---------- lib/ace/test/mode/css_tokenizer_test.js | 9 +++------ lib/ace/test/mode/html_test.js | 15 +++++---------- lib/ace/test/mode/html_tokenizer_test.js | 9 +++------ lib/ace/test/mode/javascript_test.js | 18 ++++++------------ lib/ace/test/mode/javascript_tokenizer_test.js | 9 +++------ lib/ace/test/mode/text_test.js | 15 +++++---------- lib/ace/test/mode/xml_test.js | 18 ++++++------------ lib/ace/test/mode/xml_tokenizer_test.js | 9 +++------ lib/ace/test/text_edit_test.js | 8 ++++---- 18 files changed, 80 insertions(+), 119 deletions(-) diff --git a/demo/demo_startup.js b/demo/demo_startup.js index 139850e8..99823cc9 100644 --- a/demo/demo_startup.js +++ b/demo/demo_startup.js @@ -46,12 +46,12 @@ exports.launch = function(env) { var Renderer = require("ace/virtual_renderer").VirtualRenderer; var theme = require("ace/theme/textmate"); var Document = require("ace/document").Document; - var JavaScriptMode = require("ace/mode/javascript").JavaScript; - var CssMode = require("ace/mode/css").Css; - var HtmlMode = require("ace/mode/html").Html; - var XmlMode = require("ace/mode/xml").Xml; - var PythonMode = require("ace/mode/python").Python; - var TextMode = require("ace/mode/text").Text; + var JavaScriptMode = require("ace/mode/javascript").Mode; + var CssMode = require("ace/mode/css").Mode; + var HtmlMode = require("ace/mode/html").Mode; + var XmlMode = require("ace/mode/xml").Mode; + var PythonMode = require("ace/mode/python").Mode; + var TextMode = require("ace/mode/text").Mode; var UndoManager = require("ace/undomanager").UndoManager; var docs = {}; diff --git a/lib/ace/document.js b/lib/ace/document.js index 671244f2..a705b682 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -41,7 +41,7 @@ var oop = require("pilot/oop").oop; var lang = require("pilot/lang").lang; var EventEmitter = require("pilot/event_emitter").EventEmitter; var Selection = require("ace/selection").Selection; -var TextMode = require("ace/mode/text").Text; +var TextMode = require("ace/mode/text").Mode; var Range = require("ace/range").Range; var Document = function(text, mode) { diff --git a/lib/ace/mode/css.js b/lib/ace/mode/css.js index 4c6bd198..7f69fdf1 100644 --- a/lib/ace/mode/css.js +++ b/lib/ace/mode/css.js @@ -38,16 +38,16 @@ define(function(require, exports, module) { var oop = require("pilot/oop").oop; -var TextMode = require("ace/mode/text").Text; +var TextMode = require("ace/mode/text").Mode; var Tokenizer = require("ace/tokenizer").Tokenizer; var CssHighlightRules = require("ace/mode/css_highlight_rules").CssHighlightRules; var MatchingBraceOutdent = require("ace/mode/matching_brace_outdent").MatchingBraceOutdent; -var Css = function() { +var Mode = function() { this.$tokenizer = new Tokenizer(new CssHighlightRules().getRules()); this.$outdent = new MatchingBraceOutdent(); }; -oop.inherits(Css, TextMode); +oop.inherits(Mode, TextMode); (function() { @@ -76,8 +76,8 @@ oop.inherits(Css, TextMode); return this.$outdent.autoOutdent(doc, row); }; -}).call(Css.prototype); +}).call(Mode.prototype); -exports.Css = Css; +exports.Mode = Mode; }); diff --git a/lib/ace/mode/html.js b/lib/ace/mode/html.js index f6587676..25746d8e 100644 --- a/lib/ace/mode/html.js +++ b/lib/ace/mode/html.js @@ -38,19 +38,19 @@ define(function(require, exports, module) { var oop = require("pilot/oop").oop; -var TextMode = require("ace/mode/text").Text; -var JavaScriptMode = require("ace/mode/javascript").JavaScript; -var CssMode = require("ace/mode/css").Css; +var TextMode = require("ace/mode/text").Mode; +var JavaScriptMode = require("ace/mode/javascript").Mode; +var CssMode = require("ace/mode/css").Mode; var Tokenizer = require("ace/tokenizer").Tokenizer; var HtmlHighlightRules = require("ace/mode/html_highlight_rules").HtmlHighlightRules; -var Html = function() { +var Mode = function() { this.$tokenizer = new Tokenizer(new HtmlHighlightRules().getRules()); this.$js = new JavaScriptMode(); this.$css = new CssMode(); }; -oop.inherits(Html, TextMode); +oop.inherits(Mode, TextMode); (function() { @@ -95,7 +95,7 @@ oop.inherits(Html, TextMode); return defaultHandler ? defaultHandler() : undefined; }; -}).call(Html.prototype); +}).call(Mode.prototype); -exports.Html = Html; +exports.Mode = Mode; }); diff --git a/lib/ace/mode/javascript.js b/lib/ace/mode/javascript.js index e8bc67a6..66d6c317 100644 --- a/lib/ace/mode/javascript.js +++ b/lib/ace/mode/javascript.js @@ -38,17 +38,17 @@ define(function(require, exports, module) { var oop = require("pilot/oop").oop; -var TextMode = require("ace/mode/text").Text; +var TextMode = require("ace/mode/text").Mode; var Tokenizer = require("ace/tokenizer").Tokenizer; var JavaScriptHighlightRules = require("ace/mode/javascript_highlight_rules").JavaScriptHighlightRules; var MatchingBraceOutdent = require("ace/mode/matching_brace_outdent").MatchingBraceOutdent; var Range = require("ace/range").Range; -var JavaScript = function() { +var Mode = function() { this.$tokenizer = new Tokenizer(new JavaScriptHighlightRules().getRules()); this.$outdent = new MatchingBraceOutdent(); }; -oop.inherits(JavaScript, TextMode); +oop.inherits(Mode, TextMode); (function() { @@ -121,7 +121,7 @@ oop.inherits(JavaScript, TextMode); return this.$outdent.autoOutdent(doc, row); }; -}).call(JavaScript.prototype); +}).call(Mode.prototype); -exports.JavaScript = JavaScript; +exports.Mode = Mode; }); diff --git a/lib/ace/mode/python.js b/lib/ace/mode/python.js index 1e7c9796..4111b877 100644 --- a/lib/ace/mode/python.js +++ b/lib/ace/mode/python.js @@ -38,17 +38,17 @@ define(function(require, exports, module) { var oop = require("pilot/oop").oop; -var TextMode = require("./text").Text; +var TextMode = require("./text").Mode; var Tokenizer = require("../tokenizer").Tokenizer; var PythonHighlightRules = require("./python_highlight_rules").PythonHighlightRules; var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; var Range = require("../range").Range; -var Python = function() { +var Mode = function() { this.$tokenizer = new Tokenizer(new PythonHighlightRules().getRules()); this.$outdent = new MatchingBraceOutdent(); }; -oop.inherits(Python, TextMode); +oop.inherits(Mode, TextMode); (function() { @@ -110,7 +110,7 @@ oop.inherits(Python, TextMode); return this.$outdent.autoOutdent(doc, row); }; -}).call(Python.prototype); +}).call(Mode.prototype); -exports.Python = Python; +exports.Mode = Mode; }); diff --git a/lib/ace/mode/text.js b/lib/ace/mode/text.js index 1a73194f..0e18d038 100644 --- a/lib/ace/mode/text.js +++ b/lib/ace/mode/text.js @@ -40,7 +40,7 @@ define(function(require, exports, module) { var Tokenizer = require("ace/tokenizer").Tokenizer; var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules; -var Text = function() { +var Mode = function() { this.$tokenizer = new Tokenizer(new TextHighlightRules().getRules()); }; @@ -74,7 +74,7 @@ var Text = function() { return ""; }; -}).call(Text.prototype); +}).call(Mode.prototype); -exports.Text = Text; +exports.Mode = Mode; }); diff --git a/lib/ace/mode/xml.js b/lib/ace/mode/xml.js index 0a83adb1..e51bd7f8 100644 --- a/lib/ace/mode/xml.js +++ b/lib/ace/mode/xml.js @@ -38,15 +38,15 @@ define(function(require, exports, module) { var oop = require("pilot/oop").oop; -var TextMode = require("ace/mode/text").Text; +var TextMode = require("ace/mode/text").Mode; var Tokenizer = require("ace/tokenizer").Tokenizer; var XmlHighlightRules = require("ace/mode/xml_highlight_rules").XmlHighlightRules; -var Xml = function() { +var Mode = function() { this.$tokenizer = new Tokenizer(new XmlHighlightRules().getRules()); }; -oop.inherits(Xml, TextMode); +oop.inherits(Mode, TextMode); (function() { @@ -54,7 +54,7 @@ oop.inherits(Xml, TextMode); return this.$getIndent(line); }; -}).call(Xml.prototype); +}).call(Mode.prototype); -exports.Xml = Xml; +exports.Mode = Mode; }); diff --git a/lib/ace/test/mode/css_test.js b/lib/ace/test/mode/css_test.js index 3fc588ea..27b5e55a 100644 --- a/lib/ace/test/mode/css_test.js +++ b/lib/ace/test/mode/css_test.js @@ -35,17 +35,12 @@ * * ***** END LICENSE BLOCK ***** */ -require.def([ - "ace/Document", - "ace/Range", - "ace/mode/Css" - ], function( - Document, - Range, - cssMod - ) { +define(function(require, exports, module) { + +var Document = require("ace/document").Document; +var Range = require("ace/range").Range; +var Css = require("ace/mode/css").Mode; -var CssMode = cssMod.Css; var CssTest = new TestCase("mode.CssTest", { setUp : function() { diff --git a/lib/ace/test/mode/css_tokenizer_test.js b/lib/ace/test/mode/css_tokenizer_test.js index 7baedfab..858770ba 100644 --- a/lib/ace/test/mode/css_tokenizer_test.js +++ b/lib/ace/test/mode/css_tokenizer_test.js @@ -35,13 +35,10 @@ * * ***** END LICENSE BLOCK ***** */ -require.def([ - "ace/mode/Css" - ], function( - cssMod - ) { +define(function(require, exports, module) { + +var Css = require("ace/mode/css").Mode; -var CssMode = cssMod.Css; var CssTest = new TestCase("mode.CssTest", { setUp : function() { diff --git a/lib/ace/test/mode/html_test.js b/lib/ace/test/mode/html_test.js index ae80f579..1e631b55 100644 --- a/lib/ace/test/mode/html_test.js +++ b/lib/ace/test/mode/html_test.js @@ -35,17 +35,12 @@ * * ***** END LICENSE BLOCK ***** */ -require.def([ - "ace/Document", - "ace/Range", - "ace/mode/Html" - ], function( - Document, - Range, - htmlMod - ) { +define(function(require, exports, module) { + +var Document = require("ace/document").Document; +var Range = require("ace/range").Range; +var Html = require("ace/mode/html").Mode; -var HtmlMode = htmlMod.Html; var HtmlTest = new TestCase("mode.HtmlTest", { setUp : function() { diff --git a/lib/ace/test/mode/html_tokenizer_test.js b/lib/ace/test/mode/html_tokenizer_test.js index b95bbe4e..6c89dc81 100644 --- a/lib/ace/test/mode/html_tokenizer_test.js +++ b/lib/ace/test/mode/html_tokenizer_test.js @@ -35,13 +35,10 @@ * * ***** END LICENSE BLOCK ***** */ -require.def([ - "ace/mode/Html" - ], function( - htmlMod - ) { +define(function(require, exports, module) { + +var Html = require("ace/mode/html").Mode; -var HtmlMode = htmlMod.Html; var HtmlTest = new TestCase("mode.HtmlTest", { setUp : function() { diff --git a/lib/ace/test/mode/javascript_test.js b/lib/ace/test/mode/javascript_test.js index 2374edde..52de56d1 100644 --- a/lib/ace/test/mode/javascript_test.js +++ b/lib/ace/test/mode/javascript_test.js @@ -35,19 +35,13 @@ * * ***** END LICENSE BLOCK ***** */ -require.def([ - "ace/Document", - "ace/Range", - "ace/Tokenizer", - "ace/mode/JavaScript" - ], function( - Document, - Range, - Tokenizer, - jsMod - ) { +define(function(require, exports, module) { + +var Document = require("ace/document").Document; +var Range = require("ace/range").Range; +var Tokenizer = require("ace/tokenizer").Tokenizer; +var JavaScript = require("ace/mode/javascript").Mode; -var JavaScriptMode = jsMod.JavaScript; var JavaScriptTest = new TestCase("mode.JavaScriptTest", { setUp : function() { diff --git a/lib/ace/test/mode/javascript_tokenizer_test.js b/lib/ace/test/mode/javascript_tokenizer_test.js index a80bcdd5..518d58e4 100644 --- a/lib/ace/test/mode/javascript_tokenizer_test.js +++ b/lib/ace/test/mode/javascript_tokenizer_test.js @@ -35,13 +35,10 @@ * * ***** END LICENSE BLOCK ***** */ -require.def([ - "ace/mode/JavaScript" - ], function( - jsMod - ) { +define(function(require, exports, module) { + +var JavaScript = require("ace/mode/javascript").Mode; -var JavaScriptMode = jsMod.JavaScript; var JavaScriptTokenizerTest = new TestCase("mode.JavaScriptTokenizerTest", { setUp : function() { diff --git a/lib/ace/test/mode/text_test.js b/lib/ace/test/mode/text_test.js index 9ca3880f..ef41e7b3 100644 --- a/lib/ace/test/mode/text_test.js +++ b/lib/ace/test/mode/text_test.js @@ -35,17 +35,12 @@ * * ***** END LICENSE BLOCK ***** */ -require.def([ - "ace/Document", - "ace/Range", - "ace/mode/Text" - ], function( - Document, - Range, - textMod - ) { +define(function(require, exports, module) { + +var Document = require("ace/document").Document; +var Range = require("ace/range").Range; +var Text = require("ace/mode/text").Mode; -var TextMode = textMod.Text; var TextTest = new TestCase("mode.TextTest", { setUp : function() { diff --git a/lib/ace/test/mode/xml_test.js b/lib/ace/test/mode/xml_test.js index f94f4a13..8f2962c6 100644 --- a/lib/ace/test/mode/xml_test.js +++ b/lib/ace/test/mode/xml_test.js @@ -35,19 +35,13 @@ * * ***** END LICENSE BLOCK ***** */ -require.def([ - "ace/Document", - "ace/Range", - "ace/Tokenizer", - "ace/mode/Xml" - ], function( - Document, - Range, - Tokenizer, - xmlMod - ) { +define(function(require, exports, module) { + +var Document = require("ace/document").Document; +var Range = require("ace/range").Range; +var Tokenizer = require("ace/tokenizer").Tokenizer; +var Xml = require("ace/mode/xml").Mode; -var XmlMode = xmlMod.Xml; var XmlTest = new TestCase("mode.XmlTest", { setUp : function() { diff --git a/lib/ace/test/mode/xml_tokenizer_test.js b/lib/ace/test/mode/xml_tokenizer_test.js index ada2ea38..cb03b4f5 100644 --- a/lib/ace/test/mode/xml_tokenizer_test.js +++ b/lib/ace/test/mode/xml_tokenizer_test.js @@ -35,13 +35,10 @@ * * ***** END LICENSE BLOCK ***** */ -require.def([ - "ace/mode/Xml" - ], function( - xmlMod - ) { +define(function(require, exports, module) { + +var Xml = require("ace/mode/xml").Mode; -var XmlMode = xmlMod.Xml; var XmlTest = new TestCase("mode.XmlTest", { setUp : function() { diff --git a/lib/ace/test/text_edit_test.js b/lib/ace/test/text_edit_test.js index c8d40c7b..fbc39d2b 100644 --- a/lib/ace/test/text_edit_test.js +++ b/lib/ace/test/text_edit_test.js @@ -48,7 +48,7 @@ global.location = browser.location; var Document = require("../document"), Editor = require("../editor"), - JavaScriptMode = require("../mode/javascript").JavaScript, + JavaScriptMode = require("../mode/javascript").Mode, MockRenderer = require("./mockrenderer"), assert = require("./assertions"); @@ -112,7 +112,7 @@ var Test = { assert.position(editor.getCursorPosition(), 2, 0); }, - "__test: indent block" : function() { + "test: indent block" : function() { var doc = new Document(["a12345", "b12345", "c12345"].join("\n")); var editor = new Editor(new MockRenderer(), doc); @@ -131,7 +131,7 @@ var Test = { assert.position(range.end, 2, 7); }, - "__test: outdent block" : function() { + "test: outdent block" : function() { var doc = new Document([" a12345", " b12345", " c12345"].join("\n")); var editor = new Editor(new MockRenderer(), doc); @@ -248,7 +248,7 @@ var Test = { assert.position(editor.getSelection().getSelectionLead(), 2, 0); }, - "__test: move lines up should select moved lines" : function() { + "test: move lines up should select moved lines" : function() { var doc = new Document(["11", "22", "33", "44"].join("\n")); var editor = new Editor(new MockRenderer(), doc); From f370a6f7fa90550ed17a63a165b2b6f78c43e52a Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Mon, 13 Dec 2010 10:39:25 +0100 Subject: [PATCH 88/90] remove lib directory from plugins otherwise the modules cannot be loaded with nodejs --- demo/boot.js | 3 +- plugins/cockpit/{lib => }/cli.js | 0 plugins/cockpit/{lib => }/index.js | 0 plugins/cockpit/{lib => }/test/assert.js | 0 plugins/cockpit/{lib => }/test/testCli.js | 0 plugins/cockpit/{lib => }/test/testNothing.js | 0 plugins/cockpit/{lib => }/ui/plain.css | 0 plugins/cockpit/{lib => }/ui/plain.js | 0 plugins/pilot/{lib => }/canon.js | 0 plugins/pilot/{lib => }/catalog.js | 0 plugins/pilot/{lib => }/commands/settings.js | 0 plugins/pilot/{lib => }/console.js | 0 plugins/pilot/{lib => }/core.js | 0 plugins/pilot/{lib => }/dom.js | 0 plugins/pilot/{lib => }/event.js | 0 plugins/pilot/{lib => }/event_emitter.js | 0 plugins/pilot/fixoldbrowsers.js | 145 +++++++++++++++++ plugins/pilot/{lib => }/index.js | 1 - plugins/pilot/{lib => }/keyboard/index.js | 0 plugins/pilot/{lib => }/keyboard/keyutil.js | 0 .../{lib => }/keyboard/tests/testKeyboard.js | 0 plugins/pilot/{lib => }/lang.js | 0 plugins/pilot/lib/fixoldbrowsers.js | 147 ------------------ plugins/pilot/{lib => }/oop.js | 0 plugins/pilot/{lib => }/plugin_manager.js | 0 plugins/pilot/{lib => }/promise.js | 0 plugins/pilot/{lib => }/proxy.js | 0 plugins/pilot/{lib => }/rangeutils.js | 0 plugins/pilot/{lib => }/settings.js | 0 plugins/pilot/{lib => }/settings/canon.js | 0 plugins/pilot/{lib => }/stacktrace.js | 0 .../pilot/{lib => }/tests/testRangeutils.js | 0 plugins/pilot/{lib => }/types.js | 0 plugins/pilot/{lib => }/types/basic.js | 0 plugins/pilot/{lib => }/types/command.js | 0 plugins/pilot/{lib => }/types/settings.js | 0 plugins/pilot/{lib => }/util.js | 0 37 files changed, 147 insertions(+), 149 deletions(-) rename plugins/cockpit/{lib => }/cli.js (100%) rename plugins/cockpit/{lib => }/index.js (100%) rename plugins/cockpit/{lib => }/test/assert.js (100%) rename plugins/cockpit/{lib => }/test/testCli.js (100%) rename plugins/cockpit/{lib => }/test/testNothing.js (100%) rename plugins/cockpit/{lib => }/ui/plain.css (100%) rename plugins/cockpit/{lib => }/ui/plain.js (100%) rename plugins/pilot/{lib => }/canon.js (100%) rename plugins/pilot/{lib => }/catalog.js (100%) rename plugins/pilot/{lib => }/commands/settings.js (100%) rename plugins/pilot/{lib => }/console.js (100%) rename plugins/pilot/{lib => }/core.js (100%) rename plugins/pilot/{lib => }/dom.js (100%) rename plugins/pilot/{lib => }/event.js (100%) rename plugins/pilot/{lib => }/event_emitter.js (100%) create mode 100644 plugins/pilot/fixoldbrowsers.js rename plugins/pilot/{lib => }/index.js (99%) rename plugins/pilot/{lib => }/keyboard/index.js (100%) rename plugins/pilot/{lib => }/keyboard/keyutil.js (100%) rename plugins/pilot/{lib => }/keyboard/tests/testKeyboard.js (100%) rename plugins/pilot/{lib => }/lang.js (100%) delete mode 100644 plugins/pilot/lib/fixoldbrowsers.js rename plugins/pilot/{lib => }/oop.js (100%) rename plugins/pilot/{lib => }/plugin_manager.js (100%) rename plugins/pilot/{lib => }/promise.js (100%) rename plugins/pilot/{lib => }/proxy.js (100%) rename plugins/pilot/{lib => }/rangeutils.js (100%) rename plugins/pilot/{lib => }/settings.js (100%) rename plugins/pilot/{lib => }/settings/canon.js (100%) rename plugins/pilot/{lib => }/stacktrace.js (100%) rename plugins/pilot/{lib => }/tests/testRangeutils.js (100%) rename plugins/pilot/{lib => }/types.js (100%) rename plugins/pilot/{lib => }/types/basic.js (100%) rename plugins/pilot/{lib => }/types/command.js (100%) rename plugins/pilot/{lib => }/types/settings.js (100%) rename plugins/pilot/{lib => }/util.js (100%) diff --git a/demo/boot.js b/demo/boot.js index 8cb3e6e3..95b704b9 100644 --- a/demo/boot.js +++ b/demo/boot.js @@ -96,7 +96,8 @@ var setupPlugins = function(config, callback) { for (i = 0; i < packages.length; i++) { location.push({ name: packages[i], - main: "index" + main: "index", + lib: "." }); knownPlugins.push(packages[i]); } diff --git a/plugins/cockpit/lib/cli.js b/plugins/cockpit/cli.js similarity index 100% rename from plugins/cockpit/lib/cli.js rename to plugins/cockpit/cli.js diff --git a/plugins/cockpit/lib/index.js b/plugins/cockpit/index.js similarity index 100% rename from plugins/cockpit/lib/index.js rename to plugins/cockpit/index.js diff --git a/plugins/cockpit/lib/test/assert.js b/plugins/cockpit/test/assert.js similarity index 100% rename from plugins/cockpit/lib/test/assert.js rename to plugins/cockpit/test/assert.js diff --git a/plugins/cockpit/lib/test/testCli.js b/plugins/cockpit/test/testCli.js similarity index 100% rename from plugins/cockpit/lib/test/testCli.js rename to plugins/cockpit/test/testCli.js diff --git a/plugins/cockpit/lib/test/testNothing.js b/plugins/cockpit/test/testNothing.js similarity index 100% rename from plugins/cockpit/lib/test/testNothing.js rename to plugins/cockpit/test/testNothing.js diff --git a/plugins/cockpit/lib/ui/plain.css b/plugins/cockpit/ui/plain.css similarity index 100% rename from plugins/cockpit/lib/ui/plain.css rename to plugins/cockpit/ui/plain.css diff --git a/plugins/cockpit/lib/ui/plain.js b/plugins/cockpit/ui/plain.js similarity index 100% rename from plugins/cockpit/lib/ui/plain.js rename to plugins/cockpit/ui/plain.js diff --git a/plugins/pilot/lib/canon.js b/plugins/pilot/canon.js similarity index 100% rename from plugins/pilot/lib/canon.js rename to plugins/pilot/canon.js diff --git a/plugins/pilot/lib/catalog.js b/plugins/pilot/catalog.js similarity index 100% rename from plugins/pilot/lib/catalog.js rename to plugins/pilot/catalog.js diff --git a/plugins/pilot/lib/commands/settings.js b/plugins/pilot/commands/settings.js similarity index 100% rename from plugins/pilot/lib/commands/settings.js rename to plugins/pilot/commands/settings.js diff --git a/plugins/pilot/lib/console.js b/plugins/pilot/console.js similarity index 100% rename from plugins/pilot/lib/console.js rename to plugins/pilot/console.js diff --git a/plugins/pilot/lib/core.js b/plugins/pilot/core.js similarity index 100% rename from plugins/pilot/lib/core.js rename to plugins/pilot/core.js diff --git a/plugins/pilot/lib/dom.js b/plugins/pilot/dom.js similarity index 100% rename from plugins/pilot/lib/dom.js rename to plugins/pilot/dom.js diff --git a/plugins/pilot/lib/event.js b/plugins/pilot/event.js similarity index 100% rename from plugins/pilot/lib/event.js rename to plugins/pilot/event.js diff --git a/plugins/pilot/lib/event_emitter.js b/plugins/pilot/event_emitter.js similarity index 100% rename from plugins/pilot/lib/event_emitter.js rename to plugins/pilot/event_emitter.js diff --git a/plugins/pilot/fixoldbrowsers.js b/plugins/pilot/fixoldbrowsers.js new file mode 100644 index 00000000..1f7f1033 --- /dev/null +++ b/plugins/pilot/fixoldbrowsers.js @@ -0,0 +1,145 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Skywriter. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Kevin Dangoor (kdangoor@mozilla.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +// Narwhal's shim for ES5 defineProperty +// ES5 15.2.3.6 +if (!Object.defineProperty) { + Object.defineProperty = function(object, property, descriptor) { + var has = Object.prototype.hasOwnProperty; + if (typeof descriptor == "object" && object.__defineGetter__) { + if (has.call(descriptor, "value")) { + if (!object.__lookupGetter__(property) && !object.__lookupSetter__(property)) { + // data property defined and no pre-existing accessors + object[property] = descriptor.value; + } + if (has.call(descriptor, "get") || has.call(descriptor, "set")) { + // descriptor has a value property but accessor already exists + throw new TypeError("Object doesn't support this action"); + } + } + // fail silently if "writable", "enumerable", or "configurable" + // are requested but not supported + /* + // alternate approach: + if ( // can't implement these features; allow false but not true + !(has.call(descriptor, "writable") ? descriptor.writable : true) || + !(has.call(descriptor, "enumerable") ? descriptor.enumerable : true) || + !(has.call(descriptor, "configurable") ? descriptor.configurable : true) + ) + throw new RangeError( + "This implementation of Object.defineProperty does not " + + "support configurable, enumerable, or writable." + ); + */ + else if (typeof descriptor.get == "function") { + object.__defineGetter__(property, descriptor.get); + } + if (typeof descriptor.set == "function") { + object.__defineSetter__(property, descriptor.set); + } + } + return object; + }; +} + +// ES5 15.2.3.7 +if (!Object.defineProperties) { + Object.defineProperties = function(object, properties) { + for (var property in properties) { + if (Object.prototype.hasOwnProperty.call(properties, property)) { + Object.defineProperty(object, property, properties[property]); + } + } + return object; + }; +} + + + +/** + * Array detector. + * Firefox 3.5 and Safari 4 have this already. Chrome 4 however ... + * Note to Dojo - your isArray is still broken: instanceof doesn't work with + * Arrays taken from a different frame/window. + */ +if (!Array.isArray) { + Array.isArray = function(data) { + return data && Object.prototype.toString.call(data) === "[object Array]"; + }; +} + +/** + * Retrieves the list of keys on an object. + */ +if (!Object.keys) { + Object.keys = function(obj) { + var k, ret = []; + for (k in obj) { + if (obj.hasOwnProperty(k)) { + ret.push(k); + } + } + return ret; + }; +} + +if (!Function.prototype.bind) { + // From Narwhal + Function.prototype.bind = function () { + var args = Array.prototype.slice.call(arguments); + var self = this; + var bound = function () { + return self.call.apply( + self, + args.concat( + Array.prototype.slice.call(arguments) + ) + ); + }; + bound.name = this.name; + bound.displayName = this.displayName; + bound.length = this.length; + bound.unbound = self; + return bound; + }; +} + +exports.globalsLoaded = true; + +}); \ No newline at end of file diff --git a/plugins/pilot/lib/index.js b/plugins/pilot/index.js similarity index 99% rename from plugins/pilot/lib/index.js rename to plugins/pilot/index.js index 73262d42..157d4f1c 100644 --- a/plugins/pilot/lib/index.js +++ b/plugins/pilot/index.js @@ -50,7 +50,6 @@ packages.unshift("require", "exports", "module"); define(packages, function(require, exports, module) { -console.log(packages); exports.startup = function(data, reason) { deps.forEach(function(dep) { console.log("test startup for " + dep); diff --git a/plugins/pilot/lib/keyboard/index.js b/plugins/pilot/keyboard/index.js similarity index 100% rename from plugins/pilot/lib/keyboard/index.js rename to plugins/pilot/keyboard/index.js diff --git a/plugins/pilot/lib/keyboard/keyutil.js b/plugins/pilot/keyboard/keyutil.js similarity index 100% rename from plugins/pilot/lib/keyboard/keyutil.js rename to plugins/pilot/keyboard/keyutil.js diff --git a/plugins/pilot/lib/keyboard/tests/testKeyboard.js b/plugins/pilot/keyboard/tests/testKeyboard.js similarity index 100% rename from plugins/pilot/lib/keyboard/tests/testKeyboard.js rename to plugins/pilot/keyboard/tests/testKeyboard.js diff --git a/plugins/pilot/lib/lang.js b/plugins/pilot/lang.js similarity index 100% rename from plugins/pilot/lib/lang.js rename to plugins/pilot/lang.js diff --git a/plugins/pilot/lib/fixoldbrowsers.js b/plugins/pilot/lib/fixoldbrowsers.js deleted file mode 100644 index 995afb8a..00000000 --- a/plugins/pilot/lib/fixoldbrowsers.js +++ /dev/null @@ -1,147 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla Skywriter. - * - * The Initial Developer of the Original Code is - * Mozilla. - * Portions created by the Initial Developer are Copyright (C) 2009 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Kevin Dangoor (kdangoor@mozilla.com) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -define(function(require, exports, module) { - -exports.startup = function(data, reason) { - // Narwhal's shim for ES5 defineProperty - // ES5 15.2.3.6 - if (!Object.defineProperty) { - Object.defineProperty = function(object, property, descriptor) { - var has = Object.prototype.hasOwnProperty; - if (typeof descriptor == "object" && object.__defineGetter__) { - if (has.call(descriptor, "value")) { - if (!object.__lookupGetter__(property) && !object.__lookupSetter__(property)) { - // data property defined and no pre-existing accessors - object[property] = descriptor.value; - } - if (has.call(descriptor, "get") || has.call(descriptor, "set")) { - // descriptor has a value property but accessor already exists - throw new TypeError("Object doesn't support this action"); - } - } - // fail silently if "writable", "enumerable", or "configurable" - // are requested but not supported - /* - // alternate approach: - if ( // can't implement these features; allow false but not true - !(has.call(descriptor, "writable") ? descriptor.writable : true) || - !(has.call(descriptor, "enumerable") ? descriptor.enumerable : true) || - !(has.call(descriptor, "configurable") ? descriptor.configurable : true) - ) - throw new RangeError( - "This implementation of Object.defineProperty does not " + - "support configurable, enumerable, or writable." - ); - */ - else if (typeof descriptor.get == "function") { - object.__defineGetter__(property, descriptor.get); - } - if (typeof descriptor.set == "function") { - object.__defineSetter__(property, descriptor.set); - } - } - return object; - }; - } - - // ES5 15.2.3.7 - if (!Object.defineProperties) { - Object.defineProperties = function(object, properties) { - for (var property in properties) { - if (Object.prototype.hasOwnProperty.call(properties, property)) { - Object.defineProperty(object, property, properties[property]); - } - } - return object; - }; - } - - - - /** - * Array detector. - * Firefox 3.5 and Safari 4 have this already. Chrome 4 however ... - * Note to Dojo - your isArray is still broken: instanceof doesn't work with - * Arrays taken from a different frame/window. - */ - if (!Array.isArray) { - Array.isArray = function(data) { - return data && Object.prototype.toString.call(data) === "[object Array]"; - }; - } - - /** - * Retrieves the list of keys on an object. - */ - if (!Object.keys) { - Object.keys = function(obj) { - var k, ret = []; - for (k in obj) { - if (obj.hasOwnProperty(k)) { - ret.push(k); - } - } - return ret; - }; - } - - if (!Function.prototype.bind) { - // From Narwhal - Function.prototype.bind = function () { - var args = Array.prototype.slice.call(arguments); - var self = this; - var bound = function () { - return self.call.apply( - self, - args.concat( - Array.prototype.slice.call(arguments) - ) - ); - }; - bound.name = this.name; - bound.displayName = this.displayName; - bound.length = this.length; - bound.unbound = self; - return bound; - }; - } - - exports.globalsLoaded = true; -}; - -}); \ No newline at end of file diff --git a/plugins/pilot/lib/oop.js b/plugins/pilot/oop.js similarity index 100% rename from plugins/pilot/lib/oop.js rename to plugins/pilot/oop.js diff --git a/plugins/pilot/lib/plugin_manager.js b/plugins/pilot/plugin_manager.js similarity index 100% rename from plugins/pilot/lib/plugin_manager.js rename to plugins/pilot/plugin_manager.js diff --git a/plugins/pilot/lib/promise.js b/plugins/pilot/promise.js similarity index 100% rename from plugins/pilot/lib/promise.js rename to plugins/pilot/promise.js diff --git a/plugins/pilot/lib/proxy.js b/plugins/pilot/proxy.js similarity index 100% rename from plugins/pilot/lib/proxy.js rename to plugins/pilot/proxy.js diff --git a/plugins/pilot/lib/rangeutils.js b/plugins/pilot/rangeutils.js similarity index 100% rename from plugins/pilot/lib/rangeutils.js rename to plugins/pilot/rangeutils.js diff --git a/plugins/pilot/lib/settings.js b/plugins/pilot/settings.js similarity index 100% rename from plugins/pilot/lib/settings.js rename to plugins/pilot/settings.js diff --git a/plugins/pilot/lib/settings/canon.js b/plugins/pilot/settings/canon.js similarity index 100% rename from plugins/pilot/lib/settings/canon.js rename to plugins/pilot/settings/canon.js diff --git a/plugins/pilot/lib/stacktrace.js b/plugins/pilot/stacktrace.js similarity index 100% rename from plugins/pilot/lib/stacktrace.js rename to plugins/pilot/stacktrace.js diff --git a/plugins/pilot/lib/tests/testRangeutils.js b/plugins/pilot/tests/testRangeutils.js similarity index 100% rename from plugins/pilot/lib/tests/testRangeutils.js rename to plugins/pilot/tests/testRangeutils.js diff --git a/plugins/pilot/lib/types.js b/plugins/pilot/types.js similarity index 100% rename from plugins/pilot/lib/types.js rename to plugins/pilot/types.js diff --git a/plugins/pilot/lib/types/basic.js b/plugins/pilot/types/basic.js similarity index 100% rename from plugins/pilot/lib/types/basic.js rename to plugins/pilot/types/basic.js diff --git a/plugins/pilot/lib/types/command.js b/plugins/pilot/types/command.js similarity index 100% rename from plugins/pilot/lib/types/command.js rename to plugins/pilot/types/command.js diff --git a/plugins/pilot/lib/types/settings.js b/plugins/pilot/types/settings.js similarity index 100% rename from plugins/pilot/lib/types/settings.js rename to plugins/pilot/types/settings.js diff --git a/plugins/pilot/lib/util.js b/plugins/pilot/util.js similarity index 100% rename from plugins/pilot/lib/util.js rename to plugins/pilot/util.js From 46ac14ab6299c0aa4d82f83e01a6ce5ab6b82743 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Mon, 13 Dec 2010 10:40:48 +0100 Subject: [PATCH 89/90] make sure the browser fix is always loaded --- demo/boot.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/demo/boot.js b/demo/boot.js index 95b704b9..1e63002a 100644 --- a/demo/boot.js +++ b/demo/boot.js @@ -110,15 +110,11 @@ var setupPlugins = function(config, callback) { } } } -console.log(JSON.stringify({ - packagePaths: pluginPackageInfo, - paths: paths - })); require({ packagePaths: pluginPackageInfo, paths: paths }); - require(["pilot/plugin_manager", "pilot/settings"], function() { + require(["pilot/fixoldbrowsers", "pilot/plugin_manager", "pilot/settings"], function() { var pluginsModule = require("pilot/plugin_manager"); var settings = require("pilot/settings").settings; var catalog = pluginsModule.catalog; From 5e0695b58813592b57ecb91eb3a5e79986226116 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Tue, 14 Dec 2010 11:36:21 +0100 Subject: [PATCH 90/90] pass in the env to canon.execute to allow multiple editors --- lib/ace/keybinding.js | 2 +- plugins/cockpit/cli.js | 8 ++++++-- plugins/pilot/canon.js | 6 +----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/ace/keybinding.js b/lib/ace/keybinding.js index 31df2ee3..d9ecd4a1 100644 --- a/lib/ace/keybinding.js +++ b/lib/ace/keybinding.js @@ -56,7 +56,7 @@ var KeyBinding = function(element, editor, config) { var commandName = (_self.config.reverse[hashId] || {})[(key || String.fromCharCode(e.keyCode)).toLowerCase()]; - var success = canon.exec(commandName); + var success = canon.exec(commandName, {editor: editor}); if (success) { return event.stopEvent(e); } diff --git a/plugins/cockpit/cli.js b/plugins/cockpit/cli.js index 027ba9f8..85382cb9 100644 --- a/plugins/cockpit/cli.js +++ b/plugins/cockpit/cli.js @@ -244,8 +244,10 @@ exports.Assignment = Assignment; * class * @constructor */ -function Requisition() { +function Requisition(env) { + this.env = env; } + Requisition.prototype = { /** * The command that we are about to execute. @@ -377,7 +379,9 @@ exports.Requisition = Requisition; * if not specified. * @constructor */ -function CliRequisition(options) { +function CliRequisition(env, options) { + Requisition.call(this, env); + if (options && options.flags) { /** * TODO: We were using a default of keyboard.buildFlags({ }); diff --git a/plugins/pilot/canon.js b/plugins/pilot/canon.js index aa308f49..5bf4e79a 100644 --- a/plugins/pilot/canon.js +++ b/plugins/pilot/canon.js @@ -37,7 +37,6 @@ define(function(require, exports, module) { - var console = require('pilot/console'); var Trace = require('pilot/stacktrace').Trace; var oop = require('pilot/oop').oop; @@ -70,11 +69,8 @@ var commandExtensionSpec = { indexOn: 'name' }; -var env; - exports.startup = function(data, reason) { // TODO: this is probably all kinds of evil, but we need something working - env = data.env; catalog.addExtensionSpec(commandExtensionSpec); }; @@ -160,7 +156,7 @@ exports.getCommandNames = function() { * everything it needs to about the command params * @param command Either a command, or the name of one */ -exports.exec = function(command, args) { +exports.exec = function(command, env, args) { if (typeof command === 'string') { command = commands[command]; }