Skip to content

Commit

Permalink
Issue: miho#24. paste of clipboard text on already selected text fixed.
Browse files Browse the repository at this point in the history
  • Loading branch information
kia committed Feb 10, 2023
1 parent 62b9725 commit 100cd8a
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 18 deletions.
56 changes: 45 additions & 11 deletions src/main/java/eu/mihosoft/monacofx/ClipboardBridge.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Expand All @@ -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<String> list = new ArrayList<>(Arrays.asList(lines));
list.add(pasteString);
Expand All @@ -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<String> 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());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
62 changes: 55 additions & 7 deletions src/test/java/eu/mihosoft/monacofx/ClipboardBridgeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);

Expand All @@ -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");
Expand All @@ -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);
}
}

0 comments on commit 100cd8a

Please sign in to comment.