fix: cursor and buffer not syncing when overloaded with cursor movements

This commit is contained in:
zaaarf 2023-11-29 00:32:02 +01:00
parent 70bd32a686
commit 7ae82c83c0
No known key found for this signature in database
GPG key ID: 6445A5CD15E5B40C
5 changed files with 63 additions and 23 deletions

View file

@ -15,8 +15,7 @@ public class BufferAttachAction extends AnAction {
public static void attach(AnActionEvent e, String buffer, boolean silent) {
BufferHandler bufferHandler = CodeMPHandler.attach(buffer);
if(!silent) ActionUtil.notify(e, "Success",
String.format("Successfully attached to buffer to buffer to %s!", buffer)
);
String.format("Successfully attached to buffer to buffer to %s!", buffer));
CodeMP.LOGGER.debug("Attached to buffer to {}!", buffer);
//TODO "get" the Editor corresponding to buffer, for now use the current one

View file

@ -5,6 +5,7 @@ import com.codemp.intellij.exceptions.lib.ChannelException;
import com.codemp.intellij.exceptions.lib.DeadlockedException;
import com.codemp.intellij.jni.BufferHandler;
import com.codemp.intellij.jni.CodeMPHandler;
import com.codemp.intellij.jni.StringVec;
import com.codemp.intellij.jni.TextChangeWrapper;
import com.codemp.intellij.listeners.BufferEventListener;
import com.intellij.openapi.Disposable;
@ -22,6 +23,7 @@ import java.util.concurrent.ConcurrentHashMap;
public class BufferEventAwaiterTask extends Task.Backgroundable implements Disposable {
private final Map<String, Disposable> bufferListeners = new ConcurrentHashMap<>();
private final Set<String> initialisedBuffers = Collections.newSetFromMap(new ConcurrentHashMap<>()); //also tonioware
public BufferEventAwaiterTask(@NotNull Project project) {
super(project, "Awaiting CodeMP buffer events", false);
@ -41,6 +43,8 @@ public class BufferEventAwaiterTask extends Task.Backgroundable implements Dispo
}
public void unregisterListener(String name) {
CodeMP.ACTIVE_BUFFERS_REVERSE.remove(CodeMP.ACTIVE_BUFFERS.remove(name));
this.initialisedBuffers.remove(name);
Disposable listener = this.bufferListeners.remove(name);
if(listener != null)
listener.dispose();
@ -50,17 +54,25 @@ public class BufferEventAwaiterTask extends Task.Backgroundable implements Dispo
public void dispose() {}
@Override
@SuppressWarnings({"InfiniteLoopStatement", "UnstableApiUsage"})
@SuppressWarnings({"InfiniteLoopStatement", "UnstableApiUsage", "BusyWait"})
public void run(@NotNull ProgressIndicator indicator) {
try {
Thread.sleep(100); //tonioware
} catch(InterruptedException ex) {
throw new RuntimeException(ex);
}
try {
while(true) {
String buffer = CodeMPHandler.selectBuffer();
StringVec buffers = new StringVec(); //jni moment
CodeMP.ACTIVE_BUFFERS.keySet().forEach(buffers::push);
Optional<String> bufferOptional = CodeMPHandler.selectBuffer(buffers, 100L);
if(bufferOptional.isEmpty())
continue;
String buffer = bufferOptional.get();
if(!this.initialisedBuffers.contains(buffer)) { //tonioware
try {
Thread.sleep(100);
} catch(InterruptedException ignored) {}
this.initialisedBuffers.add(buffer);
}
BufferHandler handler = CodeMPHandler.getBuffer(buffer);
List<TextChangeWrapper> changeList = new ArrayList<>();
@ -81,7 +93,6 @@ public class BufferEventAwaiterTask extends Task.Backgroundable implements Dispo
}
Editor bufferEditor = CodeMP.ACTIVE_BUFFERS.get(buffer);
ApplicationManager.getApplication().invokeLaterOnWriteThread(() ->
ApplicationManager.getApplication().runWriteAction(() ->
CommandProcessor.getInstance().executeCommand(

View file

@ -69,11 +69,7 @@ public class CursorEventAwaiterTask extends Task.Backgroundable implements Dispo
return;
}
RangeHighlighter highlighter = this.highlighterMap.get(event.getUser());
if(highlighter != null)
highlighter.dispose();
this.highlighterMap.put(event.getUser(), editor
RangeHighlighter previous = this.highlighterMap.put(event.getUser(), editor
.getMarkupModel()
.addRangeHighlighter(
startOffset,
@ -87,6 +83,9 @@ public class CursorEventAwaiterTask extends Task.Backgroundable implements Dispo
Font.PLAIN
), HighlighterTargetArea.EXACT_RANGE
));
if(previous != null)
previous.dispose();
});
} catch(IndexOutOfBoundsException ignored) {}
}

View file

@ -35,6 +35,5 @@ foreign_typemap!( //thanks @tasn on GitHub for the idea
}
};
};
($p:f_type, unique_prefix="/*codemp::prelude::CodempResult<swig_subst_type!(T)>*/") => "/*codemp::prelude::CodempResult<swig_subst_type!(T)>*/swig_f_type!(T)"
"swig_foreign_from_i_type!(T, $p)";
($p:f_type, unique_prefix="/*err*/") => "/*err*/swig_f_type!(T)" "swig_foreign_from_i_type!(T, $p)";
);

View file

@ -1,5 +1,7 @@
use std::sync::Arc;
use std::time::Duration;
use codemp::prelude::*;
use codemp::tools;
use rifgen::rifgen_attr::{generate_access_methods, generate_interface, generate_interface_doc};
pub mod glue { //rifgen generated code
@ -66,8 +68,16 @@ impl CodeMPHandler {
}
#[generate_interface]
fn select_buffer() -> CodempResult<String> {
CODEMP_INSTANCE.select_buffer()
fn select_buffer(mut buffer_ids: StringVec, timeout: i64) -> CodempResult<Option<String>> {
let mut buffers = Vec::new();
for id in buffer_ids.v.iter_mut() {
match CODEMP_INSTANCE.get_buffer(id.as_str()) {
Ok(buf) => buffers.push(buf),
Err(_) => continue
}
}
CODEMP_INSTANCE.rt().block_on(
tools::select_buffer_timeout(&buffers, Duration::from_millis(timeout as u64)))
}
}
@ -92,7 +102,7 @@ struct CursorHandler {
impl CursorHandler {
#[generate_interface(constructor)]
fn new() -> CursorHandler {
panic!("Default constructor for CursorHandler should never be called!")
unimplemented!()
}
#[generate_interface]
@ -137,7 +147,7 @@ struct BufferHandler {
impl BufferHandler {
#[generate_interface(constructor)]
fn new() -> BufferHandler {
panic!("Default constructor for BufferHandler should never be called!")
unimplemented!()
}
#[generate_interface]
@ -145,6 +155,11 @@ impl BufferHandler {
self.buffer.name.clone()
}
#[generate_interface]
fn get_content(&self) -> String {
self.buffer.content()
}
#[generate_interface]
fn try_recv(&self) -> CodempResult<Option<TextChangeWrapper>> {
match self.buffer.try_recv() {
@ -175,3 +190,20 @@ impl BufferHandler {
self.buffer.send(CodempTextChange { span: start_offset..end_offset, content })
}
}
#[generate_interface_doc]
struct StringVec { //jni moment
v: Vec<String>
}
impl StringVec {
#[generate_interface(constructor)]
fn new() -> StringVec {
Self { v: Vec::new() }
}
#[generate_interface]
fn push(&mut self, s: String) {
self.v.push(s);
}
}