1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
#include "format.h"
#include "completion.h"
#include "dged/buffer.h"
#include "dged/buffer_view.h"
#include "dged/minibuffer.h"
#include "dged/settings.h"
#include "dged/window.h"
#include "main/completion.h"
#include "main/lsp.h"
struct formatted_buffer {
struct buffer *buffer;
bool save;
};
static uint32_t get_tab_width(struct buffer *buffer) {
struct setting *tw = lang_setting(&buffer->lang, "tab-width");
if (tw == NULL) {
tw = settings_get("editor.tab-width");
}
uint32_t tab_width = 4;
if (tw != NULL && tw->value.type == Setting_Number) {
tab_width = tw->value.data.number_value;
}
return tab_width;
}
static bool use_tabs(struct buffer *buffer) {
struct setting *ut = lang_setting(&buffer->lang, "use-tabs");
if (ut == NULL) {
ut = settings_get("editor.use-tabs");
}
bool use_tabs = false;
if (ut != NULL && ut->value.type == Setting_Bool) {
use_tabs = ut->value.data.bool_value;
}
return use_tabs;
}
static struct formatting_options options_from_lang(struct buffer *buffer) {
return (struct formatting_options){
.tab_size = get_tab_width(buffer),
.use_spaces = !use_tabs(buffer),
};
}
void handle_format_response(struct lsp_server *server,
struct lsp_response *response, void *userdata) {
text_edit_vec edits = text_edits_from_json(&response->value.result);
struct formatted_buffer *buffer = (struct formatted_buffer *)userdata;
pause_completion();
if (!VEC_EMPTY(&edits)) {
apply_edits_buffer(server, buffer->buffer, edits, NULL);
if (buffer->save) {
buffer_to_file(buffer->buffer);
}
}
resume_completion();
text_edits_free(edits);
free(buffer);
}
static void format_buffer(struct lsp_server *server, struct buffer *buffer,
bool save) {
struct formatted_buffer *b =
(struct formatted_buffer *)calloc(1, sizeof(struct formatted_buffer));
b->buffer = buffer;
b->save = save;
uint64_t id = new_pending_request(server, handle_format_response, b);
struct versioned_text_document_identifier doc =
versioned_identifier_from_buffer(buffer);
struct document_formatting_params params = {
.text_document.uri = doc.uri,
.options = options_from_lang(buffer),
};
struct s8 json_payload = document_formatting_params_to_json(¶ms);
lsp_send(lsp_backend(server),
lsp_create_request(id, s8("textDocument/formatting"), json_payload));
versioned_text_document_identifier_free(&doc);
s8delete(json_payload);
}
void format_document(struct lsp_server *server, struct buffer *buffer) {
format_buffer(server, buffer, false);
}
void format_document_save(struct lsp_server *server, struct buffer *buffer) {
format_buffer(server, buffer, true);
}
void format_region(struct lsp_server *server, struct buffer *buffer,
struct region region) {
struct formatted_buffer *b =
(struct formatted_buffer *)calloc(1, sizeof(struct formatted_buffer));
b->buffer = buffer;
b->save = false;
uint64_t id = new_pending_request(server, handle_format_response, b);
struct versioned_text_document_identifier doc =
versioned_identifier_from_buffer(buffer);
struct document_range_formatting_params params = {
.text_document.uri = doc.uri,
.range = region_to_lsp(buffer, region, server),
.options = options_from_lang(buffer),
};
struct s8 json_payload = document_range_formatting_params_to_json(¶ms);
lsp_send(lsp_backend(server),
lsp_create_request(id, s8("textDocument/formatting"), json_payload));
versioned_text_document_identifier_free(&doc);
s8delete(json_payload);
}
int32_t format_cmd(struct command_ctx ctx, int argc, const char **argv) {
(void)ctx;
(void)argc;
(void)argv;
struct buffer_view *bv = window_buffer_view(windows_get_active());
struct lsp_server *server = lsp_server_for_lang_id(bv->buffer->lang.id);
if (server == NULL) {
return 0;
}
struct region reg = region_new(bv->dot, bv->mark);
if (bv->mark_set && region_has_size(reg)) {
buffer_view_clear_mark(bv);
format_region(server, bv->buffer, reg);
} else {
format_document(server, bv->buffer);
}
return 0;
}
|