10f66f451Sopenharmony_ci/* vi.c - You can't spell "evil" without "vi". 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2015 Rob Landley <rob@landley.net> 40f66f451Sopenharmony_ci * Copyright 2019 Jarno Mäkipää <jmakip87@gmail.com> 50f66f451Sopenharmony_ci * 60f66f451Sopenharmony_ci * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/vi.html 70f66f451Sopenharmony_ci 80f66f451Sopenharmony_ciUSE_VI(NEWTOY(vi, ">1s:", TOYFLAG_USR|TOYFLAG_BIN)) 90f66f451Sopenharmony_ci 100f66f451Sopenharmony_ciconfig VI 110f66f451Sopenharmony_ci bool "vi" 120f66f451Sopenharmony_ci default n 130f66f451Sopenharmony_ci help 140f66f451Sopenharmony_ci usage: vi [-s script] FILE 150f66f451Sopenharmony_ci -s script: run script file 160f66f451Sopenharmony_ci Visual text editor. Predates the existence of standardized cursor keys, 170f66f451Sopenharmony_ci so the controls are weird and historical. 180f66f451Sopenharmony_ci*/ 190f66f451Sopenharmony_ci 200f66f451Sopenharmony_ci#define FOR_vi 210f66f451Sopenharmony_ci#include "toys.h" 220f66f451Sopenharmony_ci 230f66f451Sopenharmony_ciGLOBALS( 240f66f451Sopenharmony_ci char *s; 250f66f451Sopenharmony_ci int vi_mode, tabstop, list; 260f66f451Sopenharmony_ci int cur_col, cur_row, scr_row; 270f66f451Sopenharmony_ci int drawn_row, drawn_col; 280f66f451Sopenharmony_ci int count0, count1, vi_mov_flag; 290f66f451Sopenharmony_ci unsigned screen_height, screen_width; 300f66f451Sopenharmony_ci char vi_reg, *last_search; 310f66f451Sopenharmony_ci struct str_line { 320f66f451Sopenharmony_ci int alloc; 330f66f451Sopenharmony_ci int len; 340f66f451Sopenharmony_ci char *data; 350f66f451Sopenharmony_ci } *il; 360f66f451Sopenharmony_ci size_t screen, cursor; //offsets 370f66f451Sopenharmony_ci //yank buffer 380f66f451Sopenharmony_ci struct yank_buf { 390f66f451Sopenharmony_ci char reg; 400f66f451Sopenharmony_ci int alloc; 410f66f451Sopenharmony_ci char* data; 420f66f451Sopenharmony_ci } yank; 430f66f451Sopenharmony_ci 440f66f451Sopenharmony_ci int modified; 450f66f451Sopenharmony_ci size_t filesize; 460f66f451Sopenharmony_ci// mem_block contains RO data that is either original file as mmap 470f66f451Sopenharmony_ci// or heap allocated inserted data 480f66f451Sopenharmony_ci// 490f66f451Sopenharmony_ci// 500f66f451Sopenharmony_ci// 510f66f451Sopenharmony_ci struct block_list { 520f66f451Sopenharmony_ci struct block_list *next, *prev; 530f66f451Sopenharmony_ci struct mem_block { 540f66f451Sopenharmony_ci size_t size; 550f66f451Sopenharmony_ci size_t len; 560f66f451Sopenharmony_ci enum alloc_flag { 570f66f451Sopenharmony_ci MMAP, //can be munmap() before exit() 580f66f451Sopenharmony_ci HEAP, //can be free() before exit() 590f66f451Sopenharmony_ci STACK, //global or stack perhaps toybuf 600f66f451Sopenharmony_ci } alloc; 610f66f451Sopenharmony_ci const char *data; 620f66f451Sopenharmony_ci } *node; 630f66f451Sopenharmony_ci } *text; 640f66f451Sopenharmony_ci 650f66f451Sopenharmony_ci// slices do not contain actual allocated data but slices of data in mem_block 660f66f451Sopenharmony_ci// when file is first opened it has only one slice. 670f66f451Sopenharmony_ci// after inserting data into middle new mem_block is allocated for insert data 680f66f451Sopenharmony_ci// and 3 slices are created, where first and last slice are pointing to original 690f66f451Sopenharmony_ci// mem_block with offsets, and middle slice is pointing to newly allocated block 700f66f451Sopenharmony_ci// When deleting, data is not freed but mem_blocks are sliced more such way that 710f66f451Sopenharmony_ci// deleted data left between 2 slices 720f66f451Sopenharmony_ci struct slice_list { 730f66f451Sopenharmony_ci struct slice_list *next, *prev; 740f66f451Sopenharmony_ci struct slice { 750f66f451Sopenharmony_ci size_t len; 760f66f451Sopenharmony_ci const char *data; 770f66f451Sopenharmony_ci } *node; 780f66f451Sopenharmony_ci } *slices; 790f66f451Sopenharmony_ci) 800f66f451Sopenharmony_ci 810f66f451Sopenharmony_cistatic const char *blank = " \n\r\t"; 820f66f451Sopenharmony_cistatic const char *specials = ",.:;=-+*/(){}<>[]!@#$%^&|\\?\"\'"; 830f66f451Sopenharmony_ci 840f66f451Sopenharmony_ci//get utf8 length and width at same time 850f66f451Sopenharmony_cistatic int utf8_lnw(int *width, char *s, int bytes) 860f66f451Sopenharmony_ci{ 870f66f451Sopenharmony_ci unsigned wc; 880f66f451Sopenharmony_ci int length = 1; 890f66f451Sopenharmony_ci 900f66f451Sopenharmony_ci if (*s == '\t') *width = TT.tabstop; 910f66f451Sopenharmony_ci else { 920f66f451Sopenharmony_ci length = utf8towc(&wc, s, bytes); 930f66f451Sopenharmony_ci if (length < 1) length = 0, *width = 0; 940f66f451Sopenharmony_ci else *width = wcwidth(wc); 950f66f451Sopenharmony_ci } 960f66f451Sopenharmony_ci return length; 970f66f451Sopenharmony_ci} 980f66f451Sopenharmony_ci 990f66f451Sopenharmony_cistatic int utf8_dec(char key, char *utf8_scratch, int *sta_p) 1000f66f451Sopenharmony_ci{ 1010f66f451Sopenharmony_ci int len = 0; 1020f66f451Sopenharmony_ci char *c = utf8_scratch; 1030f66f451Sopenharmony_ci c[*sta_p] = key; 1040f66f451Sopenharmony_ci if (!(*sta_p)) *c = key; 1050f66f451Sopenharmony_ci if (*c < 0x7F) { *sta_p = 1; return 1; } 1060f66f451Sopenharmony_ci if ((*c & 0xE0) == 0xc0) len = 2; 1070f66f451Sopenharmony_ci else if ((*c & 0xF0) == 0xE0 ) len = 3; 1080f66f451Sopenharmony_ci else if ((*c & 0xF8) == 0xF0 ) len = 4; 1090f66f451Sopenharmony_ci else {*sta_p = 0; return 0; } 1100f66f451Sopenharmony_ci 1110f66f451Sopenharmony_ci (*sta_p)++; 1120f66f451Sopenharmony_ci 1130f66f451Sopenharmony_ci if (*sta_p == 1) return 0; 1140f66f451Sopenharmony_ci if ((c[*sta_p-1] & 0xc0) != 0x80) {*sta_p = 0; return 0; } 1150f66f451Sopenharmony_ci 1160f66f451Sopenharmony_ci if (*sta_p == len) { c[(*sta_p)] = 0; return 1; } 1170f66f451Sopenharmony_ci 1180f66f451Sopenharmony_ci return 0; 1190f66f451Sopenharmony_ci} 1200f66f451Sopenharmony_ci 1210f66f451Sopenharmony_cistatic char* utf8_last(char* str, int size) 1220f66f451Sopenharmony_ci{ 1230f66f451Sopenharmony_ci char* end = str+size; 1240f66f451Sopenharmony_ci int pos = size, len, width = 0; 1250f66f451Sopenharmony_ci for (;pos >= 0; end--, pos--) { 1260f66f451Sopenharmony_ci len = utf8_lnw(&width, end, size-pos); 1270f66f451Sopenharmony_ci if (len && width) return end; 1280f66f451Sopenharmony_ci } 1290f66f451Sopenharmony_ci return 0; 1300f66f451Sopenharmony_ci} 1310f66f451Sopenharmony_ci 1320f66f451Sopenharmony_cistruct double_list *dlist_add_before(struct double_list **head, 1330f66f451Sopenharmony_ci struct double_list **list, char *data) 1340f66f451Sopenharmony_ci{ 1350f66f451Sopenharmony_ci struct double_list *new = xmalloc(sizeof(struct double_list)); 1360f66f451Sopenharmony_ci new->data = data; 1370f66f451Sopenharmony_ci if (*list == *head) *head = new; 1380f66f451Sopenharmony_ci 1390f66f451Sopenharmony_ci dlist_add_nomalloc(list, new); 1400f66f451Sopenharmony_ci return new; 1410f66f451Sopenharmony_ci} 1420f66f451Sopenharmony_ci 1430f66f451Sopenharmony_cistruct double_list *dlist_add_after(struct double_list **head, 1440f66f451Sopenharmony_ci struct double_list **list, char *data) 1450f66f451Sopenharmony_ci{ 1460f66f451Sopenharmony_ci struct double_list *new = xmalloc(sizeof(struct double_list)); 1470f66f451Sopenharmony_ci new->data = data; 1480f66f451Sopenharmony_ci 1490f66f451Sopenharmony_ci if (*list) { 1500f66f451Sopenharmony_ci new->prev = *list; 1510f66f451Sopenharmony_ci new->next = (*list)->next; 1520f66f451Sopenharmony_ci (*list)->next->prev = new; 1530f66f451Sopenharmony_ci (*list)->next = new; 1540f66f451Sopenharmony_ci } else *head = *list = new->next = new->prev = new; 1550f66f451Sopenharmony_ci return new; 1560f66f451Sopenharmony_ci} 1570f66f451Sopenharmony_ci 1580f66f451Sopenharmony_ci// str must be already allocated 1590f66f451Sopenharmony_ci// ownership of allocated data is moved 1600f66f451Sopenharmony_ci// data, pre allocated data 1610f66f451Sopenharmony_ci// offset, offset in whole text 1620f66f451Sopenharmony_ci// size, data allocation size of given data 1630f66f451Sopenharmony_ci// len, length of the string 1640f66f451Sopenharmony_ci// type, define allocation type for cleanup purposes at app exit 1650f66f451Sopenharmony_cistatic int insert_str(const char *data, size_t offset, size_t size, size_t len, 1660f66f451Sopenharmony_ci enum alloc_flag type) 1670f66f451Sopenharmony_ci{ 1680f66f451Sopenharmony_ci struct mem_block *b = xmalloc(sizeof(struct mem_block)); 1690f66f451Sopenharmony_ci struct slice *next = xmalloc(sizeof(struct slice)); 1700f66f451Sopenharmony_ci struct slice_list *s = TT.slices; 1710f66f451Sopenharmony_ci b->size = size; 1720f66f451Sopenharmony_ci b->len = len; 1730f66f451Sopenharmony_ci b->alloc = type; 1740f66f451Sopenharmony_ci b->data = data; 1750f66f451Sopenharmony_ci next->len = len; 1760f66f451Sopenharmony_ci next->data = data; 1770f66f451Sopenharmony_ci 1780f66f451Sopenharmony_ci //mem blocks can be just added unordered 1790f66f451Sopenharmony_ci TT.text = (struct block_list *)dlist_add((struct double_list **)&TT.text, 1800f66f451Sopenharmony_ci (char *)b); 1810f66f451Sopenharmony_ci 1820f66f451Sopenharmony_ci if (!s) { 1830f66f451Sopenharmony_ci TT.slices = (struct slice_list *)dlist_add( 1840f66f451Sopenharmony_ci (struct double_list **)&TT.slices, 1850f66f451Sopenharmony_ci (char *)next); 1860f66f451Sopenharmony_ci } else { 1870f66f451Sopenharmony_ci size_t pos = 0; 1880f66f451Sopenharmony_ci //search insertation point for slice 1890f66f451Sopenharmony_ci do { 1900f66f451Sopenharmony_ci if (pos<=offset && pos+s->node->len>offset) break; 1910f66f451Sopenharmony_ci pos += s->node->len; 1920f66f451Sopenharmony_ci s = s->next; 1930f66f451Sopenharmony_ci if (s == TT.slices) return -1; //error out of bounds 1940f66f451Sopenharmony_ci } while (1); 1950f66f451Sopenharmony_ci //need to cut previous slice into 2 since insert is in middle 1960f66f451Sopenharmony_ci if (pos+s->node->len>offset && pos!=offset) { 1970f66f451Sopenharmony_ci struct slice *tail = xmalloc(sizeof(struct slice)); 1980f66f451Sopenharmony_ci tail->len = s->node->len-(offset-pos); 1990f66f451Sopenharmony_ci tail->data = s->node->data+(offset-pos); 2000f66f451Sopenharmony_ci s->node->len = offset-pos; 2010f66f451Sopenharmony_ci //pos = offset; 2020f66f451Sopenharmony_ci s = (struct slice_list *)dlist_add_after( 2030f66f451Sopenharmony_ci (struct double_list **)&TT.slices, 2040f66f451Sopenharmony_ci (struct double_list **)&s, 2050f66f451Sopenharmony_ci (char *)tail); 2060f66f451Sopenharmony_ci 2070f66f451Sopenharmony_ci s = (struct slice_list *)dlist_add_before( 2080f66f451Sopenharmony_ci (struct double_list **)&TT.slices, 2090f66f451Sopenharmony_ci (struct double_list **)&s, 2100f66f451Sopenharmony_ci (char *)next); 2110f66f451Sopenharmony_ci } else if (pos==offset) { 2120f66f451Sopenharmony_ci // insert before 2130f66f451Sopenharmony_ci s = (struct slice_list *)dlist_add_before( 2140f66f451Sopenharmony_ci (struct double_list **)&TT.slices, 2150f66f451Sopenharmony_ci (struct double_list **)&s, 2160f66f451Sopenharmony_ci (char *)next); 2170f66f451Sopenharmony_ci } else { 2180f66f451Sopenharmony_ci // insert after 2190f66f451Sopenharmony_ci s = (struct slice_list *)dlist_add_after((struct double_list **)&TT.slices, 2200f66f451Sopenharmony_ci (struct double_list **)&s, 2210f66f451Sopenharmony_ci (char *)next); 2220f66f451Sopenharmony_ci } 2230f66f451Sopenharmony_ci } 2240f66f451Sopenharmony_ci return 0; 2250f66f451Sopenharmony_ci} 2260f66f451Sopenharmony_ci 2270f66f451Sopenharmony_ci// this will not free any memory 2280f66f451Sopenharmony_ci// will only create more slices depending on position 2290f66f451Sopenharmony_cistatic int cut_str(size_t offset, size_t len) 2300f66f451Sopenharmony_ci{ 2310f66f451Sopenharmony_ci struct slice_list *e, *s = TT.slices; 2320f66f451Sopenharmony_ci size_t end = offset+len; 2330f66f451Sopenharmony_ci size_t epos, spos = 0; 2340f66f451Sopenharmony_ci if (!s) return -1; 2350f66f451Sopenharmony_ci 2360f66f451Sopenharmony_ci //find start and end slices 2370f66f451Sopenharmony_ci for (;;) { 2380f66f451Sopenharmony_ci if (spos<=offset && spos+s->node->len>offset) break; 2390f66f451Sopenharmony_ci spos += s->node->len; 2400f66f451Sopenharmony_ci s = s->next; 2410f66f451Sopenharmony_ci 2420f66f451Sopenharmony_ci if (s == TT.slices) return -1; //error out of bounds 2430f66f451Sopenharmony_ci } 2440f66f451Sopenharmony_ci 2450f66f451Sopenharmony_ci for (e = s, epos = spos; ; ) { 2460f66f451Sopenharmony_ci if (epos<=end && epos+e->node->len>end) break; 2470f66f451Sopenharmony_ci epos += e->node->len; 2480f66f451Sopenharmony_ci e = e->next; 2490f66f451Sopenharmony_ci 2500f66f451Sopenharmony_ci if (e == TT.slices) return -1; //error out of bounds 2510f66f451Sopenharmony_ci } 2520f66f451Sopenharmony_ci 2530f66f451Sopenharmony_ci for (;;) { 2540f66f451Sopenharmony_ci if (spos == offset && ( end >= spos+s->node->len)) { 2550f66f451Sopenharmony_ci //cut full 2560f66f451Sopenharmony_ci spos += s->node->len; 2570f66f451Sopenharmony_ci offset += s->node->len; 2580f66f451Sopenharmony_ci s = dlist_pop(&s); 2590f66f451Sopenharmony_ci if (s == TT.slices) TT.slices = s->next; 2600f66f451Sopenharmony_ci 2610f66f451Sopenharmony_ci } else if (spos < offset && ( end >= spos+s->node->len)) { 2620f66f451Sopenharmony_ci //cut end 2630f66f451Sopenharmony_ci size_t clip = s->node->len - (offset - spos); 2640f66f451Sopenharmony_ci offset = spos+s->node->len; 2650f66f451Sopenharmony_ci spos += s->node->len; 2660f66f451Sopenharmony_ci s->node->len -= clip; 2670f66f451Sopenharmony_ci } else if (spos == offset && s == e) { 2680f66f451Sopenharmony_ci //cut begin 2690f66f451Sopenharmony_ci size_t clip = end - offset; 2700f66f451Sopenharmony_ci s->node->len -= clip; 2710f66f451Sopenharmony_ci s->node->data += clip; 2720f66f451Sopenharmony_ci break; 2730f66f451Sopenharmony_ci } else { 2740f66f451Sopenharmony_ci //cut middle 2750f66f451Sopenharmony_ci struct slice *tail = xmalloc(sizeof(struct slice)); 2760f66f451Sopenharmony_ci size_t clip = end-offset; 2770f66f451Sopenharmony_ci tail->len = s->node->len-(offset-spos)-clip; 2780f66f451Sopenharmony_ci tail->data = s->node->data+(offset-spos)+clip; 2790f66f451Sopenharmony_ci s->node->len = offset-spos; //wrong? 2800f66f451Sopenharmony_ci s = (struct slice_list *)dlist_add_after( 2810f66f451Sopenharmony_ci (struct double_list **)&TT.slices, 2820f66f451Sopenharmony_ci (struct double_list **)&s, 2830f66f451Sopenharmony_ci (char *)tail); 2840f66f451Sopenharmony_ci break; 2850f66f451Sopenharmony_ci } 2860f66f451Sopenharmony_ci if (s == e) break; 2870f66f451Sopenharmony_ci 2880f66f451Sopenharmony_ci s = s->next; 2890f66f451Sopenharmony_ci } 2900f66f451Sopenharmony_ci 2910f66f451Sopenharmony_ci return 0; 2920f66f451Sopenharmony_ci} 2930f66f451Sopenharmony_ci 2940f66f451Sopenharmony_ci//find offset position in slices 2950f66f451Sopenharmony_cistatic struct slice_list *slice_offset(size_t *start, size_t offset) 2960f66f451Sopenharmony_ci{ 2970f66f451Sopenharmony_ci struct slice_list *s = TT.slices; 2980f66f451Sopenharmony_ci size_t spos = 0; 2990f66f451Sopenharmony_ci 3000f66f451Sopenharmony_ci //find start 3010f66f451Sopenharmony_ci for ( ;s ; ) { 3020f66f451Sopenharmony_ci if (spos<=offset && spos+s->node->len>offset) break; 3030f66f451Sopenharmony_ci 3040f66f451Sopenharmony_ci spos += s->node->len; 3050f66f451Sopenharmony_ci s = s->next; 3060f66f451Sopenharmony_ci 3070f66f451Sopenharmony_ci if (s == TT.slices) s = 0; //error out of bounds 3080f66f451Sopenharmony_ci } 3090f66f451Sopenharmony_ci if (s) *start = spos; 3100f66f451Sopenharmony_ci return s; 3110f66f451Sopenharmony_ci} 3120f66f451Sopenharmony_ci 3130f66f451Sopenharmony_cistatic size_t text_strchr(size_t offset, char c) 3140f66f451Sopenharmony_ci{ 3150f66f451Sopenharmony_ci struct slice_list *s = TT.slices; 3160f66f451Sopenharmony_ci size_t epos, spos = 0; 3170f66f451Sopenharmony_ci int i = 0; 3180f66f451Sopenharmony_ci 3190f66f451Sopenharmony_ci //find start 3200f66f451Sopenharmony_ci if (!(s = slice_offset(&spos, offset))) return SIZE_MAX; 3210f66f451Sopenharmony_ci 3220f66f451Sopenharmony_ci i = offset-spos; 3230f66f451Sopenharmony_ci epos = spos+i; 3240f66f451Sopenharmony_ci do { 3250f66f451Sopenharmony_ci for (; i < s->node->len; i++, epos++) 3260f66f451Sopenharmony_ci if (s->node->data[i] == c) return epos; 3270f66f451Sopenharmony_ci s = s->next; 3280f66f451Sopenharmony_ci i = 0; 3290f66f451Sopenharmony_ci } while (s != TT.slices); 3300f66f451Sopenharmony_ci 3310f66f451Sopenharmony_ci return SIZE_MAX; 3320f66f451Sopenharmony_ci} 3330f66f451Sopenharmony_ci 3340f66f451Sopenharmony_cistatic size_t text_strrchr(size_t offset, char c) 3350f66f451Sopenharmony_ci{ 3360f66f451Sopenharmony_ci struct slice_list *s = TT.slices; 3370f66f451Sopenharmony_ci size_t epos, spos = 0; 3380f66f451Sopenharmony_ci int i = 0; 3390f66f451Sopenharmony_ci 3400f66f451Sopenharmony_ci //find start 3410f66f451Sopenharmony_ci if (!(s = slice_offset(&spos, offset))) return SIZE_MAX; 3420f66f451Sopenharmony_ci 3430f66f451Sopenharmony_ci i = offset-spos; 3440f66f451Sopenharmony_ci epos = spos+i; 3450f66f451Sopenharmony_ci do { 3460f66f451Sopenharmony_ci for (; i >= 0; i--, epos--) 3470f66f451Sopenharmony_ci if (s->node->data[i] == c) return epos; 3480f66f451Sopenharmony_ci s = s->prev; 3490f66f451Sopenharmony_ci i = s->node->len-1; 3500f66f451Sopenharmony_ci } while (s != TT.slices->prev); //tail 3510f66f451Sopenharmony_ci 3520f66f451Sopenharmony_ci return SIZE_MAX; 3530f66f451Sopenharmony_ci} 3540f66f451Sopenharmony_ci 3550f66f451Sopenharmony_cistatic size_t text_filesize() 3560f66f451Sopenharmony_ci{ 3570f66f451Sopenharmony_ci struct slice_list *s = TT.slices; 3580f66f451Sopenharmony_ci size_t pos = 0; 3590f66f451Sopenharmony_ci if (s) do { 3600f66f451Sopenharmony_ci 3610f66f451Sopenharmony_ci pos += s->node->len; 3620f66f451Sopenharmony_ci s = s->next; 3630f66f451Sopenharmony_ci 3640f66f451Sopenharmony_ci } while (s != TT.slices); 3650f66f451Sopenharmony_ci 3660f66f451Sopenharmony_ci return pos; 3670f66f451Sopenharmony_ci} 3680f66f451Sopenharmony_ci 3690f66f451Sopenharmony_cistatic int text_count(size_t start, size_t end, char c) 3700f66f451Sopenharmony_ci{ 3710f66f451Sopenharmony_ci struct slice_list *s = TT.slices; 3720f66f451Sopenharmony_ci size_t i, count = 0, spos = 0; 3730f66f451Sopenharmony_ci if (!(s = slice_offset(&spos, start))) return 0; 3740f66f451Sopenharmony_ci i = start-spos; 3750f66f451Sopenharmony_ci if (s) do { 3760f66f451Sopenharmony_ci for (; i < s->node->len && spos+i<end; i++) 3770f66f451Sopenharmony_ci if (s->node->data[i] == c) count++; 3780f66f451Sopenharmony_ci if (spos+i>=end) return count; 3790f66f451Sopenharmony_ci 3800f66f451Sopenharmony_ci spos += s->node->len; 3810f66f451Sopenharmony_ci i = 0; 3820f66f451Sopenharmony_ci s = s->next; 3830f66f451Sopenharmony_ci 3840f66f451Sopenharmony_ci } while (s != TT.slices); 3850f66f451Sopenharmony_ci 3860f66f451Sopenharmony_ci return count; 3870f66f451Sopenharmony_ci} 3880f66f451Sopenharmony_ci 3890f66f451Sopenharmony_cistatic char text_byte(size_t offset) 3900f66f451Sopenharmony_ci{ 3910f66f451Sopenharmony_ci struct slice_list *s = TT.slices; 3920f66f451Sopenharmony_ci size_t spos = 0; 3930f66f451Sopenharmony_ci //find start 3940f66f451Sopenharmony_ci if (!(s = slice_offset(&spos, offset))) return 0; 3950f66f451Sopenharmony_ci return s->node->data[offset-spos]; 3960f66f451Sopenharmony_ci} 3970f66f451Sopenharmony_ci 3980f66f451Sopenharmony_ci//utf-8 codepoint -1 if not valid, 0 if out_of_bounds, len if valid 3990f66f451Sopenharmony_ci//copies data to dest if dest is not 0 4000f66f451Sopenharmony_cistatic int text_codepoint(char *dest, size_t offset) 4010f66f451Sopenharmony_ci{ 4020f66f451Sopenharmony_ci char scratch[8] = {0}; 4030f66f451Sopenharmony_ci int state = 0, finished = 0; 4040f66f451Sopenharmony_ci 4050f66f451Sopenharmony_ci for (;!(finished = utf8_dec(text_byte(offset), scratch, &state)); offset++) 4060f66f451Sopenharmony_ci if (!state) return -1; 4070f66f451Sopenharmony_ci 4080f66f451Sopenharmony_ci if (!finished && !state) return -1; 4090f66f451Sopenharmony_ci if (dest) memcpy(dest, scratch, 8); 4100f66f451Sopenharmony_ci 4110f66f451Sopenharmony_ci return strlen(scratch); 4120f66f451Sopenharmony_ci} 4130f66f451Sopenharmony_ci 4140f66f451Sopenharmony_cistatic size_t text_sol(size_t offset) 4150f66f451Sopenharmony_ci{ 4160f66f451Sopenharmony_ci size_t pos; 4170f66f451Sopenharmony_ci if (!TT.filesize || !offset) return 0; 4180f66f451Sopenharmony_ci else if (TT.filesize <= offset) return TT.filesize-1; 4190f66f451Sopenharmony_ci else if ((pos = text_strrchr(offset-1, '\n')) == SIZE_MAX) return 0; 4200f66f451Sopenharmony_ci else if (pos < offset) return pos+1; 4210f66f451Sopenharmony_ci return offset; 4220f66f451Sopenharmony_ci} 4230f66f451Sopenharmony_ci 4240f66f451Sopenharmony_cistatic size_t text_eol(size_t offset) 4250f66f451Sopenharmony_ci{ 4260f66f451Sopenharmony_ci if (!TT.filesize) offset = 1; 4270f66f451Sopenharmony_ci else if (TT.filesize <= offset) return TT.filesize-1; 4280f66f451Sopenharmony_ci else if ((offset = text_strchr(offset, '\n')) == SIZE_MAX) 4290f66f451Sopenharmony_ci return TT.filesize-1; 4300f66f451Sopenharmony_ci return offset; 4310f66f451Sopenharmony_ci} 4320f66f451Sopenharmony_ci 4330f66f451Sopenharmony_cistatic size_t text_nsol(size_t offset) 4340f66f451Sopenharmony_ci{ 4350f66f451Sopenharmony_ci offset = text_eol(offset); 4360f66f451Sopenharmony_ci if (text_byte(offset) == '\n') offset++; 4370f66f451Sopenharmony_ci if (offset >= TT.filesize) offset--; 4380f66f451Sopenharmony_ci return offset; 4390f66f451Sopenharmony_ci} 4400f66f451Sopenharmony_ci 4410f66f451Sopenharmony_cistatic size_t text_psol(size_t offset) 4420f66f451Sopenharmony_ci{ 4430f66f451Sopenharmony_ci offset = text_sol(offset); 4440f66f451Sopenharmony_ci if (offset) offset--; 4450f66f451Sopenharmony_ci if (offset && text_byte(offset-1) != '\n') offset = text_sol(offset-1); 4460f66f451Sopenharmony_ci return offset; 4470f66f451Sopenharmony_ci} 4480f66f451Sopenharmony_ci 4490f66f451Sopenharmony_cistatic size_t text_getline(char *dest, size_t offset, size_t max_len) 4500f66f451Sopenharmony_ci{ 4510f66f451Sopenharmony_ci struct slice_list *s = TT.slices; 4520f66f451Sopenharmony_ci size_t end, spos = 0; 4530f66f451Sopenharmony_ci int i, j = 0; 4540f66f451Sopenharmony_ci 4550f66f451Sopenharmony_ci if (dest) *dest = 0; 4560f66f451Sopenharmony_ci 4570f66f451Sopenharmony_ci if (!s) return 0; 4580f66f451Sopenharmony_ci if ((end = text_strchr(offset, '\n')) == SIZE_MAX) 4590f66f451Sopenharmony_ci if ((end = TT.filesize) > offset+max_len) return 0; 4600f66f451Sopenharmony_ci 4610f66f451Sopenharmony_ci //find start 4620f66f451Sopenharmony_ci if (!(s = slice_offset(&spos, offset))) return 0; 4630f66f451Sopenharmony_ci 4640f66f451Sopenharmony_ci i = offset-spos; 4650f66f451Sopenharmony_ci j = end-offset+1; 4660f66f451Sopenharmony_ci if (dest) do { 4670f66f451Sopenharmony_ci for (; i < s->node->len && j; i++, j--, dest++) 4680f66f451Sopenharmony_ci *dest = s->node->data[i]; 4690f66f451Sopenharmony_ci s = s->next; 4700f66f451Sopenharmony_ci i = 0; 4710f66f451Sopenharmony_ci } while (s != TT.slices && j); 4720f66f451Sopenharmony_ci 4730f66f451Sopenharmony_ci if (dest) *dest = 0; 4740f66f451Sopenharmony_ci 4750f66f451Sopenharmony_ci return end-offset; 4760f66f451Sopenharmony_ci} 4770f66f451Sopenharmony_ci 4780f66f451Sopenharmony_ci//copying is needed when file has lot of inserts that are 4790f66f451Sopenharmony_ci//just few char long, but not always. Advanced search should 4800f66f451Sopenharmony_ci//check big slices directly and just copy edge cases. 4810f66f451Sopenharmony_ci//Also this is only line based search multiline 4820f66f451Sopenharmony_ci//and regexec should be done instead. 4830f66f451Sopenharmony_cistatic size_t text_strstr(size_t offset, char *str) 4840f66f451Sopenharmony_ci{ 4850f66f451Sopenharmony_ci size_t bytes, pos = offset; 4860f66f451Sopenharmony_ci char *s = 0; 4870f66f451Sopenharmony_ci do { 4880f66f451Sopenharmony_ci bytes = text_getline(toybuf, pos, ARRAY_LEN(toybuf)); 4890f66f451Sopenharmony_ci if (!bytes) pos++; //empty line 4900f66f451Sopenharmony_ci else if ((s = strstr(toybuf, str))) return pos+(s-toybuf); 4910f66f451Sopenharmony_ci else pos += bytes; 4920f66f451Sopenharmony_ci } while (pos < TT.filesize); 4930f66f451Sopenharmony_ci 4940f66f451Sopenharmony_ci return SIZE_MAX; 4950f66f451Sopenharmony_ci} 4960f66f451Sopenharmony_ci 4970f66f451Sopenharmony_cistatic void block_list_free(void *node) 4980f66f451Sopenharmony_ci{ 4990f66f451Sopenharmony_ci struct block_list *d = node; 5000f66f451Sopenharmony_ci 5010f66f451Sopenharmony_ci if (d->node->alloc == HEAP) free((void *)d->node->data); 5020f66f451Sopenharmony_ci else if (d->node->alloc == MMAP) munmap((void *)d->node->data, d->node->size); 5030f66f451Sopenharmony_ci 5040f66f451Sopenharmony_ci free(d->node); 5050f66f451Sopenharmony_ci free(d); 5060f66f451Sopenharmony_ci} 5070f66f451Sopenharmony_ci 5080f66f451Sopenharmony_cistatic void linelist_unload() 5090f66f451Sopenharmony_ci{ 5100f66f451Sopenharmony_ci llist_traverse((void *)TT.slices, llist_free_double); 5110f66f451Sopenharmony_ci llist_traverse((void *)TT.text, block_list_free); 5120f66f451Sopenharmony_ci TT.slices = 0, TT.text = 0; 5130f66f451Sopenharmony_ci} 5140f66f451Sopenharmony_ci 5150f66f451Sopenharmony_cistatic int linelist_load(char *filename) 5160f66f451Sopenharmony_ci{ 5170f66f451Sopenharmony_ci if (!filename) filename = (char*)*toys.optargs; 5180f66f451Sopenharmony_ci 5190f66f451Sopenharmony_ci if (filename) { 5200f66f451Sopenharmony_ci int fd = open(filename, O_RDONLY); 5210f66f451Sopenharmony_ci long long size; 5220f66f451Sopenharmony_ci 5230f66f451Sopenharmony_ci if (fd == -1 || !(size = fdlength(fd))) { 5240f66f451Sopenharmony_ci insert_str("", 0, 0, 0, STACK); 5250f66f451Sopenharmony_ci TT.filesize = 0; 5260f66f451Sopenharmony_ci 5270f66f451Sopenharmony_ci return 0; 5280f66f451Sopenharmony_ci } 5290f66f451Sopenharmony_ci insert_str(xmmap(0, size, PROT_READ, MAP_SHARED, fd, 0), 0, size,size,MMAP); 5300f66f451Sopenharmony_ci xclose(fd); 5310f66f451Sopenharmony_ci TT.filesize = text_filesize(); 5320f66f451Sopenharmony_ci } 5330f66f451Sopenharmony_ci 5340f66f451Sopenharmony_ci return 1; 5350f66f451Sopenharmony_ci} 5360f66f451Sopenharmony_ci 5370f66f451Sopenharmony_cistatic void write_file(char *filename) 5380f66f451Sopenharmony_ci{ 5390f66f451Sopenharmony_ci struct slice_list *s = TT.slices; 5400f66f451Sopenharmony_ci struct stat st; 5410f66f451Sopenharmony_ci int fd = 0; 5420f66f451Sopenharmony_ci if (!s) return; 5430f66f451Sopenharmony_ci 5440f66f451Sopenharmony_ci if (!filename) filename = (char*)*toys.optargs; 5450f66f451Sopenharmony_ci 5460f66f451Sopenharmony_ci sprintf(toybuf, "%s.swp", filename); 5470f66f451Sopenharmony_ci 5480f66f451Sopenharmony_ci if ( (fd = xopen(toybuf, O_WRONLY | O_CREAT | O_TRUNC)) <0) return; 5490f66f451Sopenharmony_ci 5500f66f451Sopenharmony_ci do { 5510f66f451Sopenharmony_ci xwrite(fd, (void *)s->node->data, s->node->len ); 5520f66f451Sopenharmony_ci s = s->next; 5530f66f451Sopenharmony_ci } while (s != TT.slices); 5540f66f451Sopenharmony_ci 5550f66f451Sopenharmony_ci linelist_unload(); 5560f66f451Sopenharmony_ci 5570f66f451Sopenharmony_ci xclose(fd); 5580f66f451Sopenharmony_ci if (!stat(filename, &st)) chmod(toybuf, st.st_mode); 5590f66f451Sopenharmony_ci else chmod(toybuf, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); 5600f66f451Sopenharmony_ci xrename(toybuf, filename); 5610f66f451Sopenharmony_ci linelist_load(filename); 5620f66f451Sopenharmony_ci} 5630f66f451Sopenharmony_ci 5640f66f451Sopenharmony_ci//jump into valid offset index 5650f66f451Sopenharmony_ci//and valid utf8 codepoint 5660f66f451Sopenharmony_cistatic void check_cursor_bounds() 5670f66f451Sopenharmony_ci{ 5680f66f451Sopenharmony_ci char buf[8] = {0}; 5690f66f451Sopenharmony_ci int len, width = 0; 5700f66f451Sopenharmony_ci if (!TT.filesize) TT.cursor = 0; 5710f66f451Sopenharmony_ci 5720f66f451Sopenharmony_ci for (;;) { 5730f66f451Sopenharmony_ci if (TT.cursor < 1) { 5740f66f451Sopenharmony_ci TT.cursor = 0; 5750f66f451Sopenharmony_ci return; 5760f66f451Sopenharmony_ci } else if (TT.cursor >= TT.filesize-1) { 5770f66f451Sopenharmony_ci TT.cursor = TT.filesize-1; 5780f66f451Sopenharmony_ci return; 5790f66f451Sopenharmony_ci } 5800f66f451Sopenharmony_ci if ((len = text_codepoint(buf, TT.cursor)) < 1) { 5810f66f451Sopenharmony_ci TT.cursor--; //we are not in valid data try jump over 5820f66f451Sopenharmony_ci continue; 5830f66f451Sopenharmony_ci } 5840f66f451Sopenharmony_ci if (utf8_lnw(&width, buf, len) && width) break; 5850f66f451Sopenharmony_ci else TT.cursor--; //combine char jump over 5860f66f451Sopenharmony_ci } 5870f66f451Sopenharmony_ci} 5880f66f451Sopenharmony_ci 5890f66f451Sopenharmony_ci// TT.vi_mov_flag is used for special cases when certain move 5900f66f451Sopenharmony_ci// acts differently depending is there DELETE/YANK or NOP 5910f66f451Sopenharmony_ci// Also commands such as G does not default to count0=1 5920f66f451Sopenharmony_ci// 0x1 = Command needs argument (f,F,r...) 5930f66f451Sopenharmony_ci// 0x2 = Move 1 right on yank/delete/insert (e, $...) 5940f66f451Sopenharmony_ci// 0x4 = yank/delete last line fully 5950f66f451Sopenharmony_ci// 0x10000000 = redraw after cursor needed 5960f66f451Sopenharmony_ci// 0x20000000 = full redraw needed 5970f66f451Sopenharmony_ci// 0x40000000 = count0 not given 5980f66f451Sopenharmony_ci// 0x80000000 = move was reverse 5990f66f451Sopenharmony_ci 6000f66f451Sopenharmony_ci//TODO rewrite the logic, difficulties counting lines 6010f66f451Sopenharmony_ci//and with big files scroll should not rely in knowing 6020f66f451Sopenharmony_ci//absoluteline numbers 6030f66f451Sopenharmony_cistatic void adjust_screen_buffer() 6040f66f451Sopenharmony_ci{ 6050f66f451Sopenharmony_ci size_t c, s; 6060f66f451Sopenharmony_ci TT.cur_row = 0, TT.scr_row = 0; 6070f66f451Sopenharmony_ci if (!TT.cursor) { 6080f66f451Sopenharmony_ci TT.screen = 0; 6090f66f451Sopenharmony_ci TT.vi_mov_flag = 0x20000000; 6100f66f451Sopenharmony_ci return; 6110f66f451Sopenharmony_ci } else if (TT.screen > (1<<18) || TT.cursor > (1<<18)) { 6120f66f451Sopenharmony_ci //give up, file is big, do full redraw 6130f66f451Sopenharmony_ci 6140f66f451Sopenharmony_ci TT.screen = text_strrchr(TT.cursor-1, '\n')+1; 6150f66f451Sopenharmony_ci TT.vi_mov_flag = 0x20000000; 6160f66f451Sopenharmony_ci return; 6170f66f451Sopenharmony_ci } 6180f66f451Sopenharmony_ci 6190f66f451Sopenharmony_ci s = text_count(0, TT.screen, '\n'); 6200f66f451Sopenharmony_ci c = text_count(0, TT.cursor, '\n'); 6210f66f451Sopenharmony_ci if (s >= c) { 6220f66f451Sopenharmony_ci TT.screen = text_strrchr(TT.cursor-1, '\n')+1; 6230f66f451Sopenharmony_ci s = c; 6240f66f451Sopenharmony_ci TT.vi_mov_flag = 0x20000000; //TODO I disabled scroll 6250f66f451Sopenharmony_ci } else { 6260f66f451Sopenharmony_ci int distance = c-s+1; 6270f66f451Sopenharmony_ci if (distance > (int)TT.screen_height) { 6280f66f451Sopenharmony_ci int n, adj = distance-TT.screen_height; 6290f66f451Sopenharmony_ci TT.vi_mov_flag = 0x20000000; //TODO I disabled scroll 6300f66f451Sopenharmony_ci for (;adj; adj--, s++) 6310f66f451Sopenharmony_ci if ((n = text_strchr(TT.screen, '\n'))+1 > TT.screen) 6320f66f451Sopenharmony_ci TT.screen = n+1; 6330f66f451Sopenharmony_ci } 6340f66f451Sopenharmony_ci } 6350f66f451Sopenharmony_ci 6360f66f451Sopenharmony_ci TT.scr_row = s; 6370f66f451Sopenharmony_ci TT.cur_row = c; 6380f66f451Sopenharmony_ci 6390f66f451Sopenharmony_ci} 6400f66f451Sopenharmony_ci 6410f66f451Sopenharmony_ci//TODO search yank buffer by register 6420f66f451Sopenharmony_ci//TODO yanks could be separate slices so no need to copy data 6430f66f451Sopenharmony_ci//now only supports default register 6440f66f451Sopenharmony_cistatic int vi_yank(char reg, size_t from, int flags) 6450f66f451Sopenharmony_ci{ 6460f66f451Sopenharmony_ci size_t start = from, end = TT.cursor; 6470f66f451Sopenharmony_ci char *str; 6480f66f451Sopenharmony_ci 6490f66f451Sopenharmony_ci memset(TT.yank.data, 0, TT.yank.alloc); 6500f66f451Sopenharmony_ci if (TT.vi_mov_flag&0x80000000) start = TT.cursor, end = from; 6510f66f451Sopenharmony_ci else TT.cursor = start; //yank moves cursor to left pos always? 6520f66f451Sopenharmony_ci 6530f66f451Sopenharmony_ci if (TT.yank.alloc < end-from) { 6540f66f451Sopenharmony_ci size_t new_bounds = (1+end-from)/1024; 6550f66f451Sopenharmony_ci new_bounds += ((1+end-from)%1024) ? 1 : 0; 6560f66f451Sopenharmony_ci new_bounds *= 1024; 6570f66f451Sopenharmony_ci TT.yank.data = xrealloc(TT.yank.data, new_bounds); 6580f66f451Sopenharmony_ci TT.yank.alloc = new_bounds; 6590f66f451Sopenharmony_ci } 6600f66f451Sopenharmony_ci 6610f66f451Sopenharmony_ci //this is naive copy 6620f66f451Sopenharmony_ci for (str = TT.yank.data ; start<end; start++, str++) *str = text_byte(start); 6630f66f451Sopenharmony_ci 6640f66f451Sopenharmony_ci *str = 0; 6650f66f451Sopenharmony_ci 6660f66f451Sopenharmony_ci return 1; 6670f66f451Sopenharmony_ci} 6680f66f451Sopenharmony_ci 6690f66f451Sopenharmony_cistatic int vi_delete(char reg, size_t from, int flags) 6700f66f451Sopenharmony_ci{ 6710f66f451Sopenharmony_ci size_t start = from, end = TT.cursor; 6720f66f451Sopenharmony_ci 6730f66f451Sopenharmony_ci vi_yank(reg, from, flags); 6740f66f451Sopenharmony_ci 6750f66f451Sopenharmony_ci if (TT.vi_mov_flag&0x80000000) 6760f66f451Sopenharmony_ci start = TT.cursor, end = from; 6770f66f451Sopenharmony_ci 6780f66f451Sopenharmony_ci //pre adjust cursor move one right until at next valid rune 6790f66f451Sopenharmony_ci if (TT.vi_mov_flag&2) { 6800f66f451Sopenharmony_ci //TODO 6810f66f451Sopenharmony_ci } 6820f66f451Sopenharmony_ci //do slice cut 6830f66f451Sopenharmony_ci cut_str(start, end-start); 6840f66f451Sopenharmony_ci 6850f66f451Sopenharmony_ci //cursor is at start at after delete 6860f66f451Sopenharmony_ci TT.cursor = start; 6870f66f451Sopenharmony_ci TT.filesize = text_filesize(); 6880f66f451Sopenharmony_ci //find line start by strrchr(/n) ++ 6890f66f451Sopenharmony_ci //set cur_col with crunch_n_str maybe? 6900f66f451Sopenharmony_ci TT.vi_mov_flag |= 0x30000000; 6910f66f451Sopenharmony_ci 6920f66f451Sopenharmony_ci return 1; 6930f66f451Sopenharmony_ci} 6940f66f451Sopenharmony_ci 6950f66f451Sopenharmony_cistatic int vi_change(char reg, size_t to, int flags) 6960f66f451Sopenharmony_ci{ 6970f66f451Sopenharmony_ci vi_delete(reg, to, flags); 6980f66f451Sopenharmony_ci TT.vi_mode = 2; 6990f66f451Sopenharmony_ci return 1; 7000f66f451Sopenharmony_ci} 7010f66f451Sopenharmony_ci 7020f66f451Sopenharmony_cistatic int cur_left(int count0, int count1, char *unused) 7030f66f451Sopenharmony_ci{ 7040f66f451Sopenharmony_ci int count = count0*count1; 7050f66f451Sopenharmony_ci TT.vi_mov_flag |= 0x80000000; 7060f66f451Sopenharmony_ci for (;count && TT.cursor; count--) { 7070f66f451Sopenharmony_ci TT.cursor--; 7080f66f451Sopenharmony_ci if (text_byte(TT.cursor) == '\n') TT.cursor++; 7090f66f451Sopenharmony_ci check_cursor_bounds(); 7100f66f451Sopenharmony_ci } 7110f66f451Sopenharmony_ci return 1; 7120f66f451Sopenharmony_ci} 7130f66f451Sopenharmony_ci 7140f66f451Sopenharmony_cistatic int cur_right(int count0, int count1, char *unused) 7150f66f451Sopenharmony_ci{ 7160f66f451Sopenharmony_ci int count = count0*count1, len, width = 0; 7170f66f451Sopenharmony_ci char buf[8] = {0}; 7180f66f451Sopenharmony_ci 7190f66f451Sopenharmony_ci for (;count; count--) { 7200f66f451Sopenharmony_ci len = text_codepoint(buf, TT.cursor); 7210f66f451Sopenharmony_ci 7220f66f451Sopenharmony_ci if (*buf == '\n') break; 7230f66f451Sopenharmony_ci else if (len > 0) TT.cursor += len; 7240f66f451Sopenharmony_ci else TT.cursor++; 7250f66f451Sopenharmony_ci 7260f66f451Sopenharmony_ci for (;TT.cursor < TT.filesize;) { 7270f66f451Sopenharmony_ci if ((len = text_codepoint(buf, TT.cursor)) < 1) { 7280f66f451Sopenharmony_ci TT.cursor++; //we are not in valid data try jump over 7290f66f451Sopenharmony_ci continue; 7300f66f451Sopenharmony_ci } 7310f66f451Sopenharmony_ci 7320f66f451Sopenharmony_ci if (utf8_lnw(&width, buf, len) && width) break; 7330f66f451Sopenharmony_ci else TT.cursor += len; 7340f66f451Sopenharmony_ci } 7350f66f451Sopenharmony_ci } 7360f66f451Sopenharmony_ci check_cursor_bounds(); 7370f66f451Sopenharmony_ci return 1; 7380f66f451Sopenharmony_ci} 7390f66f451Sopenharmony_ci 7400f66f451Sopenharmony_ci//TODO column shift 7410f66f451Sopenharmony_cistatic int cur_up(int count0, int count1, char *unused) 7420f66f451Sopenharmony_ci{ 7430f66f451Sopenharmony_ci int count = count0*count1; 7440f66f451Sopenharmony_ci for (;count--;) TT.cursor = text_psol(TT.cursor); 7450f66f451Sopenharmony_ci 7460f66f451Sopenharmony_ci TT.vi_mov_flag |= 0x80000000; 7470f66f451Sopenharmony_ci check_cursor_bounds(); 7480f66f451Sopenharmony_ci return 1; 7490f66f451Sopenharmony_ci} 7500f66f451Sopenharmony_ci 7510f66f451Sopenharmony_ci//TODO column shift 7520f66f451Sopenharmony_cistatic int cur_down(int count0, int count1, char *unused) 7530f66f451Sopenharmony_ci{ 7540f66f451Sopenharmony_ci int count = count0*count1; 7550f66f451Sopenharmony_ci for (;count--;) TT.cursor = text_nsol(TT.cursor); 7560f66f451Sopenharmony_ci check_cursor_bounds(); 7570f66f451Sopenharmony_ci return 1; 7580f66f451Sopenharmony_ci} 7590f66f451Sopenharmony_ci 7600f66f451Sopenharmony_cistatic int vi_H(int count0, int count1, char *unused) 7610f66f451Sopenharmony_ci{ 7620f66f451Sopenharmony_ci TT.cursor = text_sol(TT.screen); 7630f66f451Sopenharmony_ci return 1; 7640f66f451Sopenharmony_ci} 7650f66f451Sopenharmony_ci 7660f66f451Sopenharmony_cistatic int vi_L(int count0, int count1, char *unused) 7670f66f451Sopenharmony_ci{ 7680f66f451Sopenharmony_ci TT.cursor = text_sol(TT.screen); 7690f66f451Sopenharmony_ci cur_down(TT.screen_height-1, 1, 0); 7700f66f451Sopenharmony_ci return 1; 7710f66f451Sopenharmony_ci} 7720f66f451Sopenharmony_ci 7730f66f451Sopenharmony_cistatic int vi_M(int count0, int count1, char *unused) 7740f66f451Sopenharmony_ci{ 7750f66f451Sopenharmony_ci TT.cursor = text_sol(TT.screen); 7760f66f451Sopenharmony_ci cur_down(TT.screen_height/2, 1, 0); 7770f66f451Sopenharmony_ci return 1; 7780f66f451Sopenharmony_ci} 7790f66f451Sopenharmony_ci 7800f66f451Sopenharmony_cistatic int search_str(char *s) 7810f66f451Sopenharmony_ci{ 7820f66f451Sopenharmony_ci size_t pos = text_strstr(TT.cursor+1, s); 7830f66f451Sopenharmony_ci 7840f66f451Sopenharmony_ci if (TT.last_search != s) { 7850f66f451Sopenharmony_ci free(TT.last_search); 7860f66f451Sopenharmony_ci TT.last_search = xstrdup(s); 7870f66f451Sopenharmony_ci } 7880f66f451Sopenharmony_ci 7890f66f451Sopenharmony_ci if (pos != SIZE_MAX) TT.cursor = pos; 7900f66f451Sopenharmony_ci check_cursor_bounds(); 7910f66f451Sopenharmony_ci return 0; 7920f66f451Sopenharmony_ci} 7930f66f451Sopenharmony_ci 7940f66f451Sopenharmony_cistatic int vi_yy(char reg, int count0, int count1) 7950f66f451Sopenharmony_ci{ 7960f66f451Sopenharmony_ci size_t history = TT.cursor; 7970f66f451Sopenharmony_ci size_t pos = text_sol(TT.cursor); //go left to first char on line 7980f66f451Sopenharmony_ci TT.vi_mov_flag |= 0x4; 7990f66f451Sopenharmony_ci 8000f66f451Sopenharmony_ci for (;count0; count0--) TT.cursor = text_nsol(TT.cursor); 8010f66f451Sopenharmony_ci 8020f66f451Sopenharmony_ci vi_yank(reg, pos, 0); 8030f66f451Sopenharmony_ci 8040f66f451Sopenharmony_ci TT.cursor = history; 8050f66f451Sopenharmony_ci return 1; 8060f66f451Sopenharmony_ci} 8070f66f451Sopenharmony_ci 8080f66f451Sopenharmony_cistatic int vi_dd(char reg, int count0, int count1) 8090f66f451Sopenharmony_ci{ 8100f66f451Sopenharmony_ci size_t pos = text_sol(TT.cursor); //go left to first char on line 8110f66f451Sopenharmony_ci TT.vi_mov_flag |= 0x30000000; 8120f66f451Sopenharmony_ci 8130f66f451Sopenharmony_ci for (;count0; count0--) TT.cursor = text_nsol(TT.cursor); 8140f66f451Sopenharmony_ci 8150f66f451Sopenharmony_ci if (pos == TT.cursor && TT.filesize) pos--; 8160f66f451Sopenharmony_ci vi_delete(reg, pos, 0); 8170f66f451Sopenharmony_ci check_cursor_bounds(); 8180f66f451Sopenharmony_ci return 1; 8190f66f451Sopenharmony_ci} 8200f66f451Sopenharmony_ci 8210f66f451Sopenharmony_cistatic int vi_x(char reg, int count0, int count1) 8220f66f451Sopenharmony_ci{ 8230f66f451Sopenharmony_ci size_t from = TT.cursor; 8240f66f451Sopenharmony_ci 8250f66f451Sopenharmony_ci if (text_byte(TT.cursor) == '\n') { 8260f66f451Sopenharmony_ci cur_left(count0-1, 1, 0); 8270f66f451Sopenharmony_ci } 8280f66f451Sopenharmony_ci else { 8290f66f451Sopenharmony_ci cur_right(count0-1, 1, 0); 8300f66f451Sopenharmony_ci if (text_byte(TT.cursor) == '\n') TT.vi_mov_flag |= 2; 8310f66f451Sopenharmony_ci else cur_right(1, 1, 0); 8320f66f451Sopenharmony_ci } 8330f66f451Sopenharmony_ci 8340f66f451Sopenharmony_ci vi_delete(reg, from, 0); 8350f66f451Sopenharmony_ci check_cursor_bounds(); 8360f66f451Sopenharmony_ci return 1; 8370f66f451Sopenharmony_ci} 8380f66f451Sopenharmony_ci 8390f66f451Sopenharmony_cistatic int vi_movw(int count0, int count1, char *unused) 8400f66f451Sopenharmony_ci{ 8410f66f451Sopenharmony_ci int count = count0*count1; 8420f66f451Sopenharmony_ci while (count--) { 8430f66f451Sopenharmony_ci char c = text_byte(TT.cursor); 8440f66f451Sopenharmony_ci do { 8450f66f451Sopenharmony_ci if (TT.cursor > TT.filesize-1) break; 8460f66f451Sopenharmony_ci //if at empty jump to non empty 8470f66f451Sopenharmony_ci if (c == '\n') { 8480f66f451Sopenharmony_ci if (++TT.cursor > TT.filesize-1) break; 8490f66f451Sopenharmony_ci if ((c = text_byte(TT.cursor)) == '\n') break; 8500f66f451Sopenharmony_ci continue; 8510f66f451Sopenharmony_ci } else if (strchr(blank, c)) do { 8520f66f451Sopenharmony_ci if (++TT.cursor > TT.filesize-1) break; 8530f66f451Sopenharmony_ci c = text_byte(TT.cursor); 8540f66f451Sopenharmony_ci } while (strchr(blank, c)); 8550f66f451Sopenharmony_ci //if at special jump to non special 8560f66f451Sopenharmony_ci else if (strchr(specials, c)) do { 8570f66f451Sopenharmony_ci if (++TT.cursor > TT.filesize-1) break; 8580f66f451Sopenharmony_ci c = text_byte(TT.cursor); 8590f66f451Sopenharmony_ci } while (strchr(specials, c)); 8600f66f451Sopenharmony_ci //else jump to empty or spesial 8610f66f451Sopenharmony_ci else do { 8620f66f451Sopenharmony_ci if (++TT.cursor > TT.filesize-1) break; 8630f66f451Sopenharmony_ci c = text_byte(TT.cursor); 8640f66f451Sopenharmony_ci } while (c && !strchr(blank, c) && !strchr(specials, c)); 8650f66f451Sopenharmony_ci 8660f66f451Sopenharmony_ci } while (strchr(blank, c) && c != '\n'); //never stop at empty 8670f66f451Sopenharmony_ci } 8680f66f451Sopenharmony_ci check_cursor_bounds(); 8690f66f451Sopenharmony_ci return 1; 8700f66f451Sopenharmony_ci} 8710f66f451Sopenharmony_ci 8720f66f451Sopenharmony_cistatic int vi_movb(int count0, int count1, char *unused) 8730f66f451Sopenharmony_ci{ 8740f66f451Sopenharmony_ci int count = count0*count1; 8750f66f451Sopenharmony_ci int type = 0; 8760f66f451Sopenharmony_ci char c; 8770f66f451Sopenharmony_ci while (count--) { 8780f66f451Sopenharmony_ci c = text_byte(TT.cursor); 8790f66f451Sopenharmony_ci do { 8800f66f451Sopenharmony_ci if (!TT.cursor) break; 8810f66f451Sopenharmony_ci //if at empty jump to non empty 8820f66f451Sopenharmony_ci if (strchr(blank, c)) do { 8830f66f451Sopenharmony_ci if (!--TT.cursor) break; 8840f66f451Sopenharmony_ci c = text_byte(TT.cursor); 8850f66f451Sopenharmony_ci } while (strchr(blank, c)); 8860f66f451Sopenharmony_ci //if at special jump to non special 8870f66f451Sopenharmony_ci else if (strchr(specials, c)) do { 8880f66f451Sopenharmony_ci if (!--TT.cursor) break; 8890f66f451Sopenharmony_ci type = 0; 8900f66f451Sopenharmony_ci c = text_byte(TT.cursor); 8910f66f451Sopenharmony_ci } while (strchr(specials, c)); 8920f66f451Sopenharmony_ci //else jump to empty or spesial 8930f66f451Sopenharmony_ci else do { 8940f66f451Sopenharmony_ci if (!--TT.cursor) break; 8950f66f451Sopenharmony_ci type = 1; 8960f66f451Sopenharmony_ci c = text_byte(TT.cursor); 8970f66f451Sopenharmony_ci } while (!strchr(blank, c) && !strchr(specials, c)); 8980f66f451Sopenharmony_ci 8990f66f451Sopenharmony_ci } while (strchr(blank, c)); //never stop at empty 9000f66f451Sopenharmony_ci } 9010f66f451Sopenharmony_ci //find first 9020f66f451Sopenharmony_ci for (;TT.cursor; TT.cursor--) { 9030f66f451Sopenharmony_ci c = text_byte(TT.cursor-1); 9040f66f451Sopenharmony_ci if (type && !strchr(blank, c) && !strchr(specials, c)) break; 9050f66f451Sopenharmony_ci else if (!type && !strchr(specials, c)) break; 9060f66f451Sopenharmony_ci } 9070f66f451Sopenharmony_ci 9080f66f451Sopenharmony_ci TT.vi_mov_flag |= 0x80000000; 9090f66f451Sopenharmony_ci check_cursor_bounds(); 9100f66f451Sopenharmony_ci return 1; 9110f66f451Sopenharmony_ci} 9120f66f451Sopenharmony_ci 9130f66f451Sopenharmony_cistatic int vi_move(int count0, int count1, char *unused) 9140f66f451Sopenharmony_ci{ 9150f66f451Sopenharmony_ci int count = count0*count1; 9160f66f451Sopenharmony_ci int type = 0; 9170f66f451Sopenharmony_ci char c; 9180f66f451Sopenharmony_ci 9190f66f451Sopenharmony_ci if (count>1) vi_movw(count-1, 1, unused); 9200f66f451Sopenharmony_ci 9210f66f451Sopenharmony_ci c = text_byte(TT.cursor); 9220f66f451Sopenharmony_ci if (strchr(specials, c)) type = 1; 9230f66f451Sopenharmony_ci TT.cursor++; 9240f66f451Sopenharmony_ci for (;TT.cursor < TT.filesize-1; TT.cursor++) { 9250f66f451Sopenharmony_ci c = text_byte(TT.cursor+1); 9260f66f451Sopenharmony_ci if (!type && (strchr(blank, c) || strchr(specials, c))) break; 9270f66f451Sopenharmony_ci else if (type && !strchr(specials, c)) break; 9280f66f451Sopenharmony_ci } 9290f66f451Sopenharmony_ci 9300f66f451Sopenharmony_ci TT.vi_mov_flag |= 2; 9310f66f451Sopenharmony_ci check_cursor_bounds(); 9320f66f451Sopenharmony_ci return 1; 9330f66f451Sopenharmony_ci} 9340f66f451Sopenharmony_ci 9350f66f451Sopenharmony_ci 9360f66f451Sopenharmony_cistatic void i_insert(char *str, int len) 9370f66f451Sopenharmony_ci{ 9380f66f451Sopenharmony_ci if (!str || !len) return; 9390f66f451Sopenharmony_ci 9400f66f451Sopenharmony_ci insert_str(xstrdup(str), TT.cursor, len, len, HEAP); 9410f66f451Sopenharmony_ci TT.cursor += len; 9420f66f451Sopenharmony_ci TT.filesize = text_filesize(); 9430f66f451Sopenharmony_ci TT.vi_mov_flag |= 0x30000000; 9440f66f451Sopenharmony_ci} 9450f66f451Sopenharmony_ci 9460f66f451Sopenharmony_cistatic int vi_zero(int count0, int count1, char *unused) 9470f66f451Sopenharmony_ci{ 9480f66f451Sopenharmony_ci TT.cursor = text_sol(TT.cursor); 9490f66f451Sopenharmony_ci TT.cur_col = 0; 9500f66f451Sopenharmony_ci TT.vi_mov_flag |= 0x80000000; 9510f66f451Sopenharmony_ci return 1; 9520f66f451Sopenharmony_ci} 9530f66f451Sopenharmony_ci 9540f66f451Sopenharmony_cistatic int vi_dollar(int count0, int count1, char *unused) 9550f66f451Sopenharmony_ci{ 9560f66f451Sopenharmony_ci size_t new = text_strchr(TT.cursor, '\n'); 9570f66f451Sopenharmony_ci 9580f66f451Sopenharmony_ci if (new != TT.cursor) { 9590f66f451Sopenharmony_ci TT.cursor = new - 1; 9600f66f451Sopenharmony_ci TT.vi_mov_flag |= 2; 9610f66f451Sopenharmony_ci check_cursor_bounds(); 9620f66f451Sopenharmony_ci } 9630f66f451Sopenharmony_ci return 1; 9640f66f451Sopenharmony_ci} 9650f66f451Sopenharmony_ci 9660f66f451Sopenharmony_cistatic void vi_eol() 9670f66f451Sopenharmony_ci{ 9680f66f451Sopenharmony_ci TT.cursor = text_strchr(TT.cursor, '\n'); 9690f66f451Sopenharmony_ci check_cursor_bounds(); 9700f66f451Sopenharmony_ci} 9710f66f451Sopenharmony_ci 9720f66f451Sopenharmony_cistatic void ctrl_b() 9730f66f451Sopenharmony_ci{ 9740f66f451Sopenharmony_ci int i; 9750f66f451Sopenharmony_ci 9760f66f451Sopenharmony_ci for (i=0; i<TT.screen_height-2; ++i) { 9770f66f451Sopenharmony_ci TT.screen = text_psol(TT.screen); 9780f66f451Sopenharmony_ci // TODO: retain x offset. 9790f66f451Sopenharmony_ci TT.cursor = text_psol(TT.screen); 9800f66f451Sopenharmony_ci } 9810f66f451Sopenharmony_ci} 9820f66f451Sopenharmony_ci 9830f66f451Sopenharmony_cistatic void ctrl_f() 9840f66f451Sopenharmony_ci{ 9850f66f451Sopenharmony_ci int i; 9860f66f451Sopenharmony_ci 9870f66f451Sopenharmony_ci for (i=0; i<TT.screen_height-2; ++i) TT.screen = text_nsol(TT.screen); 9880f66f451Sopenharmony_ci // TODO: real vi keeps the x position. 9890f66f451Sopenharmony_ci if (TT.screen > TT.cursor) TT.cursor = TT.screen; 9900f66f451Sopenharmony_ci} 9910f66f451Sopenharmony_ci 9920f66f451Sopenharmony_cistatic void ctrl_e() 9930f66f451Sopenharmony_ci{ 9940f66f451Sopenharmony_ci TT.screen = text_nsol(TT.screen); 9950f66f451Sopenharmony_ci // TODO: real vi keeps the x position. 9960f66f451Sopenharmony_ci if (TT.screen > TT.cursor) TT.cursor = TT.screen; 9970f66f451Sopenharmony_ci} 9980f66f451Sopenharmony_ci 9990f66f451Sopenharmony_cistatic void ctrl_y() 10000f66f451Sopenharmony_ci{ 10010f66f451Sopenharmony_ci TT.screen = text_psol(TT.screen); 10020f66f451Sopenharmony_ci // TODO: only if we're on the bottom line 10030f66f451Sopenharmony_ci TT.cursor = text_psol(TT.cursor); 10040f66f451Sopenharmony_ci // TODO: real vi keeps the x position. 10050f66f451Sopenharmony_ci} 10060f66f451Sopenharmony_ci 10070f66f451Sopenharmony_ci//TODO check register where to push from 10080f66f451Sopenharmony_cistatic int vi_push(char reg, int count0, int count1) 10090f66f451Sopenharmony_ci{ 10100f66f451Sopenharmony_ci //if row changes during push original cursor position is kept 10110f66f451Sopenharmony_ci //vi inconsistancy 10120f66f451Sopenharmony_ci //if yank ends with \n push is linemode else push in place+1 10130f66f451Sopenharmony_ci size_t history = TT.cursor; 10140f66f451Sopenharmony_ci char *start = TT.yank.data; 10150f66f451Sopenharmony_ci char *eol = strchr(start, '\n'); 10160f66f451Sopenharmony_ci 10170f66f451Sopenharmony_ci if (start[strlen(start)-1] == '\n') { 10180f66f451Sopenharmony_ci if ((TT.cursor = text_strchr(TT.cursor, '\n')) == SIZE_MAX) 10190f66f451Sopenharmony_ci TT.cursor = TT.filesize; 10200f66f451Sopenharmony_ci else TT.cursor = text_nsol(TT.cursor); 10210f66f451Sopenharmony_ci } else cur_right(1, 1, 0); 10220f66f451Sopenharmony_ci 10230f66f451Sopenharmony_ci i_insert(start, strlen(start)); 10240f66f451Sopenharmony_ci if (eol) { 10250f66f451Sopenharmony_ci TT.vi_mov_flag |= 0x10000000; 10260f66f451Sopenharmony_ci TT.cursor = history; 10270f66f451Sopenharmony_ci } 10280f66f451Sopenharmony_ci 10290f66f451Sopenharmony_ci return 1; 10300f66f451Sopenharmony_ci} 10310f66f451Sopenharmony_ci 10320f66f451Sopenharmony_cistatic int vi_find_c(int count0, int count1, char *symbol) 10330f66f451Sopenharmony_ci{ 10340f66f451Sopenharmony_ci//// int count = count0*count1; 10350f66f451Sopenharmony_ci size_t pos = text_strchr(TT.cursor, *symbol); 10360f66f451Sopenharmony_ci if (pos != SIZE_MAX) TT.cursor = pos; 10370f66f451Sopenharmony_ci return 1; 10380f66f451Sopenharmony_ci} 10390f66f451Sopenharmony_ci 10400f66f451Sopenharmony_cistatic int vi_find_cb(int count0, int count1, char *symbol) 10410f66f451Sopenharmony_ci{ 10420f66f451Sopenharmony_ci //do backward search 10430f66f451Sopenharmony_ci size_t pos = text_strrchr(TT.cursor, *symbol); 10440f66f451Sopenharmony_ci if (pos != SIZE_MAX) TT.cursor = pos; 10450f66f451Sopenharmony_ci return 1; 10460f66f451Sopenharmony_ci} 10470f66f451Sopenharmony_ci 10480f66f451Sopenharmony_ci//if count is not spesified should go to last line 10490f66f451Sopenharmony_cistatic int vi_go(int count0, int count1, char *symbol) 10500f66f451Sopenharmony_ci{ 10510f66f451Sopenharmony_ci size_t prev_cursor = TT.cursor; 10520f66f451Sopenharmony_ci int count = count0*count1-1; 10530f66f451Sopenharmony_ci TT.cursor = 0; 10540f66f451Sopenharmony_ci 10550f66f451Sopenharmony_ci if (TT.vi_mov_flag&0x40000000 && (TT.cursor = TT.filesize) > 0) 10560f66f451Sopenharmony_ci TT.cursor = text_sol(TT.cursor-1); 10570f66f451Sopenharmony_ci else if (count) { 10580f66f451Sopenharmony_ci size_t next = 0; 10590f66f451Sopenharmony_ci for ( ;count && (next = text_strchr(next+1, '\n')) != SIZE_MAX; count--) 10600f66f451Sopenharmony_ci TT.cursor = next; 10610f66f451Sopenharmony_ci TT.cursor++; 10620f66f451Sopenharmony_ci } 10630f66f451Sopenharmony_ci 10640f66f451Sopenharmony_ci check_cursor_bounds(); //adjusts cursor column 10650f66f451Sopenharmony_ci if (prev_cursor > TT.cursor) TT.vi_mov_flag |= 0x80000000; 10660f66f451Sopenharmony_ci 10670f66f451Sopenharmony_ci return 1; 10680f66f451Sopenharmony_ci} 10690f66f451Sopenharmony_ci 10700f66f451Sopenharmony_cistatic int vi_o(char reg, int count0, int count1) 10710f66f451Sopenharmony_ci{ 10720f66f451Sopenharmony_ci TT.cursor = text_eol(TT.cursor); 10730f66f451Sopenharmony_ci insert_str(xstrdup("\n"), TT.cursor++, 1, 1, HEAP); 10740f66f451Sopenharmony_ci TT.vi_mov_flag |= 0x30000000; 10750f66f451Sopenharmony_ci TT.vi_mode = 2; 10760f66f451Sopenharmony_ci return 1; 10770f66f451Sopenharmony_ci} 10780f66f451Sopenharmony_ci 10790f66f451Sopenharmony_cistatic int vi_O(char reg, int count0, int count1) 10800f66f451Sopenharmony_ci{ 10810f66f451Sopenharmony_ci TT.cursor = text_psol(TT.cursor); 10820f66f451Sopenharmony_ci return vi_o(reg, count0, count1); 10830f66f451Sopenharmony_ci} 10840f66f451Sopenharmony_ci 10850f66f451Sopenharmony_cistatic int vi_D(char reg, int count0, int count1) 10860f66f451Sopenharmony_ci{ 10870f66f451Sopenharmony_ci size_t pos = TT.cursor; 10880f66f451Sopenharmony_ci if (!count0) return 1; 10890f66f451Sopenharmony_ci vi_eol(); 10900f66f451Sopenharmony_ci vi_delete(reg, pos, 0); 10910f66f451Sopenharmony_ci if (--count0) vi_dd(reg, count0, 1); 10920f66f451Sopenharmony_ci 10930f66f451Sopenharmony_ci check_cursor_bounds(); 10940f66f451Sopenharmony_ci return 1; 10950f66f451Sopenharmony_ci} 10960f66f451Sopenharmony_ci 10970f66f451Sopenharmony_cistatic int vi_I(char reg, int count0, int count1) 10980f66f451Sopenharmony_ci{ 10990f66f451Sopenharmony_ci TT.cursor = text_sol(TT.cursor); 11000f66f451Sopenharmony_ci TT.vi_mode = 2; 11010f66f451Sopenharmony_ci return 1; 11020f66f451Sopenharmony_ci} 11030f66f451Sopenharmony_ci 11040f66f451Sopenharmony_cistatic int vi_join(char reg, int count0, int count1) 11050f66f451Sopenharmony_ci{ 11060f66f451Sopenharmony_ci size_t next; 11070f66f451Sopenharmony_ci while (count0--) { 11080f66f451Sopenharmony_ci //just strchr(/n) and cut_str(pos, 1); 11090f66f451Sopenharmony_ci if ((next = text_strchr(TT.cursor, '\n')) == SIZE_MAX) break; 11100f66f451Sopenharmony_ci TT.cursor = next+1; 11110f66f451Sopenharmony_ci vi_delete(reg, TT.cursor-1, 0); 11120f66f451Sopenharmony_ci } 11130f66f451Sopenharmony_ci return 1; 11140f66f451Sopenharmony_ci} 11150f66f451Sopenharmony_ci 11160f66f451Sopenharmony_cistatic int vi_find_next(char reg, int count0, int count1) 11170f66f451Sopenharmony_ci{ 11180f66f451Sopenharmony_ci if (TT.last_search) search_str(TT.last_search); 11190f66f451Sopenharmony_ci return 1; 11200f66f451Sopenharmony_ci} 11210f66f451Sopenharmony_ci 11220f66f451Sopenharmony_ci//NOTES 11230f66f451Sopenharmony_ci//vi-mode cmd syntax is 11240f66f451Sopenharmony_ci//("[REG])[COUNT0]CMD[COUNT1](MOV) 11250f66f451Sopenharmony_ci//where: 11260f66f451Sopenharmony_ci//------------------------------------------------------------- 11270f66f451Sopenharmony_ci//"[REG] is optional buffer where deleted/yanked text goes REG can be 11280f66f451Sopenharmony_ci// atleast 0-9, a-z or default " 11290f66f451Sopenharmony_ci//[COUNT] is optional multiplier for cmd execution if there is 2 COUNT 11300f66f451Sopenharmony_ci// operations they are multiplied together 11310f66f451Sopenharmony_ci//CMD is operation to be executed 11320f66f451Sopenharmony_ci//(MOV) is movement operation, some CMD does not require MOV and some 11330f66f451Sopenharmony_ci// have special cases such as dd, yy, also movements can work without 11340f66f451Sopenharmony_ci// CMD 11350f66f451Sopenharmony_ci//ex commands can be even more complicated than this.... 11360f66f451Sopenharmony_ci// 11370f66f451Sopenharmony_cistruct vi_cmd_param { 11380f66f451Sopenharmony_ci const char* cmd; 11390f66f451Sopenharmony_ci unsigned flags; 11400f66f451Sopenharmony_ci int (*vi_cmd)(char, size_t, int);//REG,from,FLAGS 11410f66f451Sopenharmony_ci}; 11420f66f451Sopenharmony_cistruct vi_mov_param { 11430f66f451Sopenharmony_ci const char* mov; 11440f66f451Sopenharmony_ci unsigned flags; 11450f66f451Sopenharmony_ci int (*vi_mov)(int, int, char*);//COUNT0,COUNT1,params 11460f66f451Sopenharmony_ci}; 11470f66f451Sopenharmony_ci//special cases without MOV and such 11480f66f451Sopenharmony_cistruct vi_special_param { 11490f66f451Sopenharmony_ci const char *cmd; 11500f66f451Sopenharmony_ci int (*vi_special)(char, int, int);//REG,COUNT0,COUNT1 11510f66f451Sopenharmony_ci}; 11520f66f451Sopenharmony_cistruct vi_special_param vi_special[] = 11530f66f451Sopenharmony_ci{ 11540f66f451Sopenharmony_ci {"D", &vi_D}, 11550f66f451Sopenharmony_ci {"I", &vi_I}, 11560f66f451Sopenharmony_ci {"J", &vi_join}, 11570f66f451Sopenharmony_ci {"O", &vi_O}, 11580f66f451Sopenharmony_ci {"n", &vi_find_next}, 11590f66f451Sopenharmony_ci {"o", &vi_o}, 11600f66f451Sopenharmony_ci {"p", &vi_push}, 11610f66f451Sopenharmony_ci {"x", &vi_x}, 11620f66f451Sopenharmony_ci {"dd", &vi_dd}, 11630f66f451Sopenharmony_ci {"yy", &vi_yy}, 11640f66f451Sopenharmony_ci}; 11650f66f451Sopenharmony_ci//there is around ~47 vi moves 11660f66f451Sopenharmony_ci//some of them need extra params 11670f66f451Sopenharmony_ci//such as f and ' 11680f66f451Sopenharmony_cistruct vi_mov_param vi_movs[] = 11690f66f451Sopenharmony_ci{ 11700f66f451Sopenharmony_ci {"0", 0, &vi_zero}, 11710f66f451Sopenharmony_ci {"b", 0, &vi_movb}, 11720f66f451Sopenharmony_ci {"e", 0, &vi_move}, 11730f66f451Sopenharmony_ci {"G", 0, &vi_go}, 11740f66f451Sopenharmony_ci {"H", 0, &vi_H}, 11750f66f451Sopenharmony_ci {"h", 0, &cur_left}, 11760f66f451Sopenharmony_ci {"j", 0, &cur_down}, 11770f66f451Sopenharmony_ci {"k", 0, &cur_up}, 11780f66f451Sopenharmony_ci {"L", 0, &vi_L}, 11790f66f451Sopenharmony_ci {"l", 0, &cur_right}, 11800f66f451Sopenharmony_ci {"M", 0, &vi_M}, 11810f66f451Sopenharmony_ci {"w", 0, &vi_movw}, 11820f66f451Sopenharmony_ci {"$", 0, &vi_dollar}, 11830f66f451Sopenharmony_ci {"f", 1, &vi_find_c}, 11840f66f451Sopenharmony_ci {"F", 1, &vi_find_cb}, 11850f66f451Sopenharmony_ci}; 11860f66f451Sopenharmony_ci//change and delete unfortunately behave different depending on move command, 11870f66f451Sopenharmony_ci//such as ce cw are same, but dw and de are not... 11880f66f451Sopenharmony_ci//also dw stops at w position and cw seem to stop at e pos+1... 11890f66f451Sopenharmony_ci//so after movement we need to possibly set up some flags before executing 11900f66f451Sopenharmony_ci//command, and command needs to adjust... 11910f66f451Sopenharmony_cistruct vi_cmd_param vi_cmds[] = 11920f66f451Sopenharmony_ci{ 11930f66f451Sopenharmony_ci {"c", 1, &vi_change}, 11940f66f451Sopenharmony_ci {"d", 1, &vi_delete}, 11950f66f451Sopenharmony_ci {"y", 1, &vi_yank}, 11960f66f451Sopenharmony_ci}; 11970f66f451Sopenharmony_ci 11980f66f451Sopenharmony_cistatic int run_vi_cmd(char *cmd) 11990f66f451Sopenharmony_ci{ 12000f66f451Sopenharmony_ci int i = 0, val = 0; 12010f66f451Sopenharmony_ci char *cmd_e; 12020f66f451Sopenharmony_ci int (*vi_cmd)(char, size_t, int) = 0; 12030f66f451Sopenharmony_ci int (*vi_mov)(int, int, char*) = 0; 12040f66f451Sopenharmony_ci 12050f66f451Sopenharmony_ci TT.count0 = 0, TT.count1 = 0, TT.vi_mov_flag = 0; 12060f66f451Sopenharmony_ci TT.vi_reg = '"'; 12070f66f451Sopenharmony_ci 12080f66f451Sopenharmony_ci if (*cmd == '"') { 12090f66f451Sopenharmony_ci cmd++; 12100f66f451Sopenharmony_ci TT.vi_reg = *cmd; //TODO check validity 12110f66f451Sopenharmony_ci cmd++; 12120f66f451Sopenharmony_ci } 12130f66f451Sopenharmony_ci errno = 0; 12140f66f451Sopenharmony_ci val = strtol(cmd, &cmd_e, 10); 12150f66f451Sopenharmony_ci if (errno || val == 0) val = 1, TT.vi_mov_flag |= 0x40000000; 12160f66f451Sopenharmony_ci else cmd = cmd_e; 12170f66f451Sopenharmony_ci TT.count0 = val; 12180f66f451Sopenharmony_ci 12190f66f451Sopenharmony_ci for (i = 0; i < ARRAY_LEN(vi_special); i++) { 12200f66f451Sopenharmony_ci if (strstr(cmd, vi_special[i].cmd)) { 12210f66f451Sopenharmony_ci return vi_special[i].vi_special(TT.vi_reg, TT.count0, TT.count1); 12220f66f451Sopenharmony_ci } 12230f66f451Sopenharmony_ci } 12240f66f451Sopenharmony_ci 12250f66f451Sopenharmony_ci for (i = 0; i < ARRAY_LEN(vi_cmds); i++) { 12260f66f451Sopenharmony_ci if (!strncmp(cmd, vi_cmds[i].cmd, strlen(vi_cmds[i].cmd))) { 12270f66f451Sopenharmony_ci vi_cmd = vi_cmds[i].vi_cmd; 12280f66f451Sopenharmony_ci cmd += strlen(vi_cmds[i].cmd); 12290f66f451Sopenharmony_ci break; 12300f66f451Sopenharmony_ci } 12310f66f451Sopenharmony_ci } 12320f66f451Sopenharmony_ci errno = 0; 12330f66f451Sopenharmony_ci val = strtol(cmd, &cmd_e, 10); 12340f66f451Sopenharmony_ci if (errno || val == 0) val = 1; 12350f66f451Sopenharmony_ci else cmd = cmd_e; 12360f66f451Sopenharmony_ci TT.count1 = val; 12370f66f451Sopenharmony_ci 12380f66f451Sopenharmony_ci for (i = 0; i < ARRAY_LEN(vi_movs); i++) { 12390f66f451Sopenharmony_ci if (!strncmp(cmd, vi_movs[i].mov, strlen(vi_movs[i].mov))) { 12400f66f451Sopenharmony_ci vi_mov = vi_movs[i].vi_mov; 12410f66f451Sopenharmony_ci TT.vi_mov_flag |= vi_movs[i].flags; 12420f66f451Sopenharmony_ci cmd++; 12430f66f451Sopenharmony_ci if (TT.vi_mov_flag&1 && !(*cmd)) return 0; 12440f66f451Sopenharmony_ci break; 12450f66f451Sopenharmony_ci } 12460f66f451Sopenharmony_ci } 12470f66f451Sopenharmony_ci if (vi_mov) { 12480f66f451Sopenharmony_ci int prev_cursor = TT.cursor; 12490f66f451Sopenharmony_ci if (vi_mov(TT.count0, TT.count1, cmd)) { 12500f66f451Sopenharmony_ci if (vi_cmd) return (vi_cmd(TT.vi_reg, prev_cursor, TT.vi_mov_flag)); 12510f66f451Sopenharmony_ci else return 1; 12520f66f451Sopenharmony_ci } else return 0; //return some error 12530f66f451Sopenharmony_ci } 12540f66f451Sopenharmony_ci return 0; 12550f66f451Sopenharmony_ci} 12560f66f451Sopenharmony_ci 12570f66f451Sopenharmony_ci 12580f66f451Sopenharmony_cistatic int run_ex_cmd(char *cmd) 12590f66f451Sopenharmony_ci{ 12600f66f451Sopenharmony_ci if (cmd[0] == '/') { 12610f66f451Sopenharmony_ci search_str(&cmd[1]); 12620f66f451Sopenharmony_ci } else if (cmd[0] == '?') { 12630f66f451Sopenharmony_ci // TODO: backwards search. 12640f66f451Sopenharmony_ci } else if (cmd[0] == ':') { 12650f66f451Sopenharmony_ci if (!strcmp(&cmd[1], "q") || !strcmp(&cmd[1], "q!")) { 12660f66f451Sopenharmony_ci // TODO: if no !, check whether file modified. 12670f66f451Sopenharmony_ci //exit_application; 12680f66f451Sopenharmony_ci return -1; 12690f66f451Sopenharmony_ci } 12700f66f451Sopenharmony_ci else if (strstr(&cmd[1], "wq")) { 12710f66f451Sopenharmony_ci write_file(0); 12720f66f451Sopenharmony_ci return -1; 12730f66f451Sopenharmony_ci } 12740f66f451Sopenharmony_ci else if (strstr(&cmd[1], "w")) { 12750f66f451Sopenharmony_ci write_file(0); 12760f66f451Sopenharmony_ci return 1; 12770f66f451Sopenharmony_ci } 12780f66f451Sopenharmony_ci else if (strstr(&cmd[1], "set list")) { 12790f66f451Sopenharmony_ci TT.list = 1; 12800f66f451Sopenharmony_ci TT.vi_mov_flag |= 0x30000000; 12810f66f451Sopenharmony_ci return 1; 12820f66f451Sopenharmony_ci } 12830f66f451Sopenharmony_ci else if (strstr(&cmd[1], "set nolist")) { 12840f66f451Sopenharmony_ci TT.list = 0; 12850f66f451Sopenharmony_ci TT.vi_mov_flag |= 0x30000000; 12860f66f451Sopenharmony_ci return 1; 12870f66f451Sopenharmony_ci } 12880f66f451Sopenharmony_ci } 12890f66f451Sopenharmony_ci return 0; 12900f66f451Sopenharmony_ci 12910f66f451Sopenharmony_ci} 12920f66f451Sopenharmony_ci 12930f66f451Sopenharmony_cistatic int vi_crunch(FILE *out, int cols, int wc) 12940f66f451Sopenharmony_ci{ 12950f66f451Sopenharmony_ci int ret = 0; 12960f66f451Sopenharmony_ci if (wc < 32 && TT.list) { 12970f66f451Sopenharmony_ci tty_esc("1m"); 12980f66f451Sopenharmony_ci ret = crunch_escape(out,cols,wc); 12990f66f451Sopenharmony_ci tty_esc("m"); 13000f66f451Sopenharmony_ci } else if (wc == 0x09) { 13010f66f451Sopenharmony_ci if (out) { 13020f66f451Sopenharmony_ci int i = TT.tabstop; 13030f66f451Sopenharmony_ci for (;i--;) fputs(" ", out); 13040f66f451Sopenharmony_ci } 13050f66f451Sopenharmony_ci ret = TT.tabstop; 13060f66f451Sopenharmony_ci } else if (wc == '\n') return 0; 13070f66f451Sopenharmony_ci return ret; 13080f66f451Sopenharmony_ci} 13090f66f451Sopenharmony_ci 13100f66f451Sopenharmony_ci//crunch_str with n bytes restriction for printing substrings or 13110f66f451Sopenharmony_ci//non null terminated strings 13120f66f451Sopenharmony_cistatic int crunch_nstr(char **str, int width, int n, FILE *out, char *escmore, 13130f66f451Sopenharmony_ci int (*escout)(FILE *out, int cols, int wc)) 13140f66f451Sopenharmony_ci{ 13150f66f451Sopenharmony_ci int columns = 0, col, bytes; 13160f66f451Sopenharmony_ci char *start, *end; 13170f66f451Sopenharmony_ci unsigned wc; 13180f66f451Sopenharmony_ci 13190f66f451Sopenharmony_ci for (end = start = *str; *end && n>0; columns += col, end += bytes, n -= bytes) { 13200f66f451Sopenharmony_ci if ((bytes = utf8towc(&wc, end, 4))>0 && (col = wcwidth(wc))>=0) { 13210f66f451Sopenharmony_ci if (!escmore || wc>255 || !strchr(escmore, wc)) { 13220f66f451Sopenharmony_ci if (width-columns<col) break; 13230f66f451Sopenharmony_ci if (out) fwrite(end, bytes, 1, out); 13240f66f451Sopenharmony_ci 13250f66f451Sopenharmony_ci continue; 13260f66f451Sopenharmony_ci } 13270f66f451Sopenharmony_ci } 13280f66f451Sopenharmony_ci 13290f66f451Sopenharmony_ci if (bytes<1) { 13300f66f451Sopenharmony_ci bytes = 1; 13310f66f451Sopenharmony_ci wc = *end; 13320f66f451Sopenharmony_ci } 13330f66f451Sopenharmony_ci col = width-columns; 13340f66f451Sopenharmony_ci if (col<1) break; 13350f66f451Sopenharmony_ci if (escout) { 13360f66f451Sopenharmony_ci if ((col = escout(out, col, wc))<0) break; 13370f66f451Sopenharmony_ci } else if (out) fwrite(end, 1, bytes, out); 13380f66f451Sopenharmony_ci } 13390f66f451Sopenharmony_ci *str = end; 13400f66f451Sopenharmony_ci 13410f66f451Sopenharmony_ci return columns; 13420f66f451Sopenharmony_ci} 13430f66f451Sopenharmony_ci 13440f66f451Sopenharmony_cistatic void draw_page() 13450f66f451Sopenharmony_ci{ 13460f66f451Sopenharmony_ci unsigned y = 0; 13470f66f451Sopenharmony_ci int x = 0; 13480f66f451Sopenharmony_ci 13490f66f451Sopenharmony_ci char *line = 0, *end = 0; 13500f66f451Sopenharmony_ci int bytes = 0; 13510f66f451Sopenharmony_ci 13520f66f451Sopenharmony_ci //screen coordinates for cursor 13530f66f451Sopenharmony_ci int cy_scr = 0, cx_scr = 0; 13540f66f451Sopenharmony_ci 13550f66f451Sopenharmony_ci //variables used only for cursor handling 13560f66f451Sopenharmony_ci int aw = 0, iw = 0, clip = 0, margin = 8; 13570f66f451Sopenharmony_ci 13580f66f451Sopenharmony_ci int scroll = 0, redraw = 0; 13590f66f451Sopenharmony_ci 13600f66f451Sopenharmony_ci int SSOL, SOL; 13610f66f451Sopenharmony_ci 13620f66f451Sopenharmony_ci 13630f66f451Sopenharmony_ci adjust_screen_buffer(); 13640f66f451Sopenharmony_ci //redraw = 3; //force full redraw 13650f66f451Sopenharmony_ci redraw = (TT.vi_mov_flag & 0x30000000)>>28; 13660f66f451Sopenharmony_ci 13670f66f451Sopenharmony_ci scroll = TT.drawn_row-TT.scr_row; 13680f66f451Sopenharmony_ci if (TT.drawn_row<0 || TT.cur_row<0 || TT.scr_row<0) redraw = 3; 13690f66f451Sopenharmony_ci else if (abs(scroll)>TT.screen_height/2) redraw = 3; 13700f66f451Sopenharmony_ci 13710f66f451Sopenharmony_ci tty_jump(0, 0); 13720f66f451Sopenharmony_ci if (redraw&2) tty_esc("2J"), tty_esc("H"); //clear screen 13730f66f451Sopenharmony_ci else if (scroll>0) printf("\033[%dL", scroll); //scroll up 13740f66f451Sopenharmony_ci else if (scroll<0) printf("\033[%dM", -scroll); //scroll down 13750f66f451Sopenharmony_ci 13760f66f451Sopenharmony_ci SOL = text_sol(TT.cursor); 13770f66f451Sopenharmony_ci bytes = text_getline(toybuf, SOL, ARRAY_LEN(toybuf)); 13780f66f451Sopenharmony_ci line = toybuf; 13790f66f451Sopenharmony_ci 13800f66f451Sopenharmony_ci for (SSOL = TT.screen, y = 0; SSOL < SOL; y++) SSOL = text_nsol(SSOL); 13810f66f451Sopenharmony_ci 13820f66f451Sopenharmony_ci cy_scr = y; 13830f66f451Sopenharmony_ci 13840f66f451Sopenharmony_ci //draw cursor row 13850f66f451Sopenharmony_ci ///////////////////////////////////////////////////////////// 13860f66f451Sopenharmony_ci //for long lines line starts to scroll when cursor hits margin 13870f66f451Sopenharmony_ci bytes = TT.cursor-SOL; // TT.cur_col; 13880f66f451Sopenharmony_ci end = line; 13890f66f451Sopenharmony_ci 13900f66f451Sopenharmony_ci 13910f66f451Sopenharmony_ci tty_jump(0, y); 13920f66f451Sopenharmony_ci tty_esc("2K"); 13930f66f451Sopenharmony_ci //find cursor position 13940f66f451Sopenharmony_ci aw = crunch_nstr(&end, INT_MAX, bytes, 0, "\t\n", vi_crunch); 13950f66f451Sopenharmony_ci 13960f66f451Sopenharmony_ci //if we need to render text that is not inserted to buffer yet 13970f66f451Sopenharmony_ci if (TT.vi_mode == 2 && TT.il->len) { 13980f66f451Sopenharmony_ci char* iend = TT.il->data; //input end 13990f66f451Sopenharmony_ci x = 0; 14000f66f451Sopenharmony_ci //find insert end position 14010f66f451Sopenharmony_ci iw = crunch_str(&iend, INT_MAX, 0, "\t\n", vi_crunch); 14020f66f451Sopenharmony_ci clip = (aw+iw) - TT.screen_width+margin; 14030f66f451Sopenharmony_ci 14040f66f451Sopenharmony_ci //if clipped area is bigger than text before insert 14050f66f451Sopenharmony_ci if (clip > aw) { 14060f66f451Sopenharmony_ci clip -= aw; 14070f66f451Sopenharmony_ci iend = TT.il->data; 14080f66f451Sopenharmony_ci 14090f66f451Sopenharmony_ci iw -= crunch_str(&iend, clip, 0, "\t\n", vi_crunch); 14100f66f451Sopenharmony_ci x = crunch_str(&iend, iw, stdout, "\t\n", vi_crunch); 14110f66f451Sopenharmony_ci } else { 14120f66f451Sopenharmony_ci iend = TT.il->data; 14130f66f451Sopenharmony_ci end = line; 14140f66f451Sopenharmony_ci 14150f66f451Sopenharmony_ci //if clipped area is substring from cursor row start 14160f66f451Sopenharmony_ci aw -= crunch_nstr(&end, clip, bytes, 0, "\t\n", vi_crunch); 14170f66f451Sopenharmony_ci x = crunch_str(&end, aw, stdout, "\t\n", vi_crunch); 14180f66f451Sopenharmony_ci x += crunch_str(&iend, iw, stdout, "\t\n", vi_crunch); 14190f66f451Sopenharmony_ci } 14200f66f451Sopenharmony_ci } 14210f66f451Sopenharmony_ci //when not inserting but still need to keep cursor inside screen 14220f66f451Sopenharmony_ci //margin area 14230f66f451Sopenharmony_ci else if ( aw+margin > TT.screen_width) { 14240f66f451Sopenharmony_ci clip = aw-TT.screen_width+margin; 14250f66f451Sopenharmony_ci end = line; 14260f66f451Sopenharmony_ci aw -= crunch_nstr(&end, clip, bytes, 0, "\t\n", vi_crunch); 14270f66f451Sopenharmony_ci x = crunch_str(&end, aw, stdout, "\t\n", vi_crunch); 14280f66f451Sopenharmony_ci } 14290f66f451Sopenharmony_ci else { 14300f66f451Sopenharmony_ci end = line; 14310f66f451Sopenharmony_ci x = crunch_nstr(&end, aw, bytes, stdout, "\t\n", vi_crunch); 14320f66f451Sopenharmony_ci } 14330f66f451Sopenharmony_ci cx_scr = x; 14340f66f451Sopenharmony_ci cy_scr = y; 14350f66f451Sopenharmony_ci x += crunch_str(&end, TT.screen_width-x, stdout, "\t\n", vi_crunch); 14360f66f451Sopenharmony_ci 14370f66f451Sopenharmony_ci //start drawing all other rows that needs update 14380f66f451Sopenharmony_ci /////////////////////////////////////////////////////////////////// 14390f66f451Sopenharmony_ci y = 0, SSOL = TT.screen, line = toybuf; 14400f66f451Sopenharmony_ci bytes = text_getline(toybuf, SSOL, ARRAY_LEN(toybuf)); 14410f66f451Sopenharmony_ci 14420f66f451Sopenharmony_ci //if we moved around in long line might need to redraw everything 14430f66f451Sopenharmony_ci if (clip != TT.drawn_col) redraw = 3; 14440f66f451Sopenharmony_ci 14450f66f451Sopenharmony_ci for (; y < TT.screen_height; y++ ) { 14460f66f451Sopenharmony_ci int draw_line = 0; 14470f66f451Sopenharmony_ci if (SSOL == SOL) { 14480f66f451Sopenharmony_ci line = toybuf; 14490f66f451Sopenharmony_ci SSOL += bytes+1; 14500f66f451Sopenharmony_ci bytes = text_getline(line, SSOL, ARRAY_LEN(toybuf)); 14510f66f451Sopenharmony_ci continue; 14520f66f451Sopenharmony_ci } else if (redraw) draw_line++; 14530f66f451Sopenharmony_ci else if (scroll<0 && TT.screen_height-y-1<-scroll) 14540f66f451Sopenharmony_ci scroll++, draw_line++; 14550f66f451Sopenharmony_ci else if (scroll>0) scroll--, draw_line++; 14560f66f451Sopenharmony_ci 14570f66f451Sopenharmony_ci tty_jump(0, y); 14580f66f451Sopenharmony_ci if (draw_line) { 14590f66f451Sopenharmony_ci tty_esc("2K"); 14600f66f451Sopenharmony_ci if (line && strlen(line)) { 14610f66f451Sopenharmony_ci aw = crunch_nstr(&line, clip, bytes, 0, "\t\n", vi_crunch); 14620f66f451Sopenharmony_ci crunch_str(&line, TT.screen_width-1, stdout, "\t\n", vi_crunch); 14630f66f451Sopenharmony_ci if ( *line ) printf("@"); 14640f66f451Sopenharmony_ci } else printf("\033[2m~\033[m"); 14650f66f451Sopenharmony_ci } 14660f66f451Sopenharmony_ci if (SSOL+bytes < TT.filesize) { 14670f66f451Sopenharmony_ci line = toybuf; 14680f66f451Sopenharmony_ci SSOL += bytes+1; 14690f66f451Sopenharmony_ci bytes = text_getline(line, SSOL, ARRAY_LEN(toybuf)); 14700f66f451Sopenharmony_ci } else line = 0; 14710f66f451Sopenharmony_ci } 14720f66f451Sopenharmony_ci 14730f66f451Sopenharmony_ci TT.drawn_row = TT.scr_row, TT.drawn_col = clip; 14740f66f451Sopenharmony_ci 14750f66f451Sopenharmony_ci // Finished updating visual area, show status line. 14760f66f451Sopenharmony_ci tty_jump(0, TT.screen_height); 14770f66f451Sopenharmony_ci tty_esc("2K"); 14780f66f451Sopenharmony_ci if (TT.vi_mode == 2) printf("\033[1m-- INSERT --\033[m"); 14790f66f451Sopenharmony_ci if (!TT.vi_mode) { 14800f66f451Sopenharmony_ci cx_scr = printf("%s", TT.il->data); 14810f66f451Sopenharmony_ci cy_scr = TT.screen_height; 14820f66f451Sopenharmony_ci *toybuf = 0; 14830f66f451Sopenharmony_ci } else { 14840f66f451Sopenharmony_ci // TODO: the row,col display doesn't show the cursor column 14850f66f451Sopenharmony_ci // TODO: real vi shows the percentage by lines, not bytes 14860f66f451Sopenharmony_ci sprintf(toybuf, "%zu/%zuC %zu%% %d,%d", TT.cursor, TT.filesize, 14870f66f451Sopenharmony_ci (100*TT.cursor)/(TT.filesize ? : 1), TT.cur_row+1, TT.cur_col+1); 14880f66f451Sopenharmony_ci if (TT.cur_col != cx_scr) sprintf(toybuf+strlen(toybuf),"-%d", cx_scr+1); 14890f66f451Sopenharmony_ci } 14900f66f451Sopenharmony_ci tty_jump(TT.screen_width-strlen(toybuf), TT.screen_height); 14910f66f451Sopenharmony_ci printf("%s", toybuf); 14920f66f451Sopenharmony_ci 14930f66f451Sopenharmony_ci tty_jump(cx_scr, cy_scr); 14940f66f451Sopenharmony_ci xflush(1); 14950f66f451Sopenharmony_ci} 14960f66f451Sopenharmony_ci 14970f66f451Sopenharmony_civoid vi_main(void) 14980f66f451Sopenharmony_ci{ 14990f66f451Sopenharmony_ci char stdout_buf[8192]; 15000f66f451Sopenharmony_ci char keybuf[16] = {0}; 15010f66f451Sopenharmony_ci char vi_buf[16] = {0}; 15020f66f451Sopenharmony_ci char utf8_code[8] = {0}; 15030f66f451Sopenharmony_ci int utf8_dec_p = 0, vi_buf_pos = 0; 15040f66f451Sopenharmony_ci FILE *script = FLAG(s) ? xfopen(TT.s, "r") : 0; 15050f66f451Sopenharmony_ci 15060f66f451Sopenharmony_ci TT.il = xzalloc(sizeof(struct str_line)); 15070f66f451Sopenharmony_ci TT.il->data = xzalloc(80); 15080f66f451Sopenharmony_ci TT.yank.data = xzalloc(128); 15090f66f451Sopenharmony_ci 15100f66f451Sopenharmony_ci TT.il->alloc = 80, TT.yank.alloc = 128; 15110f66f451Sopenharmony_ci 15120f66f451Sopenharmony_ci linelist_load(0); 15130f66f451Sopenharmony_ci 15140f66f451Sopenharmony_ci TT.vi_mov_flag = 0x20000000; 15150f66f451Sopenharmony_ci TT.vi_mode = 1, TT.tabstop = 8; 15160f66f451Sopenharmony_ci 15170f66f451Sopenharmony_ci TT.screen_width = 80, TT.screen_height = 24; 15180f66f451Sopenharmony_ci terminal_size(&TT.screen_width, &TT.screen_height); 15190f66f451Sopenharmony_ci TT.screen_height -= 1; 15200f66f451Sopenharmony_ci 15210f66f451Sopenharmony_ci // Avoid flicker. 15220f66f451Sopenharmony_ci setbuffer(stdout, stdout_buf, sizeof(stdout_buf)); 15230f66f451Sopenharmony_ci 15240f66f451Sopenharmony_ci xsignal(SIGWINCH, generic_signal); 15250f66f451Sopenharmony_ci set_terminal(0, 1, 0, 0); 15260f66f451Sopenharmony_ci //writes stdout into different xterm buffer so when we exit 15270f66f451Sopenharmony_ci //we dont get scroll log full of junk 15280f66f451Sopenharmony_ci tty_esc("?1049h"); 15290f66f451Sopenharmony_ci 15300f66f451Sopenharmony_ci for (;;) { 15310f66f451Sopenharmony_ci int key = 0; 15320f66f451Sopenharmony_ci 15330f66f451Sopenharmony_ci draw_page(); 15340f66f451Sopenharmony_ci if (script) { 15350f66f451Sopenharmony_ci key = fgetc(script); 15360f66f451Sopenharmony_ci if (key == EOF) { 15370f66f451Sopenharmony_ci fclose(script); 15380f66f451Sopenharmony_ci script = 0; 15390f66f451Sopenharmony_ci key = scan_key(keybuf, -1); 15400f66f451Sopenharmony_ci } 15410f66f451Sopenharmony_ci } else key = scan_key(keybuf, -1); 15420f66f451Sopenharmony_ci 15430f66f451Sopenharmony_ci if (key == -1) goto cleanup_vi; 15440f66f451Sopenharmony_ci else if (key == -3) { 15450f66f451Sopenharmony_ci toys.signal = 0; 15460f66f451Sopenharmony_ci terminal_size(&TT.screen_width, &TT.screen_height); 15470f66f451Sopenharmony_ci TT.screen_height -= 1; //TODO this is hack fix visual alignment 15480f66f451Sopenharmony_ci continue; 15490f66f451Sopenharmony_ci } 15500f66f451Sopenharmony_ci 15510f66f451Sopenharmony_ci // TODO: support cursor keys in ex mode too. 15520f66f451Sopenharmony_ci if (TT.vi_mode && key>=256) { 15530f66f451Sopenharmony_ci key -= 256; 15540f66f451Sopenharmony_ci if (key==KEY_UP) cur_up(1, 1, 0); 15550f66f451Sopenharmony_ci else if (key==KEY_DOWN) cur_down(1, 1, 0); 15560f66f451Sopenharmony_ci else if (key==KEY_LEFT) cur_left(1, 1, 0); 15570f66f451Sopenharmony_ci else if (key==KEY_RIGHT) cur_right(1, 1, 0); 15580f66f451Sopenharmony_ci else if (key==KEY_HOME) vi_zero(1, 1, 0); 15590f66f451Sopenharmony_ci else if (key==KEY_END) vi_dollar(1, 1, 0); 15600f66f451Sopenharmony_ci else if (key==KEY_PGDN) ctrl_f(); 15610f66f451Sopenharmony_ci else if (key==KEY_PGUP) ctrl_b(); 15620f66f451Sopenharmony_ci continue; 15630f66f451Sopenharmony_ci } 15640f66f451Sopenharmony_ci 15650f66f451Sopenharmony_ci if (TT.vi_mode == 1) { //NORMAL 15660f66f451Sopenharmony_ci switch (key) { 15670f66f451Sopenharmony_ci case '/': 15680f66f451Sopenharmony_ci case '?': 15690f66f451Sopenharmony_ci case ':': 15700f66f451Sopenharmony_ci TT.vi_mode = 0; 15710f66f451Sopenharmony_ci TT.il->data[0]=key; 15720f66f451Sopenharmony_ci TT.il->len++; 15730f66f451Sopenharmony_ci break; 15740f66f451Sopenharmony_ci case 'A': 15750f66f451Sopenharmony_ci vi_eol(); 15760f66f451Sopenharmony_ci TT.vi_mode = 2; 15770f66f451Sopenharmony_ci break; 15780f66f451Sopenharmony_ci case 'a': 15790f66f451Sopenharmony_ci cur_right(1, 1, 0); 15800f66f451Sopenharmony_ci // FALLTHROUGH 15810f66f451Sopenharmony_ci case 'i': 15820f66f451Sopenharmony_ci TT.vi_mode = 2; 15830f66f451Sopenharmony_ci break; 15840f66f451Sopenharmony_ci case 'B'-'@': 15850f66f451Sopenharmony_ci ctrl_b(); 15860f66f451Sopenharmony_ci break; 15870f66f451Sopenharmony_ci case 'E'-'@': 15880f66f451Sopenharmony_ci ctrl_e(); 15890f66f451Sopenharmony_ci break; 15900f66f451Sopenharmony_ci case 'F'-'@': 15910f66f451Sopenharmony_ci ctrl_f(); 15920f66f451Sopenharmony_ci break; 15930f66f451Sopenharmony_ci case 'Y'-'@': 15940f66f451Sopenharmony_ci ctrl_y(); 15950f66f451Sopenharmony_ci break; 15960f66f451Sopenharmony_ci case 27: 15970f66f451Sopenharmony_ci vi_buf[0] = 0; 15980f66f451Sopenharmony_ci vi_buf_pos = 0; 15990f66f451Sopenharmony_ci break; 16000f66f451Sopenharmony_ci default: 16010f66f451Sopenharmony_ci if (key > 0x20 && key < 0x7B) { 16020f66f451Sopenharmony_ci vi_buf[vi_buf_pos] = key;//TODO handle input better 16030f66f451Sopenharmony_ci vi_buf_pos++; 16040f66f451Sopenharmony_ci if (run_vi_cmd(vi_buf)) { 16050f66f451Sopenharmony_ci memset(vi_buf, 0, 16); 16060f66f451Sopenharmony_ci vi_buf_pos = 0; 16070f66f451Sopenharmony_ci } 16080f66f451Sopenharmony_ci else if (vi_buf_pos == 16) { 16090f66f451Sopenharmony_ci vi_buf_pos = 0; 16100f66f451Sopenharmony_ci memset(vi_buf, 0, 16); 16110f66f451Sopenharmony_ci } 16120f66f451Sopenharmony_ci 16130f66f451Sopenharmony_ci } 16140f66f451Sopenharmony_ci 16150f66f451Sopenharmony_ci break; 16160f66f451Sopenharmony_ci } 16170f66f451Sopenharmony_ci } else if (TT.vi_mode == 0) { //EX MODE 16180f66f451Sopenharmony_ci switch (key) { 16190f66f451Sopenharmony_ci case 0x7F: 16200f66f451Sopenharmony_ci case 0x08: 16210f66f451Sopenharmony_ci if (TT.il->len > 1) { 16220f66f451Sopenharmony_ci TT.il->data[--TT.il->len] = 0; 16230f66f451Sopenharmony_ci break; 16240f66f451Sopenharmony_ci } 16250f66f451Sopenharmony_ci // FALLTHROUGH 16260f66f451Sopenharmony_ci case 27: 16270f66f451Sopenharmony_ci TT.vi_mode = 1; 16280f66f451Sopenharmony_ci TT.il->len = 0; 16290f66f451Sopenharmony_ci memset(TT.il->data, 0, TT.il->alloc); 16300f66f451Sopenharmony_ci break; 16310f66f451Sopenharmony_ci case 0x0A: 16320f66f451Sopenharmony_ci case 0x0D: 16330f66f451Sopenharmony_ci if (run_ex_cmd(TT.il->data) == -1) 16340f66f451Sopenharmony_ci goto cleanup_vi; 16350f66f451Sopenharmony_ci TT.vi_mode = 1; 16360f66f451Sopenharmony_ci TT.il->len = 0; 16370f66f451Sopenharmony_ci memset(TT.il->data, 0, TT.il->alloc); 16380f66f451Sopenharmony_ci break; 16390f66f451Sopenharmony_ci default: //add chars to ex command until ENTER 16400f66f451Sopenharmony_ci if (key >= 0x20 && key < 0x7F) { //might be utf? 16410f66f451Sopenharmony_ci if (TT.il->len == TT.il->alloc) { 16420f66f451Sopenharmony_ci TT.il->data = realloc(TT.il->data, TT.il->alloc*2); 16430f66f451Sopenharmony_ci TT.il->alloc *= 2; 16440f66f451Sopenharmony_ci } 16450f66f451Sopenharmony_ci TT.il->data[TT.il->len] = key; 16460f66f451Sopenharmony_ci TT.il->len++; 16470f66f451Sopenharmony_ci } 16480f66f451Sopenharmony_ci break; 16490f66f451Sopenharmony_ci } 16500f66f451Sopenharmony_ci } else if (TT.vi_mode == 2) {//INSERT MODE 16510f66f451Sopenharmony_ci switch (key) { 16520f66f451Sopenharmony_ci case 27: 16530f66f451Sopenharmony_ci i_insert(TT.il->data, TT.il->len); 16540f66f451Sopenharmony_ci cur_left(1, 1, 0); 16550f66f451Sopenharmony_ci TT.vi_mode = 1; 16560f66f451Sopenharmony_ci TT.il->len = 0; 16570f66f451Sopenharmony_ci memset(TT.il->data, 0, TT.il->alloc); 16580f66f451Sopenharmony_ci break; 16590f66f451Sopenharmony_ci case 0x7F: 16600f66f451Sopenharmony_ci case 0x08: 16610f66f451Sopenharmony_ci if (TT.il->len) { 16620f66f451Sopenharmony_ci char *last = utf8_last(TT.il->data, TT.il->len); 16630f66f451Sopenharmony_ci int shrink = strlen(last); 16640f66f451Sopenharmony_ci memset(last, 0, shrink); 16650f66f451Sopenharmony_ci TT.il->len -= shrink; 16660f66f451Sopenharmony_ci } 16670f66f451Sopenharmony_ci break; 16680f66f451Sopenharmony_ci case 0x0A: 16690f66f451Sopenharmony_ci case 0x0D: 16700f66f451Sopenharmony_ci //insert newline 16710f66f451Sopenharmony_ci // 16720f66f451Sopenharmony_ci TT.il->data[TT.il->len++] = '\n'; 16730f66f451Sopenharmony_ci i_insert(TT.il->data, TT.il->len); 16740f66f451Sopenharmony_ci TT.il->len = 0; 16750f66f451Sopenharmony_ci memset(TT.il->data, 0, TT.il->alloc); 16760f66f451Sopenharmony_ci break; 16770f66f451Sopenharmony_ci default: 16780f66f451Sopenharmony_ci if ((key >= 0x20 || key == 0x09) && 16790f66f451Sopenharmony_ci utf8_dec(key, utf8_code, &utf8_dec_p)) { 16800f66f451Sopenharmony_ci 16810f66f451Sopenharmony_ci if (TT.il->len+utf8_dec_p+1 >= TT.il->alloc) { 16820f66f451Sopenharmony_ci TT.il->data = realloc(TT.il->data, TT.il->alloc*2); 16830f66f451Sopenharmony_ci TT.il->alloc *= 2; 16840f66f451Sopenharmony_ci } 16850f66f451Sopenharmony_ci strcpy(TT.il->data+TT.il->len, utf8_code); 16860f66f451Sopenharmony_ci TT.il->len += utf8_dec_p; 16870f66f451Sopenharmony_ci utf8_dec_p = 0; 16880f66f451Sopenharmony_ci *utf8_code = 0; 16890f66f451Sopenharmony_ci 16900f66f451Sopenharmony_ci } 16910f66f451Sopenharmony_ci break; 16920f66f451Sopenharmony_ci } 16930f66f451Sopenharmony_ci } 16940f66f451Sopenharmony_ci } 16950f66f451Sopenharmony_cicleanup_vi: 16960f66f451Sopenharmony_ci linelist_unload(); 16970f66f451Sopenharmony_ci free(TT.il->data), free(TT.il), free(TT.yank.data); 16980f66f451Sopenharmony_ci tty_reset(); 16990f66f451Sopenharmony_ci tty_esc("?1049l"); 17000f66f451Sopenharmony_ci} 1701