586 lines
18 KiB
JavaScript
586 lines
18 KiB
JavaScript
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Distributed under the BSD license:
|
|
*
|
|
* Copyright (c) 2010, Ajax.org B.V.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* * Neither the name of Ajax.org B.V. nor the
|
|
* names of its contributors may be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT 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 AJAX.ORG B.V. 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.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
define(function(require, exports, module) {
|
|
"use strict";
|
|
|
|
require("ace/lib/fixoldbrowsers");
|
|
|
|
require("ace/multi_select");
|
|
require("ace/ext/spellcheck");
|
|
require("./inline_editor");
|
|
require("./dev_util");
|
|
require("./file_drop");
|
|
|
|
var config = require("ace/config");
|
|
config.init();
|
|
var env = {};
|
|
|
|
var dom = require("ace/lib/dom");
|
|
var net = require("ace/lib/net");
|
|
var lang = require("ace/lib/lang");
|
|
var useragent = require("ace/lib/useragent");
|
|
|
|
var event = require("ace/lib/event");
|
|
var theme = require("ace/theme/textmate");
|
|
var EditSession = require("ace/edit_session").EditSession;
|
|
var UndoManager = require("ace/undomanager").UndoManager;
|
|
|
|
var HashHandler = require("ace/keyboard/hash_handler").HashHandler;
|
|
|
|
var Renderer = require("ace/virtual_renderer").VirtualRenderer;
|
|
var Editor = require("ace/editor").Editor;
|
|
|
|
var whitespace = require("ace/ext/whitespace");
|
|
|
|
|
|
|
|
var doclist = require("./doclist");
|
|
var modelist = require("ace/ext/modelist");
|
|
var themelist = require("ace/ext/themelist");
|
|
var layout = require("./layout");
|
|
var TokenTooltip = require("./token_tooltip").TokenTooltip;
|
|
var util = require("./util");
|
|
var saveOption = util.saveOption;
|
|
var fillDropdown = util.fillDropdown;
|
|
var bindCheckbox = util.bindCheckbox;
|
|
var bindDropdown = util.bindDropdown;
|
|
|
|
var ElasticTabstopsLite = require("ace/ext/elastic_tabstops_lite").ElasticTabstopsLite;
|
|
|
|
var IncrementalSearch = require("ace/incremental_search").IncrementalSearch;
|
|
|
|
|
|
var workerModule = require("ace/worker/worker_client");
|
|
if (location.href.indexOf("noworker") !== -1) {
|
|
workerModule.WorkerClient = workerModule.UIWorkerClient;
|
|
}
|
|
|
|
/*********** create editor ***************************/
|
|
var container = document.getElementById("editor-container");
|
|
|
|
// Splitting.
|
|
var Split = require("ace/split").Split;
|
|
var split = new Split(container, theme, 1);
|
|
env.editor = split.getEditor(0);
|
|
split.on("focus", function(editor) {
|
|
env.editor = editor;
|
|
updateUIEditorOptions();
|
|
});
|
|
env.split = split;
|
|
window.env = env;
|
|
|
|
|
|
var consoleEl = dom.createElement("div");
|
|
container.parentNode.appendChild(consoleEl);
|
|
consoleEl.style.cssText = "position:fixed; bottom:1px; right:0;\
|
|
border:1px solid #baf; z-index:100";
|
|
|
|
var cmdLine = new layout.singleLineEditor(consoleEl);
|
|
cmdLine.editor = env.editor;
|
|
env.editor.cmdLine = cmdLine;
|
|
|
|
env.editor.showCommandLine = function(val) {
|
|
this.cmdLine.focus();
|
|
if (typeof val == "string")
|
|
this.cmdLine.setValue(val, 1);
|
|
};
|
|
|
|
/**
|
|
* This demonstrates how you can define commands and bind shortcuts to them.
|
|
*/
|
|
env.editor.commands.addCommands([{
|
|
name: "gotoline",
|
|
bindKey: {win: "Ctrl-L", mac: "Command-L"},
|
|
exec: function(editor, line) {
|
|
if (typeof line == "object") {
|
|
var arg = this.name + " " + editor.getCursorPosition().row;
|
|
editor.cmdLine.setValue(arg, 1);
|
|
editor.cmdLine.focus();
|
|
return;
|
|
}
|
|
line = parseInt(line, 10);
|
|
if (!isNaN(line))
|
|
editor.gotoLine(line);
|
|
},
|
|
readOnly: true
|
|
}, {
|
|
name: "snippet",
|
|
bindKey: {win: "Alt-C", mac: "Command-Alt-C"},
|
|
exec: function(editor, needle) {
|
|
if (typeof needle == "object") {
|
|
editor.cmdLine.setValue("snippet ", 1);
|
|
editor.cmdLine.focus();
|
|
return;
|
|
}
|
|
var s = snippetManager.getSnippetByName(needle, editor);
|
|
if (s)
|
|
snippetManager.insertSnippet(editor, s.content);
|
|
},
|
|
readOnly: true
|
|
}, {
|
|
name: "focusCommandLine",
|
|
bindKey: "shift-esc|ctrl-`",
|
|
exec: function(editor, needle) { editor.cmdLine.focus(); },
|
|
readOnly: true
|
|
}, {
|
|
name: "nextFile",
|
|
bindKey: "Ctrl-tab",
|
|
exec: function(editor) { doclist.cycleOpen(editor, 1); },
|
|
readOnly: true
|
|
}, {
|
|
name: "previousFile",
|
|
bindKey: "Ctrl-shift-tab",
|
|
exec: function(editor) { doclist.cycleOpen(editor, -1); },
|
|
readOnly: true
|
|
}, {
|
|
name: "execute",
|
|
bindKey: "ctrl+enter",
|
|
exec: function(editor) {
|
|
try {
|
|
var r = window.eval(editor.getCopyText() || editor.getValue());
|
|
} catch(e) {
|
|
r = e;
|
|
}
|
|
editor.cmdLine.setValue(r + "");
|
|
},
|
|
readOnly: true
|
|
}, {
|
|
name: "showKeyboardShortcuts",
|
|
bindKey: {win: "Ctrl-Alt-h", mac: "Command-Alt-h"},
|
|
exec: function(editor) {
|
|
config.loadModule("ace/ext/keybinding_menu", function(module) {
|
|
module.init(editor);
|
|
editor.showKeyboardShortcuts();
|
|
});
|
|
}
|
|
}, {
|
|
name: "increaseFontSize",
|
|
bindKey: "Ctrl-=|Ctrl-+",
|
|
exec: function(editor) {
|
|
var size = parseInt(editor.getFontSize(), 10) || 12;
|
|
editor.setFontSize(size + 1);
|
|
}
|
|
}, {
|
|
name: "decreaseFontSize",
|
|
bindKey: "Ctrl+-|Ctrl-_",
|
|
exec: function(editor) {
|
|
var size = parseInt(editor.getFontSize(), 10) || 12;
|
|
editor.setFontSize(Math.max(size - 1 || 1));
|
|
}
|
|
}, {
|
|
name: "resetFontSize",
|
|
bindKey: "Ctrl+0|Ctrl-Numpad0",
|
|
exec: function(editor) {
|
|
editor.setFontSize(12);
|
|
}
|
|
}]);
|
|
|
|
|
|
env.editor.commands.addCommands(whitespace.commands);
|
|
|
|
cmdLine.commands.bindKeys({
|
|
"Shift-Return|Ctrl-Return|Alt-Return": function(cmdLine) { cmdLine.insert("\n"); },
|
|
"Esc|Shift-Esc": function(cmdLine){ cmdLine.editor.focus(); },
|
|
"Return": function(cmdLine){
|
|
var command = cmdLine.getValue().split(/\s+/);
|
|
var editor = cmdLine.editor;
|
|
editor.commands.exec(command[0], editor, command[1]);
|
|
editor.focus();
|
|
}
|
|
});
|
|
|
|
cmdLine.commands.removeCommands(["find", "gotoline", "findall", "replace", "replaceall"]);
|
|
|
|
var commands = env.editor.commands;
|
|
commands.addCommand({
|
|
name: "save",
|
|
bindKey: {win: "Ctrl-S", mac: "Command-S"},
|
|
exec: function(arg) {
|
|
var session = env.editor.session;
|
|
var name = session.name.match(/[^\/]+$/);
|
|
localStorage.setItem(
|
|
"saved_file:" + name,
|
|
session.getValue()
|
|
);
|
|
env.editor.cmdLine.setValue("saved "+ name);
|
|
}
|
|
});
|
|
|
|
commands.addCommand({
|
|
name: "load",
|
|
bindKey: {win: "Ctrl-O", mac: "Command-O"},
|
|
exec: function(arg) {
|
|
var session = env.editor.session;
|
|
var name = session.name.match(/[^\/]+$/);
|
|
var value = localStorage.getItem("saved_file:" + name);
|
|
if (typeof value == "string") {
|
|
session.setValue(value);
|
|
env.editor.cmdLine.setValue("loaded "+ name);
|
|
} else {
|
|
env.editor.cmdLine.setValue("no previuos value saved for "+ name);
|
|
}
|
|
}
|
|
});
|
|
|
|
var keybindings = {
|
|
ace: null, // Null = use "default" keymapping
|
|
vim: require("ace/keyboard/vim").handler,
|
|
emacs: "ace/keyboard/emacs",
|
|
// This is a way to define simple keyboard remappings
|
|
custom: new HashHandler({
|
|
"gotoright": "Tab",
|
|
"indent": "]",
|
|
"outdent": "[",
|
|
"gotolinestart": "^",
|
|
"gotolineend": "$"
|
|
})
|
|
};
|
|
|
|
|
|
|
|
/*********** manage layout ***************************/
|
|
var consoleHeight = 20;
|
|
function onResize() {
|
|
var left = env.split.$container.offsetLeft;
|
|
var width = document.documentElement.clientWidth - left;
|
|
container.style.width = width + "px";
|
|
container.style.height = document.documentElement.clientHeight - consoleHeight + "px";
|
|
env.split.resize();
|
|
|
|
consoleEl.style.width = width + "px";
|
|
cmdLine.resize();
|
|
}
|
|
|
|
window.onresize = onResize;
|
|
onResize();
|
|
|
|
/*********** options panel ***************************/
|
|
var docEl = document.getElementById("doc");
|
|
var modeEl = document.getElementById("mode");
|
|
var wrapModeEl = document.getElementById("soft_wrap");
|
|
var themeEl = document.getElementById("theme");
|
|
var foldingEl = document.getElementById("folding");
|
|
var selectStyleEl = document.getElementById("select_style");
|
|
var highlightActiveEl = document.getElementById("highlight_active");
|
|
var showHiddenEl = document.getElementById("show_hidden");
|
|
var showGutterEl = document.getElementById("show_gutter");
|
|
var showPrintMarginEl = document.getElementById("show_print_margin");
|
|
var highlightSelectedWordE = document.getElementById("highlight_selected_word");
|
|
var showHScrollEl = document.getElementById("show_hscroll");
|
|
var showVScrollEl = document.getElementById("show_vscroll");
|
|
var animateScrollEl = document.getElementById("animate_scroll");
|
|
var softTabEl = document.getElementById("soft_tab");
|
|
var behavioursEl = document.getElementById("enable_behaviours");
|
|
|
|
fillDropdown(docEl, doclist.all);
|
|
|
|
fillDropdown(modeEl, modelist.modes);
|
|
var modesByName = modelist.modesByName;
|
|
bindDropdown("mode", function(value) {
|
|
env.editor.session.setMode(modesByName[value].mode || modesByName.text.mode);
|
|
env.editor.session.modeName = value;
|
|
});
|
|
|
|
doclist.history = doclist.docs.map(function(doc) {
|
|
return doc.name;
|
|
});
|
|
doclist.history.index = 0;
|
|
doclist.cycleOpen = function(editor, dir) {
|
|
var h = this.history;
|
|
h.index += dir;
|
|
if (h.index >= h.length)
|
|
h.index = 0;
|
|
else if (h.index <= 0)
|
|
h.index = h.length - 1;
|
|
var s = h[h.index];
|
|
docEl.value = s;
|
|
docEl.onchange();
|
|
};
|
|
doclist.addToHistory = function(name) {
|
|
var h = this.history;
|
|
var i = h.indexOf(name);
|
|
if (i != h.index) {
|
|
if (i != -1)
|
|
h.splice(i, 1);
|
|
h.index = h.push(name);
|
|
}
|
|
};
|
|
|
|
bindDropdown("doc", function(name) {
|
|
doclist.loadDoc(name, function(session) {
|
|
if (!session)
|
|
return;
|
|
doclist.addToHistory(session.name);
|
|
session = env.split.setSession(session);
|
|
whitespace.detectIndentation(session);
|
|
updateUIEditorOptions();
|
|
env.editor.focus();
|
|
});
|
|
});
|
|
|
|
|
|
function updateUIEditorOptions() {
|
|
var editor = env.editor;
|
|
var session = editor.session;
|
|
|
|
session.setFoldStyle(foldingEl.value);
|
|
|
|
saveOption(docEl, session.name);
|
|
saveOption(modeEl, session.modeName || "text");
|
|
saveOption(wrapModeEl, session.getUseWrapMode() ? session.getWrapLimitRange().min || "free" : "off");
|
|
|
|
saveOption(selectStyleEl, editor.getSelectionStyle() == "line");
|
|
saveOption(themeEl, editor.getTheme());
|
|
saveOption(highlightActiveEl, editor.getHighlightActiveLine());
|
|
saveOption(showHiddenEl, editor.getShowInvisibles());
|
|
saveOption(showGutterEl, editor.renderer.getShowGutter());
|
|
saveOption(showPrintMarginEl, editor.renderer.getShowPrintMargin());
|
|
saveOption(highlightSelectedWordE, editor.getHighlightSelectedWord());
|
|
saveOption(showHScrollEl, editor.renderer.getHScrollBarAlwaysVisible());
|
|
saveOption(animateScrollEl, editor.getAnimatedScroll());
|
|
saveOption(softTabEl, session.getUseSoftTabs());
|
|
saveOption(behavioursEl, editor.getBehavioursEnabled());
|
|
}
|
|
|
|
themelist.themes.forEach(function(x){ x.value = x.theme });
|
|
fillDropdown(themeEl, {
|
|
Bright: themelist.themes.filter(function(x){return !x.isDark}),
|
|
Dark: themelist.themes.filter(function(x){return x.isDark})
|
|
});
|
|
|
|
event.addListener(themeEl, "mouseover", function(e){
|
|
themeEl.desiredValue = e.target.value;
|
|
if (!themeEl.$timer)
|
|
themeEl.$timer = setTimeout(themeEl.updateTheme);
|
|
});
|
|
|
|
event.addListener(themeEl, "mouseout", function(e){
|
|
themeEl.desiredValue = null;
|
|
if (!themeEl.$timer)
|
|
themeEl.$timer = setTimeout(themeEl.updateTheme, 20);
|
|
});
|
|
|
|
themeEl.updateTheme = function(){
|
|
env.split.setTheme((themeEl.desiredValue || themeEl.selectedValue));
|
|
themeEl.$timer = null;
|
|
};
|
|
|
|
bindDropdown("theme", function(value) {
|
|
if (!value)
|
|
return;
|
|
env.editor.setTheme(value);
|
|
themeEl.selectedValue = value;
|
|
});
|
|
|
|
bindDropdown("keybinding", function(value) {
|
|
env.editor.setKeyboardHandler(keybindings[value]);
|
|
});
|
|
|
|
bindDropdown("fontsize", function(value) {
|
|
env.split.setFontSize(value);
|
|
});
|
|
|
|
bindDropdown("folding", function(value) {
|
|
env.editor.session.setFoldStyle(value);
|
|
env.editor.setShowFoldWidgets(value !== "manual");
|
|
});
|
|
|
|
bindDropdown("soft_wrap", function(value) {
|
|
env.editor.setOption("wrap", value);
|
|
});
|
|
|
|
bindCheckbox("select_style", function(checked) {
|
|
env.editor.setOption("selectionStyle", checked ? "line" : "text");
|
|
});
|
|
|
|
bindCheckbox("highlight_active", function(checked) {
|
|
env.editor.setHighlightActiveLine(checked);
|
|
});
|
|
|
|
bindCheckbox("show_hidden", function(checked) {
|
|
env.editor.setShowInvisibles(checked);
|
|
});
|
|
|
|
bindCheckbox("display_indent_guides", function(checked) {
|
|
env.editor.setDisplayIndentGuides(checked);
|
|
});
|
|
|
|
bindCheckbox("show_gutter", function(checked) {
|
|
env.editor.renderer.setShowGutter(checked);
|
|
});
|
|
|
|
bindCheckbox("show_print_margin", function(checked) {
|
|
env.editor.renderer.setShowPrintMargin(checked);
|
|
});
|
|
|
|
bindCheckbox("highlight_selected_word", function(checked) {
|
|
env.editor.setHighlightSelectedWord(checked);
|
|
});
|
|
|
|
bindCheckbox("show_hscroll", function(checked) {
|
|
env.editor.setOption("hScrollBarAlwaysVisible", checked);
|
|
});
|
|
|
|
bindCheckbox("show_vscroll", function(checked) {
|
|
env.editor.setOption("vScrollBarAlwaysVisible", checked);
|
|
});
|
|
|
|
bindCheckbox("animate_scroll", function(checked) {
|
|
env.editor.setAnimatedScroll(checked);
|
|
});
|
|
|
|
bindCheckbox("soft_tab", function(checked) {
|
|
env.editor.session.setUseSoftTabs(checked);
|
|
});
|
|
|
|
bindCheckbox("enable_behaviours", function(checked) {
|
|
env.editor.setBehavioursEnabled(checked);
|
|
});
|
|
|
|
bindCheckbox("fade_fold_widgets", function(checked) {
|
|
env.editor.setFadeFoldWidgets(checked);
|
|
});
|
|
bindCheckbox("read_only", function(checked) {
|
|
env.editor.setReadOnly(checked);
|
|
});
|
|
bindCheckbox("scrollPastEnd", function(checked) {
|
|
env.editor.setOption("scrollPastEnd", checked);
|
|
});
|
|
|
|
bindDropdown("split", function(value) {
|
|
var sp = env.split;
|
|
if (value == "none") {
|
|
sp.setSplits(1);
|
|
} else {
|
|
var newEditor = (sp.getSplits() == 1);
|
|
sp.setOrientation(value == "below" ? sp.BELOW : sp.BESIDE);
|
|
sp.setSplits(2);
|
|
|
|
if (newEditor) {
|
|
var session = sp.getEditor(0).session;
|
|
var newSession = sp.setSession(session, 1);
|
|
newSession.name = session.name;
|
|
}
|
|
}
|
|
});
|
|
|
|
|
|
bindCheckbox("elastic_tabstops", function(checked) {
|
|
env.editor.setOption("useElasticTabstops", checked);
|
|
});
|
|
|
|
var iSearchCheckbox = bindCheckbox("isearch", function(checked) {
|
|
env.editor.setOption("useIncrementalSearch", checked);
|
|
});
|
|
|
|
env.editor.addEventListener('incrementalSearchSettingChanged', function(event) {
|
|
iSearchCheckbox.checked = event.isEnabled;
|
|
});
|
|
|
|
|
|
function synchroniseScrolling() {
|
|
var s1 = env.split.$editors[0].session;
|
|
var s2 = env.split.$editors[1].session;
|
|
s1.on('changeScrollTop', function(pos) {s2.setScrollTop(pos)});
|
|
s2.on('changeScrollTop', function(pos) {s1.setScrollTop(pos)});
|
|
s1.on('changeScrollLeft', function(pos) {s2.setScrollLeft(pos)});
|
|
s2.on('changeScrollLeft', function(pos) {s1.setScrollLeft(pos)});
|
|
}
|
|
|
|
bindCheckbox("highlight_token", function(checked) {
|
|
var editor = env.editor;
|
|
if (editor.tokenTooltip && !checked) {
|
|
editor.tokenTooltip.destroy();
|
|
delete editor.tokenTooltip;
|
|
} else if (checked) {
|
|
editor.tokenTooltip = new TokenTooltip(editor);
|
|
}
|
|
});
|
|
|
|
var StatusBar = require("ace/ext/statusbar").StatusBar;
|
|
new StatusBar(env.editor, cmdLine.container);
|
|
|
|
|
|
var Emmet = require("ace/ext/emmet");
|
|
net.loadScript("https://cloud9ide.github.io/emmet-core/emmet.js", function() {
|
|
Emmet.setCore(window.emmet);
|
|
env.editor.setOption("enableEmmet", true);
|
|
});
|
|
|
|
|
|
// require("ace/placeholder").PlaceHolder;
|
|
|
|
var snippetManager = require("ace/snippets").snippetManager;
|
|
|
|
env.editSnippets = function() {
|
|
var sp = env.split;
|
|
if (sp.getSplits() == 2) {
|
|
sp.setSplits(1);
|
|
return;
|
|
}
|
|
sp.setSplits(1);
|
|
sp.setSplits(2);
|
|
sp.setOrientation(sp.BESIDE);
|
|
var editor = sp.$editors[1];
|
|
var id = sp.$editors[0].session.$mode.$id || "";
|
|
var m = snippetManager.files[id];
|
|
if (!doclist["snippets/" + id]) {
|
|
var text = m.snippetText;
|
|
var s = doclist.initDoc(text, "", {});
|
|
s.setMode("ace/mode/snippets");
|
|
doclist["snippets/" + id] = s;
|
|
}
|
|
editor.on("blur", function() {
|
|
m.snippetText = editor.getValue();
|
|
snippetManager.unregister(m.snippets);
|
|
m.snippets = snippetManager.parseSnippetFile(m.snippetText, m.scope);
|
|
snippetManager.register(m.snippets);
|
|
});
|
|
sp.$editors[0].once("changeMode", function() {
|
|
sp.setSplits(1);
|
|
});
|
|
editor.setSession(doclist["snippets/" + id], 1);
|
|
editor.focus();
|
|
};
|
|
|
|
require("ace/ext/language_tools");
|
|
env.editor.setOptions({
|
|
enableBasicAutocompletion: true,
|
|
enableLiveAutocompletion: false,
|
|
enableSnippets: true
|
|
});
|
|
|
|
var beautify = require("ace/ext/beautify");
|
|
env.editor.commands.addCommands(beautify.commands);
|
|
|
|
});
|