1
1
mirror of https://github.com/qvacua/vimr.git synced 2024-12-18 11:11:34 +03:00
vimr/NvimView/NvimServer/NvimServer.m

222 lines
5.1 KiB
Mathematica
Raw Normal View History

/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
2017-12-20 23:35:36 +03:00
#import "NvimServer.h"
2018-03-20 09:53:46 +03:00
#import "server_ui.h"
2016-07-10 15:43:26 +03:00
#import "Logging.h"
#import "CocoaCategories.h"
2019-03-03 23:57:03 +03:00
// FileInfo and Boolean are #defined by Carbon and NeoVim.
// Since we don't need the Carbon versions of them, we rename them.
#define FileInfo CarbonFileInfo
#define Boolean CarbonBoolean
#import <nvim/main.h>
2019-03-03 23:57:03 +03:00
// When #define'd you can execute the NvimServer binary
// and neovim will be started:
2017-12-20 23:35:36 +03:00
// $ ./NvimServer local remote
#undef DEBUG_NEOVIM_SERVER_STANDALONE
//#define DEBUG_NEOVIM_SERVER_STANDALONE
static const double qTimeout = 5;
2016-07-09 23:52:59 +03:00
2017-12-20 23:35:36 +03:00
@interface NvimServer ()
2016-07-09 23:52:59 +03:00
- (NSArray<NSString *> *)nvimArgs;
2016-07-09 23:52:59 +03:00
@end
static CFDataRef data_async(CFDataRef data, argv_callback cb) {
loop_schedule(&main_loop, event_create(cb, 3, data));
return NULL;
}
2019-03-03 23:57:03 +03:00
static CFDataRef local_server_callback(
CFMessagePortRef local, SInt32 msgid, CFDataRef data, void *info
) {
// release in the loop callbacks!
// (or in the case clause when not passed to the callback)
CFRetain(data);
2018-05-11 11:41:08 +03:00
switch (msgid) {
2018-05-11 11:41:08 +03:00
case NvimBridgeMsgIdAgentReady: {
@autoreleasepool {
NSInteger *values = (NSInteger *) CFDataGetBytePtr(data);
2018-05-11 11:41:08 +03:00
NvimServer *nvimServer = (__bridge NvimServer *) info;
start_neovim(values[0], values[1], nvimServer.nvimArgs);
CFRelease(data);
}
2018-05-11 11:41:08 +03:00
return NULL;
}
2017-01-06 12:16:55 +03:00
2018-05-11 11:41:08 +03:00
case NvimBridgeMsgIdScroll:
return data_async(data, neovim_scroll);
2017-05-30 23:13:52 +03:00
2018-05-11 11:41:08 +03:00
case NvimBridgeMsgIdResize:
return data_async(data, neovim_resize);
2018-05-11 11:41:08 +03:00
case NvimBridgeMsgIdInput:
return data_async(data, neovim_vim_input);
2017-01-06 12:06:47 +03:00
2018-10-03 15:36:28 +03:00
case NvimBridgeMsgIdDeleteInput:
return data_async(data, neovim_delete_and_input);
2018-05-11 11:41:08 +03:00
case NvimBridgeMsgIdFocusGained:
return data_async(data, neovim_focus_gained);
case NvimBridgeMsgIdReadyForRpcEvents:
return data_async(data, neovim_ready_for_rpcevents);
2018-05-11 11:41:08 +03:00
default:
2018-05-13 12:09:40 +03:00
CFRelease(data);
2018-05-11 11:41:08 +03:00
return NULL;
}
}
2017-12-20 23:35:36 +03:00
@implementation NvimServer {
NSString *_localServerName;
NSString *_remoteServerName;
NSArray<NSString *> *_nvimArgs;
CFMessagePortRef _remoteServerPort;
NSThread *_localServerThread;
CFMessagePortRef _localServerPort;
CFRunLoopRef _localServerRunLoop;
}
- (NSArray<NSString *> *)nvimArgs {
return _nvimArgs;
}
- (instancetype)initWithLocalServerName:(NSString *)localServerName
remoteServerName:(NSString *)remoteServerName
2018-05-11 11:41:08 +03:00
nvimArgs:(NSArray<NSString *> *)nvimArgs {
self = [super init];
if (self == nil) {
return nil;
}
2016-07-10 15:24:45 +03:00
_localServerName = localServerName;
_remoteServerName = remoteServerName;
_nvimArgs = nvimArgs;
2019-03-03 23:57:03 +03:00
_localServerThread = [
[NSThread alloc] initWithTarget:self
selector:@selector(runLocalServer)
object:nil
];
_localServerThread.name = localServerName;
[_localServerThread start];
#ifndef DEBUG_NEOVIM_SERVER_STANDALONE
2019-03-03 23:57:03 +03:00
_remoteServerPort = CFMessagePortCreateRemote(
kCFAllocatorDefault,
(__bridge CFStringRef) _remoteServerName
);
#endif
return self;
}
- (void)dealloc {
if (CFMessagePortIsValid(_remoteServerPort)) {
CFMessagePortInvalidate(_remoteServerPort);
}
CFRelease(_remoteServerPort);
if (CFMessagePortIsValid(_localServerPort)) {
CFMessagePortInvalidate(_localServerPort);
}
CFRelease(_localServerPort);
CFRunLoopStop(_localServerRunLoop);
[_localServerThread cancel];
}
- (void)runLocalServer {
@autoreleasepool {
unsigned char shouldFree = false;
CFMessagePortContext localContext = {
.version = 0,
2016-07-10 15:24:45 +03:00
.info = (__bridge void *) self,
.retain = NULL,
.release = NULL,
.copyDescription = NULL
};
_localServerPort = CFMessagePortCreateLocal(
kCFAllocatorDefault,
2016-07-10 15:24:45 +03:00
(__bridge CFStringRef) _localServerName,
local_server_callback,
&localContext,
&shouldFree
);
// FIXME: handle shouldFree == true
}
2016-07-10 15:10:09 +03:00
_localServerRunLoop = CFRunLoopGetCurrent();
2019-03-03 23:57:03 +03:00
CFRunLoopSourceRef runLoopSrc
= CFMessagePortCreateRunLoopSource(
kCFAllocatorDefault,
_localServerPort,
0
);
CFRunLoopAddSource(_localServerRunLoop, runLoopSrc, kCFRunLoopCommonModes);
2016-07-10 15:10:09 +03:00
CFRelease(runLoopSrc);
#ifdef DEBUG_NEOVIM_SERVER_STANDALONE
server_start_neovim();
#endif
2016-07-10 15:10:09 +03:00
CFRunLoopRun();
}
2018-01-23 22:40:20 +03:00
- (void)sendMessageWithId:(NvimServerMsgId)msgid {
2018-05-13 10:29:15 +03:00
[self sendMessageWithId:msgid data:NULL];
}
2018-05-13 10:29:15 +03:00
- (void)sendMessageWithId:(NvimServerMsgId)msgid data:(CFDataRef)data {
#ifdef DEBUG_NEOVIM_SERVER_STANDALONE
return;
#endif
2016-07-09 23:52:59 +03:00
if (_remoteServerPort == NULL) {
2019-03-03 23:57:03 +03:00
WLOG("Remote server is null: The msg (%lu) could not be sent.",
(unsigned long) msgid);
2016-07-09 23:52:59 +03:00
return;
}
2019-03-03 23:57:03 +03:00
SInt32 responseCode = CFMessagePortSendRequest(
_remoteServerPort, msgid, data, qTimeout, qTimeout, NULL, NULL
);
if (responseCode == kCFMessagePortSuccess) {
return;
}
2019-03-03 23:57:03 +03:00
WLOG("The msg (%lu) could not be sent: %d",
(unsigned long) msgid, responseCode);
}
- (void)notifyReadiness {
#ifndef DEBUG_NEOVIM_SERVER_STANDALONE
2018-05-13 10:29:15 +03:00
[self sendMessageWithId:NvimServerMsgIdServerReady data:NULL];
#endif
}
@end