se.c (10328B)
1 /* See LICENSE for license details. */ 2 3 /* 4 ** This file mainly contains the functionality of handling the 5 ** "buffer". There should a good amount of customisation you 6 ** can do wihtout tuching this file, but adding or changing 7 ** functionality to fit your needs shouldn't be too hard. 8 */ 9 10 #include <errno.h> 11 #include <ctype.h> 12 #include <stdarg.h> 13 #include <time.h> 14 #include <dirent.h> 15 16 #include "se.h" 17 #include "x.h" 18 #include "config.h" 19 #include "extension.h" 20 21 ///////////////////////////////////////////// 22 // Internal functions 23 // 24 25 static int writef_string(int y, int x1, int x2, const char* fmt, ...); 26 static void color_selection(struct glyph* letter); 27 28 //////////////////////////////////////////// 29 // function implementations 30 // 31 32 int 33 writef_string(int y, int x1, int x2, const char* fmt, ...) 34 { 35 char string[STATUS_BAR_MAX_LEN]; 36 37 va_list args; 38 va_start(args, fmt); 39 vsnprintf(string, STATUS_BAR_MAX_LEN, fmt, args); 40 va_end(args); 41 42 return write_string(string, y, x1, x2); 43 } 44 45 char status_bar_contents[STATUS_BAR_MAX_LEN] = {0}; 46 static int status_bar_end; 47 uint32_t status_bar_bg; 48 void 49 writef_to_status_bar(const char* fmt, ...) 50 { 51 if (fmt) { 52 if (status_bar_bg == error_color || 53 status_bar_bg == warning_color || 54 status_bar_bg == ok_color) 55 return; 56 57 va_list args; 58 va_start(args, fmt); 59 vsnprintf(status_bar_contents, STATUS_BAR_MAX_LEN, fmt, args); 60 va_end(args); 61 62 status_bar_bg = alternate_bg_dark; 63 return; 64 } 65 66 global_attr = default_attributes; 67 global_attr.bg = status_bar_bg; 68 69 status_bar_end = write_string(status_bar_contents, screen.row-1, 0, screen.col); 70 screen_set_region(status_bar_end, screen.row-1, screen.col-1, screen.row-1, ' '); 71 72 global_attr = default_attributes; 73 } 74 75 void 76 draw_status_bar() 77 { 78 writef_to_status_bar(NULL); 79 xdrawline(0, screen.row-1, screen.col); 80 draw_horisontal_line(screen.row-2, 0, screen.col-1); 81 if (get_fb(focused_window)->mode & FB_SEARCH_BLOCKING) 82 xdrawcursor(status_bar_end, screen.row-1, 1); 83 status_bar_bg = alternate_bg_dark; 84 } 85 86 void 87 window_node_draw_to_screen(struct window_split_node* wn) 88 { 89 struct window_buffer* wb = &wn->wb; 90 struct file_buffer* fb = get_fb(wb); 91 int minx = wn->minx, miny = wn->miny, 92 maxx = wn->maxx, maxy = wn->maxy; 93 94 LIMIT(wb->cursor_offset, 0, fb->len); 95 screen_set_region(minx, miny, maxx, maxy, ' '); 96 int focused = wb == focused_window && !(fb->mode & FB_SEARCH_BLOCKING); 97 98 int x = minx, y = miny; 99 global_attr = default_attributes; 100 101 // force the screen in a place where the cursor is visable 102 int ox, oy, xscroll; 103 fb_offset_to_xy(fb, wb->cursor_offset, maxx - minx, wb->y_scroll, &ox, &oy, &xscroll); 104 if (oy < 0) { 105 wb->y_scroll += oy; 106 } else { 107 oy += miny - maxy+2; 108 if (oy > 0) 109 wb->y_scroll += oy; 110 } 111 if (wb->y_scroll < 0) 112 wb->y_scroll = 0; 113 114 if (wrap_buffer) 115 xscroll = 0; 116 117 // move to y_scroll 118 char* repl = fb->contents; 119 char* last = repl + fb->len; 120 char* new_repl; 121 int line = wb->y_scroll; 122 while ((new_repl = memchr(repl, '\n', last - repl))) { 123 if (--line < 0) 124 break; 125 else if (new_repl+1 < last) 126 repl = new_repl+1; 127 else 128 return; 129 } 130 int offset_start = repl - fb->contents - 1; 131 int cursor_x = 0, cursor_y = 0; 132 133 // actually write to the screen 134 int once = 0; 135 int search_found = 0; 136 int non_blocking_search_found = 0; 137 138 // TODO: verify that last - repl is the same as offset_last - offset_start 139 int move_buffer_len = last - repl + 2; 140 uint8_t* move_buffer = xmalloc(move_buffer_len); 141 memset(move_buffer, 0, move_buffer_len); 142 move_buffer[0] = 0; 143 int lastx = x, lasty = y; 144 int move_buffer_index = 0; 145 146 // TODO: write max string len of 127 147 // TODO: make the write thing similar to syntax? 148 char* new_line_start = NULL; 149 call_extension(wb_new_line_draw, &new_line_start, wb, y - miny, maxy - y, minx, maxx, &global_attr); 150 if (new_line_start) { 151 struct glyph old_attr = global_attr; 152 global_attr = default_attributes; 153 x = write_string(new_line_start, y, minx, maxx+1); 154 global_attr = old_attr; 155 } 156 157 int tmp = 0; 158 call_extension(wb_write_status_bar, &tmp, NULL, 0, 0, 0, 0, NULL, NULL); 159 160 for (int charsize = 1; repl < last && charsize; repl += charsize) { 161 if (y > lasty) { 162 move_buffer[move_buffer_index] = x - minx; 163 move_buffer[move_buffer_index] |= 1<<7; 164 } else { 165 move_buffer[move_buffer_index] = x - lastx; 166 } 167 move_buffer_index++; 168 lastx = x, lasty = y; 169 170 if (!once && repl - fb->contents >= wb->cursor_offset) { 171 // if the buffer being drawn is focused, set the cursor position global 172 once = 1; 173 cursor_x = x - xscroll; 174 cursor_y = y; 175 LIMIT(cursor_x, minx, maxx); 176 LIMIT(cursor_y, miny, maxy); 177 } 178 179 if (!wrap_buffer && x - xscroll > maxx && *repl != '\n') { 180 charsize = 1; 181 x++; 182 continue; 183 } 184 185 if (*repl == '\n' || (wrap_buffer && x >= maxx)) { 186 x = minx; 187 if (++y >= maxy-1) 188 break; 189 if (wrap_buffer && *repl != '\n') 190 continue; 191 charsize = 1; 192 char* new_line_start = NULL; 193 call_extension(wb_new_line_draw, &new_line_start, wb, y - miny, maxy - y, minx, maxx, &global_attr); 194 if (new_line_start) { 195 struct glyph old_attr = global_attr; 196 global_attr = default_attributes; 197 x = write_string(new_line_start, y, minx, maxx+1); 198 global_attr = old_attr; 199 } 200 continue; 201 } else if (*repl == '\t') { 202 charsize = 1; 203 if ((x - minx) <= 0) { 204 x += screen_set_char(' ', x - xscroll, y); 205 if (x >= maxx) 206 continue; 207 } 208 while ((x - minx) % tabspaces != 0 && x - xscroll <= maxx) 209 x += screen_set_char(' ', x - xscroll, y); 210 211 if (x - xscroll <= maxx) 212 x += screen_set_char(' ', x, y); 213 continue; 214 } 215 216 rune_t u; 217 charsize = utf8_decode_buffer(repl, last - repl, &u); 218 219 int width; 220 if (x - xscroll >= minx) 221 width = screen_set_char(u, x - xscroll, y); 222 else 223 width = wcwidth(u); 224 225 // drawing search highlight 226 if (fb->mode & FB_SEARCH_BLOCKING_MASK) { 227 if (!search_found && fb_offset_starts_with(fb, repl - fb->contents, fb->search_term)) 228 search_found = strlen(fb->search_term); 229 if (search_found) { 230 screen_set_attr(x - xscroll, y)->bg = highlight_color; 231 screen_set_attr(x - xscroll, y)->fg = default_attributes.bg; 232 search_found--; 233 } 234 } 235 if (fb->mode & FB_SEARCH_NON_BLOCKING) { 236 if (!non_blocking_search_found && fb_offset_starts_with(fb, repl - fb->contents, fb->non_blocking_search_term)) 237 non_blocking_search_found = strlen(fb->search_term); 238 if (non_blocking_search_found) { 239 screen_set_attr(x - xscroll, y)->fg = highlight_color; 240 screen_set_attr(x - xscroll, y)->mode |= ATTR_UNDERLINE; 241 non_blocking_search_found--; 242 } 243 } 244 245 x += width; 246 } 247 int offset_end = repl - fb->contents; 248 global_attr = default_attributes; 249 250 if (wb->cursor_offset >= fb->len) { 251 cursor_x = x - xscroll; 252 cursor_y = MIN(y, maxy); 253 } 254 255 call_extension(window_written_to_screen, wn, offset_start, offset_end, move_buffer, move_buffer_len); 256 257 int status_end = minx; 258 int write_again; 259 do { 260 write_again = 0; 261 char bar[LINE_MAX_LEN]; 262 *bar = 0; 263 264 call_extension(wb_write_status_bar, &write_again, wb, status_end, maxx+1, cursor_x - minx + xscroll, cursor_y - miny + wb->y_scroll, bar, &global_attr); 265 status_end = write_string(bar, maxy-1, status_end, maxx+1); 266 267 global_attr = default_attributes; 268 } while (write_again); 269 270 if (fb->mode & FB_SELECTION_ON) { 271 int y1, y2, tmp; 272 fb_offset_to_xy(fb, fb->s1o, 0, wb->y_scroll, &tmp, &y1, &tmp); 273 fb_offset_to_xy(fb, fb->s2o, 0, wb->y_scroll, &tmp, &y2, &tmp); 274 writef_string(maxy-1, status_end, maxx, " %dL", abs(y1-y2)); 275 } 276 277 if (focused) { 278 for (int i = minx; i < maxx+1; i++) { 279 if (!(fb->mode & FB_SELECTION_ON)) { 280 if (screen_set_attr(i, cursor_y)->bg == default_attributes.bg) 281 screen_set_attr(i, cursor_y)->bg = mouse_line_bg; 282 } 283 screen_set_attr(i, maxy-1)->bg = alternate_bg_bright; 284 } 285 } 286 287 wb_write_selection(wb, minx, miny, maxx, maxy); 288 //do_syntax_scheme(NULL, &(struct syntax_scheme){0}, 0); 289 290 for (int i = miny; i < maxy; i++) 291 xdrawline(minx, i, maxx+1); 292 293 draw_horisontal_line(maxy-1, minx, maxx); 294 295 xdrawcursor(cursor_x, cursor_y, focused); 296 free(move_buffer); 297 } 298 299 int 300 write_string(const char* string, int y, int minx, int maxx) 301 { 302 if (!string) 303 return 0; 304 LIMIT(maxx, 0, screen.col); 305 LIMIT(minx, 0, maxx); 306 307 int offset = 0; 308 int len = strlen(string); 309 while(minx < maxx && offset < len) { 310 rune_t u; 311 int charsize = utf8_decode_buffer(string + offset, len - offset, &u); 312 offset += charsize; 313 if (charsize == 1 && u <= 32) 314 u = ' '; 315 minx += screen_set_char(u, minx, y); 316 } 317 return minx; 318 } 319 320 void 321 color_selection(struct glyph* letter) 322 { 323 if (letter->bg == default_attributes.bg) 324 letter->bg = selection_bg; 325 } 326 327 void 328 wb_move_cursor_to_selection_start(struct window_buffer* wb) 329 { 330 const struct file_buffer* fb = get_fb(wb); 331 if (fb_is_selection_start_top_left(fb)) 332 wb_move_to_offset(wb, fb->s1o, CURSOR_SNAPPED); 333 else 334 wb_move_to_offset(wb, fb->s2o, CURSOR_SNAPPED); 335 } 336 337 void 338 wb_write_selection(struct window_buffer* wb, int minx, int miny, int maxx, int maxy) 339 { 340 soft_assert(wb, return;); 341 struct file_buffer* fb = get_fb(wb); 342 343 LIMIT(maxx, 0, screen.col-1); 344 LIMIT(maxy, 0, screen.row-1); 345 LIMIT(minx, 0, maxx); 346 LIMIT(miny, 0, maxy); 347 348 if (!(fb->mode & FB_SELECTION_ON)) 349 return; 350 351 int x, y, x2, y2, tmp, xscroll; 352 if (fb_is_selection_start_top_left(fb)) { 353 fb_offset_to_xy(fb, fb->s1o, maxx - minx, wb->y_scroll, &x, &y, &tmp); 354 fb_offset_to_xy(fb, fb->s2o, maxx - minx, wb->y_scroll, &x2, &y2, &xscroll); 355 } else { 356 fb_offset_to_xy(fb, fb->s2o, maxx - minx, wb->y_scroll, &x, &y, &xscroll); 357 fb_offset_to_xy(fb, fb->s1o, maxx - minx, wb->y_scroll, &x2, &y2, &tmp); 358 } 359 x += minx, x2 += minx + 1; 360 y += miny, y2 += miny; 361 if (!wrap_buffer) { 362 x -= xscroll; 363 x2 -= xscroll; 364 } 365 366 367 for(; y < y2; y++) { 368 for(; x <= maxx; x++) 369 color_selection(screen_set_attr(x, y)); 370 x = 0; 371 } 372 for(; x < x2; x++) 373 color_selection(screen_set_attr(x, y)); 374 }