1 2 3 /* This version of microEmacs is based on the public domain C 4 * version written by Dave G. Conroy. 5 * The D programming language version is written by Walter Bright. 6 * http://www.digitalmars.com/d/ 7 * This program is in the public domain. 8 */ 9 10 /* 11 * The functions in this file are a general set of line management utilities. 12 * They are the only routines that touch the text. They also touch the buffer 13 * and window structures, to make sure that the necessary updating gets done. 14 * There are routines in this file that handle the kill buffer too. It isn't 15 * here for any good reason. 16 * 17 * Note that this code only updates the dot and mark values in the window list. 18 * Since all the code acts on the current window, the buffer that we are 19 * editing must be being displayed, which means that "b_nwnd" is non zero, 20 * which means that the dot and mark values in the buffer headers are nonsense. 21 */ 22 23 module line; 24 25 import core.memory; 26 import core.stdc..string; 27 28 import std.utf; 29 30 import ed; 31 import buffer; 32 import window; 33 import main; 34 import display; 35 import random; 36 37 /* 38 * All text is kept in circularly linked lists of "LINE" structures. These 39 * begin at the header line (which is the blank line beyond the end of the 40 * buffer). This line is pointed to by the "BUFFER". Each line contains the 41 * number of bytes in the line (the "used" size), the size of the text array, 42 * and the text. The end of line is not stored as a byte; it's implied. Future 43 * additions will include update hints, and a list of marks into the line. 44 */ 45 struct LINE { 46 LINE *l_fp; /* Link to the next line */ 47 LINE *l_bp; /* Link to the previous line */ 48 SyntaxState syntaxState; // state at the beginning of the line 49 char[] l_text; /* A bunch of characters. */ 50 } 51 52 LINE* lforw(LINE* lp) { return lp.l_fp; } 53 LINE* lback(LINE* lp) { return lp.l_bp; } 54 char lputc(LINE* lp, int n, char c) { return lp.l_text[n] = c; } 55 int llength(LINE* lp) { return cast(int)lp.l_text.length; } 56 char lgetc(LINE* lp, int n) { return lp.l_text[n]; } 57 58 bool empty(LINE* lp, int n) { return lp == curbp.b_linep; } 59 int front(LINE* lp, int n) { return n == llength(lp) ? '\n' : lgetc(lp, n); } 60 61 void popFront(ref LINE* lp, ref int n) 62 { 63 if (n < llength(lp)) 64 n += 1; 65 else 66 { 67 lp = lforw(lp); 68 n = 0; 69 } 70 } 71 72 bool atFront(LINE* lp, int n) { return n == 0 && lback(lp) == curbp.b_linep; } 73 74 void popBack(ref LINE* lp, ref int n) 75 { 76 if (n) 77 n -= 1; 78 else 79 { 80 lp = lback(lp); 81 n = llength(lp); 82 } 83 } 84 85 int peekBack(LINE* lp, int n) 86 { 87 popBack(lp, n); 88 return front(lp, n); 89 } 90 91 /* 92 * This routine allocates a block of memory large enough to hold a LINE 93 * containing "used" characters. The block is always rounded up a bit. Return 94 * a pointer to the new block, or null if there isn't any memory left. Print a 95 * message in the message line if no space. 96 */ 97 98 LINE* line_realloc(LINE* lpold, int used) 99 { 100 if (!lpold) 101 lpold = new LINE; 102 lpold.l_text.length = used; 103 return lpold; 104 } 105 106 /* 107 * Delete line "lp". Fix all of the links that might point at it (they are 108 * moved to offset 0 of the next line). Unlink the line from whatever buffer it 109 * might be in. Release the memory. The buffers are updated too; the magic 110 * conditions described in the above comments don't hold here. 111 */ 112 void line_free(LINE* lp) 113 { 114 foreach (wp; windows) 115 { 116 if (wp.w_linep == lp) 117 wp.w_linep = lp.l_fp; 118 if (wp.w_dotp == lp) { 119 wp.w_dotp = lp.l_fp; 120 wp.w_doto = 0; 121 } 122 if (wp.w_markp == lp) { 123 wp.w_markp = lp.l_fp; 124 wp.w_marko = 0; 125 } 126 } 127 foreach (bp; buffers) 128 { 129 assert(bp); 130 /* If there are windows on this buffer, the dot and mark */ 131 /* values are nonsense. */ 132 if (bp.b_nwnd == 0) /* if no windows on this buffer */ 133 { 134 /* update dot or mark in the buffer */ 135 if (bp.b_dotp == lp) { 136 bp.b_dotp = lp.l_fp; 137 bp.b_doto = 0; 138 } 139 if (bp.b_markp == lp) { 140 bp.b_markp = lp.l_fp; 141 bp.b_marko = 0; 142 } 143 } 144 } 145 lp.l_bp.l_fp = lp.l_fp; 146 lp.l_fp.l_bp = lp.l_bp; 147 //delete lp; 148 core.memory.GC.free(lp); 149 } 150 151 /* 152 * This routine gets called when a character is changed in place in the current 153 * buffer. It updates all of the required flags in the buffer and window 154 * system. The flag used is passed as an argument; if the buffer is being 155 * displayed in more than 1 window we change EDIT to HARD. Set MODE if the 156 * mode line needs to be updated (the "*" has to be set). 157 */ 158 void line_change(int flag) 159 { 160 if (curwp.w_markp) /* if marking */ 161 curwp.w_flag |= WFMOVE; /* so highlighting is updated */ 162 if ((curbp.b_flag&(BFCHG|BFRDONLY)) == 0) /* First change, so */ 163 { flag |= WFMODE; /* update mode lines */ 164 curbp.b_flag |= BFCHG; 165 } 166 foreach (wp; windows) 167 { 168 if (wp.w_bufp == curbp) 169 { 170 wp.w_flag |= flag; 171 if (wp != curwp) 172 wp.w_flag |= WFHARD; 173 } 174 } 175 } 176 177 /* 178 * Insert "n" copies of the character "c" at the current location of dot. In 179 * the easy case all that happens is the text is stored in the line. In the 180 * hard case, the line has to be reallocated. When the window list is updated, 181 * take special care; I screwed it up once. You always update dot in the 182 * current window. You update mark, and a dot in another window, if it is 183 * greater than the place where you did the insert. Return TRUE if all is 184 * well, and FALSE on errors. 185 */ 186 int line_insert(int n, char c) 187 { 188 LINE *lp1; 189 LINE *lp2; 190 LINE *lp3; 191 int doto; 192 193 if (curbp.b_flag & BFRDONLY) /* if buffer is read-only */ 194 return FALSE; /* error */ 195 line_change(WFEDIT); 196 lp1 = curwp.w_dotp; /* Current line */ 197 if (lp1 == curbp.b_linep) { /* At the end: special */ 198 if (curwp.w_doto != 0) { 199 mlwrite("bug: line_insert"); 200 return (FALSE); 201 } 202 lp2 = line_realloc(null, n); /* Allocate new line */ 203 lp3 = lp1.l_bp; /* Previous line */ 204 lp3.l_fp = lp2; /* Link in */ 205 lp2.l_fp = lp1; 206 lp1.l_bp = lp2; 207 lp2.l_bp = lp3; 208 lp2.l_text[0 .. n] = c; 209 curwp.w_dotp = lp2; 210 curwp.w_doto = n; 211 return (TRUE); 212 } 213 doto = curwp.w_doto; /* Save for later. */ 214 lp2 = lp1; 215 lp2.l_text.length = lp2.l_text.length + n; 216 217 memmove(lp2.l_text.ptr + doto + n, 218 lp2.l_text.ptr + doto, 219 (lp2.l_text.length - n - doto) * char.sizeof); 220 if (n == 1) 221 lp2.l_text[doto] = c; 222 else 223 lp2.l_text[doto .. doto + n] = c; 224 225 /* Update windows */ 226 foreach (wp; windows) 227 { if (wp.w_linep == lp1) 228 wp.w_linep = lp2; 229 if (wp.w_dotp == lp1) { 230 wp.w_dotp = lp2; 231 if (wp==curwp || wp.w_doto>doto) 232 wp.w_doto += n; 233 } 234 if (wp.w_markp == lp1) { 235 wp.w_markp = lp2; 236 if (wp.w_marko > doto) 237 wp.w_marko += n; 238 } 239 } 240 241 return (TRUE); 242 } 243 244 /*************************** 245 * Same as line_insert(), but for overwrite mode. 246 */ 247 248 int line_overwrite(int n, char c) 249 { int status = true; 250 251 while (n-- > 0) 252 { if (curwp.w_doto < llength(curwp.w_dotp)) 253 status = random_forwdel(FALSE,1); 254 if (status) 255 status = line_insert(1,c); 256 if (!status) 257 break; 258 } 259 return status; 260 } 261 262 /******************************************** 263 * Insert a newline into the buffer at the current location of dot in the 264 * current window. The funny ass-backwards way it does things is not a botch; 265 * it just makes the last line in the file not a special case. Return TRUE if 266 * everything works out and FALSE on error (memory allocation failure). The 267 * update of dot and mark is a bit easier then in the above case, because the 268 * split forces more updating. 269 */ 270 int line_newline() 271 { 272 LINE *lp1; 273 LINE *lp2; 274 int doto; 275 276 if (curbp.b_flag & BFRDONLY) /* if buffer is read-only */ 277 return FALSE; /* error */ 278 lp1 = curwp.w_dotp; /* Get the address and */ 279 doto = curwp.w_doto; /* offset of "." */ 280 lp2 = line_realloc(null,doto); /* New first half line */ 281 lp2.l_text[0 .. doto] = lp1.l_text[0 .. doto]; 282 memmove(lp1.l_text.ptr, lp1.l_text.ptr + doto, (lp1.l_text.length - doto) * char.sizeof); 283 lp1.l_text.length = lp1.l_text.length - doto; 284 285 lp2.l_bp = lp1.l_bp; 286 lp1.l_bp = lp2; 287 lp2.l_bp.l_fp = lp2; 288 lp2.l_fp = lp1; 289 290 foreach (wp; windows) 291 { 292 if (wp.w_linep == lp1) 293 wp.w_linep = lp2; 294 if (wp.w_dotp == lp1) { 295 if (wp.w_doto < doto) 296 wp.w_dotp = lp2; 297 else 298 wp.w_doto -= doto; 299 } 300 if (wp.w_markp == lp1) { 301 if (wp.w_marko < doto) 302 wp.w_markp = lp2; 303 else 304 wp.w_marko -= doto; 305 } 306 } 307 line_change(WFHARD); 308 return (TRUE); 309 } 310 311 /* 312 * This function deletes "n" bytes, starting at dot. It understands how do deal 313 * with end of lines, etc. It returns TRUE if all of the characters were 314 * deleted, and FALSE if they were not (because dot ran into the end of the 315 * buffer). The "kflag" is TRUE if the text should be put in the kill buffer. 316 */ 317 bool line_delete(int n, bool kflag) 318 { 319 LINE* dotp; 320 int doto; 321 int chunk; 322 323 if (curbp.b_flag & BFRDONLY) /* if buffer is read-only */ 324 return FALSE; /* error */ 325 while (n != 0) { 326 dotp = curwp.w_dotp; 327 doto = curwp.w_doto; 328 if (dotp == curbp.b_linep) /* Hit end of buffer. */ 329 return (FALSE); 330 chunk = cast(int)dotp.l_text.length - doto; /* Size of chunk. */ 331 if (chunk > n) 332 chunk = n; 333 if (chunk == 0) { /* End of line, merge. */ 334 line_change(WFHARD); 335 if (line_delnewline() == FALSE 336 || (kflag!=FALSE && kill_appendchar('\n')==FALSE)) 337 return (FALSE); 338 --n; 339 continue; 340 } 341 line_change(WFEDIT); 342 if (kflag != FALSE) { /* Kill? */ 343 if (!kill_appendstring(dotp.l_text[doto .. doto + chunk])) 344 return FALSE; 345 } 346 memmove(dotp.l_text.ptr + doto, 347 dotp.l_text.ptr + doto + chunk, 348 (dotp.l_text.length - chunk - doto) * char.sizeof); 349 dotp.l_text.length = dotp.l_text.length - chunk; 350 351 foreach (wp; windows) 352 { 353 if (wp.w_dotp==dotp && wp.w_doto>=doto) { 354 wp.w_doto -= chunk; 355 if (wp.w_doto < doto) 356 wp.w_doto = doto; 357 } 358 if (wp.w_markp==dotp && wp.w_marko>=doto) { 359 wp.w_marko -= chunk; 360 if (wp.w_marko < doto) 361 wp.w_marko = doto; 362 } 363 } 364 n -= chunk; 365 } 366 return (TRUE); 367 } 368 369 /* 370 * Delete a newline. Join the current line with the next line. If the next line 371 * is the magic header line always return TRUE; merging the last line with the 372 * header line can be thought of as always being a successful operation, even 373 * if nothing is done, and this makes the kill buffer work "right". Easy cases 374 * can be done by shuffling data around. Hard cases require that lines be moved 375 * about in memory. Return FALSE on error and TRUE if all looks ok. Called by 376 * "line_delete" only. 377 */ 378 bool line_delnewline() 379 { 380 LINE *lp1; 381 LINE *lp2; 382 LINE *lp3; 383 int lp1used; 384 385 if (curbp.b_flag & BFRDONLY) /* if buffer is read-only */ 386 return FALSE; /* error */ 387 lp1 = curwp.w_dotp; 388 lp2 = lp1.l_fp; 389 lp1used = cast(int)lp1.l_text.length; 390 if (lp2 == curbp.b_linep) { /* At the buffer end. */ 391 if (lp1used == 0) /* Blank line. */ 392 line_free(lp1); 393 return (TRUE); 394 } 395 lp3 = line_realloc(lp1, lp1used + cast(int)lp2.l_text.length); 396 lp3.l_bp.l_fp = lp3; 397 398 memmove(lp3.l_text.ptr + lp1used, lp2.l_text.ptr, lp2.l_text.length * char.sizeof); 399 lp3.l_fp = lp2.l_fp; 400 lp3.l_fp.l_bp = lp3; 401 402 foreach (wp; windows) 403 { 404 if (wp.w_linep==lp1 || wp.w_linep==lp2) 405 wp.w_linep = lp3; 406 if (wp.w_dotp == lp1) 407 wp.w_dotp = lp3; 408 else if (wp.w_dotp == lp2) { 409 wp.w_dotp = lp3; 410 wp.w_doto += lp1used; 411 } 412 if (wp.w_markp == lp1) 413 wp.w_markp = lp3; 414 else if (wp.w_markp == lp2) { 415 wp.w_markp = lp3; 416 wp.w_marko += lp1used; 417 } 418 } 419 420 //delete lp2.l_text; 421 //delete lp2; 422 core.memory.GC.free(lp2.l_text.ptr); 423 core.memory.GC.free(lp2); 424 425 return (TRUE); 426 } 427 428 429 /********************** KILL BUFFER STUFF *********************/ 430 431 struct killbuf_t 432 { 433 char[] buf; 434 } 435 436 __gshared killbuf_t[4] killbuffer; 437 __gshared killbuf_t *kbp = &killbuffer[0]; /* current kill buffer */ 438 439 /************************************ 440 * Set the current kill buffer to i. 441 */ 442 443 void kill_setbuffer(int i) 444 { 445 kbp = &killbuffer[i]; 446 } 447 448 void kill_toClipboard() 449 { 450 version (Windows) 451 { 452 import console; 453 454 if (kbp == &killbuffer[0]) 455 setClipboard(kbp.buf); 456 } 457 } 458 459 /* 460 * Delete all of the text saved in the kill buffer. Called by commands when a 461 * new kill context is being created. The kill buffer array is released, just 462 * in case the buffer has grown to immense size. No errors. 463 */ 464 void kill_freebuffer() 465 { 466 //delete kbp.buf; 467 core.memory.GC.free(kbp.buf.ptr); 468 kbp.buf = null; 469 } 470 471 void kill_fromClipboard() 472 { 473 version (Windows) 474 { 475 import console; 476 477 if (kbp == &killbuffer[0]) 478 { 479 auto s = getClipboard(); 480 if (s) 481 { 482 kill_freebuffer(); 483 kbp.buf = s; 484 } 485 } 486 } 487 } 488 489 /* 490 * Append a character to the kill buffer, enlarging the buffer if there isn't 491 * any room. Always grow the buffer in chunks, on the assumption that if you 492 * put something in the kill buffer you are going to put more stuff there too 493 * later. Return TRUE if all is well, and FALSE on errors. 494 */ 495 bool kill_appendchar(char c) 496 { 497 kbp.buf ~= c; 498 return (TRUE); 499 } 500 501 /******************************** 502 * Append string to kill buffer. 503 */ 504 505 bool kill_appendstring(const char[] s) 506 { 507 kbp.buf ~= s; 508 return (TRUE); 509 } 510 511 /* 512 * This function gets characters from the kill buffer. If the character index 513 * "n" is off the end, it returns "-1". This lets the caller just scan along 514 * until it gets a "-1" back. 515 */ 516 int kill_remove(int n) 517 { 518 return (n >= kbp.buf.length) ? -1 : kbp.buf[n]; 519 } 520 521 /******************************** 522 * We're going to use at least size bytes, so make room for it. 523 * Returns: 524 * FALSE out of memory 525 */ 526 527 int kill_setsize(int size) 528 { 529 auto oldlength = kbp.buf.length; 530 kbp.buf.length = size; 531 kbp.buf.length = oldlength; 532 return TRUE; 533 }