1 /*
2 *
3 * A class for diplaying and operating an advanced text editor with
4 * syntax highlighting, scrolling and other useful features.
5 *
6 * Copyright (C) 1999-2001 by Konstantin Klyagin <k@thekonst.net>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 * USA
22 *
23 * History of changes:
24 *
25 * 04.01.2000 development started
26 * 09.01.2000 the first release is ready
27 * 11.01.2000 one-line comments hightlight feature added
28 * 29.01.2000 text selecting and copying feature (cut-n'-paste)
29 * 01.02.2000 setpos() method added
30 * 03.02.2000 eddelword() method added, some minor changes made
31 * 06.02.2000 delmark() method added, hl_comment() minor bug fixed
32 * 18.02.2000 bool wrap variable added
33 * 11.03.2000 full tab support added
34 * 01.04.2000 emacs keys binding option added
35 * 20.04.2000 getline() & putline() methods added
36 * 23.04.2000 colorschemes added
37 * 07.05.2000 setpos() changed
38 * 11.05.2000 whole lines highlighing feature added
39 * 28.06.2000 shiftident() method added
40 * 10.07.2000 undo() implemented
41 * 25.07.2000 tab support improved
42 * 06.09.2000 blocks handling improved, shiftmarkedblock method added
43 * 31.10.2008 mergeline() minor bug fixed
44 *
45 */
46
47 #ifdef HAVE_CONFIG_H
48 #include <config.h>
49 #endif
50
51 #ifdef HAVE_STDINT_H
52 #include <stdint.h> /* for intptr_t */
53 #endif
54
55 #include "texteditor.h"
56
57 #define CURLINE (curfile ? (curfile->sy+curfile->y) : 0)
58 #define CURCOL (curfile ? (curfile->sx+curfile->x) : 0)
59 #define CURSTRING (char *) curfile->lines->at(CURLINE)
60 #define CSTRLEN strlen(CURSTRING ? CURSTRING : "")
61 #define UPDATECURRENTLINE { kgotoxy(x1, y1+curfile->y); showline(CURLINE, curfile->sx, x2-x1); }
62
63 #define MAX_STRLEN 10240
64 #define ALONE_DELIM " ;(){}[].,:-+*/^?!=<>"
65 #define NONCHAR_DELIM " ;(){}[].,:-+*/^?!=<>\"'_"
66 #define WORD_DELIM " ,"
67
68 #define EM_TAB 2
69 #define EM_CTRL 4
70 #define EM_MANUAL 8
71
72 #define CHECKLOADED if(!getfcount()) return;
73
texteditor()74 texteditor::texteditor():
75 otherkeys(0), fn(-1), wrap(false), abscol(0), idle(0),
76 insertmode(true), undolog(true), show(true), curfile(0),
77 prevshift(false), smarttab(true) {
78
79 files = new linkedlist;
80 files->freeitem = &editfilefree;
81 }
82
~texteditor()83 texteditor::~texteditor() {
84 delete files;
85 }
86
load(const string abuf,const string id)87 int texteditor::load(const string abuf, const string id) {
88 int newfn = addwindow(strdup(id.c_str()));
89 string buf = abuf;
90 vector<string> lst;
91 vector<string>::iterator i;
92
93 setfnum(newfn);
94
95 breakintolines(buf, lst, wrap ? x2-x1-1 : 0);
96
97 curfile->lines->empty();
98 for(i = lst.begin(); i != lst.end(); i++) {
99 curfile->lines->add(strdup(i->c_str()));
100 }
101 curfile->lines->add(strdup(""));
102
103 return newfn;
104 }
105
load(FILE * f,const string id)106 int texteditor::load(FILE *f, const string id) {
107 int i = -1;
108 struct stat st;
109 char *p = 0;
110
111 if(f)
112 if(!fstat(fileno(f), &st)) {
113 p = new char[st.st_size+1];
114 fseek(f, 0, SEEK_SET);
115 fread(p, st.st_size, 1, f);
116 p[st.st_size] = 0;
117 i = load(p, strdup(id.c_str()));
118 delete p;
119 }
120
121 return i;
122 }
123
load(ifstream & f,const string id)124 int texteditor::load(ifstream &f, const string id) {
125 int ret, size;
126 char *buf;
127
128 f.seekg(0, ios::end);
129 size = f.tellg();
130 f.seekg(0, ios::beg);
131
132 buf = new char[size+1];
133 f.read(buf, size);
134 buf[size] = 0;
135 ret = load(buf, strdup(id.c_str()));
136 delete buf;
137
138 return ret;
139 }
140
save(const char * linebreak)141 char *texteditor::save(const char *linebreak) {
142 int i;
143 char *buf, *p, *prev;
144
145 buf = p = 0;
146
147 for(i = 0; i < curfile->lines->count; i++) {
148 prev = p;
149 p = (char *) curfile->lines->at(i);
150
151 if(!buf) {
152 buf = (char *) malloc(strlen(p) + strlen(linebreak) + 1);
153 buf[0] = 0;
154 } else {
155 buf = (char *) realloc(buf, strlen(buf) + strlen(p) + strlen(linebreak) + 1);
156 }
157
158 if(i) {
159 if(!wrap) {
160 strcat(buf, linebreak);
161 } else
162 if(!prev[0] ||
163 (prev[strlen(prev)-1] != ' ') &&
164 (strlen(prev) < x2-x1-1)) {
165 strcat(buf, linebreak);
166 }
167 }
168
169 while(strspn(p, " ") >= TAB_SIZE) {
170 p += TAB_SIZE;
171 strcat(buf, "\t");
172 }
173
174 if(!((i == curfile->lines->count-1) && !strcmp(p, linebreak)))
175 strcat(buf, p);
176 }
177
178 return buf;
179 }
180
save(FILE * f,const char * linebreak)181 int texteditor::save(FILE *f, const char *linebreak) {
182 char *buf = save(linebreak);
183 fwrite(buf, strlen(buf), 1, f);
184 delete buf;
185 modified = false;
186 return 0;
187 }
188
save(ofstream & f,const string linebreak)189 int texteditor::save(ofstream &f, const string linebreak) {
190 char *buf = save(linebreak.c_str());
191 f.write(buf, strlen(buf));
192 delete buf;
193 f.close();
194 modified = false;
195 return 0;
196 }
197
getfnum()198 int texteditor::getfnum() {
199 return fn;
200 }
201
getfcount()202 int texteditor::getfcount() {
203 return files->count;
204 }
205
getfid()206 char *texteditor::getfid() {
207 return getfid(fn);
208 }
209
getfid(int fnn)210 char *texteditor::getfid(int fnn) {
211 if(files->count) {
212 editfile *ef = (editfile *) files->at(fnn);
213 if(ef) return ef->id; else return 0;
214 } else {
215 return 0;
216 }
217 }
218
setfid(char * id)219 void texteditor::setfid(char *id) {
220 setfid(fn, id);
221 }
222
setfid(int fnn,char * id)223 void texteditor::setfid(int fnn, char *id) {
224 if(fnn < files->count) {
225 editfile *ef = (editfile *) files->at(fnn);
226 if(ef) ef->id = id;
227 }
228 }
229
setfnum(int n)230 void texteditor::setfnum(int n) {
231 if(n < files->count && n >= 0 && n != fn) {
232
233 // save previous window params
234
235 if(curfile && (fn >= 0)) curfile->modified = modified;
236
237 // set new file number
238
239 fn = n;
240 curfile = (editfile *) files->at(fn);
241 modified = curfile->modified;
242
243 colors = colorschemes[curfile->ncolorscheme];
244 }
245 }
246
addwindow(char * id)247 int texteditor::addwindow(char *id) {
248 editfile *ef = new editfile;
249
250 ef->lines = new linkedlist;
251 ef->blocks = new linkedlist;
252 ef->highlines = new linkedlist;
253 ef->undo = new linkedlist;
254
255 ef->blocks->freeitem = &textblockfree;
256 ef->lines->freeitem = &charpointerfree;
257 ef->highlines->freeitem = &highlinefree;
258 ef->undo->freeitem = &undorecordfree;
259
260 ef->markblock = new textblock;
261 memset(ef->markblock, 0, sizeof(textblock));
262
263 ef->sx = ef->x = ef->sy = ef->y = 0;
264 ef->modified = ef->markmode = ef->showmarked = false;
265 ef->id = id;
266 ef->ncolorscheme = 0;
267
268 files->add(ef);
269 return files->count-1;
270 }
271
modification(tundoaction action,const string & data,bool connected,int curx,int cury)272 void texteditor::modification(tundoaction action, const string &data, bool connected, int curx, int cury) {
273 if(undolog && !data.empty()) {
274 undorecord *ur = new undorecord;
275 ur->x = curx < 0 ? CURCOL : curx;
276 ur->y = cury < 0 ? CURLINE : cury;
277 ur->action = action;
278 ur->data = data;
279 ur->prevconnected = connected;
280 curfile->undo->add(ur);
281 }
282
283 abscol = CURCOL;
284 modified = true;
285 scancomments(true);
286 }
287
setcoords(int nx1,int ny1,int nx2,int ny2)288 void texteditor::setcoords(int nx1, int ny1, int nx2, int ny2) {
289 x1 = nx1; x2 = nx2;
290 y1 = ny1; y2 = ny2;
291 if(curfile) setpos(CURCOL, CURLINE);
292 }
293
addscheme(int nc,int bc,int fbold,...)294 int texteditor::addscheme(int nc, int bc, int fbold, ...) {
295 va_list ap;
296 int p, nscheme = colorschemes.size();
297
298 va_start(ap, fbold);
299 colorscheme s;
300
301 s.ncolor = nc;
302 s.blockcolor = bc;
303 s.bold = fbold;
304
305 while((p = va_arg(ap, int)) != 0) s.difcolors.push_back(p);
306
307 colorschemes.push_back(s);
308 return nscheme;
309 }
310
addhighlight(int nscheme,string text,int color,hl_kind kind)311 void texteditor::addhighlight(int nscheme, string text, int color, hl_kind kind) {
312 int i;
313 hlight h;
314
315 if(nscheme >= 0 && nscheme < colorschemes.size()) {
316 colorscheme &s = colorschemes[nscheme];
317
318 if(kind == h_quotes) {
319 s.synt_quote = text;
320 s.qcolor = color;
321
322 if((i = text.find(" ")) != -1) {
323 s.synt_qescape = text.substr(i+1);
324 s.synt_quote.resize(i);
325 }
326 } else {
327 h.text = text;
328 h.color = color;
329 h.kind = kind;
330 s.hl.push_back(h);
331 sort(s.hl.begin(), s.hl.end());
332 }
333 }
334 }
335
addcolordif(int nscheme,int pairno)336 void texteditor::addcolordif(int nscheme, int pairno) {
337 if(nscheme >= 0 && nscheme < colorschemes.size()) {
338 colorscheme &s = colorschemes[nscheme];
339 s.difcolors.push_back(pairno);
340 }
341 }
342
setcolorscheme(int nscheme)343 void texteditor::setcolorscheme(int nscheme) {
344 setcolorscheme(getfnum(), nscheme);
345 }
346
setcolorscheme(int nfn,int nscheme)347 void texteditor::setcolorscheme(int nfn, int nscheme) {
348 editfile *f = (editfile *) files->at(nfn);
349
350 if(f) {
351 f->ncolorscheme = nscheme;
352 if(nfn == getfnum()) {
353 colors = colorschemes[f->ncolorscheme];
354 }
355 }
356 }
357
addblock(int x1,int y1,int x2,int y2,int color)358 void texteditor::addblock(int x1, int y1, int x2, int y2, int color) {
359 textblock *tb = new textblock;
360 tb->x1 = x1;
361 tb->y1 = y1;
362 tb->x2 = x2;
363 tb->y2 = y2;
364 tb->color = color;
365 curfile->blocks->add(tb);
366 }
367
startmark()368 void texteditor::startmark() {
369 CHECKLOADED;
370
371 if(!curfile->markmode) {
372 curfile->markmode = curfile->showmarked = true;
373 curfile->markreverse = false;
374 curfile->markblock->x1 = curfile->markblock->x2 = CURCOL;
375 curfile->markblock->y1 = curfile->markblock->y2 = CURLINE;
376 curfile->markblock->color = colors.blockcolor;
377 draw();
378 }
379 }
380
endmark()381 void texteditor::endmark() {
382 CHECKLOADED;
383
384 if(curfile->markmode) {
385 marktext();
386 curfile->markmode = false;
387 }
388 }
389
marktext()390 void texteditor::marktext() {
391 bool corrx, corry, sameline;
392 CHECKLOADED;
393
394 if(curfile->markreverse) {
395 corrx = curfile->markblock->x2 >= CURCOL;
396 corry = curfile->markblock->y2 >= CURLINE;
397 sameline = curfile->markblock->y2 == CURLINE;
398 } else {
399 corrx = curfile->markblock->x1 <= CURCOL;
400 corry = curfile->markblock->y1 <= CURLINE;
401 sameline = curfile->markblock->y1 == CURLINE;
402 }
403
404 if((corry && !corrx && sameline) || !corry) {
405 curfile->markreverse = !curfile->markreverse;
406 }
407
408 if(curfile->markreverse) {
409 curfile->markblock->x1 = CURCOL;
410 curfile->markblock->y1 = CURLINE;
411 } else {
412 curfile->markblock->x2 = CURCOL;
413 curfile->markblock->y2 = CURLINE;
414 }
415
416 draw();
417 updatecursor();
418 }
419
copymark(FILE * f)420 void texteditor::copymark(FILE *f) {
421 int i;
422 CHECKLOADED;
423
424 for(i = curfile->markblock->y1; i <= curfile->markblock->y2; i++) {
425
426 if(i == curfile->markblock->y1 && curfile->markblock->y1 == curfile->markblock->y2) {
427
428 char *p = strdup((char *) curfile->lines->at(i) + curfile->markblock->x1);
429 p[curfile->markblock->x2-curfile->markblock->x1] = 0;
430 fprintf(f, "%s", p);
431 free(p);
432
433 } else if(i == curfile->markblock->y1) {
434
435 fprintf(f, "%s\n", (char *) curfile->lines->at(i) + curfile->markblock->x1);
436
437 } else if(i == curfile->markblock->y2) {
438
439 if(curfile->markblock->x2) {
440 char *p = strdup((char *) curfile->lines->at(i));
441 p[curfile->markblock->x2] = 0;
442 fprintf(f, "%s", p);
443 if(!CURCOL) fprintf(f, "\n");
444 free(p);
445 }
446
447 } else {
448
449 fprintf(f, "%s\n", (char *) curfile->lines->at(i));
450
451 }
452 }
453 }
454
copymark(char * p,int maxlen)455 void texteditor::copymark(char *p, int maxlen) {
456 }
457
delmark()458 void texteditor::delmark() {
459 CHECKLOADED;
460
461 int i, newcol, newrow, line = 0;
462 char *c, *p, *sl, *el;
463 string deltext;
464 textblock *mb = curfile->markblock;
465
466 if(!mb->x1 && !mb->x2 && !mb->y1 && !mb->y2) return;
467
468 for(i = mb->y1; i <= mb->y2; i++) {
469 c = (char *) curfile->lines->at(i-line);
470
471 if((i == mb->y1) && (i == mb->y2)) {
472
473 deltext = c+mb->x1;
474 deltext.resize(mb->x2-mb->x1);
475
476 p = new char[strlen(c)];
477 strncpy(p, c, newcol = mb->x1);
478 strcpy(p + mb->x1, c + mb->x2);
479 p[strlen(c) - mb->x2 + mb->x1] = 0;
480 curfile->lines->replace(newrow = i, p);
481
482 } else if(i == mb->y1) {
483
484 deltext = c+mb->x1;
485
486 sl = strdup(c);
487 sl[mb->x1] = 0;
488
489 } else {
490 char *lch = (char *) curfile->lines->at(i-line);
491
492 deltext += "\n";
493 if(i == mb->y1) deltext += lch+mb->x1; else deltext += lch;
494
495 if(i == mb->y2) {
496 deltext.resize(deltext.size()-strlen(lch)+mb->x2);
497 el = strdup(c + mb->x2);
498 p = new char[strlen(sl)+strlen(el)+1];
499 strcpy(p, sl);
500 strcat(p, el);
501 curfile->lines->remove(i-line);
502 curfile->lines->replace(newrow = i-line-1, p);
503 newcol = strlen(sl);
504 free(sl);
505 free(el);
506 } else {
507 curfile->lines->remove(i-line);
508 line++;
509 }
510 }
511 }
512
513 modification(udelblock, deltext, false, mb->x1, mb->y1);
514 memset(curfile->markblock, 0, sizeof(textblock));
515 setpos(newcol, newrow);
516 draw();
517 }
518
clearmark()519 void texteditor::clearmark() {
520 CHECKLOADED;
521 memset(curfile->markblock, 0, sizeof(textblock));
522 draw();
523 }
524
insert(FILE * f)525 void texteditor::insert(FILE *f) {
526 struct stat sb;
527 int fsize;
528 char *buf;
529
530 if(f) {
531 fseek(f, 0, SEEK_SET);
532 fstat(fileno(f), &sb);
533 buf = new char[(fsize = sb.st_size)+1];
534 fread(buf, fsize, 1, f);
535 buf[fsize] = 0;
536 insert(buf);
537 delete buf;
538 }
539 }
540
insert(const string abuf)541 void texteditor::insert(const string abuf) {
542 CHECKLOADED;
543
544 string sbuf;
545 vector<string> lst;
546 vector<string>::iterator is;
547
548 sbuf = abuf;
549
550 if(sbuf.find_first_of("\n\t") != -1) {
551 breakintolines(sbuf, lst, 0);
552 for(sbuf = "", is = lst.begin(); is != lst.end(); is++) {
553 sbuf += *is + "\n";
554 }
555 }
556
557 if(!sbuf.empty()) {
558 char *sl = strdup(CURSTRING), *el = strdup(CURSTRING+CURCOL), buf[1024], *s;
559 const char *curpos = sbuf.c_str();
560 bool firstpass = true;
561 int line = 0;
562
563 sl[CURCOL] = 0;
564
565 while(1) {
566 if(!firstpass) {
567 if(curpos = strchr(curpos, '\n')) curpos++;
568 else break;
569 }
570
571 strncpy(buf, curpos, 1024);
572 if(s = strchr(buf, '\n')) *s = 0;
573 curpos += strlen(buf);
574
575 if(!line++) {
576 strinsert(buf, 0, sl);
577 if(!*curpos) strcat(buf, el);
578 curfile->lines->replace(CURLINE, strdup(buf));
579 } else {
580 if(!*curpos) strcat(buf, el);
581 curfile->lines->insert(CURLINE+line, strdup(buf));
582 }
583
584 firstpass = false;
585 }
586
587 delete el;
588 delete sl;
589
590 modification(uinsblock, sbuf);
591 }
592 }
593
sethlcolor(int n)594 void texteditor::sethlcolor(int n) {
595 int at = colors.bold;
596
597 if(!n) n = colors.ncolor;
598
599 if(::find(colors.difcolors.begin(), colors.difcolors.end(), n) !=
600 colors.difcolors.end())
601 at = !at;
602
603 attrset(at ? boldcolor(n) : normalcolor(n));
604 }
605
draw_print(char * buf,int bcolor,int distance)606 void texteditor::draw_print(char *buf, int bcolor, int distance) {
607 if(outx + strlen(buf) > distance) buf[distance-outx] = 0;
608 if(buf[0]) {
609 sethlcolor(bcolor);
610 printw("%s", buf);
611 outx += strlen(buf);
612 buf[0] = 0;
613 }
614 }
615
dstralone(const char * buf,const char * startword,int wordlen,const char * delim)616 int dstralone(const char *buf, const char *startword, int wordlen, const char *delim) {
617 int leftdelim = 0, rightdelim = 0;
618 const char *si;
619
620 for(si = startword-1; si != buf && *si < 32; si--);
621 if(si >= buf) leftdelim = (strchr(delim, *si) != 0); else leftdelim = 1;
622
623 for(si = startword + wordlen; *si && *si < 32; si++);
624 if(*si) rightdelim = (strchr(delim, *si) != 0); else rightdelim = 1;
625
626 return leftdelim && rightdelim;
627 }
628
scancomments(bool visible)629 void texteditor::scancomments(bool visible) {
630 int sl, el, i;
631 const char *rsub, *lsub;
632
633 curfile->blocks->empty();
634
635 if(visible) {
636 sl = curfile->sy;
637 el = curfile->sy+y2-y1;
638 if(el > curfile->lines->count) el = curfile->lines->count;
639 } else {
640 sl = 0;
641 el = curfile->lines->count;
642 }
643
644 vector<hlight>::iterator hi = ::find(colors.hl.begin(), colors.hl.end(), h_comment);
645
646 if(hi != colors.hl.end()) {
647 string lc, rc, comment = hi->text;
648 struct textblock *tb = 0;
649
650 lc = getword(comment, " ");
651 rc = getword(comment, " ");
652
653 for(i = sl; i < el; i++) {
654 char *p = (char *) curfile->lines->at(i);
655 const char *sub = p;
656
657 while(1) {
658 lsub = strqstr(sub, lc.c_str(), colors.synt_quote.c_str());
659
660 if(tb) rsub = strstr(sub, rc.c_str());
661 else rsub = strqstr(sub, rc.c_str(), colors.synt_quote.c_str());
662
663 if(rsub && (((rsub < lsub) && lsub) || !lsub)) {
664 sub = rsub;
665 if(!tb) {
666 tb = new textblock;
667 tb->color = hi->color;
668 tb->y1 = 0;
669 tb->x1 = 0;
670 }
671 tb->y2 = i;
672 tb->x2 = sub-p+rc.size();
673 curfile->blocks->add(tb);
674 tb = 0;
675 sub += rc.size();
676 } else if(lsub) {
677 sub = lsub;
678 if(!tb) {
679 tb = new textblock;
680 tb->color = hi->color;
681 tb->y1 = i;
682 tb->x1 = sub-p;
683 }
684 sub += lc.size();
685 } else if(lsub && rsub) {
686 if(!tb) {
687 tb = new textblock;
688 tb->color = hi->color;
689 }
690 tb->y1 = tb->y2 = i;
691 tb->x1 = p-lsub;
692 tb->x2 = p-rsub;
693 curfile->blocks->add(tb);
694 tb = 0;
695 } else {
696 break;
697 }
698 }
699 }
700
701 if(tb) {
702 tb->y2 = i+1;
703 tb->x2 = 0;
704 curfile->blocks->add(tb);
705 }
706 }
707 }
708
hl_comment(char * cp,char * txt,int color)709 int texteditor::hl_comment(char *cp, char *txt, int color) {
710 int r;
711 const char *p;
712
713 r = 0;
714 if(p = strqstr(cp, txt, "\"'"))
715 r = hl_comment(cp, p-cp, strlen(cp), color);
716
717 return r;
718 }
719
hl_comment(char * cp,int st,int pend,int color)720 int texteditor::hl_comment(char *cp, int st, int pend, int color) {
721 int i, delcount, r;
722 char ins[5] = "\001 ";
723 int origclr = -1;
724
725 delcount = r = 0;
726
727 if(color && (st <= strlen(cp)) && (pend-st > 0)) {
728 /// !!! for(i = 0; (i <= pend) && (i < strlen(cp)); i++)
729
730 for(i = 0; (i <= pend) && (i < strlen(cp)); i++) {
731 switch(cp[i]) {
732 case 1: origclr = cp[i+++1]; break;
733 case 2: origclr = -1; break;
734 }
735 }
736
737 if(pend > strlen(cp))
738 pend = strlen(cp);
739
740 if(cp[pend] != 2) {
741 strinsert(cp, pend, "\002");
742 r++;
743 }
744
745 if(origclr != -1) {
746 ins[1] = origclr;
747 strinsert(cp, pend+1, ins);
748 r += 2;
749 }
750
751 for(i = st; (i < pend) && (i < strlen(cp)); i++) {
752 switch(cp[i]) {
753 case 1:
754 strcut(cp, i--, 2);
755 delcount += 2;
756 pend -= 2;
757 break;
758 case 2:
759 strcut(cp, i--, 1);
760 delcount++;
761 pend--;
762 break;
763 }
764 }
765
766 ins[1] = color;
767 strinsert(cp, st, ins);
768 r += 2;
769 }
770
771 return r-delcount;
772 }
773
count_clrcodes(char * cp,int pos)774 int texteditor::count_clrcodes(char *cp, int pos) {
775 int i, j, k;
776 j = k = 0;
777
778 for(i = 0; i < strlen(cp) && j < pos; i++) {
779 if(cp[i] == 1) {
780 k++;
781 if(i++ < strlen(cp)) k++;
782 } else if(cp[i] == 2) k++; else j++;
783 }
784
785 return k;
786 }
787
showline(int ln,int startx,int distance,int extrax)788 void texteditor::showline(int ln, int startx, int distance, int extrax) {
789 if(!show) return;
790
791 int i, n, inscount, bcolor, sxinscount, printed, j, lastoccur, q, eolstart, npos, offs;
792 char *cs, *sr, *nr, *r, ins[3] = "\001 ";
793
794 vector<int> layout;
795 vector<int>::iterator iq;
796 vector<hlight>::iterator hi;
797
798 const char *p;
799
800 if(!(cs = (char *) curfile->lines->at(ln))) return;
801 char *cp = (char *) malloc(i = ((strlen(cs)+1)*4)*sizeof(char));
802 char *buf = (char *) malloc(i);
803
804 eolstart = i;
805
806 strcpy(cp, cs);
807 buf[0] = 0;
808 inscount = sxinscount = bcolor = 0;
809
810 highline *hline = (highline *) curfile->highlines->find(&(i = ln+1), &findhighline);
811
812 if(hline) {
813 ins[1] = hline->color;
814 strinsert(cp, 0, ins);
815 strcat(cp, "\002");
816 } else {
817 if(strlen(cp))
818 for(hi = colors.hl.begin(); hi != colors.hl.end(); hi++) {
819 ins[1] = hi->color;
820 p = cp;
821 lastoccur = 0;
822
823 switch(hi->kind) {
824 case h_alone:
825 for(sr = r = strdup(hi->text.c_str()); r && r != sr+hi->text.size(); ) {
826 if(nr = strchr(r, ';')) {
827 *nr = 0;
828 nr++;
829 }
830
831 if(!strlen(r)) {
832 r = nr;
833 continue;
834 }
835
836 p = cp;
837 lastoccur = 0;
838
839 while(p = strqstr(p+lastoccur, r, colors.synt_quote.c_str(), colors.synt_qescape.c_str())) {
840 if(eolstart) eolstart += lastoccur;
841 if(p-cp > eolstart) {
842 r = 0;
843 break;
844 }
845
846 lastoccur = strlen(r);
847 if(dstralone(cp, p, lastoccur, ALONE_DELIM)) {
848 strinsert(cp, p-cp+lastoccur, "\002");
849 strinsert(cp, p-cp, ins);
850 inscount++;
851 lastoccur += 3;
852 }
853 }
854
855 r = nr;
856 }
857
858 free(sr);
859 break;
860
861 case h_symbol:
862 layout = getsymbolpositions(string(cp).substr(0, eolstart),
863 hi->text, colors.synt_quote, colors.synt_qescape);
864
865 for(offs = 0, iq = layout.begin(); iq != layout.end(); iq++) {
866 offs += hl_comment(cp, *iq+offs, *iq+offs+1, hi->color);
867 }
868 break;
869
870 case h_block:
871 while(p = strqpbrk(cp, p-cp+lastoccur, hi->text.c_str(),
872 colors.synt_quote.c_str(), colors.synt_qescape.c_str())) {
873 if(eolstart) eolstart += lastoccur;
874 if(p-cp > eolstart) break;
875 lastoccur = strspn(p, hi->text.c_str());
876 if(dstralone(cp, p, lastoccur, ALONE_DELIM)) {
877 strinsert(cp, p-cp+lastoccur, "\002");
878 strinsert(cp, p-cp, ins);
879 lastoccur += 3;
880 }
881 }
882 break;
883
884 case h_eol:
885 if((npos = find_quoted(p, hi->text, 0,
886 colors.synt_quote, colors.synt_qescape)) != -1)
887 hl_comment(cp, eolstart = npos, strlen(cp),
888 hi->color);
889
890 break;
891
892 case h_quotes:
893 case h_comment:
894 /* TODO: should these be handled,
895 * are they possible to get here at all ?
896 */
897 break;
898 }
899 }
900
901 // Quotes highlight ...
902
903 if(!colors.synt_quote.empty()) {
904 bool qst;
905
906 layout = getquotelayout(string(cp).substr(0, eolstart),
907 colors.synt_quote, colors.synt_qescape);
908
909 for(qst = false, offs = 0, iq = layout.begin(); iq != layout.end(); iq++) {
910 qst = !qst;
911
912 if(!qst) {
913 offs += hl_comment(cp, *(iq-1)+offs,
914 *iq+offs+1, colors.qcolor);
915 }
916 }
917
918 if(qst) {
919 hl_comment(cp, *(layout.end()-1)+offs, strlen(cp), colors.qcolor);
920 }
921 }
922
923 // Blocks ...
924
925 for(i = 0; i < curfile->blocks->count + 1; i++) {
926 textblock *tb;
927
928 if(i == curfile->blocks->count) {
929 if(curfile->showmarked) {
930 tb = curfile->markblock;
931 } else break;
932 } else {
933 tb = (textblock *) curfile->blocks->at(i);
934 }
935
936 if(ln >= tb->y1 && ln <= tb->y2) {
937 q = strlen(cp);
938
939 if(ln == tb->y1 && tb->y1 == tb->y2) {
940 n = count_clrcodes(cp, tb->x1) + tb->x1;
941 q = count_clrcodes(cp, tb->x2) + tb->x2;
942 } else if(ln == tb->y1) {
943 n = count_clrcodes(cp, tb->x1) + tb->x1;
944 } else if(ln == tb->y2) {
945 n = j = 0;
946 q = count_clrcodes(cp, tb->x2) + tb->x2;
947 } else n = j = 0;
948
949 if(!(tb->x1 == tb->x2 && tb->y1 == tb->y2)) {
950 hl_comment(cp, n, q, tb->color);
951 }
952 }
953 }
954 }
955
956 // let's count the amount of color codes inserted
957 // before start X position (startx variable)
958
959 sxinscount = count_clrcodes(cp, startx);
960
961 for(i = 0; i < startx+sxinscount && i < strlen(cp)+inscount*3; i++) {
962 if(cp[i] == 1) bcolor = cp[++i]; else
963 if(cp[i] == 2) bcolor = 0;
964 }
965
966 for(i = startx+sxinscount, n = 0, outx = 0; i < strlen(cp); i++) {
967 if(cp[i] == 1) {
968 draw_print(buf, bcolor, distance);
969 bcolor = cp[++i];
970 n = 0;
971 } else if(cp[i] == 2) {
972 draw_print(buf, bcolor, distance);
973 n = bcolor = 0;
974 } else {
975 buf[n++] = cp[i];
976 buf[n] = 0;
977 }
978 }
979
980 draw_print(buf, bcolor, distance);
981 if(!hline) sethlcolor(0);
982
983 printed = strlen(cs)-startx;
984 if(printed < 0) printed = 0; else
985 if(printed > distance) printed = distance;
986 mvhline(y1+ln-curfile->sy, x1+extrax+printed, ' ', distance-printed);
987
988 free (buf);
989 free (cp);
990 }
991
draw(int fromline)992 void texteditor::draw(int fromline) {
993 int k;
994
995 if(show) {
996 if(curfile->lines) {
997 for(k = curfile->sy+fromline; k < curfile->lines->count && k < y2-y1+curfile->sy; k++) {
998 kgotoxy(x1, k-curfile->sy+y1);
999 showline(k, curfile->sx, x2-x1);
1000 }
1001
1002 if(k < y2-y1+curfile->sy) {
1003 sethlcolor(colors.ncolor);
1004 for(; k < y2-y1+curfile->sy; k++) mvhline(k-curfile->sy+y1, x1, ' ', x2-x1);
1005 }
1006 }
1007
1008 refresh();
1009 }
1010 }
1011
draw()1012 void texteditor::draw() {
1013 if(active && curfile) {
1014 if(curfile->lines) scancomments(true);
1015 draw(0);
1016 }
1017 }
1018
endofline()1019 bool texteditor::endofline() {
1020 return CURCOL == CSTRLEN;
1021 }
1022
currentchar()1023 const char texteditor::currentchar() {
1024 char *p = CURSTRING;
1025 return p[CURCOL];
1026 }
1027
updatecursor()1028 void texteditor::updatecursor() {
1029 if(active && curfile) {
1030 if(curfile->y >= y2-y1) curfile->y = y2-y1-1;
1031 if(curfile->x >= x2-x1) curfile->x = x2-x1-1;
1032 kgotoxy(x1+curfile->x, y1+curfile->y);
1033 }
1034 }
1035
fix_x(bool tab)1036 bool texteditor::fix_x(bool tab) {
1037 int osx = curfile->sx, clen = CSTRLEN;
1038
1039 if(CURCOL > clen) {
1040 if(clen-curfile->sx < 0) {
1041 curfile->sx = CSTRLEN/(x2-x1-1);
1042 }
1043 curfile->x = CSTRLEN-curfile->sx;
1044 } else {
1045 if(abscol-curfile->sx > x2-x1-1) setpos(abscol, CURLINE);
1046 }
1047
1048 if(tab) {
1049 int rm = rtabmargin(true, CURCOL, CURSTRING);
1050 char *p = CURSTRING;
1051
1052 /* if CURCOL is 0 we'll be outside of the array => not good */
1053 if(CURCOL > 0)
1054 if(p[CURCOL-1] == ' ')
1055 if(strspn(p+CURCOL, " ") >= rm-CURCOL)
1056 if(CURCOL != ltabmargin(true, rm, p)) {
1057 //if(rm <= curfile->sx+x2-x1) curfile->x = rm-curfile->sx;
1058 curfile->x += rm-curfile->x;
1059 }
1060 }
1061
1062 return osx != curfile->sx;
1063 }
1064
eddel(bool usetabs)1065 void texteditor::eddel(bool usetabs) {
1066 char *p = CURSTRING;
1067 int nextlen, todelete = 1, rm;
1068 string deltext;
1069
1070 if(p) {
1071 if(CURCOL < strlen(p)) {
1072 if(usetabs && ((rm = rtabmargin(true, CURCOL, CURSTRING)) != -1)) {
1073 deltext.append(todelete = rm-CURCOL, ' ');
1074 } else {
1075 deltext = *(p+CURCOL);
1076 }
1077
1078 modification(udelchar, deltext);
1079 strcut(p, CURCOL, todelete);
1080 int px = CURCOL, py = CURLINE;
1081 mergeline(CURLINE-1, false, px, py); // can't we append this one to previous, since we've shrotened it?
1082 mergeline(py, false, px, py); // can't we append next one to this?
1083 setpos(px, py);
1084 updatecursor();
1085 draw();
1086
1087 } else {
1088 int px = CURCOL, py = CURLINE;
1089 mergeline(py, true, px, py);
1090
1091 modification(udelchar, "\n");
1092 setpos(px, py);
1093 draw();
1094 }
1095
1096 updatecursor();
1097 }
1098 }
1099
edbackspace()1100 void texteditor::edbackspace() {
1101 int i, bc;
1102
1103 if(CURCOL) {
1104 bool spacetoend = endofline() && !currentchar();
1105 bool curspace = isspace(currentchar());
1106
1107 edmove(KEY_LEFT);
1108
1109 if(spacetoend) {
1110 bc = CSTRLEN-CURCOL;
1111 for(i = 0; i < bc; i++) eddel(false);
1112 } else {
1113 if(!curspace && isspace(currentchar())) {
1114 eddelword();
1115 } else {
1116 eddel();
1117 }
1118 }
1119 } else if(CURLINE) {
1120 edmove(KEY_UP);
1121 edmove(KEY_END);
1122 eddel();
1123 }
1124 }
1125
eddelword()1126 void texteditor::eddelword() {
1127 // This is the kkconsui original version: it does not skip whitespace
1128 char *p = CURSTRING, *e;
1129 string deltext, n;
1130 int count;
1131
1132 if(!strlen(p)) {
1133 eddelline();
1134 } else if(CURCOL == strlen(p)) {
1135 if(CURLINE < curfile->lines->count-1) {
1136 eddel();
1137 if(currentchar() == ' ') eddelword();
1138 }
1139 } else {
1140 n = p;
1141 deltext = n.substr(CURCOL);
1142
1143 if(currentchar() == ' ') {
1144 count = strspn(p+CURCOL, " ");
1145 n.replace(CURCOL, count, "");
1146 } else {
1147 n = p;
1148 if(!(e = strpbrk(&p[CURCOL], NONCHAR_DELIM))) e = p + strlen(p);
1149
1150 if((count = e-p-curfile->sx-curfile->x)) {
1151 n.replace(CURCOL, count, "");
1152 } else {
1153 count += strspn(n.substr(CURCOL).c_str(), NONCHAR_DELIM);
1154 n.replace(CURCOL, strspn(n.c_str()+CURCOL, NONCHAR_DELIM), "");
1155 }
1156 }
1157
1158 deltext.resize(count);
1159 curfile->lines->replace(CURLINE, strdup(n.c_str()));
1160 modification(udelchar, deltext);
1161 int px = CURCOL, py = CURLINE;
1162 mergeline(py-1, false, px, py);
1163 mergeline(py, false, px, py);
1164 setpos(px, py);
1165 draw();
1166 updatecursor();
1167 }
1168 }
1169
eddelwordemacs()1170 void texteditor::eddelwordemacs() {
1171 // This is the "emacs-compliant" version, it skips all whitespace
1172 char *p = CURSTRING, *e;
1173 string deltext, n;
1174 int count = 0;
1175
1176 if(!strlen(p)) {
1177 if(CURLINE < curfile->lines->count-1) {
1178 eddelline();
1179 eddelwordemacs();
1180 }
1181 } else if(CURCOL == strlen(p)) {
1182 if(CURLINE < curfile->lines->count-1) {
1183 eddel();
1184 if(currentchar() == ' ') eddelword();
1185 }
1186 } else {
1187 n = p;
1188 deltext = n.substr(CURCOL);
1189
1190 // skip whitespace
1191 if(currentchar() == ' ') {
1192 count = strspn(p+CURCOL, " ");
1193 n.replace(CURCOL, count, "");
1194 curfile->lines->replace(CURLINE, strdup(n.c_str()));
1195 int px = CURCOL, py = CURLINE;
1196 mergeline(py-1, false, px, py);
1197 mergeline(py, false, px, py);
1198 setpos(px, py);
1199 }
1200
1201 n = p = CURSTRING;
1202
1203 if(!(e = strpbrk(&p[CURCOL], NONCHAR_DELIM))) e = p + strlen(p);
1204
1205 if((count = e-p-curfile->sx-curfile->x)) {
1206 n.replace(CURCOL, count, "");
1207 } else {
1208 count += strspn(n.substr(CURCOL).c_str(), NONCHAR_DELIM);
1209 n.replace(CURCOL, strspn(n.c_str()+CURCOL, NONCHAR_DELIM), "");
1210 }
1211
1212 deltext.resize(count);
1213 curfile->lines->replace(CURLINE, strdup(n.c_str()));
1214 modification(udelchar, deltext);
1215
1216 int px = CURCOL, py = CURLINE;
1217 mergeline(py-1, false, px, py);
1218 mergeline(py, false, px, py);
1219 setpos(px, py);
1220 draw();
1221 updatecursor();
1222 }
1223 }
1224
eddelline()1225 void texteditor::eddelline() {
1226 char *p = (char *) curfile->lines->at(CURLINE);
1227 string deltext = (string) p + "\n";
1228
1229 if(CURLINE+1 < curfile->lines->count) {
1230 int px = 0, py = CURLINE;
1231 curfile->lines->remove(CURLINE);
1232 mergeline(py-1, false, px, py);
1233
1234 if(!curfile->lines->count) {
1235 curfile->sy = curfile->sx = curfile->y = curfile->x = 0;
1236 char *p = strdup("");
1237 curfile->lines->add(p);
1238 } else if(CURLINE >= curfile->lines->count) {
1239 edmove(KEY_UP);
1240 }
1241 } else {
1242 char *p = strdup("");
1243 curfile->lines->replace(curfile->lines->count-1, p);
1244 }
1245
1246 shiftmarkedblock(-1);
1247 modification(udelchar, deltext, false, 0);
1248 edmove(KEY_HOME);
1249 abscol = 0;
1250 draw();
1251 updatecursor();
1252 }
1253
eddelbegofline()1254 void texteditor::eddelbegofline() {
1255 char *p = CURSTRING;
1256 string deltext, n;
1257
1258 if(CURCOL == 0 && CURLINE) { // We're at the beginning of the line
1259 edmove(KEY_UP);
1260 edmove(KEY_END);
1261 eddel();
1262 } else if(CURCOL == strlen(p)) { // We're at the end
1263 eddelline();
1264 } else {
1265 n = p;
1266 deltext = (string) p;
1267
1268 n.replace(curfile->sx, CURCOL, "");
1269
1270 edmove(KEY_HOME);
1271
1272 curfile->lines->replace(CURLINE, strdup(n.c_str()));
1273 modification(udelchar, deltext);
1274 int px = 0, py = CURLINE;
1275 mergeline(py-1, false, px, py);
1276 mergeline(CURLINE, false, px, py);
1277 draw();
1278 updatecursor();
1279 }
1280
1281 }
1282
eddelendofline()1283 void texteditor::eddelendofline() {
1284 char *p = CURSTRING;
1285 string deltext, n;
1286 int count = 0;
1287
1288 if(CURCOL == 0) { // We're at the beginning of the line
1289 eddelline();
1290 } else if (CURCOL == strlen(p)) { // We're at the end
1291 eddel();
1292 } else {
1293 n = p;
1294 deltext = (string) p + "\n";
1295
1296 count = strlen(p) - CURCOL;
1297 n.replace(CURCOL, count, "");
1298
1299 curfile->lines->replace(CURLINE, strdup(n.c_str()));
1300 modification(udelchar, deltext);
1301 draw(curfile->y);
1302 updatecursor();
1303 }
1304
1305 }
1306
edtransposechar()1307 void texteditor::edtransposechar() {
1308 char *p = CURSTRING;
1309 string deltext;
1310 char tmp;
1311
1312 if (CURCOL == 0) return;
1313 else if (CURCOL == strlen(p)) {
1314 deltext = (string) p;
1315
1316 tmp = p[CURCOL-2];
1317 p[CURCOL-2] = p[CURCOL-1];
1318 p[CURCOL-1] = tmp;
1319
1320 curfile->lines->replace(CURLINE, strdup(p));
1321 modification(udelchar, deltext);
1322 draw(curfile->y);
1323 updatecursor();
1324 } else {
1325 deltext = (string) p;
1326
1327 tmp = p[CURCOL-1];
1328 p[CURCOL-1] = p[CURCOL];
1329 p[CURCOL] = tmp;
1330
1331 setpos(CURCOL+1, CURLINE);
1332
1333 curfile->lines->replace(CURLINE, strdup(p));
1334 modification(udelchar, deltext);
1335 draw(curfile->y);
1336 updatecursor();
1337 }
1338
1339 }
1340
edenter(bool countspaces)1341 void texteditor::edenter(bool countspaces) {
1342 char *p = CURSTRING, *r;
1343 string spaceins;
1344
1345 if(wrap) strimtrail(p);
1346
1347 int oldsx = curfile->sx;
1348 int spacecount = strspn(p, " ");
1349 int nextlen = CSTRLEN-CURCOL+spacecount+1;
1350
1351 char *nextstr = (char *) malloc(nextlen < 1 ? 1 : nextlen);
1352 if(CURCOL < spacecount) spacecount = 0;
1353
1354 if(!countspaces) spacecount = 0;
1355 r = strlen(p) > CURCOL ? p+CURCOL : p+strlen(p);
1356 sprintf(nextstr, "%-*s%s", spacecount, "", r);
1357
1358 curfile->lines->insert(CURLINE+2, nextstr);
1359
1360 modification(uinschar, "\n");
1361 spaceins.append(spacecount, ' ');
1362 modification(uinschar, spaceins);
1363
1364 curfile->sx = p[CURCOL] = 0;
1365 curfile->x = spacecount;
1366
1367 if(curfile->x > x2-x1) {
1368 curfile->sx = curfile->x-(x2-x1);
1369 curfile->x -= curfile->sx;
1370 }
1371
1372 // Shift the marked block down if ENTER was
1373 // pressed on the line above it
1374
1375 shiftmarkedblock(1);
1376
1377 if(curfile->y+1 < y2-y1) {
1378 if(curfile->sx != oldsx) draw(); else draw(curfile->y);
1379 }
1380
1381 abscol = CURCOL;
1382 edmove(KEY_DOWN);
1383 }
1384
edmove(int k,int options)1385 void texteditor::edmove(int k, int options) {
1386 int i, lm;
1387 bool fdraw = false;
1388 bool ctrlpressed = (options & EM_CTRL) && (getctrlkeys() & CONTROL_PRESSED);
1389 bool shiftpressed = (getctrlkeys() & SHIFT_PRESSED);
1390 char *p = CURSTRING;
1391
1392 if(options & EM_MANUAL) {
1393 if(shiftpressed != prevshift) {
1394 if(shiftpressed && !curfile->markmode) startmark();
1395 if(!shiftpressed && curfile->markmode) endmark();
1396 }
1397 prevshift = shiftpressed;
1398 }
1399
1400 if(curfile->lines->count) {
1401 switch(k) {
1402 case KEY_UP:
1403 if(curfile->y) {
1404 curfile->y--;
1405 } else if(CURLINE) {
1406 i = CURLINE-1;
1407 // sy -= (y2-y1)/2;
1408 curfile->sy--;
1409 if(curfile->sy < 0) curfile->sy = 0;
1410 curfile->y = i-curfile->sy;
1411 fdraw = true;
1412 }
1413
1414 setpos(abscol, CURLINE);
1415 if(fix_x(options & EM_TAB) || fdraw) draw();
1416 updatecursor();
1417 break;
1418
1419 case KEY_DOWN:
1420 if(CURLINE < curfile->lines->count-1) {
1421 if(curfile->y+1 < y2-y1) {
1422 curfile->y++;
1423 } else {
1424 i = CURLINE+1;
1425 // sy += (y2-y1)/2;
1426 curfile->sy++;
1427 if(curfile->lines->count-curfile->sy < y2-y1) curfile->sy = curfile->lines->count-y2+y1;
1428 curfile->y = i-curfile->sy;
1429 fdraw = true;
1430 }
1431
1432 setpos(abscol, CURLINE);
1433 if(fix_x(options & EM_TAB) || fdraw) draw();
1434 updatecursor();
1435 }
1436 break;
1437
1438 case KEY_LEFT:
1439 if(ctrlpressed) {
1440 char *p = CURSTRING, *r, *s = p+CURCOL;
1441
1442 if(p == s) r = 0; else {
1443 for(r = s; (r != p) && !strchr(NONCHAR_DELIM, *r); r--);
1444 for(; (r != p) && strchr(NONCHAR_DELIM, *r); r--);
1445 for(; (r != p) && !strchr(NONCHAR_DELIM, *r); r--);
1446
1447 if(strchr(NONCHAR_DELIM, *r)) {
1448 if(r == p) r = 0; else r++;
1449 }
1450 }
1451
1452 if(r) {
1453 if((curfile->x -= s-r) < 0) {
1454 curfile->sx += curfile->x;
1455 curfile->x = 0;
1456 draw();
1457 updatecursor();
1458 }
1459 } else if(CURLINE) {
1460 setpos(strlen((char *) curfile->lines->at(CURLINE-1)), CURLINE-1);
1461 }
1462 } else {
1463 /*
1464 if(CURCOL && (options & EM_TAB) && ((lm = ltabmargin(true, -1, CURSTRING)) != -1)) {
1465 setpos(lm, CURLINE);
1466 } else
1467 */
1468 if(curfile->x) {
1469 curfile->x--;
1470
1471 char *p = CURSTRING;
1472
1473 if(CURCOL && (options & EM_TAB))
1474 if((lm = ltabmargin(true, CURCOL, p)) != -1)
1475 if(CURCOL+1 != lm)
1476 if(currentchar() == ' ') setpos(lm, CURLINE);
1477 } else if(curfile->sx) {
1478 i = CURCOL;
1479 curfile->sx -= (x2-x1)/3;
1480 if(curfile->sx < 0) curfile->sx = 0;
1481 curfile->x = i-curfile->sx-1;
1482 draw();
1483 } else if(CURLINE) {
1484 edmove(KEY_UP);
1485 edmove(KEY_END);
1486 }
1487 }
1488 break;
1489
1490 case KEY_RIGHT:
1491 if(ctrlpressed) {
1492 char *p = CURSTRING+CURCOL+1, *r = 0;
1493
1494 if(*(CURSTRING+CURCOL)) {
1495 if(r = strpbrk(p, NONCHAR_DELIM))
1496 for(; *r && strchr(NONCHAR_DELIM, *r); r++);
1497 }
1498
1499 if(r) {
1500 curfile->x += r-p+1;
1501 } else {
1502 if(endofline() && (CURLINE < curfile->lines->count-1)) {
1503 setpos(0, CURLINE+1);
1504 } else {
1505 curfile->x = CSTRLEN;
1506 }
1507 }
1508 } else {
1509 if(CSTRLEN > CURCOL) {
1510 curfile->x++;
1511 fix_x(options & EM_TAB);
1512 } else if(CURLINE < curfile->lines->count-1) {
1513 edmove(KEY_DOWN);
1514 edmove(KEY_HOME);
1515 }
1516 }
1517 break;
1518
1519 case KEY_HOME:
1520 i = curfile->sx;
1521
1522 if(ctrlpressed) {
1523 curfile->y = 0;
1524 curfile->sx = curfile->x = 0;
1525 } else if(curfile->x) {
1526 curfile->sx = curfile->x = 0;
1527 }
1528
1529 if(curfile->sx < i) draw();
1530 updatecursor();
1531 break;
1532
1533 case KEY_END:
1534 if(ctrlpressed) {
1535 i = curfile->sx;
1536 curfile->y = y2-y1-1;
1537 curfile->sx = curfile->x = 0;
1538
1539 if(CURLINE >= curfile->lines->count) {
1540 curfile->y = curfile->lines->count-curfile->sy-1;
1541 }
1542
1543 if(i) draw();
1544 } else if(CURCOL != CSTRLEN) {
1545 setpos(CSTRLEN, CURLINE);
1546 }
1547
1548 updatecursor();
1549 break;
1550
1551 case KEY_PPAGE:
1552 if(ctrlpressed) {
1553 setpos(0, 0);
1554 abscol = 0;
1555 } else if(CURLINE) {
1556 if(curfile->y-y2-y1 < 0 && !curfile->sy) curfile->y = 0; else {
1557 curfile->sy = curfile->sy-y2+y1;
1558 if(curfile->sy < 0) curfile->sy = 0;
1559 }
1560
1561 fix_x(options & EM_TAB);
1562 draw();
1563 updatecursor();
1564 }
1565 break;
1566
1567 case KEY_NPAGE:
1568 if(ctrlpressed) {
1569 setpos(0, curfile->lines->count-1);
1570 abscol = 0;
1571 } else if(CURLINE != curfile->lines->count) {
1572 if(curfile->sy + y2-y1 == curfile->lines->count) curfile->y = y2-y1-1; else {
1573 curfile->sy += y2-y1;
1574 if(curfile->sy+y2-y1 > curfile->lines->count) curfile->sy = curfile->lines->count-y2+y1;
1575 if(curfile->sy < 0) {
1576 curfile->sy = 0;
1577 curfile->y = curfile->lines->count-1;
1578 }
1579 }
1580
1581 fix_x(options & EM_TAB);
1582 draw();
1583 }
1584 break;
1585 case KEY_EMACS_BEG_OF_BUFFER:
1586 setpos(0, 0);
1587 break;
1588 case KEY_EMACS_END_OF_BUFFER:
1589 p = (char *) curfile->lines->at(curfile->lines->count-1);
1590 i = strlen(p);
1591 setpos(i, curfile->lines->count-1);
1592 break;
1593 case KEY_EMACS_FORWARD_WORD:
1594 if(endofline() && CURLINE < curfile->lines->count-1) {
1595 setpos(0, CURLINE+1);
1596 p = CURSTRING;
1597 if(strchr(NONCHAR_DELIM, p[CURCOL])) {
1598 i = strspn(p+CURCOL, NONCHAR_DELIM);
1599 setpos(CURCOL+i, CURLINE);
1600 }
1601 } else if(endofline() && CURLINE == curfile->lines->count-1)
1602 return;
1603 i = 0;
1604 if(strchr(NONCHAR_DELIM, p[CURCOL]))
1605 i = strspn(p+CURCOL, NONCHAR_DELIM);
1606 i += strcspn(p+CURCOL+i, NONCHAR_DELIM);
1607 setpos(CURCOL+i, CURLINE);
1608 break;
1609 case KEY_EMACS_BACKWARD_WORD:
1610 if(CURCOL == 0 && CURLINE > 0 && curfile->lines->count) {
1611 setpos(strlen((char *)curfile->lines->at(CURLINE-1)),
1612 CURLINE-1);
1613 }
1614
1615 if(CURCOL > 0) {
1616 char *s;
1617 int len, offset = 0;
1618
1619 p = CURSTRING;
1620 len = CURCOL;
1621 s = (char *)malloc(len+1);
1622
1623 for(i = 0; i < len; i++) {
1624 s[i] = p[len-i-1];
1625 }
1626 s[len] = '\0';
1627
1628 if(strchr(NONCHAR_DELIM, p[CURCOL]) ||
1629 strchr(NONCHAR_DELIM, p[CURCOL-1]))
1630 offset = strspn(s, NONCHAR_DELIM);
1631
1632 offset += strcspn(s+offset, NONCHAR_DELIM);
1633
1634 if(offset == CURCOL && strchr(NONCHAR_DELIM, p[0])) {
1635 setpos(strlen((char *)curfile->lines->at(CURLINE-1)),
1636 CURLINE-1);
1637 edmove(KEY_EMACS_BACKWARD_WORD);
1638 } else
1639 setpos(CURCOL-offset, CURLINE);
1640
1641 if(s) free(s);
1642 }
1643 break;
1644 }
1645 }
1646
1647 if(curfile->x >= x2-x1)
1648 switch(k) {
1649
1650 case KEY_RIGHT:
1651 case KEY_LEFT:
1652
1653 i = CURCOL;
1654 curfile->sx += (x2-x1)/3;
1655 curfile->x = i-curfile->sx;
1656 draw();
1657 updatecursor();
1658 break;
1659 }
1660
1661 if(options & EM_MANUAL)
1662 switch(k) {
1663 case KEY_LEFT:
1664 case KEY_RIGHT:
1665 case KEY_HOME:
1666 case KEY_END: abscol = CURCOL; break;
1667 default: if(abscol <= 0) abscol = CURCOL; break;
1668 }
1669
1670 if(options & EM_MANUAL) {
1671 if(curfile->markmode) marktext();
1672 }
1673 }
1674
inschar(int k)1675 void texteditor::inschar(int k) {
1676 if(k == '\t') {
1677
1678 int rm = rtabmargin(true, CURCOL, CURSTRING)-CURCOL, i;
1679 if(rm < 0) rm = rtabmargin(true, CURCOL)-CURCOL;
1680 for(i = 0; i < rm; i++) inschar(' ');
1681
1682 } else {
1683
1684 char *p = CURSTRING;
1685 int len = strlen(p);
1686 char *n = (char *) malloc(len+5);
1687 char np[2];
1688
1689 strcpy(n, p);
1690 sprintf(np, "%c", k);
1691 strinsert(n, CURCOL, np);
1692
1693 if(wrap && strlen(n) > x2-x1-1) {
1694 int cx = CURCOL+1;
1695 int cy = CURLINE;
1696 curfile->lines->replace(CURLINE, n);
1697 modification(uinschar, np);
1698 wrapline(CURLINE, cx, cy); // check for line wrap
1699 setpos(cx, cy);
1700 draw();
1701
1702 } else {
1703 curfile->lines->replace(CURLINE, n);
1704 modification(uinschar, np);
1705
1706 UPDATECURRENTLINE;
1707 edmove(KEY_RIGHT, 0);
1708 }
1709
1710 updatecursor();
1711 abscol = CURCOL;
1712 }
1713 }
1714
setpos(int col,int line)1715 void texteditor::setpos(int col, int line) {
1716 bool drawneeded = false;
1717
1718 CHECKLOADED;
1719
1720 if(line >= curfile->lines->count)
1721 line = curfile->lines->count-1;
1722
1723 if(line < 0)
1724 line = 0;
1725
1726 if((line >= curfile->sy) && (line < curfile->sy+y2-y1)) {
1727 curfile->y = line-curfile->sy;
1728 } else {
1729 if((curfile->sy = line-(y2-y1)/2) < 0) curfile->sy = 0;
1730 if(curfile->sy+y2-y1-1 > curfile->lines->count) {
1731 curfile->sy = curfile->lines->count-y2+y1;
1732 }
1733
1734 if(curfile->sy < 0) curfile->sy = 0;
1735 curfile->y = line-curfile->sy;
1736 drawneeded = true;
1737 }
1738
1739 if((col >= curfile->sx) && (col < curfile->sx+x2-x1)) {
1740 curfile->x = col-curfile->sx;
1741 } else {
1742 char *p = CURSTRING;
1743 if(col > strlen(p)) col = strlen(p);
1744 curfile->sx = 0;
1745
1746 if((curfile->x = col) > x2-x1-1) {
1747 curfile->sx = curfile->x-(x2-x1)/2;
1748 curfile->x -= curfile->sx;
1749 }
1750 drawneeded = true;
1751 }
1752
1753 if(drawneeded) draw();
1754 updatecursor();
1755 }
1756
getpos(int * col,int * line)1757 void texteditor::getpos(int *col, int *line) {
1758 if(col) *col = CURCOL;
1759 if(line) *line = CURLINE;
1760 }
1761
open()1762 int texteditor::open() {
1763 int k, l, go;
1764
1765 if((x2-x1 < 2) || (y2-y1 < 2)) {
1766 return 0;
1767 }
1768
1769 if(fn < 0 || fn > files->count) setfnum(0);
1770
1771 active = true;
1772
1773 if(curfile) if(curfile->lines) {
1774 if(!curfile->lines->count) {
1775 char *p = strdup("");
1776 curfile->lines->add(p);
1777 }
1778
1779 if(CURCOL > CSTRLEN) fix_x(true);
1780 draw();
1781 updatecursor();
1782 }
1783
1784 abscol = CURCOL;
1785
1786 while(active && files->count) {
1787 refresh();
1788 if(idle) go = keypressed(); else go = 1;
1789
1790 if(go) {
1791 k = getkey();
1792 if(emacs) k = emacsbind(k);
1793
1794 switch(k) {
1795 case KEY_UP:
1796 case KEY_DOWN:
1797 case KEY_LEFT:
1798 case KEY_RIGHT:
1799 case KEY_HOME:
1800 case KEY_END:
1801 case KEY_PPAGE:
1802 case KEY_NPAGE:
1803 case KEY_EMACS_BEG_OF_BUFFER:
1804 case KEY_EMACS_END_OF_BUFFER:
1805 case KEY_EMACS_FORWARD_WORD:
1806 case KEY_EMACS_BACKWARD_WORD:
1807 edmove(k, EM_TAB | EM_CTRL | EM_MANUAL);
1808 updatecursor();
1809 break;
1810
1811 default:
1812 if(prevshift) prevshift = curfile->markmode = false;
1813 switch(k) {
1814 case '\r':
1815 if(otherkeys)
1816 if((*otherkeys)(*this, k) == -1) return -1;
1817
1818 if(insertmode || (curfile->lines->count == CURLINE+1)) {
1819 edenter(smarttab);
1820 } else {
1821 edmove(KEY_DOWN);
1822 edmove(KEY_HOME);
1823 }
1824 break;
1825 case KEY_BACKSPACE:
1826 case CTRL('h'):
1827 case 127:
1828 edbackspace();
1829 break;
1830 case CTRL('y'):
1831 eddelline();
1832 break;
1833 case KEY_EMACS_C_U:
1834 eddelbegofline();
1835 break;
1836 case KEY_EMACS_C_K:
1837 eddelendofline();
1838 break;
1839 case KEY_EMACS_C_T:
1840 edtransposechar();
1841 break;
1842 case KEY_EMACS_M_D:
1843 eddelwordemacs();
1844 break;
1845 case KEY_TAB:
1846 inschar('\t');
1847 break;
1848 case CTRL('t'):
1849 eddelword();
1850 break;
1851
1852 default:
1853 if(k >= 32 && k <= 255) {
1854 if(!insertmode && !endofline()) eddel();
1855 inschar(k);
1856 } else if(otherkeys) {
1857 if(!getctrlkeys() && ((k == KEY_IC) || (k == KEY_DC)))
1858 switch(k) {
1859 case KEY_IC: insertmode = !insertmode; break;
1860 case KEY_DC: eddel(); break;
1861 } else {
1862 l = fn;
1863 if((*otherkeys)(*this, k) == -1) return -1;
1864 if(l != fn) {
1865 draw();
1866 updatecursor();
1867 }
1868 }
1869 }
1870 }
1871 }
1872 } else {
1873 if(idle) (*idle)(*this);
1874 }
1875 }
1876
1877 active = false;
1878 return !files->count ? TEXTEDITOR_NOFILES :
1879 0;
1880 }
1881
close()1882 void texteditor::close() {
1883 files->remove(fn);
1884 curfile = 0;
1885
1886 if(files->count) {
1887 int n = fn;
1888 fn = -1;
1889 if(n >= files->count) n = files->count-1;
1890 setfnum(n);
1891 } else {
1892 active = false;
1893 fn = -1;
1894 }
1895 }
1896
find(const char * needle,const char * options,int * col,int * line)1897 bool texteditor::find(const char *needle, const char *options, int *col, int *line) {
1898 const char *f;
1899 char *p;
1900 int i, plus;
1901 enum {fromcur, fromstart, backward} fdirection;
1902 bool casesens = (bool) strchr(options, 's');
1903
1904 if(strchr(options, 't')) {
1905 fdirection = fromstart;
1906 i = 0;
1907 } else if(strchr(options, 'b')) {
1908 fdirection = backward;
1909 i = 0;
1910 } else if(strchr(options, 'c')) {
1911 fdirection = fromcur;
1912 i = CURLINE;
1913 }
1914
1915 for(; i < curfile->lines->count; i++) {
1916 p = (char *) curfile->lines->at(i);
1917
1918 if((fdirection == fromcur) && (i == CURLINE)) plus = CURCOL+1;
1919 else plus = 0;
1920
1921 if(!casesens) f = strqcasestr(p+plus, needle, "");
1922 else f = strstr(p+plus, needle);
1923
1924 if(f) {
1925 *col = (int) (f-p);
1926 *line = i;
1927 return true;
1928 }
1929 }
1930
1931 return false;
1932 }
1933
ismark()1934 bool texteditor::ismark() {
1935 return curfile ? curfile->markmode : false;
1936 }
1937
getline(int ln)1938 char *texteditor::getline(int ln) {
1939 return (char *) (getfcount() ? curfile->lines->at(ln) : 0);
1940 }
1941
putline(int ln,const char * newline)1942 void texteditor::putline(int ln, const char *newline) {
1943 char *p = (char *) curfile->lines->at(ln);
1944 string deltext, instext;
1945
1946 deltext = (string) p + "\n";
1947 instext = (string) newline + "\n";
1948
1949 curfile->lines->replace(ln, (void *) newline);
1950
1951 modification(udelchar, deltext, false, 0, ln);
1952 modification(uinschar, instext, true, 0, ln);
1953 }
1954
redraw()1955 void texteditor::redraw() {
1956 active = (bool) curfile;
1957 draw();
1958 }
1959
highlight(int line,int color)1960 void texteditor::highlight(int line, int color) {
1961 highlight(getfnum(), line, color);
1962 }
1963
highlight(int fn,int line,int color)1964 void texteditor::highlight(int fn, int line, int color) {
1965 editfile *f = (editfile *) files->at(fn);
1966 int i;
1967
1968 if(f) {
1969 if((i = f->highlines->findnum(&line, &findhighline)) != -1) {
1970 f->highlines->remove(i);
1971 }
1972
1973 highline *h = new highline;
1974 h->line = line;
1975 h->color = color;
1976 f->highlines->add(h);
1977 }
1978 }
1979
unlight(int line)1980 void texteditor::unlight(int line) {
1981 unlight(getfnum(), line);
1982 }
1983
unlight(int fn,int line)1984 void texteditor::unlight(int fn, int line) {
1985 int i;
1986 editfile *f = (editfile *) files->at(fn);
1987
1988 if(f) {
1989 if((i = f->highlines->findnum(&line, &findhighline)) != -1) {
1990 f->highlines->remove(i);
1991 }
1992 }
1993 }
1994
clearlight()1995 void texteditor::clearlight() {
1996 clearlight(getfnum());
1997 }
1998
clearlight(int fn)1999 void texteditor::clearlight(int fn) {
2000 editfile *f = (editfile *) files->at(fn);
2001 if(f) f->highlines->empty();
2002 }
2003
switchmark()2004 void texteditor::switchmark() {
2005 CHECKLOADED;
2006
2007 if(ismark()) endmark();
2008 else startmark();
2009 }
2010
shiftident(int x1,int y1,int x2,int y2,int delta)2011 void texteditor::shiftident(int x1, int y1, int x2, int y2, int delta) {
2012 int starty = y1, endy = y2, i;
2013 char *p, *newp;
2014 string origtext, repltext;
2015
2016 CHECKLOADED;
2017 if(!delta) return;
2018 if(x1) starty++;
2019 if(!x2) endy--;
2020
2021 for(i = starty; i <= endy; i++) {
2022 p = (char *) curfile->lines->at(i);
2023
2024 if(delta > 0) {
2025 newp = new char[strlen(p)+delta+1];
2026 sprintf(newp, "%*s%s", delta, "", p);
2027 } else {
2028 if(strspn(p, " ") >= -delta) {
2029 newp = strdup(p-delta);
2030 } else {
2031 newp = strdup(p);
2032 strimlead(newp);
2033 }
2034 }
2035
2036 strimtrail(newp);
2037
2038 if(origtext.empty() && repltext.empty()) {
2039 origtext = p;
2040 repltext = newp;
2041 } else {
2042 origtext += "\n";
2043 repltext += "\n";
2044 origtext += p;
2045 repltext += newp;
2046 }
2047
2048 curfile->lines->replace(i, newp);
2049 }
2050
2051 modification(udelblock, origtext, true, curfile->markblock->x1, curfile->markblock->y1);
2052 modification(uinsblock, repltext, false, curfile->markblock->x1, curfile->markblock->y1);
2053 }
2054
shiftident(int delta)2055 void texteditor::shiftident(int delta) {
2056 CHECKLOADED;
2057 shiftident(curfile->markblock->x1, curfile->markblock->y1,
2058 curfile->markblock->x2, curfile->markblock->y2, delta);
2059 }
2060
undo()2061 void texteditor::undo() {
2062 int i, aline;
2063 undorecord *ur;
2064 tundoaction a;
2065 bool firstpass = true, finished = false;
2066 undolog = show = false;
2067
2068 CHECKLOADED;
2069 while(curfile->undo->count && !finished) {
2070 ur = (undorecord *) curfile->undo->at(curfile->undo->count-1);
2071
2072 if(!firstpass && ((a != ur->action) || (aline != ur->y))) {
2073 if(!ur->prevconnected) break;
2074 finished = true;
2075 } else {
2076 a = ur->action;
2077 aline = ur->y;
2078 }
2079
2080 firstpass = false;
2081 setpos(ur->x, ur->y);
2082
2083 switch(ur->action) {
2084 case uinschar:
2085 case uinsblock:
2086 clearmark();
2087 for(i = 0; i < ur->data.size(); i++) eddel(false);
2088 break;
2089 case udelchar:
2090 case udelblock:
2091 for(i = 0; i < ur->data.size(); i++)
2092 switch(ur->data[i]) {
2093 case '\n':
2094 edenter(false);
2095 edmove(KEY_HOME);
2096 break;
2097 default:
2098 inschar(ur->data[i]);
2099 break;
2100 }
2101 break;
2102 }
2103
2104 curfile->undo->remove(curfile->undo->count-1);
2105 }
2106
2107 abscol = CURCOL;
2108 scancomments(true);
2109 undolog = show = true;
2110 redraw();
2111 }
2112
2113 // --------------------------------------------------------------------------
2114
textblockfree(void * p)2115 void texteditor::textblockfree(void *p) {
2116 textblock *tb = (textblock *) p;
2117 if(tb) delete tb;
2118 }
2119
highlinefree(void * p)2120 void texteditor::highlinefree(void *p) {
2121 highline *hl = (highline *) p;
2122 if(hl) delete hl;
2123 }
2124
editfilefree(void * p)2125 void texteditor::editfilefree(void *p) {
2126 editfile *ef = (editfile *) p;
2127 if(ef) {
2128 delete ef->lines;
2129 delete ef->blocks;
2130 delete ef->highlines;
2131 delete ef->undo;
2132 delete ef->markblock;
2133 free (ef->id) ; /* this is allocated by a c-routine => must deallocated with free */
2134 delete ef;
2135 }
2136 }
2137
undorecordfree(void * p)2138 void texteditor::undorecordfree(void *p) {
2139 undorecord *ur = (undorecord *) p;
2140 if(ur) delete ur;
2141 }
2142
findint(void * p1,void * p2)2143 int texteditor::findint(void *p1, void *p2) {
2144 return (intptr_t) p1 != (intptr_t) p2;
2145 }
2146
findhighline(void * p1,void * p2)2147 int texteditor::findhighline(void *p1, void *p2) {
2148 return (intptr_t) p1 != ((highline *) p2)->line;
2149 }
2150
shiftmarkedblock(int delta)2151 void texteditor::shiftmarkedblock(int delta) {
2152 CHECKLOADED;
2153 if(CURLINE <= curfile->markblock->y1) {
2154 curfile->markblock->y1 += delta;
2155 curfile->markblock->y2 += delta;
2156 } else if((CURLINE > curfile->markblock->y1) && (CURLINE < curfile->markblock->y2)) {
2157 curfile->markblock->y2 += delta;
2158 }
2159 }
2160
prepend(char * text,int ln)2161 void texteditor::prepend(char *text, int ln)
2162 {
2163 if (!text)
2164 return;
2165 char *p = (char *) curfile->lines->at(ln);
2166 if (p) {
2167 char *n = (char *) malloc(strlen(p)+2+strlen(text));
2168 strcpy(n, text);
2169 strcat(n, p);
2170 curfile->lines->replace(ln, n);
2171 } else {
2172 curfile->lines->insert(ln+1, strdup(text));
2173 }
2174 }
2175
wrapline(int ln,int & px,int & py)2176 void texteditor::wrapline(int ln, int &px, int &py)
2177 {
2178 char *p = (char *) curfile->lines->at(ln);
2179
2180 if(wrap && p && strlen(p) > x2-x1-1) { // it's longer than window width and we want it wrapped
2181 char *n = (char *) malloc(strlen(p)+5);
2182 strcpy(n, p);
2183 char *sub = strpbrk(n, WORD_DELIM), *osub = 0, *sep;
2184
2185 if(sub) { // there's some whitespace
2186 while((osub = strpbrk(sub+1, WORD_DELIM)) && // find last word on line
2187 (strspn(osub, WORD_DELIM) < strlen(osub)) &&
2188 ((osub-n)<(x2-x1-1))) sub = osub;
2189 } else {
2190 sub = n+strlen(n)-2;
2191 }
2192
2193 char sins[2] = " ";
2194 sins[0] = *sub;
2195 strinsert(n, sub-n, sins); // append space to the end of line
2196 sub++; // go to previous space position
2197 *sub = 0; // cut the line
2198 sep = sub+1; // first character of line remainder
2199
2200 curfile->lines->replace(ln, n);
2201 prepend(sep, ln+1); // prepend wrapped end of line to beginning of the next one
2202 if (px>=strlen(n)) { // cursor moved to next line
2203 px -= strlen(n);
2204 py++;
2205 wrapline(ln+1, px, py); // wrap again and keep the cursor position updated
2206 } else {
2207 int dx, dy; // dummy
2208 wrapline(ln+1, dx, dy); // just wrap the rest
2209 }
2210 }
2211 }
2212
mergeline(int ln,bool force,int & px,int & py)2213 void texteditor::mergeline(int ln, bool force, int &px, int &py)
2214 {
2215 char *p = (char *) curfile->lines->at(ln);
2216 if (!p || ((!*p || (p[strlen(p)-1]!=' ')) && !force)) // the line is not mergeable
2217 return;
2218 char *next = (char *) curfile->lines->at(ln+1);
2219 int able = x2-x1-strlen(p)-1; // how much space do we have on this line
2220
2221 if(next && (*next || force)) {
2222 if(wrap && (able < strlen(next))) { // not whole next line fits here
2223 char *anext = strdup(next), *asub, *atsub;
2224 anext[able] = 0;
2225
2226 if(asub = strpbrk(anext, WORD_DELIM)) {
2227 int pxdeltamerge;
2228 for(; atsub = strpbrk(asub+1, WORD_DELIM); asub = atsub);
2229 char *newline = new char[strlen(p)+asub-anext+2];
2230 strcpy(newline, p);
2231 if ((ln==(py-1)) && (px<(asub-anext+1))) { // move to previous line
2232 px += strlen(newline);
2233 pxdeltamerge = px; //accepting that change px even if the line is merged
2234 py--;
2235 }
2236 else {
2237 if (ln==(py-1)) {
2238 px -= (asub-anext+1); // move back
2239 pxdeltamerge = px;
2240 }
2241 else
2242 pxdeltamerge = px - (asub-anext+1); //px can't be changed even if the line is merged
2243 }
2244 strncat(newline, next, asub-anext+1);
2245 strcut(next, 0, asub-anext+1);
2246 curfile->lines->replace(ln, newline);
2247 //mergeline(ln+1, false, px, py); // we've merged something from the next line - try to merge it too
2248 mergeline(ln+1, false, pxdeltamerge, py); // we've merged something from the next line - try to merge it too
2249 }
2250
2251 free(anext);
2252 } else { // whole next line fits on this one
2253 int nextlen;
2254 if(next) nextlen = strlen(next); else nextlen = 0;
2255 char *newline = new char[nextlen+strlen(p)+1];
2256
2257 if (ln == (py-1)) {
2258 px += strlen(p);
2259 py--;
2260 }
2261 sprintf(newline, "%s%s", p, nextlen ? next : "");
2262 curfile->lines->replace(ln, newline);
2263 curfile->lines->remove(ln+1);
2264 shiftmarkedblock(-1);
2265
2266 if (wrap && *newline && newline[strlen(newline)-1]==' ') // if it wasn't last one in "paragraph", try to merge with another one
2267 mergeline(ln, false, px, py);
2268 }
2269 }
2270 }
2271
2272 // --------------------------------------------------------------------------
2273
2274 #ifdef __KTOOL_USE_NAMESPACES
2275
2276 using ktool::hlight;
2277
2278 #endif
2279
operator ==(const hl_kind & k) const2280 bool hlight::operator == (const hl_kind &k) const {
2281 return kind == k;
2282 }
2283
operator !=(const hl_kind & k) const2284 bool hlight::operator != (const hl_kind &k) const {
2285 return kind != k;
2286 }
2287
operator <(const hlight & ah) const2288 bool hlight::operator < (const hlight &ah) const {
2289 return kind == h_eol;
2290 }
2291
2292