Comrade
IntelliJ를 NeoVim 플러그인으로 사용하기
개요
IntelliJ와 NeoVim을 연동해서 파일 변경사항을 동기화하고, 자동완성과 린팅 등을 IntelliJ에서 받아와 NeoVim에서 사용할 수 있게 해주는 플러그인.
- beeender/Comrade - NeoVim에 설치하는 플러그인
- beeender/ComradeNeovim - IntelliJ에 설치하는 플러그인
플러그인이 두 개가 있으며, 각각 IntelliJ와 NeoVim에 설치하여 이 둘을 통해 IntelliJ와 NeoVim이 연동되는 방식이다.
그러나 Comrade는 2020년, ComradeNeovim은 2019년 이후로는 전혀 유지보수가 되지 않는 상태.
- ComradeNeovim
- Java 버전으로 1.8 사용
- IntelliJ Platform Plugin SDK 0.4.7 버전 사용
- (2022년 3월 현재 최신 버전은 1.13.2)
문제 해결
Apple Silicon에서 작동하지 않는 문제 해결
Intel 맥에서는 문제없이 잘 작동했으나 내 M2 프로세서 Apple Silicon이 장착된 Mac Mini에서는 작동하지 않는 문제가 있었다.
원인이 되는 곳은 다음 코드였다.
import org.scalasbt.ipcsocket.UnixDomainSocket
// ↑ 여기가 문제!
private fun createRPCConnection(address: String): NeovimConnection {
Log.info("Creating RPC connection from '$address'")
val ipInfo = parseIPV4String(address)
if (ipInfo!= null)
return SocketConnection(Socket(ipInfo.first, ipInfo.second))
else {
val file = File(address)
if (file.exists())
return SocketConnection(
if (isWindows()) Win32NamedPipeSocketPatched(address)
else UnixDomainSocket(address))
// ↑ 여기가 문제!
}
throw IllegalArgumentException("Cannot create RPC connection from given address: '$address'.")
}
해결 과정을 나열해 보자면 다음과 같다.
- sbt의
UnixDomainSocket
을 사용하면UnsupportedOperationException
("Not supported")
가 던져진다. - 왜 그런가? 로그 코드를 추가하고, 빌드하고, IntelliJ에 설치한 다음, IntelliJ 로그를 보면서 확인.
sun.nio.ch. SocketChannelImpl.java
@Override
public Socket socket() {
synchronized (stateLock) {
if (socket == null) {
if (isNetSocket()) {
socket = SocketAdaptor.create(this);
} else {
throw new UnsupportedOperationException("Not supported");
// ↑ 여기에서 던진다
}
}
return socket;
}
}
소켓을 생성해 리턴하는 코드를 보면 isNetSocket()
을 호출하는데, Comrade는 net socket이 아니라 unix domain socket을 사용하기 때문에 작동하지 않았던 것이다.
isNetSocket()
과 isUnixSocket()
/**
* Returns true if this channel is to a INET or INET6 socket.
*/
boolean isNetSocket() {
return (family == INET) || (family == INET6);
}
/**
* Returns true if this channel is to a UNIX socket.
*/
boolean isUnixSocket() {
return (family == UNIX);
}
이걸 해결하기 위해 사흘간 다양한 시도를 해 보았고 그 과정에서 새로 알게 된 것들이 몇 가지 있었다.
- Java 16 부터 Unix domain socket 이 지원된다. (
SocketChannel
,ServerSocketChannel
) - ComradeNeovim에서 사용하고 있는 org.scalasbt.ipcsocket. UnixDomainSocket은 Apple Silicon을 아직 지원하지 않는다.
- junixsocket — Unix Domain Sockets for Java은 Apple Silicon도 지원한다.
삽질을 많이 하긴 했지만 결론적으로 sbt의 UnixDomainSocket
을 junixsocket의 AFUNIXSocket
으로 교체하여 해결할 수 있었다.
다음은 문제를 해결한 코드이다.
Merge: Fix Apple Silicon issue
createRPCConnection
함수를 좀 수정했다.
import org.newsclub.net.unix.AFUNIXSocket
import org.newsclub.net.unix.AFUNIXSocketAddress
private fun createRPCConnection(address: String): NeovimConnection {
Log.info("Creating RPC connection from '$address'")
val ipInfo = parseIPV4String(address)
if (ipInfo!= null) {
return SocketConnection(Socket(ipInfo.first, ipInfo.second))
}
val file = File(address)
if (!file.exists()) {
throw IllegalArgumentException("Cannot create RPC connection from given address: '$address'.")
}
if (isWindows()) {
return SocketConnection(Win32NamedPipeSocketPatched(address))
}
// ↓ AFUNIXSocket을 사용해 문제 해결
val socket : AFUNIXSocket = AFUNIXSocket.newInstance()
socket.connect(AFUNIXSocketAddress.of(File(address)))
return SocketConnection(socket)
}
IntelliJ, Java 버전업
최신 버전의 IntelliJ 기준으로 빌드가 되지 않는 문제를 해결했다.
아무도 merge 해주지 않는다는 걸 알지만.. 일단 PR은 올려뒀다.