vip

VI Plus
git clone https://codeberg.org/night0721/vip
Log | Files | Refs | README | LICENSE

editor.c (5887B)


      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 #include <unistd.h>
      5 #include <ctype.h>
      6 
      7 #include "editor.h"
      8 #include "vip.h"
      9 #include "term.h"
     10 #include "io.h"
     11 #include "bar.h"
     12 
     13 extern editor vip;
     14 
     15 void refresh_screen()
     16 {
     17 	scroll();
     18 
     19 	struct abuf ab = ABUF_INIT;
     20 
     21 	abAppend(&ab, "\x1b[?25l", 6);
     22 	abAppend(&ab, "\x1b[H", 3);
     23 
     24 	draw_rows(&ab);
     25 	draw_status_bar(&ab);
     26 	draw_message_bar(&ab);
     27 
     28 	char buf[32];
     29 	snprintf(buf, sizeof(buf), "\x1b[%d;%dH", (vip.cy - vip.rowoff) + 1,
     30 			(vip.rx - vip.coloff) + 1);
     31 	abAppend(&ab, buf, strlen(buf));
     32 
     33 	abAppend(&ab, "\x1b[?25h", 6);
     34 
     35 	write(STDOUT_FILENO, ab.b, ab.len);
     36 	abFree(&ab);
     37 }
     38 
     39 void move_cursor(int key)
     40 {
     41 	row *row = (vip.cy >= vip.rows) ? NULL : &vip.row[vip.cy];
     42 	switch (key) {
     43 		case ARROW_LEFT:
     44 			if (vip.cx != 0) {
     45 				vip.cx--;
     46 			}
     47 			break;
     48 		case ARROW_RIGHT:
     49 			if (row && vip.cx < row->size) {
     50 				vip.cx++;
     51 			}
     52 			break;
     53 		case ARROW_UP:
     54 			if (vip.cy != 0) {
     55 				vip.cy--;
     56 			}
     57 			break;
     58 		case ARROW_DOWN:
     59 			if (vip.cy < vip.rows) {
     60 				vip.cy++;
     61 			}
     62 			break;
     63 	}
     64 	row = (vip.cy >= vip.rows) ? NULL : &vip.row[vip.cy];
     65 	int rowlen = row ? row->size : 0;
     66 	if (vip.cx > rowlen) {
     67 		vip.cx = rowlen;
     68 	}
     69 }
     70 
     71 void scroll()
     72 {
     73 	vip.rx = 0;
     74 	if (vip.cy < vip.rows) {
     75 		vip.rx = row_cx_to_rx(&vip.row[vip.cy], vip.cx);
     76 	}
     77 	if (vip.cy < vip.rowoff) {
     78 		vip.rowoff = vip.cy;
     79 	}
     80 	if (vip.cy >= vip.rowoff + vip.screenrows) {
     81 		vip.rowoff = vip.cy - vip.screenrows + 1;
     82 	}
     83 	if (vip.rx < vip.coloff) {
     84 		vip.coloff = vip.rx;
     85 	}
     86 	if (vip.rx >= vip.coloff + vip.screencols) {
     87 		vip.coloff = vip.rx - vip.screencols + 1;
     88 	}
     89 }
     90 
     91 void insert_char(int c)
     92 {
     93 	if (vip.cy == vip.rows) {
     94 		insert_row(vip.rows, "", 0);
     95 	}
     96 	row_insert_char(&vip.row[vip.cy], vip.cx, c);
     97 	vip.cx++;
     98 }
     99 
    100 void insert_new_line()
    101 {
    102 	if (vip.cx == 0) {
    103 		insert_row(vip.cy, "", 0);
    104 	} else {
    105 		row *row = &vip.row[vip.cy];
    106 		insert_row(vip.cy + 1, &row->chars[vip.cx], row->size - vip.cx);
    107 		row = &vip.row[vip.cy];
    108 		row->size = vip.cx;
    109 		row->chars[row->size] = '\0';
    110 		update_row(row);
    111 	}
    112 	vip.cy++;
    113 	vip.cx = 0;
    114 }
    115 
    116 /*
    117  * 'o' in vim
    118  */
    119 void shift_new_line()
    120 {
    121 	insert_row(vip.cy + 1, "", 0);
    122 	vip.cy++;
    123 	vip.cx = 0;
    124 }
    125 
    126 void del_char()
    127 {
    128 	if (vip.cy == vip.rows) return;
    129 	if (vip.cx == 0 && vip.cy == 0) return;
    130 
    131 	row *row = &vip.row[vip.cy];
    132 	if (vip.cx > 0) {
    133 		row_del_char(row, vip.cx - 1);
    134 		vip.cx--;
    135 	} else {
    136 		vip.cx = vip.row[vip.cy - 1].size;
    137 		row_append_str(&vip.row[vip.cy - 1], row->chars, row->size);
    138 		del_row(vip.cy);
    139 		vip.cy--;
    140 	}
    141 }
    142 
    143 void init_editor()
    144 {
    145 	vip.cx = 0;
    146 	vip.cy = 0;
    147 	vip.rx = 0;
    148 	vip.rowoff = 0;
    149 	vip.coloff = 0;
    150 	vip.rows = 0;
    151 	vip.row = NULL;
    152 	vip.dirty = 0;
    153 	vip.mode = NORMAL;
    154 	vip.filename = NULL;
    155 	vip.statusmsg[0] = '\0';
    156 	vip.statusmsg_time = 0;
    157 	vip.syntax = NULL;
    158 
    159 	if (get_window_size(&vip.screenrows, &vip.screencols) == -1) {
    160 		die("get_window_size");
    161 	}
    162 	vip.screenrows -= 2;
    163 }
    164 
    165 void open_editor(char *filename)
    166 {
    167 	free(vip.filename);
    168 	vip.filename = strdup(filename);
    169 
    170 	select_syntax_highlight();
    171 
    172 	FILE *fp = fopen(filename, "r");
    173 	if (!fp) {
    174 		die("fopen");
    175 	}
    176 	char *line = NULL;
    177 	size_t linecap = 0;
    178 	ssize_t len;
    179 	while ((len = getline(&line, &linecap, fp)) != -1) {
    180 		/* remove new line and carriage return at end of line */
    181 		while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r')) {
    182 			len--;
    183 		}
    184 		insert_row(vip.rows, line, len);
    185 	}
    186 	free(line);
    187 	fclose(fp);
    188 	/* reset dirtiness as nothing is modified yet */
    189 	vip.dirty = 0;
    190 }
    191 
    192 char *prompt_editor(char *prompt, void (*callback)(char *, int))
    193 {
    194 	size_t bufsize = 128;
    195 	char *buf = malloc(bufsize);
    196 	size_t buflen = 0;
    197 	buf[0] = '\0';
    198 	while (1) {
    199 		set_status_bar_message(prompt, buf);
    200 		refresh_screen();
    201 		int c = read_key();
    202 		if (c == DEL_KEY || c == CTRL_KEY('h') || c == BACKSPACE) {
    203 			if (buflen != 0) {
    204 				buf[--buflen] = '\0';
    205 			}
    206 		} else if (c == '\x1b') {
    207 			set_status_bar_message("");
    208 			if (callback) callback(buf, c);
    209 			free(buf);
    210 			return NULL;
    211 		} else if (c == '\r') {
    212 			if (buflen != 0) {
    213 				set_status_bar_message("");
    214 				if (callback) callback(buf, c);
    215 				return buf;
    216 			}
    217 		} else if (!iscntrl(c) && c < 128) {
    218 			if (buflen == bufsize - 1) {
    219 				bufsize *= 2;
    220 				buf = realloc(buf, bufsize);
    221 			}
    222 			buf[buflen++] = c;
    223 			buf[buflen] = '\0';
    224 		}
    225 
    226 		if (callback) callback(buf, c);
    227 	}
    228 }
    229 
    230 void find_callback(char *query, int key)
    231 {
    232 	static int last_match = -1;
    233 	static int direction = 1;
    234 
    235 	static int saved_hl_line;
    236 	static char *saved_hl = NULL;
    237 	if (saved_hl) {
    238 		memcpy(vip.row[saved_hl_line].hl, saved_hl, vip.row[saved_hl_line].render_size);
    239 		free(saved_hl);
    240 		saved_hl = NULL;
    241 	}
    242 
    243 	if (key == '\r' || key == '\x1b') {
    244 		last_match = -1;
    245 		direction = 1;
    246 		return;
    247 	} else if (key == CTRL_KEY('n')) {
    248 		direction = 1;
    249 	} else if (key == CTRL_KEY('p')) {
    250 		direction = -1;
    251 	} else {
    252 		last_match = -1;
    253 		direction = 1;
    254 	}
    255 
    256 	if (last_match == -1) direction = 1;
    257 	int current = last_match;
    258 	for (int i = 0; i < vip.rows; i++) {
    259 		current += direction;
    260 
    261 		if (current == -1) current = vip.rows - 1;
    262 		else if (current == vip.rows) current = 0;
    263 
    264 		row *row = &vip.row[current];
    265 		char *match = strstr(row->render, query);
    266 		if (match) {
    267 			last_match = current;
    268 			vip.cy = current;
    269 			vip.cx = row_rx_to_cx(row, match - row->render);
    270 			vip.rowoff = vip.rows;
    271 
    272 			saved_hl_line = current;
    273 			saved_hl = malloc(row->render_size);
    274 			memcpy(saved_hl, row->hl, row->render_size);
    275 
    276 			memset(&row->hl[match - row->render], MATCH, strlen(query));
    277 			memset(&row->hl[match - row->render + strlen(query)], RESET, row->render_size - (match - row->render + strlen(query)));
    278 			break;
    279 		}
    280 	}
    281 }
    282 
    283 void find_editor()
    284 {
    285 	int tmp_cx = vip.cx;
    286 	int tmp_cy = vip.cy;
    287 	int tmp_coloff = vip.coloff;
    288 	int tmp_rowoff = vip.rowoff;
    289 	char *query = prompt_editor("/%s", find_callback);
    290 	if (query) {
    291 		free(query);
    292 	} else {
    293 		vip.cx = tmp_cx;
    294 		vip.cy = tmp_cy;
    295 		vip.coloff = tmp_coloff;
    296 		vip.rowoff = tmp_rowoff;
    297 	}
    298 }