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 move the cursor around on the screen. They 12 * compute a new value for the cursor, then adjust ".". The display code 13 * always updates the cursor location, so only moves between lines, or 14 * functions that adjust the top line in the window and invalidate the 15 * framing, are hard. 16 */ 17 18 module basic; 19 20 import std.conv; 21 22 import ed; 23 import line; 24 import main; 25 import window; 26 import display; 27 import console; 28 29 /********************************* 30 * Move the cursor to the 31 * beginning of the current line. 32 * Trivial. 33 */ 34 35 int gotobol(bool f, int n) 36 { int s; 37 38 if (curwp.w_doto == 0) 39 s = backline(f, n); 40 else 41 { 42 if (curwp.w_markp) 43 curwp.w_flag |= WFMOVE; 44 s = TRUE; 45 curwp.w_doto = 0; 46 if( n > 1 ) 47 s = backline(f, n-1); 48 } 49 curgoal = 0; 50 return s; 51 } 52 53 /* 54 * Move the cursor backwards by "n" characters. If "n" is less than zero call 55 * "forwchar" to actually do the move. Otherwise compute the new cursor 56 * location. Error if you try and move out of the buffer. Set the flag if the 57 * line pointer for dot changes. 58 */ 59 int backchar(bool f, int n) 60 { 61 if (n < 0) 62 return (forwchar(f, -n)); 63 if (curwp.w_markp && n) 64 curwp.w_flag |= WFMOVE; 65 while (n--) { 66 if (curwp.w_doto == 0) { 67 LINE *lp; 68 if ((lp=lback(curwp.w_dotp)) == curbp.b_linep) 69 return (FALSE); 70 curwp.w_dotp = lp; 71 curwp.w_doto = llength(lp); 72 curwp.w_flag |= WFMOVE; 73 } else 74 curwp.w_doto--; 75 } 76 return (TRUE); 77 } 78 79 /************************************** 80 * Move the cursor to the end of the current line. 81 * If already at the end, advance to next line. 82 */ 83 84 int gotoeol(bool f, int n) 85 { 86 int s; 87 88 s = TRUE; 89 if( curwp.w_doto != llength(curwp.w_dotp) ) 90 { 91 if (curwp.w_markp) 92 curwp.w_flag |= WFMOVE; 93 n--; 94 } 95 if( n > 0 ) 96 s = forwline(f,n); 97 curwp.w_doto = llength(curwp.w_dotp); 98 return( s ); 99 } 100 101 /* 102 * Move the cursor forwards by "n" characters. If "n" is less than zero call 103 * "backchar" to actually do the move. Otherwise compute the new cursor 104 * location, and move ".". Error if you try and move off the end of the 105 * buffer. Set the flag if the line pointer for dot changes. 106 */ 107 int forwchar(bool f, int n) 108 { 109 if (n < 0) 110 return (backchar(f, -n)); 111 if (curwp.w_markp && n) 112 curwp.w_flag |= WFMOVE; 113 while (n--) { 114 if (curwp.w_doto == llength(curwp.w_dotp)) { 115 if (curwp.w_dotp == curbp.b_linep) 116 return (FALSE); 117 curwp.w_dotp = lforw(curwp.w_dotp); 118 curwp.w_doto = 0; 119 curwp.w_flag |= WFMOVE; 120 } else 121 curwp.w_doto++; 122 } 123 return (TRUE); 124 } 125 126 /* 127 * Goto the beginning of the buffer. Massive adjustment of dot. This is 128 * considered to be hard motion; it really isn't if the original value of dot 129 * is the same as the new value of dot. Normally bound to "M-<". 130 */ 131 int gotobob(bool f, int n) 132 { 133 curwp.w_dotp = lforw(curbp.b_linep); 134 curwp.w_doto = 0; 135 curwp.w_flag |= WFHARD; 136 return (TRUE); 137 } 138 139 /* 140 * Move to the end of the buffer. Dot is always put at the end of the file 141 * (ZJ). The standard screen code does most of the hard parts of update. 142 * Bound to "M.". 143 */ 144 int gotoeob(bool f, int n) 145 { 146 curwp.w_dotp = curbp.b_linep; 147 curwp.w_doto = 0; 148 curwp.w_flag |= WFHARD; 149 return (TRUE); 150 } 151 152 /* 153 * Move forward by full lines. If the number of lines to move is less than 154 * zero, call the backward line function to actually do it. The last command 155 * controls how the goal column is set. Bound to "C-N". No errors are 156 * possible. 157 */ 158 int forwline(bool f, int n) 159 { 160 if (n < 0) 161 return (backline(f, -n)); 162 auto dlp = curwp.w_dotp; 163 164 /* Reset goal if last command not backline() or forwline() */ 165 if ((lastflag&CFCPCN) == 0) 166 curgoal = getcol(dlp,curwp.w_doto); 167 thisflag |= CFCPCN; /* this command was a */ 168 /* forwline or backline */ 169 while (n-- && dlp!=curbp.b_linep) 170 dlp = lforw(dlp); 171 curwp.w_dotp = dlp; 172 curwp.w_doto = getgoal(dlp); 173 curwp.w_flag |= WFMOVE; 174 return (TRUE); 175 } 176 177 /******************************* 178 * Proceed to beginning of next line. 179 */ 180 181 int basic_nextline(bool f, int n) 182 { 183 if (curwp.w_doto == 0 || gotobol(FALSE,1)) 184 { 185 lastflag &= ~CFCPCN; 186 return forwline(f,n); 187 } 188 return FALSE; 189 } 190 191 /* 192 * This function is like "forwline", but goes backwards. The scheme is exactly 193 * the same. Check for arguments that are less than zero and call your 194 * alternate. Figure out the new line and call "movedot" to perform the 195 * motion. No errors are possible. Bound to "C-P". 196 */ 197 int backline(bool f, int n) 198 { 199 if (n < 0) 200 return (forwline(f, -n)); 201 auto dlp = curwp.w_dotp; 202 203 /* Reset goal if last command not backline() or forwline() */ 204 if ((lastflag&CFCPCN) == 0) 205 curgoal = getcol(dlp,curwp.w_doto); 206 thisflag |= CFCPCN; 207 208 while (n-- && lback(dlp)!=curbp.b_linep) 209 dlp = lback(dlp); 210 curwp.w_dotp = dlp; 211 curwp.w_doto = getgoal(dlp); 212 curwp.w_flag |= WFMOVE; 213 return (TRUE); 214 } 215 216 /********************************** 217 * Goto line number. 218 */ 219 220 int gotoline(bool f, int n) 221 { string number; 222 223 if (mlreply("Goto line: ", null, number) == FALSE) 224 return FALSE; 225 try 226 { 227 const num = to!(int)(number); 228 gotobob(f, n); /* move to beginning of buffer */ 229 return forwline(f, num - 1); 230 } 231 catch (Throwable o) 232 { 233 } 234 return FALSE; 235 } 236 237 /* 238 * This routine, given a pointer to a LINE, and the current cursor goal 239 * column, return the best choice for the offset. The offset is returned. 240 * Used by forwline() and backline(). 241 */ 242 int getgoal(LINE* dlp) 243 { 244 int c; 245 int col; 246 int newcol; 247 int dbo; 248 249 col = 0; 250 dbo = 0; 251 while (dbo != llength(dlp)) { 252 c = lgetc(dlp, dbo); 253 newcol = col; 254 if (c == '\t') 255 newcol |= 0x07; 256 else if (c<0x20 || c==0x7F) 257 ++newcol; 258 ++newcol; 259 if (newcol > curgoal) 260 break; 261 col = newcol; 262 ++dbo; 263 } 264 return (dbo); 265 } 266 267 /* 268 * Scroll forward by a specified number of lines, or by a full page if no 269 * argument. Bound to "C-V". The "2" in the arithmetic on the window size is 270 * the overlap; this value is the default overlap value in ITS EMACS. Because 271 * this zaps the top line in the display window, we have to do a hard update. 272 */ 273 int forwpage(bool f, int n) 274 { 275 if (f == FALSE) { 276 n = curwp.w_ntrows - 2; /* Default scroll. */ 277 if (n <= 0) /* Forget the overlap */ 278 n = 1; /* if tiny window. */ 279 } else if (n < 0) 280 return (backpage(f, -n)); 281 else if (CVMVAS) /* Convert from pages */ 282 n *= curwp.w_ntrows; /* to lines. */ 283 auto lp = curwp.w_linep; 284 while (n-- && lp!=curbp.b_linep) 285 lp = lforw(lp); 286 curwp.w_linep = lp; 287 curwp.w_dotp = lp; 288 curwp.w_doto = 0; 289 curwp.w_flag |= WFHARD; 290 return (TRUE); 291 } 292 293 /* 294 * This command is like "forwpage", but it goes backwards. The "2", like 295 * above, is the overlap between the two windows. The value is from the ITS 296 * EMACS manual. Bound to "M-V". We do a hard update for exactly the same 297 * reason. 298 */ 299 int backpage(bool f, int n) 300 { 301 if (f == FALSE) { 302 n = curwp.w_ntrows - 2; /* Default scroll. */ 303 if (n <= 0) /* Don't blow up if the */ 304 n = 1; /* window is tiny. */ 305 } else if (n < 0) 306 return (forwpage(f, -n)); 307 else if (CVMVAS) /* Convert from pages */ 308 n *= curwp.w_ntrows; /* to lines. */ 309 auto lp = curwp.w_linep; 310 while (n-- && lback(lp)!=curbp.b_linep) 311 lp = lback(lp); 312 curwp.w_linep = lp; 313 curwp.w_dotp = lp; 314 curwp.w_doto = 0; 315 curwp.w_flag |= WFHARD; 316 return (TRUE); 317 } 318 319 /* 320 * Set the mark in the current window to the value of "." in the window. No 321 * errors are possible. Bound to "M-.". 322 */ 323 int basic_setmark(bool f, int n) 324 { 325 removemark(f,n); /* delete old mark */ 326 curwp.w_markp = curwp.w_dotp; 327 curwp.w_marko = curwp.w_doto; 328 /* Get starting column for column regions */ 329 markcol = getcol(curwp.w_markp,curwp.w_doto); 330 mlwrite("[Mark set]"); 331 return (TRUE); 332 } 333 334 /************************* 335 * Remove mark from current window. 336 */ 337 338 int removemark(bool f, int n) 339 { 340 if (curwp.w_markp) 341 { curwp.w_flag |= WFHARD; 342 curwp.w_markp = null; 343 mlwrite("[Mark removed]"); 344 } 345 else 346 mlwrite("[No mark]"); 347 return (TRUE); 348 } 349 350 /* 351 * Swap the values of "." and "mark" in the current window. This is pretty 352 * easy, bacause all of the hard work gets done by the standard routine 353 * that moves the mark about. The only possible error is "no mark". Bound to 354 * "C-X C-X". 355 */ 356 int swapmark(bool f, int n) 357 { 358 if (curwp.w_markp == null) { 359 mlwrite("No mark in this window"); 360 return (FALSE); 361 } 362 auto odotp = curwp.w_dotp; 363 auto odoto = curwp.w_doto; 364 curwp.w_dotp = curwp.w_markp; 365 curwp.w_doto = curwp.w_marko; 366 curwp.w_markp = odotp; 367 curwp.w_marko = odoto; 368 curwp.w_flag |= WFMOVE; 369 return (TRUE); 370 }