From 23e138019964662b4e847770eeda2bb5d3130f7a Mon Sep 17 00:00:00 2001 From: pommicket Date: Thu, 22 Dec 2022 16:38:32 -0500 Subject: better write_string --- ds.c | 14 +++++++++++++- json.c | 5 ++++- lsp-write-request.c | 30 +++++++++++++++++++++--------- main.c | 1 + 4 files changed, 39 insertions(+), 11 deletions(-) diff --git a/ds.c b/ds.c index ef4a1b4..eb235d6 100644 --- a/ds.c +++ b/ds.c @@ -297,7 +297,6 @@ void str_builder_append(StrBuilder *builder, const char *s) { size_t prev_len = prev_size - 1; // null terminator // note: this zeroes the newly created elements, so we have a new null terminator arr_set_len(builder->str, prev_size + s_len); - // -1 for null terminator memcpy(builder->str + prev_len, s, s_len); } @@ -331,3 +330,16 @@ u32 str_builder_len(StrBuilder *builder) { return arr_len(builder->str) - 1; } +char *str_builder_get_ptr(StrBuilder *builder, size_t index) { + assert(index <= str_builder_len(builder)); + return &builder->str[index]; +} + +void str_builder_shrink(StrBuilder *builder, size_t new_len) { + if (new_len > str_builder_len(builder)) { + assert(0); + return; + } + arr_set_len(builder->str, new_len + 1); +} + diff --git a/json.c b/json.c index 5d83b89..c11d907 100644 --- a/json.c +++ b/json.c @@ -605,7 +605,9 @@ void json_debug_print(const JSON *json) { // e.g. converts "Hello\nworld" to "Hello\\nworld" // if out_sz is at least 2 * strlen(str) + 1, the string will fit. -void json_escape_to(char *out, size_t out_sz, const char *in) { +// returns the number of bytes actually written, not including the null terminator. +size_t json_escape_to(char *out, size_t out_sz, const char *in) { + char *start = out; char *end = out + out_sz; assert(out_sz); @@ -653,6 +655,7 @@ void json_escape_to(char *out, size_t out_sz, const char *in) { } brk: *out = '\0'; + return (size_t)(out - start); } // e.g. converts "Hello\nworld" to "Hello\\nworld" diff --git a/lsp-write-request.c b/lsp-write-request.c index e5d671d..f375559 100644 --- a/lsp-write-request.c +++ b/lsp-write-request.c @@ -74,11 +74,23 @@ static void write_arr_elem(JSONWriter *o) { } } -static void write_string(JSONWriter *o, const char* string) { - // @TODO: escape in-place - char *escaped = json_escape(string); - str_builder_appendf(&o->builder, "\"%s\"", escaped); - free(escaped); +static void write_escaped(JSONWriter *o, const char *string) { + StrBuilder *b = &o->builder; + size_t output_index = str_builder_len(b); + size_t capacity = 2 * strlen(string) + 1; + // append a bunch of null bytes which will hold the escaped string + str_builder_append_null(b, capacity); + char *out = str_builder_get_ptr(b, output_index); + // do the escaping + size_t length = json_escape_to(out, capacity, string); + // shrink down to just the escaped text + str_builder_shrink(&o->builder, output_index + length); +} + +static void write_string(JSONWriter *o, const char *string) { + str_builder_append(&o->builder, "\""); + write_escaped(o, string); + str_builder_append(&o->builder, "\""); } static void write_key(JSONWriter *o, const char *key) { @@ -121,10 +133,10 @@ static void write_key_string(JSONWriter *o, const char *key, const char *s) { } static void write_file_uri(JSONWriter *o, DocumentID document) { - // @OPTIM : could store escaped document paths instead of document paths - char *escaped_path = json_escape(o->lsp->document_paths[document]); - str_builder_appendf(&o->builder, "\"file:///%s\"", escaped_path); - free(escaped_path); + const char *path = o->lsp->document_paths[document]; + str_builder_append(&o->builder, "\"file:///"); + write_escaped(o, path); + str_builder_append(&o->builder, "\""); } static void write_key_file_uri(JSONWriter *o, const char *key, DocumentID document) { diff --git a/main.c b/main.c index f0321ee..df88311 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,7 @@ /* @TODO: - send didClose +- don't select the one and only completion when user types stuff - LSP setting - scroll through completions - figure out under which circumstances backspace should close completions -- cgit v1.2.3