mirror of
https://github.com/hexedtech/codemp-intellij.git
synced 2024-11-21 22:54:48 +01:00
feat: buffer and workspace disconnect, lifetime system for listeners
This commit is contained in:
parent
dfae6d6b9d
commit
8c04d9b8c2
10 changed files with 210 additions and 40 deletions
|
@ -1,6 +1,7 @@
|
||||||
package com.codemp.intellij.actions;
|
package com.codemp.intellij.actions;
|
||||||
|
|
||||||
import com.codemp.intellij.actions.buffer.BufferAttachAction;
|
import com.codemp.intellij.actions.buffer.BufferAttachAction;
|
||||||
|
import com.codemp.intellij.actions.workspace.WorkspaceJoinAction;
|
||||||
import com.intellij.openapi.actionSystem.AnAction;
|
import com.intellij.openapi.actionSystem.AnAction;
|
||||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
@ -13,7 +14,7 @@ public class FastForwardAction extends AnAction {
|
||||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||||
try {
|
try {
|
||||||
ConnectAction.connect("http://alemi.dev:50052", true);
|
ConnectAction.connect("http://alemi.dev:50052", true);
|
||||||
JoinAction.join(e, "default", true);
|
WorkspaceJoinAction.join(e, "default", true);
|
||||||
BufferAttachAction.attach(e, "test", true);
|
BufferAttachAction.attach(e, "test", true);
|
||||||
} catch(Exception ex) {
|
} catch(Exception ex) {
|
||||||
throw new RuntimeException(ex);
|
throw new RuntimeException(ex);
|
||||||
|
|
|
@ -6,6 +6,7 @@ import com.codemp.intellij.jni.CodeMPHandler;
|
||||||
import com.codemp.intellij.jni.TextChangeWrapper;
|
import com.codemp.intellij.jni.TextChangeWrapper;
|
||||||
import com.codemp.intellij.listeners.BufferEventListener;
|
import com.codemp.intellij.listeners.BufferEventListener;
|
||||||
import com.codemp.intellij.util.ActionUtil;
|
import com.codemp.intellij.util.ActionUtil;
|
||||||
|
import com.codemp.intellij.util.DisposableRegistry;
|
||||||
import com.intellij.openapi.actionSystem.AnAction;
|
import com.intellij.openapi.actionSystem.AnAction;
|
||||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||||
import com.intellij.openapi.application.ApplicationManager;
|
import com.intellij.openapi.application.ApplicationManager;
|
||||||
|
@ -32,12 +33,18 @@ public class BufferAttachAction extends AnAction {
|
||||||
|
|
||||||
Project project = ActionUtil.getCurrentProject(e);
|
Project project = ActionUtil.getCurrentProject(e);
|
||||||
Document document = ActionUtil.getCurrentEditor(e).getDocument();
|
Document document = ActionUtil.getCurrentEditor(e).getDocument();
|
||||||
document.addDocumentListener(listener);
|
document.addDocumentListener(listener, DisposableRegistry.getOrCreate(String.format("codemp-buffer-%s", buffer)));
|
||||||
|
|
||||||
ProgressManager.getInstance().run(new Task.Backgroundable(e.getProject(), "Awaiting CodeMP buffer events") {
|
ProgressManager.getInstance().run(new Task.Backgroundable(e.getProject(), "Awaiting CodeMP buffer events") {
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings({"InfiniteLoopStatement", "UnstableApiUsage"})
|
@SuppressWarnings({"InfiniteLoopStatement", "UnstableApiUsage"})
|
||||||
public void run(@NotNull ProgressIndicator indicator) {
|
public void run(@NotNull ProgressIndicator indicator) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(100); //tonioware
|
||||||
|
} catch(InterruptedException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
try {
|
try {
|
||||||
TextChangeWrapper event = bufferHandler.recv();
|
TextChangeWrapper event = bufferHandler.recv();
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
package com.codemp.intellij.actions.buffer;
|
||||||
|
|
||||||
|
import com.codemp.intellij.CodeMP;
|
||||||
|
import com.codemp.intellij.exceptions.ide.BufferDetachException;
|
||||||
|
import com.codemp.intellij.jni.CodeMPHandler;
|
||||||
|
import com.codemp.intellij.util.DisposableRegistry;
|
||||||
|
import com.intellij.openapi.actionSystem.AnAction;
|
||||||
|
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||||
|
import com.intellij.openapi.ui.Messages;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class BufferDetachAction extends AnAction {
|
||||||
|
public static void detach(String buffer, boolean silent) throws Exception {
|
||||||
|
boolean res = CodeMPHandler.detach(buffer);
|
||||||
|
if(!res) throw new BufferDetachException(buffer);
|
||||||
|
|
||||||
|
//dispose of listener's associated disposable
|
||||||
|
DisposableRegistry.disposeOf(String.format("codemp-buffer-%s", buffer));
|
||||||
|
|
||||||
|
if(!silent) Messages.showInfoMessage(String.format("Detached from buffer %s!", buffer),
|
||||||
|
"Detach from CodeMP Buffer" );
|
||||||
|
CodeMP.LOGGER.debug("Detached from buffer {}!", buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||||
|
String buffer = Messages.showInputDialog(
|
||||||
|
"Buffer name:",
|
||||||
|
"Detach from CodeMP Buffer",
|
||||||
|
Messages.getQuestionIcon());
|
||||||
|
|
||||||
|
try {
|
||||||
|
detach(buffer, false);
|
||||||
|
} catch(Exception ex) {
|
||||||
|
Messages.showErrorDialog(String.format(
|
||||||
|
"Failed to detach from buffer with name %s: %s!",
|
||||||
|
buffer, ex.getMessage()), "Detach from CodeMP Buffer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package com.codemp.intellij.actions;
|
package com.codemp.intellij.actions.workspace;
|
||||||
|
|
||||||
import com.codemp.intellij.CodeMP;
|
import com.codemp.intellij.CodeMP;
|
||||||
import com.codemp.intellij.jni.CodeMPHandler;
|
import com.codemp.intellij.jni.CodeMPHandler;
|
||||||
|
@ -7,7 +7,7 @@ import com.codemp.intellij.jni.CursorHandler;
|
||||||
import com.codemp.intellij.listeners.CursorEventListener;
|
import com.codemp.intellij.listeners.CursorEventListener;
|
||||||
import com.codemp.intellij.util.ActionUtil;
|
import com.codemp.intellij.util.ActionUtil;
|
||||||
import com.codemp.intellij.util.ColorUtil;
|
import com.codemp.intellij.util.ColorUtil;
|
||||||
import com.intellij.openapi.Disposable;
|
import com.codemp.intellij.util.DisposableRegistry;
|
||||||
import com.intellij.openapi.actionSystem.AnAction;
|
import com.intellij.openapi.actionSystem.AnAction;
|
||||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||||
import com.intellij.openapi.application.ApplicationManager;
|
import com.intellij.openapi.application.ApplicationManager;
|
||||||
|
@ -25,18 +25,18 @@ import com.intellij.openapi.ui.Messages;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class JoinAction extends AnAction {
|
public class WorkspaceJoinAction extends AnAction {
|
||||||
|
|
||||||
private static final Map<String, RangeHighlighter> highlighterMap = new HashMap<>();
|
private static final Map<String, RangeHighlighter> highlighterMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public static void join(AnActionEvent e, String session, boolean silent) throws Exception {
|
public static void join(AnActionEvent e, String workspace, boolean silent) throws Exception {
|
||||||
CursorHandler cursorHandler = CodeMPHandler.join(session);
|
CursorHandler cursorHandler = CodeMPHandler.join(workspace);
|
||||||
|
|
||||||
if(!silent) Messages.showInfoMessage(String.format("Joined session %s!", session), "CodeMP");
|
if(!silent) Messages.showInfoMessage(String.format("Joined workspace %s!", workspace), "CodeMP");
|
||||||
else CodeMP.LOGGER.debug("Joined session {}!", session);
|
else CodeMP.LOGGER.debug("Joined workspace {}!", workspace);
|
||||||
|
|
||||||
Editor editor = ActionUtil.getCurrentEditor(e);
|
Editor editor = ActionUtil.getCurrentEditor(e);
|
||||||
|
|
||||||
|
@ -49,7 +49,8 @@ public class JoinAction extends AnAction {
|
||||||
|
|
||||||
EditorFactory.getInstance()
|
EditorFactory.getInstance()
|
||||||
.getEventMulticaster()
|
.getEventMulticaster()
|
||||||
.addCaretListener(new CursorEventListener(), task);
|
.addCaretListener(new CursorEventListener(),
|
||||||
|
DisposableRegistry.getOrCreate(String.format("codemp-cursor-%s", workspace)));
|
||||||
|
|
||||||
ProgressManager.getInstance().run(task);
|
ProgressManager.getInstance().run(task);
|
||||||
}
|
}
|
||||||
|
@ -74,7 +75,7 @@ public class JoinAction extends AnAction {
|
||||||
|
|
||||||
//TODO this is janky as it shows a progress bar it doesn't use tbh
|
//TODO this is janky as it shows a progress bar it doesn't use tbh
|
||||||
//implements disposable so i can use it as lifetime ig
|
//implements disposable so i can use it as lifetime ig
|
||||||
private static class CursorEventAwaiter extends Task.Backgroundable implements Disposable {
|
private static class CursorEventAwaiter extends Task.Backgroundable {
|
||||||
|
|
||||||
private final CursorHandler handler;
|
private final CursorHandler handler;
|
||||||
private final Editor editor;
|
private final Editor editor;
|
||||||
|
@ -85,9 +86,6 @@ public class JoinAction extends AnAction {
|
||||||
this.editor = editor;
|
this.editor = editor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dispose() {}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("InfiniteLoopStatement")
|
@SuppressWarnings("InfiniteLoopStatement")
|
||||||
public void run(@NotNull ProgressIndicator indicator) {
|
public void run(@NotNull ProgressIndicator indicator) {
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.codemp.intellij.actions.workspace;
|
||||||
|
|
||||||
|
import com.codemp.intellij.CodeMP;
|
||||||
|
import com.codemp.intellij.jni.CodeMPHandler;
|
||||||
|
import com.codemp.intellij.util.DisposableRegistry;
|
||||||
|
import com.intellij.openapi.actionSystem.AnAction;
|
||||||
|
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||||
|
import com.intellij.openapi.ui.Messages;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class WorkspaceLeaveAction extends AnAction {
|
||||||
|
public static void leave(boolean silent) throws Exception {
|
||||||
|
CodeMPHandler.leaveWorkspace();
|
||||||
|
|
||||||
|
//dispose of listener's associated disposable
|
||||||
|
DisposableRegistry.disposeOf("codemp-cursor");
|
||||||
|
|
||||||
|
if(!silent) Messages.showInfoMessage("Left workspace!",
|
||||||
|
"Detach from CodeMP Buffer" );
|
||||||
|
CodeMP.LOGGER.debug("Left workspace!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||||
|
try {
|
||||||
|
leave(false);
|
||||||
|
} catch(Exception ex) {
|
||||||
|
Messages.showErrorDialog(String.format(
|
||||||
|
"Failed to leave workspace: %s!",
|
||||||
|
ex.getMessage()), "Leave CodeMP Workspace");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.codemp.intellij.exceptions.ide;
|
||||||
|
|
||||||
|
import com.codemp.intellij.exceptions.CodeMPException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown upon failure to detach from a buffer.
|
||||||
|
*/
|
||||||
|
public class BufferDetachException extends CodeMPException {
|
||||||
|
|
||||||
|
public BufferDetachException(String name) {
|
||||||
|
super(String.format("Could not detach from buffer named \"%s\"!", name));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
package com.codemp.intellij.util;
|
||||||
|
|
||||||
|
import com.intellij.openapi.Disposable;
|
||||||
|
import com.intellij.openapi.util.Disposer;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A registry holding {@link Disposable Disposables} used within the plugin,
|
||||||
|
* since there's no other way to keep track of them across different sections.
|
||||||
|
* Only parentless {@link Disposable Disposables} are handled here, since
|
||||||
|
* those with a parent will be disposed automatically.
|
||||||
|
*/
|
||||||
|
public class DisposableRegistry {
|
||||||
|
private static final Map<String, Disposable> DISPOSABLE_MAP = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public static boolean exists(String name) {
|
||||||
|
return DISPOSABLE_MAP.containsKey(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Disposable get(String name) {
|
||||||
|
return DISPOSABLE_MAP.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Disposable create(String name) {
|
||||||
|
disposeOf(name); //get rid of existing ones, if there is one, to prevent memory leaks
|
||||||
|
Disposable res = Disposer.newDisposable(name);
|
||||||
|
DISPOSABLE_MAP.put(name, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Disposable getOrCreate(String name) {
|
||||||
|
Disposable disposable = DISPOSABLE_MAP.get(name);
|
||||||
|
if(disposable == null)
|
||||||
|
disposable = create(name);
|
||||||
|
return disposable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean track(String name, Disposable disposable) {
|
||||||
|
boolean replaced = exists(name);
|
||||||
|
if(replaced)
|
||||||
|
disposeOf(name);
|
||||||
|
DISPOSABLE_MAP.put(name, disposable);
|
||||||
|
return replaced;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean disposeOf(String name) {
|
||||||
|
if(exists(name)) {
|
||||||
|
Disposable disposable = DISPOSABLE_MAP.remove(name);
|
||||||
|
Disposer.dispose(disposable);
|
||||||
|
return true;
|
||||||
|
} else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean disposeOf(Disposable disposable) {
|
||||||
|
if(DISPOSABLE_MAP.containsValue(disposable)) {
|
||||||
|
return DISPOSABLE_MAP.entrySet().removeIf(entry -> {
|
||||||
|
if(entry.getValue().equals(disposable)) {
|
||||||
|
Disposer.dispose(disposable, false);
|
||||||
|
return true;
|
||||||
|
} else return false;
|
||||||
|
});
|
||||||
|
} else return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,16 +27,24 @@
|
||||||
<add-to-group group-id="ToolsMenu" anchor="first"/>
|
<add-to-group group-id="ToolsMenu" anchor="first"/>
|
||||||
<action id="codemp.fast-forward" class="com.codemp.intellij.actions.FastForwardAction" text="Just Hurry"/>
|
<action id="codemp.fast-forward" class="com.codemp.intellij.actions.FastForwardAction" text="Just Hurry"/>
|
||||||
<action id="codemp.connect" class="com.codemp.intellij.actions.ConnectAction" text="Connect..."/>
|
<action id="codemp.connect" class="com.codemp.intellij.actions.ConnectAction" text="Connect..."/>
|
||||||
<action id="codemp.join" class="com.codemp.intellij.actions.JoinAction" text="Join..."/>
|
|
||||||
<group id="codemp.buffer" text="Buffer" popup="true">
|
<group id="codemp.workspace" text="Workspace" popup="true">
|
||||||
<action id="codemp.buffer.create" class="com.codemp.intellij.actions.buffer.BufferCreateAction"
|
<action id="codemp.workspace.join" class="com.codemp.intellij.actions.workspace.WorkspaceJoinAction"
|
||||||
text="Create Buffer"/>
|
text="Join Workspace"/>
|
||||||
<action id="codemp.buffer.create-with-content"
|
<action id="codemp.workspace.leave" class="com.codemp.intellij.actions.workspace.WorkspaceLeaveAction"
|
||||||
class="com.codemp.intellij.actions.buffer.BufferCreateWithContentAction"
|
text="Leave Workspace"/>
|
||||||
text="Create Buffer with Content"/>
|
</group>
|
||||||
<action id="codemp.buffer.attach" class="com.codemp.intellij.actions.buffer.BufferAttachAction"
|
<group id="codemp.buffer" text="Buffer" popup="true">
|
||||||
text="Attach to Buffer"/>
|
<action id="codemp.buffer.create" class="com.codemp.intellij.actions.buffer.BufferCreateAction"
|
||||||
</group>
|
text="Create Buffer"/>
|
||||||
|
<action id="codemp.buffer.create-with-content"
|
||||||
|
class="com.codemp.intellij.actions.buffer.BufferCreateWithContentAction"
|
||||||
|
text="Create Buffer with Content"/>
|
||||||
|
<action id="codemp.buffer.attach" class="com.codemp.intellij.actions.buffer.BufferAttachAction"
|
||||||
|
text="Attach to Buffer"/>
|
||||||
|
<action id="codemp.buffer.detach" class="com.codemp.intellij.actions.buffer.BufferDetachAction"
|
||||||
|
text="Detach from Buffer"/>
|
||||||
|
</group>
|
||||||
</group>
|
</group>
|
||||||
</actions>
|
</actions>
|
||||||
|
|
||||||
|
@ -44,4 +52,4 @@
|
||||||
<!-- Extension points defined by the plugin.
|
<!-- Extension points defined by the plugin.
|
||||||
Read more: https://plugins.jetbrains.com/docs/intellij/plugin-extension-points.html -->
|
Read more: https://plugins.jetbrains.com/docs/intellij/plugin-extension-points.html -->
|
||||||
</extensions>
|
</extensions>
|
||||||
</idea-plugin>
|
</idea-plugin>
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use codemp::Error;
|
||||||
use codemp::prelude::CodempError;
|
use codemp::prelude::CodempError;
|
||||||
|
|
||||||
pub struct ErrorWrapper(CodempError);
|
pub struct ErrorWrapper(CodempError);
|
||||||
|
@ -15,6 +16,7 @@ impl ErrorWrapper {
|
||||||
format!("Error {}: {}", status, message),
|
format!("Error {}: {}", status, message),
|
||||||
CodempError::InvalidState { msg } => msg.to_string(),
|
CodempError::InvalidState { msg } => msg.to_string(),
|
||||||
CodempError::Filler { message } => message.to_string(),
|
CodempError::Filler { message } => message.to_string(),
|
||||||
|
Error::Deadlocked => { "Error: deadlocked! (safe to retry)".to_string() }
|
||||||
CodempError::Channel { send } => {
|
CodempError::Channel { send } => {
|
||||||
if *send {
|
if *send {
|
||||||
"Error while sending message on channel: the channel was closed!".to_string()
|
"Error while sending message on channel: the channel was closed!".to_string()
|
||||||
|
@ -22,6 +24,6 @@ impl ErrorWrapper {
|
||||||
"Error while reading message from channel: the channel was closed!".to_string()
|
"Error while reading message from channel: the channel was closed!".to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,11 @@ impl CodeMPHandler {
|
||||||
convert_buffer(CODEMP_INSTANCE.attach(&path))
|
convert_buffer(CODEMP_INSTANCE.attach(&path))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[generate_interface]
|
||||||
|
fn detach(path: String) -> Result<bool, String> {
|
||||||
|
convert(CODEMP_INSTANCE.disconnect_buffer(&path))
|
||||||
|
}
|
||||||
|
|
||||||
#[generate_interface]
|
#[generate_interface]
|
||||||
fn get_cursor() -> Result<CursorHandler, String> {
|
fn get_cursor() -> Result<CursorHandler, String> {
|
||||||
convert_cursor(CODEMP_INSTANCE.get_cursor())
|
convert_cursor(CODEMP_INSTANCE.get_cursor())
|
||||||
|
@ -154,8 +159,8 @@ impl CursorHandler {
|
||||||
fn send(&self, buffer: String, start_row: i32, start_col: i32, end_row: i32, end_col: i32) -> Result<(), String> {
|
fn send(&self, buffer: String, start_row: i32, start_col: i32, end_row: i32, end_col: i32) -> Result<(), String> {
|
||||||
self.cursor.send(CodempCursorPosition {
|
self.cursor.send(CodempCursorPosition {
|
||||||
buffer,
|
buffer,
|
||||||
start: Some(CodempRowCol { row: start_row, col: start_col }),
|
start: CodempRowCol::wrap(start_row, start_col),
|
||||||
end: Some(CodempRowCol { row: end_row, col: end_col })
|
end: CodempRowCol::wrap(end_row, end_col)
|
||||||
}).map_err(|err| ErrorWrapper::from(err).get_error_message())
|
}).map_err(|err| ErrorWrapper::from(err).get_error_message())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,20 +210,17 @@ impl BufferHandler {
|
||||||
fn recv(&self) -> Result<TextChangeWrapper, String> {
|
fn recv(&self) -> Result<TextChangeWrapper, String> {
|
||||||
match self.buffer.blocking_recv(CODEMP_INSTANCE.rt()) {
|
match self.buffer.blocking_recv(CODEMP_INSTANCE.rt()) {
|
||||||
Err(err) => Err(ErrorWrapper::from(err).get_error_message()),
|
Err(err) => Err(ErrorWrapper::from(err).get_error_message()),
|
||||||
Ok(change) => {
|
Ok(change) => Ok(TextChangeWrapper {
|
||||||
println!("test {:?}", change);
|
start: change.span.start,
|
||||||
Ok(TextChangeWrapper {
|
end: change.span.end,
|
||||||
start: change.span.start,
|
content: change.content.clone()
|
||||||
end: change.span.end,
|
})
|
||||||
content: change.content.clone()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[generate_interface]
|
#[generate_interface]
|
||||||
fn send(&self, start_offset: usize, end_offset: usize, content: String) -> Result<(), String> {
|
fn send(&self, start_offset: usize, end_offset: usize, content: String) -> Result<(), String> {
|
||||||
self.buffer.send(CodempTextChange { span: start_offset..end_offset, content, after: "".to_string() })
|
self.buffer.send(CodempTextChange { span: start_offset..end_offset, content })
|
||||||
.map_err(|err| ErrorWrapper::from(err).get_error_message())
|
.map_err(|err| ErrorWrapper::from(err).get_error_message())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue