<commit_before>// Changes: https://github.com/mawww/kakoune/blob/master/doc/pages/keys.asciidoc#changes
import * as vscode from 'vscode'

import { registerCommand, Command, CommandFlags, CommandState, InputKind } from '.'

import { Extension }                                  from '../extension'
import { getSelectionFromEnd, getSelectionFromStart } from '../utils/textInDocument'


function getRegister(state: CommandState<any>, ctx: Extension) {
  return state.currentRegister || ctx.registers.dquote
}

registerCommand(Command.deleteYank, CommandFlags.Edit, async (editor, state, _, ctx) => {
  const reg = getRegister(state, ctx)

  if (reg.canWrite())
    await reg.set(editor, editor.selections.map(x => editor.document.getText(x)))

  return (builder: vscode.TextEditorEdit) => {
    for (const selection of editor.selections)
      builder.delete(selection)
  }
})

registerCommand(Command.deleteInsertYank, CommandFlags.Edit | CommandFlags.SwitchToInsert, async (editor, state, _, ctx) => {
  const reg = getRegister(state, ctx)

  if (reg.canWrite())
    await reg.set(editor, editor.selections.map(x => editor.document.getText(x)))

  return (builder: vscode.TextEditorEdit) => {
    for (const selection of editor.selections)
      builder.delete(selection)
  }
})

registerCommand(Command.deleteNoYank, CommandFlags.Edit, editor => builder => {
  for (const selection of editor.selections)
    builder.delete(selection)
})

registerCommand(Command.deleteInsertNoYank, CommandFlags.Edit | CommandFlags.SwitchToInsert, editor => builder => {
  for (const selection of editor.selections)
    builder.delete(selection)
})

registerCommand(Command.yank, CommandFlags.None, (editor, state, _, ctx) => {
  const reg = getRegister(state, ctx)

  if (reg.canWrite())
    return reg.set(editor, editor.selections.map(x => editor.document.getText(x)))

  return undefined
})


function getContentToPaste(editor: vscode.TextEditor, state: CommandState<any>, ctx: Extension) {
  return getRegister(state, ctx)
    .get(editor)
    .then(reg => reg !== undefined && reg[0] ? reg[0] : undefined)
}

registerCommand(Command.pasteAfter, CommandFlags.Edit, async (editor, state, _, ctx) => {
  const content = await getContentToPaste(editor, state, ctx)

  if (content === undefined)
    return undefined

  const shouldInsertInNewLine = content.endsWith('\n')

  if (shouldInsertInNewLine) {
    return (builder: vscode.TextEditorEdit) => {
      for (const selection of editor.selections)
        builder.insert(selection.end.with(selection.end.line + 1, 0), content)
    }
  } else {
    return (builder: vscode.TextEditorEdit) => {
      for (const selection of editor.selections)
        builder.insert(selection.end, content)
    }
  }
})

registerCommand(Command.pasteBefore, CommandFlags.Edit, async (editor, state, _, ctx) => {
  const content = await getContentToPaste(editor, state, ctx)

  if (content === undefined)
    return

  const shouldInsertInNewLine = content.endsWith('\n')

  if (shouldInsertInNewLine) {
    return (builder: vscode.TextEditorEdit) => {
      for (const selection of editor.selections)
        builder.insert(selection.start.with(undefined, 0), content)
    }
  } else {
    return (builder: vscode.TextEditorEdit) => {
      for (const selection of editor.selections)
        builder.insert(selection.start, content)
    }
  }
})

registerCommand(Command.pasteSelectAfter, CommandFlags.ChangeSelections | CommandFlags.Edit, async (editor, state, undoStops, ctx) => {
  const content = await getContentToPaste(editor, state, ctx)

  if (content === undefined)
    return

  const shouldInsertInNewLine = content.endsWith('\n')
  const newSelections = [] as vscode.Selection[]

  if (shouldInsertInNewLine) {
    await editor.edit(builder => {
      for (const selection of editor.selections) {
        builder.insert(selection.end.with(selection.end.line + 1, 0), content)
        newSelections.push(getSelectionFromStart(editor.document, content, selection.end.with(selection.end.line + 1, 0)))
      }
    }, undoStops)
  } else {
    await editor.edit(builder => {
      for (const selection of editor.selections) {
        builder.insert(selection.end, content)
        newSelections.push(getSelectionFromStart(editor.document, content, selection.end))
      }
    }, undoStops)
  }

  editor.selections = newSelections
})

registerCommand(Command.pasteSelectBefore, CommandFlags.ChangeSelections | CommandFlags.Edit, async (editor, state, undoStops, ctx) => {
  const content = await getContentToPaste(editor, state, ctx)

  if (content === undefined)
    return

  const shouldInsertInNewLine = content.endsWith('\n')
  const newSelections = [] as vscode.Selection[]

  if (shouldInsertInNewLine) {
    await editor.edit(builder => {
      for (const selection of editor.selections) {
        builder.insert(selection.start.with(undefined, 0), content)
        newSelections.push(getSelectionFromStart(editor.document, content, selection.start.with(undefined, 0)))
      }
    }, undoStops)
  } else {
    await editor.edit(builder => {
      for (const selection of editor.selections) {
        builder.insert(selection.start, content)
        newSelections.push(getSelectionFromEnd(editor.document, content, selection.start))
      }
    }, undoStops)
  }

  editor.selections = newSelections
})

registerCommand(Command.pasteReplace, CommandFlags.Edit, async (editor, state, _, ctx) => {
  const content = await getContentToPaste(editor, state, ctx)

  if (content === undefined)
    return

  return (builder: vscode.TextEditorEdit) => {
    for (const selection of editor.selections)
      builder.replace(selection, content)
  }
})

registerCommand(Command.pasteReplaceEvery, CommandFlags.Edit, async (editor, state, _, ctx) => {
  const contents = await getRegister(state, ctx).get(editor)

  if (contents === undefined || contents.length !== editor.selections.length)
    return

  return (builder: vscode.TextEditorEdit) => {
    for (let i = 0; i < contents.length; i++)
      builder.replace(editor.selections[i], contents[i])
  }
})


registerCommand(Command.replaceCharacters, CommandFlags.Edit, InputKind.Key, undefined, async (editor, { currentCount, input: key }) => {
  const string = key.repeat(currentCount || 1)

  return (builder: vscode.TextEditorEdit) => {
    for (const selection of editor.selections) {
      let i = selection.start.line<commit_msg>Fix invalid multiple-selection paste behavior (fixes #47).<commit_after>// Changes: https://github.com/mawww/kakoune/blob/master/doc/pages/keys.asciidoc#changes
import * as vscode from 'vscode'

import { registerCommand, Command, CommandFlags, CommandState, InputKind } from '.'

import { Extension }                                  from '../extension'
import { getSelectionFromEnd, getSelectionFromStart } from '../utils/textInDocument'


function getRegister(state: CommandState<any>, ctx: Extension) {
  return state.currentRegister || ctx.registers.dquote
}

registerCommand(Command.deleteYank, CommandFlags.Edit, async (editor, state, _, ctx) => {
  const reg = getRegister(state, ctx)

  if (reg.canWrite())
    await reg.set(editor, editor.selections.map(x => editor.document.getText(x)))

  return (builder: vscode.TextEditorEdit) => {
    for (const selection of editor.selections)
      builder.delete(selection)
  }
})

registerCommand(Command.deleteInsertYank, CommandFlags.Edit | CommandFlags.SwitchToInsert, async (editor, state, _, ctx) => {
  const reg = getRegister(state, ctx)

  if (reg.canWrite())
    await reg.set(editor, editor.selections.map(x => editor.document.getText(x)))

  return (builder: vscode.TextEditorEdit) => {
    for (const selection of editor.selections)
      builder.delete(selection)
  }
})

registerCommand(Command.deleteNoYank, CommandFlags.Edit, editor => builder => {
  for (const selection of editor.selections)
    builder.delete(selection)
})

registerCommand(Command.deleteInsertNoYank, CommandFlags.Edit | CommandFlags.SwitchToInsert, editor => builder => {
  for (const selection of editor.selections)
    builder.delete(selection)
})

registerCommand(Command.yank, CommandFlags.None, (editor, state, _, ctx) => {
  const reg = getRegister(state, ctx)

  if (reg.canWrite())
    return reg.set(editor, editor.selections.map(x => editor.document.getText(x)))

  return undefined
})


async function getContentsToPaste(editor: vscode.TextEditor, state: CommandState<any>, ctx: Extension, amount: number) {
  const yanked = await getRegister(state, ctx).get(editor)

  if (yanked === undefined)
    return undefined

  const results = [] as string[],
        yankedLength = yanked.length

  let i = 0

  for (; i < amount && i < yankedLength; i++) {
    results.push(yanked[i])
  }

  for (; i < amount; i++) {
    results.push(yanked[yankedLength - 1])
  }

  return results
}

registerCommand(Command.pasteAfter, CommandFlags.Edit, async (editor, state, _, ctx) => {
  const contents = await getContentsToPaste(editor, state, ctx, editor.selections.length)

  if (contents === undefined)
    return undefined

  return (builder: vscode.TextEditorEdit) => {
    for (let i = 0; i < contents.length; i++) {
      const content = contents[i],
            selection = editor.selections[i]

      if (content.endsWith('\n'))
        builder.insert(selection.end.with(selection.end.line + 1, 0), content)
      else
        builder.insert(selection.end, content)
    }
  }
})

registerCommand(Command.pasteBefore, CommandFlags.Edit, async (editor, state, _, ctx) => {
  const contents = await getContentsToPaste(editor, state, ctx, editor.selections.length)

  if (contents === undefined)
    return

  return (builder: vscode.TextEditorEdit) => {
    for (let i = 0; i < contents.length; i++) {
      const content = contents[i],
            selection = editor.selections[i]

      if (content.endsWith('\n'))
        builder.insert(selection.start.with(undefined, 0), content)
      else
        builder.insert(selection.start, content)
    }
  }
})

registerCommand(Command.pasteSelectAfter, CommandFlags.ChangeSelections | CommandFlags.Edit, async (editor, state, undoStops, ctx) => {
  const contents = await getContentsToPaste(editor, state, ctx, editor.selections.length)

  if (contents === undefined)
    return

  const newSelections = [] as vscode.Selection[]

  await editor.edit(builder => {
    for (let i = 0; i < contents.length; i++) {
      const content = contents[i],
            selection = editor.selections[i]

      if (content.endsWith('\n')) {
        builder.insert(selection.end.with(selection.end.line + 1, 0), content)
        newSelections.push(getSelectionFromStart(editor.document, content, selection.end.with(selection.end.line + 1, 0)))
      } else {
        builder.insert(selection.end, content)
        newSelections.push(getSelectionFromStart(editor.document, content, selection.end))
      }
    }
  }, undoStops)

  editor.selections = newSelections
})

registerCommand(Command.pasteSelectBefore, CommandFlags.ChangeSelections | CommandFlags.Edit, async (editor, state, undoStops, ctx) => {
  const contents = await getContentsToPaste(editor, state, ctx, editor.selections.length)

  if (contents === undefined)
    return

  const newSelections = [] as vscode.Selection[]

  await editor.edit(builder => {
    for (let i = 0; i < contents.length; i++) {
      const content = contents[i],
            selection = editor.selections[i]

      if (content.endsWith('\n')) {
        builder.insert(selection.start.with(undefined, 0), content)
        newSelections.push(getSelectionFromStart(editor.document, content, selection.start.with(undefined, 0)))
      } else {
        builder.insert(selection.start, content)
        newSelections.push(getSelectionFromEnd(editor.document, content, selection.start))
      }
    }
  }, undoStops)

  editor.selections = newSelections
})

registerCommand(Command.pasteReplace, CommandFlags.Edit, async (editor, state, _, ctx) => {
  const contents = await getContentsToPaste(editor, state, ctx, editor.selections.length)

  if (contents === undefined)
    return

  return (builder: vscode.TextEditorEdit) => {
    for (let i = 0; i < contents.length; i++) {
      const content = contents[i],
            selection = editor.selections[i]

      builder.replace(selection, content)
    }
  }
})

registerCommand(Command.pasteReplaceEvery, CommandFlags.Edit, async (editor, state, _, ctx) => {
  const contents = await getRegister(state, ctx).get(editor)

  if (contents === undefined || contents.length !== editor.selections.length)
    return

  return (builder: vscode.TextEditorEdit) => {
    for (let i = 0; i < contents.length; i++)
      builder.replace(editor.selections[i], contents[i])
  }
})


registerCommand(Command.replaceCharacters, CommandFlags.Edit, InputKind.Key, undefined, async (editor, { currentCount, input: key }) => {
  const string = key.repeat(currentCount || 1)

  return (builder: vscode.TextEditorEdit) => {
    for (const selection of editor.selections) {
      let i = selection.start.line
{'fraction_non_alphanumeric': 0.12667432070417145, 'fraction_numerical': 0.0025258323765786454, 'mean_word_length': 3.884485981308411, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 64, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2451739', 'n_tokens_mistral': 3959, 'n_tokens_neox': 3838, 'n_words': 874}