<commit_before>import { WorkingDirectoryFileChange } from '../models/status'
import { DiffLineType, Diff } from '../models/diff'

function extractAdditionalText(hunkHeader: string): string {
  const additionalTextIndex = hunkHeader.lastIndexOf('@@')

  // guard against being sent only one instance of @@ in the text
  if (additionalTextIndex <= 0) {
    return ''
  }

  // return everything after the found '@@'
  return hunkHeader.substring(additionalTextIndex + 2)
}

function formatPatchHeader(
  from: string | null,
  to: string | null,
  beforeStart: number,
  beforeLength: number,
  afterStart: number,
  afterLength: number,
  afterText: string
): string {

  const fromText = from ? `a/${from}` : '/dev/null'
  const toText = to ? `b/${to}` : '/dev/null'

  return `--- ${fromText}\n+++ ${toText}\n@@ -${beforeStart},${beforeLength} +${afterStart},${afterLength} @@${afterText}\n`
}

export function createPatchForModifiedFile(file: WorkingDirectoryFileChange, diff: Diff): string {
  const selection = file.selection.selectedLines
  const selectedLinesArray = Array.from(selection)

  let globalLinesSkipped = 0

  let input = ''

  diff.sections.forEach(s => {

    let linesSkipped = 0
    let linesIncluded = 0
    let linesRemoved = 0
    let patchBody = ''

    const selectedLines = selectedLinesArray.filter(a => a[0] >= s.unifiedDiffStart && a[0] <= s.unifiedDiffEnd)

    // don't generate a patch if no lines are selected
    if (selectedLines.every(l => l[1] === false)) {
      globalLinesSkipped += selectedLines.length
      return
    }

    s.lines
      .forEach((line, index) => {
        if (line.type === DiffLineType.Hunk) {
          // ignore the header
          return
        }

        if (line.type === DiffLineType.Context) {
          patchBody += line.text + '\n'
          return
        }

        const absoluteIndex = s.unifiedDiffStart + index
        if (selection.get(absoluteIndex)) {
          patchBody += line.text + '\n'
          if (line.type === DiffLineType.Add) {
            linesIncluded += 1
          } else if (line.type === DiffLineType.Delete) {
            linesRemoved += 1
          }
        } else if (line.type === DiffLineType.Delete) {
          // need to generate the correct patch here
          patchBody += ' ' + line.text.substr(1, line.text.length - 1) + '\n'
          linesSkipped -= 1
          globalLinesSkipped -= 1
        } else {
          // ignore this line when creating the patch
          linesSkipped += 1
          // and for subsequent patches
          globalLinesSkipped += 1
        }
      })

    const header = s.lines[0]
    const additionalText = extractAdditionalText(header.text)
    const beforeStart = s.range.oldStartLine
    const beforeCount = s.range.oldLineCount
    const afterStart = s.range.newStartLine
    const afterCount = s.range.newLineCount + linesSkipped

    const patchHeader = formatPatchHeader(
      file.path,
      file.path,
      beforeStart,
      beforeCount,
      afterStart,
      afterCount,
      additionalText)

      input += patchHeader + patchBody
  })

  return input
}


export function createPatchForNewFile(file: WorkingDirectoryFileChange, diff: Diff): string {
  const selection = file.selection.selectedLines
  let input = ''

  diff.sections.map(s => {<commit_msg>Reintroduce the horrid NaN bug so that I can get on with my life<commit_after>import { WorkingDirectoryFileChange } from '../models/status'
import { DiffLineType, Diff } from '../models/diff'

function extractAdditionalText(hunkHeader: string): string {
  const additionalTextIndex = hunkHeader.lastIndexOf('@@')

  // guard against being sent only one instance of @@ in the text
  if (additionalTextIndex <= 0) {
    return ''
  }

  // return everything after the found '@@'
  return hunkHeader.substring(additionalTextIndex + 2)
}

function formatPatchHeader(
  from: string | null,
  to: string | null,
  beforeStart: number,
  beforeLength: number,
  afterStart: number,
  afterLength: number,
  afterText: string
): string {

  const fromText = from ? `a/${from}` : '/dev/null'
  const toText = to ? `b/${to}` : '/dev/null'

  return `--- ${fromText}\n+++ ${toText}\n@@ -${beforeStart},${beforeLength} +${afterStart},${afterLength} @@${afterText}\n`
}

export function createPatchForModifiedFile(file: WorkingDirectoryFileChange, diff: Diff): string {
  const selection = file.selection.selectedLines
  const selectedLinesArray = Array.from(selection)

  let globalLinesSkipped = 0

  let input = ''

  diff.sections.forEach(s => {

    let linesSkipped = 0
    let linesIncluded = 0
    let linesRemoved = 0
    let patchBody = ''

    const selectedLines = selectedLinesArray.filter(a => a[0] >= s.unifiedDiffStart && a[0] <= s.unifiedDiffEnd)

    // don't generate a patch if no lines are selected
    if (selectedLines.every(l => l[1] === false)) {
      globalLinesSkipped += selectedLines.length
      return
    }

    s.lines
      .forEach((line, index) => {
        if (line.type === DiffLineType.Hunk) {
          // ignore the header
          return
        }

        if (line.type === DiffLineType.Context) {
          patchBody += line.text + '\n'
          return
        }

        const absoluteIndex = s.unifiedDiffStart + index
        if (selection.get(absoluteIndex)) {
          patchBody += line.text + '\n'
          if (line.type === DiffLineType.Add) {
            linesIncluded += 1
          } else if (line.type === DiffLineType.Delete) {
            linesRemoved += 1
          }
        } else if (line.type === DiffLineType.Delete) {
          // need to generate the correct patch here
          patchBody += ' ' + line.text.substr(1, line.text.length - 1) + '\n'
          linesSkipped -= 1
          globalLinesSkipped -= 1
        } else {
          // ignore this line when creating the patch
          linesSkipped += 1
          // and for subsequent patches
          globalLinesSkipped += 1
        }
      })

    const header = s.lines[0]
    const additionalText = extractAdditionalText(header.text)
    const beforeStart = s.range.oldStartLine
    const beforeCount = s.range.oldLineCount
    const afterStart = s.range.newStartLine

    // TODO: HERE BE DRAGONS
    //
    // Due to a bug in the original implementation of the diff parser
    // all omitted line counts were treates as NaN and NaN plus NaN
    // is always NaN so up until the diff parser refactor afterCount
    // was always NaN. I'm making it so again so that we can get the
    // parser merged and then we can come back and refactor patch
    // formatter and I can go get started on dinner.
    //
    // niik 2016-09-28
    const afterCount = s.range.newLineCount === 1
      ? NaN
      : s.range.newLineCount + linesSkipped
    //const afterCount = s.range.newLineCount + linesSkipped

    const patchHeader = formatPatchHeader(
      file.path,
      file.path,
      beforeStart,
      beforeCount,
      afterStart,
      afterCount,
      additionalText)

      input += patchHeader + patchBody
  })

  return input
}


export function createPatchForNewFile(file: WorkingDirectoryFileChange, diff: Diff): string {
  const selection = file.selection.selectedLines
  let input = ''

  diff.sections.map(s => {
{'fraction_non_alphanumeric': 0.11166184772132727, 'fraction_numerical': 0.006195786864931847, 'mean_word_length': 2.564278704612365, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 15, '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': '2950161', 'n_tokens_mistral': 2146, 'n_tokens_neox': 2072, 'n_words': 589}