Add debug dialog, Use bytes everywhere, Sync somewhat works (WIP)
This commit is contained in:
parent
d47edc9e1a
commit
09d7d80d29
BIN
icons/bug.png
Normal file
BIN
icons/bug.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 502 B |
BIN
icons/bug@2x.png
Normal file
BIN
icons/bug@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 945 B |
@ -2,7 +2,6 @@ package me.mrletsplay.shareclient;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
@ -29,6 +28,7 @@ import org.osgi.framework.BundleContext;
|
||||
|
||||
import me.mrletsplay.shareclient.util.ChecksumUtil;
|
||||
import me.mrletsplay.shareclient.util.Peer;
|
||||
import me.mrletsplay.shareclient.util.ProjectAndPath;
|
||||
import me.mrletsplay.shareclient.util.ProjectRelativePath;
|
||||
import me.mrletsplay.shareclient.util.ShareSession;
|
||||
import me.mrletsplay.shareclient.util.SharedProject;
|
||||
@ -51,6 +51,7 @@ import me.mrletsplay.shareclientcore.connection.message.Message;
|
||||
import me.mrletsplay.shareclientcore.connection.message.PeerJoinMessage;
|
||||
import me.mrletsplay.shareclientcore.connection.message.PeerLeaveMessage;
|
||||
import me.mrletsplay.shareclientcore.connection.message.RequestFullSyncMessage;
|
||||
import me.mrletsplay.shareclientcore.document.Char;
|
||||
import me.mrletsplay.shareclientcore.document.SharedDocument;
|
||||
|
||||
/**
|
||||
@ -230,17 +231,15 @@ public class ShareClient extends AbstractUIPlugin implements MessageListener, Di
|
||||
|
||||
byte[] bytes = new byte[sync.content().size()];
|
||||
for(int i = 0; i < bytes.length; i++) {
|
||||
|
||||
bytes[i] = sync.content().get(i).value();
|
||||
}
|
||||
String content = sync.content().stream()
|
||||
.map(c -> String.valueOf(c.value()))
|
||||
.collect(Collectors.joining());
|
||||
|
||||
SharedDocument sharedDocument = activeSession.getOrCreateSharedDocument(path, () -> content);
|
||||
// TODO: update sharedDocuments
|
||||
SharedDocument sharedDocument = activeSession.getOrCreateSharedDocument(path, null /* because the content will be replaced afterwards anyway */);
|
||||
sharedDocument.clear();
|
||||
for(Char c : sync.content()) sharedDocument.getCharBag().add(c);
|
||||
|
||||
if(listener != null) listener.setIgnoreChanges(true);
|
||||
Files.write(filePath, content.getBytes(StandardCharsets.UTF_8)); // TODO: may cause problems with binary files? but they shouldn't be shared in the first place, so...
|
||||
Files.write(filePath, bytes);
|
||||
sharedProject.getLocal().refreshLocal(IResource.DEPTH_INFINITE, null);
|
||||
if(listener != null) listener.setIgnoreChanges(false);
|
||||
} catch (IOException | CoreException e) {
|
||||
@ -299,17 +298,13 @@ public class ShareClient extends AbstractUIPlugin implements MessageListener, Di
|
||||
return;
|
||||
}
|
||||
|
||||
if(activeSession.getSharedDocument(path) != null) return;
|
||||
SharedDocument doc = activeSession.getSharedDocument(path); // Doesn't use getOrCreateSharedDocument, because it doesn't make sense to apply a change to a document that wasn't previously shared
|
||||
|
||||
// FIXME: doesn't work
|
||||
SharedDocument doc = activeSession.getOrCreateSharedDocument(path, () -> {
|
||||
try {
|
||||
return Files.readString(resolvePath(path));
|
||||
}catch(IOException e) {
|
||||
MessageDialog.openError(null, "Share Client", "Failed to read file: " + e.toString());
|
||||
throw new RuntimeException(e);
|
||||
if(doc == null) {
|
||||
// TODO: show proper synchronization issue warning, because all received changes should be in previously shared documents
|
||||
MessageDialog.openError(null, "Share Client", "Synchronization issue (received change in non-shared document)");
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
doc.onMessage(message);
|
||||
}
|
||||
@ -333,7 +328,7 @@ public class ShareClient extends AbstractUIPlugin implements MessageListener, Di
|
||||
for(Map.Entry<ProjectRelativePath, Path> en : getProjectFiles(shared).entrySet()) {
|
||||
activeSession.getOrCreateSharedDocument(en.getKey(), () -> {
|
||||
try {
|
||||
return Files.readString(en.getValue(), StandardCharsets.UTF_8);
|
||||
return Files.readAllBytes(en.getValue());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
@ -364,7 +359,13 @@ public class ShareClient extends AbstractUIPlugin implements MessageListener, Di
|
||||
return true;
|
||||
}
|
||||
|
||||
private Path resolvePath(ProjectRelativePath path) {
|
||||
private ProjectAndPath resolveToProjectAndPath(ProjectRelativePath path) {
|
||||
SharedProject sharedProject = activeSession.getSharedProject(path.projectName());
|
||||
if(sharedProject == null) return null;
|
||||
return new ProjectAndPath(sharedProject.getLocal(), path.relativePath());
|
||||
}
|
||||
|
||||
private Path resolveToPath(ProjectRelativePath path) {
|
||||
SharedProject sharedProject = activeSession.getSharedProject(path.projectName());
|
||||
if(sharedProject == null) return null;
|
||||
Path projectLocation = sharedProject.getLocal().getLocation().toPath();
|
||||
|
@ -21,6 +21,7 @@ public class ShareClientPreferencePage extends FieldEditorPreferencePage impleme
|
||||
addField(new BooleanFieldEditor(ShareClientPreferences.SHOW_CURSORS, "Show other users' cursors (TODO)", getFieldEditorParent()));
|
||||
addField(new BooleanFieldEditor(ShareClientPreferences.ONLY_SHARE_SOURCE_FOLDERS, "Only share files in source folders (TODO)", getFieldEditorParent()));
|
||||
addField(new BooleanFieldEditor(ShareClientPreferences.USE_SHARECLIENT_PROJECT_CONFIG, "Use configuration from .shareclient file in the project (TODO)", getFieldEditorParent()));
|
||||
addField(new BooleanFieldEditor(ShareClientPreferences.DEBUG_MODE, "Debug mode", getFieldEditorParent())); // TODO: update view on setting change
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -7,6 +7,7 @@ public class ShareClientPreferences {
|
||||
USERNAME = "username",
|
||||
SHOW_CURSORS = "showCursors",
|
||||
ONLY_SHARE_SOURCE_FOLDERS = "onlyShareSourceFolders", // TODO: option to only share source folders of projects?
|
||||
USE_SHARECLIENT_PROJECT_CONFIG = "useShareClientConfig"; // TODO: option to enable a .shareclient project-specific config file
|
||||
USE_SHARECLIENT_PROJECT_CONFIG = "useShareClientConfig", // TODO: option to enable a .shareclient project-specific config file
|
||||
DEBUG_MODE = "debugMode";
|
||||
|
||||
}
|
||||
|
@ -8,9 +8,13 @@ import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.jface.text.BadLocationException;
|
||||
import org.eclipse.jface.text.IDocument;
|
||||
|
||||
import me.mrletsplay.shareclient.ShareClient;
|
||||
import me.mrletsplay.shareclient.util.listeners.ShareClientDocumentListener;
|
||||
import me.mrletsplay.shareclientcore.connection.RemoteConnection;
|
||||
import me.mrletsplay.shareclientcore.document.DocumentListener;
|
||||
import me.mrletsplay.shareclientcore.document.SharedDocument;
|
||||
|
||||
public class ShareSession {
|
||||
@ -79,51 +83,48 @@ public class ShareSession {
|
||||
|
||||
public SharedDocument getOrCreateSharedDocument(ProjectRelativePath path, Supplier<byte[]> initialContents) {
|
||||
return sharedDocuments.computeIfAbsent(path, p -> {
|
||||
SharedDocument doc = new SharedDocument(connection, path.toString(), initialContents.get());
|
||||
SharedDocument doc = new SharedDocument(connection, path.toString(), initialContents == null ? null : initialContents.get());
|
||||
|
||||
// doc.addListener(new DocumentListener() {
|
||||
//
|
||||
// @Override
|
||||
// public void onInsert(int index, byte character) {
|
||||
// // FIXME: potential desync. If changes arrive while waiting for asyncExec to execute, it will insert at the wrong position
|
||||
// Display.getDefault().asyncExec(() -> {
|
||||
// ShareClientDocumentListener documentListener = ShareClient.getDefault().getPartListener().getListener(path);
|
||||
// if(documentListener != null) {
|
||||
// IDocument document = documentListener.getDocument();
|
||||
//
|
||||
// documentListener.setIgnoreChanges(true);
|
||||
// try {
|
||||
// document.replace(index, 0, String.valueOf(character));
|
||||
// } catch (BadLocationException e) {
|
||||
// e.printStackTrace();
|
||||
// // TODO: treat as inconsistency
|
||||
//// MessageDialog.openError(null, "Share Client", "Failed to update document: " + e.toString());
|
||||
// }
|
||||
// documentListener.setIgnoreChanges(false);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onDelete(int index) {
|
||||
// Display.getDefault().asyncExec(() -> {
|
||||
// ShareClientDocumentListener documentListener = ShareClient.getDefault().getPartListener().getListener(path);
|
||||
// if(documentListener != null) {
|
||||
// IDocument document = documentListener.getDocument();
|
||||
//
|
||||
// documentListener.setIgnoreChanges(true);
|
||||
// try {
|
||||
// document.replace(index, 1, "");
|
||||
// } catch (BadLocationException e) {
|
||||
// e.printStackTrace();
|
||||
// // TODO: treat as inconsistency
|
||||
//// MessageDialog.openError(null, "Share Client", "Failed to update document: " + e.toString());
|
||||
// }
|
||||
// documentListener.setIgnoreChanges(false);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
doc.addListener(new DocumentListener() {
|
||||
|
||||
@Override
|
||||
public void onInsert(int index, byte character) {
|
||||
// TODO: assert that we are on the UI thread
|
||||
ShareClientDocumentListener documentListener = ShareClient.getDefault().getPartListener().getListener(path);
|
||||
if(documentListener != null) {
|
||||
IDocument document = documentListener.getDocument();
|
||||
|
||||
documentListener.setIgnoreChanges(true);
|
||||
try {
|
||||
document.replace(index, 0, String.valueOf((char) character)); // FIXME: dangerous! will explode on multi-byte characters
|
||||
} catch (BadLocationException e) {
|
||||
e.printStackTrace();
|
||||
// TODO: treat as inconsistency
|
||||
// MessageDialog.openError(null, "Share Client", "Failed to update document: " + e.toString());
|
||||
}
|
||||
documentListener.setIgnoreChanges(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDelete(int index) {
|
||||
// TODO: assert that we are on the UI thread
|
||||
ShareClientDocumentListener documentListener = ShareClient.getDefault().getPartListener().getListener(path);
|
||||
if(documentListener != null) {
|
||||
IDocument document = documentListener.getDocument();
|
||||
|
||||
documentListener.setIgnoreChanges(true);
|
||||
try {
|
||||
document.replace(index, 1, "");
|
||||
} catch (BadLocationException e) {
|
||||
e.printStackTrace();
|
||||
// TODO: treat as inconsistency
|
||||
// MessageDialog.openError(null, "Share Client", "Failed to update document: " + e.toString());
|
||||
}
|
||||
documentListener.setIgnoreChanges(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return doc;
|
||||
});
|
||||
|
@ -1,9 +1,10 @@
|
||||
package me.mrletsplay.shareclient.util.listeners;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.eclipse.jface.text.DocumentEvent;
|
||||
import org.eclipse.jface.text.IDocument;
|
||||
import org.eclipse.jface.text.IDocumentListener;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
|
||||
import me.mrletsplay.shareclient.ShareClient;
|
||||
import me.mrletsplay.shareclient.util.ProjectAndPath;
|
||||
@ -38,20 +39,20 @@ public class ShareClientDocumentListener implements IDocumentListener {
|
||||
|
||||
System.out.println("UPDATE ON THREAD " + Thread.currentThread());
|
||||
|
||||
Display.getDefault().asyncExec(() -> {
|
||||
// FIXME: bug somewhere here, can cause discrepancies in local editor when editing while changes are coming in
|
||||
|
||||
ShareSession session = ShareClient.getDefault().getActiveSession();
|
||||
if(session == null) return;
|
||||
|
||||
SharedProject sharedProject = session.getSharedProject(path.project());
|
||||
if(sharedProject == null) return;
|
||||
|
||||
SharedDocument doc = session.getOrCreateSharedDocument(new ProjectRelativePath(sharedProject.getRemoteName(), path.path()), () -> event.fDocument.get());
|
||||
SharedDocument doc = session.getOrCreateSharedDocument(new ProjectRelativePath(sharedProject.getRemoteName(), path.path()), () -> event.fDocument.get().getBytes(StandardCharsets.UTF_8));
|
||||
if(event.getLength() > 0) {
|
||||
doc.localDelete(event.getOffset(), event.getLength());
|
||||
}
|
||||
|
||||
doc.localInsert(event.getOffset(), event.getText());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,43 @@
|
||||
package me.mrletsplay.shareclient.views;
|
||||
|
||||
import org.eclipse.jface.dialogs.TitleAreaDialog;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.eclipse.swt.widgets.Text;
|
||||
|
||||
public class ScrollableDialog extends TitleAreaDialog {
|
||||
|
||||
private String text;
|
||||
|
||||
public ScrollableDialog(Shell parentShell, String title, String text) {
|
||||
super(parentShell);
|
||||
setTitle(title);
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Control createDialogArea(Composite parent) {
|
||||
Composite composite = (Composite) super.createDialogArea(parent);
|
||||
|
||||
GridData gridData = new GridData();
|
||||
gridData.grabExcessHorizontalSpace = true;
|
||||
gridData.horizontalAlignment = GridData.FILL;
|
||||
gridData.grabExcessVerticalSpace = true;
|
||||
gridData.verticalAlignment = GridData.FILL;
|
||||
|
||||
Text scrollable = new Text(composite, SWT.BORDER | SWT.V_SCROLL);
|
||||
scrollable.setLayoutData(gridData);
|
||||
scrollable.setText(text);
|
||||
|
||||
return composite;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isResizable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -31,6 +31,7 @@ import org.eclipse.ui.dialogs.PreferencesUtil;
|
||||
import org.eclipse.ui.part.ViewPart;
|
||||
|
||||
import me.mrletsplay.shareclient.ShareClient;
|
||||
import me.mrletsplay.shareclient.ShareClientPreferences;
|
||||
import me.mrletsplay.shareclient.util.ShareSession;
|
||||
import me.mrletsplay.shareclientcore.connection.ConnectionException;
|
||||
import me.mrletsplay.shareclientcore.connection.RemoteConnection;
|
||||
@ -161,6 +162,33 @@ public class ShareView extends ViewPart {
|
||||
|
||||
};
|
||||
|
||||
Action debug = new Action("Debug", ImageDescriptor.createFromFile(ShareView.class, "/icons/bug.png")) {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
ShareSession session = ShareClient.getDefault().getActiveSession();
|
||||
if(session == null) {
|
||||
MessageDialog.openInformation(null, "Debug", "No session running");
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
session.getSharedDocuments().forEach((path, document) -> {
|
||||
sb.append("--- Document: ").append(path).append('\n');
|
||||
|
||||
sb.append(document.getContentsAsString());
|
||||
|
||||
sb.append('\n');
|
||||
sb.append('\n');
|
||||
});
|
||||
|
||||
// MessageDialog.openInformation(null, "Debug Info", sb.toString());
|
||||
new ScrollableDialog(null, "Debug Info", sb.toString()).open();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
if(ShareClient.getDefault().getActiveSession() == null) {
|
||||
toolbars.add(joinSession);
|
||||
}else {
|
||||
@ -170,6 +198,10 @@ public class ShareView extends ViewPart {
|
||||
|
||||
toolbars.add(showSettings);
|
||||
|
||||
if(ShareClient.getDefault().getPreferenceStore().getBoolean(ShareClientPreferences.DEBUG_MODE)) {
|
||||
toolbars.add(debug);
|
||||
}
|
||||
|
||||
bars.updateActionBars();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user