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 routines in this file implement commands that work word at a time. 12 * There are all sorts of word mode commands. If I do any sentence and/or 13 * paragraph mode commands, they are likely to be put in this file. 14 */ 15 16 module word; 17 18 import std.ascii; 19 20 import ed; 21 import main; 22 import window; 23 import random; 24 import line; 25 import terminal; 26 import region; 27 import basic; 28 import display; 29 30 /* Word wrap. Back-over whatever precedes the point on the current 31 * line and stop on the first word-break or the beginning of the line. If we 32 * reach the beginning of the line, jump back to the end of the word and start 33 * a new line. Otherwise, break the line at the word-break, eat it, and jump 34 * back to the end of the word. 35 * NOTE: This function may leaving trailing blanks. 36 * Returns true on success, false on errors. 37 */ 38 int word_wrap(bool f, int n) 39 { 40 int cnt; 41 LINE* oldp; 42 43 oldp = curwp.w_dotp; 44 cnt = -1; 45 do { 46 cnt++; 47 if (! backchar(false, 1)) 48 goto err; 49 } while (! inword()); 50 if (! word_back(false, 1)) 51 goto err; 52 /* If still on same line (but not at the beginning) */ 53 if (oldp == curwp.w_dotp && curwp.w_doto) 54 { int i; 55 56 if (!random_backdel(false, 1)) 57 goto err; 58 if (!random_newline(false, 1)) 59 goto err; 60 oldp = lback(curwp.w_dotp); 61 i = 0; 62 while (1) 63 { 64 auto c = lgetc(oldp,i); 65 if (c != ' ' && c != '\t') 66 break; 67 line_insert(1,c); 68 i++; 69 } 70 } 71 while (inword() == true) 72 if (forwchar(false, 1) == false) 73 goto err; 74 return forwchar(false, cnt); 75 76 err: 77 return false; 78 } 79 80 /**************************** 81 * Word wrap the current line. 82 */ 83 84 int word_wrap_line(bool f, int n) 85 { 86 int i; 87 int j; 88 int col; 89 char c; 90 int inword; 91 int lasti; 92 LINE* oldp; 93 LINE* dotpsave; 94 int dotosave; 95 96 if (n < 0) 97 goto err; 98 99 if (window_marking(curwp)) 100 { REGION region; 101 int s; 102 103 if ((s = getregion(®ion)) != true) 104 return s; 105 dotpsave = curwp.w_dotp; 106 dotosave = curwp.w_doto; 107 curwp.w_dotp = region.r_linep; 108 curwp.w_doto = region.r_offset; 109 n = region.r_nlines; 110 } 111 112 while (n-- > 0) 113 { 114 L1: 115 col = 0; 116 lasti = 0; 117 inword = 0; 118 for (i = 0; i < llength(curwp.w_dotp); i++) 119 { 120 c = lgetc(curwp.w_dotp, i); 121 if (c == ' ' || c == '\t') 122 { 123 if (inword) 124 lasti = i; 125 inword = 0; 126 } 127 else 128 { 129 inword = 1; 130 } 131 col = getcol(curwp.w_dotp, i); 132 if (col >= term.t_ncol && lasti) 133 { 134 if (!forwchar(0, lasti - curwp.w_doto)) 135 goto err; 136 if (!random_newline(0,1)) 137 goto err; 138 139 /* Remove leading whitespace from new line */ 140 while (1) 141 { 142 if (!llength(curwp.w_dotp)) 143 break; 144 c = lgetc(curwp.w_dotp, 0); 145 if (c == ' ' || c == '\t') 146 { 147 if (!random_forwdel(0, 1)) 148 goto err; 149 } 150 else 151 break; 152 } 153 154 /* Match indenting of original line (oldp) */ 155 oldp = lback(curwp.w_dotp); 156 for (j = 0; j < llength(oldp); j++) 157 { 158 c = lgetc(oldp, j); 159 if (c == ' ' || c == '\t') 160 { 161 if (!line_insert(1, c)) 162 goto err; 163 } 164 else 165 break; 166 } 167 168 goto L1; 169 } 170 } 171 if (!forwline(0, 1)) 172 goto err; 173 } 174 if (window_marking(curwp)) 175 { 176 if (dotosave > llength(dotpsave)) 177 dotosave = llength(dotpsave); 178 curwp.w_dotp = dotpsave; 179 curwp.w_doto = dotosave; 180 } 181 return true; 182 183 err: 184 return false; 185 } 186 187 /************************* 188 * Select word that the cursor is on. 189 */ 190 191 int word_select(bool f, int n) 192 { 193 int inw; 194 int s; 195 196 inw = inword(); 197 do 198 s = backchar(false, 1); 199 while (s && inword() == inw); 200 201 return s && 202 forwchar(false,1) && 203 basic_setmark(false,1) && 204 word_forw(f,n); 205 } 206 207 /****************************** 208 * Select line that the cursor is on. 209 */ 210 211 int word_lineselect(bool f, int n) 212 { 213 return (curwp.w_doto == 0 || gotobol(false,1)) && 214 basic_setmark(false,1) && 215 forwline(f,n); 216 } 217 218 /* 219 * Move the cursor backward by "n" words. All of the details of motion are 220 * performed by the "backchar" and "forwchar" routines. Error if you try to 221 * move beyond the buffers. 222 */ 223 int word_back(bool f, int n) 224 { 225 if (n < 0) 226 return (word_forw(f, -n)); 227 if (backchar(false, 1) == false) 228 return (false); 229 while (n--) { 230 auto inw = inword(); 231 do 232 if (backchar(false, 1) == false) 233 return (false); 234 while (inword() == inw); 235 } 236 return (forwchar(false, 1)); 237 } 238 239 /* 240 * Move the cursor forward by the specified number of words. All of the motion 241 * is done by "forwchar". Error if you try and move beyond the buffer's end. 242 */ 243 int word_forw(bool f, int n) 244 { 245 if (n < 0) 246 return (word_back(f, -n)); 247 while (n--) { 248 auto inw = inword(); 249 do 250 if (forwchar(false, 1) == false) 251 return (false); 252 while (inword() == inw); 253 } 254 return (true); 255 } 256 257 /* 258 * Move the cursor forward by the specified number of words. As you move, 259 * convert any characters to upper case. Error if you try and move beyond the 260 * end of the buffer. Bound to "M-U". 261 */ 262 int word_upper(bool f, int n) 263 { 264 return word_setcase(f,n,0); 265 } 266 267 /* 268 * Move the cursor forward by the specified number of words. As you move 269 * convert characters to lower case. Error if you try and move over the end of 270 * the buffer. Bound to "M-L". 271 */ 272 int word_lower(bool f, int n) 273 { 274 return word_setcase(f,n,1); 275 } 276 277 /************************* 278 * Move the cursor forward by the specified number of words. As you move 279 * convert the first character of the word to upper case, and subsequent 280 * characters to lower case. Error if you try and move past the end of the 281 * buffer. Bound to "M-C". 282 */ 283 284 int capword(bool f, int n) 285 { 286 return word_setcase(f,n,2); 287 } 288 289 private int word_setcase(bool f, int n, int flag) 290 { 291 char c; 292 293 if (n < 0) 294 return (false); 295 while (n--) { 296 while (inword() == false) { 297 if (forwchar(false, 1) == false) 298 return (false); 299 } 300 if (flag == 2 && inword() != false) { 301 c = lgetc(curwp.w_dotp, curwp.w_doto); 302 if (isLower(c)) 303 { c -= 'a'-'A'; 304 lputc(curwp.w_dotp, curwp.w_doto, c); 305 line_change(WFHARD); 306 } 307 if (forwchar(false, 1) == false) 308 return (false); 309 } 310 while (inword() != false) { 311 c = lgetc(curwp.w_dotp, curwp.w_doto); 312 final switch (flag) 313 { case 0: 314 if (isLower(c)) { 315 c -= 'a'-'A'; 316 goto L1; 317 } 318 break; 319 case 1: 320 case 2: 321 if (isUpper(c)) { 322 c += 'a'-'A'; 323 L1: lputc(curwp.w_dotp, curwp.w_doto, c); 324 line_change(WFHARD); 325 } 326 break; 327 } 328 if (forwchar(false, 1) == false) 329 return (false); 330 } 331 } 332 return (true); 333 } 334 335 /* 336 * Kill forward by "n" words. Remember the location of dot. Move forward by 337 * the right number of words. Put dot back where it was and issue the kill 338 * command for the right number of characters. Bound to "M-D". 339 */ 340 int delfword(bool f, int n) 341 { 342 int size; 343 LINE* dotp; 344 int doto; 345 346 if (n < 0) 347 return (false); 348 dotp = curwp.w_dotp; 349 doto = curwp.w_doto; 350 size = 0; 351 while (n--) { 352 while (inword() == false) { 353 if (forwchar(false, 1) == false) 354 return (false); 355 ++size; 356 } 357 while (inword() != false) { 358 if (forwchar(false, 1) == false) 359 return (false); 360 ++size; 361 } 362 } 363 curwp.w_dotp = dotp; 364 curwp.w_doto = doto; 365 return (line_delete(size, true)); 366 } 367 368 /* 369 * Kill backwards by "n" words. Move backwards by the desired number of words, 370 * counting the characters. When dot is finally moved to its resting place, 371 * fire off the kill command. Bound to "M-Rubout" and to "M-Backspace". 372 */ 373 int delbword(bool f, int n) 374 { 375 int size; 376 377 if (n < 0) 378 return (false); 379 if (backchar(false, 1) == false) 380 return (false); 381 size = 0; 382 while (n--) { 383 while (inword() == false) { 384 if (backchar(false, 1) == false) 385 return (false); 386 ++size; 387 } 388 while (inword() != false) { 389 if (backchar(false, 1) == false) 390 return (false); 391 ++size; 392 } 393 } 394 if (forwchar(false, 1) == false) 395 return false; 396 return line_delete(size, true); 397 } 398 399 /* 400 * Return true if the character at dot is a character that is considered to be 401 * part of a word. The word character list is hard coded. Should be setable. 402 * This routine MUST return only a 1 or a 0. 403 */ 404 bool inword() 405 { 406 if (curwp.w_doto == llength(curwp.w_dotp)) 407 return false; 408 auto c = lgetc(curwp.w_dotp, curwp.w_doto); 409 return (isAlphaNum(c) || 410 c=='$' || c=='_'); /* For identifiers */ 411 }