<commit_before>import _ from 'underscore';
import bridge from '../common/bridge';
import Buffers from './lib/buffers';
import BufferView from './buffer-view';
import InputBox from './input-box';
import ModeManager, {Mode} from './lib/mode-manager';
import Names from './lib/names';
import NameView from './name-view';
import shortcutManager from './lib/shortcut-manager';
import TabNav from './tab-nav';
import React from 'react';

const rootBufferName = '~';

export default class IrcWindow extends React.Component {
  constructor(props) {
    super(props);
    this.modeManager = new ModeManager(Mode.NORMAL);
    this.state = {
      nick: '',
      buffers: new Buffers(rootBufferName),
      mode: this.modeManager.current(),
      names: new Names(),
    };
  }

  setNick(nick) {
    this.setState({nick});
  }

  componentDidMount() {
    this.modeManager.onChange(function (to) {
      this.setState({mode: to});
    }.bind(this));

    // irc events
    bridge.on('registered', data => this.setNick(data.nick));
    bridge.on('message', this.message.bind(this));
    bridge.on('join', this.join.bind(this));
    bridge.on('part', this.part.bind(this));
    bridge.on('nick', this.changeNick.bind(this));
    bridge.on('names', this.updateNames.bind(this));
    bridge.on('quit', this.quit.bind(this));

    // window events
    bridge.on('focus', this.focusWindow.bind(this));

    // shortcuts
    shortcutManager.on('next-tab', function () {
      this.state.buffers.setCurrent(this.state.buffers.next().name);
      this.forceUpdate();
    }.bind(this));
    shortcutManager.on('previous-tab', function () {
      this.state.buffers.setCurrent(this.state.buffers.previous().name);
      this.forceUpdate();
    }.bind(this));

    this.props.errorHandler.on('irc', this.handleError.bind(this));
  }

  setWindowTitle(title) {
    let titleTag = document.getElementsByTagName('title')[0];
    titleTag.innerText = `koko - ${title}`;
  }

  render() {
    this.setWindowTitle(this.props.server);

    let currentBufferName = this.state.buffers.current().name;
    let currentNames = this.state.names.get(currentBufferName);

    return (
      <div id='irc-window'>
        <TabNav buffers={this.state.buffers} />
        <NameView names={currentNames} />
        <BufferView mode={this.state.mode} buffers={this.state.buffers} />
        <InputBox mode={this.state.mode} submit={this.submitInput.bind(this)}
                  blur={this.blurInput.bind(this)} />
      </div>
    );
  }

  submitInput(raw) {
    let target = this.state.buffers.current().name;

    let resetToNormal = true;
    switch (this.state.mode) {
    case Mode.COMMAND:
      let methodName = this.tryGetLocalHandler(raw);
      if (methodName) {
        this[methodName](raw);
      } else {
        bridge.send(Mode.toString(this.state.mode), {raw, context: {target}});
      }
      break;
    case Mode.MESSAGE:
      if (target !== rootBufferName) {
        bridge.send(Mode.toString(this.state.mode), {raw, context: {target}});
        this.state.buffers.send(target, this.state.nick, raw);
        this.forceUpdate();
        resetToNormal = false;
      }
      break;
    }

    if (resetToNormal) {
      this.modeManager.setMode(Mode.NORMAL);
    }
  }

  tryGetLocalHandler(raw) {
    let tokens = raw.split(' ');
    if (tokens.length === 1 && tokens[0] === 'part' &&
        this.state.buffers.current().name !== '#') {
      return 'partPersonalMessage';
    } else if (tokens[0] === 'pm') {
      return 'sendPersonalMessage';
    }
  }

  blurInput() {
    this.modeManager.setMode(Mode.NORMAL);
  }

  message(data) {
    let to = data.to[0] === '#' || data.to === rootBufferName ? data.to : data.nick;
    this.state.buffers.send(to, data.nick, data.text);
    this.forceUpdate();
  }

  join(data) {
    let isMe = data.nick === this.state.nick;
    if (isMe) {
      this.state.buffers.add(data.channel);
      this.state.buffers.setCurrent(data.channel);
    } else {
      this.state.names.add(data.channel, data.nick);
    }<commit_msg>Focus input when joining a channel.<commit_after>import _ from 'underscore';
import bridge from '../common/bridge';
import Buffers from './lib/buffers';
import BufferView from './buffer-view';
import InputBox from './input-box';
import ModeManager, {Mode} from './lib/mode-manager';
import Names from './lib/names';
import NameView from './name-view';
import shortcutManager from './lib/shortcut-manager';
import TabNav from './tab-nav';
import React from 'react';

const rootBufferName = '~';

export default class IrcWindow extends React.Component {
  constructor(props) {
    super(props);
    this.modeManager = new ModeManager(Mode.NORMAL);
    this.state = {
      nick: '',
      buffers: new Buffers(rootBufferName),
      mode: this.modeManager.current(),
      names: new Names(),
    };
  }

  setNick(nick) {
    this.setState({nick});
  }

  componentDidMount() {
    this.modeManager.onChange(function (to) {
      this.setState({mode: to});
    }.bind(this));

    // irc events
    bridge.on('registered', data => this.setNick(data.nick));
    bridge.on('message', this.message.bind(this));
    bridge.on('join', this.join.bind(this));
    bridge.on('part', this.part.bind(this));
    bridge.on('nick', this.changeNick.bind(this));
    bridge.on('names', this.updateNames.bind(this));
    bridge.on('quit', this.quit.bind(this));

    // window events
    bridge.on('focus', this.focusWindow.bind(this));

    // shortcuts
    shortcutManager.on('next-tab', function () {
      this.state.buffers.setCurrent(this.state.buffers.next().name);
      this.forceUpdate();
    }.bind(this));
    shortcutManager.on('previous-tab', function () {
      this.state.buffers.setCurrent(this.state.buffers.previous().name);
      this.forceUpdate();
    }.bind(this));

    this.props.errorHandler.on('irc', this.handleError.bind(this));
  }

  setWindowTitle(title) {
    let titleTag = document.getElementsByTagName('title')[0];
    titleTag.innerText = `koko - ${title}`;
  }

  render() {
    this.setWindowTitle(this.props.server);

    let currentBufferName = this.state.buffers.current().name;
    let currentNames = this.state.names.get(currentBufferName);

    return (
      <div id='irc-window'>
        <TabNav buffers={this.state.buffers} />
        <NameView names={currentNames} />
        <BufferView mode={this.state.mode} buffers={this.state.buffers} />
        <InputBox mode={this.state.mode} submit={this.submitInput.bind(this)}
                  blur={this.blurInput.bind(this)} />
      </div>
    );
  }

  submitInput(raw) {
    let target = this.state.buffers.current().name;

    let resetToNormal = true;
    switch (this.state.mode) {
    case Mode.COMMAND:
      let methodName = this.tryGetLocalHandler(raw);
      if (methodName) {
        this[methodName](raw);
      } else {
        bridge.send(Mode.toString(this.state.mode), {raw, context: {target}});
      }
      break;
    case Mode.MESSAGE:
      if (target !== rootBufferName) {
        bridge.send(Mode.toString(this.state.mode), {raw, context: {target}});
        this.state.buffers.send(target, this.state.nick, raw);
        this.forceUpdate();
        resetToNormal = false;
      }
      break;
    }

    if (resetToNormal) {
      this.modeManager.setMode(Mode.NORMAL);
    }
  }

  tryGetLocalHandler(raw) {
    let tokens = raw.split(' ');
    if (tokens.length === 1 && tokens[0] === 'part' &&
        this.state.buffers.current().name !== '#') {
      return 'partPersonalMessage';
    } else if (tokens[0] === 'pm') {
      return 'sendPersonalMessage';
    }
  }

  blurInput() {
    this.modeManager.setMode(Mode.NORMAL);
  }

  message(data) {
    let to = data.to[0] === '#' || data.to === rootBufferName ? data.to : data.nick;
    this.state.buffers.send(to, data.nick, data.text);
    this.forceUpdate();
  }

  join(data) {
    let isMe = data.nick === this.state.nick;
    if (isMe) {
      this.state.buffers.add(data.channel);
      this.state.buffers.setCurrent(data.channel);
      this.modeManager.setMode(Mode.MESSAGE);
    } else {
      this.state.names.add(data.channel, data.nick);
    }
{'fraction_non_alphanumeric': 0.1672384219554031, 'fraction_numerical': 0.0012251899044351876, 'mean_word_length': 2.9838945827232797, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 17, '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': '6054094', 'n_tokens_mistral': 2654, 'n_tokens_neox': 2596, 'n_words': 456}