mirror of
https://github.com/hexedtech/codemp-intellij.git
synced 2024-12-04 20:04:52 +01:00
fix: cursor and buffer not syncing when overloaded with cursor movements
This commit is contained in:
parent
70bd32a686
commit
7ae82c83c0
5 changed files with 63 additions and 23 deletions
|
@ -15,8 +15,7 @@ public class BufferAttachAction extends AnAction {
|
||||||
public static void attach(AnActionEvent e, String buffer, boolean silent) {
|
public static void attach(AnActionEvent e, String buffer, boolean silent) {
|
||||||
BufferHandler bufferHandler = CodeMPHandler.attach(buffer);
|
BufferHandler bufferHandler = CodeMPHandler.attach(buffer);
|
||||||
if(!silent) ActionUtil.notify(e, "Success",
|
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);
|
CodeMP.LOGGER.debug("Attached to buffer to {}!", buffer);
|
||||||
|
|
||||||
//TODO "get" the Editor corresponding to buffer, for now use the current one
|
//TODO "get" the Editor corresponding to buffer, for now use the current one
|
||||||
|
|
|
@ -5,6 +5,7 @@ import com.codemp.intellij.exceptions.lib.ChannelException;
|
||||||
import com.codemp.intellij.exceptions.lib.DeadlockedException;
|
import com.codemp.intellij.exceptions.lib.DeadlockedException;
|
||||||
import com.codemp.intellij.jni.BufferHandler;
|
import com.codemp.intellij.jni.BufferHandler;
|
||||||
import com.codemp.intellij.jni.CodeMPHandler;
|
import com.codemp.intellij.jni.CodeMPHandler;
|
||||||
|
import com.codemp.intellij.jni.StringVec;
|
||||||
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.intellij.openapi.Disposable;
|
import com.intellij.openapi.Disposable;
|
||||||
|
@ -22,6 +23,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class BufferEventAwaiterTask extends Task.Backgroundable implements Disposable {
|
public class BufferEventAwaiterTask extends Task.Backgroundable implements Disposable {
|
||||||
private final Map<String, Disposable> bufferListeners = new ConcurrentHashMap<>();
|
private final Map<String, Disposable> bufferListeners = new ConcurrentHashMap<>();
|
||||||
|
private final Set<String> initialisedBuffers = Collections.newSetFromMap(new ConcurrentHashMap<>()); //also tonioware
|
||||||
|
|
||||||
public BufferEventAwaiterTask(@NotNull Project project) {
|
public BufferEventAwaiterTask(@NotNull Project project) {
|
||||||
super(project, "Awaiting CodeMP buffer events", false);
|
super(project, "Awaiting CodeMP buffer events", false);
|
||||||
|
@ -41,6 +43,8 @@ public class BufferEventAwaiterTask extends Task.Backgroundable implements Dispo
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unregisterListener(String name) {
|
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);
|
Disposable listener = this.bufferListeners.remove(name);
|
||||||
if(listener != null)
|
if(listener != null)
|
||||||
listener.dispose();
|
listener.dispose();
|
||||||
|
@ -50,17 +54,25 @@ public class BufferEventAwaiterTask extends Task.Backgroundable implements Dispo
|
||||||
public void dispose() {}
|
public void dispose() {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings({"InfiniteLoopStatement", "UnstableApiUsage"})
|
@SuppressWarnings({"InfiniteLoopStatement", "UnstableApiUsage", "BusyWait"})
|
||||||
public void run(@NotNull ProgressIndicator indicator) {
|
public void run(@NotNull ProgressIndicator indicator) {
|
||||||
try {
|
|
||||||
Thread.sleep(100); //tonioware
|
|
||||||
} catch(InterruptedException ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while(true) {
|
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);
|
BufferHandler handler = CodeMPHandler.getBuffer(buffer);
|
||||||
|
|
||||||
List<TextChangeWrapper> changeList = new ArrayList<>();
|
List<TextChangeWrapper> changeList = new ArrayList<>();
|
||||||
|
@ -81,7 +93,6 @@ public class BufferEventAwaiterTask extends Task.Backgroundable implements Dispo
|
||||||
}
|
}
|
||||||
|
|
||||||
Editor bufferEditor = CodeMP.ACTIVE_BUFFERS.get(buffer);
|
Editor bufferEditor = CodeMP.ACTIVE_BUFFERS.get(buffer);
|
||||||
|
|
||||||
ApplicationManager.getApplication().invokeLaterOnWriteThread(() ->
|
ApplicationManager.getApplication().invokeLaterOnWriteThread(() ->
|
||||||
ApplicationManager.getApplication().runWriteAction(() ->
|
ApplicationManager.getApplication().runWriteAction(() ->
|
||||||
CommandProcessor.getInstance().executeCommand(
|
CommandProcessor.getInstance().executeCommand(
|
||||||
|
|
|
@ -69,11 +69,7 @@ public class CursorEventAwaiterTask extends Task.Backgroundable implements Dispo
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RangeHighlighter highlighter = this.highlighterMap.get(event.getUser());
|
RangeHighlighter previous = this.highlighterMap.put(event.getUser(), editor
|
||||||
if(highlighter != null)
|
|
||||||
highlighter.dispose();
|
|
||||||
|
|
||||||
this.highlighterMap.put(event.getUser(), editor
|
|
||||||
.getMarkupModel()
|
.getMarkupModel()
|
||||||
.addRangeHighlighter(
|
.addRangeHighlighter(
|
||||||
startOffset,
|
startOffset,
|
||||||
|
@ -87,6 +83,9 @@ public class CursorEventAwaiterTask extends Task.Backgroundable implements Dispo
|
||||||
Font.PLAIN
|
Font.PLAIN
|
||||||
), HighlighterTargetArea.EXACT_RANGE
|
), HighlighterTargetArea.EXACT_RANGE
|
||||||
));
|
));
|
||||||
|
|
||||||
|
if(previous != null)
|
||||||
|
previous.dispose();
|
||||||
});
|
});
|
||||||
} catch(IndexOutOfBoundsException ignored) {}
|
} catch(IndexOutOfBoundsException ignored) {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)"
|
($p:f_type, unique_prefix="/*err*/") => "/*err*/swig_f_type!(T)" "swig_foreign_from_i_type!(T, $p)";
|
||||||
"swig_foreign_from_i_type!(T, $p)";
|
|
||||||
);
|
);
|
|
@ -1,5 +1,7 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
use codemp::prelude::*;
|
use codemp::prelude::*;
|
||||||
|
use codemp::tools;
|
||||||
use rifgen::rifgen_attr::{generate_access_methods, generate_interface, generate_interface_doc};
|
use rifgen::rifgen_attr::{generate_access_methods, generate_interface, generate_interface_doc};
|
||||||
|
|
||||||
pub mod glue { //rifgen generated code
|
pub mod glue { //rifgen generated code
|
||||||
|
@ -66,8 +68,16 @@ impl CodeMPHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[generate_interface]
|
#[generate_interface]
|
||||||
fn select_buffer() -> CodempResult<String> {
|
fn select_buffer(mut buffer_ids: StringVec, timeout: i64) -> CodempResult<Option<String>> {
|
||||||
CODEMP_INSTANCE.select_buffer()
|
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 {
|
impl CursorHandler {
|
||||||
#[generate_interface(constructor)]
|
#[generate_interface(constructor)]
|
||||||
fn new() -> CursorHandler {
|
fn new() -> CursorHandler {
|
||||||
panic!("Default constructor for CursorHandler should never be called!")
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[generate_interface]
|
#[generate_interface]
|
||||||
|
@ -137,7 +147,7 @@ struct BufferHandler {
|
||||||
impl BufferHandler {
|
impl BufferHandler {
|
||||||
#[generate_interface(constructor)]
|
#[generate_interface(constructor)]
|
||||||
fn new() -> BufferHandler {
|
fn new() -> BufferHandler {
|
||||||
panic!("Default constructor for BufferHandler should never be called!")
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[generate_interface]
|
#[generate_interface]
|
||||||
|
@ -145,6 +155,11 @@ impl BufferHandler {
|
||||||
self.buffer.name.clone()
|
self.buffer.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[generate_interface]
|
||||||
|
fn get_content(&self) -> String {
|
||||||
|
self.buffer.content()
|
||||||
|
}
|
||||||
|
|
||||||
#[generate_interface]
|
#[generate_interface]
|
||||||
fn try_recv(&self) -> CodempResult<Option<TextChangeWrapper>> {
|
fn try_recv(&self) -> CodempResult<Option<TextChangeWrapper>> {
|
||||||
match self.buffer.try_recv() {
|
match self.buffer.try_recv() {
|
||||||
|
@ -175,3 +190,20 @@ impl BufferHandler {
|
||||||
self.buffer.send(CodempTextChange { span: start_offset..end_offset, content })
|
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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue