mirror of
https://github.com/hexedtech/codemp-intellij.git
synced 2024-11-23 23:54:48 +01:00
fix: file consistency issues, cursor position
This commit is contained in:
parent
5761ef71ab
commit
c155773753
9 changed files with 82 additions and 65 deletions
|
@ -3,6 +3,7 @@ package mp.code.intellij;
|
||||||
import com.google.common.collect.BiMap;
|
import com.google.common.collect.BiMap;
|
||||||
import com.google.common.collect.HashBiMap;
|
import com.google.common.collect.HashBiMap;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
import com.intellij.openapi.diagnostic.Logger;
|
||||||
import com.intellij.openapi.editor.markup.RangeHighlighter;
|
import com.intellij.openapi.editor.markup.RangeHighlighter;
|
||||||
import mp.code.Extensions;
|
import mp.code.Extensions;
|
||||||
import mp.code.Workspace;
|
import mp.code.Workspace;
|
||||||
|
@ -10,15 +11,13 @@ import mp.code.data.Config;
|
||||||
import mp.code.exceptions.ConnectionException;
|
import mp.code.exceptions.ConnectionException;
|
||||||
import mp.code.intellij.exceptions.ide.NotConnectedException;
|
import mp.code.intellij.exceptions.ide.NotConnectedException;
|
||||||
import mp.code.Client;
|
import mp.code.Client;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class CodeMP {
|
public class CodeMP {
|
||||||
public static Logger LOGGER = LoggerFactory.getLogger(CodeMP.class);
|
public static final Logger LOGGER = Logger.getInstance(CodeMP.class);
|
||||||
private static Client CLIENT = null;
|
private static Client CLIENT = null;
|
||||||
private static String ACTIVE_WORKSPACE_ID = null;
|
private static String ACTIVE_WORKSPACE_ID = null;
|
||||||
|
|
||||||
|
|
|
@ -63,9 +63,9 @@ public class BufferShareAction extends AnAction {
|
||||||
ApplicationManager.getApplication().runWriteAction(() -> {
|
ApplicationManager.getApplication().runWriteAction(() -> {
|
||||||
try {
|
try {
|
||||||
FileUtil.getAndRegisterBufferEquivalent(this, proj, controller.get());
|
FileUtil.getAndRegisterBufferEquivalent(this, proj, controller.get());
|
||||||
} catch(Exception ex) {
|
} catch(ControllerException | IOException ex) {
|
||||||
throw new RuntimeException(ex);
|
throw new RuntimeException(ex);
|
||||||
}
|
} catch(UnsupportedOperationException ignored) {}
|
||||||
});
|
});
|
||||||
controller.get().callback(buf -> new BufferCallback(proj).accept(buf));
|
controller.get().callback(buf -> new BufferCallback(proj).accept(buf));
|
||||||
} catch(ControllerException | IOException ex) {
|
} catch(ControllerException | IOException ex) {
|
||||||
|
|
|
@ -21,8 +21,12 @@ public class BufferEventListener implements DocumentListener {
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public void documentChanged(@NotNull DocumentEvent event) {
|
public void documentChanged(@NotNull DocumentEvent event) {
|
||||||
CodeMP.LOGGER.debug("Changed {} to {} at offset {}",
|
CodeMP.LOGGER.debug(String.format(
|
||||||
event.getOldFragment(), event.getNewFragment(), event.getOffset());
|
"Changed %s to %s at offset %d",
|
||||||
|
event.getOldFragment(),
|
||||||
|
event.getNewFragment(),
|
||||||
|
event.getOffset()
|
||||||
|
));
|
||||||
|
|
||||||
Object group = CommandProcessor.getInstance().getCurrentCommandGroupId();
|
Object group = CommandProcessor.getInstance().getCurrentCommandGroupId();
|
||||||
if(group instanceof String groupString)
|
if(group instanceof String groupString)
|
||||||
|
@ -36,7 +40,7 @@ public class BufferEventListener implements DocumentListener {
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
|
|
||||||
if(file == null) return;
|
if(file == null || !file.isInLocalFileSystem()) return;
|
||||||
|
|
||||||
Optional.ofNullable(CodeMP.BUFFER_MAPPER.get(file.toNioPath()))
|
Optional.ofNullable(CodeMP.BUFFER_MAPPER.get(file.toNioPath()))
|
||||||
.flatMap(c -> CodeMP.getActiveWorkspace().getBuffer(c))
|
.flatMap(c -> CodeMP.getActiveWorkspace().getBuffer(c))
|
||||||
|
|
|
@ -1,24 +1,22 @@
|
||||||
package mp.code.intellij.listeners;
|
package mp.code.intellij.listeners;
|
||||||
|
|
||||||
import com.intellij.openapi.application.ApplicationManager;
|
import com.intellij.openapi.application.ApplicationManager;
|
||||||
import com.intellij.openapi.application.CoroutinesKt;
|
import com.intellij.openapi.editor.LogicalPosition;
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
import com.intellij.util.SlowOperations;
|
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import mp.code.exceptions.ControllerException;
|
import mp.code.exceptions.ControllerException;
|
||||||
import mp.code.intellij.CodeMP;
|
import mp.code.intellij.CodeMP;
|
||||||
import mp.code.intellij.util.FileUtil;
|
import mp.code.intellij.util.FileUtil;
|
||||||
import com.intellij.openapi.editor.Caret;
|
import com.intellij.openapi.editor.Caret;
|
||||||
import com.intellij.openapi.editor.Editor;
|
import com.intellij.openapi.editor.Editor;
|
||||||
import com.intellij.openapi.editor.VisualPosition;
|
|
||||||
import com.intellij.openapi.editor.event.CaretEvent;
|
import com.intellij.openapi.editor.event.CaretEvent;
|
||||||
import com.intellij.openapi.editor.event.CaretListener;
|
import com.intellij.openapi.editor.event.CaretListener;
|
||||||
import mp.code.data.Cursor;
|
import mp.code.data.Cursor;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
public class CursorEventListener implements CaretListener {
|
public class CursorEventListener implements CaretListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -29,26 +27,35 @@ public class CursorEventListener implements CaretListener {
|
||||||
Caret caret = event.getCaret();
|
Caret caret = event.getCaret();
|
||||||
if (caret == null) return;
|
if (caret == null) return;
|
||||||
|
|
||||||
VirtualFile file = event.getEditor().getVirtualFile();
|
|
||||||
|
Editor editor = event.getEditor();
|
||||||
|
VirtualFile file = editor.getVirtualFile();
|
||||||
if(file == null) return;
|
if(file == null) return;
|
||||||
|
|
||||||
Path nioPath = file.toNioPath();
|
try {
|
||||||
if (nioPath == null) return;
|
if(
|
||||||
|
Optional.ofNullable(CodeMP.BUFFER_MAPPER.get(file.toNioPath()))
|
||||||
|
.flatMap(n -> CodeMP.getActiveWorkspace().getBuffer(n))
|
||||||
|
.isEmpty()
|
||||||
|
) return;
|
||||||
|
} catch(UnsupportedOperationException ex) {
|
||||||
|
// probably won't be like this long term, but for now we work with real physical files
|
||||||
|
// so converting to nio path is always legal when it's the right file
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String buffer_name = CodeMP.BUFFER_MAPPER.get(nioPath);
|
LogicalPosition startPos = editor.offsetToLogicalPosition(caret.getSelectionStart());
|
||||||
if (buffer_name == null) return;
|
LogicalPosition endPos = editor.offsetToLogicalPosition(caret.getSelectionEnd());
|
||||||
|
|
||||||
if(CodeMP.getActiveWorkspace().getBuffer(buffer_name).isEmpty()) return;
|
CodeMP.LOGGER.debug(String.format(
|
||||||
|
"Caret moved from %dx %dy to %dx %dy",
|
||||||
|
startPos.line,
|
||||||
|
startPos.column,
|
||||||
|
endPos.line,
|
||||||
|
endPos.column
|
||||||
|
));
|
||||||
|
|
||||||
VisualPosition startPos = caret.getSelectionStartPosition();
|
new Thread(() -> ApplicationManager.getApplication().runReadAction(() -> {
|
||||||
VisualPosition endPos = caret.getSelectionEndPosition();
|
|
||||||
CodeMP.LOGGER.debug("Caret moved from {}x {}y to {}x {}y",
|
|
||||||
startPos.line, startPos.column, endPos.line, endPos.column
|
|
||||||
);
|
|
||||||
|
|
||||||
new Thread(() -> {
|
|
||||||
ApplicationManager.getApplication().runReadAction(() -> {
|
|
||||||
Editor editor = event.getEditor();
|
|
||||||
try {
|
try {
|
||||||
CodeMP.getActiveWorkspace().getCursor().send(new Cursor(
|
CodeMP.getActiveWorkspace().getCursor().send(new Cursor(
|
||||||
startPos.line,
|
startPos.line,
|
||||||
|
@ -61,7 +68,6 @@ public class CursorEventListener implements CaretListener {
|
||||||
} catch(ControllerException e) {
|
} catch(ControllerException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
});
|
})).start();
|
||||||
}).start();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,10 @@ package mp.code.intellij.ui;
|
||||||
import com.intellij.openapi.application.ApplicationManager;
|
import com.intellij.openapi.application.ApplicationManager;
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.openapi.ui.Messages;
|
import com.intellij.openapi.ui.Messages;
|
||||||
|
import com.intellij.ui.components.JBList;
|
||||||
import com.intellij.ui.treeStructure.Tree;
|
import com.intellij.ui.treeStructure.Tree;
|
||||||
|
|
||||||
import mp.code.Workspace;
|
import mp.code.Workspace;
|
||||||
|
import mp.code.exceptions.ControllerException;
|
||||||
import mp.code.intellij.CodeMP;
|
import mp.code.intellij.CodeMP;
|
||||||
import mp.code.intellij.util.FileUtil;
|
import mp.code.intellij.util.FileUtil;
|
||||||
import mp.code.intellij.util.InteractionUtil;
|
import mp.code.intellij.util.InteractionUtil;
|
||||||
|
@ -17,6 +18,7 @@ import javax.swing.tree.TreePath;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public class CodeMPToolPanel extends JPanel {
|
public class CodeMPToolPanel extends JPanel {
|
||||||
|
@ -93,14 +95,13 @@ public class CodeMPToolPanel extends JPanel {
|
||||||
).ifPresent(controller -> {
|
).ifPresent(controller -> {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1000); // TODO: this sucks
|
Thread.sleep(1000); // TODO: this sucks
|
||||||
} catch(InterruptedException ignored) {
|
} catch(InterruptedException ignored) {}
|
||||||
}
|
|
||||||
ApplicationManager.getApplication().runWriteAction(() -> {
|
ApplicationManager.getApplication().runWriteAction(() -> {
|
||||||
try {
|
try {
|
||||||
FileUtil.getAndRegisterBufferEquivalent(this, project, controller);
|
FileUtil.getAndRegisterBufferEquivalent(this, project, controller);
|
||||||
} catch(Exception ex) {
|
} catch(ControllerException | IOException ex) {
|
||||||
throw new RuntimeException(ex);
|
throw new RuntimeException(ex);
|
||||||
}
|
} catch(UnsupportedOperationException ignored) {}
|
||||||
});
|
});
|
||||||
controller.callback(buf -> new BufferCallback(project).accept(buf));
|
controller.callback(buf -> new BufferCallback(project).accept(buf));
|
||||||
});
|
});
|
||||||
|
@ -109,7 +110,7 @@ public class CodeMPToolPanel extends JPanel {
|
||||||
|
|
||||||
this.add(tree, BorderLayout.CENTER);
|
this.add(tree, BorderLayout.CENTER);
|
||||||
|
|
||||||
JList userlist = new JList<String>(ws.userList());
|
JList<String> userlist = new JBList<>(ws.userList());
|
||||||
this.add(userlist, BorderLayout.SOUTH);
|
this.add(userlist, BorderLayout.SOUTH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ public class FileUtil {
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FileEditor getAndRegisterBufferEquivalent(Object requestor, Project project, BufferController buffer) throws ControllerException, IOException {
|
public static FileEditor getAndRegisterBufferEquivalent(Object requestor, Project project, BufferController buffer) throws UnsupportedOperationException, ControllerException, IOException {
|
||||||
VirtualFile contentRoot = ProjectRootManager.getInstance(project).getContentRoots()[0];
|
VirtualFile contentRoot = ProjectRootManager.getInstance(project).getContentRoots()[0];
|
||||||
String bufferName = buffer.getName();
|
String bufferName = buffer.getName();
|
||||||
|
|
||||||
|
|
|
@ -42,8 +42,12 @@ public class BufferCallback implements Consumer<BufferController> {
|
||||||
if(changeOptional.isEmpty())
|
if(changeOptional.isEmpty())
|
||||||
break;
|
break;
|
||||||
TextChange change = changeOptional.get();
|
TextChange change = changeOptional.get();
|
||||||
CodeMP.LOGGER.debug("Received text change {} from offset {} to {}!",
|
CodeMP.LOGGER.debug(String.format(
|
||||||
change.content, change.start, change.end);
|
"Received text change %s from offset %d to %d!",
|
||||||
|
change.content,
|
||||||
|
change.start,
|
||||||
|
change.end
|
||||||
|
));
|
||||||
changeList.add(change);
|
changeList.add(change);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,15 +36,15 @@ public class CursorCallback implements Consumer<CursorController> {
|
||||||
if(c.isEmpty()) break;
|
if(c.isEmpty()) break;
|
||||||
Cursor event = c.get();
|
Cursor event = c.get();
|
||||||
|
|
||||||
CodeMP.LOGGER.debug(
|
CodeMP.LOGGER.debug(String.format(
|
||||||
"Cursor moved by user {}! Start pos: {}x {}y; end pos: {}x {}y in buffer {}!",
|
"Cursor moved by user %s! Start pos: %dx %dy; end pos: %dx %dy in buffer %s!",
|
||||||
event.user,
|
event.user,
|
||||||
event.startCol,
|
event.startCol,
|
||||||
event.startRow,
|
event.startRow,
|
||||||
event.endCol,
|
event.endCol,
|
||||||
event.endRow,
|
event.endRow,
|
||||||
event.buffer
|
event.buffer
|
||||||
);
|
));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ApplicationManager.getApplication().runReadAction(() -> {
|
ApplicationManager.getApplication().runReadAction(() -> {
|
||||||
|
@ -56,9 +56,12 @@ public class CursorCallback implements Consumer<CursorController> {
|
||||||
|
|
||||||
int documentLength = editor.getDocument().getTextLength();
|
int documentLength = editor.getDocument().getTextLength();
|
||||||
if(startOffset > documentLength || endOffset > documentLength) {
|
if(startOffset > documentLength || endOffset > documentLength) {
|
||||||
CodeMP.LOGGER.debug(
|
CodeMP.LOGGER.debug(String.format(
|
||||||
"Out of bounds cursor: start was {}, end was {}, document length was {}!",
|
"Out of bounds cursor: start was %d, end was %d, document length was %d!",
|
||||||
startOffset, endOffset, documentLength);
|
startOffset,
|
||||||
|
endOffset,
|
||||||
|
documentLength
|
||||||
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<idea-plugin>
|
<idea-plugin>
|
||||||
<id>mp.code.intellij</id>
|
<id>mp.code.intellij</id>
|
||||||
<name>CodeMP</name>
|
<name>CodeMP</name>
|
||||||
<vendor email="me@zaaarf.foo" url="https://zaaarf.foo">CodeMP</vendor>
|
<vendor email="me@zaaarf.foo" url="https://code.mp">CodeMP</vendor>
|
||||||
|
|
||||||
<description>A plugin for MultiPlayer code editing across different IDEs.</description>
|
<description>A plugin for MultiPlayer code editing across different IDEs.</description>
|
||||||
|
|
||||||
|
@ -31,15 +31,15 @@
|
||||||
<action id="codemp.buffer.share" class="mp.code.intellij.actions.buffer.BufferShareAction"
|
<action id="codemp.buffer.share" class="mp.code.intellij.actions.buffer.BufferShareAction"
|
||||||
text="Share Current Buffer"/>
|
text="Share Current Buffer"/>
|
||||||
<action id="codemp.buffer.attach" class="mp.code.intellij.actions.buffer.BufferAttachAction"
|
<action id="codemp.buffer.attach" class="mp.code.intellij.actions.buffer.BufferAttachAction"
|
||||||
text="Attach to remote buffer"/>
|
text="Attach to Remote Buffer"/>
|
||||||
<action id="codemp.buffer.detach" class="mp.code.intellij.actions.buffer.BufferDetachAction"
|
<action id="codemp.buffer.detach" class="mp.code.intellij.actions.buffer.BufferDetachAction"
|
||||||
text="Detach from remote buffer"/>
|
text="Detach from Remote Buffer"/>
|
||||||
<action id="codemp.buffer.create" class="mp.code.intellij.actions.buffer.BufferCreateAction"
|
<action id="codemp.buffer.create" class="mp.code.intellij.actions.buffer.BufferCreateAction"
|
||||||
text="Create a new empty remote buffer"/>
|
text="Create a New Empty Remote Buffer"/>
|
||||||
<action id="codemp.buffer.delete" class="mp.code.intellij.actions.buffer.BufferDeleteAction"
|
<action id="codemp.buffer.delete" class="mp.code.intellij.actions.buffer.BufferDeleteAction"
|
||||||
text="Delete a remote buffer"/>
|
text="Delete a Remote Buffer"/>
|
||||||
<action id="codemp.buffer.sync" class="mp.code.intellij.actions.buffer.BufferSyncAction"
|
<action id="codemp.buffer.sync" class="mp.code.intellij.actions.buffer.BufferSyncAction"
|
||||||
text="Sync content of a managed buffer"/>
|
text="Sync Content of a Managed Buffer"/>
|
||||||
</group>
|
</group>
|
||||||
</actions>
|
</actions>
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@
|
||||||
displayName="CodeMP"/>
|
displayName="CodeMP"/>
|
||||||
<workspaceModel.fileIndexContributor implementation="mp.code.intellij.vfs.CodeMPFileIndexContributor" />
|
<workspaceModel.fileIndexContributor implementation="mp.code.intellij.vfs.CodeMPFileIndexContributor" />
|
||||||
<toolWindow
|
<toolWindow
|
||||||
id="CodeMPToolWindow"
|
id="CodeMP"
|
||||||
factoryClass="mp.code.intellij.ui.CodeMPWindowFactory"
|
factoryClass="mp.code.intellij.ui.CodeMPWindowFactory"
|
||||||
anchor="right"
|
anchor="right"
|
||||||
doNotActivateOnStart="false" />
|
doNotActivateOnStart="false" />
|
||||||
|
|
Loading…
Reference in a new issue