1
1
mirror of https://github.com/qvacua/vimr.git synced 2024-12-25 06:43:24 +03:00

Make NvimServer (only) a CoreFoundation exe

This commit is contained in:
Tae Won Ha 2019-03-25 10:35:55 +01:00
parent b5282a89a8
commit 9912e538ac
No known key found for this signature in database
GPG Key ID: E40743465B5B8B44
21 changed files with 917 additions and 913 deletions

View File

@ -1,20 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
#import <Foundation/Foundation.h>
@interface NSObject (NeoVimServer)
@property (readonly, nonnull) const char *cdesc;
@end
@interface NSString (NeoVimServer)
@property (readonly, nonnull) const char *cstr;
@property (readonly) NSUInteger clength;
@end

View File

@ -1,18 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
#import "CocoaCategories.h"
@implementation NSString (NeoVimServer)
- (const char *)cstr {
return [self cStringUsingEncoding:NSUTF8StringEncoding];
}
- (NSUInteger)clength {
return [self lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
}
@end

View File

@ -1,9 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
#import <Foundation/Foundation.h>
#import <os/log.h>
extern os_log_t logger;

View File

@ -1,22 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
#import <Foundation/Foundation.h>
#import "SharedTypes.h"
@interface NvimServer : NSObject
- (instancetype)initWithLocalServerName:(NSString *)localServerName
remoteServerName:(NSString *)remoteServerName
nvimArgs:(NSArray<NSString *> *)nvimArgs;
- (void)sendMessageWithId:(NvimServerMsgId)msgid;
- (void)sendMessageWithId:(NvimServerMsgId)msgid data:(CFDataRef)data;
- (void)notifyReadiness;
@end

View File

@ -1,222 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
#import "NvimServer.h"
#import "server_ui.h"
#import "Logging.h"
// 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>
// When #define'd you can execute the NvimServer binary
// and neovim will be started:
// $ ./NvimServer local remote
#undef DEBUG_NEOVIM_SERVER_STANDALONE
//#define DEBUG_NEOVIM_SERVER_STANDALONE
static const double qTimeout = 5;
@interface NvimServer ()
- (NSArray<NSString *> *)nvimArgs;
@end
static CFDataRef data_async(CFDataRef data, argv_callback cb) {
loop_schedule(&main_loop, event_create(cb, 3, data));
return NULL;
}
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);
switch (msgid) {
case NvimBridgeMsgIdAgentReady: {
@autoreleasepool {
const NSInteger *const values = (NSInteger *) CFDataGetBytePtr(data);
NvimServer *const nvimServer = (__bridge NvimServer *) info;
start_neovim(values[0], values[1], nvimServer.nvimArgs);
CFRelease(data);
}
return NULL;
}
case NvimBridgeMsgIdScroll:
return data_async(data, neovim_scroll);
case NvimBridgeMsgIdResize:
return data_async(data, neovim_resize);
case NvimBridgeMsgIdDeleteInput:
return data_async(data, neovim_delete_and_input);
case NvimBridgeMsgIdFocusGained:
return data_async(data, neovim_focus_gained);
case NvimBridgeMsgIdReadyForRpcEvents:
return data_async(data, neovim_ready_for_rpcevents);
default:
CFRelease(data);
return NULL;
}
}
@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
nvimArgs:(NSArray<NSString *> *)nvimArgs {
self = [super init];
if (self == nil) {
return nil;
}
_localServerName = localServerName;
_remoteServerName = remoteServerName;
_nvimArgs = nvimArgs;
_localServerThread = [
[NSThread alloc] initWithTarget:self
selector:@selector(runLocalServer)
object:nil
];
_localServerThread.name = localServerName;
[_localServerThread start];
#ifndef DEBUG_NEOVIM_SERVER_STANDALONE
_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; // Carbon Boolean = unsigned char
CFMessagePortContext localContext = {
.version = 0,
.info = (__bridge void *) self,
.retain = NULL,
.release = NULL,
.copyDescription = NULL
};
_localServerPort = CFMessagePortCreateLocal(
kCFAllocatorDefault,
(__bridge CFStringRef) _localServerName,
local_server_callback,
&localContext,
&shouldFree
);
// FIXME: handle shouldFree == true
}
_localServerRunLoop = CFRunLoopGetCurrent();
CFRunLoopSourceRef const runLoopSrc = CFMessagePortCreateRunLoopSource(
kCFAllocatorDefault,
_localServerPort,
0
);
CFRunLoopAddSource(_localServerRunLoop, runLoopSrc, kCFRunLoopCommonModes);
CFRelease(runLoopSrc);
#ifdef DEBUG_NEOVIM_SERVER_STANDALONE
server_start_neovim();
#endif
CFRunLoopRun();
}
- (void)sendMessageWithId:(NvimServerMsgId)msgid {
[self sendMessageWithId:msgid data:NULL];
}
- (void)sendMessageWithId:(NvimServerMsgId)msgid data:(CFDataRef)data {
#ifdef DEBUG_NEOVIM_SERVER_STANDALONE
return;
#endif
if (_remoteServerPort == NULL) {
os_log_error(
logger,
"Remote server is null: The msg (%lu) could not be sent.",
(unsigned long) msgid
);
return;
}
SInt32 responseCode = CFMessagePortSendRequest(
_remoteServerPort, msgid, data, qTimeout, qTimeout, NULL, NULL
);
if (responseCode == kCFMessagePortSuccess) {
return;
}
os_log_error(
logger,
"The msg (%lu) could not be sent: %d",
(unsigned long) msgid, responseCode
);
}
- (void)notifyReadiness {
#ifndef DEBUG_NEOVIM_SERVER_STANDALONE
[self sendMessageWithId:NvimServerMsgIdServerReady data:NULL];
#endif
}
@end

View File

@ -0,0 +1,14 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
#ifndef NVIMSERVER_FOUNDATION_SHIM_H
#define NVIMSERVER_FOUNDATION_SHIM_H
#include <CoreFoundation/CoreFoundation.h>
#define NSInteger long
#define NSUInteger unsigned long
#endif // NVIMSERVER_FOUNDATION_SHIM_H

View File

@ -0,0 +1,64 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
#include "server_log.h"
#include "server.h"
os_log_t logger;
static void observe_parent_termination(void);
int main(int argc, const char *argv[]) {
logger = os_log_create("com.qvacua.NvimServer", "server");
observe_parent_termination();
const int nvim_argc = argc - 3;
const char **nvim_args = &argv[3];
const char *remote_port_name = argv[1];
const char *local_port_name = argv[2];
server_set_nvim_args(nvim_argc, nvim_argc == 0 ? NULL : nvim_args);
server_init_local_port(local_port_name);
server_init_remote_port(remote_port_name);
server_send_msg(NvimServerMsgIdServerReady, NULL);
os_log_debug(
logger,
"Started NvimServer '%s' and connected it with GUI '%s'.",
local_port_name, remote_port_name
);
CFRunLoopRun();
os_log_debug(logger, "NvimServer exiting.");
return 0;
}
static void observe_parent_termination() {
const pid_t parent_pid = getppid();
const dispatch_queue_t queue = dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0
);
dispatch_source_t source = dispatch_source_create(
DISPATCH_SOURCE_TYPE_PROC,
(uintptr_t) parent_pid,
DISPATCH_PROC_EXIT,
queue
);
if (source == NULL) {
os_log_error(logger, "No parent process monitoring...");
return;
}
dispatch_source_set_event_handler(source, ^{
os_log_fault(logger, "Exiting neovim server due to parent termination.");
CFRunLoopStop(CFRunLoopGetMain());
dispatch_source_cancel(source);
});
dispatch_resume(source);
}

View File

@ -1,76 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
#import <Foundation/Foundation.h>
#import "NvimServer.h"
#import "Logging.h"
NvimServer *_neovim_server;
os_log_t logger;
static void observe_parent_termination(CFRunLoopRef mainRunLoop) {
const pid_t parent_pid = getppid();
const dispatch_queue_t queue = dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0
);
dispatch_source_t source = dispatch_source_create(
DISPATCH_SOURCE_TYPE_PROC,
(uintptr_t) parent_pid,
DISPATCH_PROC_EXIT,
queue
);
if (source == NULL) {
os_log_error(logger, "No parent process monitoring...");
return;
}
dispatch_source_set_event_handler(source, ^{
os_log_fault(logger, "Exiting neovim server due to parent termination.");
CFRunLoopStop(mainRunLoop);
dispatch_source_cancel(source);
});
dispatch_resume(source);
}
int main(int argc, const char *argv[]) {
logger = os_log_create("com.qvacua.NvimServer", "server");
CFRunLoopRef const mainRunLoop = CFRunLoopGetCurrent();
observe_parent_termination(mainRunLoop);
@autoreleasepool {
NSArray<NSString *> *const arguments
= [NSProcessInfo processInfo].arguments;
NSString *const remoteServerName = arguments[1];
NSString *const localServerName = arguments[2];
NSArray<NSString *> *const nvimArgs = argc > 3
? [arguments subarrayWithRange:NSMakeRange(3, (NSUInteger) (argc - 3))]
: nil;
_neovim_server = [
[NvimServer alloc] initWithLocalServerName:localServerName
remoteServerName:remoteServerName
nvimArgs:nvimArgs
];
os_log_debug(
logger,
"Started neovim server '%@' with args '%@'"
" and connected it with the remote agent '%@'.",
localServerName, nvimArgs, remoteServerName
);
[_neovim_server notifyReadiness];
}
CFRunLoopRun();
os_log_debug(logger, "NvimServer returning.");
return 0;
}

View File

@ -0,0 +1,438 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
#include <uv.h>
#include "server.h"
#include "server_log.h"
#include "server_ui_bridge.h"
// 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
#include <stdlib.h>
#include <nvim/main.h>
#include <nvim/edit.h>
#include <nvim/mouse.h>
#include <nvim/screen.h>
#include <nvim/fileio.h>
#include <nvim/api/private/helpers.h>
#include <api/vim.h.generated.h>
#include <nvim/aucmd.h>
#pragma mark cond_var_t
typedef struct {
uv_mutex_t mutex;
uv_cond_t condition;
uint64_t timeout;
bool posted;
} cond_var_t;
static void cond_var_init(cond_var_t *cond_var, uint64_t timeout, bool posted) {
memset(cond_var, 0, sizeof((*cond_var)));
(*cond_var).timeout = timeout;
(*cond_var).posted = posted;
uv_cond_init(&(*cond_var).condition);
uv_mutex_init(&(*cond_var).mutex);
}
static void cond_var_destroy(cond_var_t *cond_var) {
uv_mutex_destroy(&(*cond_var).mutex);
uv_cond_destroy(&(*cond_var).condition);
}
#pragma mark server
static CFMessagePortRef local_port;
static CFRunLoopRef local_port_run_loop;
static uv_thread_t local_port_thread;
static CFMessagePortRef remote_port;
static uv_thread_t nvim_thread;
static const char *cfstr2cstr(CFStringRef cfstr, bool *free_bytes);
static void setenv_vimruntime(void);
static void start_nvim(void *_);
static int nvim_argc = 0;
static const char **nvim_argv;
static CFDataRef data_async(CFDataRef data, argv_callback cb);
typedef void (^async_work_block)(CFDataRef);
static void run_local_port(void *cond_var);
static CFDataRef local_port_callback(
CFMessagePortRef local,
SInt32 msgid,
CFDataRef data,
void *info
);
static String backspace;
static void scroll(void **argv);
static void resize(void **argv);
static void delete_and_input(void **argv);
static void focus_gained(void **argv);
static void ready_for_rpcevents(void **argv);
static void debug1(void **argv);
static void do_autocmd_guienter(void **argv);
// We declare nvim_main because it's not declared in any header files of neovim
extern int nvim_main(int argc, const char **argv);
void server_set_nvim_args(int argc, const char **const argv) {
nvim_argc = argc + 1;
nvim_argv = malloc(nvim_argc * sizeof(char *));
nvim_argv[0] = "nvim";
for (int i = 0; i < argc; i++) { nvim_argv[i + 1] = argv[i]; }
}
void server_init_local_port(const char *name) {
CFStringRef name_cf = CFStringCreateWithCString(
kCFAllocatorDefault,
name,
kCFStringEncodingUTF8
);
local_port = CFMessagePortCreateLocal(
kCFAllocatorDefault,
name_cf,
local_port_callback,
NULL,
NULL
);
CFRelease(name_cf);
cond_var_t cond_var;
cond_var_init(&cond_var, 5, false);
uv_thread_create(&local_port_thread, run_local_port, &cond_var);
uv_mutex_lock(&cond_var.mutex);
while (!cond_var.posted) {
uv_cond_timedwait(&cond_var.condition, &cond_var.mutex, cond_var.timeout);
}
uv_mutex_unlock(&cond_var.mutex);
cond_var_destroy(&cond_var);
}
void server_destroy_local_port() {
CFRunLoopStop(local_port_run_loop);
if (CFMessagePortIsValid(local_port)) { CFMessagePortInvalidate(local_port); }
CFRelease(local_port);
}
void server_init_remote_port(const char *name) {
CFStringRef name_cf = CFStringCreateWithCString(
kCFAllocatorDefault,
name,
kCFStringEncodingUTF8
);
remote_port = CFMessagePortCreateRemote(kCFAllocatorDefault, name_cf);
CFRelease(name_cf);
}
void server_destroy_remote_port() {
if (CFMessagePortIsValid(remote_port)) {
CFMessagePortInvalidate(remote_port);
}
CFRelease(remote_port);
}
void server_send_msg(NvimServerMsgId msgid, CFDataRef data) {
SInt32 response_code = CFMessagePortSendRequest(
remote_port,
(SInt32) msgid,
data,
5.0,
5.0,
NULL,
NULL
);
if (response_code == kCFMessagePortSuccess) { return; }
os_log_error(
logger,
"The msg (%lu) could not be sent: %d",
(long) msgid, response_code
);
}
static void start_nvim(void *_) {
backspace = cstr_as_string("<BS>");
setenv_vimruntime();
// Set $LANG to en_US.UTF-8 such that the copied text to the system clipboard
// is not garbled.
setenv("LANG", "en_US.UTF-8", true);
nvim_main(nvim_argc, nvim_argv);
}
static void setenv_vimruntime() {
CFBundleRef main_bundle = CFBundleGetMainBundle();
CFURLRef exe_url = CFBundleCopyBundleURL(main_bundle);
CFURLRef bundle_url = CFURLCreateCopyDeletingLastPathComponent(
kCFAllocatorDefault,
exe_url
);
CFRelease(exe_url);
CFURLRef rsrc_url = CFURLCreateCopyAppendingPathComponent(
kCFAllocatorDefault,
bundle_url,
CFSTR("Resources"),
true
);
CFRelease(bundle_url);
CFURLRef runtime_url = CFURLCreateCopyAppendingPathComponent(
kCFAllocatorDefault,
rsrc_url,
CFSTR("runtime"),
true
);
CFRelease(rsrc_url);
CFStringRef runtime_path = CFURLCopyPath(runtime_url);
CFRelease(runtime_url);
bool free_runtime_cstr;
const char *runtime_cstr = cfstr2cstr(runtime_path, &free_runtime_cstr);
setenv("VIMRUNTIME", runtime_cstr, true);
if (free_runtime_cstr) { free((void *) runtime_cstr); }
CFRelease(runtime_path);
}
static CFDataRef data_async(CFDataRef data, argv_callback cb) {
loop_schedule(&main_loop, event_create(cb, 3, data));
return NULL;
}
static void work_async(void **argv, async_work_block body) {
CFDataRef data = argv[0];
body(data);
CFRelease(data); // retained in local_port_callback
}
static CFDataRef local_port_callback(
CFMessagePortRef local __unused,
SInt32 msgid,
CFDataRef data,
void *info __unused
) {
if (data != NULL) {
CFRetain(data); // released in work_async (or in the case block below)
}
switch (msgid) {
case NvimBridgeMsgIdAgentReady: {
const NSInteger *const values = (NSInteger *) CFDataGetBytePtr(data);
bridge_data.init_width = (int) values[0];
bridge_data.init_height = (int) values[1];
CFRelease(data);
uv_thread_create(&nvim_thread, start_nvim, NULL);
return NULL;
}
case NvimBridgeMsgIdScroll:
return data_async(data, scroll);
case NvimBridgeMsgIdResize:
return data_async(data, resize);
case NvimBridgeMsgIdDeleteInput:
return data_async(data, delete_and_input);
case NvimBridgeMsgIdFocusGained:
return data_async(data, focus_gained);
case NvimBridgeMsgIdReadyForRpcEvents:
return data_async(data, ready_for_rpcevents);
case NvimBridgeMsgIdDebug1:
return data_async(data, debug1);
default:
os_log(logger, "msgid received: %{public}ld", (long) msgid);
if (data != NULL) { CFRelease(data); }
return NULL;
}
}
static void run_local_port(void *arg) {
local_port_run_loop = CFRunLoopGetCurrent();
CFRunLoopSourceRef const run_loop_src = CFMessagePortCreateRunLoopSource(
kCFAllocatorDefault,
local_port,
0
);
CFRunLoopAddSource(local_port_run_loop, run_loop_src, kCFRunLoopCommonModes);
CFRelease(run_loop_src);
cond_var_t *cond_var = (cond_var_t *) arg;
uv_mutex_lock(&cond_var->mutex);
cond_var->posted = true;
uv_cond_signal(&cond_var->condition);
uv_mutex_unlock(&cond_var->mutex);
CFRunLoopRun();
}
static const char *cfstr2cstr(CFStringRef cfstr, bool *free_bytes) {
*free_bytes = false;
const char *cptr = CFStringGetCStringPtr(cfstr, kCFStringEncodingUTF8);
if (cptr != NULL) { return cptr; }
CFIndex out_len = 0;
CFRange whole_range = CFRangeMake(0, CFStringGetLength(cfstr));
CFIndex converted = CFStringGetBytes(
cfstr,
whole_range,
kCFStringEncodingUTF8,
0,
false,
NULL,
0,
&out_len
);
if (converted == 0 || out_len == 0) { return NULL; }
const char *result = malloc((size_t) (out_len + 1));
converted = CFStringGetBytes(
cfstr,
whole_range,
kCFStringEncodingUTF8,
0,
false,
(UInt8 *) result,
out_len,
NULL
);
if (converted == 0) {
free((void *) result);
return NULL;
}
*free_bytes = true;
return result;
}
#pragma mark local message port callbacks
static void scroll(void **argv) {
work_async(argv, ^(CFDataRef data) {
const NSInteger *const values
= (const NSInteger *const) CFDataGetBytePtr(data);
const int horiz = (int) values[0];
const int vert = (int) values[1];
int row = (int) values[2];
int column = (int) values[3];
if (horiz == 0 && vert == 0) {
return;
}
if (row < 0 || column < 0) {
row = 0;
column = 0;
}
// value > 0 => down or right
int horizDir;
int vertDir;
if (horiz != 0) {
horizDir = horiz > 0 ? MSCR_RIGHT : MSCR_LEFT;
custom_ui_scroll(horizDir, abs(horiz), row, column);
}
if (vert != 0) {
vertDir = vert > 0 ? MSCR_DOWN : MSCR_UP;
custom_ui_scroll(vertDir, abs(vert), row, column);
}
update_screen(VALID);
setcursor();
ui_flush();
});
}
static void resize(void **argv) {
work_async(argv, ^(CFDataRef data) {
const NSInteger *const values
= (const NSInteger *const) CFDataGetBytePtr(data);
const NSInteger width = values[0];
const NSInteger height = values[1];
server_set_ui_size(bridge_data.bridge, (int) width, (int) height);
ui_refresh();
});
}
static void delete_and_input(void **argv) {
work_async(argv, ^(CFDataRef data) {
const NSInteger *const values
= (const NSInteger *const) CFDataGetBytePtr(data);
const NSInteger count = values[0];
for (int i = 0; i < count; i++) {
nvim_input(backspace);
}
const char *stringPtr = (const char *) (values + 1);
String string = cbuf_to_string(
stringPtr,
CFDataGetLength(data) - sizeof(NSInteger)
);
nvim_input(string);
api_free_string(string);
});
}
static void focus_gained(void **argv) {
work_async(argv, ^(CFDataRef data) {
const bool *values = (const bool *) CFDataGetBytePtr(data);
aucmd_schedule_focusgained(values[0]);
});
}
static void ready_for_rpcevents(void **argv) {
work_async(argv, ^(CFDataRef data) {
loop_schedule_deferred(&main_loop, event_create(do_autocmd_guienter, 0));
});
}
static void debug1(void **argv) {
work_async(argv, ^(CFDataRef data) {
// yet noop
os_log(logger, "debug1");
});
}
static void do_autocmd_guienter(void **argv) {
static bool recursive = false;
if (recursive) {
return; // disallow recursion
}
recursive = true;
apply_autocmds(EVENT_GUIENTER, NULL, NULL, false, curbuf);
recursive = false;
}

View File

@ -0,0 +1,22 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
#ifndef NVIMSERVER_SERVER_H
#define NVIMSERVER_SERVER_H
#include <CoreFoundation/CoreFoundation.h>
#include "server_shared_types.h"
void server_set_nvim_args(int argc, const char **const args);
void server_init_local_port(const char *name);
void server_destroy_local_port(void);
void server_init_remote_port(const char *name);
void server_destroy_remote_port(void);
void server_send_msg(NvimServerMsgId msgId, CFDataRef data);
#endif // NVIMSERVER_SERVER_H

View File

@ -0,0 +1,13 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
#ifndef NVIMSERVER_LOG_H
#define NVIMSERVER_LOG_H
#include <os/log.h>
extern os_log_t logger;
#endif // NVIMSERVER_LOG_H

View File

@ -3,9 +3,12 @@
* See LICENSE
*/
#import <Foundation/Foundation.h>
#ifndef NVIMSERVER_SHARED_TYPES_H
#define NVIMSERVER_SHARED_TYPES_H
typedef NS_OPTIONS(NSUInteger, FontTrait) {
#include "foundation_shim.h"
typedef CF_OPTIONS(NSUInteger, FontTrait) {
FontTraitNone = 0,
FontTraitItalic = (1 << 0),
FontTraitBold = (1 << 1),
@ -13,13 +16,13 @@ typedef NS_OPTIONS(NSUInteger, FontTrait) {
FontTraitUndercurl = (1 << 3)
};
typedef NS_ENUM(NSInteger, RenderDataType) {
typedef CF_ENUM(NSInteger, RenderDataType) {
RenderDataTypeRawLine,
RenderDataTypeGoto,
RenderDataTypeScroll,
};
typedef NS_ENUM(NSInteger, NvimServerMsgId) {
typedef CF_ENUM(NSInteger, NvimServerMsgId) {
NvimServerMsgIdServerReady = 0,
NvimServerMsgIdNvimReady,
NvimServerMsgIdResize,
@ -35,7 +38,7 @@ typedef NS_ENUM(NSInteger, NvimServerMsgId) {
NvimServerMsgIdSetTitle,
NvimServerMsgIdStop,
NvimServerMsgIdOptionSet,
NvimServerMsgIdDirtyStatusChanged,
NvimServerMsgIdCwdChanged,
NvimServerMsgIdColorSchemeChanged,
@ -46,14 +49,16 @@ typedef NS_ENUM(NSInteger, NvimServerMsgId) {
NvimServerMsgIdDebug1,
};
typedef NS_ENUM(NSInteger, NvimBridgeMsgId) {
typedef CF_ENUM(NSInteger, NvimBridgeMsgId) {
NvimBridgeMsgIdAgentReady = 0,
NvimBridgeMsgIdReadyForRpcEvents,
NvimBridgeMsgIdDeleteInput,
NvimBridgeMsgIdResize,
NvimBridgeMsgIdScroll,
NvimBridgeMsgIdFocusGained,
NvimBridgeMsgIdDebug1,
};
#endif // NVIMSERVER_SHARED_TYPES_H

View File

@ -1,23 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
#import <Foundation/Foundation.h>
@class NvimServer;
extern NvimServer *_neovim_server;
extern void start_neovim(NSInteger width, NSInteger height, NSArray<NSString *> *args);
extern void neovim_scroll(void **argv);
extern void neovim_resize(void **argv);
extern void neovim_delete_and_input(void **argv);
extern void neovim_focus_gained(void **argv);
extern void neovim_ready_for_rpcevents(void **argv);
extern void neovim_debug1(void **argv);

View File

@ -3,277 +3,47 @@
* See LICENSE
*/
#import <Foundation/Foundation.h>
#include "server_log.h"
#include "server_shared_types.h"
#include "server.h"
#include "server_ui_bridge.h"
#import "Logging.h"
#import "server_ui.h"
#import "NvimServer.h"
#import "CocoaCategories.h"
#include <nvim/vim.h>
#include <nvim/fileio.h>
#include <nvim/undo.h>
#include <nvim/syntax.h>
#include <nvim/highlight.h>
#include <nvim/msgpack_rpc/helpers.h>
// 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
server_ui_bridge_data_t bridge_data;
#import <nvim/main.h>
#import <nvim/vim.h>
#import <nvim/api/vim.h>
#import <nvim/ui.h>
#import <nvim/ui_bridge.h>
#import <nvim/fileio.h>
#import <nvim/undo.h>
#import <nvim/mouse.h>
#import <nvim/screen.h>
#import <nvim/edit.h>
#import <nvim/syntax.h>
#import <nvim/aucmd.h>
#import <nvim/highlight.h>
#import <nvim/msgpack_rpc/helpers.h>
#pragma mark server_ui_bridge
static NSInteger default_foreground = 0xFF000000;
static NSInteger default_background = 0xFFFFFFFF;
static NSInteger default_special = 0xFFFF0000;
static NSInteger _default_foreground = 0xFF000000;
static NSInteger _default_background = 0xFFFFFFFF;
static NSInteger _default_special = 0xFFFF0000;
typedef struct {
UIBridgeData *bridge;
Loop *loop;
bool stop;
} ServerUiData;
// We declare nvim_main because it's not declared in any header files of neovim
extern int nvim_main(int argc, char **argv);
// The thread in which neovim's main runs
static uv_thread_t _nvim_thread;
static ServerUiData *_server_ui_data;
static NSString *_backspace = @"<BS>";
static bool _dirty = false;
static NSInteger _initialWidth = 30;
static NSInteger _initialHeight = 15;
static bool are_buffers_dirty = false;
static msgpack_sbuffer flush_sbuffer;
static msgpack_packer flush_packer;
#pragma mark Helper functions
static inline String vim_string_from(NSString *str) {
return (String) {.data = (char *) str.cstr, .size = str.clength};
}
static void refresh_ui_screen(int type) {
update_screen(type);
setcursor();
ui_flush();
}
static bool has_dirty_docs() {
FOR_ALL_BUFFERS(buffer) {
if (bufIsChanged(buffer)) {
return true;
}
}
return false;
}
static void msgpack_pack_cstr(msgpack_packer *packer, const char *cstr) {
const size_t len = strlen(cstr);
msgpack_pack_str(packer, len);
msgpack_pack_str_body(packer, cstr, len);
}
static void msgpack_pack_bool(msgpack_packer *packer, bool value) {
if (value) {
msgpack_pack_true(packer);
} else {
msgpack_pack_false(packer);
}
}
typedef void (^pack_block)(msgpack_packer *packer);
static void send_msg_packing(NvimServerMsgId msgid, pack_block body);
static void msgpack_pack_bool(msgpack_packer *packer, bool value);
static void pack_flush_data(RenderDataType type, pack_block body);
static void msgpack_pack_cstr(msgpack_packer *packer, const char *cstr);
static void send_cwd(void);
static void send_dirty_status(void);
static void send_colorscheme(void);
static void send_msg_packing(NvimServerMsgId msgid, pack_block body) {
msgpack_sbuffer sbuf;
msgpack_sbuffer_init(&sbuf);
static void server_ui_scheduler(Event event, void *d);
static void server_ui_main(UIBridgeData *bridge, UI *ui);
msgpack_packer packer;
msgpack_packer_init(&packer, &sbuf, msgpack_sbuffer_write);
body(&packer);
CFDataRef const data = CFDataCreateWithBytesNoCopy(
kCFAllocatorDefault,
(const UInt8 *) sbuf.data,
sbuf.size,
kCFAllocatorNull
);
[_neovim_server sendMessageWithId:msgid data:data];
CFRelease(data);
msgpack_sbuffer_destroy(&sbuf);
}
static void pack_flush_data(RenderDataType type, pack_block body) {
msgpack_pack_array(&flush_packer, 2);
msgpack_pack_int64(&flush_packer, type);
body(&flush_packer);
}
static void send_dirty_status() {
const bool new_dirty_status = has_dirty_docs();
if (_dirty == new_dirty_status) {
return;
}
_dirty = new_dirty_status;
send_msg_packing(
NvimServerMsgIdDirtyStatusChanged,
^(msgpack_packer *packer) {
msgpack_pack_bool(packer, _dirty);
}
);
}
static void send_cwd() {
char_u *const temp = xmalloc(MAXPATHL);
if (os_dirname(temp, MAXPATHL) == FAIL) {
xfree(temp);
[_neovim_server sendMessageWithId:NvimServerMsgIdCwdChanged];
}
send_msg_packing(NvimServerMsgIdCwdChanged, ^(msgpack_packer *packer) {
msgpack_pack_cstr(packer, (const char *) temp);
xfree(temp);
});
}
static int foreground_for(HlAttrs attrs) {
const int mask = attrs.rgb_ae_attr;
return mask & HL_INVERSE ? attrs.rgb_bg_color : attrs.rgb_fg_color;
}
static int background_for(HlAttrs attrs) {
const int mask = attrs.rgb_ae_attr;
return mask & HL_INVERSE ? attrs.rgb_fg_color : attrs.rgb_bg_color;
}
static void send_colorscheme() {
// It seems that the highlight groupt only gets updated when the screen is
// redrawn. Since there's a guard var, probably it's safe to call it here...
if (need_highlight_changed) {
highlight_changed();
}
const HlAttrs visualAttrs = syn_attr2entry(highlight_attr[HLF_V]);
const HlAttrs dirAttrs = syn_attr2entry(highlight_attr[HLF_D]);
send_msg_packing(
NvimServerMsgIdColorSchemeChanged,
^(msgpack_packer *packer) {
msgpack_pack_array(packer, 5);
msgpack_pack_int64(packer, normal_fg);
msgpack_pack_int64(packer, normal_bg);
msgpack_pack_int64(packer, foreground_for(visualAttrs));
msgpack_pack_int64(packer, background_for(visualAttrs));
msgpack_pack_int64(packer, foreground_for(dirAttrs));
}
);
}
static void run_neovim(void *arg) {
int argc;
char **argv;
@autoreleasepool {
NSArray<NSString *> *nvimArgs = arg;
argc = (int) nvimArgs.count + 1;
argv = (char **) malloc((argc + 1) * sizeof(char *));
argv[0] = "nvim";
for (NSUInteger i = 0; i < nvimArgs.count; i++) {
char *str = (char *) nvimArgs[i].cstr;
argv[i + 1] = malloc(strlen(str) + 1);
strcpy(argv[i + 1], str);
}
[nvimArgs release]; // retained in start_neovim()
}
nvim_main(argc, argv);
for (int i = 0; i < argc - 1; i++) {
free(argv[i + 1]);
}
free(argv);
}
static void set_ui_size(UIBridgeData *bridge, int width, int height) {
bridge->ui->width = width;
bridge->ui->height = height;
bridge->bridge.width = width;
bridge->bridge.height = height;
}
static void server_ui_scheduler(Event event, void *d) {
UI *const ui = d;
ServerUiData *data = ui->data;
loop_schedule(data->loop, event);
}
static void server_ui_main(UIBridgeData *bridge, UI *ui) {
msgpack_sbuffer_init(&flush_sbuffer);
msgpack_packer_init(&flush_packer, &flush_sbuffer, msgpack_sbuffer_write);
Loop loop;
loop_init(&loop, NULL);
_server_ui_data = xcalloc(1, sizeof(ServerUiData));
ui->data = _server_ui_data;
_server_ui_data->bridge = bridge;
_server_ui_data->loop = &loop;
set_ui_size(bridge, (int) _initialWidth, (int) _initialHeight);
_server_ui_data->stop = false;
CONTINUE(bridge);
send_msg_packing(NvimServerMsgIdNvimReady, ^(msgpack_packer *packer) {
msgpack_pack_bool(packer, msg_didany > 0);
});
// We have to manually trigger this to initially get the colorscheme.
send_colorscheme();
while (!_server_ui_data->stop) {
loop_poll_events(&loop, -1);
}
ui_bridge_stopped(bridge);
loop_close(&loop, false);
xfree(_server_ui_data);
xfree(ui);
free(msgpack_sbuffer_release(&flush_sbuffer));
}
#pragma mark NeoVim's UI callbacks
#pragma mark ui_bridge callbacks
static void server_ui_flush(UI *ui __unused) {
if (flush_sbuffer.size == 0) {
return;
}
if (flush_sbuffer.size == 0) { return; }
CFDataRef const data = CFDataCreateWithBytesNoCopy(
kCFAllocatorDefault,
@ -281,7 +51,7 @@ static void server_ui_flush(UI *ui __unused) {
flush_sbuffer.size,
kCFAllocatorNull
);
[_neovim_server sendMessageWithId:NvimServerMsgIdFlush data:data];
server_send_msg(NvimServerMsgIdFlush, data);
CFRelease(data);
free(msgpack_sbuffer_release(&flush_sbuffer));
@ -301,11 +71,14 @@ static void server_ui_grid_resize(
}
static void server_ui_grid_clear(UI *ui __unused, Integer grid __unused) {
[_neovim_server sendMessageWithId:NvimServerMsgIdClear];
server_send_msg(NvimServerMsgIdClear, NULL);
}
static void server_ui_cursor_goto(
UI *ui __unused, Integer grid __unused, Integer row, Integer col
UI *ui __unused,
Integer grid __unused,
Integer row,
Integer col
) {
pack_flush_data(RenderDataTypeGoto, ^(msgpack_packer *packer) {
msgpack_pack_array(packer, 2);
@ -315,25 +88,27 @@ static void server_ui_cursor_goto(
}
static void server_ui_update_menu(UI *ui __unused) {
[_neovim_server sendMessageWithId:NvimServerMsgIdSetMenu];
server_send_msg(NvimServerMsgIdSetMenu, NULL);
}
static void server_ui_busy_start(UI *ui __unused) {
[_neovim_server sendMessageWithId:NvimServerMsgIdBusyStart];
server_send_msg(NvimServerMsgIdBusyStart, NULL);
}
static void server_ui_busy_stop(UI *ui __unused) {
[_neovim_server sendMessageWithId:NvimServerMsgIdBusyStop];
server_send_msg(NvimServerMsgIdBusyStop, NULL);
}
static void server_ui_mode_info_set(
UI *ui __unused, Boolean enabled __unused, Array cursor_styles __unused
) {
// yet noop
}
UI *ui __unused,
Boolean enabled __unused,
Array cursor_styles __unused
) {}
static void server_ui_mode_change(
UI *ui __unused, String mode_str __unused, Integer mode
UI *ui __unused,
String mode_str __unused,
Integer mode
) {
send_msg_packing(NvimServerMsgIdModeChange, ^(msgpack_packer *packer) {
msgpack_pack_int64(packer, mode);
@ -368,18 +143,10 @@ static void server_ui_hl_attr_define(
Array info __unused
) {
FontTrait trait = FontTraitNone;
if (attrs.rgb_ae_attr & HL_ITALIC) {
trait |= FontTraitItalic;
}
if (attrs.rgb_ae_attr & HL_BOLD) {
trait |= FontTraitBold;
}
if (attrs.rgb_ae_attr & HL_UNDERLINE) {
trait |= FontTraitUnderline;
}
if (attrs.rgb_ae_attr & HL_UNDERCURL) {
trait |= FontTraitUndercurl;
}
if (attrs.rgb_ae_attr & HL_ITALIC) { trait |= FontTraitItalic; }
if (attrs.rgb_ae_attr & HL_BOLD) { trait |= FontTraitBold; }
if (attrs.rgb_ae_attr & HL_UNDERLINE) { trait |= FontTraitUnderline; }
if (attrs.rgb_ae_attr & HL_UNDERCURL) { trait |= FontTraitUndercurl; }
send_msg_packing(NvimServerMsgIdHighlightAttrs, ^(msgpack_packer *packer) {
msgpack_pack_array(packer, 6);
@ -400,7 +167,7 @@ static void server_ui_raw_line(
Integer endcol,
Integer clearcol,
Integer clearattr,
Boolean wrap,
Boolean wrap __unused,
const schar_T *chunk,
const sattr_T *attrs
) {
@ -427,11 +194,11 @@ static void server_ui_raw_line(
}
static void server_ui_bell(UI *ui __unused) {
[_neovim_server sendMessageWithId:NvimServerMsgIdBell];
server_send_msg(NvimServerMsgIdBell, NULL);
}
static void server_ui_visual_bell(UI *ui __unused) {
[_neovim_server sendMessageWithId:NvimServerMsgIdVisualBell];
server_send_msg(NvimServerMsgIdVisualBell, NULL);
}
static void server_ui_default_colors_set(
@ -442,39 +209,27 @@ static void server_ui_default_colors_set(
Integer cterm_fg __unused,
Integer cterm_bg __unused
) {
if (rgb_fg != -1) {
_default_foreground = rgb_fg;
}
if (rgb_bg != -1) {
_default_background = rgb_bg;
}
if (rgb_sp != -1) {
_default_special = rgb_sp;
}
if (rgb_fg != -1) { default_foreground = rgb_fg; }
if (rgb_bg != -1) { default_background = rgb_bg; }
if (rgb_sp != -1) { default_special = rgb_sp; }
send_msg_packing(
NvimServerMsgIdDefaultColorsChanged,
^(msgpack_packer *packer) {
msgpack_pack_array(packer, 3);
msgpack_pack_int64(packer, _default_foreground);
msgpack_pack_int64(packer, _default_background);
msgpack_pack_int64(packer, _default_special);
msgpack_pack_int64(packer, default_foreground);
msgpack_pack_int64(packer, default_background);
msgpack_pack_int64(packer, default_special);
}
);
}
static void server_ui_set_title(UI *ui __unused, String title) {
@autoreleasepool {
if (title.size == 0) {
return;
}
if (title.size == 0) { return; }
send_msg_packing(NvimServerMsgIdSetTitle, ^(msgpack_packer *packer) {
msgpack_rpc_from_string(title, packer);
});
}
send_msg_packing(NvimServerMsgIdSetTitle, ^(msgpack_packer *packer) {
msgpack_rpc_from_string(title, packer);
});
}
static void server_ui_option_set(UI *ui __unused, String name, Object value) {
@ -486,22 +241,17 @@ static void server_ui_option_set(UI *ui __unused, String name, Object value) {
}
static void server_ui_stop(UI *ui __unused) {
[_neovim_server sendMessageWithId:NvimServerMsgIdStop];
server_send_msg(NvimServerMsgIdStop, NULL);
ServerUiData *const data = ui->data;
server_ui_bridge_data_t *const data = ui->data;
data->stop = true;
}
static void dummy(UI *ui __unused) {
static void dummy(UI *ui __unused) {}
}
static void dummy2(UI *ui __unused, String icon __unused) {}
static void dummy2(UI *ui __unused, String icon) {
}
#pragma mark Public
// called by neovim
#pragma mark called by nvim
void custom_ui_start(void) {
UI *const ui = xcalloc(1, sizeof(UI));
@ -538,8 +288,7 @@ void custom_ui_start(void) {
void custom_ui_rpcevent_subscribed() {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
[_neovim_server sendMessageWithId:NvimServerMsgIdRpcEventSubscribed
data:NULL];
server_send_msg(NvimServerMsgIdRpcEventSubscribed, NULL);
});
}
@ -571,176 +320,189 @@ void custom_ui_autocmds_groups(
return;
}
@autoreleasepool {
if (event == EVENT_DIRCHANGED) {
send_cwd();
return;
}
if (event == EVENT_COLORSCHEME) {
send_colorscheme();
return;
}
if (event == EVENT_TEXTCHANGED
|| event == EVENT_TEXTCHANGEDI
|| event == EVENT_BUFWRITEPOST
|| event == EVENT_BUFLEAVE) {
send_dirty_status();
}
send_msg_packing(
NvimServerMsgIdAutoCommandEvent,
^(msgpack_packer *packer) {
msgpack_pack_array(packer, 2);
msgpack_pack_int64(packer, (NSInteger) event);
if (buf == NULL) {
msgpack_pack_int64(packer, -1);
} else {
msgpack_pack_int64(packer, (NSInteger) buf->handle);
}
});
if (event == EVENT_DIRCHANGED) {
send_cwd();
return;
}
}
#pragma mark Other help functions
void start_neovim(
NSInteger width, NSInteger height, NSArray<NSString *> *args
) {
// The caller has an @autoreleasepool.
_initialWidth = width;
_initialHeight = height;
// set $VIMRUNTIME to ${RESOURCE_PATH_OF_XPC_BUNDLE}/runtime
NSString *const bundlePath = [
NSBundle bundleForClass:[NvimServer class]
].bundlePath;
NSString *const resourcesPath = [bundlePath.stringByDeletingLastPathComponent
stringByAppendingPathComponent:@"Resources"];
NSString *const runtimePath
= [resourcesPath stringByAppendingPathComponent:@"runtime"];
setenv("VIMRUNTIME", runtimePath.fileSystemRepresentation, true);
// Set $LANG to en_US.UTF-8 such that the copied text to the system clipboard
// is not garbled.
setenv("LANG", "en_US.UTF-8", true);
// released in run_neovim()
uv_thread_create(&_nvim_thread, run_neovim, [args retain]);
}
#pragma mark Functions for neovim's main loop
typedef void (^async_work_block)(NSData *);
static void work_async(void **argv, async_work_block block) {
@autoreleasepool {
NSData *const data = argv[0];
block(data);
[data release]; // retained in local_server_callback
if (event == EVENT_COLORSCHEME) {
send_colorscheme();
return;
}
}
void neovim_scroll(void **argv) {
work_async(argv, ^(NSData *data) {
const NSInteger *const values = data.bytes;
const int horiz = (int) values[0];
const int vert = (int) values[1];
int row = (int) values[2];
int column = (int) values[3];
if (horiz == 0 && vert == 0) {
return;
}
if (row < 0 || column < 0) {
row = 0;
column = 0;
}
// value > 0 => down or right
int horizDir;
int vertDir;
if (horiz != 0) {
horizDir = horiz > 0 ? MSCR_RIGHT : MSCR_LEFT;
custom_ui_scroll(horizDir, ABS(horiz), row, column);
}
if (vert != 0) {
vertDir = vert > 0 ? MSCR_DOWN : MSCR_UP;
custom_ui_scroll(vertDir, ABS(vert), row, column);
}
refresh_ui_screen(VALID);
});
}
void neovim_resize(void **argv) {
work_async(argv, ^(NSData *data) {
const NSInteger *const values = data.bytes;
const NSInteger width = values[0];
const NSInteger height = values[1];
set_ui_size(_server_ui_data->bridge, (int) width, (int) height);
ui_refresh();
});
}
void neovim_delete_and_input(void **argv) {
work_async(argv, ^(NSData *data) {
const NSInteger *const values = data.bytes;
const NSInteger count = values[0];
for (int i = 0; i < count; i++) {
nvim_input(vim_string_from(_backspace));
}
const void *const stringPtr = (void *) (values + 1);
NSString *string = [[NSString alloc]
initWithBytes:stringPtr
length:data.length - sizeof(NSInteger)
encoding:NSUTF8StringEncoding
];
nvim_input(vim_string_from(string));
[string release];
});
}
static void do_autocmd_guienter() {
static bool recursive = false;
if (recursive) {
return; // disallow recursion
if (event == EVENT_TEXTCHANGED
|| event == EVENT_TEXTCHANGEDI
|| event == EVENT_BUFWRITEPOST
|| event == EVENT_BUFLEAVE) {
send_dirty_status();
}
recursive = true;
apply_autocmds(EVENT_GUIENTER, NULL, NULL, false, curbuf);
recursive = false;
send_msg_packing(
NvimServerMsgIdAutoCommandEvent,
^(msgpack_packer *packer) {
msgpack_pack_array(packer, 2);
msgpack_pack_int64(packer, (NSInteger) event);
if (buf == NULL) {
msgpack_pack_int64(packer, -1);
} else {
msgpack_pack_int64(packer, (NSInteger) buf->handle);
}
});
}
static void guienter_event(void **argv __unused) {
do_autocmd_guienter();
#pragma mark helpers
static bool has_dirty_docs() {
FOR_ALL_BUFFERS(buffer) {
if (bufIsChanged(buffer)) { return true; }
}
return false;
}
static void aucmd_schedule_guienter() {
loop_schedule_deferred(&main_loop, event_create(guienter_event, 0));
static void msgpack_pack_cstr(msgpack_packer *packer, const char *cstr) {
const size_t len = strlen(cstr);
msgpack_pack_str(packer, len);
msgpack_pack_str_body(packer, cstr, len);
}
void neovim_focus_gained(void **argv) {
work_async(argv, ^(NSData *data) {
const bool *values = data.bytes;
static void msgpack_pack_bool(msgpack_packer *packer, bool value) {
if (value) { msgpack_pack_true(packer); }
else { msgpack_pack_false(packer); }
}
aucmd_schedule_focusgained(values[0]);
static void send_msg_packing(NvimServerMsgId msgid, pack_block body) {
msgpack_sbuffer sbuf;
msgpack_sbuffer_init(&sbuf);
msgpack_packer packer;
msgpack_packer_init(&packer, &sbuf, msgpack_sbuffer_write);
body(&packer);
CFDataRef const data = CFDataCreateWithBytesNoCopy(
kCFAllocatorDefault,
(const UInt8 *) sbuf.data,
sbuf.size,
kCFAllocatorNull
);
server_send_msg(msgid, data);
CFRelease(data);
msgpack_sbuffer_destroy(&sbuf);
}
static void pack_flush_data(RenderDataType type, pack_block body) {
msgpack_pack_array(&flush_packer, 2);
msgpack_pack_int64(&flush_packer, type);
body(&flush_packer);
}
static void send_dirty_status() {
const bool new_dirty_status = has_dirty_docs();
if (are_buffers_dirty == new_dirty_status) { return; }
are_buffers_dirty = new_dirty_status;
send_msg_packing(
NvimServerMsgIdDirtyStatusChanged,
^(msgpack_packer *packer) {
msgpack_pack_bool(packer, are_buffers_dirty);
}
);
}
static void send_cwd() {
char_u *const temp = xmalloc(MAXPATHL);
if (os_dirname(temp, MAXPATHL) == FAIL) {
xfree(temp);
server_send_msg(NvimServerMsgIdCwdChanged, NULL);
return;
}
send_msg_packing(NvimServerMsgIdCwdChanged, ^(msgpack_packer *packer) {
msgpack_pack_cstr(packer, (const char *) temp);
xfree(temp);
});
}
void neovim_ready_for_rpcevents(void **argv) {
work_async(argv, ^(NSData *data) {
aucmd_schedule_guienter();
});
static int foreground_for(HlAttrs attrs) {
const int mask = attrs.rgb_ae_attr;
return mask & HL_INVERSE ? attrs.rgb_bg_color : attrs.rgb_fg_color;
}
void neovim_debug1(void **argv) {
work_async(argv, ^(NSData *data) {
// yet noop
os_log(logger, "debug1");
});
static int background_for(HlAttrs attrs) {
const int mask = attrs.rgb_ae_attr;
return mask & HL_INVERSE ? attrs.rgb_fg_color : attrs.rgb_bg_color;
}
static void send_colorscheme() {
// It seems that the highlight groupt only gets updated when the screen is
// redrawn. Since there's a guard var, probably it's safe to call it here...
if (need_highlight_changed) { highlight_changed(); }
const HlAttrs visualAttrs = syn_attr2entry(highlight_attr[HLF_V]);
const HlAttrs dirAttrs = syn_attr2entry(highlight_attr[HLF_D]);
send_msg_packing(
NvimServerMsgIdColorSchemeChanged,
^(msgpack_packer *packer) {
msgpack_pack_array(packer, 5);
msgpack_pack_int64(packer, normal_fg);
msgpack_pack_int64(packer, normal_bg);
msgpack_pack_int64(packer, foreground_for(visualAttrs));
msgpack_pack_int64(packer, background_for(visualAttrs));
msgpack_pack_int64(packer, foreground_for(dirAttrs));
}
);
}
void server_set_ui_size(UIBridgeData *bridge, int width, int height) {
bridge->ui->width = width;
bridge->ui->height = height;
bridge->bridge.width = width;
bridge->bridge.height = height;
}
static void server_ui_scheduler(Event event, void *d) {
UI *const ui = d;
server_ui_bridge_data_t *data = ui->data;
loop_schedule(data->loop, event);
}
static void server_ui_main(UIBridgeData *bridge, UI *ui) {
msgpack_sbuffer_init(&flush_sbuffer);
msgpack_packer_init(&flush_packer, &flush_sbuffer, msgpack_sbuffer_write);
Loop loop;
loop_init(&loop, NULL);
ui->data = &bridge_data;
bridge_data.bridge = bridge;
bridge_data.loop = &loop;
server_set_ui_size(bridge, bridge_data.init_width, bridge_data.init_height);
bridge_data.stop = false;
CONTINUE(bridge);
send_msg_packing(NvimServerMsgIdNvimReady, ^(msgpack_packer *packer) {
msgpack_pack_bool(packer, msg_didany > 0);
});
// We have to manually trigger this to initially get the colorscheme.
send_colorscheme();
while (!bridge_data.stop) { loop_poll_events(&loop, -1); }
ui_bridge_stopped(bridge);
loop_close(&loop, false);
server_destroy_local_port();
server_destroy_remote_port();
xfree(ui);
free(msgpack_sbuffer_release(&flush_sbuffer));
// mch_exit() of neovim will call exit(...)
}

View File

@ -0,0 +1,32 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
#ifndef NVIMSERVER_SERVER_UI_BRIDGE_H
#define NVIMSERVER_SERVER_UI_BRIDGE_H
// 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
#include <nvim/api/private/defs.h>
#include <nvim/ui_bridge.h>
typedef struct {
UIBridgeData *bridge;
Loop *loop;
bool stop;
int init_width;
int init_height;
} server_ui_bridge_data_t;
extern server_ui_bridge_data_t bridge_data;
void server_set_ui_size(UIBridgeData *bridge, int width, int height);
#endif // NVIMSERVER_SERVER_UI_BRIDGE_H

View File

@ -8,6 +8,7 @@
/* Begin PBXBuildFile section */
1929B00C084F8EA5EF0BE6E2 /* NvimView+Geometry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BD896D408673954F4AA2 /* NvimView+Geometry.swift */; };
1929B0533B55B2349DE2EFE2 /* foundation_shim.h in Headers */ = {isa = PBXBuildFile; fileRef = 1929B27A8FF9A75A09969777 /* foundation_shim.h */; settings = {ATTRIBUTES = (Public, ); }; };
1929B06F50B2585777FFBE48 /* NvimApiCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B002A03693B14B14BE34 /* NvimApiCommons.swift */; };
1929B0B1A64AA449F666FCC9 /* 1.json in Resources */ = {isa = PBXBuildFile; fileRef = 1929B8619FD13BC2570CBFB2 /* 1.json */; };
1929B14D2EBC34BCFEC78ACB /* CellAttributesCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BB19DD03ECD6ECC35F94 /* CellAttributesCollection.swift */; };
@ -49,11 +50,14 @@
1929BEA71F454E92A0CE5AB6 /* SwiftCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B9C55A79D97272894F5D /* SwiftCommons.swift */; };
1929BF6E40C70A4157A5C755 /* UGridTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BBA08E4195666290EC6A /* UGridTest.swift */; };
1929BF95400085EE3F0FFAD5 /* FontTrait.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B9D7F040B8B9E2F038DF /* FontTrait.swift */; };
1929BFEAF40AE8349E800CE4 /* server.c in Sources */ = {isa = PBXBuildFile; fileRef = 1929B7398AD1DE525FA53E38 /* server.c */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
4B06F70A2247FBEE0069C9F2 /* server_ui_bridge.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B06F7092247FBEE0069C9F2 /* server_ui_bridge.c */; };
4B0A1B142129F49500F1E02F /* SwiftCommonsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0A1B132129F49500F1E02F /* SwiftCommonsTest.swift */; };
4B0A1B39212B332800F1E02F /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B0A1B38212B332800F1E02F /* Nimble.framework */; };
4B0A1B3B212B333700F1E02F /* Nimble.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4B0A1B38212B332800F1E02F /* Nimble.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
4B17E549209E3E4100265C1D /* RxNeovimApi.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B17E548209E3E4100265C1D /* RxNeovimApi.framework */; };
4B21ED53213D4AEC009FD017 /* CocoaCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B0C89838D8402BB80BFC /* CocoaCommons.swift */; };
4B379CCD2248CFB7004B89B4 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B379CCC2248CFB6004B89B4 /* CoreFoundation.framework */; };
4B4A48DC222C7C6A00C8E3A1 /* SharedTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B4A48DB222C7C6A00C8E3A1 /* SharedTypes.h */; settings = {ATTRIBUTES = (Public, ); }; };
4B6DFB39223592B90066BB43 /* OSLogCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B39C7DCDA4E9D5220CD8 /* OSLogCommons.swift */; };
4B8662E81FDC3F9F007F490D /* com.qvacua.NvimView.vim in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4B8662E41FDC3D4F007F490D /* com.qvacua.NvimView.vim */; };
@ -68,10 +72,7 @@
4B90F03F1FD2AFAE008A39E0 /* NvimView+Draw.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F0211FD2AFAD008A39E0 /* NvimView+Draw.swift */; };
4B90F0421FD2AFAE008A39E0 /* NvimView+UiBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F0241FD2AFAD008A39E0 /* NvimView+UiBridge.swift */; };
4B90F0431FD2AFAE008A39E0 /* NvimView+MenuItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F0251FD2AFAD008A39E0 /* NvimView+MenuItems.swift */; };
4B90F0521FD2AFD3008A39E0 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F0511FD2AFD3008A39E0 /* main.m */; };
4B90F0661FD2AFF7008A39E0 /* server_ui.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F0561FD2AFF7008A39E0 /* server_ui.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
4B90F0681FD2AFF7008A39E0 /* CocoaCategories.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F05A1FD2AFF7008A39E0 /* CocoaCategories.m */; };
4B90F06B1FD2AFF7008A39E0 /* NvimServer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F0641FD2AFF7008A39E0 /* NvimServer.m */; };
4B90F0521FD2AFD3008A39E0 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F0511FD2AFD3008A39E0 /* main.c */; };
4B9E5E1C20990DF2006455C3 /* RxMessagePort.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B9E5E1B20990DF1006455C3 /* RxMessagePort.framework */; };
4BB1F5C9209740E400EC394A /* RxMsgpackRpc.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BB1F5C8209740E400EC394A /* RxMsgpackRpc.framework */; };
4BB1F5CB209740E900EC394A /* MessagePack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BB1F5CA209740E900EC394A /* MessagePack.framework */; };
@ -100,7 +101,6 @@
4BF01CF0223502CC00411218 /* SwiftCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B9C55A79D97272894F5D /* SwiftCommons.swift */; };
4BF01CF1223502D400411218 /* Defs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BF14AE831C6832659B66 /* Defs.swift */; };
4BF01CF2223502DB00411218 /* CoreCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BAB9FFE8345228B559EC /* CoreCommons.swift */; };
4BF01CF32235030E00411218 /* OSLogCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B39C7DCDA4E9D5220CD8 /* OSLogCommons.swift */; };
4BF18510212DCCEA00954FE7 /* NvimView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B90F0041FD2AF59008A39E0 /* NvimView.framework */; };
4BF18511212DCCF600954FE7 /* NvimView.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4B90F0041FD2AF59008A39E0 /* NvimView.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
4BF18512212DCD6E00954FE7 /* RxNeovimApi.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B17E548209E3E4100265C1D /* RxNeovimApi.framework */; };
@ -202,12 +202,15 @@
1929B0C89838D8402BB80BFC /* CocoaCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CocoaCommons.swift; sourceTree = "<group>"; };
1929B114CC85D012D7477D58 /* PerfTester.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PerfTester.swift; sourceTree = "<group>"; };
1929B22A0CAD417EC3790F02 /* NvimView+Objects.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NvimView+Objects.swift"; sourceTree = "<group>"; };
1929B27A8FF9A75A09969777 /* foundation_shim.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = foundation_shim.h; sourceTree = "<group>"; };
1929B2CE622DF2B4D21D0C0E /* FontTrait.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FontTrait.swift; sourceTree = "<group>"; };
1929B39C7DCDA4E9D5220CD8 /* OSLogCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OSLogCommons.swift; sourceTree = "<group>"; };
1929B3EAE37505620F8AECD5 /* server.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = server.h; sourceTree = "<group>"; };
1929B47330DAD129520A2273 /* Typesetter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Typesetter.swift; sourceTree = "<group>"; };
1929B52174EC68D2974B5BAE /* UiBridge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UiBridge.swift; sourceTree = "<group>"; };
1929B60D1775A75D7C0F6721 /* SimpleCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimpleCache.swift; sourceTree = "<group>"; };
1929B73455764E42DACF6BB8 /* Geometry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Geometry.swift; sourceTree = "<group>"; };
1929B7398AD1DE525FA53E38 /* server.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = server.c; sourceTree = "<group>"; };
1929B8619FD13BC2570CBFB2 /* 1.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = 1.json; sourceTree = "<group>"; };
1929B8E176C11DD61A8DCE95 /* RxSwiftCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxSwiftCommons.swift; sourceTree = "<group>"; };
1929B9290D503536FFDA9C49 /* MessagePackCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagePackCommons.swift; sourceTree = "<group>"; };
@ -229,12 +232,18 @@
1929BF14AE831C6832659B66 /* Defs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Defs.swift; sourceTree = "<group>"; };
1929BF88DE64FC62AFFCBC84 /* NimbleCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NimbleCommons.swift; sourceTree = "<group>"; };
1929BFCCDE5C7145BE5A7387 /* TypesetterTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypesetterTest.swift; sourceTree = "<group>"; };
1929BFDA282A4CA4838385E9 /* foundation_shim.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = foundation_shim.h; sourceTree = "<group>"; };
4B06F7082247FBEE0069C9F2 /* server_ui_bridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = server_ui_bridge.h; sourceTree = "<group>"; };
4B06F7092247FBEE0069C9F2 /* server_ui_bridge.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = server_ui_bridge.c; sourceTree = "<group>"; };
4B06F70B22481D3A0069C9F2 /* include */ = {isa = PBXFileReference; lastKnownFileType = folder; name = include; path = neovim/build/include; sourceTree = "<group>"; };
4B06F70C22481D980069C9F2 /* ui_events.generated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ui_events.generated.h; path = neovim/build/src/nvim/auto/ui_events.generated.h; sourceTree = "<group>"; };
4B0A1B112129F49500F1E02F /* NvimViewTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NvimViewTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
4B0A1B132129F49500F1E02F /* SwiftCommonsTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftCommonsTest.swift; sourceTree = "<group>"; };
4B0A1B152129F49500F1E02F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
4B0A1B38212B332800F1E02F /* Nimble.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nimble.framework; path = ../Carthage/Build/Mac/Nimble.framework; sourceTree = "<group>"; };
4B17E548209E3E4100265C1D /* RxNeovimApi.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxNeovimApi.framework; path = ../Carthage/Build/Mac/RxNeovimApi.framework; sourceTree = "<group>"; };
4B4A48DA222C7C5600C8E3A1 /* SharedTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SharedTypes.h; sourceTree = "<group>"; };
4B379CCC2248CFB6004B89B4 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
4B4A48DA222C7C5600C8E3A1 /* server_shared_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = server_shared_types.h; sourceTree = "<group>"; };
4B4A48DB222C7C6A00C8E3A1 /* SharedTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SharedTypes.h; sourceTree = "<group>"; };
4B8662E41FDC3D4F007F490D /* com.qvacua.NvimView.vim */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.vim; path = com.qvacua.NvimView.vim; sourceTree = "<group>"; };
4B90F0041FD2AF59008A39E0 /* NvimView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = NvimView.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@ -251,14 +260,8 @@
4B90F0241FD2AFAD008A39E0 /* NvimView+UiBridge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NvimView+UiBridge.swift"; sourceTree = "<group>"; };
4B90F0251FD2AFAD008A39E0 /* NvimView+MenuItems.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NvimView+MenuItems.swift"; sourceTree = "<group>"; };
4B90F04F1FD2AFD3008A39E0 /* NvimServer */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = NvimServer; sourceTree = BUILT_PRODUCTS_DIR; };
4B90F0511FD2AFD3008A39E0 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
4B90F0561FD2AFF7008A39E0 /* server_ui.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = server_ui.m; sourceTree = "<group>"; };
4B90F0571FD2AFF7008A39E0 /* CocoaCategories.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CocoaCategories.h; sourceTree = "<group>"; };
4B90F05A1FD2AFF7008A39E0 /* CocoaCategories.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CocoaCategories.m; sourceTree = "<group>"; };
4B90F05B1FD2AFF7008A39E0 /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Logging.h; sourceTree = "<group>"; };
4B90F0621FD2AFF7008A39E0 /* NvimServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NvimServer.h; sourceTree = "<group>"; };
4B90F0631FD2AFF7008A39E0 /* server_ui.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = server_ui.h; sourceTree = "<group>"; };
4B90F0641FD2AFF7008A39E0 /* NvimServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NvimServer.m; sourceTree = "<group>"; };
4B90F0511FD2AFD3008A39E0 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
4B90F05B1FD2AFF7008A39E0 /* server_log.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = server_log.h; sourceTree = "<group>"; };
4B9E5E1B20990DF1006455C3 /* RxMessagePort.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxMessagePort.framework; path = ../Carthage/Build/Mac/RxMessagePort.framework; sourceTree = "<group>"; };
4BB1F5C8209740E400EC394A /* RxMsgpackRpc.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxMsgpackRpc.framework; path = ../Carthage/Build/Mac/RxMsgpackRpc.framework; sourceTree = "<group>"; };
4BB1F5CA209740E900EC394A /* MessagePack.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessagePack.framework; path = ../Carthage/Build/Mac/MessagePack.framework; sourceTree = "<group>"; };
@ -277,7 +280,6 @@
4BF1852721313EE500954FE7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
4BF1852921313EE500954FE7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
4BF18C5A1FD2E72D00DF95D1 /* nvim */ = {isa = PBXFileReference; lastKnownFileType = folder; name = nvim; path = neovim/src/nvim; sourceTree = "<group>"; };
4BF18C5B1FD2E74800DF95D1 /* auto */ = {isa = PBXFileReference; lastKnownFileType = folder; name = auto; path = neovim/build/src/nvim/auto; sourceTree = "<group>"; };
4BF18C5C1FD2EEE400DF95D1 /* NvimView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NvimView.h; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -314,6 +316,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
4B379CCD2248CFB7004B89B4 /* CoreFoundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -381,8 +384,9 @@
4B90EFFA1FD2AF59008A39E0 = {
isa = PBXGroup;
children = (
4BF18C5B1FD2E74800DF95D1 /* auto */,
4B06F70C22481D980069C9F2 /* ui_events.generated.h */,
4BF18C5A1FD2E72D00DF95D1 /* nvim */,
4B06F70B22481D3A0069C9F2 /* include */,
4BE45C0B1FD2DA49005C0A95 /* runtime */,
4B90F0061FD2AF59008A39E0 /* NvimView */,
4B90F0501FD2AFD3008A39E0 /* NvimServer */,
@ -434,6 +438,7 @@
1929BD896D408673954F4AA2 /* NvimView+Geometry.swift */,
1929BA4C89E9FE90065C32F6 /* CursorModeShape.swift */,
1929BF14AE831C6832659B66 /* Defs.swift */,
1929B27A8FF9A75A09969777 /* foundation_shim.h */,
);
path = NvimView;
sourceTree = "<group>";
@ -441,15 +446,14 @@
4B90F0501FD2AFD3008A39E0 /* NvimServer */ = {
isa = PBXGroup;
children = (
4B4A48DA222C7C5600C8E3A1 /* SharedTypes.h */,
4B90F0511FD2AFD3008A39E0 /* main.m */,
4B90F0571FD2AFF7008A39E0 /* CocoaCategories.h */,
4B90F05A1FD2AFF7008A39E0 /* CocoaCategories.m */,
4B90F05B1FD2AFF7008A39E0 /* Logging.h */,
4B90F0621FD2AFF7008A39E0 /* NvimServer.h */,
4B90F0641FD2AFF7008A39E0 /* NvimServer.m */,
4B90F0631FD2AFF7008A39E0 /* server_ui.h */,
4B90F0561FD2AFF7008A39E0 /* server_ui.m */,
4B4A48DA222C7C5600C8E3A1 /* server_shared_types.h */,
4B90F0511FD2AFD3008A39E0 /* main.c */,
4B90F05B1FD2AFF7008A39E0 /* server_log.h */,
1929B3EAE37505620F8AECD5 /* server.h */,
1929B7398AD1DE525FA53E38 /* server.c */,
4B06F7082247FBEE0069C9F2 /* server_ui_bridge.h */,
4B06F7092247FBEE0069C9F2 /* server_ui_bridge.c */,
1929BFDA282A4CA4838385E9 /* foundation_shim.h */,
);
path = NvimServer;
sourceTree = "<group>";
@ -457,6 +461,7 @@
4B90F06F1FD2B9F1008A39E0 /* Frameworks */ = {
isa = PBXGroup;
children = (
4B379CCC2248CFB6004B89B4 /* CoreFoundation.framework */,
4BEBC239215FD19C007113C4 /* Socket.framework */,
4B0A1B38212B332800F1E02F /* Nimble.framework */,
4B17E548209E3E4100265C1D /* RxNeovimApi.framework */,
@ -506,6 +511,7 @@
files = (
4BF18C5D1FD2EEE400DF95D1 /* NvimView.h in Headers */,
4B4A48DC222C7C6A00C8E3A1 /* SharedTypes.h in Headers */,
1929B0533B55B2349DE2EFE2 /* foundation_shim.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -711,7 +717,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/bash;
shellScript = "if [[ $(md5 -q NvimView/SharedTypes.h) != $(md5 -q NvimServer/SharedTypes.h) ]]; then\n echo \"SharedTypes.h not equal!\"\n exit 1\nfi\n";
shellScript = "if [[ $(md5 -q NvimView/SharedTypes.h) != $(md5 -q NvimServer/server_shared_types.h) ]]; then\n echo \"SharedTypes.h not equal!\"\n exit 1\nfi\n";
};
4BE45C091FD2D92D005C0A95 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
@ -790,10 +796,9 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
4B90F06B1FD2AFF7008A39E0 /* NvimServer.m in Sources */,
4B90F0661FD2AFF7008A39E0 /* server_ui.m in Sources */,
4B90F0521FD2AFD3008A39E0 /* main.m in Sources */,
4B90F0681FD2AFF7008A39E0 /* CocoaCategories.m in Sources */,
4B90F0521FD2AFD3008A39E0 /* main.c in Sources */,
1929BFEAF40AE8349E800CE4 /* server.c in Sources */,
4B06F70A2247FBEE0069C9F2 /* server_ui_bridge.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1070,17 +1075,19 @@
4B90F0541FD2AFD3008A39E0 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = NO;
CLANG_LINK_OBJC_RUNTIME = NO;
CLANG_MODULES_AUTOLINK = NO;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
"INCLUDE_GENERATED_DECLARATIONS=1",
);
HEADER_SEARCH_PATHS = (
"$(PROJECT_DIR)/neovim/build/include",
"$(PROJECT_DIR)/neovim/src",
"$(PROJECT_DIR)/neovim/build/include",
"$(PROJECT_DIR)/neovim/.deps/usr/include",
"$(PROJECT_DIR)/neovim/build/config",
"$(PROJECT_DIR)/third-party/libintl/include",
"$(PROJECT_DIR)/neovim/build/src/nvim/auto",
);
LIBRARY_SEARCH_PATHS = (
"$(PROJECT_DIR)/neovim/build/lib",
@ -1111,14 +1118,16 @@
4B90F0551FD2AFD3008A39E0 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = NO;
CLANG_LINK_OBJC_RUNTIME = NO;
CLANG_MODULES_AUTOLINK = NO;
GCC_PREPROCESSOR_DEFINITIONS = "INCLUDE_GENERATED_DECLARATIONS=1";
HEADER_SEARCH_PATHS = (
"$(PROJECT_DIR)/neovim/build/include",
"$(PROJECT_DIR)/neovim/src",
"$(PROJECT_DIR)/neovim/build/include",
"$(PROJECT_DIR)/neovim/.deps/usr/include",
"$(PROJECT_DIR)/neovim/build/config",
"$(PROJECT_DIR)/third-party/libintl/include",
"$(PROJECT_DIR)/neovim/build/src/nvim/auto",
);
LIBRARY_SEARCH_PATHS = (
"$(PROJECT_DIR)/neovim/build/lib",

View File

@ -63,6 +63,24 @@
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
<CommandLineArguments>
<CommandLineArgument
argument = "nvim-local"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "nvim-remote"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "third"
isEnabled = "YES">
</CommandLineArgument>
</CommandLineArguments>
<LocationScenarioReference
identifier = "com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier"
referenceType = "1">
</LocationScenarioReference>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"

View File

@ -15,3 +15,4 @@ FOUNDATION_EXPORT const unsigned char NvimViewVersionString[];
// TODO: this header should not be public, but we cannot use a bridging header in a framework.
#import <NvimView/SharedTypes.h>
#import <NvimView/foundation_shim.h>

View File

@ -3,9 +3,12 @@
* See LICENSE
*/
#import <Foundation/Foundation.h>
#ifndef NVIMSERVER_SHARED_TYPES_H
#define NVIMSERVER_SHARED_TYPES_H
typedef NS_OPTIONS(NSUInteger, FontTrait) {
#include "foundation_shim.h"
typedef CF_OPTIONS(NSUInteger, FontTrait) {
FontTraitNone = 0,
FontTraitItalic = (1 << 0),
FontTraitBold = (1 << 1),
@ -13,13 +16,13 @@ typedef NS_OPTIONS(NSUInteger, FontTrait) {
FontTraitUndercurl = (1 << 3)
};
typedef NS_ENUM(NSInteger, RenderDataType) {
typedef CF_ENUM(NSInteger, RenderDataType) {
RenderDataTypeRawLine,
RenderDataTypeGoto,
RenderDataTypeScroll,
};
typedef NS_ENUM(NSInteger, NvimServerMsgId) {
typedef CF_ENUM(NSInteger, NvimServerMsgId) {
NvimServerMsgIdServerReady = 0,
NvimServerMsgIdNvimReady,
NvimServerMsgIdResize,
@ -35,7 +38,7 @@ typedef NS_ENUM(NSInteger, NvimServerMsgId) {
NvimServerMsgIdSetTitle,
NvimServerMsgIdStop,
NvimServerMsgIdOptionSet,
NvimServerMsgIdDirtyStatusChanged,
NvimServerMsgIdCwdChanged,
NvimServerMsgIdColorSchemeChanged,
@ -46,14 +49,16 @@ typedef NS_ENUM(NSInteger, NvimServerMsgId) {
NvimServerMsgIdDebug1,
};
typedef NS_ENUM(NSInteger, NvimBridgeMsgId) {
typedef CF_ENUM(NSInteger, NvimBridgeMsgId) {
NvimBridgeMsgIdAgentReady = 0,
NvimBridgeMsgIdReadyForRpcEvents,
NvimBridgeMsgIdDeleteInput,
NvimBridgeMsgIdResize,
NvimBridgeMsgIdScroll,
NvimBridgeMsgIdFocusGained,
NvimBridgeMsgIdDebug1,
};
#endif // NVIMSERVER_SHARED_TYPES_H

View File

@ -0,0 +1,11 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
#ifndef NVIMSERVER_FOUNDATION_SHIM_H
#define NVIMSERVER_FOUNDATION_SHIM_H
#include <Foundation/Foundation.h>
#endif // NVIMSERVER_FOUNDATION_SHIM_H

@ -1 +1 @@
Subproject commit 54c9468a7424d5b4ad754ce22a65910102808a72
Subproject commit dcb37af2a59d4e456a2389755afe4e4313d21ca3