<commit_before>import _ = require('underscore');
import AppErrorHandler = require('./lib/app-error-handler');
import BufferView = require('./buffer-view');
import Channel = require('./lib/channel');
import configuration = require('./lib/configuration');
import InputBox = require('./input-box');
import ipc = require('./lib/ipc');
import Log = require('./lib/log');
import Name = require('./lib/name');
import NameView = require('./name-view');
import React = require('react');
import shortcut = require('./lib/shortcut-manager');
import TabNav = require('./tab-nav');
import TopicView = require('./topic-view');
import TypedReact = require('typed-react');

const D = React.DOM;

const rootChannelName = configuration.get('app', 'root-channel-name');
const commandSymbol = configuration.get('app', 'command-symbol');

interface IrcViewProps {
  errorHandler: AppErrorHandler;
}

interface IrcViewState {
  nick: string;
  channels: Channel[];
}

class IrcView extends TypedReact.Component<IrcViewProps, IrcViewState> {
  getInitialState(): IrcViewState {
    return {
      nick: '',
      channels: [new Channel(rootChannelName, true)],
    };
  }

  setNick(nick: string) {
    this.setState(<IrcViewState>{nick});
    Log.setCurrentNick(nick);
  }

  componentDidMount() {
    // irc events
    ipc.on('registered', data => this.setNick(data.nick));
    ipc.on('message', this.onMessage);
    ipc.on('join', this.onJoin);
    ipc.on('part', this.onPart);
    ipc.on('nick', this.onChangeNick);
    ipc.on('names', this.onNames);
    ipc.on('+mode', this.onMode.bind(this, true));
    ipc.on('-mode', this.onMode.bind(this, false));
    ipc.on('quit', this.onQuit);
    ipc.on('whois', this.onWhois);
    ipc.on('kick', this.onKick);
    ipc.on('topic', this.onTopic);

    // shortcuts
    shortcut.Manager.on('next-tab', () => {
      let next = Channel.next(this.state.channels);
      this.state.channels = Channel.setCurrent(this.state.channels, next.name);
      this.forceUpdate();
    });
    shortcut.Manager.on('previous-tab', () => {
      let prev = Channel.previous(this.state.channels);
      this.state.channels = Channel.setCurrent(this.state.channels, prev.name);
      this.forceUpdate();
    });

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

  render() {
    let channel = Channel.current(this.state.channels);
    let names = channel.names;
    let topic = channel.topic;

    let className = topic ? 'with-topic' : '';

    return (
      D.div({id: 'irc-view', className},
        TabNav({channels: this.state.channels}),
        TopicView({topic}),
        NameView({names}),
        BufferView({channels: this.state.channels}),
        InputBox({channel: Channel.current(this.state.channels).name,
                  names,
                  submit: this.submitInput})
      )
    );
  }

  submitInput(raw: string) {
    let current = Channel.current(this.state.channels);
    if (raw.startsWith(commandSymbol)) {
      raw = raw.substring(1);
      let methodName = this.tryGetLocalHandler(raw);
      if (methodName) {
        this[methodName](raw);
      } else {
        ipc.send('command', {raw, context: {target: current.name}});
      }
    } else {
      if (current.name !== rootChannelName) {
        ipc.send('message', {raw, context: {target: current.name}});
        current.send(this.state.nick, raw);
        this.forceUpdate();
      }
    }
  }

  tryGetLocalHandler(raw: string): string {
    let tokens = raw.split(' ');
    if (tokens.length === 1 && tokens[0] === 'part' &&
        !Channel.current(this.state.channels).name.startsWith('#')) {
      return 'partPersonalChat';
    } else if (tokens[0] === 'pm') {
      return 'startPersonalChat';
    } else if (tokens.length === 1 && tokens[0] === 'topic') {
      return 'showTopic';
    }
  }

  onMessage(data) {
    let to = data.to[0] === '#' || data.to === rootChannelName ? data.to : data.nick;
    Channel.get(this.state.channels, to).send(data.nick, data.text);
    this.forceUpdate();
  }

  onJoin(data) {
    let isMe = data.nick === this.state.nick;
    let channel;
    if (isMe) {
      this.state.channels.push(new Channel(data.channel));
      this.state.channels = Channel.setCurrent(this.state.channels, data.channel);
      channel = Channel.get(this.state.channels, data.channel);
    } else {
      channel = Channel.get(this.state.channels, data.channel);
      channel.addName(data.nick);
    }
    channel.join(data.nick, data.message);
    this.forceUpdate();
  }

  onPart(data) {
    let isMe = data.nick === this.state.nick;
    if (isMe && data.channel !== rootChannelName) {
      this.state.channels = Channel.remove(this.state.channels, data.channel);
      this.state.channels = Channel.setCurrent(this.state.channels, rootChannelName);
    } else {
      let channel = Channel.get(this.state.channels, data.channel);
      channel.part(data.nick, data.reason, data.message);
      channel.removeName(data.nick);
    }
    this.forceUpdate();
  }

  startPersonalChat(raw: string) {
    let tokens = raw.split(' ');
    if (tokens.length < 3) {
      this.props.errorHandler.handle({
        type: 'normal',
        error: new Error('Invalid command arguments: [nick,message]'),
      });
    } else {
      let target = tokens[1];
      let raw = tokens.splice(2).join(' ');
      ipc.send('message', {raw, context: {target}});
      let channel = Channel.get(this.state.channels, target);
      if (!channel) {
        channel = new Channel(target);
        this.state.channels.push(channel);
      }
      channel.send(this.state.nick, raw);
      this.state.channels = Channel.setCurrent(this.state.channels, target);
      this.forceUpdate();
    }
  }
<commit_msg>Change personal message command from `pm` to `msg`.<commit_after>import _ = require('underscore');
import AppErrorHandler = require('./lib/app-error-handler');
import BufferView = require('./buffer-view');
import Channel = require('./lib/channel');
import configuration = require('./lib/configuration');
import InputBox = require('./input-box');
import ipc = require('./lib/ipc');
import Log = require('./lib/log');
import Name = require('./lib/name');
import NameView = require('./name-view');
import React = require('react');
import shortcut = require('./lib/shortcut-manager');
import TabNav = require('./tab-nav');
import TopicView = require('./topic-view');
import TypedReact = require('typed-react');

const D = React.DOM;

const rootChannelName = configuration.get('app', 'root-channel-name');
const commandSymbol = configuration.get('app', 'command-symbol');

interface IrcViewProps {
  errorHandler: AppErrorHandler;
}

interface IrcViewState {
  nick: string;
  channels: Channel[];
}

class IrcView extends TypedReact.Component<IrcViewProps, IrcViewState> {
  getInitialState(): IrcViewState {
    return {
      nick: '',
      channels: [new Channel(rootChannelName, true)],
    };
  }

  setNick(nick: string) {
    this.setState(<IrcViewState>{nick});
    Log.setCurrentNick(nick);
  }

  componentDidMount() {
    // irc events
    ipc.on('registered', data => this.setNick(data.nick));
    ipc.on('message', this.onMessage);
    ipc.on('join', this.onJoin);
    ipc.on('part', this.onPart);
    ipc.on('nick', this.onChangeNick);
    ipc.on('names', this.onNames);
    ipc.on('+mode', this.onMode.bind(this, true));
    ipc.on('-mode', this.onMode.bind(this, false));
    ipc.on('quit', this.onQuit);
    ipc.on('whois', this.onWhois);
    ipc.on('kick', this.onKick);
    ipc.on('topic', this.onTopic);

    // shortcuts
    shortcut.Manager.on('next-tab', () => {
      let next = Channel.next(this.state.channels);
      this.state.channels = Channel.setCurrent(this.state.channels, next.name);
      this.forceUpdate();
    });
    shortcut.Manager.on('previous-tab', () => {
      let prev = Channel.previous(this.state.channels);
      this.state.channels = Channel.setCurrent(this.state.channels, prev.name);
      this.forceUpdate();
    });

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

  render() {
    let channel = Channel.current(this.state.channels);
    let names = channel.names;
    let topic = channel.topic;

    let className = topic ? 'with-topic' : '';

    return (
      D.div({id: 'irc-view', className},
        TabNav({channels: this.state.channels}),
        TopicView({topic}),
        NameView({names}),
        BufferView({channels: this.state.channels}),
        InputBox({channel: Channel.current(this.state.channels).name,
                  names,
                  submit: this.submitInput})
      )
    );
  }

  submitInput(raw: string) {
    let current = Channel.current(this.state.channels);
    if (raw.startsWith(commandSymbol)) {
      raw = raw.substring(1);
      if (!this.tryHandleLocally(raw)) {
        ipc.send('command', {raw, context: {target: current.name}});
      }
    } else {
      if (current.name !== rootChannelName) {
        ipc.send('message', {raw, context: {target: current.name}});
        current.send(this.state.nick, raw);
        this.forceUpdate();
      }
    }
  }

  tryHandleLocally(raw: string): boolean {
    let tokens = raw.split(' ');
    if (tokens.length === 1 && tokens[0] === 'part' &&
        !Channel.current(this.state.channels).name.startsWith('#')) {
      this.partPersonalChat();
      return true;
    } else if (tokens[0] === 'msg') {
      this.startPersonalChat(tokens[1], tokens.splice(2).join(' '));
      return true;
    } else if (tokens.length === 1 && tokens[0] === 'topic') {
      this.showTopic();
      return true;
    }
    return false;
  }

  onMessage(data) {
    let to = data.to[0] === '#' || data.to === rootChannelName ? data.to : data.nick;
    Channel.get(this.state.channels, to).send(data.nick, data.text);
    this.forceUpdate();
  }

  onJoin(data) {
    let isMe = data.nick === this.state.nick;
    let channel;
    if (isMe) {
      this.state.channels.push(new Channel(data.channel));
      this.state.channels = Channel.setCurrent(this.state.channels, data.channel);
      channel = Channel.get(this.state.channels, data.channel);
    } else {
      channel = Channel.get(this.state.channels, data.channel);
      channel.addName(data.nick);
    }
    channel.join(data.nick, data.message);
    this.forceUpdate();
  }

  onPart(data) {
    let isMe = data.nick === this.state.nick;
    if (isMe && data.channel !== rootChannelName) {
      this.state.channels = Channel.remove(this.state.channels, data.channel);
      this.state.channels = Channel.setCurrent(this.state.channels, rootChannelName);
    } else {
      let channel = Channel.get(this.state.channels, data.channel);
      channel.part(data.nick, data.reason, data.message);
      channel.removeName(data.nick);
    }
    this.forceUpdate();
  }

  startPersonalChat(target: string, raw: string) {
    if (!target || !raw) {
      this.props.errorHandler.handle({
        type: 'normal',
        error: new Error('Invalid command arguments: [nick,message]'),
      });
    } else {
      ipc.send('message', {raw, context: {target}});
      let channel = Channel.get(this.state.channels, target);
      if (!channel) {
        channel = new Channel(target);
        this.state.channels.push(channel);
      }
      channel.send(this.state.nick, raw);
      this.state.channels = Channel.setCurrent(this.state.channels, target);
      this.forceUpdate();
    }
  }

{'fraction_non_alphanumeric': 0.1698096658187878, 'fraction_numerical': 0.0016665204806595912, 'mean_word_length': 3.085274095306342, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 13, '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': '5176284', 'n_tokens_mistral': 3614, 'n_tokens_neox': 3554, 'n_words': 655}