Skip to content

Instantly share code, notes, and snippets.

@ssilva
Last active September 12, 2017 02:12
Show Gist options
  • Save ssilva/930d188bd30a985a47199683390ec400 to your computer and use it in GitHub Desktop.
Save ssilva/930d188bd30a985a47199683390ec400 to your computer and use it in GitHub Desktop.
msgpack neovim c client proof of concept
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <msgpack.h>
/*
* $ NVIM_LISTEN_ADDRESS=127.0.0.1:8888 nvim
*
*/
void unpack_stream(msgpack_sbuffer *sbuf)
{
msgpack_unpacker unpacker;
msgpack_unpacker_init(&unpacker, MSGPACK_UNPACKER_INIT_BUFFER_SIZE);
// Feed the unpacked with data
msgpack_unpacker_reserve_buffer(&unpacker, sbuf->size);
memcpy(msgpack_unpacker_buffer(&unpacker), sbuf->data, sbuf->size);
msgpack_unpacker_buffer_consumed(&unpacker, sbuf->size);
msgpack_unpacked result;
msgpack_unpacked_init(&result);
while (msgpack_unpacker_next(&unpacker, &result)) {
msgpack_object_print(stdout, result.data);
puts("");
}
}
void unpack(msgpack_sbuffer *sbuf)
{
msgpack_zone mempool;
msgpack_zone_init(&mempool, 2048);
msgpack_object deserialized;
msgpack_unpack(sbuf->data, sbuf->size, NULL, &mempool, &deserialized);
msgpack_object_print(stdout, deserialized);
puts("");
msgpack_zone_destroy(&mempool);
}
void prepare(msgpack_sbuffer *sbuf)
{
msgpack_packer packer;
msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write);
// [0, id, 0, "method", ["param1", "param2"]]
msgpack_pack_array(&packer, 4);
msgpack_pack_int(&packer, 0);
msgpack_pack_int(&packer, 82);
char method[] = "vim_command";
msgpack_pack_str(&packer, sizeof(method) - 1);
msgpack_pack_str_body(&packer, method, sizeof(method) - 1);
msgpack_pack_array(&packer, 1);
char param[] = "echo \"hello world\"";
msgpack_pack_str(&packer, sizeof(param) - 1);
msgpack_pack_str_body(&packer, param, sizeof(param) - 1);
}
int connect_nvim(unsigned int port)
{
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if (sfd == -1) {
fprintf(stderr, "Error opening socket\n");
return -1;
}
struct sockaddr_in addr;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = 0;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_family = AF_INET;
if (connect(sfd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
fprintf(stderr, "Error connecting to socket\n");
return -1;
}
return sfd;
}
int main(int argc, char **argv)
{
// FIXME Do not hard-code the port
//char *nvim_listen_addr = getenv("NVIM_LISTEN_ADDRESS");
//if (nvim_listen_addr)
// printf("Detected env var: %s\n", nvim_listen_addr);
int sfd = connect_nvim(8888);
msgpack_sbuffer sbuf;
msgpack_sbuffer_init(&sbuf);
prepare(&sbuf);
printf("About to send: ");
unpack(&sbuf);
if (write(sfd, sbuf.data, sbuf.size) == -1) {
fprintf(stderr, "Error sending data\n");
return 1;
}
if (read(sfd, sbuf.data, sbuf.size) == -1) {
fprintf(stderr, "Error receiving data\n");
return 1;
}
close(sfd);
printf("Received: ");
unpack(&sbuf);
msgpack_sbuffer_destroy(&sbuf);
return 0;
}
TARGET=nvim-c-client
CC=gcc
DEBUG=-g
OPT=-O0
WARN=-Wall
PTHREAD=-pthread
CCFLAGS=$(DEBUG) $(OPT) $(WARN) $(PTHREAD) -pipe
MSGPACKLIB=`pkg-config --cflags --libs msgpack`
LD=gcc
#LDFLAGS=$(PTHREAD) $(MSGPACKLIB) -export-dynamic
LDFLAGS=$(MSGPACKLIB)
OBJS=main.o
all: $(OBJS)
$(LD) -o $(TARGET) $(OBJS) $(LDFLAGS)
main.o: src/main.c
$(CC) -c $(CCFLAGS) src/main.c $(MSGPACKLIB) -o main.o
clean:
rm -f *.o $(TARGET)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment