diff options
| -rw-r--r-- | src/dged/buffer.c | 27 | ||||
| -rw-r--r-- | src/dged/buffer.h | 9 | ||||
| -rw-r--r-- | src/dged/text.c | 48 | ||||
| -rw-r--r-- | src/dged/text.h | 3 | ||||
| -rw-r--r-- | src/main/lsp.c | 73 | ||||
| -rw-r--r-- | src/main/lsp/types.c | 4 |
6 files changed, 140 insertions, 24 deletions
diff --git a/src/dged/buffer.c b/src/dged/buffer.c index fed8f87..c3f5655 100644 --- a/src/dged/buffer.c +++ b/src/dged/buffer.c @@ -234,8 +234,6 @@ static void buffer_read_from_file(struct buffer *b) { free(fullname); return; } - - undo_push_boundary(&b->undo, (struct undo_boundary){.save_point = true}); } static void write_line_lf(struct text_chunk *chunk, void *userdata) { @@ -388,6 +386,7 @@ struct buffer buffer_from_file(const char *path) { char *full_path = to_abspath(path); struct buffer b = create_internal(basename((char *)path), full_path); buffer_read_from_file(&b); + undo_push_boundary(&b.undo, (struct undo_boundary){.save_point = true}); dispatch_hook(&g_create_hooks, struct create_hook, &b); @@ -470,6 +469,8 @@ void buffer_set_filename(struct buffer *buffer, const char *filename) { buffer->modified = true; } +static void *text_alloc(size_t sz) { return calloc(sz, 1); } + void buffer_reload(struct buffer *buffer) { if (buffer->filename == NULL) { return; @@ -484,8 +485,26 @@ void buffer_reload(struct buffer *buffer) { if (sb.st_mtim.tv_sec != buffer->last_write.tv_sec || sb.st_mtim.tv_nsec != buffer->last_write.tv_nsec) { + + undo_push_boundary(&buffer->undo, + (struct undo_boundary){.save_point = false}); + + struct text_chunk txt = buffer_text(buffer); + undo_push_delete( + &buffer->undo, + (struct undo_delete){.data = txt.text, + .nbytes = txt.nbytes, + .pos = ((struct position){.col = 0, .row = 0})}); text_clear(buffer->text); + buffer_read_from_file(buffer); + undo_push_add( + &buffer->undo, + (struct undo_add){.begin = (struct position){.col = 0, .row = 0}, + .end = (struct position){ + .col = 0, .row = buffer_num_lines(buffer)}}); + undo_push_boundary(&buffer->undo, + (struct undo_boundary){.save_point = true}); dispatch_hook(&buffer->hooks->reload_hooks, struct reload_hook, buffer); } } @@ -1081,6 +1100,10 @@ struct text_chunk buffer_line(struct buffer *buffer, uint32_t line) { return text_get_line(buffer->text, line); } +struct text_chunk buffer_text(struct buffer *buffer) { + return text_get(buffer->text, text_alloc); +} + struct text_chunk buffer_region(struct buffer *buffer, struct region region) { struct location begin_bytes = buffer_location_to_byte_coords(buffer, region.begin); diff --git a/src/dged/buffer.h b/src/dged/buffer.h index 25cc42b..640150a 100644 --- a/src/dged/buffer.h +++ b/src/dged/buffer.h @@ -435,6 +435,15 @@ struct text_chunk buffer_line(struct buffer *buffer, uint32_t line); struct text_chunk buffer_region(struct buffer *buffer, struct region region); /** + * Get all text in the buffer. + * + * @param buffer The buffer to get text from. + * + * @returns A text chunk describing the full buffer + */ +struct text_chunk buffer_text(struct buffer *buffer); + +/** * Add a text property to a region of the buffer. * * @param buffer The buffer to add a text property to. diff --git a/src/dged/text.c b/src/dged/text.c index 59290ca..f517ed4 100644 --- a/src/dged/text.c +++ b/src/dged/text.c @@ -6,7 +6,6 @@ #include <string.h> #include "display.h" -#include "signal.h" #include "utf8.h" #include "vec.h" @@ -167,6 +166,15 @@ uint32_t text_line_size(const struct text *text, uint32_t lineidx) { uint32_t text_num_lines(const struct text *text) { return text->nlines; } +size_t text_size(const struct text *text) { + size_t total = 0; + for (uint64_t linei = 0; linei < text->nlines; ++linei) { + total += text->lines[linei].nbytes; + } + + return total; +} + static void split_line(struct text *text, uint32_t offset, uint32_t lineidx, uint32_t newlineidx) { struct line *line = &text->lines[lineidx]; @@ -486,6 +494,44 @@ struct text_chunk text_get_region(struct text *text, uint32_t start_line, }; } +struct copy_chunk_params { + enum line_endings line_endings; + struct text_chunk *target_chunk; +}; + +static void copy_chunk(struct text_chunk *src, void *userdata) { + struct copy_chunk_params *params = (struct copy_chunk_params *)userdata; + struct text_chunk *target = params->target_chunk; + + memcpy(target->text + target->nbytes, src->text, src->nbytes); + target->nbytes += src->nbytes; + if (params->line_endings == LineEnding_CRLF) { + target->text[target->nbytes] = '\r'; + ++target->nbytes; + } + + target->text[target->nbytes] = '\n'; + ++target->nbytes; +} + +struct text_chunk text_get(struct text *text, void *(*alloc)(size_t size)) { + size_t needed = text_size(text); + size_t line_end_bytes = 1; + if (text->line_ends == LineEnding_CRLF) { + line_end_bytes = 2; + } + needed += text_num_lines(text) * line_end_bytes; + + struct text_chunk ret = {0}; + ret.text = alloc(needed); + ret.allocated = true; + + struct copy_chunk_params params = {.target_chunk = &ret, + .line_endings = text->line_ends}; + text_for_each_chunk(text, copy_chunk, ¶ms); + return ret; +} + static property_vec *find_property_layer(struct text *text, layer_id layer) { if (layer == PropertyLayer_Default) { return &text->properties; diff --git a/src/dged/text.h b/src/dged/text.h index 108ded8..1ad6dbc 100644 --- a/src/dged/text.h +++ b/src/dged/text.h @@ -41,6 +41,7 @@ void text_delete(struct text *text, uint32_t start_line, uint32_t start_offset, enum line_endings text_get_line_ending(const struct text *); +size_t text_size(const struct text *text); uint32_t text_num_lines(const struct text *text); uint32_t text_line_size(const struct text *text, uint32_t lineidx); struct utf8_codepoint_iterator @@ -59,6 +60,8 @@ struct text_chunk text_get_region(struct text *text, uint32_t start_line, uint32_t start_offset, uint32_t end_line, uint32_t end_offset); +struct text_chunk text_get(struct text *text, void *(*alloc)(size_t size)); + enum text_property_type { TextProperty_Colors, TextProperty_Data, diff --git a/src/main/lsp.c b/src/main/lsp.c index e09f308..7f30a93 100644 --- a/src/main/lsp.c +++ b/src/main/lsp.c @@ -9,6 +9,7 @@ #include "dged/hash.h" #include "dged/hashmap.h" #include "dged/lang.h" +#include "dged/location.h" #include "dged/minibuffer.h" #include "dged/reactor.h" #include "dged/settings.h" @@ -190,6 +191,57 @@ request_response_received(struct lsp_server *server, uint64_t id, return false; } +static struct region edit_location_to_lsp(struct buffer *buffer, + struct edit_location edit, + struct lsp_server *server) { + + struct region res = edit.coordinates; + if (server->position_encoding == PositionEncoding_Utf8) { + /* In this case, the buffer hook has already + * done the job for us. */ + res.begin.col = edit.bytes.begin.col; + res.end.col = edit.bytes.end.col; + return res; + } + + return region_to_lsp(buffer, res, server); +} + +static void buffer_reloaded(struct buffer *buffer, void *userdata) { + struct lsp_server *server = (struct lsp_server *)userdata; + + struct text_chunk new_text = buffer_text(buffer); + + struct text_document_content_change_event evt = { + .full_document = true, + .text = s8new((const char *)new_text.text, new_text.nbytes), + .range = region_new( + (struct location){.col = 0, .line = 0}, + (struct location){.col = 0, .line = buffer_num_lines(buffer)}), + }; + + struct versioned_text_document_identifier text_document = + versioned_identifier_from_buffer(buffer); + struct did_change_text_document_params params = { + .text_document = text_document, + .content_changes = &evt, + .ncontent_changes = 1, + }; + + struct s8 json_payload = did_change_text_document_params_to_json(¶ms); + + lsp_send(server->lsp, + lsp_create_notification(s8("textDocument/didChange"), json_payload)); + + versioned_text_document_identifier_free(&text_document); + s8delete(json_payload); + s8delete(evt.text); + + if (new_text.allocated) { + free(new_text.text); + } +} + static void buffer_updated(struct buffer *buffer, void *userdata) { struct lsp_server *server = (struct lsp_server *)userdata; @@ -318,22 +370,6 @@ static uint32_t count_bytes(struct text_chunk *chunk, uint32_t target_col) { return nbytes; } -static struct region edit_location_to_lsp(struct buffer *buffer, - struct edit_location edit, - struct lsp_server *server) { - - struct region res = edit.coordinates; - if (server->position_encoding == PositionEncoding_Utf8) { - /* In this case, the buffer hook has already - * done the job for us. */ - res.begin.col = edit.bytes.begin.col; - res.end.col = edit.bytes.end.col; - return res; - } - - return region_to_lsp(buffer, res, server); -} - struct region region_to_lsp(struct buffer *buffer, struct region region, struct lsp_server *server) { struct region res = region; @@ -386,9 +422,7 @@ static void buffer_text_changed(struct buffer *buffer, return; case TextDocumentSync_Full: - new_text = - buffer_region(buffer, region_new((struct location){.line = 0, .col = 0}, - buffer_end(buffer))); + new_text = buffer_text(buffer); break; case TextDocumentSync_Incremental: @@ -475,6 +509,7 @@ static void lsp_buffer_initialized(struct lsp_server *server, buffer_add_update_hook(buffer, buffer_updated, server); buffer_add_pre_save_hook(buffer, buffer_pre_save, server); buffer_add_post_save_hook(buffer, buffer_post_save, server); + buffer_add_reload_hook(buffer, buffer_reloaded, server); send_did_open(server, buffer); setup_completion(server, buffer); diff --git a/src/main/lsp/types.c b/src/main/lsp/types.c index a623be0..cd46afa 100644 --- a/src/main/lsp/types.c +++ b/src/main/lsp/types.c @@ -272,7 +272,7 @@ struct s8 did_change_text_document_params_to_json( event_buf_size += num; } else { - const char *item_fmt = "{ \"text\", \"%.*s\" }%s"; + const char *item_fmt = "{ \"text\": \"%.*s\" }%s"; ssize_t num = snprintf(NULL, 0, item_fmt, escaped.l, escaped.s, i == params->ncontent_changes - 1 ? "" : ", "); @@ -309,7 +309,7 @@ struct s8 did_change_text_document_params_to_json( offset += num; } else { - const char *item_fmt = "{ \"text\", \"%.*s\" }%s"; + const char *item_fmt = "{ \"text\": \"%.*s\" }%s"; ssize_t num = snprintf(&buf[offset], event_buf_size - offset, item_fmt, escaped.l, escaped.s, i == params->ncontent_changes - 1 ? "" : ", "); |
