<commit_before>import * as utils from './utils.js';

const _defaultSettings = {
    echo: true,
    promptPrefix: '> ',
    template: '

',
    predefinedCommands: true
};

const _promptIndentPadding = typeof InstallTrigger !== 'undefined'; // Firefox - misplaced cursor when using 'text-indent'

class Console {
    constructor(containerElement, settings) {
        if (!containerElement || !utils.isElement(containerElement)) {
            throw '"containerElement" must be an HTMLElement.'
        }

        this._settings = utils.extend({}, _defaultSettings, settings);
        this._containerNode = containerElement;
        this._consoleNode = null;
        this._inputNode = null;
        this._prefixNode = null;
        this._promptNode = null;
        this._outputNode = null;
        this._outputLineNode = null;
        this._definitions = {};
        this._current = null;
        this._queue = [];
        this._history = [];
        this._historyIndex = -1;
        this._initialized = false;

        this.init();
    }

    get settings() {
        return this._settings;
    }

    get definitions() {
        return this._definitions;
    }

    get initialized() {
        return this._initialized;
    }

    init() {
        if (this._initialized) return;

        this._consoleNode = utils.createElement(this._settings.template);

        this._containerNode.appendChild(this._consoleNode);

        this._outputNode = this._consoleNode.querySelector('.output');
        this._inputNode = this._consoleNode.querySelector('.input');
        this._prefixNode = this._consoleNode.querySelector('.prefix');
        this._promptNode = this._consoleNode.querySelector('.prompt');

        this._promptNode.addEventListener('keydown', (function (event) {
            if (!this._current) {
                switch (event.keyCode) {
                    case 13:
                        var value = this._promptNode.textContent;
                        if (value) {
                            this.execute(value);
                        }
                        event.preventDefault();
                        return false;
                    case 38:
                        this._historyBack();
                        event.preventDefault();
                        return false;
                    case 40:
                        this._historyForward();
                        event.preventDefault();
                        return false;
                    case 9:
                        event.preventDefault();
                        return false;
                }
            } else if (this._current.readLine && event.keyCode === 13) {
                this._current.readLine.resolve(this._promptNode.textContent);
                return false;
            }
            return true;
        }).bind(this));

        this._promptNode.addEventListener('keypress', (function (event) {
            if (this._current && this._current.read) {
                if (event.charCode !== 0) {
                    this._current.read.char = String.fromCharCode(event.charCode);
                    if (this._current.read.capture) {
                        return false;
                    }
                } else {
                    return false;
                }
            }
            return true;
        }).bind(this));

        this._promptNode.addEventListener('keyup', (function () {
            if (this._current && this._current.read && this._current.read.char) {
                this._current.read.resolve(this._current.read.char);
            }
        }).bind(this));

        this._promptNode.addEventListener('paste', (function () {
            setTimeout((function () {
                var value = this._promptNode.textContent;
                var lines = value.split(/\r\n|\r|\n/g);
                var length = lines.length;
                if (length > 1) {
                    for (var i = 1; i < length; i++) {
                        if (lines[i].length > 0) {
                            this._queue.get(this).push(lines[i]);
                        }
                    }
                    if (this._current && this._current.readLine) {
                        this._current.readLine.resolve(lines[0]);
                    } else if (this._current && this._current.read) {
                        this._current.read.resolve(lines[0][0]);
                    } else {
                        this._current(lines[0]);
                    }
                }
            }).bind(this), 0);
        }).bind(this));

        if (_promptIndentPadding) {
            this._promptNode.addEventListener('input', (function () {
                prompt.css(this._getPromptIndent());
            }).bind(this));
        }

        this._consoleNode.addEventListener('click', (function (event) {
            if (event.target !== this._inputNode && !this._inputNode.contains(event.target) &&
                event.target !== this._outputNode && !this._outputNode.contains(event.target)) {
                this._promptNode.focus();
            }
        }).bind(this));

        if (this._settings.predefinedCommands) {
            this.predefine();
        }

        this._activateInput();

        this._initialized = true;
    }

    dispose() {
        if (!this._initialized) return;

        this._containerNode.removeChild(this._consoleNode);
        this._consoleNode = null;
        this._outputNode = null;
        this._inputNode = null;
        this._prefixNode = null;
        this._promptNode = null;
        this._definitions = {};
        this._current = null;
        this._queue = [];
        this._history = [];
        this._historyIndex = -1;

        this._initialized = false;
    }

    reset() {
        this.dispose();
        this.init();
    }

    read(callback, capture) {
        if (!this._current) return;

        this._activateInput(true);

        this._current.read = utils.defer();
        this._current.read.then((function (value) {
            this._current.read = null;
            if (!capture) {
                this._promptNode.textContent = value;
            }
            this._deactivateInput();
            if (callback.call(this._current, value) === true) {
                this._read(callback, capture);
            } else {
                this._flushInput();
            }
        }).bind(this));
        this._current.read.capture = capture;

        if (this._queue.length > 0) {
            this._current.read.resolve(this._queue.shift()[0]);
        }
    }

    readLine(callback) {
        if (!this._current) return;

        this._activateInput(true);

        this._current.readLine = utils.defer();
        this._current.readLine.then((function (value) {
            this._current.readLine = null;
            this._promptNode.textContent = value;
            this._deactivateInput();
            this._flushInput();
            if (callback.call(this._current, value) === true) {
                this.readLine(callback);
            }
        }).bind(this));

        if (this._queue.length > 0) {
            this._current.readLine.resolve(this._queue.shift());
        }
    }

    write(value, cssClass) {
        value = value || '';
        var outputValue = utils.createElement(`<span class="${cssClass}">${value}</span>`);
        if (!this._outputLineNode) {
            this._outputLineNode = utils.createElement('

');
            this._outputNode.appendChild(this._outputLineNode);
        }
        this._outputLineNode.appendChild(outputValue);
    }

    writeLine(value, cssClass) {
        value = (value || '') + '\n';
        this.write(value, cssClass);
        this._outputLineNode = null;
    }

    writePad(value, padding, length, cssClass) {
        this.write(utils.pad(value, padding, length), cssClass);
    }

    clear() {
        this._outputNode.innerHTML = '';
    }

    focus() {
        this._promptNode.focus();
    }

    blur() {
        utils.blur(this._promptNode);
    }

    execute(command) {
        if (this._current) {
            this._queue.push(command);
            return;
        }

        if (typeof command !== 'string' || command.length === 0) {
            throw 'Invalid command';
        }

        this._promptNode.textContent = command;
        this._flushInput(!this._settings.echo);
        this._historyAdd(command);
        this._deactivateInput();

        command = command.trim();

        var parsed = this._parseCommand(command);

        var definitions = this._getDefinitions(parsed.name);
        if (!definitions || definitions.length < 1) {
            this.writeLine('Invalid command', 'error');
            this._activateInput();
            return;
        } else if (definitions.length > 1) {
            this.writeLine('Ambiguous command', 'error');
            this.writeLine();
            for (var i = 0; i < definitions.length; i++) {
                this.writePad(definitions[i].name, ' ', 10);
                this.writeLine(definitions[i].description);
            }
            this.writeLine();
            this._activateInput();
            return;
        }

        var definition = definitions[0];

        this._current = {
            command: command,
            definition: definition,
            console: this
        };

        var args = parsed.args;
        if (!definition.parse) {
            args = [parsed.arg];
        }

        var result;
        try {
            result = definition.callback.apply(this._current, args);
        } catch (error) {
            this.writeLine('Unhandled exception. See consoleNode log for details.', 'error');
            console.error(error);
        }

        Promise.all([result]).then((function () {
            setTimeout((function () {
                this._current = null;
                this._activateInput();
                if (this._queue.length > 0) {
                    this.execute(this._queue.shift());
                }
            }).bind(this), 0);
        }).bind(this));
    }

    define(names, callback, settings) {
        var definitions = this._createDefinitions(names, callback, settings);
        for (var i = 0, l = definitions.length; i < l; i++) {
            this._definitions[definitions[i].name] = definitions[i];
        }
    }

    predefine() {
        this.define(['HELP', '?'], function () {
            this.console.writeLine('The following commands are available:');
            this.console.writeLine();
            for (var key in this.console.definitions) {
                var definition = this.console.definitions[key];
                if (!!utils.unwrap(definition.available)) {
                    this.console.writePad(key, ' ', 10);
                    this.console.writeLine(definition.description);
                }
            }
            this.console.writeLine();
        }, {
                description: 'Lists the available commands'
            });

        this.define('ECHO', function (arg) {
            var toggle = arg.toUpperCase();
            if (toggle === 'ON') {
                this.console.settings.echo = true;
            } else if (toggle === 'OFF') {
                this.console.settings.echo = false;
            } else {
                this.console.writeLine(arg);
            }
        }, {
                parse: false,
                description: 'Displays provided text or toggles command echoing'
            });

        this.define(['CLS'], function () {
            this.console.clear();
        }, {
                description: 'Clears the command prompt'
            });
    }

    _activateInput(inline) {
        if (inline) {
            if (this._outputLineNode) {
                this._prefixNode.textContent = this._outputLineNode.textContent;
                this._outputNode.removeChild(this._outputLineNode);
                this._outputLineNode = null;
            }
        } else {
            this._prefixNode.textContent = this._settings.promptPrefix;
        }
        this._inputNode.style.display = '';
        setTimeout((function () {
            this._promptNode.setAttribute('disabled', false);
            this._setPromptIndent();
            this._promptNode.focus();
            utils.smoothScroll(this._consoleNode, this._consoleNode.scrollHeight, 1000);
        }).bind(this), 0);
    }

    _deactivateInput() {
        this._promptNode.setAttribute('disabled', true);
        this._inputNode.style.display = 'none';
    }

    _flushInput(preventWrite) {
        if (!preventWrite) {
            this.write(this._prefixNode.textContent);
            this.writeLine(this._promptNode.textContent);
        }
        this._prefixNode.textContent = '';
        this._promptNode.textContent = '';
    }

    _historyAdd(command) {
        this._history.unshift(command);
        this._historyIndex = -1;
    }

    _historyBack() {
        if (this._history.length > this._historyIndex + 1) {
            this._historyIndex++;
            this._promptNode.textContent = history[this._historyIndex];
            var event = document.createEvent('HTMLEvents');
            event.initEvent('change', true, false);
            this._promptNode.dispatchEvent(event);
        }
    }

    _historyForward() {
        if (this._historyIndex > 0) {
            this._historyIndex--;
            this._promptNode.textContent = history[this._historyIndex];
            var event = document.createEvent('HTMLEvents');
            event.initEvent('change', true, false);
            this._promptNode.dispatchEvent(event);
        }
    }

    _parseCommand(command) {
        var exp = /[^\s"]+|"([^"]*)"/gi,
            name = null,
            arg = null,
            args = [],
            match = null;

        do {
            match = exp.exec(command);
            if (match !== null) {
                var value = match[1] ? match[1] : match[0];
                if (match.index === 0) {
                    name = value;
                    arg = command.substr(value.length + (match[1] ? 3 : 1));
                } else {
                    args.push(value);
                }
            }
        } while (match !== null);

        return {
            name: name,
            arg: arg,
            args: args
        };
    }

    _createDefinitions(names, callback, settings) {
        if (typeof names !== 'string' && !Array.isArray(names)) {
            settings = callback;
            callback = names;
            names = null;
        }
        if (typeof callback !== 'function') {
            settings = callback;
            callback = null;
        }

        if (typeof names === 'string') {
            names = [names];
        } else if (Array.isArray(names)) {
            names = names.filter(function (value) {
                return typeof value === 'string';
            });
        }

        if (!Array.isArray(names) ||
            names.length === 0 ||
            typeof callback !== 'function') {
            throw 'Invalid command definition';
        }

        var definitions = [];

        for (var i = 0, l = names.length; i < l; i++) {
            var definition = {
                name: names[i].toUpperCase(),
                callback: callback,
                parse: true,
                available: true
            };

            utils.extend(definition, settings);

            definitions.push(definition);
        }

        return definitions;
    }

    _getDefinitions(name) {
        name = name.toUpperCase();

        var definition = this._definitions[name];

        if (definition) {
            return [definition];
        }

        var definitions = [];

        for (var key in this._definitions) {
            if (key.indexOf(name, 0) === 0 && utils.unwrap(this._definitions[key].available)) {
                definitions.push(this._definitions[key]);
            }
        }

        return definitions;
    }

    _getPrefixWidth() {
        var width = this._prefixNode.getBoundingClientRect().width;
        var text = this._prefixNode.textContent;
        var spacePadding = text.length - text.trim().length;

        if (!this._prefixNode._spaceWidth) {
            var elem1 = utils.createElement('| |');
            this._prefixNode.appendChild(elem1);
            var elem2 = utils.createElement('||')
            this._prefixNode.appendChild(elem2);
            this._prefixNode._spaceWidth = elem1.offsetWidth - elem2.offsetWidth;
            this._prefixNode.removeChild(elem1);
            this._prefixNode.removeChild(elem2);
        }

        width += spacePadding * this._prefixNode._spaceWidth;
        return width;
    }

    _setPromptIndent() {
        var prefixWidth = this._getPrefixWidth() + 'px';
        if (_promptIndentPadding) {
            if (this._promptNode.textContent) {
                this._promptNode.style.textIndent = prefixWidth;
                this._promptNode.style.paddingLeft = '';
            } else {
                this._promptNode.style.textIndent = '';
                this._promptNode.style.paddingLeft = prefixWidth;
            }
        }
        else {
            this._promptNode.style.textIndent = prefixWidth;
        }
    }
}

export default Console;<commit_msg>abbreviatedCommands setting<commit_after>import * as utils from './utils.js';

const _defaultSettings = {
    echo: true,
    promptPrefix: '> ',
    template: '

',
    predefinedCommands: true,
    abbreviatedCommands: true
};

const _promptIndentPadding = typeof InstallTrigger !== 'undefined'; // Firefox - misplaced cursor when using 'text-indent'

class Console {
    constructor(containerElement, settings) {
        if (!containerElement || !utils.isElement(containerElement)) {
            throw '"containerElement" must be an HTMLElement.'
        }

        this._settings = utils.extend({}, _defaultSettings, settings);
        this._containerNode = containerElement;
        this._consoleNode = null;
        this._inputNode = null;
        this._prefixNode = null;
        this._promptNode = null;
        this._outputNode = null;
        this._outputLineNode = null;
        this._definitions = {};
        this._current = null;
        this._queue = [];
        this._history = [];
        this._historyIndex = -1;
        this._initialized = false;

        this.init();
    }

    get settings() {
        return this._settings;
    }

    get definitions() {
        return this._definitions;
    }

    get initialized() {
        return this._initialized;
    }

    init() {
        if (this._initialized) return;

        this._consoleNode = utils.createElement(this._settings.template);

        this._containerNode.appendChild(this._consoleNode);

        this._outputNode = this._consoleNode.querySelector('.output');
        this._inputNode = this._consoleNode.querySelector('.input');
        this._prefixNode = this._consoleNode.querySelector('.prefix');
        this._promptNode = this._consoleNode.querySelector('.prompt');

        this._promptNode.addEventListener('keydown', (function (event) {
            if (!this._current) {
                switch (event.keyCode) {
                    case 13:
                        var value = this._promptNode.textContent;
                        if (value) {
                            this.execute(value);
                        }
                        event.preventDefault();
                        return false;
                    case 38:
                        this._historyBack();
                        event.preventDefault();
                        return false;
                    case 40:
                        this._historyForward();
                        event.preventDefault();
                        return false;
                    case 9:
                        event.preventDefault();
                        return false;
                }
            } else if (this._current.readLine && event.keyCode === 13) {
                this._current.readLine.resolve(this._promptNode.textContent);
                return false;
            }
            return true;
        }).bind(this));

        this._promptNode.addEventListener('keypress', (function (event) {
            if (this._current && this._current.read) {
                if (event.charCode !== 0) {
                    this._current.read.char = String.fromCharCode(event.charCode);
                    if (this._current.read.capture) {
                        return false;
                    }
                } else {
                    return false;
                }
            }
            return true;
        }).bind(this));

        this._promptNode.addEventListener('keyup', (function () {
            if (this._current && this._current.read && this._current.read.char) {
                this._current.read.resolve(this._current.read.char);
            }
        }).bind(this));

        this._promptNode.addEventListener('paste', (function () {
            setTimeout((function () {
                var value = this._promptNode.textContent;
                var lines = value.split(/\r\n|\r|\n/g);
                var length = lines.length;
                if (length > 1) {
                    for (var i = 1; i < length; i++) {
                        if (lines[i].length > 0) {
                            this._queue.get(this).push(lines[i]);
                        }
                    }
                    if (this._current && this._current.readLine) {
                        this._current.readLine.resolve(lines[0]);
                    } else if (this._current && this._current.read) {
                        this._current.read.resolve(lines[0][0]);
                    } else {
                        this._current(lines[0]);
                    }
                }
            }).bind(this), 0);
        }).bind(this));

        if (_promptIndentPadding) {
            this._promptNode.addEventListener('input', (function () {
                prompt.css(this._getPromptIndent());
            }).bind(this));
        }

        this._consoleNode.addEventListener('click', (function (event) {
            if (event.target !== this._inputNode && !this._inputNode.contains(event.target) &&
                event.target !== this._outputNode && !this._outputNode.contains(event.target)) {
                this._promptNode.focus();
            }
        }).bind(this));

        if (this._settings.predefinedCommands) {
            this.predefine();
        }

        this._activateInput();

        this._initialized = true;
    }

    dispose() {
        if (!this._initialized) return;

        this._containerNode.removeChild(this._consoleNode);
        this._consoleNode = null;
        this._outputNode = null;
        this._inputNode = null;
        this._prefixNode = null;
        this._promptNode = null;
        this._definitions = {};
        this._current = null;
        this._queue = [];
        this._history = [];
        this._historyIndex = -1;

        this._initialized = false;
    }

    reset() {
        this.dispose();
        this.init();
    }

    read(callback, capture) {
        if (!this._current) return;

        this._activateInput(true);

        this._current.read = utils.defer();
        this._current.read.then((function (value) {
            this._current.read = null;
            if (!capture) {
                this._promptNode.textContent = value;
            }
            this._deactivateInput();
            if (callback.call(this._current, value) === true) {
                this._read(callback, capture);
            } else {
                this._flushInput();
            }
        }).bind(this));
        this._current.read.capture = capture;

        if (this._queue.length > 0) {
            this._current.read.resolve(this._queue.shift()[0]);
        }
    }

    readLine(callback) {
        if (!this._current) return;

        this._activateInput(true);

        this._current.readLine = utils.defer();
        this._current.readLine.then((function (value) {
            this._current.readLine = null;
            this._promptNode.textContent = value;
            this._deactivateInput();
            this._flushInput();
            if (callback.call(this._current, value) === true) {
                this.readLine(callback);
            }
        }).bind(this));

        if (this._queue.length > 0) {
            this._current.readLine.resolve(this._queue.shift());
        }
    }

    write(value, cssClass) {
        value = value || '';
        var outputValue = utils.createElement(`<span class="${cssClass}">${value}</span>`);
        if (!this._outputLineNode) {
            this._outputLineNode = utils.createElement('

');
            this._outputNode.appendChild(this._outputLineNode);
        }
        this._outputLineNode.appendChild(outputValue);
    }

    writeLine(value, cssClass) {
        value = (value || '') + '\n';
        this.write(value, cssClass);
        this._outputLineNode = null;
    }

    writePad(value, padding, length, cssClass) {
        this.write(utils.pad(value, padding, length), cssClass);
    }

    clear() {
        this._outputNode.innerHTML = '';
    }

    focus() {
        this._promptNode.focus();
    }

    blur() {
        utils.blur(this._promptNode);
    }

    execute(command) {
        if (this._current) {
            this._queue.push(command);
            return;
        }

        if (typeof command !== 'string' || command.length === 0) {
            throw 'Invalid command';
        }

        this._promptNode.textContent = command;
        this._flushInput(!this._settings.echo);
        this._historyAdd(command);
        this._deactivateInput();

        command = command.trim();

        var parsed = this._parseCommand(command);

        var definitions = this._getDefinitions(parsed.name);
        if (!definitions || definitions.length < 1) {
            this.writeLine('Invalid command', 'error');
            this._activateInput();
            return;
        } else if (definitions.length > 1) {
            this.writeLine('Ambiguous command', 'error');
            this.writeLine();
            for (var i = 0; i < definitions.length; i++) {
                this.writePad(definitions[i].name, ' ', 10);
                this.writeLine(definitions[i].description);
            }
            this.writeLine();
            this._activateInput();
            return;
        }

        var definition = definitions[0];

        this._current = {
            command: command,
            definition: definition,
            console: this
        };

        var args = parsed.args;
        if (!definition.parse) {
            args = [parsed.arg];
        }

        var result;
        try {
            result = definition.callback.apply(this._current, args);
        } catch (error) {
            this.writeLine('Unhandled exception. See consoleNode log for details.', 'error');
            console.error(error);
        }

        Promise.all([result]).then((function () {
            setTimeout((function () {
                this._current = null;
                this._activateInput();
                if (this._queue.length > 0) {
                    this.execute(this._queue.shift());
                }
            }).bind(this), 0);
        }).bind(this));
    }

    define(names, callback, settings) {
        var definitions = this._createDefinitions(names, callback, settings);
        for (var i = 0, l = definitions.length; i < l; i++) {
            this._definitions[definitions[i].name] = definitions[i];
        }
    }

    predefine() {
        this.define(['HELP', '?'], function () {
            this.console.writeLine('The following commands are available:');
            this.console.writeLine();
            for (var key in this.console.definitions) {
                var definition = this.console.definitions[key];
                if (!!utils.unwrap(definition.available)) {
                    this.console.writePad(key, ' ', 10);
                    this.console.writeLine(definition.description);
                }
            }
            this.console.writeLine();
        }, {
                description: 'Lists the available commands'
            });

        this.define('ECHO', function (arg) {
            var toggle = arg.toUpperCase();
            if (toggle === 'ON') {
                this.console.settings.echo = true;
            } else if (toggle === 'OFF') {
                this.console.settings.echo = false;
            } else {
                this.console.writeLine(arg);
            }
        }, {
                parse: false,
                description: 'Displays provided text or toggles command echoing'
            });

        this.define(['CLS'], function () {
            this.console.clear();
        }, {
                description: 'Clears the command prompt'
            });
    }

    _activateInput(inline) {
        if (inline) {
            if (this._outputLineNode) {
                this._prefixNode.textContent = this._outputLineNode.textContent;
                this._outputNode.removeChild(this._outputLineNode);
                this._outputLineNode = null;
            }
        } else {
            this._prefixNode.textContent = this._settings.promptPrefix;
        }
        this._inputNode.style.display = '';
        setTimeout((function () {
            this._promptNode.setAttribute('disabled', false);
            this._setPromptIndent();
            this._promptNode.focus();
            utils.smoothScroll(this._consoleNode, this._consoleNode.scrollHeight, 1000);
        }).bind(this), 0);
    }

    _deactivateInput() {
        this._promptNode.setAttribute('disabled', true);
        this._inputNode.style.display = 'none';
    }

    _flushInput(preventWrite) {
        if (!preventWrite) {
            this.write(this._prefixNode.textContent);
            this.writeLine(this._promptNode.textContent);
        }
        this._prefixNode.textContent = '';
        this._promptNode.textContent = '';
    }

    _historyAdd(command) {
        this._history.unshift(command);
        this._historyIndex = -1;
    }

    _historyBack() {
        if (this._history.length > this._historyIndex + 1) {
            this._historyIndex++;
            this._promptNode.textContent = history[this._historyIndex];
            var event = document.createEvent('HTMLEvents');
            event.initEvent('change', true, false);
            this._promptNode.dispatchEvent(event);
        }
    }

    _historyForward() {
        if (this._historyIndex > 0) {
            this._historyIndex--;
            this._promptNode.textContent = history[this._historyIndex];
            var event = document.createEvent('HTMLEvents');
            event.initEvent('change', true, false);
            this._promptNode.dispatchEvent(event);
        }
    }

    _parseCommand(command) {
        var exp = /[^\s"]+|"([^"]*)"/gi,
            name = null,
            arg = null,
            args = [],
            match = null;

        do {
            match = exp.exec(command);
            if (match !== null) {
                var value = match[1] ? match[1] : match[0];
                if (match.index === 0) {
                    name = value;
                    arg = command.substr(value.length + (match[1] ? 3 : 1));
                } else {
                    args.push(value);
                }
            }
        } while (match !== null);

        return {
            name: name,
            arg: arg,
            args: args
        };
    }

    _createDefinitions(names, callback, settings) {
        if (typeof names !== 'string' && !Array.isArray(names)) {
            settings = callback;
            callback = names;
            names = null;
        }
        if (typeof callback !== 'function') {
            settings = callback;
            callback = null;
        }

        if (typeof names === 'string') {
            names = [names];
        } else if (Array.isArray(names)) {
            names = names.filter(function (value) {
                return typeof value === 'string';
            });
        }

        if (!Array.isArray(names) ||
            names.length === 0 ||
            typeof callback !== 'function') {
            throw 'Invalid command definition';
        }

        var definitions = [];

        for (var i = 0, l = names.length; i < l; i++) {
            var definition = {
                name: names[i].toUpperCase(),
                callback: callback,
                parse: true,
                available: true
            };

            utils.extend(definition, settings);

            definitions.push(definition);
        }

        return definitions;
    }

    _getDefinitions(name) {
        name = name.toUpperCase();

        var definition = this._definitions[name];

        if (definition) {
            return [definition];
        }

        var definitions = [];

        if (this._settings.abbreviatedCommands)
        {
            for (var key in this._definitions) {
                if (key.indexOf(name, 0) === 0 && utils.unwrap(this._definitions[key].available)) {
                    definitions.push(this._definitions[key]);
                }
            }
        }

        return definitions;
    }

    _getPrefixWidth() {
        var width = this._prefixNode.getBoundingClientRect().width;
        var text = this._prefixNode.textContent;
        var spacePadding = text.length - text.trim().length;

        if (!this._prefixNode._spaceWidth) {
            var elem1 = utils.createElement('| |');
            this._prefixNode.appendChild(elem1);
            var elem2 = utils.createElement('||')
            this._prefixNode.appendChild(elem2);
            this._prefixNode._spaceWidth = elem1.offsetWidth - elem2.offsetWidth;
            this._prefixNode.removeChild(elem1);
            this._prefixNode.removeChild(elem2);
        }

        width += spacePadding * this._prefixNode._spaceWidth;
        return width;
    }

    _setPromptIndent() {
        var prefixWidth = this._getPrefixWidth() + 'px';
        if (_promptIndentPadding) {
            if (this._promptNode.textContent) {
                this._promptNode.style.textIndent = prefixWidth;
                this._promptNode.style.paddingLeft = '';
            } else {
                this._promptNode.style.textIndent = '';
                this._promptNode.style.paddingLeft = prefixWidth;
            }
        }
        else {
            this._promptNode.style.textIndent = prefixWidth;
        }
    }
}

export default Console;<|endoftext|>


<commit_before>var ESCAPE_KEY = 27;

var events = [
  'mousemove',
  'mouseup',
  'keydown',
  'keyup'
];

var popup;

function createPopup() {
  var popup = $('
');
  popup.css({
    'position': 'fixed',
    'top': 0,
    'right': 0,
    'width': 'auto',
    'height': 'auto',
    'margin': 0,
    'padding': '6px',
    'border': 'none',
    'background-color': 'rgba(255, 255, 255, 0.8)',
    'color': '#333',
    'font-family': 'Menlo, Consolas, "Liberation Mono", monospace',
    'font-size': '14px',
    'display': 'none'
  });
  return popup;
}

function showPopup(popup, content) {
  popup.html(content);
  popup.css('display', 'block');
}

function hidePopup(popup) {
  popup.css('display', 'none');
}

var prevCharCount;
var prevText;
var prevX;
var prevY;

function showSelectionCharCount(event) {
  var selection = window.getSelection();
  if (selection) {
    var text = selection.toString();
    if (text && text.length) {
      var charCount = text.length;

      var rect = selection.getRangeAt(0).getBoundingClientRect();
      var x = rect.left;
      var y = rect.top;

      if (charCount !== prevCharCount || text !== prevText || x !== prevX || y !== prevY) {
        showPopup(popup, text.length + ' characters selected');

        prevCharCount = charCount;
        prevText = text;
        prevX = x;
        prevY = y;
      }
    } else {
      hidePopup(popup);
    }
  } else {
    hidePopup(popup);
  }
}

var listeningToMouse = false;
chrome.runtime.onMessage.addListener(function (message) {
  var shouldAttachListener = !listeningToMouse && message.active;
  if (shouldAttachListener) {
    _.each(events, function (event) {
      $(document.body).on(event, showSelectionCharCount);
    });
  } else {
    _.each(events, function (event) {
      $(document.body).off(event, showSelectionCharCount);
    });
  }
  listeningToMouse = shouldAttachListener;
});

popup = createPopup();
document.body.appendChild(popup[0]);

$(document).on('keydown', function (event) {
  if (event.which === ESCAPE_KEY) {
    chrome.runtime.sendMessage({ active: false });
  }
});
<commit_msg>Added 10M z-index to ensure output is on top<commit_after>var ESCAPE_KEY = 27;

var events = [
  'mousemove',
  'mouseup',
  'keydown',
  'keyup'
];

var popup;

function createPopup() {
  var popup = $('
');
  popup.css({
    'position': 'fixed',
    'z-index': 10000000,
    'top': 0,
    'right': 0,
    'width': 'auto',
    'height': 'auto',
    'margin': 0,
    'padding': '6px',
    'border': 'none',
    'background-color': 'rgba(255, 255, 255, 0.8)',
    'color': '#333',
    'font-family': 'Menlo, Consolas, "Liberation Mono", monospace',
    'font-size': '14px',
    'display': 'none'
  });
  return popup;
}

function showPopup(popup, content) {
  popup.html(content);
  popup.css('display', 'block');
}

function hidePopup(popup) {
  popup.css('display', 'none');
}

var prevCharCount;
var prevText;
var prevX;
var prevY;

function showSelectionCharCount(event) {
  var selection = window.getSelection();
  if (selection) {
    var text = selection.toString();
    if (text && text.length) {
      var charCount = text.length;

      var rect = selection.getRangeAt(0).getBoundingClientRect();
      var x = rect.left;
      var y = rect.top;

      if (charCount !== prevCharCount || text !== prevText || x !== prevX || y !== prevY) {
        showPopup(popup, text.length + ' characters selected');

        prevCharCount = charCount;
        prevText = text;
        prevX = x;
        prevY = y;
      }
    } else {
      hidePopup(popup);
    }
  } else {
    hidePopup(popup);
  }
}

var listeningToMouse = false;
chrome.runtime.onMessage.addListener(function (message) {
  var shouldAttachListener = !listeningToMouse && message.active;
  if (shouldAttachListener) {
    _.each(events, function (event) {
      $(document.body).on(event, showSelectionCharCount);
    });
  } else {
    _.each(events, function (event) {
      $(document.body).off(event, showSelectionCharCount);
    });
  }
  listeningToMouse = shouldAttachListener;
});

popup = createPopup();
document.body.appendChild(popup[0]);

$(document).on('keydown', function (event) {
  if (event.which === ESCAPE_KEY) {
    chrome.runtime.sendMessage({ active: false });
  }
});
<|endoftext|>


<commit_before>'use strict';

const co        = require('co');
const _         = require('lodash');
const console    = require('./console');

module.exports = function (context, source) {

    const resolve = co.wrap(function* (obj) {

        const mapper = co.wrap(function* (item, key) {

            item = yield Promise.resolve(item);
            if (_.isFunction(item)) {
                return resolve(item());
            }
            if (_.isArray(item) || _.isObject(item)) {
                return resolve(item);
            }
            if (_.isString(item) && _.startsWith(item, '@')) {
                const parts  = item.split('.');
                const handle = parts.shift();
                let entity   = source.find(handle);
                if (entity && parts.length) {
                    if (entity.type === 'component') {
                        entity = entity.variants().default();
                    }
                    const entityContext = yield resolve(entity.context);
                    return _.get(entityContext, parts.join('.'), null);
                }
                console.debug(`Could not resolve context reference for ${item}`);
                return null;
            }

            return item;
        });

        const iterator = _.isArray(obj) ? 'map' : 'mapValues';
        return yield _[iterator](obj, mapper);
    });

    return resolve(context);
};
<commit_msg>feat(context): allow escaping of entity references in context data<commit_after>'use strict';

const co        = require('co');
const _         = require('lodash');
const console    = require('./console');

module.exports = function (context, source) {

    const resolve = co.wrap(function* (obj) {

        const mapper = co.wrap(function* (item, key) {

            item = yield Promise.resolve(item);
            if (_.isFunction(item)) {
                return resolve(item());
            }
            if (_.isArray(item) || _.isObject(item)) {
                return resolve(item);
            }
            if (_.isString(item) && _.startsWith(item, '@')) {
                const parts  = item.split('.');
                const handle = parts.shift();
                let entity   = source.find(handle);
                if (entity) {
                    if (entity.type === 'component') {
                        entity = entity.variants().default();
                    }
                    const entityContext = yield resolve(entity.context);
                    if (parts.length) {
                        return _.get(entityContext, parts.join('.'), null);
                    }
                    return entityContext;
                }
                console.debug(`Could not resolve context reference for ${item}`);
                return null;
            }
            if (_.isString(item) && _.startsWith(item, '\\@')) {
                return item.replace(/^\\@/, '@');
            }

            return item;
        });

        const iterator = _.isArray(obj) ? 'map' : 'mapValues';
        return yield _[iterator](obj, mapper);
    });

    return resolve(context);
};
<|endoftext|>


<commit_before>var apijs = require("tnt.api");

var http = require("httpplease");
var promises = require('httpplease-promises');
var Promise = require('es6-promise').Promise;
var json = require("httpplease/plugins/json");
jsonHttp = http.use(json).use(promises(Promise));
http = http.use(promises(Promise));
var structure = require("./structure.js");

var cttvApi = function () {

    var req; // can be json or not

    var credentials = {
        token : undefined, // is a promise or a string
        appname : "",
        secret : "",
        expiry : undefined
    };

    var config = {
        verbose: false,
        prefix: "https://www.targetvalidation.org/api/",
        version: "1.2",
        format: "json"
    };

    var getToken = function () {
        var tokenUrl = _.url.requestToken(credentials);
        credentials.token = jsonHttp.get({
            "url": tokenUrl
        });
        return credentials.token;
    };

    var _ = {};
    _.call = function (myurl, data, format) {
        // Response format json or not
        if (!format) {
            format = "json";
        }
        if (format === "json") {
            req = jsonHttp;
        } else {
            req = http;
        }

        // No auth
        if ((!credentials.token) && (!credentials.appname) && (!credentials.secret)) {
            if (config.verbose) {
                console.log("    CttvApi running in non-authentication mode");
            }

            if (data){ // post
                return req.post({
                    "url": myurl,
                    "body": data
                });
            }

            return req.get({
                "url" : myurl
            });
        }

        // Auth - but not token
        if (!credentials.token) {
            if (config.verbose) {
                console.log("No credential token, requesting one...");
            }

            return getToken()
                .then(callApi)
                .catch(catchErr);
        // Auth & token
        } else {
            if (config.verbose) {
                console.log("Current token is: " + credentials.token);
            }
            var tokenPromise = new Promise (function (resolve) {
                resolve ({
                    body: {
                        token: credentials.token
                    }
                });
            });
            if (typeof credentials.token !== "string") { // The token is still a string
                tokenPromise = credentials.token;
            }

            return tokenPromise
                // .then (function () {
                //     return callApi
                //     // return jsonHttp.get({
                //     //     "url" : myurl,
                //     //     "headers": {
                //     //         "Auth-token": credentials.token
                //     //     }
                //     // })
                //     .catch(catchErr);
                .then (callApi)
                .catch(catchErr);
                // });
        }

        function callApi (resp) {
            if (config.verbose) {
                console.log("   ======> Got a new token: " + resp.body.token);
            }
            credentials.token = resp.body.token;
            var headers = {
                "Auth-token": resp.body.token
            };
            var myPromise;
            if (data) { // post
                myPromise = req.post ({
                    "url": myurl,
                    "headers": headers,
                    "body": data
                });
            } else { // get
                myPromise = req.get ({
                    "url": myurl,
                    "headers": headers
                });

            }
            return myPromise;
        }

        function catchErr (err) {
            // Logic to deal with expired tokens
            switch (err.status) {
                case (419) : // Token expired
                if (config.verbose) {
                    console.log("     --- Received an api error -- Possibly the token has expired (" + err.status + "), so I'll request a new one");
                }
                if (typeof credentials.token === "string" ) {
                    credentials.token = undefined;
                }
                return _.call(myurl, data);

                case (429) : // Too many calls
                if (config.verbose) {
                    console.log("     --- Received an api error -- Probably too many calls made to the api (" + err.status + "), so I'll wait some time to fetch the data");
                }
                var delayedPromise = new Promise (function (resolve) {
                    setTimeout(function (){
                        if (config.verbose) {
                            console.log(" *** trying again after receiving a too many requests error");
                        }
                        resolve(_.call(myurl, data));
                    }, 10000);
                });
                return delayedPromise;

                default:
                throw err;
            }
        }

    };

    apijs(_)
        .getset(credentials)
        .getset(config);

    // Utils
    _.utils = {};
    _.utils.flat2tree = structure.flat2tree;

    // URL object
    _.url = {};

    // prefixes
    var prefixFilterby = "public/evidence/filter?";
    var prefixAssociations = "public/association/filter?";
    var prefixSearch = "public/search?";
    var prefixGene = "private/target/";
    var prefixDisease = "private/disease/"; // updated from "efo" to "disease"
    var prefixToken = "public/auth/request_token?";
    var prefixAutocomplete = "private/autocomplete?";
    var prefixQuickSearch = "private/quicksearch?";
    var prefixExpression = "private/target/expression?";
    var prefixProxy = "proxy/generic/";
    var prefixTarget = "private/target/"; // this replaces prefixGene
    var prefixTargetRelation = "private/relation/target/";
    var prefixDiseaseRelation = "private/relation/disease/";

    _.url.gene = function (obj) {
        return config.prefix + config.version + "/" + prefixGene + obj.gene_id;
    };

    _.url.target = function (obj) {
        return config.prefix + config.version + "/" + prefixTarget + obj.target_id;
    };

    _.url.disease = function (obj) {
        return config.prefix + config.version + "/" + prefixDisease + obj.code;
    };

    _.url.search = function (obj) {
        return config.prefix + config.version + "/" + prefixSearch + parseUrlParams(obj);
    };

    _.url.associations = function (obj) {
        return config.prefix + config.version + "/" + prefixAssociations + parseUrlParams(obj);
    };

    _.url.filterby = function (obj) {
        return config.prefix + config.version + "/" + prefixFilterby + parseUrlParams(obj);
    };

    _.url.requestToken = function (obj) {
        return config.prefix + config.version + "/" + prefixToken + "app_name=" + obj.appname + "&secret=" + obj.secret + (credentials.expiry ? ("&expiry=" + credentials.expiry) : "" );
    };

    _.url.autocomplete = function (obj) {
        return config.prefix + config.version + "/" + prefixAutocomplete + parseUrlParams(obj);
    };

    _.url.quickSearch = function (obj) {
        return config.prefix + config.version + "/" + prefixQuickSearch + parseUrlParams(obj);
    };

    _.url.expression = function (obj) {
        return config.prefix + config.version + "/" + prefixExpression + parseUrlParams(obj);
    };

    _.url.proxy = function (obj) {
        return config.prefix + config.version + "/" + prefixProxy + obj.url;
    };

    _.url.targetRelation = function(obj){
        return config.prefix + config.version + "/" + prefixTargetRelation + obj.id;
    };

    _.url.diseaseRelation = function(obj){
        var id = obj.id;
        delete(obj.id);
        return config.prefix + config.version + "/" + prefixDiseaseRelation + id + "?" + parseUrlParams(obj);
    };

    /**
    * This takes a params object and returns the params concatenated in a string.
    * If a parameter is an array, it adds each item, all with hte same key.
    * Example:
    *   obj = {q:'braf',size:20,filters:['id','pvalue']};
    *   console.log( parseUrlParams(obj) );
    *   // prints "q=braf&size=20&filters=id&filters=pvalue"
    */
    var parseUrlParams = function(obj){
        var opts = [];
        for(var i in obj){
            if( obj.hasOwnProperty(i)){
                if(obj[i].constructor === Array){
                    opts.push(i+"="+(obj[i].join("&"+i+"=")));
                } else {
                    opts.push(i+"="+obj[i]);
                }
            }
        }
        return opts.join("&");
    };

    return _;
};

module.exports = cttvApi;
<commit_msg>Updated version to latest to avoid conflicts<commit_after>var apijs = require("tnt.api");

var http = require("httpplease");
var promises = require('httpplease-promises');
var Promise = require('es6-promise').Promise;
var json = require("httpplease/plugins/json");
jsonHttp = http.use(json).use(promises(Promise));
http = http.use(promises(Promise));
var structure = require("./structure.js");

var cttvApi = function () {

    var req; // can be json or not

    var credentials = {
        token : undefined, // is a promise or a string
        appname : "",
        secret : "",
        expiry : undefined
    };

    var config = {
        verbose: false,
        prefix: "https://www.targetvalidation.org/api/",
        version: "latest",
        format: "json"
    };

    var getToken = function () {
        var tokenUrl = _.url.requestToken(credentials);
        credentials.token = jsonHttp.get({
            "url": tokenUrl
        });
        return credentials.token;
    };

    var _ = {};
    _.call = function (myurl, data, format) {
        // Response format json or not
        if (!format) {
            format = "json";
        }
        if (format === "json") {
            req = jsonHttp;
        } else {
            req = http;
        }

        // No auth
        if ((!credentials.token) && (!credentials.appname) && (!credentials.secret)) {
            if (config.verbose) {
                console.log("    CttvApi running in non-authentication mode");
            }

            if (data){ // post
                return req.post({
                    "url": myurl,
                    "body": data
                });
            }

            return req.get({
                "url" : myurl
            });
        }

        // Auth - but not token
        if (!credentials.token) {
            if (config.verbose) {
                console.log("No credential token, requesting one...");
            }

            return getToken()
                .then(callApi)
                .catch(catchErr);
        // Auth & token
        } else {
            if (config.verbose) {
                console.log("Current token is: " + credentials.token);
            }
            var tokenPromise = new Promise (function (resolve) {
                resolve ({
                    body: {
                        token: credentials.token
                    }
                });
            });
            if (typeof credentials.token !== "string") { // The token is still a string
                tokenPromise = credentials.token;
            }

            return tokenPromise
                // .then (function () {
                //     return callApi
                //     // return jsonHttp.get({
                //     //     "url" : myurl,
                //     //     "headers": {
                //     //         "Auth-token": credentials.token
                //     //     }
                //     // })
                //     .catch(catchErr);
                .then (callApi)
                .catch(catchErr);
                // });
        }

        function callApi (resp) {
            if (config.verbose) {
                console.log("   ======> Got a new token: " + resp.body.token);
            }
            credentials.token = resp.body.token;
            var headers = {
                "Auth-token": resp.body.token
            };
            var myPromise;
            if (data) { // post
                myPromise = req.post ({
                    "url": myurl,
                    "headers": headers,
                    "body": data
                });
            } else { // get
                myPromise = req.get ({
                    "url": myurl,
                    "headers": headers
                });

            }
            return myPromise;
        }

        function catchErr (err) {
            // Logic to deal with expired tokens
            switch (err.status) {
                case (419) : // Token expired
                if (config.verbose) {
                    console.log("     --- Received an api error -- Possibly the token has expired (" + err.status + "), so I'll request a new one");
                }
                if (typeof credentials.token === "string" ) {
                    credentials.token = undefined;
                }
                return _.call(myurl, data);

                case (429) : // Too many calls
                if (config.verbose) {
                    console.log("     --- Received an api error -- Probably too many calls made to the api (" + err.status + "), so I'll wait some time to fetch the data");
                }
                var delayedPromise = new Promise (function (resolve) {
                    setTimeout(function (){
                        if (config.verbose) {
                            console.log(" *** trying again after receiving a too many requests error");
                        }
                        resolve(_.call(myurl, data));
                    }, 10000);
                });
                return delayedPromise;

                default:
                throw err;
            }
        }

    };

    apijs(_)
        .getset(credentials)
        .getset(config);

    // Utils
    _.utils = {};
    _.utils.flat2tree = structure.flat2tree;

    // URL object
    _.url = {};

    // prefixes
    var prefixFilterby = "public/evidence/filter?";
    var prefixAssociations = "public/association/filter?";
    var prefixSearch = "public/search?";
    var prefixGene = "private/target/";
    var prefixDisease = "private/disease/"; // updated from "efo" to "disease"
    var prefixToken = "public/auth/request_token?";
    var prefixAutocomplete = "private/autocomplete?";
    var prefixQuickSearch = "private/quicksearch?";
    var prefixExpression = "private/target/expression?";
    var prefixProxy = "proxy/generic/";
    var prefixTarget = "private/target/"; // this replaces prefixGene
    var prefixTargetRelation = "private/relation/target/";
    var prefixDiseaseRelation = "private/relation/disease/";

    _.url.gene = function (obj) {
        return config.prefix + config.version + "/" + prefixGene + obj.gene_id;
    };

    _.url.target = function (obj) {
        return config.prefix + config.version + "/" + prefixTarget + obj.target_id;
    };

    _.url.disease = function (obj) {
        return config.prefix + config.version + "/" + prefixDisease + obj.code;
    };

    _.url.search = function (obj) {
        return config.prefix + config.version + "/" + prefixSearch + parseUrlParams(obj);
    };

    _.url.associations = function (obj) {
        return config.prefix + config.version + "/" + prefixAssociations + parseUrlParams(obj);
    };

    _.url.filterby = function (obj) {
        return config.prefix + config.version + "/" + prefixFilterby + parseUrlParams(obj);
    };

    _.url.requestToken = function (obj) {
        return config.prefix + config.version + "/" + prefixToken + "app_name=" + obj.appname + "&secret=" + obj.secret + (credentials.expiry ? ("&expiry=" + credentials.expiry) : "" );
    };

    _.url.autocomplete = function (obj) {
        return config.prefix + config.version + "/" + prefixAutocomplete + parseUrlParams(obj);
    };

    _.url.quickSearch = function (obj) {
        return config.prefix + config.version + "/" + prefixQuickSearch + parseUrlParams(obj);
    };

    _.url.expression = function (obj) {
        return config.prefix + config.version + "/" + prefixExpression + parseUrlParams(obj);
    };

    _.url.proxy = function (obj) {
        return config.prefix + config.version + "/" + prefixProxy + obj.url;
    };

    _.url.targetRelation = function(obj){
        return config.prefix + config.version + "/" + prefixTargetRelation + obj.id;
    };

    _.url.diseaseRelation = function(obj){
        var id = obj.id;
        delete(obj.id);
        return config.prefix + config.version + "/" + prefixDiseaseRelation + id + "?" + parseUrlParams(obj);
    };

    /**
    * This takes a params object and returns the params concatenated in a string.
    * If a parameter is an array, it adds each item, all with hte same key.
    * Example:
    *   obj = {q:'braf',size:20,filters:['id','pvalue']};
    *   console.log( parseUrlParams(obj) );
    *   // prints "q=braf&size=20&filters=id&filters=pvalue"
    */
    var parseUrlParams = function(obj){
        var opts = [];
        for(var i in obj){
            if( obj.hasOwnProperty(i)){
                if(obj[i].constructor === Array){
                    opts.push(i+"="+(obj[i].join("&"+i+"=")));
                } else {
                    opts.push(i+"="+obj[i]);
                }
            }
        }
        return opts.join("&");
    };

    return _;
};

module.exports = cttvApi;
<|endoftext|>


<commit_before>'use strict';

import merge from './module/merge';
import insert from './component/insert';
import css from './module/css';

var defaults = {
  prefix: 'material',
  class: 'separator',
  tag: 'span'
};

/**
 * The item class is used for example as item list
 *
 * @class
 * @extends {Component}
 * @return {Object} The class instance
 * @example new Item(object);
 */
export default class Separator {

  /**
   * init
   * @return {Object} The class options
   */
  constructor(options) {

    this.init(options);
    this.build();

    return this;
  }

  /**
   * [init description]
   * @param  {?} options [description]
   * @return {?}         [description]
   */
  init(options) {
    options = options || {};
    // merge options
    this.options = merge(defaults, options);

    Object.assign(this, insert);
  }

  /**
   * Build function for item
   * @return {Object} This class instance
   */
  build(options) {
    options = options || this.options;

    // define main tag

    this.wrapper = document.createElement(this.options.tag);

    css.add(this.wrapper, this.options.prefix + '-' + this.options.class);

    if (options.type) {
      css.add(this.wrapper, this.options.class + '-' + options.type);
    }

    if (this.options.text) {
      this.wrapper.textContent = this.options.text;
    }

    if (this.options.container) {
      this.insert(this.options.container);
    }
  }
};<commit_msg>update class<commit_after>'use strict';

import merge from './module/merge';
import insert from './component/insert';
import css from './module/css';

var defaults = {
  prefix: 'material',
  class: 'divider',
  tag: 'span'
};

/**
 * The item class is used for example as item list
 *
 * @class
 * @extends {Component}
 * @return {Object} The class instance
 * @example new Item(object);
 */
export default class Separator {

  /**
   * init
   * @return {Object} The class options
   */
  constructor(options) {

    this.init(options);
    this.build();

    return this;
  }

  /**
   * [init description]
   * @param  {?} options [description]
   * @return {?}         [description]
   */
  init(options) {
    options = options || {};
    // merge options
    this.options = merge(defaults, options);

    Object.assign(this, insert);
  }

  /**
   * Build function for item
   * @return {Object} This class instance
   */
  build(options) {
    options = options || this.options;

    // define main tag

    this.wrapper = document.createElement(this.options.tag);

    css.add(this.wrapper, this.options.prefix + '-' + this.options.class);

    if (options.type) {
      css.add(this.wrapper, this.options.class + '-' + options.type);
    }

    if (this.options.text) {
      this.wrapper.textContent = this.options.text;
    }

    if (this.options.container) {
      this.insert(this.options.container);
    }
  }
};<|endoftext|>


<commit_before>'use strict';

// require('time-require');

var matter = require('parser-front-matter');
var extname = require('gulp-extname');
var Template = require('template');
var through = require('through2');
var path = require('path');

var composer = require('../');
require('./lib/runtimes')(composer);

var template = new Template();

template.engine('hbs', require('engine-handlebars'));
template.option('renameKey', function (fp) {
  return path.basename(fp, path.extname(fp));
});

template.onLoad(/\.hbs$/, function (file, next) {
  matter.parse(file, next);
});

var paths = {
  pages: ['./templates/pages/**/*.hbs'],
  layouts: ['./templates/layouts/*.hbs'],
  includes: ['./templates/includes/*.hbs']
};

template.create('pages');
template.create('layouts', {viewType: 'layout'});
template.create('includes', {viewType: 'partial'});

composer.task('layouts', function (done) {
  try {
    template.layouts(paths.layouts);
  } catch (err) {
    return done(err);
  }
  done();
});

composer.task('includes', function (done) {
  try {
    template.includes(paths.includes);
  } catch (err) {
    return done(err);
  }
  done();
});

composer.task('pages', function (done) {
  try {
    template.pages(paths.pages);
  } catch (err) {
    return done(err);
  }
  done();
});

composer.task('site', function (done) {
  var stream;
  try {
    stream = loadCollection('pages')
      .pipe(render())
      .pipe(extname())
      .pipe(dest('dist'));
  } catch (err) {
    return done(err);
  }
  return stream;
});

composer.task('watch', function () {
  composer.watch(paths.layouts, ['layouts', 'pages', 'site']);
  composer.watch(paths.includes, ['includes', 'pages', 'site']);
  composer.watch(paths.pages, ['pages', 'site']);
});

composer.task('default', ['layouts', 'includes', 'pages', 'site']);
composer.task('dev', ['default', 'watch']);

composer.run('default', function (err, results) {
  if (err) return console.error(err);
  console.log('Finshed');
});

function loadCollection (collection) {
  var stream = through.obj();
  function write () {
    template[collection].forOwn(function (view) {
      stream.write(view);
    });
    stream.end();
  }
  process.nextTick(write);
  return stream;
}

function render (locals) {
  locals = locals || {};
  return through.obj(function (file, enc, next) {
    file.render(locals, next);
  });
}

function dest (dir) {
  return through.obj(function (file, enc, next) {
    file.write(path.join(dir, path.basename(file.path)), next);
  });
}
<commit_msg>cleanup tasks<commit_after>'use strict';

// require('time-require');

var matter = require('parser-front-matter');
var extname = require('gulp-extname');
var Template = require('template');
var through = require('through2');
var path = require('path');

var composer = require('../');
require('./lib/runtimes')(composer);

var template = new Template();

template.engine('hbs', require('engine-handlebars'));
template.option('renameKey', function (fp) {
  return path.basename(fp, path.extname(fp));
});

template.onLoad(/\.hbs$/, function (file, next) {
  matter.parse(file, next);
});

var paths = {
  pages: ['./templates/pages/**/*.hbs'],
  layouts: ['./templates/layouts/*.hbs'],
  includes: ['./templates/includes/*.hbs']
};

template.create('pages');
template.create('layouts', {viewType: 'layout'});
template.create('includes', {viewType: 'partial'});

composer.task('layouts', function (done) {
  template.layouts(paths.layouts);
  done();
});

composer.task('includes', function (done) {
  template.includes(paths.includes);
  done();
});

composer.task('pages', function (done) {
  template.pages(paths.pages);
  done();
});

composer.task('site', function () {
  return loadCollection('pages')
    .pipe(render())
    .pipe(extname())
    .pipe(dest('dist'));
});

composer.task('watch', function () {
  composer.watch(paths.layouts, ['layouts', 'pages', 'site']);
  composer.watch(paths.includes, ['includes', 'pages', 'site']);
  composer.watch(paths.pages, ['pages', 'site']);
});

composer.task('default', ['layouts', 'includes', 'pages', 'site']);
composer.task('dev', ['default', 'watch']);

composer.run('default', function (err, results) {
  if (err) return console.error(err);
  console.log('Finshed');
});

function loadCollection (collection) {
  var stream = through.obj();
  function write () {
    template[collection].forOwn(function (view) {
      stream.write(view);
    });
    stream.end();
  }
  process.nextTick(write);
  return stream;
}

function render (locals) {
  locals = locals || {};
  return through.obj(function (file, enc, next) {
    file.render(locals, next);
  });
}

function dest (dir) {
  return through.obj(function (file, enc, next) {
    file.write(path.join(dir, path.basename(file.path)), next);
  });
}
<|endoftext|>


<commit_before>// Mongo DB app

var MongoClient = require('mongodb').MongoClient,
    express = require('express'),
    bodyParser = require('body-parser'),
    app = express(),
    DB;

app.set('view engine', 'jade');
app.set('views', __dirname + '/views');

app.use(bodyParser.urlencoded({ extended: false }));

console.log('Connecting to database...');

// Connecting to mongodb local server
MongoClient.connect('mongodb://localhost:27017/users')
    .then(function(db) {
        DB = db;

        app.listen(8000, function() {
            console.log('Database connected!');
        });
    })
    .catch(function(err) {
        res.send('Some error occurred!');
    });

// Root route request
app.get('/', function(req, res) {
    return DB.collection('list').find().toArray()
        .then(function(users) {
            res.render('index', {
                users: users
            });
        })
        .catch(function() {
            res.send('Some error occurred!');
        });
});

// User info route
app.get('/user/:user', function(req, res) {
    return DB.collection('list').findOne({ name: req.params.user })
        .then(function(user) {
            var id = req.query.id === 'true' ? user._id : null,
                uid = req.query.uid === 'true' ? user.uid : null;

            user ? res.render('user', {
                name: user.name,
                id: id,
                uid: uid
            }) : res.send('User not found!');
        })
        .catch(function(err) {
            res.send('Some error occurred!');
        });
});

// Route to add new user
app.post('/addUser', function(req, res) {
	if(!req.body.name && !req.body.uid) {
		res.send('Name and uid are required!');
	}

    return DB.collection('list').insertOne({
    		name: req.body.name,
    		uid: parseInt(req.body.uid, 10)
    	})
        .then(function() {
            res.redirect('/');
        })
        .catch(function() {
            res.send('Some error occurred!');
        });
});

// Route to add users in bulk
app.post('/bulkAddUsers', function(req, res) {
    var users = [{
        name: 'Jonah',
        uid: 117
    }, {
        name: 'Miles',
        uid: 118
    }];

    return DB.collection('list').insertMany(users)
        .then(function() {
            res.redirect('/');
        })
        .catch(function() {
            res.send('Some error occurred!');
        });
});
<commit_msg>Unordered bulk insert operation implementation<commit_after>// Mongo DB app

var MongoClient = require('mongodb').MongoClient,
    express = require('express'),
    bodyParser = require('body-parser'),
    app = express(),
    DB;

app.set('view engine', 'jade');
app.set('views', __dirname + '/views');

app.use(bodyParser.urlencoded({ extended: false }));

console.log('Connecting to database...');

// Connecting to mongodb local server
MongoClient.connect('mongodb://localhost:27017/users')
    .then(function(db) {
        DB = db;

        app.listen(8000, function() {
            console.log('Database connected!');
        });
    })
    .catch(function(err) {
        res.send('Some error occurred!');
    });

// Root route request
app.get('/', function(req, res) {
    return DB.collection('list').find().toArray()
        .then(function(users) {
            res.render('index', {
                users: users
            });
        })
        .catch(function() {
            res.send('Some error occurred!');
        });
});

// User info route
app.get('/user/:user', function(req, res) {
    return DB.collection('list').findOne({ name: req.params.user })
        .then(function(user) {
            var id = req.query.id === 'true' ? user._id : null,
                uid = req.query.uid === 'true' ? user.uid : null;

            user ? res.render('user', {
                name: user.name,
                id: id,
                uid: uid
            }) : res.send('User not found!');
        })
        .catch(function(err) {
            res.send('Some error occurred!');
        });
});

// Route to add new user
app.post('/addUser', function(req, res) {
	if(!req.body.name && !req.body.uid) {
		res.send('Name and uid are required!');
	}

    return DB.collection('list').insertOne({
    		name: req.body.name,
    		uid: parseInt(req.body.uid, 10)
    	})
        .then(function() {
            res.redirect('/');
        })
        .catch(function() {
            res.send('Some error occurred!');
        });
});

// Route to add users in bulk
app.post('/bulkAddUsers', function(req, res) {
    var users = [{
        name: 'Jonah',
        uid: 117,
        _id: 12
    }, {
        name: 'Miles',
        uid: 118,
        _id: 12
    }, {
        name: 'Jay',
        uid: 118,
        _id: 14
    }];

    return DB.collection('list').insertMany(users, {
        ordered: false
    })
        .then(function() {
            res.redirect('/');
        })
        .catch(function(err) {
            console.log(err);
            res.send('Some error occurred!');
        });
});
<|endoftext|>


<commit_before>var cm, doc, cmContext, docContext, cmResponse, docResponse;
var mProved, mProving, mToprove, mUnlocked;

var setCursorOnResponse = false;

$(document).ready(function() {
    setupEditor();

    $(document).keydown(function(e) {
        if (e.which === 72 && e.ctrlKey && e.altKey) {
            asyncLog("HELPSTART");
            $("#help-in-progress-button").css("display", "");
        }
    });

});

function showTooltip(e) {

    if ($(".CodeMirror-lint-tooltip").length > 0) { return; }

    var initialTarget = e.target;
    var tt = document.createElement("div");
    tt.className = "CodeMirror-lint-tooltip";
    fillDocumentation($(tt), $(e.target).text());
    document.body.appendChild(tt);

    var box = initialTarget.getBoundingClientRect();
    tt.style.top = box.bottom + "px";
    tt.style.left = box.left + "px";
    function position(e) {
        if (e.target !== initialTarget && $(e.target).closest(tt).length === 0) {
            tt.remove();
            CodeMirror.off(document, "mousemove", position);
        }
        //tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + "px";
        //tt.style.left = (e.clientX + 5) + "px";
    }

    CodeMirror.on(document, "mousemove", position);
    position(e);
    if (tt.style.opacity != null) tt.style.opacity = 1;
    return tt;

}

function setupEditor() {

    cm = CodeMirror(
        $("#main-left")[0],
        {
            "autofocus": true,
            "cursorScrollMargin": 40,
            "extraKeys": {

                "Ctrl-Alt-Up": function(cm) {
                    onCtrlUp(true);
                },

                "Ctrl-Alt-Right": function(cm) {
                },

                "Ctrl-Alt-Down": function(cm) {
                    onCtrlDown(true);
                },

                "Ctrl-Alt-Left": function(cm) {
                },

                "Ctrl-Alt-L": function(cm) {
                    $("#load-local-button").click();
                },

                "Ctrl-Alt-N": function(cm) { onCtrlDown(true); },

                "Ctrl-Alt-P": function(cm) {
                    onCtrlUp(true);
                },

                "Ctrl-Alt-S": function(cm) {
                    $("#save-local-button").click();
                },

                "Ctrl-Alt-T": function(cm) {
                    if ($("#peek-button").css("display") !== "none") {
                        $("#peek-button").click();
                        return;
                    }
                    if ($("#unpeek-button").css("display") !== "none") {
                        $("#unpeek-button").click();
                        return;
                    }
                },

                "Ctrl-Alt-Enter": function(cm) {
                    onCtrlEnter();
                },

            },
            "keyMap": "sublime",
            "lineNumbers": true,
            "lineWrapping": true,
            "matchBrackets": true,
            "mode": "text/x-coq",
            "placeholder": "(* Type your Coq code here or load a file *)",
            "showCursorWhenSelecting": true,
            "styleSelectedText": true,
        }
    );

    var targets = ["cm-admitter", "cm-tactic", "cm-terminator"];

    CodeMirror.on(cm.getWrapperElement(), "mouseover", function(e) {
        var target = e.target;
        if (!_(targets).some(function(name) {
            return $(target).hasClass(name);
        })) { return; }
        //var box = target.getBoundingClientRect();
        //var x = (box.left + box.right) / 2;
        //var y = (box.top + box.bottom) / 2;
        //var spans = cm.findMarksAt(cm.coordsChar({left: x, top: y}, "client"));
        //console.log("spans", spans);
        var aborted = false;
        function monitorMouseMove(newE) {
            if (newE.target !== e.target) {
                aborted = true;
            }
        }
        CodeMirror.on(document, "mousemove", monitorMouseMove);
        window.setTimeout(function() {
            CodeMirror.off(document, "mousemove", monitorMouseMove);
            if (!aborted) { showTooltip(e); }
        }, 300);
    });

    doc = cm.getDoc();

    cmContext = CodeMirror(
        $("#coqtop-context")[0],
        {
            "gutters": ["tactic-gutter"],
            "lineWrapping": true,
            "matchBrackets": true,
            "mode": "text/x-coq",
        }
    );

    docContext = cmContext.getDoc();

    cmResponse = CodeMirror(
        $("#coqtop-response")[0],
        {
            "lineWrapping": true,
            "matchBrackets": true,
            "mode": "text/x-coq",
        }
    );

    docResponse = cmResponse.getDoc();

    resetEditor("");

}

function resetEditor(code) {
    doc.setValue(code);
    var zeroPos = {"line": 0, "ch": 0};
    markProved(zeroPos, zeroPos);
    markProving(zeroPos, zeroPos);
    markToprove(zeroPos, zeroPos);
    markUnlocked(zeroPos, cm.findPosH(zeroPos, code.length, "char"));
}

function bumpPosition(pos) {
    return cm.findPosH(pos, 1, "char");
}

function fromtoBumpFrom(fromto) {
    return {
        "from": bumpPosition(fromto.from),
        "to": fromto.to,
    };
}

function fromtoBumpTo(fromto) {
    return {
        "from": fromto.from,
        "to": bumpPosition(fromto.to),
    };
}

function markRegion(from, to, className, readOnly) {
    return doc.markText(
        from,
        to,
        {
            "className": className,
            "clearWhenEmpty": false,
            "inclusiveLeft": true,
            "inclusiveRight": !readOnly,
            "readOnly": readOnly,
        }
    );
}

function markProved(from, to) {
    if (mProved !== undefined) { mProved.clear(); }
    mProved = markRegion(from, to, "proved", true);
}

function markProving(from, to) {
    if (mProving !== undefined) { mProving.clear(); }
    mProving = markRegion(from, to, "proving", true);
}

function markToprove(from, to) {
    if (mToprove !== undefined) { mToprove.clear(); }
    mToprove = markRegion(from, to, "toprove", true);
}

function markUnlocked(from, to) {
    if (mUnlocked !== undefined) { mUnlocked.clear(); }
    mUnlocked = markRegion(from, to, "unlocked", false);
}

function process() {
    var unlockedFromto = mUnlocked.find();
    var toproveFromto = mToprove.find();

    // make sure there are things to process
    if (unlockedFromto.to.line > unlockedFromto.from.line
        || unlockedFromto.to.ch > unlockedFromto.from.ch) {

        markUnlocked(fromtoBumpFrom(unlockedFromto));

        markToprove(fromtoBumpTo(toproveFromto));

    }
}

function onCtrlDown(fromUser) {
    var rToprove = mToprove.find();
    var rUnlocked = mUnlocked.find();
    var unlocked = doc.getRange(rUnlocked.from, rUnlocked.to);
    var nextIndex = next(unlocked);
    if (nextIndex === 0) { return; }
    var nextPos = cm.findPosH(rUnlocked.from, nextIndex, "char");
    markToprove(rToprove.from, nextPos);
    markUnlocked(nextPos, rUnlocked.to);
    if (fromUser) {
        setCursorOnResponse = true;
        doc.setCursor(nextPos);
        scrollIntoView();
    }
    return processToprove();
}

function onCtrlUp(fromUser) {
    if (processingToprove) { return Promise.resolve(); }
    var rProved = mProved.find();
    var rUnlocked = mUnlocked.find();
    var proved = doc.getRange(rProved.from, rProved.to);
    if (proved === "") { return Promise.resolve(); }
    var prevIndex = prev(proved);
    var pieceToUnprocess = proved.substring(prevIndex);
    if (pieceToUnprocess === "") { return Promise.resolve(); }
    var prevPos = cm.findPosH(rProved.from, prevIndex, "char");
    markProved(rProved.from, prevPos);
    markProving(prevPos, prevPos);
    markToprove(prevPos, prevPos);
    markUnlocked(prevPos, rUnlocked.to);
    asyncLog("PROVERUP " + pieceToUnprocess);
    if (fromUser) {
        setCursorOnResponse = true;
        doc.setCursor(prevPos);
        scrollIntoView();
    }
    return asyncUndo()
        .then(_.partial(undoCallback, fromUser, pieceToUnprocess))
    ;
}

// a <= b ?
function positionIsBefore(a, b) {
    if (a.line < b.line) { return true; }
    if (a.line === b.line && a.ch <= b.ch) { return true; }
    return false;
}

function onCtrlEnter() {
    setCursorOnResponse = false;
    var cursorPos = doc.getCursor();
    var rProved = mProved.find();
    var rUnlocked = mUnlocked.find();
    if (positionIsBefore(cursorPos, rProved.to)) {
        rewindToPos(cursorPos);
    } else if (positionIsBefore(rUnlocked.from, cursorPos)) {
        processToPos(cursorPos);
    } else { // trying to jump in the proving or toprove area, ignored
        return;
    }
}

function rewindToPos(pos) {
    var rProved = mProved.find();
    if (positionIsBefore(rProved.to, pos)) {
        return Promise.resolve();
    } else {
        return onCtrlUp(false).then(function() { rewindToPos(pos); });
    }
}

function processToPos(pos) {
    var rToprove = mToprove.find();
    var rest = doc.getRange(rToprove.to, pos);
    if (coqTrim(rest) !== "") {
        onCtrlDown(false);
        processToPos(pos);
    }
}

var processingToprove = false;

function processToprove() {
    if (processingToprove) { return Promise.resolve(); }
    // Here, the prooftree gets a chance to modify toprove
    if (activeProofTree !== undefined) {
        activeProofTree.beforeToproveConsumption();
    }
    var rProving = mProving.find();
    var rToprove = mToprove.find();
    var toprove = doc.getRange(rToprove.from, rToprove.to);
    if (toprove === '') { return Promise.resolve(); }
    var nextIndex = next(toprove);
    var pieceToProcess = toprove.substring(0, nextIndex);
    var nextPos = cm.findPosH(rToprove.from, nextIndex, "char");
    markProving(rProving.from, nextPos);
    markToprove(nextPos, rToprove.to);
    processingToprove = true;
    return asyncQuery(pieceToProcess)
        .then(function(response) {
            processingToprove = false;
            processToprove();
        })
        .catch(outputError)
    ;
}

function getProved() {
    var rProved = mProved.find();
    return doc.getRange(rProved.from, rProved.to);
}

function getProving() {
    var rProving = mProving.find();
    return doc.getRange(rProving.from, rProving.to);
}

function getToprove() {
    var rToprove = mToprove.find();
    return doc.getRange(rToprove.from, rToprove.to);
}

function getUnlocked() {
    var rUnlocked = mUnlocked.find();
    return doc.getRange(rUnlocked.from, rUnlocked.to);
}

function scrollIntoView() {
    var cursorPos = doc.getCursor();
    cm.scrollIntoView({
        "from": cm.findPosV(cursorPos, -1, "line"),
        "to":   cm.findPosV(cursorPos, +1, "line"),
    });
}
<commit_msg>fix performing useless intensive trimming on entire files<commit_after>var cm, doc, cmContext, docContext, cmResponse, docResponse;
var mProved, mProving, mToprove, mUnlocked;

var setCursorOnResponse = false;

$(document).ready(function() {
    setupEditor();

    $(document).keydown(function(e) {
        if (e.which === 72 && e.ctrlKey && e.altKey) {
            asyncLog("HELPSTART");
            $("#help-in-progress-button").css("display", "");
        }
    });

});

function showTooltip(e) {

    if ($(".CodeMirror-lint-tooltip").length > 0) { return; }

    var initialTarget = e.target;
    var tt = document.createElement("div");
    tt.className = "CodeMirror-lint-tooltip";
    fillDocumentation($(tt), $(e.target).text());
    document.body.appendChild(tt);

    var box = initialTarget.getBoundingClientRect();
    tt.style.top = box.bottom + "px";
    tt.style.left = box.left + "px";
    function position(e) {
        if (e.target !== initialTarget && $(e.target).closest(tt).length === 0) {
            tt.remove();
            CodeMirror.off(document, "mousemove", position);
        }
        //tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + "px";
        //tt.style.left = (e.clientX + 5) + "px";
    }

    CodeMirror.on(document, "mousemove", position);
    position(e);
    if (tt.style.opacity != null) tt.style.opacity = 1;
    return tt;

}

function setupEditor() {

    cm = CodeMirror(
        $("#main-left")[0],
        {
            "autofocus": true,
            "cursorScrollMargin": 40,
            "extraKeys": {

                "Ctrl-Alt-Up": function(cm) {
                    onCtrlUp(true);
                },

                "Ctrl-Alt-Right": function(cm) {
                },

                "Ctrl-Alt-Down": function(cm) {
                    onCtrlDown(true);
                },

                "Ctrl-Alt-Left": function(cm) {
                },

                "Ctrl-Alt-L": function(cm) {
                    $("#load-local-button").click();
                },

                "Ctrl-Alt-N": function(cm) { onCtrlDown(true); },

                "Ctrl-Alt-P": function(cm) {
                    onCtrlUp(true);
                },

                "Ctrl-Alt-S": function(cm) {
                    $("#save-local-button").click();
                },

                "Ctrl-Alt-T": function(cm) {
                    if ($("#peek-button").css("display") !== "none") {
                        $("#peek-button").click();
                        return;
                    }
                    if ($("#unpeek-button").css("display") !== "none") {
                        $("#unpeek-button").click();
                        return;
                    }
                },

                "Ctrl-Alt-Enter": function(cm) {
                    onCtrlEnter();
                },

            },
            "keyMap": "sublime",
            "lineNumbers": true,
            "lineWrapping": true,
            "matchBrackets": true,
            "mode": "text/x-coq",
            "placeholder": "(* Type your Coq code here or load a file *)",
            "showCursorWhenSelecting": true,
            "styleSelectedText": true,
        }
    );

    var targets = ["cm-admitter", "cm-tactic", "cm-terminator"];

    CodeMirror.on(cm.getWrapperElement(), "mouseover", function(e) {
        var target = e.target;
        if (!_(targets).some(function(name) {
            return $(target).hasClass(name);
        })) { return; }
        //var box = target.getBoundingClientRect();
        //var x = (box.left + box.right) / 2;
        //var y = (box.top + box.bottom) / 2;
        //var spans = cm.findMarksAt(cm.coordsChar({left: x, top: y}, "client"));
        //console.log("spans", spans);
        var aborted = false;
        function monitorMouseMove(newE) {
            if (newE.target !== e.target) {
                aborted = true;
            }
        }
        CodeMirror.on(document, "mousemove", monitorMouseMove);
        window.setTimeout(function() {
            CodeMirror.off(document, "mousemove", monitorMouseMove);
            if (!aborted) { showTooltip(e); }
        }, 300);
    });

    doc = cm.getDoc();

    cmContext = CodeMirror(
        $("#coqtop-context")[0],
        {
            "gutters": ["tactic-gutter"],
            "lineWrapping": true,
            "matchBrackets": true,
            "mode": "text/x-coq",
        }
    );

    docContext = cmContext.getDoc();

    cmResponse = CodeMirror(
        $("#coqtop-response")[0],
        {
            "lineWrapping": true,
            "matchBrackets": true,
            "mode": "text/x-coq",
        }
    );

    docResponse = cmResponse.getDoc();

    resetEditor("");

}

function resetEditor(code) {
    doc.setValue(code);
    var zeroPos = {"line": 0, "ch": 0};
    markProved(zeroPos, zeroPos);
    markProving(zeroPos, zeroPos);
    markToprove(zeroPos, zeroPos);
    markUnlocked(zeroPos, cm.findPosH(zeroPos, code.length, "char"));
}

function bumpPosition(pos) {
    return cm.findPosH(pos, 1, "char");
}

function fromtoBumpFrom(fromto) {
    return {
        "from": bumpPosition(fromto.from),
        "to": fromto.to,
    };
}

function fromtoBumpTo(fromto) {
    return {
        "from": fromto.from,
        "to": bumpPosition(fromto.to),
    };
}

function markRegion(from, to, className, readOnly) {
    return doc.markText(
        from,
        to,
        {
            "className": className,
            "clearWhenEmpty": false,
            "inclusiveLeft": true,
            "inclusiveRight": !readOnly,
            "readOnly": readOnly,
        }
    );
}

function markProved(from, to) {
    if (mProved !== undefined) { mProved.clear(); }
    mProved = markRegion(from, to, "proved", true);
}

function markProving(from, to) {
    if (mProving !== undefined) { mProving.clear(); }
    mProving = markRegion(from, to, "proving", true);
}

function markToprove(from, to) {
    if (mToprove !== undefined) { mToprove.clear(); }
    mToprove = markRegion(from, to, "toprove", true);
}

function markUnlocked(from, to) {
    if (mUnlocked !== undefined) { mUnlocked.clear(); }
    mUnlocked = markRegion(from, to, "unlocked", false);
}

function process() {
    var unlockedFromto = mUnlocked.find();
    var toproveFromto = mToprove.find();

    // make sure there are things to process
    if (unlockedFromto.to.line > unlockedFromto.from.line
        || unlockedFromto.to.ch > unlockedFromto.from.ch) {

        markUnlocked(fromtoBumpFrom(unlockedFromto));

        markToprove(fromtoBumpTo(toproveFromto));

    }
}

function onCtrlDown(fromUser) {
    var rToprove = mToprove.find();
    var rUnlocked = mUnlocked.find();
    var unlocked = doc.getRange(rUnlocked.from, rUnlocked.to);
    var nextIndex = next(unlocked);
    if (nextIndex === 0) { return; }
    var nextPos = cm.findPosH(rUnlocked.from, nextIndex, "char");
    markToprove(rToprove.from, nextPos);
    markUnlocked(nextPos, rUnlocked.to);
    if (fromUser) {
        setCursorOnResponse = true;
        doc.setCursor(nextPos);
        scrollIntoView();
    }
    return processToprove();
}

function onCtrlUp(fromUser) {
    if (processingToprove) { return Promise.resolve(); }
    var rProved = mProved.find();
    var rUnlocked = mUnlocked.find();
    var proved = doc.getRange(rProved.from, rProved.to);
    if (proved === "") { return Promise.resolve(); }
    var prevIndex = prev(proved);
    var pieceToUnprocess = proved.substring(prevIndex);
    if (pieceToUnprocess === "") { return Promise.resolve(); }
    var prevPos = cm.findPosH(rProved.from, prevIndex, "char");
    markProved(rProved.from, prevPos);
    markProving(prevPos, prevPos);
    markToprove(prevPos, prevPos);
    markUnlocked(prevPos, rUnlocked.to);
    asyncLog("PROVERUP " + pieceToUnprocess);
    if (fromUser) {
        setCursorOnResponse = true;
        doc.setCursor(prevPos);
        scrollIntoView();
    }
    return asyncUndo()
        .then(_.partial(undoCallback, fromUser, pieceToUnprocess))
    ;
}

// a <= b ?
function positionIsBefore(a, b) {
    if (a.line < b.line) { return true; }
    if (a.line === b.line && a.ch <= b.ch) { return true; }
    return false;
}

function onCtrlEnter() {
    setCursorOnResponse = false;
    var cursorPos = doc.getCursor();
    var rProved = mProved.find();
    var rUnlocked = mUnlocked.find();
    if (positionIsBefore(cursorPos, rProved.to)) {
        rewindToPos(cursorPos);
    } else if (positionIsBefore(rUnlocked.from, cursorPos)) {
        processToPos(cursorPos);
    } else { // trying to jump in the proving or toprove area, ignored
        return;
    }
}

function rewindToPos(pos) {
    var rProved = mProved.find();
    if (positionIsBefore(rProved.to, pos)) {
        return Promise.resolve();
    } else {
        return onCtrlUp(false).then(function() { rewindToPos(pos); });
    }
}

function processToPos(pos) {
    var rToprove = mToprove.find();
    var rest = doc.getRange(rToprove.to, pos);
    // [rest] in the next line can be huge, be careful with computations
    if (coqTrimLeft(rest) !== "") {
        onCtrlDown(false);
        processToPos(pos);
    }
}

var processingToprove = false;

function processToprove() {
    if (processingToprove) { return Promise.resolve(); }
    // Here, the prooftree gets a chance to modify toprove
    if (activeProofTree !== undefined) {
        activeProofTree.beforeToproveConsumption();
    }
    var rProving = mProving.find();
    var rToprove = mToprove.find();
    var toprove = doc.getRange(rToprove.from, rToprove.to);
    if (toprove === '') { return Promise.resolve(); }
    var nextIndex = next(toprove);
    var pieceToProcess = toprove.substring(0, nextIndex);
    var nextPos = cm.findPosH(rToprove.from, nextIndex, "char");
    markProving(rProving.from, nextPos);
    markToprove(nextPos, rToprove.to);
    processingToprove = true;
    return asyncQuery(pieceToProcess)
        .then(function(response) {
            processingToprove = false;
            processToprove();
        })
        .catch(outputError)
    ;
}

function getProved() {
    var rProved = mProved.find();
    return doc.getRange(rProved.from, rProved.to);
}

function getProving() {
    var rProving = mProving.find();
    return doc.getRange(rProving.from, rProving.to);
}

function getToprove() {
    var rToprove = mToprove.find();
    return doc.getRange(rToprove.from, rToprove.to);
}

function getUnlocked() {
    var rUnlocked = mUnlocked.find();
    return doc.getRange(rUnlocked.from, rUnlocked.to);
}

function scrollIntoView() {
    var cursorPos = doc.getCursor();
    cm.scrollIntoView({
        "from": cm.findPosV(cursorPos, -1, "line"),
        "to":   cm.findPosV(cursorPos, +1, "line"),
    });
}
<|endoftext|>