<commit_before>/* tslint:disable:react-this-binding-issue */

import * as React from 'react'
import { List } from '../list'
import { Dispatcher } from '../../lib/dispatcher'
import { Repository } from '../../models/repository'
import { Branch } from '../../lib/local-git-operations'
import { groupedAndFilteredBranches, BranchListItemModel } from './grouped-and-filtered-branches'
import { BranchListItem } from './branch'

const RowHeight = 30

interface IBranchesProps {
  readonly defaultBranch: Branch | null
  readonly currentBranch: Branch | null
  readonly allBranches: ReadonlyArray<Branch>
  readonly recentBranches: ReadonlyArray<Branch>
  readonly dispatcher: Dispatcher
  readonly repository: Repository
}

interface IBranchesState {
  readonly filter: string
}

export class Branches extends React.Component<IBranchesProps, IBranchesState> {
  private list: List | null = null
  private scrollToRow = -1
  private selectedRow = -1

  public constructor(props: IBranchesProps) {
    super(props)

    this.state = { filter: '' }
  }

  private renderRow(branchItems: ReadonlyArray<BranchListItemModel>, row: number) {
    const item = branchItems[row]
    if (item.kind === 'branch') {
      const branch = item.branch
      const commit = branch.tip
      const currentBranchName = this.props.currentBranch ? this.props.currentBranch.name : null
      return <BranchListItem
        name={branch.name}
        isCurrentBranch={branch.name === currentBranchName}
        lastCommitDate={commit ? commit.authorDate : null}/>
    } else {
      return <div className='branches-list-content branches-list-label'>{item.label}</div>
    }
  }

  private onRowSelected(branchItems: ReadonlyArray<BranchListItemModel>, row: number) {
    const item = branchItems[row]
    if (item.kind !== 'branch') { return }

    const branch = item.branch
    this.props.dispatcher.closePopup()
    this.props.dispatcher.checkoutBranch(this.props.repository, branch.nameWithoutRemote)
  }

  private canSelectRow(branchItems: ReadonlyArray<BranchListItemModel>, row: number) {
    const item = branchItems[row]
    return item.kind === 'branch'
  }

  private onFilterChanged(event: React.FormEvent<HTMLInputElement>) {
    const text = event.currentTarget.value
    this.setState({ filter: text })
  }

  private onKeyDown(branchItems: ReadonlyArray<BranchListItemModel>, event: React.KeyboardEvent<HTMLInputElement>) {
    const list = this.list
    if (!list) { return }

    let nextRow = this.selectedRow
    if (event.key === 'ArrowDown') {
      nextRow = list.nextSelectableRow('down', this.selectedRow)
    } else if (event.key === 'ArrowUp') {
      nextRow = list.nextSelectableRow('up', this.selectedRow)
    } else if (event.key === 'Enter') {
      this.onRowSelected(branchItems, this.selectedRow)
    } else if (event.key === 'Escape') {
      if (this.state.filter.length === 0) {
        this.props.dispatcher.closePopup()
        return
      }
    } else {
      return
    }

    this.scrollToRow = nextRow
    this.selectedRow = nextRow
    this.forceUpdate()
  }

  public render() {
    const scrollToRow = this.scrollToRow
    this.scrollToRow = -1

    const branchItems = groupedAndFilteredBranches(this.props.defaultBranch, this.props.currentBranch, this.props.allBranches, this.props.recentBranches, this.state.filter)
    let selectedRow = this.selectedRow
    if (selectedRow < 0 || selectedRow >= branchItems.length) {
      selectedRow = branchItems.findIndex(item => item.kind === 'branch')
    }

    this.selectedRow = selectedRow

    return (
      <div id='branches'>
        <input className='branch-filter-input'
               type='search'
               autoFocus={true}
               placeholder='Filter'
               onChange={event => this.onFilterChanged(event)}
               onKeyDown={event => this.onKeyDown(branchItems, event)}/>

        <div className='branches-list-container'>
          <List rowCount={branchItems.length}
                rowRenderer={row => this.renderRow(branchItems, row)}
                rowHeight={RowHeight}
                selectedRow={selectedRow}
                onRowSelected={row => this.onRowSelected(branchItems, row)}
                canSelectRow={row => this.canSelectRow(branchItems, row)}
                scrollToRow={scrollToRow}
                ref={ref => this.list = ref}
                invalidationProps={this.props}/>
        </div>
      </div>
    )
  }
}
<commit_msg>Bind event handlers in branch foldout<commit_after>import * as React from 'react'
import { List } from '../list'
import { Dispatcher } from '../../lib/dispatcher'
import { Repository } from '../../models/repository'
import { Branch } from '../../lib/local-git-operations'
import { groupedAndFilteredBranches, BranchListItemModel } from './grouped-and-filtered-branches'
import { BranchListItem } from './branch'

const RowHeight = 30

interface IBranchesProps {
  readonly defaultBranch: Branch | null
  readonly currentBranch: Branch | null
  readonly allBranches: ReadonlyArray<Branch>
  readonly recentBranches: ReadonlyArray<Branch>
  readonly dispatcher: Dispatcher
  readonly repository: Repository
}

interface IBranchesState {
  readonly filter: string
  readonly branchItems: ReadonlyArray<BranchListItemModel>
  readonly selectedRow: number
}

export class Branches extends React.Component<IBranchesProps, IBranchesState> {
  private list: List | null = null
  private scrollToRow = -1

  public constructor(props: IBranchesProps) {
    super(props)

    this.state = this.createState(props, '', -1)
  }

  private createState(props: IBranchesProps, newFilter: string, newSelectedRow: number): IBranchesState {
    const branchItems = groupedAndFilteredBranches(
      this.props.defaultBranch,
      this.props.currentBranch,
      this.props.allBranches,
      this.props.recentBranches,
      newFilter
    )

    const selectedRow = newSelectedRow < 0 || newSelectedRow >= branchItems.length
      ? branchItems.findIndex(item => item.kind === 'branch')
      : newSelectedRow

    const filter = newFilter

    return { filter, selectedRow, branchItems }
  }

  private receiveProps(nextProps: IBranchesProps) {
    this.setState(this.createState(nextProps, this.state.filter, this.state.selectedRow))
  }

  public componentWillReceiveProps(nextProps: IBranchesProps) {
    this.receiveProps(nextProps)
  }

  private renderRow = (row: number) => {
    const item = this.state.branchItems[row]
    if (item.kind === 'branch') {
      const branch = item.branch
      const commit = branch.tip
      const currentBranchName = this.props.currentBranch ? this.props.currentBranch.name : null
      return <BranchListItem
        name={branch.name}
        isCurrentBranch={branch.name === currentBranchName}
        lastCommitDate={commit ? commit.authorDate : null}/>
    } else {
      return <div className='branches-list-content branches-list-label'>{item.label}</div>
    }
  }

  private onRowSelected = (row: number) => {
    const item = this.state.branchItems[row]
    if (item.kind !== 'branch') { return }

    const branch = item.branch
    this.props.dispatcher.closePopup()
    this.props.dispatcher.checkoutBranch(this.props.repository, branch.nameWithoutRemote)
  }

  private canSelectRow = (row: number) => {
    const item = this.state.branchItems[row]
    return item.kind === 'branch'
  }

  private onFilterChanged = (event: React.FormEvent<HTMLInputElement>) => {
    const text = event.currentTarget.value
    this.setState(this.createState(this.props, text, this.state.selectedRow))
  }

  private onKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
    const list = this.list
    if (!list) { return }

    let nextRow = this.state.selectedRow
    if (event.key === 'ArrowDown') {
      nextRow = list.nextSelectableRow('down', this.state.selectedRow)
      event.preventDefault()
    } else if (event.key === 'ArrowUp') {
      nextRow = list.nextSelectableRow('up', this.state.selectedRow)
      event.preventDefault()
    } else if (event.key === 'Enter') {
      this.onRowSelected(this.state.selectedRow)
      event.preventDefault()
    } else if (event.key === 'Escape') {
      if (this.state.filter.length === 0) {
        this.props.dispatcher.closePopup()
        event.preventDefault()
        return
      }
    } else {
      return
    }

    this.scrollToRow = nextRow
    this.setState(this.createState(this.props, this.state.filter, nextRow))
  }

  private storeListRef = (ref: List) => {
    this.list = ref
  }

  public render() {
    const scrollToRow = this.scrollToRow
    this.scrollToRow = -1

    return (
      <div id='branches'>
        <input className='branch-filter-input'
               type='search'
               autoFocus={true}
               placeholder='Filter'
               onChange={this.onFilterChanged}
               onKeyDown={this.onKeyDown}/>

        <div className='branches-list-container'>
          <List rowCount={this.state.branchItems.length}
                rowRenderer={this.renderRow}
                rowHeight={RowHeight}
                selectedRow={this.state.selectedRow}
                onRowSelected={this.onRowSelected}
                canSelectRow={this.canSelectRow}
                scrollToRow={scrollToRow}
                ref={this.storeListRef}
                invalidationProps={this.props}/>
        </div>
      </div>
    )
  }
}

{'fraction_non_alphanumeric': 0.11692307692307692, 'fraction_numerical': 0.0014854111405835544, 'mean_word_length': 3.042024013722127, 'pattern_counts': {'":': 0, '<': 38, '<?xml version=': 0, '>': 52, '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': '6692403', 'n_tokens_mistral': 2730, 'n_tokens_neox': 2714, 'n_words': 564}