fix: file consistency issues, cursor position

This commit is contained in:
zaaarf 2024-10-08 22:58:25 +02:00
parent 5761ef71ab
commit c155773753
No known key found for this signature in database
GPG key ID: 102E445F4C3F829B
9 changed files with 82 additions and 65 deletions

View file

@ -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;

View file

@ -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) {

View file

@ -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))

View file

@ -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,39 +27,47 @@ 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();
if (file == null) return;
Path nioPath = file.toNioPath(); Editor editor = event.getEditor();
if (nioPath == null) return; VirtualFile file = editor.getVirtualFile();
if(file == null) return;
String buffer_name = CodeMP.BUFFER_MAPPER.get(nioPath); try {
if (buffer_name == 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;
}
if(CodeMP.getActiveWorkspace().getBuffer(buffer_name).isEmpty()) return; LogicalPosition startPos = editor.offsetToLogicalPosition(caret.getSelectionStart());
LogicalPosition endPos = editor.offsetToLogicalPosition(caret.getSelectionEnd());
VisualPosition startPos = caret.getSelectionStartPosition(); CodeMP.LOGGER.debug(String.format(
VisualPosition endPos = caret.getSelectionEndPosition(); "Caret moved from %dx %dy to %dx %dy",
CodeMP.LOGGER.debug("Caret moved from {}x {}y to {}x {}y", startPos.line,
startPos.line, startPos.column, endPos.line, endPos.column startPos.column,
); endPos.line,
endPos.column
));
new Thread(() -> { new Thread(() -> ApplicationManager.getApplication().runReadAction(() -> {
ApplicationManager.getApplication().runReadAction(() -> { try {
Editor editor = event.getEditor(); CodeMP.getActiveWorkspace().getCursor().send(new Cursor(
try { startPos.line,
CodeMP.getActiveWorkspace().getCursor().send(new Cursor( startPos.column,
startPos.line, endPos.line,
startPos.column, endPos.column,
endPos.line, FileUtil.getRelativePath(editor.getProject(), editor.getVirtualFile()),
endPos.column, null
FileUtil.getRelativePath(editor.getProject(), editor.getVirtualFile()), ));
null } catch(ControllerException e) {
)); throw new RuntimeException(e);
} catch(ControllerException e) { }
throw new RuntimeException(e); })).start();
}
});
}).start();
} }
} }

View file

@ -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,15 +95,14 @@ 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);
} }
} }

View file

@ -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();

View file

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

View file

@ -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;
} }

View file

@ -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" />