summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dged/buffer.c27
-rw-r--r--src/dged/buffer.h9
-rw-r--r--src/dged/text.c48
-rw-r--r--src/dged/text.h3
-rw-r--r--src/main/lsp.c73
-rw-r--r--src/main/lsp/types.c4
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, &params);
+ 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(&params);
+
+ 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 ? "" : ", ");