diff --git a/src/main/java/eu/mihosoft/monacofx/ClipboardBridge.java b/src/main/java/eu/mihosoft/monacofx/ClipboardBridge.java index 1c1b424..47e73e7 100644 --- a/src/main/java/eu/mihosoft/monacofx/ClipboardBridge.java +++ b/src/main/java/eu/mihosoft/monacofx/ClipboardBridge.java @@ -29,7 +29,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; /** * Bridge between javascript code and java to add and use system clipboard functionality. @@ -85,14 +85,47 @@ public void copy(JSObject jsSelection) { public JSObject paste(JSObject jsSelection, JSObject position) { if (systemClipboardWrapper.hasString()) { String pasteString = systemClipboardWrapper.getString(); - String originText = document.getText(); + String originText = removeSelection(jsSelection, document.getText()); String changedText = addPasteString(jsSelection, pasteString, originText); document.updateText(changedText); - calcNewCursorPosition(position, pasteString); + calcNewCursorPosition(jsSelection, position, pasteString); } return position; } + protected String removeSelection(JSObject jsSelection, String originText) { + int startLineNumber = getNumber(jsSelection, "startLineNumber"); + int startColumn = getNumber(jsSelection, "startColumn"); + int endLineNumber = getNumber(jsSelection, "endLineNumber"); + int endColumn = getNumber(jsSelection, "endColumn"); + if (startLineNumber < endLineNumber || (startLineNumber == endLineNumber && startColumn < endColumn)) { + String[] lines = originText.split("\n", -1); + AtomicInteger count = new AtomicInteger(0); + AtomicInteger startPosition = new AtomicInteger(0); + AtomicInteger endPosition = new AtomicInteger(0); + Arrays.stream(lines).forEach(line -> { + int lineNr = count.incrementAndGet(); + if (lineNr < startLineNumber) { + startPosition.getAndAdd(line.length() + 1); // +1 is needed to count \n at the end of the line + } + if (lineNr == startLineNumber) { + startPosition.getAndAdd(startColumn - 1); + } + if (lineNr < endLineNumber) { + endPosition.getAndAdd(line.length() + 1); + } + if (lineNr == endLineNumber) { + endPosition.getAndAdd(endColumn - 1); + } + }); + String substring1 = originText.substring(0, startPosition.get()); + String substring2 = originText.substring(endPosition.get(), originText.length()); + return substring1 + substring2; + } else { + return originText; + } + } + private String addPasteString(JSObject jsSelection, String pasteString, String originText) { // https://stackoverflow.com/questions/14602062/java-string-split-removed-empty-values String[] lines = originText.split("\n", -1); @@ -101,7 +134,7 @@ private String addPasteString(JSObject jsSelection, String pasteString, String o if (startLineNumber < lines.length) { String beforeMousePosition = lines[startLineNumber].substring(0, startColumn); String afterMousePosition = lines[startLineNumber].substring(startColumn); - lines[startLineNumber] = beforeMousePosition + pasteString + afterMousePosition;; + lines[startLineNumber] = beforeMousePosition + pasteString + afterMousePosition; } else { List list = new ArrayList<>(Arrays.asList(lines)); list.add(pasteString); @@ -110,15 +143,16 @@ private String addPasteString(JSObject jsSelection, String pasteString, String o return String.join("\n", lines); } - private void calcNewCursorPosition(JSObject position, String string) { - int lineNumber = getNumber(position, "lineNumber"); - int column = getNumber(position, "column"); - long count = string.split("\n", -1).length - 1; + private void calcNewCursorPosition(JSObject selection, JSObject position, String string) { + int lineNumber = getNumber(selection, "startLineNumber"); + int column = getNumber(selection, "startColumn"); + String[] split = string.split("\n", -1); + long count = split.length - 1; position.setMember("lineNumber", lineNumber + count); - Optional lastLine = string.lines().skip(count).findFirst(); - if (lastLine.isPresent()) { - position.setMember("column", column + lastLine.get().length()); + if (count > 0) { + String lastLine = split[(int) count]; + position.setMember("column", lastLine.length() + 1); } else { position.setMember("column", column + string.length()); } diff --git a/src/main/resources/eu/mihosoft/monacofx/monaco-editor/index.html b/src/main/resources/eu/mihosoft/monacofx/monaco-editor/index.html index cb75422..2bd7c8d 100644 --- a/src/main/resources/eu/mihosoft/monacofx/monaco-editor/index.html +++ b/src/main/resources/eu/mihosoft/monacofx/monaco-editor/index.html @@ -204,6 +204,9 @@ return editorView; } + // how to remove actions: + // https://github.com/microsoft/monaco-editor/issues/1567 + function removeAction(actionId) { actionId = "vs.editor.ICodeEditor:1:" + actionId; let menus = require('vs/platform/actions/common/actions').MenuRegistry._menuItems; diff --git a/src/test/java/eu/mihosoft/monacofx/ClipboardBridgeTest.java b/src/test/java/eu/mihosoft/monacofx/ClipboardBridgeTest.java index 41e1258..fa2541d 100644 --- a/src/test/java/eu/mihosoft/monacofx/ClipboardBridgeTest.java +++ b/src/test/java/eu/mihosoft/monacofx/ClipboardBridgeTest.java @@ -72,11 +72,42 @@ public void copy() { @Test public void paste() { // given - when(document.getText()).thenReturn("some text where at this position '' something is pasted"); + when(document.getText()).thenReturn("replace 'blablabu' with 'clipboard-text'"); + + JSObject selection = Mockito.mock(JSObject.class); + when(selection.getMember("startLineNumber")).thenReturn(1); + when(selection.getMember("startColumn")).thenReturn(10); + when(selection.getMember("endLineNumber")).thenReturn(1); + when(selection.getMember("endColumn")).thenReturn(18); + + JSObject position = Mockito.mock(JSObject.class); + when(position.getMember("lineNumber")).thenReturn(1); + when(position.getMember("column")).thenReturn(10); + + when(systemClipboardWrapper.hasString()).thenReturn(true); + when(systemClipboardWrapper.getString()).thenReturn("clipboard-text"); + + // when + JSObject paste = clipboardBridge.paste(selection, position); + + // then + Mockito.verify(document).updateText(updateTextCapture.capture()); + assertEquals("replace 'clipboard-text' with 'clipboard-text'", updateTextCapture.getValue()); + + } + + @Test + public void paste_two_lines_with_selection() { + // given + when(document.getText()).thenReturn( + "some text where at this position 'bla\n" + + "blabu' something is pasted"); JSObject selection = Mockito.mock(JSObject.class); when(selection.getMember("startLineNumber")).thenReturn(1); when(selection.getMember("startColumn")).thenReturn(35); + when(selection.getMember("endLineNumber")).thenReturn(2); + when(selection.getMember("endColumn")).thenReturn(6); JSObject position = Mockito.mock(JSObject.class); when(position.getMember("lineNumber")).thenReturn(1); @@ -90,7 +121,9 @@ public void paste() { // then Mockito.verify(document).updateText(updateTextCapture.capture()); - assertEquals("some text where at this position 'text in \nclipboard' something is pasted", updateTextCapture.getValue()); + assertEquals( + "some text where at this position 'text in \n" + + "clipboard' something is pasted", updateTextCapture.getValue()); verify(paste).setMember("lineNumber", 2L); verify(paste).setMember("column", 44); @@ -99,15 +132,15 @@ public void paste() { @Test public void pasteAtTheEnd() { // given - when(document.getText()).thenReturn("some text where pasted at the end"); + when(document.getText()).thenReturn("some text where pasted at the end\n"); JSObject selection = Mockito.mock(JSObject.class); when(selection.getMember("startLineNumber")).thenReturn(2); - when(selection.getMember("startColumn")).thenReturn(0); + when(selection.getMember("startColumn")).thenReturn(1); JSObject position = Mockito.mock(JSObject.class); when(position.getMember("lineNumber")).thenReturn(2); - when(position.getMember("column")).thenReturn(0); + when(position.getMember("column")).thenReturn(1); when(systemClipboardWrapper.hasString()).thenReturn(true); when(systemClipboardWrapper.getString()).thenReturn("text in clipboard"); @@ -116,8 +149,23 @@ public void pasteAtTheEnd() { // then Mockito.verify(document).updateText(updateTextCapture.capture()); assertEquals("some text where pasted at the end\ntext in clipboard", updateTextCapture.getValue()); - verify(paste).setMember("lineNumber", 2L); - verify(paste).setMember("column", 17); } + @Test + public void removeSelection() { + JSObject selection = Mockito.mock(JSObject.class); + when(selection.getMember("startLineNumber")).thenReturn(2); + when(selection.getMember("startColumn")).thenReturn(5); + when(selection.getMember("endLineNumber")).thenReturn(2); + when(selection.getMember("endColumn")).thenReturn(10); + String updatedText = clipboardBridge.removeSelection(selection, + "abcdefghijklmn\n" + + "1234" + + "56789" + + "0123456789\n"); + + assertEquals( + "abcdefghijklmn\n" + + "12340123456789\n", updatedText); + } } \ No newline at end of file