1*cf5a6c84SAndroid Build Coastguard Worker /* vi.c - You can't spell "evil" without "vi".
2*cf5a6c84SAndroid Build Coastguard Worker *
3*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2015 Rob Landley <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2019 Jarno Mäkipää <[email protected]>
5*cf5a6c84SAndroid Build Coastguard Worker *
6*cf5a6c84SAndroid Build Coastguard Worker * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/vi.html
7*cf5a6c84SAndroid Build Coastguard Worker
8*cf5a6c84SAndroid Build Coastguard Worker USE_VI(NEWTOY(vi, ">1s:c:", TOYFLAG_USR|TOYFLAG_BIN))
9*cf5a6c84SAndroid Build Coastguard Worker
10*cf5a6c84SAndroid Build Coastguard Worker config VI
11*cf5a6c84SAndroid Build Coastguard Worker bool "vi"
12*cf5a6c84SAndroid Build Coastguard Worker default n
13*cf5a6c84SAndroid Build Coastguard Worker help
14*cf5a6c84SAndroid Build Coastguard Worker usage: vi [-s SCRIPT] FILE
15*cf5a6c84SAndroid Build Coastguard Worker
16*cf5a6c84SAndroid Build Coastguard Worker Visual text editor. Predates keyboards with standardized cursor keys.
17*cf5a6c84SAndroid Build Coastguard Worker If you don't know how to use it, hit the ESC key, type :q! and press ENTER.
18*cf5a6c84SAndroid Build Coastguard Worker
19*cf5a6c84SAndroid Build Coastguard Worker -s run SCRIPT as if typed at keyboard (like -c "source SCRIPT")
20*cf5a6c84SAndroid Build Coastguard Worker -c run SCRIPT of ex commands
21*cf5a6c84SAndroid Build Coastguard Worker
22*cf5a6c84SAndroid Build Coastguard Worker The editor is usually in one of three modes:
23*cf5a6c84SAndroid Build Coastguard Worker
24*cf5a6c84SAndroid Build Coastguard Worker Hit ESC for "vi mode" where each key is a command.
25*cf5a6c84SAndroid Build Coastguard Worker Hit : for "ex mode" which runs command lines typed at bottom of screen.
26*cf5a6c84SAndroid Build Coastguard Worker Hit i (from vi mode) for "insert mode" where typing adds to the file.
27*cf5a6c84SAndroid Build Coastguard Worker
28*cf5a6c84SAndroid Build Coastguard Worker ex mode commands (ESC to exit ex mode):
29*cf5a6c84SAndroid Build Coastguard Worker
30*cf5a6c84SAndroid Build Coastguard Worker q Quit (exit editor if no unsaved changes)
31*cf5a6c84SAndroid Build Coastguard Worker q! Quit discarding unsaved changes
32*cf5a6c84SAndroid Build Coastguard Worker w Write changed contents to file (optionally to NAME argument)
33*cf5a6c84SAndroid Build Coastguard Worker wq Write to file, then quit
34*cf5a6c84SAndroid Build Coastguard Worker
35*cf5a6c84SAndroid Build Coastguard Worker vi mode single key commands:
36*cf5a6c84SAndroid Build Coastguard Worker i switch to insert mode (until next ESC)
37*cf5a6c84SAndroid Build Coastguard Worker u undo last change (can be repeated)
38*cf5a6c84SAndroid Build Coastguard Worker a append (move one character right, switch to insert mode)
39*cf5a6c84SAndroid Build Coastguard Worker A append (jump to end of line, switch to insert mode)
40*cf5a6c84SAndroid Build Coastguard Worker
41*cf5a6c84SAndroid Build Coastguard Worker vi mode commands that prompt for more data on bottom line:
42*cf5a6c84SAndroid Build Coastguard Worker : switch to ex mode
43*cf5a6c84SAndroid Build Coastguard Worker / search forwards for regex
44*cf5a6c84SAndroid Build Coastguard Worker ? search backwards for regex
45*cf5a6c84SAndroid Build Coastguard Worker . repeat last command
46*cf5a6c84SAndroid Build Coastguard Worker
47*cf5a6c84SAndroid Build Coastguard Worker [count][cmd][motion]
48*cf5a6c84SAndroid Build Coastguard Worker cmd: c d y
49*cf5a6c84SAndroid Build Coastguard Worker motion: 0 b e G H h j k L l M w $ f F
50*cf5a6c84SAndroid Build Coastguard Worker
51*cf5a6c84SAndroid Build Coastguard Worker [count][cmd]
52*cf5a6c84SAndroid Build Coastguard Worker cmd: D I J O n o p x dd yy
53*cf5a6c84SAndroid Build Coastguard Worker
54*cf5a6c84SAndroid Build Coastguard Worker [cmd]
55*cf5a6c84SAndroid Build Coastguard Worker cmd: / ? : A a i CTRL_D CTRL_B CTRL_E CTRL_F CTRL_Y \e \b
56*cf5a6c84SAndroid Build Coastguard Worker
57*cf5a6c84SAndroid Build Coastguard Worker [cmd]
58*cf5a6c84SAndroid Build Coastguard Worker \b \e \n 'set list' 'set nolist' d $ % g v
59*cf5a6c84SAndroid Build Coastguard Worker */
60*cf5a6c84SAndroid Build Coastguard Worker #define FOR_vi
61*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
62*cf5a6c84SAndroid Build Coastguard Worker #define CTL(a) a-'@'
63*cf5a6c84SAndroid Build Coastguard Worker
64*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
65*cf5a6c84SAndroid Build Coastguard Worker char *c, *s;
66*cf5a6c84SAndroid Build Coastguard Worker
67*cf5a6c84SAndroid Build Coastguard Worker char *filename;
68*cf5a6c84SAndroid Build Coastguard Worker int vi_mode, tabstop, list, cur_col, cur_row, scr_row, drawn_row, drawn_col,
69*cf5a6c84SAndroid Build Coastguard Worker count0, count1, vi_mov_flag;
70*cf5a6c84SAndroid Build Coastguard Worker unsigned screen_height, screen_width;
71*cf5a6c84SAndroid Build Coastguard Worker char vi_reg, *last_search;
72*cf5a6c84SAndroid Build Coastguard Worker struct str_line {
73*cf5a6c84SAndroid Build Coastguard Worker int alloc, len;
74*cf5a6c84SAndroid Build Coastguard Worker char *data;
75*cf5a6c84SAndroid Build Coastguard Worker } *il;
76*cf5a6c84SAndroid Build Coastguard Worker size_t screen, cursor; //offsets
77*cf5a6c84SAndroid Build Coastguard Worker //yank buffer
78*cf5a6c84SAndroid Build Coastguard Worker struct yank_buf {
79*cf5a6c84SAndroid Build Coastguard Worker char reg;
80*cf5a6c84SAndroid Build Coastguard Worker int alloc;
81*cf5a6c84SAndroid Build Coastguard Worker char *data;
82*cf5a6c84SAndroid Build Coastguard Worker } yank;
83*cf5a6c84SAndroid Build Coastguard Worker
84*cf5a6c84SAndroid Build Coastguard Worker size_t filesize;
85*cf5a6c84SAndroid Build Coastguard Worker // mem_block contains RO data that is either original file as mmap
86*cf5a6c84SAndroid Build Coastguard Worker // or heap allocated inserted data
87*cf5a6c84SAndroid Build Coastguard Worker struct block_list {
88*cf5a6c84SAndroid Build Coastguard Worker struct block_list *next, *prev;
89*cf5a6c84SAndroid Build Coastguard Worker struct mem_block {
90*cf5a6c84SAndroid Build Coastguard Worker size_t size, len;
91*cf5a6c84SAndroid Build Coastguard Worker enum alloc_flag {
92*cf5a6c84SAndroid Build Coastguard Worker MMAP, //can be munmap() before exit()
93*cf5a6c84SAndroid Build Coastguard Worker HEAP, //can be free() before exit()
94*cf5a6c84SAndroid Build Coastguard Worker STACK, //global or stack perhaps toybuf
95*cf5a6c84SAndroid Build Coastguard Worker } alloc;
96*cf5a6c84SAndroid Build Coastguard Worker const char *data;
97*cf5a6c84SAndroid Build Coastguard Worker } *node;
98*cf5a6c84SAndroid Build Coastguard Worker } *text;
99*cf5a6c84SAndroid Build Coastguard Worker
100*cf5a6c84SAndroid Build Coastguard Worker // slices do not contain actual allocated data but slices of data in mem_block
101*cf5a6c84SAndroid Build Coastguard Worker // when file is first opened it has only one slice.
102*cf5a6c84SAndroid Build Coastguard Worker // after inserting data into middle new mem_block is allocated for insert data
103*cf5a6c84SAndroid Build Coastguard Worker // and 3 slices are created, where first and last slice are pointing to original
104*cf5a6c84SAndroid Build Coastguard Worker // mem_block with offsets, and middle slice is pointing to newly allocated block
105*cf5a6c84SAndroid Build Coastguard Worker // When deleting, data is not freed but mem_blocks are sliced more such way that
106*cf5a6c84SAndroid Build Coastguard Worker // deleted data left between 2 slices
107*cf5a6c84SAndroid Build Coastguard Worker struct slice_list {
108*cf5a6c84SAndroid Build Coastguard Worker struct slice_list *next, *prev;
109*cf5a6c84SAndroid Build Coastguard Worker struct slice {
110*cf5a6c84SAndroid Build Coastguard Worker size_t len;
111*cf5a6c84SAndroid Build Coastguard Worker const char *data;
112*cf5a6c84SAndroid Build Coastguard Worker } *node;
113*cf5a6c84SAndroid Build Coastguard Worker } *slices;
114*cf5a6c84SAndroid Build Coastguard Worker )
115*cf5a6c84SAndroid Build Coastguard Worker
116*cf5a6c84SAndroid Build Coastguard Worker static const char *blank = " \n\r\t";
117*cf5a6c84SAndroid Build Coastguard Worker static const char *specials = ",.:;=-+*/(){}<>[]!@#$%^&|\\?\"\'";
118*cf5a6c84SAndroid Build Coastguard Worker
119*cf5a6c84SAndroid Build Coastguard Worker //get utf8 length and width at same time
utf8_lnw(int * width,char * s,int bytes)120*cf5a6c84SAndroid Build Coastguard Worker static int utf8_lnw(int *width, char *s, int bytes)
121*cf5a6c84SAndroid Build Coastguard Worker {
122*cf5a6c84SAndroid Build Coastguard Worker unsigned wc;
123*cf5a6c84SAndroid Build Coastguard Worker int length = 1;
124*cf5a6c84SAndroid Build Coastguard Worker
125*cf5a6c84SAndroid Build Coastguard Worker if (*s == '\t') *width = TT.tabstop;
126*cf5a6c84SAndroid Build Coastguard Worker else {
127*cf5a6c84SAndroid Build Coastguard Worker length = utf8towc(&wc, s, bytes);
128*cf5a6c84SAndroid Build Coastguard Worker if (length < 1) length = 0, *width = 0;
129*cf5a6c84SAndroid Build Coastguard Worker else *width = wcwidth(wc);
130*cf5a6c84SAndroid Build Coastguard Worker }
131*cf5a6c84SAndroid Build Coastguard Worker return length;
132*cf5a6c84SAndroid Build Coastguard Worker }
133*cf5a6c84SAndroid Build Coastguard Worker
utf8_dec(char key,char * utf8_scratch,int * sta_p)134*cf5a6c84SAndroid Build Coastguard Worker static int utf8_dec(char key, char *utf8_scratch, int *sta_p)
135*cf5a6c84SAndroid Build Coastguard Worker {
136*cf5a6c84SAndroid Build Coastguard Worker int len = 0;
137*cf5a6c84SAndroid Build Coastguard Worker char *c = utf8_scratch;
138*cf5a6c84SAndroid Build Coastguard Worker c[*sta_p] = key;
139*cf5a6c84SAndroid Build Coastguard Worker if (!(*sta_p)) *c = key;
140*cf5a6c84SAndroid Build Coastguard Worker if (*c < 0x7F) return *sta_p = 1;
141*cf5a6c84SAndroid Build Coastguard Worker if ((*c & 0xE0) == 0xc0) len = 2;
142*cf5a6c84SAndroid Build Coastguard Worker else if ((*c & 0xF0) == 0xE0 ) len = 3;
143*cf5a6c84SAndroid Build Coastguard Worker else if ((*c & 0xF8) == 0xF0 ) len = 4;
144*cf5a6c84SAndroid Build Coastguard Worker else return *sta_p = 0;
145*cf5a6c84SAndroid Build Coastguard Worker
146*cf5a6c84SAndroid Build Coastguard Worker if (++*sta_p == 1) return 0;
147*cf5a6c84SAndroid Build Coastguard Worker if ((c[*sta_p-1] & 0xc0) != 0x80) return *sta_p = 0;
148*cf5a6c84SAndroid Build Coastguard Worker
149*cf5a6c84SAndroid Build Coastguard Worker if (*sta_p == len) return !(c[(*sta_p)] = 0);
150*cf5a6c84SAndroid Build Coastguard Worker
151*cf5a6c84SAndroid Build Coastguard Worker return 0;
152*cf5a6c84SAndroid Build Coastguard Worker }
153*cf5a6c84SAndroid Build Coastguard Worker
utf8_last(char * str,int size)154*cf5a6c84SAndroid Build Coastguard Worker static char* utf8_last(char* str, int size)
155*cf5a6c84SAndroid Build Coastguard Worker {
156*cf5a6c84SAndroid Build Coastguard Worker char *end = str+size;
157*cf5a6c84SAndroid Build Coastguard Worker int pos = size, len, width = 0;
158*cf5a6c84SAndroid Build Coastguard Worker
159*cf5a6c84SAndroid Build Coastguard Worker for (;pos >= 0; end--, pos--) {
160*cf5a6c84SAndroid Build Coastguard Worker len = utf8_lnw(&width, end, size-pos);
161*cf5a6c84SAndroid Build Coastguard Worker if (len && width) return end;
162*cf5a6c84SAndroid Build Coastguard Worker }
163*cf5a6c84SAndroid Build Coastguard Worker return 0;
164*cf5a6c84SAndroid Build Coastguard Worker }
165*cf5a6c84SAndroid Build Coastguard Worker
dlist_add_before(struct double_list ** head,struct double_list ** list,char * data)166*cf5a6c84SAndroid Build Coastguard Worker struct double_list *dlist_add_before(struct double_list **head,
167*cf5a6c84SAndroid Build Coastguard Worker struct double_list **list, char *data)
168*cf5a6c84SAndroid Build Coastguard Worker {
169*cf5a6c84SAndroid Build Coastguard Worker struct double_list *new = xmalloc(sizeof(struct double_list));
170*cf5a6c84SAndroid Build Coastguard Worker new->data = data;
171*cf5a6c84SAndroid Build Coastguard Worker if (*list == *head) *head = new;
172*cf5a6c84SAndroid Build Coastguard Worker
173*cf5a6c84SAndroid Build Coastguard Worker dlist_add_nomalloc(list, new);
174*cf5a6c84SAndroid Build Coastguard Worker return new;
175*cf5a6c84SAndroid Build Coastguard Worker }
176*cf5a6c84SAndroid Build Coastguard Worker
dlist_add_after(struct double_list ** head,struct double_list ** list,char * data)177*cf5a6c84SAndroid Build Coastguard Worker struct double_list *dlist_add_after(struct double_list **head,
178*cf5a6c84SAndroid Build Coastguard Worker struct double_list **list, char *data)
179*cf5a6c84SAndroid Build Coastguard Worker {
180*cf5a6c84SAndroid Build Coastguard Worker struct double_list *new = xmalloc(sizeof(struct double_list));
181*cf5a6c84SAndroid Build Coastguard Worker new->data = data;
182*cf5a6c84SAndroid Build Coastguard Worker
183*cf5a6c84SAndroid Build Coastguard Worker if (*list) {
184*cf5a6c84SAndroid Build Coastguard Worker new->prev = *list;
185*cf5a6c84SAndroid Build Coastguard Worker new->next = (*list)->next;
186*cf5a6c84SAndroid Build Coastguard Worker (*list)->next->prev = new;
187*cf5a6c84SAndroid Build Coastguard Worker (*list)->next = new;
188*cf5a6c84SAndroid Build Coastguard Worker } else *head = *list = new->next = new->prev = new;
189*cf5a6c84SAndroid Build Coastguard Worker return new;
190*cf5a6c84SAndroid Build Coastguard Worker }
191*cf5a6c84SAndroid Build Coastguard Worker
192*cf5a6c84SAndroid Build Coastguard Worker // str must be already allocated
193*cf5a6c84SAndroid Build Coastguard Worker // ownership of allocated data is moved
194*cf5a6c84SAndroid Build Coastguard Worker // data, pre allocated data
195*cf5a6c84SAndroid Build Coastguard Worker // offset, offset in whole text
196*cf5a6c84SAndroid Build Coastguard Worker // size, data allocation size of given data
197*cf5a6c84SAndroid Build Coastguard Worker // len, length of the string
198*cf5a6c84SAndroid Build Coastguard Worker // type, define allocation type for cleanup purposes at app exit
insert_str(const char * data,size_t offset,size_t size,size_t len,enum alloc_flag type)199*cf5a6c84SAndroid Build Coastguard Worker static int insert_str(const char *data, size_t offset, size_t size, size_t len,
200*cf5a6c84SAndroid Build Coastguard Worker enum alloc_flag type)
201*cf5a6c84SAndroid Build Coastguard Worker {
202*cf5a6c84SAndroid Build Coastguard Worker struct mem_block *b = xmalloc(sizeof(struct mem_block));
203*cf5a6c84SAndroid Build Coastguard Worker struct slice *next = xmalloc(sizeof(struct slice));
204*cf5a6c84SAndroid Build Coastguard Worker struct slice_list *s = TT.slices;
205*cf5a6c84SAndroid Build Coastguard Worker
206*cf5a6c84SAndroid Build Coastguard Worker b->size = size;
207*cf5a6c84SAndroid Build Coastguard Worker b->len = len;
208*cf5a6c84SAndroid Build Coastguard Worker b->alloc = type;
209*cf5a6c84SAndroid Build Coastguard Worker b->data = data;
210*cf5a6c84SAndroid Build Coastguard Worker next->len = len;
211*cf5a6c84SAndroid Build Coastguard Worker next->data = data;
212*cf5a6c84SAndroid Build Coastguard Worker
213*cf5a6c84SAndroid Build Coastguard Worker //mem blocks can be just added unordered
214*cf5a6c84SAndroid Build Coastguard Worker TT.text = (struct block_list *)dlist_add((struct double_list **)&TT.text,
215*cf5a6c84SAndroid Build Coastguard Worker (char *)b);
216*cf5a6c84SAndroid Build Coastguard Worker
217*cf5a6c84SAndroid Build Coastguard Worker if (!s) {
218*cf5a6c84SAndroid Build Coastguard Worker TT.slices = (struct slice_list *)dlist_add(
219*cf5a6c84SAndroid Build Coastguard Worker (struct double_list **)&TT.slices,
220*cf5a6c84SAndroid Build Coastguard Worker (char *)next);
221*cf5a6c84SAndroid Build Coastguard Worker } else {
222*cf5a6c84SAndroid Build Coastguard Worker size_t pos = 0;
223*cf5a6c84SAndroid Build Coastguard Worker //search insertation point for slice
224*cf5a6c84SAndroid Build Coastguard Worker do {
225*cf5a6c84SAndroid Build Coastguard Worker if (pos<=offset && pos+s->node->len>offset) break;
226*cf5a6c84SAndroid Build Coastguard Worker pos += s->node->len;
227*cf5a6c84SAndroid Build Coastguard Worker s = s->next;
228*cf5a6c84SAndroid Build Coastguard Worker if (s == TT.slices) return -1; //error out of bounds
229*cf5a6c84SAndroid Build Coastguard Worker } while (1);
230*cf5a6c84SAndroid Build Coastguard Worker //need to cut previous slice into 2 since insert is in middle
231*cf5a6c84SAndroid Build Coastguard Worker if (pos+s->node->len>offset && pos!=offset) {
232*cf5a6c84SAndroid Build Coastguard Worker struct slice *tail = xmalloc(sizeof(struct slice));
233*cf5a6c84SAndroid Build Coastguard Worker tail->len = s->node->len-(offset-pos);
234*cf5a6c84SAndroid Build Coastguard Worker tail->data = s->node->data+(offset-pos);
235*cf5a6c84SAndroid Build Coastguard Worker s->node->len = offset-pos;
236*cf5a6c84SAndroid Build Coastguard Worker //pos = offset;
237*cf5a6c84SAndroid Build Coastguard Worker s = (struct slice_list *)dlist_add_after(
238*cf5a6c84SAndroid Build Coastguard Worker (struct double_list **)&TT.slices,
239*cf5a6c84SAndroid Build Coastguard Worker (struct double_list **)&s,
240*cf5a6c84SAndroid Build Coastguard Worker (char *)tail);
241*cf5a6c84SAndroid Build Coastguard Worker
242*cf5a6c84SAndroid Build Coastguard Worker s = (struct slice_list *)dlist_add_before(
243*cf5a6c84SAndroid Build Coastguard Worker (struct double_list **)&TT.slices,
244*cf5a6c84SAndroid Build Coastguard Worker (struct double_list **)&s,
245*cf5a6c84SAndroid Build Coastguard Worker (char *)next);
246*cf5a6c84SAndroid Build Coastguard Worker } else if (pos==offset) {
247*cf5a6c84SAndroid Build Coastguard Worker // insert before
248*cf5a6c84SAndroid Build Coastguard Worker s = (struct slice_list *)dlist_add_before(
249*cf5a6c84SAndroid Build Coastguard Worker (struct double_list **)&TT.slices,
250*cf5a6c84SAndroid Build Coastguard Worker (struct double_list **)&s,
251*cf5a6c84SAndroid Build Coastguard Worker (char *)next);
252*cf5a6c84SAndroid Build Coastguard Worker } else {
253*cf5a6c84SAndroid Build Coastguard Worker // insert after
254*cf5a6c84SAndroid Build Coastguard Worker s = (void *)dlist_add_after((void *)&TT.slices, (void *)&s, (void *)next);
255*cf5a6c84SAndroid Build Coastguard Worker }
256*cf5a6c84SAndroid Build Coastguard Worker }
257*cf5a6c84SAndroid Build Coastguard Worker return 0;
258*cf5a6c84SAndroid Build Coastguard Worker }
259*cf5a6c84SAndroid Build Coastguard Worker
260*cf5a6c84SAndroid Build Coastguard Worker // this will not free any memory
261*cf5a6c84SAndroid Build Coastguard Worker // will only create more slices depending on position
cut_str(size_t offset,size_t len)262*cf5a6c84SAndroid Build Coastguard Worker static int cut_str(size_t offset, size_t len)
263*cf5a6c84SAndroid Build Coastguard Worker {
264*cf5a6c84SAndroid Build Coastguard Worker struct slice_list *e, *s = TT.slices;
265*cf5a6c84SAndroid Build Coastguard Worker size_t end = offset+len;
266*cf5a6c84SAndroid Build Coastguard Worker size_t epos, spos = 0;
267*cf5a6c84SAndroid Build Coastguard Worker
268*cf5a6c84SAndroid Build Coastguard Worker if (!s) return -1;
269*cf5a6c84SAndroid Build Coastguard Worker
270*cf5a6c84SAndroid Build Coastguard Worker //find start and end slices
271*cf5a6c84SAndroid Build Coastguard Worker for (;;) {
272*cf5a6c84SAndroid Build Coastguard Worker if (spos<=offset && spos+s->node->len>offset) break;
273*cf5a6c84SAndroid Build Coastguard Worker spos += s->node->len;
274*cf5a6c84SAndroid Build Coastguard Worker s = s->next;
275*cf5a6c84SAndroid Build Coastguard Worker
276*cf5a6c84SAndroid Build Coastguard Worker if (s == TT.slices) return -1; //error out of bounds
277*cf5a6c84SAndroid Build Coastguard Worker }
278*cf5a6c84SAndroid Build Coastguard Worker
279*cf5a6c84SAndroid Build Coastguard Worker for (e = s, epos = spos; ; ) {
280*cf5a6c84SAndroid Build Coastguard Worker if (epos<=end && epos+e->node->len>end) break;
281*cf5a6c84SAndroid Build Coastguard Worker epos += e->node->len;
282*cf5a6c84SAndroid Build Coastguard Worker e = e->next;
283*cf5a6c84SAndroid Build Coastguard Worker
284*cf5a6c84SAndroid Build Coastguard Worker if (e == TT.slices) return -1; //error out of bounds
285*cf5a6c84SAndroid Build Coastguard Worker }
286*cf5a6c84SAndroid Build Coastguard Worker
287*cf5a6c84SAndroid Build Coastguard Worker for (;;) {
288*cf5a6c84SAndroid Build Coastguard Worker if (spos == offset && ( end >= spos+s->node->len)) {
289*cf5a6c84SAndroid Build Coastguard Worker //cut full
290*cf5a6c84SAndroid Build Coastguard Worker spos += s->node->len;
291*cf5a6c84SAndroid Build Coastguard Worker offset += s->node->len;
292*cf5a6c84SAndroid Build Coastguard Worker s = dlist_pop(&s);
293*cf5a6c84SAndroid Build Coastguard Worker if (s == TT.slices) TT.slices = s->next;
294*cf5a6c84SAndroid Build Coastguard Worker
295*cf5a6c84SAndroid Build Coastguard Worker } else if (spos < offset && ( end >= spos+s->node->len)) {
296*cf5a6c84SAndroid Build Coastguard Worker //cut end
297*cf5a6c84SAndroid Build Coastguard Worker size_t clip = s->node->len - (offset - spos);
298*cf5a6c84SAndroid Build Coastguard Worker offset = spos+s->node->len;
299*cf5a6c84SAndroid Build Coastguard Worker spos += s->node->len;
300*cf5a6c84SAndroid Build Coastguard Worker s->node->len -= clip;
301*cf5a6c84SAndroid Build Coastguard Worker } else if (spos == offset && s == e) {
302*cf5a6c84SAndroid Build Coastguard Worker //cut begin
303*cf5a6c84SAndroid Build Coastguard Worker size_t clip = end - offset;
304*cf5a6c84SAndroid Build Coastguard Worker s->node->len -= clip;
305*cf5a6c84SAndroid Build Coastguard Worker s->node->data += clip;
306*cf5a6c84SAndroid Build Coastguard Worker break;
307*cf5a6c84SAndroid Build Coastguard Worker } else {
308*cf5a6c84SAndroid Build Coastguard Worker //cut middle
309*cf5a6c84SAndroid Build Coastguard Worker struct slice *tail = xmalloc(sizeof(struct slice));
310*cf5a6c84SAndroid Build Coastguard Worker size_t clip = end-offset;
311*cf5a6c84SAndroid Build Coastguard Worker tail->len = s->node->len-(offset-spos)-clip;
312*cf5a6c84SAndroid Build Coastguard Worker tail->data = s->node->data+(offset-spos)+clip;
313*cf5a6c84SAndroid Build Coastguard Worker s->node->len = offset-spos; //wrong?
314*cf5a6c84SAndroid Build Coastguard Worker s = (struct slice_list *)dlist_add_after(
315*cf5a6c84SAndroid Build Coastguard Worker (struct double_list **)&TT.slices,
316*cf5a6c84SAndroid Build Coastguard Worker (struct double_list **)&s,
317*cf5a6c84SAndroid Build Coastguard Worker (char *)tail);
318*cf5a6c84SAndroid Build Coastguard Worker break;
319*cf5a6c84SAndroid Build Coastguard Worker }
320*cf5a6c84SAndroid Build Coastguard Worker if (s == e) break;
321*cf5a6c84SAndroid Build Coastguard Worker
322*cf5a6c84SAndroid Build Coastguard Worker s = s->next;
323*cf5a6c84SAndroid Build Coastguard Worker }
324*cf5a6c84SAndroid Build Coastguard Worker
325*cf5a6c84SAndroid Build Coastguard Worker return 0;
326*cf5a6c84SAndroid Build Coastguard Worker }
modified()327*cf5a6c84SAndroid Build Coastguard Worker static int modified()
328*cf5a6c84SAndroid Build Coastguard Worker {
329*cf5a6c84SAndroid Build Coastguard Worker if (TT.text->next != TT.text->prev) return 1;
330*cf5a6c84SAndroid Build Coastguard Worker if (TT.slices->next != TT.slices->prev) return 1;
331*cf5a6c84SAndroid Build Coastguard Worker if (!TT.text || !TT.slices) return 0;
332*cf5a6c84SAndroid Build Coastguard Worker if (!TT.text->node || !TT.slices->node) return 0;
333*cf5a6c84SAndroid Build Coastguard Worker if (TT.text->node->alloc != MMAP) return 1;
334*cf5a6c84SAndroid Build Coastguard Worker if (TT.text->node->len != TT.slices->node->len) return 1;
335*cf5a6c84SAndroid Build Coastguard Worker if (!TT.text->node->len) return 1;
336*cf5a6c84SAndroid Build Coastguard Worker return 0;
337*cf5a6c84SAndroid Build Coastguard Worker }
338*cf5a6c84SAndroid Build Coastguard Worker
339*cf5a6c84SAndroid Build Coastguard Worker //find offset position in slices
slice_offset(size_t * start,size_t offset)340*cf5a6c84SAndroid Build Coastguard Worker static struct slice_list *slice_offset(size_t *start, size_t offset)
341*cf5a6c84SAndroid Build Coastguard Worker {
342*cf5a6c84SAndroid Build Coastguard Worker struct slice_list *s = TT.slices;
343*cf5a6c84SAndroid Build Coastguard Worker size_t spos = 0;
344*cf5a6c84SAndroid Build Coastguard Worker
345*cf5a6c84SAndroid Build Coastguard Worker //find start
346*cf5a6c84SAndroid Build Coastguard Worker for ( ;s ; ) {
347*cf5a6c84SAndroid Build Coastguard Worker if (spos<=offset && spos+s->node->len>offset) break;
348*cf5a6c84SAndroid Build Coastguard Worker
349*cf5a6c84SAndroid Build Coastguard Worker spos += s->node->len;
350*cf5a6c84SAndroid Build Coastguard Worker s = s->next;
351*cf5a6c84SAndroid Build Coastguard Worker
352*cf5a6c84SAndroid Build Coastguard Worker if (s == TT.slices) s = 0; //error out of bounds
353*cf5a6c84SAndroid Build Coastguard Worker }
354*cf5a6c84SAndroid Build Coastguard Worker if (s) *start = spos;
355*cf5a6c84SAndroid Build Coastguard Worker return s;
356*cf5a6c84SAndroid Build Coastguard Worker }
357*cf5a6c84SAndroid Build Coastguard Worker
text_strchr(size_t offset,char c)358*cf5a6c84SAndroid Build Coastguard Worker static size_t text_strchr(size_t offset, char c)
359*cf5a6c84SAndroid Build Coastguard Worker {
360*cf5a6c84SAndroid Build Coastguard Worker struct slice_list *s = TT.slices;
361*cf5a6c84SAndroid Build Coastguard Worker size_t epos, spos = 0;
362*cf5a6c84SAndroid Build Coastguard Worker int i = 0;
363*cf5a6c84SAndroid Build Coastguard Worker
364*cf5a6c84SAndroid Build Coastguard Worker //find start
365*cf5a6c84SAndroid Build Coastguard Worker if (!(s = slice_offset(&spos, offset))) return SIZE_MAX;
366*cf5a6c84SAndroid Build Coastguard Worker
367*cf5a6c84SAndroid Build Coastguard Worker i = offset-spos;
368*cf5a6c84SAndroid Build Coastguard Worker epos = spos+i;
369*cf5a6c84SAndroid Build Coastguard Worker do {
370*cf5a6c84SAndroid Build Coastguard Worker for (; i < s->node->len; i++, epos++)
371*cf5a6c84SAndroid Build Coastguard Worker if (s->node->data[i] == c) return epos;
372*cf5a6c84SAndroid Build Coastguard Worker s = s->next;
373*cf5a6c84SAndroid Build Coastguard Worker i = 0;
374*cf5a6c84SAndroid Build Coastguard Worker } while (s != TT.slices);
375*cf5a6c84SAndroid Build Coastguard Worker
376*cf5a6c84SAndroid Build Coastguard Worker return SIZE_MAX;
377*cf5a6c84SAndroid Build Coastguard Worker }
378*cf5a6c84SAndroid Build Coastguard Worker
text_strrchr(size_t offset,char c)379*cf5a6c84SAndroid Build Coastguard Worker static size_t text_strrchr(size_t offset, char c)
380*cf5a6c84SAndroid Build Coastguard Worker {
381*cf5a6c84SAndroid Build Coastguard Worker struct slice_list *s = TT.slices;
382*cf5a6c84SAndroid Build Coastguard Worker size_t epos, spos = 0;
383*cf5a6c84SAndroid Build Coastguard Worker int i = 0;
384*cf5a6c84SAndroid Build Coastguard Worker
385*cf5a6c84SAndroid Build Coastguard Worker //find start
386*cf5a6c84SAndroid Build Coastguard Worker if (!(s = slice_offset(&spos, offset))) return SIZE_MAX;
387*cf5a6c84SAndroid Build Coastguard Worker
388*cf5a6c84SAndroid Build Coastguard Worker i = offset-spos;
389*cf5a6c84SAndroid Build Coastguard Worker epos = spos+i;
390*cf5a6c84SAndroid Build Coastguard Worker do {
391*cf5a6c84SAndroid Build Coastguard Worker for (; i >= 0; i--, epos--)
392*cf5a6c84SAndroid Build Coastguard Worker if (s->node->data[i] == c) return epos;
393*cf5a6c84SAndroid Build Coastguard Worker s = s->prev;
394*cf5a6c84SAndroid Build Coastguard Worker i = s->node->len-1;
395*cf5a6c84SAndroid Build Coastguard Worker } while (s != TT.slices->prev); //tail
396*cf5a6c84SAndroid Build Coastguard Worker
397*cf5a6c84SAndroid Build Coastguard Worker return SIZE_MAX;
398*cf5a6c84SAndroid Build Coastguard Worker }
399*cf5a6c84SAndroid Build Coastguard Worker
text_filesize()400*cf5a6c84SAndroid Build Coastguard Worker static size_t text_filesize()
401*cf5a6c84SAndroid Build Coastguard Worker {
402*cf5a6c84SAndroid Build Coastguard Worker struct slice_list *s = TT.slices;
403*cf5a6c84SAndroid Build Coastguard Worker size_t pos = 0;
404*cf5a6c84SAndroid Build Coastguard Worker
405*cf5a6c84SAndroid Build Coastguard Worker if (s) do {
406*cf5a6c84SAndroid Build Coastguard Worker pos += s->node->len;
407*cf5a6c84SAndroid Build Coastguard Worker s = s->next;
408*cf5a6c84SAndroid Build Coastguard Worker } while (s != TT.slices);
409*cf5a6c84SAndroid Build Coastguard Worker
410*cf5a6c84SAndroid Build Coastguard Worker return pos;
411*cf5a6c84SAndroid Build Coastguard Worker }
412*cf5a6c84SAndroid Build Coastguard Worker
text_count(size_t start,size_t end,char c)413*cf5a6c84SAndroid Build Coastguard Worker static int text_count(size_t start, size_t end, char c)
414*cf5a6c84SAndroid Build Coastguard Worker {
415*cf5a6c84SAndroid Build Coastguard Worker struct slice_list *s = TT.slices;
416*cf5a6c84SAndroid Build Coastguard Worker size_t i, count = 0, spos = 0;
417*cf5a6c84SAndroid Build Coastguard Worker if (!(s = slice_offset(&spos, start))) return 0;
418*cf5a6c84SAndroid Build Coastguard Worker i = start-spos;
419*cf5a6c84SAndroid Build Coastguard Worker if (s) do {
420*cf5a6c84SAndroid Build Coastguard Worker for (; i < s->node->len && spos+i<end; i++)
421*cf5a6c84SAndroid Build Coastguard Worker if (s->node->data[i] == c) count++;
422*cf5a6c84SAndroid Build Coastguard Worker if (spos+i>=end) return count;
423*cf5a6c84SAndroid Build Coastguard Worker
424*cf5a6c84SAndroid Build Coastguard Worker spos += s->node->len;
425*cf5a6c84SAndroid Build Coastguard Worker i = 0;
426*cf5a6c84SAndroid Build Coastguard Worker s = s->next;
427*cf5a6c84SAndroid Build Coastguard Worker
428*cf5a6c84SAndroid Build Coastguard Worker } while (s != TT.slices);
429*cf5a6c84SAndroid Build Coastguard Worker
430*cf5a6c84SAndroid Build Coastguard Worker return count;
431*cf5a6c84SAndroid Build Coastguard Worker }
432*cf5a6c84SAndroid Build Coastguard Worker
text_byte(size_t offset)433*cf5a6c84SAndroid Build Coastguard Worker static char text_byte(size_t offset)
434*cf5a6c84SAndroid Build Coastguard Worker {
435*cf5a6c84SAndroid Build Coastguard Worker struct slice_list *s = TT.slices;
436*cf5a6c84SAndroid Build Coastguard Worker size_t spos = 0;
437*cf5a6c84SAndroid Build Coastguard Worker
438*cf5a6c84SAndroid Build Coastguard Worker //find start
439*cf5a6c84SAndroid Build Coastguard Worker if (!(s = slice_offset(&spos, offset))) return 0;
440*cf5a6c84SAndroid Build Coastguard Worker return s->node->data[offset-spos];
441*cf5a6c84SAndroid Build Coastguard Worker }
442*cf5a6c84SAndroid Build Coastguard Worker
443*cf5a6c84SAndroid Build Coastguard Worker //utf-8 codepoint -1 if not valid, 0 if out_of_bounds, len if valid
444*cf5a6c84SAndroid Build Coastguard Worker //copies data to dest if dest is not 0
text_codepoint(char * dest,size_t offset)445*cf5a6c84SAndroid Build Coastguard Worker static int text_codepoint(char *dest, size_t offset)
446*cf5a6c84SAndroid Build Coastguard Worker {
447*cf5a6c84SAndroid Build Coastguard Worker char scratch[8] = {0};
448*cf5a6c84SAndroid Build Coastguard Worker int state = 0, finished = 0;
449*cf5a6c84SAndroid Build Coastguard Worker
450*cf5a6c84SAndroid Build Coastguard Worker for (;!(finished = utf8_dec(text_byte(offset), scratch, &state)); offset++)
451*cf5a6c84SAndroid Build Coastguard Worker if (!state) return -1;
452*cf5a6c84SAndroid Build Coastguard Worker
453*cf5a6c84SAndroid Build Coastguard Worker if (!finished && !state) return -1;
454*cf5a6c84SAndroid Build Coastguard Worker if (dest) memcpy(dest, scratch, 8);
455*cf5a6c84SAndroid Build Coastguard Worker
456*cf5a6c84SAndroid Build Coastguard Worker return strlen(scratch);
457*cf5a6c84SAndroid Build Coastguard Worker }
458*cf5a6c84SAndroid Build Coastguard Worker
text_sol(size_t offset)459*cf5a6c84SAndroid Build Coastguard Worker static size_t text_sol(size_t offset)
460*cf5a6c84SAndroid Build Coastguard Worker {
461*cf5a6c84SAndroid Build Coastguard Worker size_t pos;
462*cf5a6c84SAndroid Build Coastguard Worker
463*cf5a6c84SAndroid Build Coastguard Worker if (!TT.filesize || !offset) return 0;
464*cf5a6c84SAndroid Build Coastguard Worker else if (TT.filesize <= offset) return TT.filesize-1;
465*cf5a6c84SAndroid Build Coastguard Worker else if ((pos = text_strrchr(offset-1, '\n')) == SIZE_MAX) return 0;
466*cf5a6c84SAndroid Build Coastguard Worker else if (pos < offset) return pos+1;
467*cf5a6c84SAndroid Build Coastguard Worker return offset;
468*cf5a6c84SAndroid Build Coastguard Worker }
469*cf5a6c84SAndroid Build Coastguard Worker
text_eol(size_t offset)470*cf5a6c84SAndroid Build Coastguard Worker static size_t text_eol(size_t offset)
471*cf5a6c84SAndroid Build Coastguard Worker {
472*cf5a6c84SAndroid Build Coastguard Worker if (!TT.filesize) offset = 1;
473*cf5a6c84SAndroid Build Coastguard Worker else if (TT.filesize <= offset) return TT.filesize-1;
474*cf5a6c84SAndroid Build Coastguard Worker else if ((offset = text_strchr(offset, '\n')) == SIZE_MAX)
475*cf5a6c84SAndroid Build Coastguard Worker return TT.filesize-1;
476*cf5a6c84SAndroid Build Coastguard Worker return offset;
477*cf5a6c84SAndroid Build Coastguard Worker }
478*cf5a6c84SAndroid Build Coastguard Worker
text_nsol(size_t offset)479*cf5a6c84SAndroid Build Coastguard Worker static size_t text_nsol(size_t offset)
480*cf5a6c84SAndroid Build Coastguard Worker {
481*cf5a6c84SAndroid Build Coastguard Worker offset = text_eol(offset);
482*cf5a6c84SAndroid Build Coastguard Worker if (text_byte(offset) == '\n') offset++;
483*cf5a6c84SAndroid Build Coastguard Worker if (offset >= TT.filesize) offset--;
484*cf5a6c84SAndroid Build Coastguard Worker return offset;
485*cf5a6c84SAndroid Build Coastguard Worker }
486*cf5a6c84SAndroid Build Coastguard Worker
text_psol(size_t offset)487*cf5a6c84SAndroid Build Coastguard Worker static size_t text_psol(size_t offset)
488*cf5a6c84SAndroid Build Coastguard Worker {
489*cf5a6c84SAndroid Build Coastguard Worker offset = text_sol(offset);
490*cf5a6c84SAndroid Build Coastguard Worker if (offset) offset--;
491*cf5a6c84SAndroid Build Coastguard Worker if (offset && text_byte(offset-1) != '\n') offset = text_sol(offset-1);
492*cf5a6c84SAndroid Build Coastguard Worker return offset;
493*cf5a6c84SAndroid Build Coastguard Worker }
494*cf5a6c84SAndroid Build Coastguard Worker
text_getline(char * dest,size_t offset,size_t max_len)495*cf5a6c84SAndroid Build Coastguard Worker static size_t text_getline(char *dest, size_t offset, size_t max_len)
496*cf5a6c84SAndroid Build Coastguard Worker {
497*cf5a6c84SAndroid Build Coastguard Worker struct slice_list *s = TT.slices;
498*cf5a6c84SAndroid Build Coastguard Worker size_t end, spos = 0;
499*cf5a6c84SAndroid Build Coastguard Worker int i, j = 0;
500*cf5a6c84SAndroid Build Coastguard Worker
501*cf5a6c84SAndroid Build Coastguard Worker if (dest) *dest = 0;
502*cf5a6c84SAndroid Build Coastguard Worker
503*cf5a6c84SAndroid Build Coastguard Worker if (!s) return 0;
504*cf5a6c84SAndroid Build Coastguard Worker if ((end = text_strchr(offset, '\n')) == SIZE_MAX)
505*cf5a6c84SAndroid Build Coastguard Worker if ((end = TT.filesize) > offset+max_len) return 0;
506*cf5a6c84SAndroid Build Coastguard Worker
507*cf5a6c84SAndroid Build Coastguard Worker //find start
508*cf5a6c84SAndroid Build Coastguard Worker if (!(s = slice_offset(&spos, offset))) return 0;
509*cf5a6c84SAndroid Build Coastguard Worker
510*cf5a6c84SAndroid Build Coastguard Worker i = offset-spos;
511*cf5a6c84SAndroid Build Coastguard Worker j = end-offset+1;
512*cf5a6c84SAndroid Build Coastguard Worker if (dest) do {
513*cf5a6c84SAndroid Build Coastguard Worker for (; i < s->node->len && j; i++, j--, dest++)
514*cf5a6c84SAndroid Build Coastguard Worker *dest = s->node->data[i];
515*cf5a6c84SAndroid Build Coastguard Worker s = s->next;
516*cf5a6c84SAndroid Build Coastguard Worker i = 0;
517*cf5a6c84SAndroid Build Coastguard Worker } while (s != TT.slices && j);
518*cf5a6c84SAndroid Build Coastguard Worker
519*cf5a6c84SAndroid Build Coastguard Worker if (dest) *dest = 0;
520*cf5a6c84SAndroid Build Coastguard Worker
521*cf5a6c84SAndroid Build Coastguard Worker return end-offset;
522*cf5a6c84SAndroid Build Coastguard Worker }
523*cf5a6c84SAndroid Build Coastguard Worker
524*cf5a6c84SAndroid Build Coastguard Worker // copying is needed when file has lot of inserts that are
525*cf5a6c84SAndroid Build Coastguard Worker // just few char long, but not always. Advanced search should
526*cf5a6c84SAndroid Build Coastguard Worker // check big slices directly and just copy edge cases.
527*cf5a6c84SAndroid Build Coastguard Worker // Also this is only line based search multiline
528*cf5a6c84SAndroid Build Coastguard Worker // and regexec should be done instead.
text_strstr(size_t offset,char * str,int dir)529*cf5a6c84SAndroid Build Coastguard Worker static size_t text_strstr(size_t offset, char *str, int dir)
530*cf5a6c84SAndroid Build Coastguard Worker {
531*cf5a6c84SAndroid Build Coastguard Worker size_t bytes, pos = offset;
532*cf5a6c84SAndroid Build Coastguard Worker char *s = 0;
533*cf5a6c84SAndroid Build Coastguard Worker
534*cf5a6c84SAndroid Build Coastguard Worker do {
535*cf5a6c84SAndroid Build Coastguard Worker bytes = text_getline(toybuf, pos, ARRAY_LEN(toybuf));
536*cf5a6c84SAndroid Build Coastguard Worker if (!bytes) pos += (dir ? 1 : -1); //empty line
537*cf5a6c84SAndroid Build Coastguard Worker else if ((s = strstr(toybuf, str))) return pos+(s-toybuf);
538*cf5a6c84SAndroid Build Coastguard Worker else {
539*cf5a6c84SAndroid Build Coastguard Worker if (!dir) pos -= bytes;
540*cf5a6c84SAndroid Build Coastguard Worker else pos += bytes;
541*cf5a6c84SAndroid Build Coastguard Worker }
542*cf5a6c84SAndroid Build Coastguard Worker } while (pos < (dir ? 0 : TT.filesize));
543*cf5a6c84SAndroid Build Coastguard Worker
544*cf5a6c84SAndroid Build Coastguard Worker return SIZE_MAX;
545*cf5a6c84SAndroid Build Coastguard Worker }
546*cf5a6c84SAndroid Build Coastguard Worker
block_list_free(void * node)547*cf5a6c84SAndroid Build Coastguard Worker static void block_list_free(void *node)
548*cf5a6c84SAndroid Build Coastguard Worker {
549*cf5a6c84SAndroid Build Coastguard Worker struct block_list *d = node;
550*cf5a6c84SAndroid Build Coastguard Worker
551*cf5a6c84SAndroid Build Coastguard Worker if (d->node->alloc == HEAP) free((void *)d->node->data);
552*cf5a6c84SAndroid Build Coastguard Worker else if (d->node->alloc == MMAP) munmap((void *)d->node->data, d->node->size);
553*cf5a6c84SAndroid Build Coastguard Worker
554*cf5a6c84SAndroid Build Coastguard Worker free(d->node);
555*cf5a6c84SAndroid Build Coastguard Worker free(d);
556*cf5a6c84SAndroid Build Coastguard Worker }
557*cf5a6c84SAndroid Build Coastguard Worker
show_error(char * fmt,...)558*cf5a6c84SAndroid Build Coastguard Worker static void show_error(char *fmt, ...)
559*cf5a6c84SAndroid Build Coastguard Worker {
560*cf5a6c84SAndroid Build Coastguard Worker va_list va;
561*cf5a6c84SAndroid Build Coastguard Worker
562*cf5a6c84SAndroid Build Coastguard Worker printf("\a\e[%dH\e[41m\e[37m\e[K\e[1m", TT.screen_height+1);
563*cf5a6c84SAndroid Build Coastguard Worker va_start(va, fmt);
564*cf5a6c84SAndroid Build Coastguard Worker vprintf(fmt, va);
565*cf5a6c84SAndroid Build Coastguard Worker va_end(va);
566*cf5a6c84SAndroid Build Coastguard Worker printf("\e[0m");
567*cf5a6c84SAndroid Build Coastguard Worker fflush(0);
568*cf5a6c84SAndroid Build Coastguard Worker xferror(stdout);
569*cf5a6c84SAndroid Build Coastguard Worker
570*cf5a6c84SAndroid Build Coastguard Worker // TODO: better integration with status line: keep
571*cf5a6c84SAndroid Build Coastguard Worker // message until next operation.
572*cf5a6c84SAndroid Build Coastguard Worker (void)getchar();
573*cf5a6c84SAndroid Build Coastguard Worker }
574*cf5a6c84SAndroid Build Coastguard Worker
linelist_unload()575*cf5a6c84SAndroid Build Coastguard Worker static void linelist_unload()
576*cf5a6c84SAndroid Build Coastguard Worker {
577*cf5a6c84SAndroid Build Coastguard Worker llist_traverse((void *)TT.slices, llist_free_double);
578*cf5a6c84SAndroid Build Coastguard Worker llist_traverse((void *)TT.text, block_list_free);
579*cf5a6c84SAndroid Build Coastguard Worker TT.slices = 0, TT.text = 0;
580*cf5a6c84SAndroid Build Coastguard Worker }
581*cf5a6c84SAndroid Build Coastguard Worker
linelist_load(char * filename,int ignore_missing)582*cf5a6c84SAndroid Build Coastguard Worker static void linelist_load(char *filename, int ignore_missing)
583*cf5a6c84SAndroid Build Coastguard Worker {
584*cf5a6c84SAndroid Build Coastguard Worker int fd;
585*cf5a6c84SAndroid Build Coastguard Worker long long size;
586*cf5a6c84SAndroid Build Coastguard Worker
587*cf5a6c84SAndroid Build Coastguard Worker if (!filename) filename = TT.filename;
588*cf5a6c84SAndroid Build Coastguard Worker if (!filename) {
589*cf5a6c84SAndroid Build Coastguard Worker // `vi` with no arguments creates a new unnamed file.
590*cf5a6c84SAndroid Build Coastguard Worker insert_str(xstrdup("\n"), 0, 1, 1, HEAP);
591*cf5a6c84SAndroid Build Coastguard Worker return;
592*cf5a6c84SAndroid Build Coastguard Worker }
593*cf5a6c84SAndroid Build Coastguard Worker
594*cf5a6c84SAndroid Build Coastguard Worker fd = open(filename, O_RDONLY);
595*cf5a6c84SAndroid Build Coastguard Worker if (fd == -1) {
596*cf5a6c84SAndroid Build Coastguard Worker if (!ignore_missing)
597*cf5a6c84SAndroid Build Coastguard Worker show_error("Couldn't open \"%s\" for reading: %s", filename,
598*cf5a6c84SAndroid Build Coastguard Worker strerror(errno));
599*cf5a6c84SAndroid Build Coastguard Worker insert_str(xstrdup("\n"), 0, 1, 1, HEAP);
600*cf5a6c84SAndroid Build Coastguard Worker return;
601*cf5a6c84SAndroid Build Coastguard Worker }
602*cf5a6c84SAndroid Build Coastguard Worker
603*cf5a6c84SAndroid Build Coastguard Worker size = fdlength(fd);
604*cf5a6c84SAndroid Build Coastguard Worker if (size > 0) {
605*cf5a6c84SAndroid Build Coastguard Worker insert_str(xmmap(0,size,PROT_READ,MAP_SHARED,fd,0), 0, size, size, MMAP);
606*cf5a6c84SAndroid Build Coastguard Worker TT.filesize = text_filesize();
607*cf5a6c84SAndroid Build Coastguard Worker } else if (!size) insert_str(xstrdup("\n"), 0, 1, 1, HEAP);
608*cf5a6c84SAndroid Build Coastguard Worker xclose(fd);
609*cf5a6c84SAndroid Build Coastguard Worker }
610*cf5a6c84SAndroid Build Coastguard Worker
write_file(char * filename)611*cf5a6c84SAndroid Build Coastguard Worker static int write_file(char *filename)
612*cf5a6c84SAndroid Build Coastguard Worker {
613*cf5a6c84SAndroid Build Coastguard Worker struct slice_list *s = TT.slices;
614*cf5a6c84SAndroid Build Coastguard Worker struct stat st;
615*cf5a6c84SAndroid Build Coastguard Worker int fd = 0;
616*cf5a6c84SAndroid Build Coastguard Worker
617*cf5a6c84SAndroid Build Coastguard Worker if (!modified()) show_error("Not modified");
618*cf5a6c84SAndroid Build Coastguard Worker if (!filename) filename = TT.filename;
619*cf5a6c84SAndroid Build Coastguard Worker if (!filename) {
620*cf5a6c84SAndroid Build Coastguard Worker show_error("No file name");
621*cf5a6c84SAndroid Build Coastguard Worker return -1;
622*cf5a6c84SAndroid Build Coastguard Worker }
623*cf5a6c84SAndroid Build Coastguard Worker
624*cf5a6c84SAndroid Build Coastguard Worker if (stat(filename, &st) == -1) st.st_mode = 0644;
625*cf5a6c84SAndroid Build Coastguard Worker
626*cf5a6c84SAndroid Build Coastguard Worker sprintf(toybuf, "%s.swp", filename);
627*cf5a6c84SAndroid Build Coastguard Worker
628*cf5a6c84SAndroid Build Coastguard Worker if ((fd = open(toybuf, O_WRONLY | O_CREAT | O_TRUNC, st.st_mode)) == -1) {
629*cf5a6c84SAndroid Build Coastguard Worker show_error("Couldn't open \"%s\" for writing: %s", toybuf, strerror(errno));
630*cf5a6c84SAndroid Build Coastguard Worker return -1;
631*cf5a6c84SAndroid Build Coastguard Worker }
632*cf5a6c84SAndroid Build Coastguard Worker
633*cf5a6c84SAndroid Build Coastguard Worker if (s) {
634*cf5a6c84SAndroid Build Coastguard Worker do {
635*cf5a6c84SAndroid Build Coastguard Worker xwrite(fd, (void *)s->node->data, s->node->len);
636*cf5a6c84SAndroid Build Coastguard Worker s = s->next;
637*cf5a6c84SAndroid Build Coastguard Worker } while (s != TT.slices);
638*cf5a6c84SAndroid Build Coastguard Worker }
639*cf5a6c84SAndroid Build Coastguard Worker
640*cf5a6c84SAndroid Build Coastguard Worker linelist_unload();
641*cf5a6c84SAndroid Build Coastguard Worker
642*cf5a6c84SAndroid Build Coastguard Worker xclose(fd);
643*cf5a6c84SAndroid Build Coastguard Worker if (!rename(toybuf, filename)) return 1;
644*cf5a6c84SAndroid Build Coastguard Worker linelist_load(filename, 0);
645*cf5a6c84SAndroid Build Coastguard Worker return 0;
646*cf5a6c84SAndroid Build Coastguard Worker }
647*cf5a6c84SAndroid Build Coastguard Worker
648*cf5a6c84SAndroid Build Coastguard Worker // jump into valid offset index
649*cf5a6c84SAndroid Build Coastguard Worker // and valid utf8 codepoint
check_cursor_bounds()650*cf5a6c84SAndroid Build Coastguard Worker static void check_cursor_bounds()
651*cf5a6c84SAndroid Build Coastguard Worker {
652*cf5a6c84SAndroid Build Coastguard Worker char buf[8] = {0};
653*cf5a6c84SAndroid Build Coastguard Worker int len, width = 0;
654*cf5a6c84SAndroid Build Coastguard Worker
655*cf5a6c84SAndroid Build Coastguard Worker if (!TT.filesize) TT.cursor = 0;
656*cf5a6c84SAndroid Build Coastguard Worker for (;;) {
657*cf5a6c84SAndroid Build Coastguard Worker if (TT.cursor < 1) {
658*cf5a6c84SAndroid Build Coastguard Worker TT.cursor = 0;
659*cf5a6c84SAndroid Build Coastguard Worker return;
660*cf5a6c84SAndroid Build Coastguard Worker } else if (TT.cursor >= TT.filesize-1) {
661*cf5a6c84SAndroid Build Coastguard Worker TT.cursor = TT.filesize-1;
662*cf5a6c84SAndroid Build Coastguard Worker return;
663*cf5a6c84SAndroid Build Coastguard Worker }
664*cf5a6c84SAndroid Build Coastguard Worker // if we are not in valid data try jump over
665*cf5a6c84SAndroid Build Coastguard Worker if ((len = text_codepoint(buf, TT.cursor)) < 1) TT.cursor--;
666*cf5a6c84SAndroid Build Coastguard Worker else if (utf8_lnw(&width, buf, len) && width) break;
667*cf5a6c84SAndroid Build Coastguard Worker else TT.cursor--; //combine char jump over
668*cf5a6c84SAndroid Build Coastguard Worker }
669*cf5a6c84SAndroid Build Coastguard Worker }
670*cf5a6c84SAndroid Build Coastguard Worker
671*cf5a6c84SAndroid Build Coastguard Worker // TT.vi_mov_flag is used for special cases when certain move
672*cf5a6c84SAndroid Build Coastguard Worker // acts differently depending is there DELETE/YANK or NOP
673*cf5a6c84SAndroid Build Coastguard Worker // Also commands such as G does not default to count0=1
674*cf5a6c84SAndroid Build Coastguard Worker // 0x1 = Command needs argument (f,F,r...)
675*cf5a6c84SAndroid Build Coastguard Worker // 0x2 = Move 1 right on yank/delete/insert (e, $...)
676*cf5a6c84SAndroid Build Coastguard Worker // 0x4 = yank/delete last line fully
677*cf5a6c84SAndroid Build Coastguard Worker // 0x10000000 = redraw after cursor needed
678*cf5a6c84SAndroid Build Coastguard Worker // 0x20000000 = full redraw needed
679*cf5a6c84SAndroid Build Coastguard Worker // 0x40000000 = count0 not given
680*cf5a6c84SAndroid Build Coastguard Worker // 0x80000000 = move was reverse
681*cf5a6c84SAndroid Build Coastguard Worker
682*cf5a6c84SAndroid Build Coastguard Worker // TODO rewrite the logic, difficulties counting lines
683*cf5a6c84SAndroid Build Coastguard Worker // and with big files scroll should not rely in knowing
684*cf5a6c84SAndroid Build Coastguard Worker // absoluteline numbers
adjust_screen_buffer()685*cf5a6c84SAndroid Build Coastguard Worker static void adjust_screen_buffer()
686*cf5a6c84SAndroid Build Coastguard Worker {
687*cf5a6c84SAndroid Build Coastguard Worker size_t c, s;
688*cf5a6c84SAndroid Build Coastguard Worker TT.cur_row = 0, TT.scr_row = 0;
689*cf5a6c84SAndroid Build Coastguard Worker if (!TT.cursor) {
690*cf5a6c84SAndroid Build Coastguard Worker TT.screen = 0;
691*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mov_flag = 0x20000000;
692*cf5a6c84SAndroid Build Coastguard Worker return;
693*cf5a6c84SAndroid Build Coastguard Worker } else if (TT.screen > (1<<18) || TT.cursor > (1<<18)) {
694*cf5a6c84SAndroid Build Coastguard Worker //give up, file is big, do full redraw
695*cf5a6c84SAndroid Build Coastguard Worker
696*cf5a6c84SAndroid Build Coastguard Worker TT.screen = text_strrchr(TT.cursor-1, '\n')+1;
697*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mov_flag = 0x20000000;
698*cf5a6c84SAndroid Build Coastguard Worker return;
699*cf5a6c84SAndroid Build Coastguard Worker }
700*cf5a6c84SAndroid Build Coastguard Worker
701*cf5a6c84SAndroid Build Coastguard Worker s = text_count(0, TT.screen, '\n');
702*cf5a6c84SAndroid Build Coastguard Worker c = text_count(0, TT.cursor, '\n');
703*cf5a6c84SAndroid Build Coastguard Worker if (s >= c) {
704*cf5a6c84SAndroid Build Coastguard Worker TT.screen = text_strrchr(TT.cursor-1, '\n')+1;
705*cf5a6c84SAndroid Build Coastguard Worker s = c;
706*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mov_flag = 0x20000000; //TODO I disabled scroll
707*cf5a6c84SAndroid Build Coastguard Worker } else {
708*cf5a6c84SAndroid Build Coastguard Worker int distance = c-s+1;
709*cf5a6c84SAndroid Build Coastguard Worker if (distance > (int)TT.screen_height) {
710*cf5a6c84SAndroid Build Coastguard Worker int n, adj = distance-TT.screen_height;
711*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mov_flag = 0x20000000; //TODO I disabled scroll
712*cf5a6c84SAndroid Build Coastguard Worker for (;adj; adj--, s++)
713*cf5a6c84SAndroid Build Coastguard Worker if ((n = text_strchr(TT.screen, '\n'))+1 > TT.screen)
714*cf5a6c84SAndroid Build Coastguard Worker TT.screen = n+1;
715*cf5a6c84SAndroid Build Coastguard Worker }
716*cf5a6c84SAndroid Build Coastguard Worker }
717*cf5a6c84SAndroid Build Coastguard Worker
718*cf5a6c84SAndroid Build Coastguard Worker TT.scr_row = s;
719*cf5a6c84SAndroid Build Coastguard Worker TT.cur_row = c;
720*cf5a6c84SAndroid Build Coastguard Worker }
721*cf5a6c84SAndroid Build Coastguard Worker
722*cf5a6c84SAndroid Build Coastguard Worker // TODO search yank buffer by register
723*cf5a6c84SAndroid Build Coastguard Worker // TODO yanks could be separate slices so no need to copy data
724*cf5a6c84SAndroid Build Coastguard Worker // now only supports default register
vi_yank(char reg,size_t from,int flags)725*cf5a6c84SAndroid Build Coastguard Worker static int vi_yank(char reg, size_t from, int flags)
726*cf5a6c84SAndroid Build Coastguard Worker {
727*cf5a6c84SAndroid Build Coastguard Worker size_t start = from, end = TT.cursor;
728*cf5a6c84SAndroid Build Coastguard Worker char *str;
729*cf5a6c84SAndroid Build Coastguard Worker
730*cf5a6c84SAndroid Build Coastguard Worker memset(TT.yank.data, 0, TT.yank.alloc);
731*cf5a6c84SAndroid Build Coastguard Worker if (TT.vi_mov_flag&0x80000000) start = TT.cursor, end = from;
732*cf5a6c84SAndroid Build Coastguard Worker else TT.cursor = start; //yank moves cursor to left pos always?
733*cf5a6c84SAndroid Build Coastguard Worker
734*cf5a6c84SAndroid Build Coastguard Worker if (TT.yank.alloc < end-from) {
735*cf5a6c84SAndroid Build Coastguard Worker size_t new_bounds = (1+end-from)/1024;
736*cf5a6c84SAndroid Build Coastguard Worker new_bounds += ((1+end-from)%1024) ? 1 : 0;
737*cf5a6c84SAndroid Build Coastguard Worker new_bounds *= 1024;
738*cf5a6c84SAndroid Build Coastguard Worker TT.yank.data = xrealloc(TT.yank.data, new_bounds);
739*cf5a6c84SAndroid Build Coastguard Worker TT.yank.alloc = new_bounds;
740*cf5a6c84SAndroid Build Coastguard Worker }
741*cf5a6c84SAndroid Build Coastguard Worker
742*cf5a6c84SAndroid Build Coastguard Worker //this is naive copy
743*cf5a6c84SAndroid Build Coastguard Worker for (str = TT.yank.data ; start<end; start++, str++) *str = text_byte(start);
744*cf5a6c84SAndroid Build Coastguard Worker
745*cf5a6c84SAndroid Build Coastguard Worker *str = 0;
746*cf5a6c84SAndroid Build Coastguard Worker
747*cf5a6c84SAndroid Build Coastguard Worker return 1;
748*cf5a6c84SAndroid Build Coastguard Worker }
749*cf5a6c84SAndroid Build Coastguard Worker
vi_delete(char reg,size_t from,int flags)750*cf5a6c84SAndroid Build Coastguard Worker static int vi_delete(char reg, size_t from, int flags)
751*cf5a6c84SAndroid Build Coastguard Worker {
752*cf5a6c84SAndroid Build Coastguard Worker size_t start = from, end = TT.cursor;
753*cf5a6c84SAndroid Build Coastguard Worker
754*cf5a6c84SAndroid Build Coastguard Worker vi_yank(reg, from, flags);
755*cf5a6c84SAndroid Build Coastguard Worker
756*cf5a6c84SAndroid Build Coastguard Worker if (TT.vi_mov_flag&0x80000000) start = TT.cursor, end = from;
757*cf5a6c84SAndroid Build Coastguard Worker
758*cf5a6c84SAndroid Build Coastguard Worker //pre adjust cursor move one right until at next valid rune
759*cf5a6c84SAndroid Build Coastguard Worker if (TT.vi_mov_flag&2) {
760*cf5a6c84SAndroid Build Coastguard Worker //TODO
761*cf5a6c84SAndroid Build Coastguard Worker }
762*cf5a6c84SAndroid Build Coastguard Worker //do slice cut
763*cf5a6c84SAndroid Build Coastguard Worker cut_str(start, end-start);
764*cf5a6c84SAndroid Build Coastguard Worker
765*cf5a6c84SAndroid Build Coastguard Worker //cursor is at start at after delete
766*cf5a6c84SAndroid Build Coastguard Worker TT.cursor = start;
767*cf5a6c84SAndroid Build Coastguard Worker TT.filesize = text_filesize();
768*cf5a6c84SAndroid Build Coastguard Worker //find line start by strrchr(/n) ++
769*cf5a6c84SAndroid Build Coastguard Worker //set cur_col with crunch_n_str maybe?
770*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mov_flag |= 0x30000000;
771*cf5a6c84SAndroid Build Coastguard Worker
772*cf5a6c84SAndroid Build Coastguard Worker return 1;
773*cf5a6c84SAndroid Build Coastguard Worker }
774*cf5a6c84SAndroid Build Coastguard Worker
vi_change(char reg,size_t to,int flags)775*cf5a6c84SAndroid Build Coastguard Worker static int vi_change(char reg, size_t to, int flags)
776*cf5a6c84SAndroid Build Coastguard Worker {
777*cf5a6c84SAndroid Build Coastguard Worker vi_delete(reg, to, flags);
778*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mode = 2;
779*cf5a6c84SAndroid Build Coastguard Worker return 1;
780*cf5a6c84SAndroid Build Coastguard Worker }
781*cf5a6c84SAndroid Build Coastguard Worker
cur_left(int count0,int count1,char * unused)782*cf5a6c84SAndroid Build Coastguard Worker static int cur_left(int count0, int count1, char *unused)
783*cf5a6c84SAndroid Build Coastguard Worker {
784*cf5a6c84SAndroid Build Coastguard Worker int count = count0*count1;
785*cf5a6c84SAndroid Build Coastguard Worker
786*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mov_flag |= 0x80000000;
787*cf5a6c84SAndroid Build Coastguard Worker for (;count && TT.cursor; count--) {
788*cf5a6c84SAndroid Build Coastguard Worker TT.cursor--;
789*cf5a6c84SAndroid Build Coastguard Worker if (text_byte(TT.cursor) == '\n') TT.cursor++;
790*cf5a6c84SAndroid Build Coastguard Worker check_cursor_bounds();
791*cf5a6c84SAndroid Build Coastguard Worker }
792*cf5a6c84SAndroid Build Coastguard Worker return 1;
793*cf5a6c84SAndroid Build Coastguard Worker }
794*cf5a6c84SAndroid Build Coastguard Worker
cur_right(int count0,int count1,char * unused)795*cf5a6c84SAndroid Build Coastguard Worker static int cur_right(int count0, int count1, char *unused)
796*cf5a6c84SAndroid Build Coastguard Worker {
797*cf5a6c84SAndroid Build Coastguard Worker int count = count0*count1, len, width = 0;
798*cf5a6c84SAndroid Build Coastguard Worker char buf[8] = {0};
799*cf5a6c84SAndroid Build Coastguard Worker
800*cf5a6c84SAndroid Build Coastguard Worker for (;count; count--) {
801*cf5a6c84SAndroid Build Coastguard Worker len = text_codepoint(buf, TT.cursor);
802*cf5a6c84SAndroid Build Coastguard Worker
803*cf5a6c84SAndroid Build Coastguard Worker if (*buf == '\n') break;
804*cf5a6c84SAndroid Build Coastguard Worker else if (len > 0) TT.cursor += len;
805*cf5a6c84SAndroid Build Coastguard Worker else TT.cursor++;
806*cf5a6c84SAndroid Build Coastguard Worker
807*cf5a6c84SAndroid Build Coastguard Worker for (;TT.cursor < TT.filesize;) {
808*cf5a6c84SAndroid Build Coastguard Worker if ((len = text_codepoint(buf, TT.cursor)) < 1) {
809*cf5a6c84SAndroid Build Coastguard Worker TT.cursor++; //we are not in valid data try jump over
810*cf5a6c84SAndroid Build Coastguard Worker continue;
811*cf5a6c84SAndroid Build Coastguard Worker }
812*cf5a6c84SAndroid Build Coastguard Worker
813*cf5a6c84SAndroid Build Coastguard Worker if (utf8_lnw(&width, buf, len) && width) break;
814*cf5a6c84SAndroid Build Coastguard Worker else TT.cursor += len;
815*cf5a6c84SAndroid Build Coastguard Worker }
816*cf5a6c84SAndroid Build Coastguard Worker }
817*cf5a6c84SAndroid Build Coastguard Worker check_cursor_bounds();
818*cf5a6c84SAndroid Build Coastguard Worker return 1;
819*cf5a6c84SAndroid Build Coastguard Worker }
820*cf5a6c84SAndroid Build Coastguard Worker
821*cf5a6c84SAndroid Build Coastguard Worker //TODO column shift
cur_up(int count0,int count1,char * unused)822*cf5a6c84SAndroid Build Coastguard Worker static int cur_up(int count0, int count1, char *unused)
823*cf5a6c84SAndroid Build Coastguard Worker {
824*cf5a6c84SAndroid Build Coastguard Worker int count = count0*count1;
825*cf5a6c84SAndroid Build Coastguard Worker
826*cf5a6c84SAndroid Build Coastguard Worker for (;count--;) TT.cursor = text_psol(TT.cursor);
827*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mov_flag |= 0x80000000;
828*cf5a6c84SAndroid Build Coastguard Worker check_cursor_bounds();
829*cf5a6c84SAndroid Build Coastguard Worker return 1;
830*cf5a6c84SAndroid Build Coastguard Worker }
831*cf5a6c84SAndroid Build Coastguard Worker
832*cf5a6c84SAndroid Build Coastguard Worker //TODO column shift
cur_down(int count0,int count1,char * unused)833*cf5a6c84SAndroid Build Coastguard Worker static int cur_down(int count0, int count1, char *unused)
834*cf5a6c84SAndroid Build Coastguard Worker {
835*cf5a6c84SAndroid Build Coastguard Worker int count = count0*count1;
836*cf5a6c84SAndroid Build Coastguard Worker
837*cf5a6c84SAndroid Build Coastguard Worker for (;count--;) TT.cursor = text_nsol(TT.cursor);
838*cf5a6c84SAndroid Build Coastguard Worker check_cursor_bounds();
839*cf5a6c84SAndroid Build Coastguard Worker return 1;
840*cf5a6c84SAndroid Build Coastguard Worker }
841*cf5a6c84SAndroid Build Coastguard Worker
vi_H(int count0,int count1,char * unused)842*cf5a6c84SAndroid Build Coastguard Worker static int vi_H(int count0, int count1, char *unused)
843*cf5a6c84SAndroid Build Coastguard Worker {
844*cf5a6c84SAndroid Build Coastguard Worker TT.cursor = text_sol(TT.screen);
845*cf5a6c84SAndroid Build Coastguard Worker return 1;
846*cf5a6c84SAndroid Build Coastguard Worker }
847*cf5a6c84SAndroid Build Coastguard Worker
vi_L(int count0,int count1,char * unused)848*cf5a6c84SAndroid Build Coastguard Worker static int vi_L(int count0, int count1, char *unused)
849*cf5a6c84SAndroid Build Coastguard Worker {
850*cf5a6c84SAndroid Build Coastguard Worker TT.cursor = text_sol(TT.screen);
851*cf5a6c84SAndroid Build Coastguard Worker cur_down(TT.screen_height-1, 1, 0);
852*cf5a6c84SAndroid Build Coastguard Worker return 1;
853*cf5a6c84SAndroid Build Coastguard Worker }
854*cf5a6c84SAndroid Build Coastguard Worker
vi_M(int count0,int count1,char * unused)855*cf5a6c84SAndroid Build Coastguard Worker static int vi_M(int count0, int count1, char *unused)
856*cf5a6c84SAndroid Build Coastguard Worker {
857*cf5a6c84SAndroid Build Coastguard Worker TT.cursor = text_sol(TT.screen);
858*cf5a6c84SAndroid Build Coastguard Worker cur_down(TT.screen_height/2, 1, 0);
859*cf5a6c84SAndroid Build Coastguard Worker return 1;
860*cf5a6c84SAndroid Build Coastguard Worker }
861*cf5a6c84SAndroid Build Coastguard Worker
search_str(char * s,int direction)862*cf5a6c84SAndroid Build Coastguard Worker static int search_str(char *s, int direction)
863*cf5a6c84SAndroid Build Coastguard Worker {
864*cf5a6c84SAndroid Build Coastguard Worker size_t pos = text_strstr(TT.cursor+1, s, direction);
865*cf5a6c84SAndroid Build Coastguard Worker
866*cf5a6c84SAndroid Build Coastguard Worker if (TT.last_search != s) {
867*cf5a6c84SAndroid Build Coastguard Worker free(TT.last_search);
868*cf5a6c84SAndroid Build Coastguard Worker TT.last_search = xstrdup(s);
869*cf5a6c84SAndroid Build Coastguard Worker }
870*cf5a6c84SAndroid Build Coastguard Worker
871*cf5a6c84SAndroid Build Coastguard Worker if (pos != SIZE_MAX) TT.cursor = pos;
872*cf5a6c84SAndroid Build Coastguard Worker check_cursor_bounds();
873*cf5a6c84SAndroid Build Coastguard Worker return 0;
874*cf5a6c84SAndroid Build Coastguard Worker }
875*cf5a6c84SAndroid Build Coastguard Worker
vi_yy(char reg,int count0,int count1)876*cf5a6c84SAndroid Build Coastguard Worker static int vi_yy(char reg, int count0, int count1)
877*cf5a6c84SAndroid Build Coastguard Worker {
878*cf5a6c84SAndroid Build Coastguard Worker size_t history = TT.cursor;
879*cf5a6c84SAndroid Build Coastguard Worker size_t pos = text_sol(TT.cursor); //go left to first char on line
880*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mov_flag |= 4;
881*cf5a6c84SAndroid Build Coastguard Worker
882*cf5a6c84SAndroid Build Coastguard Worker for (;count0; count0--) TT.cursor = text_nsol(TT.cursor);
883*cf5a6c84SAndroid Build Coastguard Worker
884*cf5a6c84SAndroid Build Coastguard Worker vi_yank(reg, pos, 0);
885*cf5a6c84SAndroid Build Coastguard Worker
886*cf5a6c84SAndroid Build Coastguard Worker TT.cursor = history;
887*cf5a6c84SAndroid Build Coastguard Worker return 1;
888*cf5a6c84SAndroid Build Coastguard Worker }
889*cf5a6c84SAndroid Build Coastguard Worker
vi_dd(char reg,int count0,int count1)890*cf5a6c84SAndroid Build Coastguard Worker static int vi_dd(char reg, int count0, int count1)
891*cf5a6c84SAndroid Build Coastguard Worker {
892*cf5a6c84SAndroid Build Coastguard Worker size_t pos = text_sol(TT.cursor); //go left to first char on line
893*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mov_flag |= 0x30000000;
894*cf5a6c84SAndroid Build Coastguard Worker
895*cf5a6c84SAndroid Build Coastguard Worker for (;count0; count0--) TT.cursor = text_nsol(TT.cursor);
896*cf5a6c84SAndroid Build Coastguard Worker
897*cf5a6c84SAndroid Build Coastguard Worker if (pos == TT.cursor && TT.filesize) pos--;
898*cf5a6c84SAndroid Build Coastguard Worker vi_delete(reg, pos, 0);
899*cf5a6c84SAndroid Build Coastguard Worker check_cursor_bounds();
900*cf5a6c84SAndroid Build Coastguard Worker return 1;
901*cf5a6c84SAndroid Build Coastguard Worker }
902*cf5a6c84SAndroid Build Coastguard Worker
vi_x(char reg,int count0,int count1)903*cf5a6c84SAndroid Build Coastguard Worker static int vi_x(char reg, int count0, int count1)
904*cf5a6c84SAndroid Build Coastguard Worker {
905*cf5a6c84SAndroid Build Coastguard Worker size_t from = TT.cursor;
906*cf5a6c84SAndroid Build Coastguard Worker
907*cf5a6c84SAndroid Build Coastguard Worker if (text_byte(TT.cursor) == '\n') {
908*cf5a6c84SAndroid Build Coastguard Worker cur_left(count0-1, 1, 0);
909*cf5a6c84SAndroid Build Coastguard Worker }
910*cf5a6c84SAndroid Build Coastguard Worker else {
911*cf5a6c84SAndroid Build Coastguard Worker cur_right(count0-1, 1, 0);
912*cf5a6c84SAndroid Build Coastguard Worker if (text_byte(TT.cursor) == '\n') TT.vi_mov_flag |= 2;
913*cf5a6c84SAndroid Build Coastguard Worker else cur_right(1, 1, 0);
914*cf5a6c84SAndroid Build Coastguard Worker }
915*cf5a6c84SAndroid Build Coastguard Worker
916*cf5a6c84SAndroid Build Coastguard Worker vi_delete(reg, from, 0);
917*cf5a6c84SAndroid Build Coastguard Worker check_cursor_bounds();
918*cf5a6c84SAndroid Build Coastguard Worker return 1;
919*cf5a6c84SAndroid Build Coastguard Worker }
920*cf5a6c84SAndroid Build Coastguard Worker
backspace(char reg,int count0,int count1)921*cf5a6c84SAndroid Build Coastguard Worker static int backspace(char reg, int count0, int count1)
922*cf5a6c84SAndroid Build Coastguard Worker {
923*cf5a6c84SAndroid Build Coastguard Worker size_t from = 0;
924*cf5a6c84SAndroid Build Coastguard Worker size_t to = TT.cursor;
925*cf5a6c84SAndroid Build Coastguard Worker cur_left(1, 1, 0);
926*cf5a6c84SAndroid Build Coastguard Worker from = TT.cursor;
927*cf5a6c84SAndroid Build Coastguard Worker if (from != to)
928*cf5a6c84SAndroid Build Coastguard Worker vi_delete(reg, to, 0);
929*cf5a6c84SAndroid Build Coastguard Worker check_cursor_bounds();
930*cf5a6c84SAndroid Build Coastguard Worker return 1;
931*cf5a6c84SAndroid Build Coastguard Worker }
932*cf5a6c84SAndroid Build Coastguard Worker
vi_movw(int count0,int count1,char * unused)933*cf5a6c84SAndroid Build Coastguard Worker static int vi_movw(int count0, int count1, char *unused)
934*cf5a6c84SAndroid Build Coastguard Worker {
935*cf5a6c84SAndroid Build Coastguard Worker int count = count0*count1;
936*cf5a6c84SAndroid Build Coastguard Worker while (count--) {
937*cf5a6c84SAndroid Build Coastguard Worker char c = text_byte(TT.cursor);
938*cf5a6c84SAndroid Build Coastguard Worker do {
939*cf5a6c84SAndroid Build Coastguard Worker if (TT.cursor > TT.filesize-1) break;
940*cf5a6c84SAndroid Build Coastguard Worker //if at empty jump to non empty
941*cf5a6c84SAndroid Build Coastguard Worker if (c == '\n') {
942*cf5a6c84SAndroid Build Coastguard Worker if (++TT.cursor > TT.filesize-1) break;
943*cf5a6c84SAndroid Build Coastguard Worker if ((c = text_byte(TT.cursor)) == '\n') break;
944*cf5a6c84SAndroid Build Coastguard Worker continue;
945*cf5a6c84SAndroid Build Coastguard Worker } else if (strchr(blank, c)) do {
946*cf5a6c84SAndroid Build Coastguard Worker if (++TT.cursor > TT.filesize-1) break;
947*cf5a6c84SAndroid Build Coastguard Worker c = text_byte(TT.cursor);
948*cf5a6c84SAndroid Build Coastguard Worker } while (strchr(blank, c));
949*cf5a6c84SAndroid Build Coastguard Worker //if at special jump to non special
950*cf5a6c84SAndroid Build Coastguard Worker else if (strchr(specials, c)) do {
951*cf5a6c84SAndroid Build Coastguard Worker if (++TT.cursor > TT.filesize-1) break;
952*cf5a6c84SAndroid Build Coastguard Worker c = text_byte(TT.cursor);
953*cf5a6c84SAndroid Build Coastguard Worker } while (strchr(specials, c));
954*cf5a6c84SAndroid Build Coastguard Worker //else jump to empty or spesial
955*cf5a6c84SAndroid Build Coastguard Worker else do {
956*cf5a6c84SAndroid Build Coastguard Worker if (++TT.cursor > TT.filesize-1) break;
957*cf5a6c84SAndroid Build Coastguard Worker c = text_byte(TT.cursor);
958*cf5a6c84SAndroid Build Coastguard Worker } while (c && !strchr(blank, c) && !strchr(specials, c));
959*cf5a6c84SAndroid Build Coastguard Worker
960*cf5a6c84SAndroid Build Coastguard Worker } while (strchr(blank, c) && c != '\n'); //never stop at empty
961*cf5a6c84SAndroid Build Coastguard Worker }
962*cf5a6c84SAndroid Build Coastguard Worker check_cursor_bounds();
963*cf5a6c84SAndroid Build Coastguard Worker return 1;
964*cf5a6c84SAndroid Build Coastguard Worker }
965*cf5a6c84SAndroid Build Coastguard Worker
vi_movb(int count0,int count1,char * unused)966*cf5a6c84SAndroid Build Coastguard Worker static int vi_movb(int count0, int count1, char *unused)
967*cf5a6c84SAndroid Build Coastguard Worker {
968*cf5a6c84SAndroid Build Coastguard Worker int count = count0*count1;
969*cf5a6c84SAndroid Build Coastguard Worker int type = 0;
970*cf5a6c84SAndroid Build Coastguard Worker char c;
971*cf5a6c84SAndroid Build Coastguard Worker while (count--) {
972*cf5a6c84SAndroid Build Coastguard Worker c = text_byte(TT.cursor);
973*cf5a6c84SAndroid Build Coastguard Worker do {
974*cf5a6c84SAndroid Build Coastguard Worker if (!TT.cursor) break;
975*cf5a6c84SAndroid Build Coastguard Worker //if at empty jump to non empty
976*cf5a6c84SAndroid Build Coastguard Worker if (strchr(blank, c)) do {
977*cf5a6c84SAndroid Build Coastguard Worker if (!--TT.cursor) break;
978*cf5a6c84SAndroid Build Coastguard Worker c = text_byte(TT.cursor);
979*cf5a6c84SAndroid Build Coastguard Worker } while (strchr(blank, c));
980*cf5a6c84SAndroid Build Coastguard Worker //if at special jump to non special
981*cf5a6c84SAndroid Build Coastguard Worker else if (strchr(specials, c)) do {
982*cf5a6c84SAndroid Build Coastguard Worker if (!--TT.cursor) break;
983*cf5a6c84SAndroid Build Coastguard Worker type = 0;
984*cf5a6c84SAndroid Build Coastguard Worker c = text_byte(TT.cursor);
985*cf5a6c84SAndroid Build Coastguard Worker } while (strchr(specials, c));
986*cf5a6c84SAndroid Build Coastguard Worker //else jump to empty or spesial
987*cf5a6c84SAndroid Build Coastguard Worker else do {
988*cf5a6c84SAndroid Build Coastguard Worker if (!--TT.cursor) break;
989*cf5a6c84SAndroid Build Coastguard Worker type = 1;
990*cf5a6c84SAndroid Build Coastguard Worker c = text_byte(TT.cursor);
991*cf5a6c84SAndroid Build Coastguard Worker } while (!strchr(blank, c) && !strchr(specials, c));
992*cf5a6c84SAndroid Build Coastguard Worker
993*cf5a6c84SAndroid Build Coastguard Worker } while (strchr(blank, c)); //never stop at empty
994*cf5a6c84SAndroid Build Coastguard Worker }
995*cf5a6c84SAndroid Build Coastguard Worker //find first
996*cf5a6c84SAndroid Build Coastguard Worker for (;TT.cursor; TT.cursor--) {
997*cf5a6c84SAndroid Build Coastguard Worker c = text_byte(TT.cursor-1);
998*cf5a6c84SAndroid Build Coastguard Worker if (type && !strchr(blank, c) && !strchr(specials, c)) break;
999*cf5a6c84SAndroid Build Coastguard Worker else if (!type && !strchr(specials, c)) break;
1000*cf5a6c84SAndroid Build Coastguard Worker }
1001*cf5a6c84SAndroid Build Coastguard Worker
1002*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mov_flag |= 0x80000000;
1003*cf5a6c84SAndroid Build Coastguard Worker check_cursor_bounds();
1004*cf5a6c84SAndroid Build Coastguard Worker return 1;
1005*cf5a6c84SAndroid Build Coastguard Worker }
1006*cf5a6c84SAndroid Build Coastguard Worker
vi_move(int count0,int count1,char * unused)1007*cf5a6c84SAndroid Build Coastguard Worker static int vi_move(int count0, int count1, char *unused)
1008*cf5a6c84SAndroid Build Coastguard Worker {
1009*cf5a6c84SAndroid Build Coastguard Worker int count = count0*count1;
1010*cf5a6c84SAndroid Build Coastguard Worker int type = 0;
1011*cf5a6c84SAndroid Build Coastguard Worker char c;
1012*cf5a6c84SAndroid Build Coastguard Worker
1013*cf5a6c84SAndroid Build Coastguard Worker if (count>1) vi_movw(count-1, 1, unused);
1014*cf5a6c84SAndroid Build Coastguard Worker
1015*cf5a6c84SAndroid Build Coastguard Worker c = text_byte(TT.cursor);
1016*cf5a6c84SAndroid Build Coastguard Worker if (strchr(specials, c)) type = 1;
1017*cf5a6c84SAndroid Build Coastguard Worker TT.cursor++;
1018*cf5a6c84SAndroid Build Coastguard Worker for (;TT.cursor < TT.filesize-1; TT.cursor++) {
1019*cf5a6c84SAndroid Build Coastguard Worker c = text_byte(TT.cursor+1);
1020*cf5a6c84SAndroid Build Coastguard Worker if (!type && (strchr(blank, c) || strchr(specials, c))) break;
1021*cf5a6c84SAndroid Build Coastguard Worker else if (type && !strchr(specials, c)) break;
1022*cf5a6c84SAndroid Build Coastguard Worker }
1023*cf5a6c84SAndroid Build Coastguard Worker
1024*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mov_flag |= 2;
1025*cf5a6c84SAndroid Build Coastguard Worker check_cursor_bounds();
1026*cf5a6c84SAndroid Build Coastguard Worker return 1;
1027*cf5a6c84SAndroid Build Coastguard Worker }
1028*cf5a6c84SAndroid Build Coastguard Worker
1029*cf5a6c84SAndroid Build Coastguard Worker
i_insert(char * str,int len)1030*cf5a6c84SAndroid Build Coastguard Worker static void i_insert(char *str, int len)
1031*cf5a6c84SAndroid Build Coastguard Worker {
1032*cf5a6c84SAndroid Build Coastguard Worker if (!str || !len) return;
1033*cf5a6c84SAndroid Build Coastguard Worker
1034*cf5a6c84SAndroid Build Coastguard Worker insert_str(xstrdup(str), TT.cursor, len, len, HEAP);
1035*cf5a6c84SAndroid Build Coastguard Worker TT.cursor += len;
1036*cf5a6c84SAndroid Build Coastguard Worker TT.filesize = text_filesize();
1037*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mov_flag |= 0x30000000;
1038*cf5a6c84SAndroid Build Coastguard Worker }
1039*cf5a6c84SAndroid Build Coastguard Worker
vi_zero(int count0,int count1,char * unused)1040*cf5a6c84SAndroid Build Coastguard Worker static int vi_zero(int count0, int count1, char *unused)
1041*cf5a6c84SAndroid Build Coastguard Worker {
1042*cf5a6c84SAndroid Build Coastguard Worker TT.cursor = text_sol(TT.cursor);
1043*cf5a6c84SAndroid Build Coastguard Worker TT.cur_col = 0;
1044*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mov_flag |= 0x80000000;
1045*cf5a6c84SAndroid Build Coastguard Worker return 1;
1046*cf5a6c84SAndroid Build Coastguard Worker }
1047*cf5a6c84SAndroid Build Coastguard Worker
vi_dollar(int count0,int count1,char * unused)1048*cf5a6c84SAndroid Build Coastguard Worker static int vi_dollar(int count0, int count1, char *unused)
1049*cf5a6c84SAndroid Build Coastguard Worker {
1050*cf5a6c84SAndroid Build Coastguard Worker size_t new = text_strchr(TT.cursor, '\n');
1051*cf5a6c84SAndroid Build Coastguard Worker
1052*cf5a6c84SAndroid Build Coastguard Worker if (new != TT.cursor) {
1053*cf5a6c84SAndroid Build Coastguard Worker TT.cursor = new - 1;
1054*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mov_flag |= 2;
1055*cf5a6c84SAndroid Build Coastguard Worker check_cursor_bounds();
1056*cf5a6c84SAndroid Build Coastguard Worker }
1057*cf5a6c84SAndroid Build Coastguard Worker return 1;
1058*cf5a6c84SAndroid Build Coastguard Worker }
1059*cf5a6c84SAndroid Build Coastguard Worker
vi_eol()1060*cf5a6c84SAndroid Build Coastguard Worker static void vi_eol()
1061*cf5a6c84SAndroid Build Coastguard Worker {
1062*cf5a6c84SAndroid Build Coastguard Worker TT.cursor = text_strchr(TT.cursor, '\n');
1063*cf5a6c84SAndroid Build Coastguard Worker check_cursor_bounds();
1064*cf5a6c84SAndroid Build Coastguard Worker }
1065*cf5a6c84SAndroid Build Coastguard Worker
ctrl_b()1066*cf5a6c84SAndroid Build Coastguard Worker static void ctrl_b()
1067*cf5a6c84SAndroid Build Coastguard Worker {
1068*cf5a6c84SAndroid Build Coastguard Worker int i;
1069*cf5a6c84SAndroid Build Coastguard Worker
1070*cf5a6c84SAndroid Build Coastguard Worker for (i=0; i<TT.screen_height-2; ++i) {
1071*cf5a6c84SAndroid Build Coastguard Worker TT.screen = text_psol(TT.screen);
1072*cf5a6c84SAndroid Build Coastguard Worker // TODO: retain x offset.
1073*cf5a6c84SAndroid Build Coastguard Worker TT.cursor = text_psol(TT.screen);
1074*cf5a6c84SAndroid Build Coastguard Worker }
1075*cf5a6c84SAndroid Build Coastguard Worker }
1076*cf5a6c84SAndroid Build Coastguard Worker
ctrl_d()1077*cf5a6c84SAndroid Build Coastguard Worker static void ctrl_d()
1078*cf5a6c84SAndroid Build Coastguard Worker {
1079*cf5a6c84SAndroid Build Coastguard Worker int i;
1080*cf5a6c84SAndroid Build Coastguard Worker
1081*cf5a6c84SAndroid Build Coastguard Worker for (i=0; i<(TT.screen_height-2)/2; ++i) TT.screen = text_nsol(TT.screen);
1082*cf5a6c84SAndroid Build Coastguard Worker // TODO: real vi keeps the x position.
1083*cf5a6c84SAndroid Build Coastguard Worker if (TT.screen > TT.cursor) TT.cursor = TT.screen;
1084*cf5a6c84SAndroid Build Coastguard Worker }
1085*cf5a6c84SAndroid Build Coastguard Worker
ctrl_f()1086*cf5a6c84SAndroid Build Coastguard Worker static void ctrl_f()
1087*cf5a6c84SAndroid Build Coastguard Worker {
1088*cf5a6c84SAndroid Build Coastguard Worker int i;
1089*cf5a6c84SAndroid Build Coastguard Worker
1090*cf5a6c84SAndroid Build Coastguard Worker for (i=0; i<TT.screen_height-2; ++i) TT.screen = text_nsol(TT.screen);
1091*cf5a6c84SAndroid Build Coastguard Worker // TODO: real vi keeps the x position.
1092*cf5a6c84SAndroid Build Coastguard Worker if (TT.screen > TT.cursor) TT.cursor = TT.screen;
1093*cf5a6c84SAndroid Build Coastguard Worker }
1094*cf5a6c84SAndroid Build Coastguard Worker
ctrl_e()1095*cf5a6c84SAndroid Build Coastguard Worker static void ctrl_e()
1096*cf5a6c84SAndroid Build Coastguard Worker {
1097*cf5a6c84SAndroid Build Coastguard Worker TT.screen = text_nsol(TT.screen);
1098*cf5a6c84SAndroid Build Coastguard Worker // TODO: real vi keeps the x position.
1099*cf5a6c84SAndroid Build Coastguard Worker if (TT.screen > TT.cursor) TT.cursor = TT.screen;
1100*cf5a6c84SAndroid Build Coastguard Worker }
1101*cf5a6c84SAndroid Build Coastguard Worker
ctrl_y()1102*cf5a6c84SAndroid Build Coastguard Worker static void ctrl_y()
1103*cf5a6c84SAndroid Build Coastguard Worker {
1104*cf5a6c84SAndroid Build Coastguard Worker TT.screen = text_psol(TT.screen);
1105*cf5a6c84SAndroid Build Coastguard Worker // TODO: only if we're on the bottom line
1106*cf5a6c84SAndroid Build Coastguard Worker TT.cursor = text_psol(TT.cursor);
1107*cf5a6c84SAndroid Build Coastguard Worker // TODO: real vi keeps the x position.
1108*cf5a6c84SAndroid Build Coastguard Worker }
1109*cf5a6c84SAndroid Build Coastguard Worker
1110*cf5a6c84SAndroid Build Coastguard Worker //TODO check register where to push from
vi_push(char reg,int count0,int count1)1111*cf5a6c84SAndroid Build Coastguard Worker static int vi_push(char reg, int count0, int count1)
1112*cf5a6c84SAndroid Build Coastguard Worker {
1113*cf5a6c84SAndroid Build Coastguard Worker //if row changes during push original cursor position is kept
1114*cf5a6c84SAndroid Build Coastguard Worker //vi inconsistancy
1115*cf5a6c84SAndroid Build Coastguard Worker //if yank ends with \n push is linemode else push in place+1
1116*cf5a6c84SAndroid Build Coastguard Worker size_t history = TT.cursor;
1117*cf5a6c84SAndroid Build Coastguard Worker char *start = TT.yank.data, *eol = strchr(start, '\n');
1118*cf5a6c84SAndroid Build Coastguard Worker if (strlen(start) == 0) return 1;
1119*cf5a6c84SAndroid Build Coastguard Worker
1120*cf5a6c84SAndroid Build Coastguard Worker if (start[strlen(start)-1] == '\n') {
1121*cf5a6c84SAndroid Build Coastguard Worker if ((TT.cursor = text_strchr(TT.cursor, '\n')) == SIZE_MAX)
1122*cf5a6c84SAndroid Build Coastguard Worker TT.cursor = TT.filesize;
1123*cf5a6c84SAndroid Build Coastguard Worker else TT.cursor = text_nsol(TT.cursor);
1124*cf5a6c84SAndroid Build Coastguard Worker } else cur_right(1, 1, 0);
1125*cf5a6c84SAndroid Build Coastguard Worker
1126*cf5a6c84SAndroid Build Coastguard Worker i_insert(start, strlen(start));
1127*cf5a6c84SAndroid Build Coastguard Worker if (eol) {
1128*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mov_flag |= 0x10000000;
1129*cf5a6c84SAndroid Build Coastguard Worker TT.cursor = history;
1130*cf5a6c84SAndroid Build Coastguard Worker }
1131*cf5a6c84SAndroid Build Coastguard Worker
1132*cf5a6c84SAndroid Build Coastguard Worker return 1;
1133*cf5a6c84SAndroid Build Coastguard Worker }
1134*cf5a6c84SAndroid Build Coastguard Worker
vi_find_c(int count0,int count1,char * symbol)1135*cf5a6c84SAndroid Build Coastguard Worker static int vi_find_c(int count0, int count1, char *symbol)
1136*cf5a6c84SAndroid Build Coastguard Worker {
1137*cf5a6c84SAndroid Build Coastguard Worker //// int count = count0*count1;
1138*cf5a6c84SAndroid Build Coastguard Worker size_t pos = text_strchr(TT.cursor, *symbol);
1139*cf5a6c84SAndroid Build Coastguard Worker if (pos != SIZE_MAX) TT.cursor = pos;
1140*cf5a6c84SAndroid Build Coastguard Worker return 1;
1141*cf5a6c84SAndroid Build Coastguard Worker }
1142*cf5a6c84SAndroid Build Coastguard Worker
vi_find_cb(int count0,int count1,char * symbol)1143*cf5a6c84SAndroid Build Coastguard Worker static int vi_find_cb(int count0, int count1, char *symbol)
1144*cf5a6c84SAndroid Build Coastguard Worker {
1145*cf5a6c84SAndroid Build Coastguard Worker // do backward search
1146*cf5a6c84SAndroid Build Coastguard Worker size_t pos = text_strrchr(TT.cursor, *symbol);
1147*cf5a6c84SAndroid Build Coastguard Worker if (pos != SIZE_MAX) TT.cursor = pos;
1148*cf5a6c84SAndroid Build Coastguard Worker return 1;
1149*cf5a6c84SAndroid Build Coastguard Worker }
1150*cf5a6c84SAndroid Build Coastguard Worker
1151*cf5a6c84SAndroid Build Coastguard Worker //if count is not spesified should go to last line
vi_go(int count0,int count1,char * symbol)1152*cf5a6c84SAndroid Build Coastguard Worker static int vi_go(int count0, int count1, char *symbol)
1153*cf5a6c84SAndroid Build Coastguard Worker {
1154*cf5a6c84SAndroid Build Coastguard Worker size_t prev_cursor = TT.cursor;
1155*cf5a6c84SAndroid Build Coastguard Worker int count = count0*count1-1;
1156*cf5a6c84SAndroid Build Coastguard Worker TT.cursor = 0;
1157*cf5a6c84SAndroid Build Coastguard Worker
1158*cf5a6c84SAndroid Build Coastguard Worker if (TT.vi_mov_flag&0x40000000 && (TT.cursor = TT.filesize) > 0)
1159*cf5a6c84SAndroid Build Coastguard Worker TT.cursor = text_sol(TT.cursor-1);
1160*cf5a6c84SAndroid Build Coastguard Worker else if (count) {
1161*cf5a6c84SAndroid Build Coastguard Worker size_t next = 0;
1162*cf5a6c84SAndroid Build Coastguard Worker for ( ;count && (next = text_strchr(next+1, '\n')) != SIZE_MAX; count--)
1163*cf5a6c84SAndroid Build Coastguard Worker TT.cursor = next;
1164*cf5a6c84SAndroid Build Coastguard Worker TT.cursor++;
1165*cf5a6c84SAndroid Build Coastguard Worker }
1166*cf5a6c84SAndroid Build Coastguard Worker
1167*cf5a6c84SAndroid Build Coastguard Worker check_cursor_bounds(); //adjusts cursor column
1168*cf5a6c84SAndroid Build Coastguard Worker if (prev_cursor > TT.cursor) TT.vi_mov_flag |= 0x80000000;
1169*cf5a6c84SAndroid Build Coastguard Worker
1170*cf5a6c84SAndroid Build Coastguard Worker return 1;
1171*cf5a6c84SAndroid Build Coastguard Worker }
1172*cf5a6c84SAndroid Build Coastguard Worker
vi_o(char reg,int count0,int count1)1173*cf5a6c84SAndroid Build Coastguard Worker static int vi_o(char reg, int count0, int count1)
1174*cf5a6c84SAndroid Build Coastguard Worker {
1175*cf5a6c84SAndroid Build Coastguard Worker TT.cursor = text_eol(TT.cursor);
1176*cf5a6c84SAndroid Build Coastguard Worker insert_str(xstrdup("\n"), TT.cursor++, 1, 1, HEAP);
1177*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mov_flag |= 0x30000000;
1178*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mode = 2;
1179*cf5a6c84SAndroid Build Coastguard Worker return 1;
1180*cf5a6c84SAndroid Build Coastguard Worker }
1181*cf5a6c84SAndroid Build Coastguard Worker
vi_O(char reg,int count0,int count1)1182*cf5a6c84SAndroid Build Coastguard Worker static int vi_O(char reg, int count0, int count1)
1183*cf5a6c84SAndroid Build Coastguard Worker {
1184*cf5a6c84SAndroid Build Coastguard Worker TT.cursor = text_psol(TT.cursor);
1185*cf5a6c84SAndroid Build Coastguard Worker return vi_o(reg, count0, count1);
1186*cf5a6c84SAndroid Build Coastguard Worker }
1187*cf5a6c84SAndroid Build Coastguard Worker
vi_D(char reg,int count0,int count1)1188*cf5a6c84SAndroid Build Coastguard Worker static int vi_D(char reg, int count0, int count1)
1189*cf5a6c84SAndroid Build Coastguard Worker {
1190*cf5a6c84SAndroid Build Coastguard Worker size_t pos = TT.cursor;
1191*cf5a6c84SAndroid Build Coastguard Worker if (!count0) return 1;
1192*cf5a6c84SAndroid Build Coastguard Worker vi_eol();
1193*cf5a6c84SAndroid Build Coastguard Worker vi_delete(reg, pos, 0);
1194*cf5a6c84SAndroid Build Coastguard Worker if (--count0) vi_dd(reg, count0, 1);
1195*cf5a6c84SAndroid Build Coastguard Worker
1196*cf5a6c84SAndroid Build Coastguard Worker check_cursor_bounds();
1197*cf5a6c84SAndroid Build Coastguard Worker return 1;
1198*cf5a6c84SAndroid Build Coastguard Worker }
1199*cf5a6c84SAndroid Build Coastguard Worker
vi_I(char reg,int count0,int count1)1200*cf5a6c84SAndroid Build Coastguard Worker static int vi_I(char reg, int count0, int count1)
1201*cf5a6c84SAndroid Build Coastguard Worker {
1202*cf5a6c84SAndroid Build Coastguard Worker TT.cursor = text_sol(TT.cursor);
1203*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mode = 2;
1204*cf5a6c84SAndroid Build Coastguard Worker return 1;
1205*cf5a6c84SAndroid Build Coastguard Worker }
1206*cf5a6c84SAndroid Build Coastguard Worker
vi_join(char reg,int count0,int count1)1207*cf5a6c84SAndroid Build Coastguard Worker static int vi_join(char reg, int count0, int count1)
1208*cf5a6c84SAndroid Build Coastguard Worker {
1209*cf5a6c84SAndroid Build Coastguard Worker size_t next;
1210*cf5a6c84SAndroid Build Coastguard Worker while (count0--) {
1211*cf5a6c84SAndroid Build Coastguard Worker //just strchr(/n) and cut_str(pos, 1);
1212*cf5a6c84SAndroid Build Coastguard Worker if ((next = text_strchr(TT.cursor, '\n')) == SIZE_MAX) break;
1213*cf5a6c84SAndroid Build Coastguard Worker TT.cursor = next+1;
1214*cf5a6c84SAndroid Build Coastguard Worker vi_delete(reg, TT.cursor-1, 0);
1215*cf5a6c84SAndroid Build Coastguard Worker }
1216*cf5a6c84SAndroid Build Coastguard Worker return 1;
1217*cf5a6c84SAndroid Build Coastguard Worker }
1218*cf5a6c84SAndroid Build Coastguard Worker
vi_find_next(char reg,int count0,int count1)1219*cf5a6c84SAndroid Build Coastguard Worker static int vi_find_next(char reg, int count0, int count1)
1220*cf5a6c84SAndroid Build Coastguard Worker {
1221*cf5a6c84SAndroid Build Coastguard Worker if (TT.last_search) search_str(TT.last_search, 1);
1222*cf5a6c84SAndroid Build Coastguard Worker return 1;
1223*cf5a6c84SAndroid Build Coastguard Worker }
1224*cf5a6c84SAndroid Build Coastguard Worker
vi_find_prev(char reg,int count0,int count1)1225*cf5a6c84SAndroid Build Coastguard Worker static int vi_find_prev(char reg, int count0, int count1)
1226*cf5a6c84SAndroid Build Coastguard Worker {
1227*cf5a6c84SAndroid Build Coastguard Worker if (TT.last_search) search_str(TT.last_search, 0);
1228*cf5a6c84SAndroid Build Coastguard Worker return 1;
1229*cf5a6c84SAndroid Build Coastguard Worker }
1230*cf5a6c84SAndroid Build Coastguard Worker
1231*cf5a6c84SAndroid Build Coastguard Worker //NOTES
1232*cf5a6c84SAndroid Build Coastguard Worker //vi-mode cmd syntax is
1233*cf5a6c84SAndroid Build Coastguard Worker //("[REG])[COUNT0]CMD[COUNT1](MOV)
1234*cf5a6c84SAndroid Build Coastguard Worker //where:
1235*cf5a6c84SAndroid Build Coastguard Worker //-------------------------------------------------------------
1236*cf5a6c84SAndroid Build Coastguard Worker //"[REG] is optional buffer where deleted/yanked text goes REG can be
1237*cf5a6c84SAndroid Build Coastguard Worker // atleast 0-9, a-z or default "
1238*cf5a6c84SAndroid Build Coastguard Worker //[COUNT] is optional multiplier for cmd execution if there is 2 COUNT
1239*cf5a6c84SAndroid Build Coastguard Worker // operations they are multiplied together
1240*cf5a6c84SAndroid Build Coastguard Worker //CMD is operation to be executed
1241*cf5a6c84SAndroid Build Coastguard Worker //(MOV) is movement operation, some CMD does not require MOV and some
1242*cf5a6c84SAndroid Build Coastguard Worker // have special cases such as dd, yy, also movements can work without
1243*cf5a6c84SAndroid Build Coastguard Worker // CMD
1244*cf5a6c84SAndroid Build Coastguard Worker //ex commands can be even more complicated than this....
1245*cf5a6c84SAndroid Build Coastguard Worker
1246*cf5a6c84SAndroid Build Coastguard Worker //special cases without MOV and such
1247*cf5a6c84SAndroid Build Coastguard Worker struct vi_special_param {
1248*cf5a6c84SAndroid Build Coastguard Worker const char *cmd;
1249*cf5a6c84SAndroid Build Coastguard Worker int (*vi_special)(char, int, int);//REG,COUNT0,COUNT1
1250*cf5a6c84SAndroid Build Coastguard Worker } vi_special[] = {
1251*cf5a6c84SAndroid Build Coastguard Worker {"D", &vi_D},
1252*cf5a6c84SAndroid Build Coastguard Worker {"I", &vi_I},
1253*cf5a6c84SAndroid Build Coastguard Worker {"J", &vi_join},
1254*cf5a6c84SAndroid Build Coastguard Worker {"O", &vi_O},
1255*cf5a6c84SAndroid Build Coastguard Worker {"N", &vi_find_prev},
1256*cf5a6c84SAndroid Build Coastguard Worker {"n", &vi_find_next},
1257*cf5a6c84SAndroid Build Coastguard Worker {"o", &vi_o},
1258*cf5a6c84SAndroid Build Coastguard Worker {"p", &vi_push},
1259*cf5a6c84SAndroid Build Coastguard Worker {"x", &vi_x},
1260*cf5a6c84SAndroid Build Coastguard Worker {"dd", &vi_dd},
1261*cf5a6c84SAndroid Build Coastguard Worker {"yy", &vi_yy},
1262*cf5a6c84SAndroid Build Coastguard Worker };
1263*cf5a6c84SAndroid Build Coastguard Worker //there is around ~47 vi moves, some of them need extra params such as f and '
1264*cf5a6c84SAndroid Build Coastguard Worker struct vi_mov_param {
1265*cf5a6c84SAndroid Build Coastguard Worker const char* mov;
1266*cf5a6c84SAndroid Build Coastguard Worker unsigned flags;
1267*cf5a6c84SAndroid Build Coastguard Worker int (*vi_mov)(int, int, char*);//COUNT0,COUNT1,params
1268*cf5a6c84SAndroid Build Coastguard Worker } vi_movs[] = {
1269*cf5a6c84SAndroid Build Coastguard Worker {"0", 0, &vi_zero},
1270*cf5a6c84SAndroid Build Coastguard Worker {"b", 0, &vi_movb},
1271*cf5a6c84SAndroid Build Coastguard Worker {"e", 0, &vi_move},
1272*cf5a6c84SAndroid Build Coastguard Worker {"G", 0, &vi_go},
1273*cf5a6c84SAndroid Build Coastguard Worker {"H", 0, &vi_H},
1274*cf5a6c84SAndroid Build Coastguard Worker {"h", 0, &cur_left},
1275*cf5a6c84SAndroid Build Coastguard Worker {"j", 0, &cur_down},
1276*cf5a6c84SAndroid Build Coastguard Worker {"k", 0, &cur_up},
1277*cf5a6c84SAndroid Build Coastguard Worker {"L", 0, &vi_L},
1278*cf5a6c84SAndroid Build Coastguard Worker {"l", 0, &cur_right},
1279*cf5a6c84SAndroid Build Coastguard Worker {"M", 0, &vi_M},
1280*cf5a6c84SAndroid Build Coastguard Worker {"w", 0, &vi_movw},
1281*cf5a6c84SAndroid Build Coastguard Worker {"$", 0, &vi_dollar},
1282*cf5a6c84SAndroid Build Coastguard Worker {"f", 1, &vi_find_c},
1283*cf5a6c84SAndroid Build Coastguard Worker {"F", 1, &vi_find_cb},
1284*cf5a6c84SAndroid Build Coastguard Worker };
1285*cf5a6c84SAndroid Build Coastguard Worker // change and delete unfortunately behave different depending on move command,
1286*cf5a6c84SAndroid Build Coastguard Worker // such as ce cw are same, but dw and de are not...
1287*cf5a6c84SAndroid Build Coastguard Worker // also dw stops at w position and cw seem to stop at e pos+1...
1288*cf5a6c84SAndroid Build Coastguard Worker // so after movement we need to possibly set up some flags before executing
1289*cf5a6c84SAndroid Build Coastguard Worker // command, and command needs to adjust...
1290*cf5a6c84SAndroid Build Coastguard Worker struct vi_cmd_param {
1291*cf5a6c84SAndroid Build Coastguard Worker const char* cmd;
1292*cf5a6c84SAndroid Build Coastguard Worker unsigned flags;
1293*cf5a6c84SAndroid Build Coastguard Worker int (*vi_cmd)(char, size_t, int);//REG,from,FLAGS
1294*cf5a6c84SAndroid Build Coastguard Worker } vi_cmds[] = {
1295*cf5a6c84SAndroid Build Coastguard Worker {"c", 1, &vi_change},
1296*cf5a6c84SAndroid Build Coastguard Worker {"d", 1, &vi_delete},
1297*cf5a6c84SAndroid Build Coastguard Worker {"y", 1, &vi_yank},
1298*cf5a6c84SAndroid Build Coastguard Worker };
1299*cf5a6c84SAndroid Build Coastguard Worker
run_vi_cmd(char * cmd)1300*cf5a6c84SAndroid Build Coastguard Worker static int run_vi_cmd(char *cmd)
1301*cf5a6c84SAndroid Build Coastguard Worker {
1302*cf5a6c84SAndroid Build Coastguard Worker int i = 0, val = 0;
1303*cf5a6c84SAndroid Build Coastguard Worker char *cmd_e;
1304*cf5a6c84SAndroid Build Coastguard Worker int (*vi_cmd)(char, size_t, int) = 0, (*vi_mov)(int, int, char*) = 0;
1305*cf5a6c84SAndroid Build Coastguard Worker
1306*cf5a6c84SAndroid Build Coastguard Worker TT.count0 = 0, TT.count1 = 0, TT.vi_mov_flag = 0;
1307*cf5a6c84SAndroid Build Coastguard Worker TT.vi_reg = '"';
1308*cf5a6c84SAndroid Build Coastguard Worker
1309*cf5a6c84SAndroid Build Coastguard Worker if (*cmd == '"') {
1310*cf5a6c84SAndroid Build Coastguard Worker cmd++;
1311*cf5a6c84SAndroid Build Coastguard Worker TT.vi_reg = *cmd++; //TODO check validity
1312*cf5a6c84SAndroid Build Coastguard Worker }
1313*cf5a6c84SAndroid Build Coastguard Worker errno = 0;
1314*cf5a6c84SAndroid Build Coastguard Worker val = strtol(cmd, &cmd_e, 10);
1315*cf5a6c84SAndroid Build Coastguard Worker if (errno || val == 0) val = 1, TT.vi_mov_flag |= 0x40000000;
1316*cf5a6c84SAndroid Build Coastguard Worker else cmd = cmd_e;
1317*cf5a6c84SAndroid Build Coastguard Worker TT.count0 = val;
1318*cf5a6c84SAndroid Build Coastguard Worker
1319*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i < ARRAY_LEN(vi_special); i++)
1320*cf5a6c84SAndroid Build Coastguard Worker if (strstr(cmd, vi_special[i].cmd))
1321*cf5a6c84SAndroid Build Coastguard Worker return vi_special[i].vi_special(TT.vi_reg, TT.count0, TT.count1);
1322*cf5a6c84SAndroid Build Coastguard Worker
1323*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i < ARRAY_LEN(vi_cmds); i++) {
1324*cf5a6c84SAndroid Build Coastguard Worker if (!strncmp(cmd, vi_cmds[i].cmd, strlen(vi_cmds[i].cmd))) {
1325*cf5a6c84SAndroid Build Coastguard Worker vi_cmd = vi_cmds[i].vi_cmd;
1326*cf5a6c84SAndroid Build Coastguard Worker cmd += strlen(vi_cmds[i].cmd);
1327*cf5a6c84SAndroid Build Coastguard Worker break;
1328*cf5a6c84SAndroid Build Coastguard Worker }
1329*cf5a6c84SAndroid Build Coastguard Worker }
1330*cf5a6c84SAndroid Build Coastguard Worker errno = 0;
1331*cf5a6c84SAndroid Build Coastguard Worker val = strtol(cmd, &cmd_e, 10);
1332*cf5a6c84SAndroid Build Coastguard Worker if (errno || val == 0) val = 1;
1333*cf5a6c84SAndroid Build Coastguard Worker else cmd = cmd_e;
1334*cf5a6c84SAndroid Build Coastguard Worker TT.count1 = val;
1335*cf5a6c84SAndroid Build Coastguard Worker
1336*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i < ARRAY_LEN(vi_movs); i++) {
1337*cf5a6c84SAndroid Build Coastguard Worker if (!strncmp(cmd, vi_movs[i].mov, strlen(vi_movs[i].mov))) {
1338*cf5a6c84SAndroid Build Coastguard Worker vi_mov = vi_movs[i].vi_mov;
1339*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mov_flag |= vi_movs[i].flags;
1340*cf5a6c84SAndroid Build Coastguard Worker cmd++;
1341*cf5a6c84SAndroid Build Coastguard Worker if (TT.vi_mov_flag&1 && !(*cmd)) return 0;
1342*cf5a6c84SAndroid Build Coastguard Worker break;
1343*cf5a6c84SAndroid Build Coastguard Worker }
1344*cf5a6c84SAndroid Build Coastguard Worker }
1345*cf5a6c84SAndroid Build Coastguard Worker if (vi_mov) {
1346*cf5a6c84SAndroid Build Coastguard Worker int prev_cursor = TT.cursor;
1347*cf5a6c84SAndroid Build Coastguard Worker if (vi_mov(TT.count0, TT.count1, cmd)) {
1348*cf5a6c84SAndroid Build Coastguard Worker if (vi_cmd) return (vi_cmd(TT.vi_reg, prev_cursor, TT.vi_mov_flag));
1349*cf5a6c84SAndroid Build Coastguard Worker else return 1;
1350*cf5a6c84SAndroid Build Coastguard Worker } else return 0; //return some error
1351*cf5a6c84SAndroid Build Coastguard Worker }
1352*cf5a6c84SAndroid Build Coastguard Worker return 0;
1353*cf5a6c84SAndroid Build Coastguard Worker }
1354*cf5a6c84SAndroid Build Coastguard Worker
1355*cf5a6c84SAndroid Build Coastguard Worker
1356*cf5a6c84SAndroid Build Coastguard Worker static void draw_page();
1357*cf5a6c84SAndroid Build Coastguard Worker
get_endline(void)1358*cf5a6c84SAndroid Build Coastguard Worker static int get_endline(void)
1359*cf5a6c84SAndroid Build Coastguard Worker {
1360*cf5a6c84SAndroid Build Coastguard Worker int cln, rln;
1361*cf5a6c84SAndroid Build Coastguard Worker
1362*cf5a6c84SAndroid Build Coastguard Worker draw_page();
1363*cf5a6c84SAndroid Build Coastguard Worker cln = TT.cur_row+1;
1364*cf5a6c84SAndroid Build Coastguard Worker run_vi_cmd("G");
1365*cf5a6c84SAndroid Build Coastguard Worker draw_page();
1366*cf5a6c84SAndroid Build Coastguard Worker rln = TT.cur_row+1;
1367*cf5a6c84SAndroid Build Coastguard Worker run_vi_cmd(xmprintf("%dG", cln));
1368*cf5a6c84SAndroid Build Coastguard Worker
1369*cf5a6c84SAndroid Build Coastguard Worker return rln+1;
1370*cf5a6c84SAndroid Build Coastguard Worker }
1371*cf5a6c84SAndroid Build Coastguard Worker
1372*cf5a6c84SAndroid Build Coastguard Worker // Return non-zero to exit.
run_ex_cmd(char * cmd)1373*cf5a6c84SAndroid Build Coastguard Worker static int run_ex_cmd(char *cmd)
1374*cf5a6c84SAndroid Build Coastguard Worker {
1375*cf5a6c84SAndroid Build Coastguard Worker int startline = 1, ofst = 0, endline;
1376*cf5a6c84SAndroid Build Coastguard Worker
1377*cf5a6c84SAndroid Build Coastguard Worker if (*cmd == '/' || *cmd == '\?') search_str(cmd+1, *cmd == '/' ? 0 : 1);
1378*cf5a6c84SAndroid Build Coastguard Worker else if (*cmd == ':') {
1379*cf5a6c84SAndroid Build Coastguard Worker if (cmd[1] == 'q') {
1380*cf5a6c84SAndroid Build Coastguard Worker if (cmd[2] != '!' && modified())
1381*cf5a6c84SAndroid Build Coastguard Worker show_error("Unsaved changes (\"q!\" to ignore)");
1382*cf5a6c84SAndroid Build Coastguard Worker else return 1;
1383*cf5a6c84SAndroid Build Coastguard Worker } else if (!strncmp(cmd+1, "w ", 2)) write_file(&cmd[3]);
1384*cf5a6c84SAndroid Build Coastguard Worker else if (!strncmp(cmd+1, "wq", 2)) {
1385*cf5a6c84SAndroid Build Coastguard Worker if (write_file(0)) return 1;
1386*cf5a6c84SAndroid Build Coastguard Worker show_error("Unsaved changes (\"q!\" to ignore)");
1387*cf5a6c84SAndroid Build Coastguard Worker } else if (!strncmp(cmd+1, "w", 1)) write_file(0);
1388*cf5a6c84SAndroid Build Coastguard Worker
1389*cf5a6c84SAndroid Build Coastguard Worker else if (!strncmp(cmd+1, "set list", sizeof("set list"))) {
1390*cf5a6c84SAndroid Build Coastguard Worker TT.list = 1;
1391*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mov_flag |= 0x30000000;
1392*cf5a6c84SAndroid Build Coastguard Worker } else if (!strncmp(cmd+1, "set nolist", sizeof("set nolist"))) {
1393*cf5a6c84SAndroid Build Coastguard Worker TT.list = 0;
1394*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mov_flag |= 0x30000000;
1395*cf5a6c84SAndroid Build Coastguard Worker }
1396*cf5a6c84SAndroid Build Coastguard Worker
1397*cf5a6c84SAndroid Build Coastguard Worker else if (cmd[1] == 'd') {
1398*cf5a6c84SAndroid Build Coastguard Worker run_vi_cmd("dd");
1399*cf5a6c84SAndroid Build Coastguard Worker cur_up(1, 1, 0);
1400*cf5a6c84SAndroid Build Coastguard Worker } else if (cmd[1] == 'j') run_vi_cmd("J");
1401*cf5a6c84SAndroid Build Coastguard Worker else if (cmd[1] == 'g' || cmd[1] == 'v') {
1402*cf5a6c84SAndroid Build Coastguard Worker char *rgx = xmalloc(strlen(cmd));
1403*cf5a6c84SAndroid Build Coastguard Worker int el = get_endline(), ln = 0, vorg = (cmd[1] == 'v' ? REG_NOMATCH : 0);
1404*cf5a6c84SAndroid Build Coastguard Worker if (sscanf(cmd+2, "/%[^/]/%[^\ng]", rgx, cmd+1) == 2) {
1405*cf5a6c84SAndroid Build Coastguard Worker regex_t rgxc;
1406*cf5a6c84SAndroid Build Coastguard Worker if (!regcomp(&rgxc, rgx, 0)) {
1407*cf5a6c84SAndroid Build Coastguard Worker cmd[0] = ':';
1408*cf5a6c84SAndroid Build Coastguard Worker
1409*cf5a6c84SAndroid Build Coastguard Worker for (; ln < el; ln++) {
1410*cf5a6c84SAndroid Build Coastguard Worker run_vi_cmd("yy");
1411*cf5a6c84SAndroid Build Coastguard Worker if (regexec(&rgxc, TT.yank.data, 0, 0, 0) == vorg) run_ex_cmd(cmd);
1412*cf5a6c84SAndroid Build Coastguard Worker cur_down(1, 1, 0);
1413*cf5a6c84SAndroid Build Coastguard Worker }
1414*cf5a6c84SAndroid Build Coastguard Worker
1415*cf5a6c84SAndroid Build Coastguard Worker // Reset Frame
1416*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mov_flag |= 0x30000000;
1417*cf5a6c84SAndroid Build Coastguard Worker }
1418*cf5a6c84SAndroid Build Coastguard Worker regfree(&rgxc);
1419*cf5a6c84SAndroid Build Coastguard Worker }
1420*cf5a6c84SAndroid Build Coastguard Worker free(rgx);
1421*cf5a6c84SAndroid Build Coastguard Worker }
1422*cf5a6c84SAndroid Build Coastguard Worker
1423*cf5a6c84SAndroid Build Coastguard Worker // Line Ranges
1424*cf5a6c84SAndroid Build Coastguard Worker else if (cmd[1] >= '0' && cmd[1] <= '9') {
1425*cf5a6c84SAndroid Build Coastguard Worker if (strstr(cmd, ",")) {
1426*cf5a6c84SAndroid Build Coastguard Worker sscanf(cmd, ":%d,%d%[^\n]", &startline, &endline, cmd+2);
1427*cf5a6c84SAndroid Build Coastguard Worker ofst = 1;
1428*cf5a6c84SAndroid Build Coastguard Worker } else run_vi_cmd(xmprintf("%dG", atoi(cmd+1)));
1429*cf5a6c84SAndroid Build Coastguard Worker } else if (cmd[1] == '$') run_vi_cmd("G");
1430*cf5a6c84SAndroid Build Coastguard Worker else if (cmd[1] == '%') {
1431*cf5a6c84SAndroid Build Coastguard Worker endline = get_endline();
1432*cf5a6c84SAndroid Build Coastguard Worker ofst = 1;
1433*cf5a6c84SAndroid Build Coastguard Worker } else show_error("unknown command '%s'",cmd+1);
1434*cf5a6c84SAndroid Build Coastguard Worker
1435*cf5a6c84SAndroid Build Coastguard Worker if (ofst) {
1436*cf5a6c84SAndroid Build Coastguard Worker int cline = TT.cur_row+1;
1437*cf5a6c84SAndroid Build Coastguard Worker
1438*cf5a6c84SAndroid Build Coastguard Worker cmd[ofst] = ':';
1439*cf5a6c84SAndroid Build Coastguard Worker for (; startline <= endline; startline++) {
1440*cf5a6c84SAndroid Build Coastguard Worker run_ex_cmd(cmd+ofst);
1441*cf5a6c84SAndroid Build Coastguard Worker cur_down(1, 1, 0);
1442*cf5a6c84SAndroid Build Coastguard Worker }
1443*cf5a6c84SAndroid Build Coastguard Worker run_vi_cmd(xmprintf("%dG", cline));
1444*cf5a6c84SAndroid Build Coastguard Worker // Screen Reset
1445*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mov_flag |= 0x30000000;
1446*cf5a6c84SAndroid Build Coastguard Worker }
1447*cf5a6c84SAndroid Build Coastguard Worker }
1448*cf5a6c84SAndroid Build Coastguard Worker return 0;
1449*cf5a6c84SAndroid Build Coastguard Worker }
1450*cf5a6c84SAndroid Build Coastguard Worker
vi_crunch(FILE * out,int cols,int wc)1451*cf5a6c84SAndroid Build Coastguard Worker static int vi_crunch(FILE *out, int cols, int wc)
1452*cf5a6c84SAndroid Build Coastguard Worker {
1453*cf5a6c84SAndroid Build Coastguard Worker int ret = 0;
1454*cf5a6c84SAndroid Build Coastguard Worker if (wc < 32 && TT.list) {
1455*cf5a6c84SAndroid Build Coastguard Worker xputsn("\e[1m");
1456*cf5a6c84SAndroid Build Coastguard Worker ret = crunch_escape(out,cols,wc);
1457*cf5a6c84SAndroid Build Coastguard Worker xputsn("\e[m");
1458*cf5a6c84SAndroid Build Coastguard Worker } else if (wc == '\t') {
1459*cf5a6c84SAndroid Build Coastguard Worker if (out) {
1460*cf5a6c84SAndroid Build Coastguard Worker int i = TT.tabstop;
1461*cf5a6c84SAndroid Build Coastguard Worker for (;i--;) fputs(" ", out);
1462*cf5a6c84SAndroid Build Coastguard Worker }
1463*cf5a6c84SAndroid Build Coastguard Worker ret = TT.tabstop;
1464*cf5a6c84SAndroid Build Coastguard Worker } else if (wc == '\n') return 0;
1465*cf5a6c84SAndroid Build Coastguard Worker return ret;
1466*cf5a6c84SAndroid Build Coastguard Worker }
1467*cf5a6c84SAndroid Build Coastguard Worker
1468*cf5a6c84SAndroid Build Coastguard Worker //crunch_str with n bytes restriction for printing substrings or
1469*cf5a6c84SAndroid Build Coastguard Worker //non null terminated strings
crunch_nstr(char ** str,int width,int n,FILE * out,char * escmore,int (* escout)(FILE * out,int cols,int wc))1470*cf5a6c84SAndroid Build Coastguard Worker static int crunch_nstr(char **str, int width, int n, FILE *out, char *escmore,
1471*cf5a6c84SAndroid Build Coastguard Worker int (*escout)(FILE *out, int cols, int wc))
1472*cf5a6c84SAndroid Build Coastguard Worker {
1473*cf5a6c84SAndroid Build Coastguard Worker int columns = 0, col, bytes;
1474*cf5a6c84SAndroid Build Coastguard Worker char *start, *end;
1475*cf5a6c84SAndroid Build Coastguard Worker unsigned wc;
1476*cf5a6c84SAndroid Build Coastguard Worker
1477*cf5a6c84SAndroid Build Coastguard Worker for (end = start = *str; *end && n>0; columns += col, end += bytes, n -= bytes) {
1478*cf5a6c84SAndroid Build Coastguard Worker if ((bytes = utf8towc(&wc, end, 4))>0 && (col = wcwidth(wc))>=0) {
1479*cf5a6c84SAndroid Build Coastguard Worker if (!escmore || wc>255 || !strchr(escmore, wc)) {
1480*cf5a6c84SAndroid Build Coastguard Worker if (width-columns<col) break;
1481*cf5a6c84SAndroid Build Coastguard Worker if (out) fwrite(end, bytes, 1, out);
1482*cf5a6c84SAndroid Build Coastguard Worker
1483*cf5a6c84SAndroid Build Coastguard Worker continue;
1484*cf5a6c84SAndroid Build Coastguard Worker }
1485*cf5a6c84SAndroid Build Coastguard Worker }
1486*cf5a6c84SAndroid Build Coastguard Worker
1487*cf5a6c84SAndroid Build Coastguard Worker if (bytes<1) {
1488*cf5a6c84SAndroid Build Coastguard Worker bytes = 1;
1489*cf5a6c84SAndroid Build Coastguard Worker wc = *end;
1490*cf5a6c84SAndroid Build Coastguard Worker }
1491*cf5a6c84SAndroid Build Coastguard Worker col = width-columns;
1492*cf5a6c84SAndroid Build Coastguard Worker if (col<1) break;
1493*cf5a6c84SAndroid Build Coastguard Worker if (escout) {
1494*cf5a6c84SAndroid Build Coastguard Worker if ((col = escout(out, col, wc))<0) break;
1495*cf5a6c84SAndroid Build Coastguard Worker } else if (out) fwrite(end, 1, bytes, out);
1496*cf5a6c84SAndroid Build Coastguard Worker }
1497*cf5a6c84SAndroid Build Coastguard Worker *str = end;
1498*cf5a6c84SAndroid Build Coastguard Worker
1499*cf5a6c84SAndroid Build Coastguard Worker return columns;
1500*cf5a6c84SAndroid Build Coastguard Worker }
1501*cf5a6c84SAndroid Build Coastguard Worker
draw_page()1502*cf5a6c84SAndroid Build Coastguard Worker static void draw_page()
1503*cf5a6c84SAndroid Build Coastguard Worker {
1504*cf5a6c84SAndroid Build Coastguard Worker unsigned y = 0;
1505*cf5a6c84SAndroid Build Coastguard Worker int x = 0, bytes = 0;
1506*cf5a6c84SAndroid Build Coastguard Worker char *line = 0, *end = 0;
1507*cf5a6c84SAndroid Build Coastguard Worker //screen coordinates for cursor
1508*cf5a6c84SAndroid Build Coastguard Worker int cy_scr = 0, cx_scr = 0;
1509*cf5a6c84SAndroid Build Coastguard Worker //variables used only for cursor handling
1510*cf5a6c84SAndroid Build Coastguard Worker int aw = 0, iw = 0, clip = 0, margin = 8, scroll = 0, redraw = 0, SSOL, SOL;
1511*cf5a6c84SAndroid Build Coastguard Worker
1512*cf5a6c84SAndroid Build Coastguard Worker adjust_screen_buffer();
1513*cf5a6c84SAndroid Build Coastguard Worker //redraw = 3; //force full redraw
1514*cf5a6c84SAndroid Build Coastguard Worker redraw = (TT.vi_mov_flag & 0x30000000)>>28;
1515*cf5a6c84SAndroid Build Coastguard Worker
1516*cf5a6c84SAndroid Build Coastguard Worker scroll = TT.drawn_row-TT.scr_row;
1517*cf5a6c84SAndroid Build Coastguard Worker if (TT.drawn_row<0 || TT.cur_row<0 || TT.scr_row<0) redraw = 3;
1518*cf5a6c84SAndroid Build Coastguard Worker else if (abs(scroll)>TT.screen_height/2) redraw = 3;
1519*cf5a6c84SAndroid Build Coastguard Worker
1520*cf5a6c84SAndroid Build Coastguard Worker xputsn("\e[H"); // jump to top left
1521*cf5a6c84SAndroid Build Coastguard Worker if (redraw&2) xputsn("\e[2J\e[H"); //clear screen
1522*cf5a6c84SAndroid Build Coastguard Worker else if (scroll>0) printf("\e[%dL", scroll); //scroll up
1523*cf5a6c84SAndroid Build Coastguard Worker else if (scroll<0) printf("\e[%dM", -scroll); //scroll down
1524*cf5a6c84SAndroid Build Coastguard Worker
1525*cf5a6c84SAndroid Build Coastguard Worker SOL = text_sol(TT.cursor);
1526*cf5a6c84SAndroid Build Coastguard Worker bytes = text_getline(toybuf, SOL, ARRAY_LEN(toybuf));
1527*cf5a6c84SAndroid Build Coastguard Worker line = toybuf;
1528*cf5a6c84SAndroid Build Coastguard Worker
1529*cf5a6c84SAndroid Build Coastguard Worker for (SSOL = TT.screen, y = 0; SSOL < SOL; y++) SSOL = text_nsol(SSOL);
1530*cf5a6c84SAndroid Build Coastguard Worker
1531*cf5a6c84SAndroid Build Coastguard Worker cy_scr = y;
1532*cf5a6c84SAndroid Build Coastguard Worker
1533*cf5a6c84SAndroid Build Coastguard Worker // draw cursor row
1534*cf5a6c84SAndroid Build Coastguard Worker /////////////////////////////////////////////////////////////
1535*cf5a6c84SAndroid Build Coastguard Worker // for long lines line starts to scroll when cursor hits margin
1536*cf5a6c84SAndroid Build Coastguard Worker bytes = TT.cursor-SOL; // TT.cur_col;
1537*cf5a6c84SAndroid Build Coastguard Worker end = line;
1538*cf5a6c84SAndroid Build Coastguard Worker
1539*cf5a6c84SAndroid Build Coastguard Worker
1540*cf5a6c84SAndroid Build Coastguard Worker printf("\e[%u;0H\e[2K", y+1);
1541*cf5a6c84SAndroid Build Coastguard Worker // find cursor position
1542*cf5a6c84SAndroid Build Coastguard Worker aw = crunch_nstr(&end, INT_MAX, bytes, 0, "\t\n", vi_crunch);
1543*cf5a6c84SAndroid Build Coastguard Worker
1544*cf5a6c84SAndroid Build Coastguard Worker // if we need to render text that is not inserted to buffer yet
1545*cf5a6c84SAndroid Build Coastguard Worker if (TT.vi_mode == 2 && TT.il->len) {
1546*cf5a6c84SAndroid Build Coastguard Worker char* iend = TT.il->data; //input end
1547*cf5a6c84SAndroid Build Coastguard Worker x = 0;
1548*cf5a6c84SAndroid Build Coastguard Worker // find insert end position
1549*cf5a6c84SAndroid Build Coastguard Worker iw = crunch_str(&iend, INT_MAX, 0, "\t\n", vi_crunch);
1550*cf5a6c84SAndroid Build Coastguard Worker clip = (aw+iw) - TT.screen_width+margin;
1551*cf5a6c84SAndroid Build Coastguard Worker
1552*cf5a6c84SAndroid Build Coastguard Worker // if clipped area is bigger than text before insert
1553*cf5a6c84SAndroid Build Coastguard Worker if (clip > aw) {
1554*cf5a6c84SAndroid Build Coastguard Worker clip -= aw;
1555*cf5a6c84SAndroid Build Coastguard Worker iend = TT.il->data;
1556*cf5a6c84SAndroid Build Coastguard Worker
1557*cf5a6c84SAndroid Build Coastguard Worker iw -= crunch_str(&iend, clip, 0, "\t\n", vi_crunch);
1558*cf5a6c84SAndroid Build Coastguard Worker x = crunch_str(&iend, iw, stdout, "\t\n", vi_crunch);
1559*cf5a6c84SAndroid Build Coastguard Worker } else {
1560*cf5a6c84SAndroid Build Coastguard Worker iend = TT.il->data;
1561*cf5a6c84SAndroid Build Coastguard Worker end = line;
1562*cf5a6c84SAndroid Build Coastguard Worker
1563*cf5a6c84SAndroid Build Coastguard Worker //if clipped area is substring from cursor row start
1564*cf5a6c84SAndroid Build Coastguard Worker aw -= crunch_nstr(&end, clip, bytes, 0, "\t\n", vi_crunch);
1565*cf5a6c84SAndroid Build Coastguard Worker x = crunch_str(&end, aw, stdout, "\t\n", vi_crunch);
1566*cf5a6c84SAndroid Build Coastguard Worker x += crunch_str(&iend, iw, stdout, "\t\n", vi_crunch);
1567*cf5a6c84SAndroid Build Coastguard Worker }
1568*cf5a6c84SAndroid Build Coastguard Worker }
1569*cf5a6c84SAndroid Build Coastguard Worker // when not inserting but still need to keep cursor inside screen
1570*cf5a6c84SAndroid Build Coastguard Worker // margin area
1571*cf5a6c84SAndroid Build Coastguard Worker else if ( aw+margin > TT.screen_width) {
1572*cf5a6c84SAndroid Build Coastguard Worker clip = aw-TT.screen_width+margin;
1573*cf5a6c84SAndroid Build Coastguard Worker end = line;
1574*cf5a6c84SAndroid Build Coastguard Worker aw -= crunch_nstr(&end, clip, bytes, 0, "\t\n", vi_crunch);
1575*cf5a6c84SAndroid Build Coastguard Worker x = crunch_str(&end, aw, stdout, "\t\n", vi_crunch);
1576*cf5a6c84SAndroid Build Coastguard Worker }
1577*cf5a6c84SAndroid Build Coastguard Worker else {
1578*cf5a6c84SAndroid Build Coastguard Worker end = line;
1579*cf5a6c84SAndroid Build Coastguard Worker x = crunch_nstr(&end, aw, bytes, stdout, "\t\n", vi_crunch);
1580*cf5a6c84SAndroid Build Coastguard Worker }
1581*cf5a6c84SAndroid Build Coastguard Worker cx_scr = x;
1582*cf5a6c84SAndroid Build Coastguard Worker cy_scr = y;
1583*cf5a6c84SAndroid Build Coastguard Worker x += crunch_str(&end, TT.screen_width-x, stdout, "\t\n", vi_crunch);
1584*cf5a6c84SAndroid Build Coastguard Worker
1585*cf5a6c84SAndroid Build Coastguard Worker // start drawing all other rows that needs update
1586*cf5a6c84SAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////
1587*cf5a6c84SAndroid Build Coastguard Worker y = 0, SSOL = TT.screen, line = toybuf;
1588*cf5a6c84SAndroid Build Coastguard Worker bytes = text_getline(toybuf, SSOL, ARRAY_LEN(toybuf));
1589*cf5a6c84SAndroid Build Coastguard Worker
1590*cf5a6c84SAndroid Build Coastguard Worker // if we moved around in long line might need to redraw everything
1591*cf5a6c84SAndroid Build Coastguard Worker if (clip != TT.drawn_col) redraw = 3;
1592*cf5a6c84SAndroid Build Coastguard Worker
1593*cf5a6c84SAndroid Build Coastguard Worker for (; y < TT.screen_height; y++ ) {
1594*cf5a6c84SAndroid Build Coastguard Worker int draw_line = 0;
1595*cf5a6c84SAndroid Build Coastguard Worker if (SSOL == SOL) {
1596*cf5a6c84SAndroid Build Coastguard Worker line = toybuf;
1597*cf5a6c84SAndroid Build Coastguard Worker SSOL += bytes+1;
1598*cf5a6c84SAndroid Build Coastguard Worker bytes = text_getline(line, SSOL, ARRAY_LEN(toybuf));
1599*cf5a6c84SAndroid Build Coastguard Worker continue;
1600*cf5a6c84SAndroid Build Coastguard Worker } else if (redraw) draw_line++;
1601*cf5a6c84SAndroid Build Coastguard Worker else if (scroll<0 && TT.screen_height-y-1<-scroll)
1602*cf5a6c84SAndroid Build Coastguard Worker scroll++, draw_line++;
1603*cf5a6c84SAndroid Build Coastguard Worker else if (scroll>0) scroll--, draw_line++;
1604*cf5a6c84SAndroid Build Coastguard Worker
1605*cf5a6c84SAndroid Build Coastguard Worker printf("\e[%u;0H", y+1);
1606*cf5a6c84SAndroid Build Coastguard Worker if (draw_line) {
1607*cf5a6c84SAndroid Build Coastguard Worker printf("\e[2K");
1608*cf5a6c84SAndroid Build Coastguard Worker if (line && strlen(line)) {
1609*cf5a6c84SAndroid Build Coastguard Worker aw = crunch_nstr(&line, clip, bytes, 0, "\t\n", vi_crunch);
1610*cf5a6c84SAndroid Build Coastguard Worker crunch_str(&line, TT.screen_width-1, stdout, "\t\n", vi_crunch);
1611*cf5a6c84SAndroid Build Coastguard Worker if ( *line ) printf("@");
1612*cf5a6c84SAndroid Build Coastguard Worker } else printf("\e[2m~\e[m");
1613*cf5a6c84SAndroid Build Coastguard Worker }
1614*cf5a6c84SAndroid Build Coastguard Worker if (SSOL+bytes < TT.filesize) {
1615*cf5a6c84SAndroid Build Coastguard Worker line = toybuf;
1616*cf5a6c84SAndroid Build Coastguard Worker SSOL += bytes+1;
1617*cf5a6c84SAndroid Build Coastguard Worker bytes = text_getline(line, SSOL, ARRAY_LEN(toybuf));
1618*cf5a6c84SAndroid Build Coastguard Worker } else line = 0;
1619*cf5a6c84SAndroid Build Coastguard Worker }
1620*cf5a6c84SAndroid Build Coastguard Worker
1621*cf5a6c84SAndroid Build Coastguard Worker TT.drawn_row = TT.scr_row, TT.drawn_col = clip;
1622*cf5a6c84SAndroid Build Coastguard Worker
1623*cf5a6c84SAndroid Build Coastguard Worker // Finished updating visual area, show status line.
1624*cf5a6c84SAndroid Build Coastguard Worker printf("\e[%u;0H\e[2K", TT.screen_height+1);
1625*cf5a6c84SAndroid Build Coastguard Worker if (TT.vi_mode == 2) printf("\e[1m-- INSERT --\e[m");
1626*cf5a6c84SAndroid Build Coastguard Worker if (!TT.vi_mode) {
1627*cf5a6c84SAndroid Build Coastguard Worker cx_scr = printf("%s", TT.il->data);
1628*cf5a6c84SAndroid Build Coastguard Worker cy_scr = TT.screen_height;
1629*cf5a6c84SAndroid Build Coastguard Worker *toybuf = 0;
1630*cf5a6c84SAndroid Build Coastguard Worker } else {
1631*cf5a6c84SAndroid Build Coastguard Worker // TODO: the row,col display doesn't show the cursor column
1632*cf5a6c84SAndroid Build Coastguard Worker // TODO: real vi shows the percentage by lines, not bytes
1633*cf5a6c84SAndroid Build Coastguard Worker sprintf(toybuf, "%zu/%zuC %zu%% %d,%d", TT.cursor, TT.filesize,
1634*cf5a6c84SAndroid Build Coastguard Worker (100*TT.cursor)/(TT.filesize ? : 1), TT.cur_row+1, TT.cur_col+1);
1635*cf5a6c84SAndroid Build Coastguard Worker if (TT.cur_col != cx_scr) sprintf(toybuf+strlen(toybuf),"-%d", cx_scr+1);
1636*cf5a6c84SAndroid Build Coastguard Worker }
1637*cf5a6c84SAndroid Build Coastguard Worker printf("\e[%u;%uH%s\e[%u;%uH", TT.screen_height+1,
1638*cf5a6c84SAndroid Build Coastguard Worker (int) (1+TT.screen_width-strlen(toybuf)),
1639*cf5a6c84SAndroid Build Coastguard Worker toybuf, cy_scr+1, cx_scr+1);
1640*cf5a6c84SAndroid Build Coastguard Worker fflush(0);
1641*cf5a6c84SAndroid Build Coastguard Worker xferror(stdout);
1642*cf5a6c84SAndroid Build Coastguard Worker }
1643*cf5a6c84SAndroid Build Coastguard Worker
vi_main(void)1644*cf5a6c84SAndroid Build Coastguard Worker void vi_main(void)
1645*cf5a6c84SAndroid Build Coastguard Worker {
1646*cf5a6c84SAndroid Build Coastguard Worker char keybuf[16] = {0}, vi_buf[16] = {0}, utf8_code[8] = {0};
1647*cf5a6c84SAndroid Build Coastguard Worker int utf8_dec_p = 0, vi_buf_pos = 0;
1648*cf5a6c84SAndroid Build Coastguard Worker FILE *script = TT.s ? xfopen(TT.s, "r") : 0;
1649*cf5a6c84SAndroid Build Coastguard Worker
1650*cf5a6c84SAndroid Build Coastguard Worker TT.il = xzalloc(sizeof(struct str_line));
1651*cf5a6c84SAndroid Build Coastguard Worker TT.il->data = xzalloc(TT.il->alloc = 80);
1652*cf5a6c84SAndroid Build Coastguard Worker TT.yank.data = xzalloc(TT.yank.alloc = 128);
1653*cf5a6c84SAndroid Build Coastguard Worker
1654*cf5a6c84SAndroid Build Coastguard Worker TT.filename = *toys.optargs;
1655*cf5a6c84SAndroid Build Coastguard Worker linelist_load(0, 1);
1656*cf5a6c84SAndroid Build Coastguard Worker
1657*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mov_flag = 0x20000000;
1658*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mode = 1, TT.tabstop = 8;
1659*cf5a6c84SAndroid Build Coastguard Worker
1660*cf5a6c84SAndroid Build Coastguard Worker TT.screen_width = 80, TT.screen_height = 24;
1661*cf5a6c84SAndroid Build Coastguard Worker terminal_size(&TT.screen_width, &TT.screen_height);
1662*cf5a6c84SAndroid Build Coastguard Worker TT.screen_height -= 1;
1663*cf5a6c84SAndroid Build Coastguard Worker
1664*cf5a6c84SAndroid Build Coastguard Worker xsignal(SIGWINCH, generic_signal);
1665*cf5a6c84SAndroid Build Coastguard Worker set_terminal(0, 1, 0, 0);
1666*cf5a6c84SAndroid Build Coastguard Worker //writes stdout into different xterm buffer so when we exit
1667*cf5a6c84SAndroid Build Coastguard Worker //we dont get scroll log full of junk
1668*cf5a6c84SAndroid Build Coastguard Worker xputsn("\e[?1049h");
1669*cf5a6c84SAndroid Build Coastguard Worker
1670*cf5a6c84SAndroid Build Coastguard Worker if (TT.c) {
1671*cf5a6c84SAndroid Build Coastguard Worker FILE *cc = xfopen(TT.c, "r");
1672*cf5a6c84SAndroid Build Coastguard Worker char *line;
1673*cf5a6c84SAndroid Build Coastguard Worker
1674*cf5a6c84SAndroid Build Coastguard Worker while ((line = xgetline(cc))) if (run_ex_cmd(TT.il->data)) goto cleanup_vi;
1675*cf5a6c84SAndroid Build Coastguard Worker fclose(cc);
1676*cf5a6c84SAndroid Build Coastguard Worker }
1677*cf5a6c84SAndroid Build Coastguard Worker
1678*cf5a6c84SAndroid Build Coastguard Worker for (;;) {
1679*cf5a6c84SAndroid Build Coastguard Worker int key = 0;
1680*cf5a6c84SAndroid Build Coastguard Worker
1681*cf5a6c84SAndroid Build Coastguard Worker draw_page();
1682*cf5a6c84SAndroid Build Coastguard Worker // TODO script should handle cursor keys
1683*cf5a6c84SAndroid Build Coastguard Worker if (script && EOF==(key = fgetc(script))) {
1684*cf5a6c84SAndroid Build Coastguard Worker fclose(script);
1685*cf5a6c84SAndroid Build Coastguard Worker script = 0;
1686*cf5a6c84SAndroid Build Coastguard Worker }
1687*cf5a6c84SAndroid Build Coastguard Worker if (!script) key = scan_key(keybuf, -1);
1688*cf5a6c84SAndroid Build Coastguard Worker
1689*cf5a6c84SAndroid Build Coastguard Worker if (key == -1) goto cleanup_vi;
1690*cf5a6c84SAndroid Build Coastguard Worker else if (key == -3) {
1691*cf5a6c84SAndroid Build Coastguard Worker toys.signal = 0;
1692*cf5a6c84SAndroid Build Coastguard Worker terminal_size(&TT.screen_width, &TT.screen_height);
1693*cf5a6c84SAndroid Build Coastguard Worker TT.screen_height -= 1; //TODO this is hack fix visual alignment
1694*cf5a6c84SAndroid Build Coastguard Worker continue;
1695*cf5a6c84SAndroid Build Coastguard Worker }
1696*cf5a6c84SAndroid Build Coastguard Worker
1697*cf5a6c84SAndroid Build Coastguard Worker // TODO: support cursor keys in ex mode too.
1698*cf5a6c84SAndroid Build Coastguard Worker if (TT.vi_mode && key>=256) {
1699*cf5a6c84SAndroid Build Coastguard Worker key -= 256;
1700*cf5a6c84SAndroid Build Coastguard Worker //if handling arrow keys insert what ever is in input buffer before moving
1701*cf5a6c84SAndroid Build Coastguard Worker if (TT.il->len) {
1702*cf5a6c84SAndroid Build Coastguard Worker i_insert(TT.il->data, TT.il->len);
1703*cf5a6c84SAndroid Build Coastguard Worker TT.il->len = 0;
1704*cf5a6c84SAndroid Build Coastguard Worker memset(TT.il->data, 0, TT.il->alloc);
1705*cf5a6c84SAndroid Build Coastguard Worker }
1706*cf5a6c84SAndroid Build Coastguard Worker if (key==KEY_UP) cur_up(1, 1, 0);
1707*cf5a6c84SAndroid Build Coastguard Worker else if (key==KEY_DOWN) cur_down(1, 1, 0);
1708*cf5a6c84SAndroid Build Coastguard Worker else if (key==KEY_LEFT) cur_left(1, 1, 0);
1709*cf5a6c84SAndroid Build Coastguard Worker else if (key==KEY_RIGHT) cur_right(1, 1, 0);
1710*cf5a6c84SAndroid Build Coastguard Worker else if (key==KEY_HOME) vi_zero(1, 1, 0);
1711*cf5a6c84SAndroid Build Coastguard Worker else if (key==KEY_END) vi_dollar(1, 1, 0);
1712*cf5a6c84SAndroid Build Coastguard Worker else if (key==KEY_PGDN) ctrl_f();
1713*cf5a6c84SAndroid Build Coastguard Worker else if (key==KEY_PGUP) ctrl_b();
1714*cf5a6c84SAndroid Build Coastguard Worker
1715*cf5a6c84SAndroid Build Coastguard Worker continue;
1716*cf5a6c84SAndroid Build Coastguard Worker }
1717*cf5a6c84SAndroid Build Coastguard Worker
1718*cf5a6c84SAndroid Build Coastguard Worker if (TT.vi_mode == 1) { //NORMAL
1719*cf5a6c84SAndroid Build Coastguard Worker switch (key) {
1720*cf5a6c84SAndroid Build Coastguard Worker case '/':
1721*cf5a6c84SAndroid Build Coastguard Worker case '?':
1722*cf5a6c84SAndroid Build Coastguard Worker case ':':
1723*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mode = 0;
1724*cf5a6c84SAndroid Build Coastguard Worker TT.il->data[0]=key;
1725*cf5a6c84SAndroid Build Coastguard Worker TT.il->len++;
1726*cf5a6c84SAndroid Build Coastguard Worker break;
1727*cf5a6c84SAndroid Build Coastguard Worker case 'A':
1728*cf5a6c84SAndroid Build Coastguard Worker vi_eol();
1729*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mode = 2;
1730*cf5a6c84SAndroid Build Coastguard Worker break;
1731*cf5a6c84SAndroid Build Coastguard Worker case 'a':
1732*cf5a6c84SAndroid Build Coastguard Worker cur_right(1, 1, 0);
1733*cf5a6c84SAndroid Build Coastguard Worker // FALLTHROUGH
1734*cf5a6c84SAndroid Build Coastguard Worker case 'i':
1735*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mode = 2;
1736*cf5a6c84SAndroid Build Coastguard Worker break;
1737*cf5a6c84SAndroid Build Coastguard Worker case CTL('D'):
1738*cf5a6c84SAndroid Build Coastguard Worker ctrl_d();
1739*cf5a6c84SAndroid Build Coastguard Worker break;
1740*cf5a6c84SAndroid Build Coastguard Worker case CTL('B'):
1741*cf5a6c84SAndroid Build Coastguard Worker ctrl_b();
1742*cf5a6c84SAndroid Build Coastguard Worker break;
1743*cf5a6c84SAndroid Build Coastguard Worker case CTL('E'):
1744*cf5a6c84SAndroid Build Coastguard Worker ctrl_e();
1745*cf5a6c84SAndroid Build Coastguard Worker break;
1746*cf5a6c84SAndroid Build Coastguard Worker case CTL('F'):
1747*cf5a6c84SAndroid Build Coastguard Worker ctrl_f();
1748*cf5a6c84SAndroid Build Coastguard Worker break;
1749*cf5a6c84SAndroid Build Coastguard Worker case CTL('Y'):
1750*cf5a6c84SAndroid Build Coastguard Worker ctrl_y();
1751*cf5a6c84SAndroid Build Coastguard Worker break;
1752*cf5a6c84SAndroid Build Coastguard Worker case '\e':
1753*cf5a6c84SAndroid Build Coastguard Worker vi_buf[0] = 0;
1754*cf5a6c84SAndroid Build Coastguard Worker vi_buf_pos = 0;
1755*cf5a6c84SAndroid Build Coastguard Worker break;
1756*cf5a6c84SAndroid Build Coastguard Worker case 0x7F: //FALLTHROUGH
1757*cf5a6c84SAndroid Build Coastguard Worker case '\b':
1758*cf5a6c84SAndroid Build Coastguard Worker backspace(TT.vi_reg, 1, 1);
1759*cf5a6c84SAndroid Build Coastguard Worker break;
1760*cf5a6c84SAndroid Build Coastguard Worker default:
1761*cf5a6c84SAndroid Build Coastguard Worker if (key > ' ' && key < '{') {
1762*cf5a6c84SAndroid Build Coastguard Worker vi_buf[vi_buf_pos] = key;//TODO handle input better
1763*cf5a6c84SAndroid Build Coastguard Worker vi_buf_pos++;
1764*cf5a6c84SAndroid Build Coastguard Worker if (run_vi_cmd(vi_buf)) {
1765*cf5a6c84SAndroid Build Coastguard Worker memset(vi_buf, 0, 16);
1766*cf5a6c84SAndroid Build Coastguard Worker vi_buf_pos = 0;
1767*cf5a6c84SAndroid Build Coastguard Worker }
1768*cf5a6c84SAndroid Build Coastguard Worker else if (vi_buf_pos == 15) {
1769*cf5a6c84SAndroid Build Coastguard Worker vi_buf_pos = 0;
1770*cf5a6c84SAndroid Build Coastguard Worker memset(vi_buf, 0, 16);
1771*cf5a6c84SAndroid Build Coastguard Worker }
1772*cf5a6c84SAndroid Build Coastguard Worker
1773*cf5a6c84SAndroid Build Coastguard Worker }
1774*cf5a6c84SAndroid Build Coastguard Worker
1775*cf5a6c84SAndroid Build Coastguard Worker break;
1776*cf5a6c84SAndroid Build Coastguard Worker }
1777*cf5a6c84SAndroid Build Coastguard Worker } else if (TT.vi_mode == 0) { //EX MODE
1778*cf5a6c84SAndroid Build Coastguard Worker switch (key) {
1779*cf5a6c84SAndroid Build Coastguard Worker case '\x7f':
1780*cf5a6c84SAndroid Build Coastguard Worker case '\b':
1781*cf5a6c84SAndroid Build Coastguard Worker if (TT.il->len > 1) {
1782*cf5a6c84SAndroid Build Coastguard Worker TT.il->data[--TT.il->len] = 0;
1783*cf5a6c84SAndroid Build Coastguard Worker break;
1784*cf5a6c84SAndroid Build Coastguard Worker }
1785*cf5a6c84SAndroid Build Coastguard Worker // FALLTHROUGH
1786*cf5a6c84SAndroid Build Coastguard Worker case '\e':
1787*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mode = 1;
1788*cf5a6c84SAndroid Build Coastguard Worker TT.il->len = 0;
1789*cf5a6c84SAndroid Build Coastguard Worker memset(TT.il->data, 0, TT.il->alloc);
1790*cf5a6c84SAndroid Build Coastguard Worker break;
1791*cf5a6c84SAndroid Build Coastguard Worker case '\n':
1792*cf5a6c84SAndroid Build Coastguard Worker case '\r':
1793*cf5a6c84SAndroid Build Coastguard Worker if (run_ex_cmd(TT.il->data)) goto cleanup_vi;
1794*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mode = 1;
1795*cf5a6c84SAndroid Build Coastguard Worker TT.il->len = 0;
1796*cf5a6c84SAndroid Build Coastguard Worker memset(TT.il->data, 0, TT.il->alloc);
1797*cf5a6c84SAndroid Build Coastguard Worker break;
1798*cf5a6c84SAndroid Build Coastguard Worker default: //add chars to ex command until ENTER
1799*cf5a6c84SAndroid Build Coastguard Worker if (key >= ' ' && key < 0x7F) { //might be utf?
1800*cf5a6c84SAndroid Build Coastguard Worker if (TT.il->len == TT.il->alloc) {
1801*cf5a6c84SAndroid Build Coastguard Worker TT.il->data = realloc(TT.il->data, TT.il->alloc*2);
1802*cf5a6c84SAndroid Build Coastguard Worker TT.il->alloc *= 2;
1803*cf5a6c84SAndroid Build Coastguard Worker }
1804*cf5a6c84SAndroid Build Coastguard Worker TT.il->data[TT.il->len] = key;
1805*cf5a6c84SAndroid Build Coastguard Worker TT.il->len++;
1806*cf5a6c84SAndroid Build Coastguard Worker }
1807*cf5a6c84SAndroid Build Coastguard Worker break;
1808*cf5a6c84SAndroid Build Coastguard Worker }
1809*cf5a6c84SAndroid Build Coastguard Worker } else if (TT.vi_mode == 2) {//INSERT MODE
1810*cf5a6c84SAndroid Build Coastguard Worker switch (key) {
1811*cf5a6c84SAndroid Build Coastguard Worker case '\e':
1812*cf5a6c84SAndroid Build Coastguard Worker i_insert(TT.il->data, TT.il->len);
1813*cf5a6c84SAndroid Build Coastguard Worker cur_left(1, 1, 0);
1814*cf5a6c84SAndroid Build Coastguard Worker TT.vi_mode = 1;
1815*cf5a6c84SAndroid Build Coastguard Worker TT.il->len = 0;
1816*cf5a6c84SAndroid Build Coastguard Worker memset(TT.il->data, 0, TT.il->alloc);
1817*cf5a6c84SAndroid Build Coastguard Worker break;
1818*cf5a6c84SAndroid Build Coastguard Worker case 0x7F:
1819*cf5a6c84SAndroid Build Coastguard Worker case '\b':
1820*cf5a6c84SAndroid Build Coastguard Worker if (TT.il->len) {
1821*cf5a6c84SAndroid Build Coastguard Worker char *last = utf8_last(TT.il->data, TT.il->len);
1822*cf5a6c84SAndroid Build Coastguard Worker int shrink = strlen(last);
1823*cf5a6c84SAndroid Build Coastguard Worker memset(last, 0, shrink);
1824*cf5a6c84SAndroid Build Coastguard Worker TT.il->len -= shrink;
1825*cf5a6c84SAndroid Build Coastguard Worker } else backspace(TT.vi_reg, 1, 1);
1826*cf5a6c84SAndroid Build Coastguard Worker break;
1827*cf5a6c84SAndroid Build Coastguard Worker case '\n':
1828*cf5a6c84SAndroid Build Coastguard Worker case '\r':
1829*cf5a6c84SAndroid Build Coastguard Worker //insert newline
1830*cf5a6c84SAndroid Build Coastguard Worker TT.il->data[TT.il->len++] = '\n';
1831*cf5a6c84SAndroid Build Coastguard Worker i_insert(TT.il->data, TT.il->len);
1832*cf5a6c84SAndroid Build Coastguard Worker TT.il->len = 0;
1833*cf5a6c84SAndroid Build Coastguard Worker memset(TT.il->data, 0, TT.il->alloc);
1834*cf5a6c84SAndroid Build Coastguard Worker break;
1835*cf5a6c84SAndroid Build Coastguard Worker default:
1836*cf5a6c84SAndroid Build Coastguard Worker if ((key >= ' ' || key == '\t') &&
1837*cf5a6c84SAndroid Build Coastguard Worker utf8_dec(key, utf8_code, &utf8_dec_p))
1838*cf5a6c84SAndroid Build Coastguard Worker {
1839*cf5a6c84SAndroid Build Coastguard Worker if (TT.il->len+utf8_dec_p+1 >= TT.il->alloc) {
1840*cf5a6c84SAndroid Build Coastguard Worker TT.il->data = realloc(TT.il->data, TT.il->alloc*2);
1841*cf5a6c84SAndroid Build Coastguard Worker TT.il->alloc *= 2;
1842*cf5a6c84SAndroid Build Coastguard Worker }
1843*cf5a6c84SAndroid Build Coastguard Worker strcpy(TT.il->data+TT.il->len, utf8_code);
1844*cf5a6c84SAndroid Build Coastguard Worker TT.il->len += utf8_dec_p;
1845*cf5a6c84SAndroid Build Coastguard Worker utf8_dec_p = 0;
1846*cf5a6c84SAndroid Build Coastguard Worker *utf8_code = 0;
1847*cf5a6c84SAndroid Build Coastguard Worker }
1848*cf5a6c84SAndroid Build Coastguard Worker break;
1849*cf5a6c84SAndroid Build Coastguard Worker }
1850*cf5a6c84SAndroid Build Coastguard Worker }
1851*cf5a6c84SAndroid Build Coastguard Worker }
1852*cf5a6c84SAndroid Build Coastguard Worker cleanup_vi:
1853*cf5a6c84SAndroid Build Coastguard Worker linelist_unload();
1854*cf5a6c84SAndroid Build Coastguard Worker free(TT.il->data), free(TT.il), free(TT.yank.data);
1855*cf5a6c84SAndroid Build Coastguard Worker tty_reset();
1856*cf5a6c84SAndroid Build Coastguard Worker xputsn("\e[?1049l");
1857*cf5a6c84SAndroid Build Coastguard Worker }
1858