Skip to content
This repository has been archived by the owner on Apr 1, 2020. It is now read-only.

Commit

Permalink
Fix for #2414 - truncated copy/paste (#2515)
Browse files Browse the repository at this point in the history
This is a fix for some of the issues raised in #2414. One thing to note - there was some question as to whether win32yank works for everyone. I did find a possible workaround for that, if it's still an issue:

```
const textToPaste = clipboard.readText()
const sanitizedTextLines = replaceAll(textToPaste, { "'": "''" })
await neovimInstance.command("let @+='" + sanitizedTextLines + "'")
```

I don't have a windows box to test this on, so perhaps we can add this code to `NeovimEditorCommands. pasteContents` later if needed.
  • Loading branch information
psxpaul authored and akinsho committed Aug 27, 2018
1 parent e3f65e6 commit e482ae8
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 10 deletions.
30 changes: 23 additions & 7 deletions browser/src/Editor/NeovimEditor/NeovimEditorCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import * as Oni from "oni-api"
import { NeovimInstance } from "./../../neovim"
import { CallbackCommand, CommandManager } from "./../../Services/CommandManager"
import { ContextMenuManager } from "./../../Services/ContextMenu"
import { editorManager } from "./../../Services/EditorManager"
import { findAllReferences, format, LanguageEditorIntegration } from "./../../Services/Language"
import { replaceAll } from "./../../Utility"

Expand Down Expand Up @@ -67,13 +68,22 @@ export class NeovimEditorCommands {

const pasteContents = async (neovimInstance: NeovimInstance) => {
const textToPaste = clipboard.readText()
const sanitizedText = replaceAll(textToPaste, { "<": "<lt>" })
.split(os.EOL)
.join("<cr>")
const replacements = { "'": "''" }
replacements[os.EOL] = "\n"
const sanitizedTextLines = replaceAll(textToPaste, replacements)
await neovimInstance.command('let b:oniclipboard=@"')
await neovimInstance.command(`let @"='${sanitizedTextLines}'`)

if (editorManager.activeEditor.mode === "insert") {
await neovimInstance.command("set paste")
await neovimInstance.input('<c-r>"')
await neovimInstance.command("set nopaste")
} else {
await neovimInstance.command("normal! p")
}

await neovimInstance.command("set paste")
await neovimInstance.input(sanitizedText)
await neovimInstance.command("set nopaste")
await neovimInstance.command('let @"=b:oniclipboard')
await neovimInstance.command("unlet b:oniclipboard")
}

const commands = [
Expand Down Expand Up @@ -116,7 +126,13 @@ export class NeovimEditorCommands {
"editor.clipboard.yank",
"Clipboard: Yank",
"Yank contents to clipboard",
() => this._neovimInstance.input("y"),
() => this._neovimInstance.command('normal! "+y'),
),
new CallbackCommand(
"editor.clipboard.cut",
"Clipboard: Cut",
"Cut contents to clipboard",
() => this._neovimInstance.command('normal! "+x'),
),
new CallbackCommand("oni.editor.findAllReferences", null, null, () =>
findAllReferences(),
Expand Down
6 changes: 3 additions & 3 deletions main/src/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,19 +288,19 @@ export const buildMenu = (mainWindow, loadInit) => {
{
label: "Copy",
click(item, focusedWindow) {
executeVimCommand(focusedWindow, '\\"+y')
executeOniCommand(focusedWindow, "editor.clipboard.yank")
},
},
{
label: "Cut",
click(item, focusedWindow) {
executeVimCommand(focusedWindow, '\\"+x')
executeOniCommand(focusedWindow, "editor.clipboard.cut")
},
},
{
label: "Paste",
click(item, focusedWindow) {
executeVimCommand(focusedWindow, '\\"+gP')
executeOniCommand(focusedWindow, "editor.clipboard.paste")
},
},
{
Expand Down
1 change: 1 addition & 0 deletions test/CiTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const CiTests = [
"Neovim.CallOniCommands",
"NoInstalledNeovim",
"Sidebar.ToggleSplitTest",
"LargePasteTest",

"Snippets.BasicInsertTest",

Expand Down
97 changes: 97 additions & 0 deletions test/ci/LargePasteTest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/**
* Test for pasting a large number of lines
*
* Regression test for #2414
*/
import * as assert from "assert"
import * as Oni from "oni-api"

import { createNewFile, getTemporaryFilePath, navigateToFile } from "./Common"

export const test = async (oni: Oni.Plugin.Api) => {
const filePath = createLargeTestFile()
await oni.automation.waitForEditors()

// open file with 2000 lines
navigateToFile(filePath, oni)

// select everything
oni.automation.sendKeys("<s-v>")
await oni.automation.waitFor(() => oni.editors.activeEditor.mode === "visual")
oni.automation.sendKeys("G")
await oni.automation.waitFor(() => oni.editors.activeEditor.activeBuffer.cursor.line === 1999)

// copy and paste should result in 4000 lines
await copy(oni)
oni.automation.sendKeys("o")
await oni.automation.waitFor(() => oni.editors.activeEditor.mode === "insert")
await paste(oni, () => oni.editors.activeEditor.activeBuffer.lineCount === 4001)
assert.strictEqual(oni.editors.activeEditor.activeBuffer.lineCount, 4001)

// go to first line, and copy first word ('this')
oni.automation.sendKeys("gg")
await oni.automation.waitFor(() => oni.editors.activeEditor.activeBuffer.cursor.line === 0)
oni.automation.sendKeys("v")
await oni.automation.waitFor(() => oni.editors.activeEditor.mode === "visual")
oni.automation.sendKeys("e")
await oni.automation.waitFor(() => oni.editors.activeEditor.activeBuffer.cursor.column === 3)
await copy(oni)

// paste in the middle of the first word
oni.automation.sendKeys("3l")
await oni.automation.waitFor(() => oni.editors.activeEditor.activeBuffer.cursor.column === 3)
oni.automation.sendKeys("i")
await oni.automation.waitFor(() => oni.editors.activeEditor.mode === "insert")
await paste(oni, () => oni.editors.activeEditor.activeBuffer.cursor.column === 7)

const [firstLine] = await oni.editors.activeEditor.activeBuffer.getLines(0, 1)
assert.strictEqual(
firstLine,
"thithiss is a line of 'text' that will be repeated a bunch of times to make for a large wall of 'text' to paste",
)
}

import * as fs from "fs"
import * as os from "os"

const createLargeTestFile = (): string => {
const filePath = getTemporaryFilePath("js")
const line =
"this is a line of 'text' that will be repeated a bunch of times to make for a large wall of 'text' to paste"

const lines = []
for (let i = 0; i < 2000; i++) {
lines.push(line)
}

fs.writeFileSync(filePath, lines.join(os.EOL))
return filePath
}

import { isMac } from "../../browser/src/Platform"

const copy = async (oni: Oni.Plugin.Api) => {
if (isMac()) {
oni.automation.sendKeys("<m-c>")
} else {
oni.automation.sendKeys("<c-c>")
}

await oni.automation.waitFor(() => oni.editors.activeEditor.mode === "normal")
}

const paste = async (
oni: Oni.Plugin.Api,
waitConditionChecker: Oni.Automation.WaitConditionChecker,
) => {
if (isMac()) {
oni.automation.sendKeys("<m-v>")
} else {
oni.automation.sendKeys("<c-v>")
}

await oni.automation.waitFor(waitConditionChecker)

oni.automation.sendKeys("<esc>")
await oni.automation.waitFor(() => oni.editors.activeEditor.mode === "normal")
}

0 comments on commit e482ae8

Please sign in to comment.