se

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 }