<commit_before>var jQuery = require('jquery');
var Terminal = require('./compiled/Terminal');
var React = require('react');
var _ = require('lodash');

jQuery(document).ready(function () {
    window.terminal = new Terminal(getDimensions());

    jQuery(window).resize(function() {
        terminal.resize(getDimensions());
    });

    React.render(<Board terminal={window.terminal}/>, document.getElementById('black-board'));

    jQuery(document).keydown(function(event) {
        focusLastInput(event);
    });
});

var Board = React.createClass({
    componentDidMount: function () {
        this.props.terminal.on('invocation', this.forceUpdate.bind(this));
    },
    handleKeyDown: function (event) {
        // Ctrl+l
        if (event.ctrlKey && event.keyCode === 76) {
            this.props.terminal.clearInvocations();
            event.stopPropagation();
        }
    },
    render: function () {
        var invocations = this.props.terminal.invocations.map(function (invocation) {
            return (
                <Invocation key={invocation.id} invocation={invocation}/>
            )
        });
        return (
            <div id="board" onKeyDown={this.handleKeyDown}>
                <div id="invocations">
                    {invocations}
                </div>
                <StatusLine currentWorkingDirectory={this.props.terminal.currentDirectory}/>
            </div>
        );
    }
});

var Invocation = React.createClass({
    componentDidMount: function () {
        this.props.invocation.on('data', function () {
            this.setState({ canBeDecorated: this.props.invocation.canBeDecorated()});
        }.bind(this));
    },
    componentDidUpdate: scrollToBottom,

    getInitialState: function() {
        return {
            decorate: true,
            canBeDecorated: this.props.invocation.canBeDecorated()
        };
    },
    render: function () {
        var buffer, decorationToggle;

        if (this.state.decorate && this.state.canBeDecorated) {
            buffer = this.props.invocation.decorate();
        } else {
            buffer = this.props.invocation.getBuffer().render();
        }

        if (this.props.invocation.canBeDecorated()) {
            decorationToggle = <DecorationToggle invocation={this}/>;
        }

        return (
            <div className="invocation">
                <Prompt prompt={this.props.invocation.getPrompt()} status={this.props.invocation.status}/>
                {decorationToggle}
                {buffer}
            </div>
        );
    }
});

var DecorationToggle = React.createClass({
    getInitialState: function() {
        return {enabled: this.props.invocation.state.decorate};
    },
    handleClick: function() {
        var newState = !this.state.enabled;
        this.setState({enabled: newState});
        this.props.invocation.setState({decorate: newState});
    },
    render: function () {
        var classes = ['decoration-toggle'];

        if (!this.state.enabled) {
            classes.push('disabled');
        }

        return (
            <a href="#" className={classes.join(' ')} onClick={this.handleClick}>
                <i className="fa fa-magic"></i>
            </a>
        );
    }
});

var Prompt = React.createClass({
    getInputNode: function () {
        return this.refs.command.getDOMNode()
    },
    getValue: function () {
        return this.getInputNode().innerText;
    },
    componentDidMount: function () {
        this.getInputNode().focus();
    },
    handleKeyUp: function (event) {
        this.props.prompt.buffer.setTo(this.getValue());
    },
    handleKeyDown: function (event) {
        if (event.keyCode == 13) {
            this.props.prompt.send(this.getValue());

            event.stopPropagation();
            return false;
        }

        // Ctrl+P, ↑.
        if ((event.ctrlKey && event.keyCode === 80) || event.keyCode === 38) {
            var prevCommand = this.props.prompt.history.getPrevious();
            if (typeof prevCommand != 'undefined') {
                this.getInputNode().innerText = prevCommand;
            }

            event.stopPropagation();
            return false;
        }

        // Ctrl+N, ↓.
        if ((event.ctrlKey && event.keyCode === 78) || event.keyCode === 40) {
            var command = this.props.prompt.history.getNext();
            this.getInputNode().innerText = command || '';

            event.stopPropagation();
            return false;
        }
    },
    render: function () {
        var classes = ['prompt', this.props.status].join(' ');

        return (
            <div className="prompt-wrapper">
                <div className="prompt-decoration">
                    <div className="arrow"/>
                </div>
                <div className={classes}
                     onKeyDown={this.handleKeyDown}
                     onKeyUp={this.handleKeyUp}
                     type="text"
                     ref="command"
                     contentEditable="true" /><commit_msg>Add onInput.<commit_after>var jQuery = require('jquery');
var Terminal = require('./compiled/Terminal');
var React = require('react');
var _ = require('lodash');

jQuery(document).ready(function () {
    window.terminal = new Terminal(getDimensions());

    jQuery(window).resize(function() {
        terminal.resize(getDimensions());
    });

    React.render(<Board terminal={window.terminal}/>, document.getElementById('black-board'));

    jQuery(document).keydown(function(event) {
        focusLastInput(event);
    });
});

var Board = React.createClass({
    componentDidMount: function () {
        this.props.terminal.on('invocation', this.forceUpdate.bind(this));
    },
    handleKeyDown: function (event) {
        // Ctrl+l
        if (event.ctrlKey && event.keyCode === 76) {
            this.props.terminal.clearInvocations();
            event.stopPropagation();
        }
    },
    render: function () {
        var invocations = this.props.terminal.invocations.map(function (invocation) {
            return (
                <Invocation key={invocation.id} invocation={invocation}/>
            )
        });
        return (
            <div id="board" onKeyDown={this.handleKeyDown}>
                <div id="invocations">
                    {invocations}
                </div>
                <StatusLine currentWorkingDirectory={this.props.terminal.currentDirectory}/>
            </div>
        );
    }
});

var Invocation = React.createClass({
    componentDidMount: function () {
        this.props.invocation.on('data', function () {
            this.setState({ canBeDecorated: this.props.invocation.canBeDecorated()});
        }.bind(this));
    },
    componentDidUpdate: scrollToBottom,

    getInitialState: function() {
        return {
            decorate: true,
            canBeDecorated: this.props.invocation.canBeDecorated()
        };
    },
    render: function () {
        var buffer, decorationToggle;

        if (this.state.decorate && this.state.canBeDecorated) {
            buffer = this.props.invocation.decorate();
        } else {
            buffer = this.props.invocation.getBuffer().render();
        }

        if (this.props.invocation.canBeDecorated()) {
            decorationToggle = <DecorationToggle invocation={this}/>;
        }

        return (
            <div className="invocation">
                <Prompt prompt={this.props.invocation.getPrompt()} status={this.props.invocation.status}/>
                {decorationToggle}
                {buffer}
            </div>
        );
    }
});

var DecorationToggle = React.createClass({
    getInitialState: function() {
        return {enabled: this.props.invocation.state.decorate};
    },
    handleClick: function() {
        var newState = !this.state.enabled;
        this.setState({enabled: newState});
        this.props.invocation.setState({decorate: newState});
    },
    render: function () {
        var classes = ['decoration-toggle'];

        if (!this.state.enabled) {
            classes.push('disabled');
        }

        return (
            <a href="#" className={classes.join(' ')} onClick={this.handleClick}>
                <i className="fa fa-magic"></i>
            </a>
        );
    }
});

var Prompt = React.createClass({
    getInputNode: function () {
        return this.refs.command.getDOMNode()
    },
    getValue: function () {
        return this.getInputNode().innerText;
    },
    componentDidMount: function () {
        this.getInputNode().focus();
    },
    handleKeyUp: function (event) {
        this.props.prompt.buffer.setTo(this.getValue());
    },
    handleKeyDown: function (event) {
        if (event.keyCode == 13) {
            this.props.prompt.send(this.getValue());

            event.stopPropagation();
            return false;
        }

        // Ctrl+P, ↑.
        if ((event.ctrlKey && event.keyCode === 80) || event.keyCode === 38) {
            var prevCommand = this.props.prompt.history.getPrevious();
            if (typeof prevCommand != 'undefined') {
                this.getInputNode().innerText = prevCommand;
            }

            event.stopPropagation();
            return false;
        }

        // Ctrl+N, ↓.
        if ((event.ctrlKey && event.keyCode === 78) || event.keyCode === 40) {
            var command = this.props.prompt.history.getNext();
            this.getInputNode().innerText = command || '';

            event.stopPropagation();
            return false;
        }
    },
    handleInput: function (event) {
        var el = event.target;

        if (el.childNodes.length) {
            var sel = window.getSelection();
            var offset = sel.baseOffset;
            var range = document.createRange();

            // Do syntax highlighting.
            //el.innerHTML = el.innerHTML.toUpperCase();

            range.setStart(el.childNodes[0], offset);
            range.collapse(true);
            sel.removeAllRanges();
            sel.addRange(range);
        }
    },
    render: function () {
        var classes = ['prompt', this.props.status].join(' ');

        return (
            <div className="prompt-wrapper">
                <div className="prompt-decoration">
                    <div className="arrow"/>
                </div>
                <div className={classes}
                     onKeyDown={this.handleKeyDown}
                     onKeyUp={this.handleKeyUp}
                     onInput={this.handleInput}
                     type="text"
                     ref="command"
                     contentEditable="true" />
{'fraction_non_alphanumeric': 0.1396948003014318, 'fraction_numerical': 0.002354935945742276, 'mean_word_length': 1.8984438984438985, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6394819', 'n_tokens_mistral': 2975, 'n_tokens_neox': 2816, 'n_words': 481}