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 12 * deal with the region, that magic space 13 * between "." and mark. Some functions are 14 * commands. Some functions are just for 15 * internal use. 16 */ 17 18 module region; 19 20 import std..string; 21 import std.ascii; 22 23 import ed; 24 import line; 25 import main; 26 import window; 27 import display; 28 import buffer; 29 30 /* 31 * The starting position of a region, and the size of the region in 32 * characters, is kept in a region structure. Used by the region commands. 33 */ 34 struct REGION { 35 LINE *r_linep; /* Origin LINE address */ 36 uint r_offset; /* Origin LINE offset (not in col mode) */ 37 uint r_size; /* Length in characters (approx in col mode) */ 38 uint r_nlines; /* Number of lines */ 39 uint r_leftcol; /* Left column for column cut */ 40 uint r_rightcol; /* And right column */ 41 } 42 43 44 /********************************* 45 * Toggle column cut/paste mode. 46 */ 47 48 int region_togglemode(bool f, int n) 49 { 50 column_mode ^= 1; /* toggle screen mode */ 51 line_change(WFHARD); 52 mlwrite(column_mode ? "[Column mode on]" : "[Column mode off]"); 53 return TRUE; 54 } 55 56 /* 57 * Kill the region. Ask "getregion" 58 * to figure out the bounds of the region. 59 * Move "." to the start, and kill the characters. 60 */ 61 int region_kill(bool f, int n) 62 { 63 int s; 64 REGION region; 65 66 if (curbp.b_flag & BFRDONLY) 67 return FALSE; 68 if ((s=getregion(®ion)) != TRUE) 69 goto err; 70 if (region.r_size == 0) 71 goto err; /* error if 0 length */ 72 if ((lastflag&CFKILL) == 0) /* This is a kill type */ 73 kill_freebuffer(); /* command, so do magic */ 74 thisflag |= CFKILL; /* kill buffer stuff. */ 75 curwp.w_dotp = region.r_linep; 76 curwp.w_doto = region.r_offset; 77 curwp.w_markp = null; 78 if (column_mode) 79 { 80 if (!kill_setsize(region.r_size)) 81 return FALSE; 82 while (region.r_nlines--) 83 { int lright; 84 LINE* linep = curwp.w_dotp; 85 86 curwp.w_doto = coltodoto(linep,region.r_leftcol); 87 lright = coltodoto(linep,region.r_rightcol); 88 if (!line_delete(lright - curwp.w_doto, TRUE)) 89 goto err; 90 if (!kill_appendchar('\n')) 91 goto err; 92 curwp.w_dotp = lforw(linep); 93 } 94 curwp.w_dotp = region.r_linep; 95 curwp.w_doto = coltodoto(region.r_linep,region.r_leftcol); 96 line_change(WFHARD); 97 } 98 else 99 s = line_delete(region.r_size, TRUE); 100 kill_toClipboard(); 101 return s; 102 err: 103 return FALSE; 104 } 105 106 /* 107 * Copy all of the characters in the 108 * region to the kill buffer. Don't move dot 109 * at all. This is a bit like a kill region followed 110 * by a yank. Bound to "M-W". 111 */ 112 int region_copy(bool f, int n) 113 { 114 LINE* linep; 115 int loffs; 116 int s; 117 REGION region; 118 119 if ((s=getregion(®ion)) != TRUE) 120 return (s); 121 if ((lastflag&CFKILL) == 0) /* Kill type command. */ 122 kill_freebuffer(); 123 124 /* Turn off marked region */ 125 curwp.w_markp = null; 126 curwp.w_flag |= WFHARD; 127 128 thisflag |= CFKILL; 129 linep = region.r_linep; /* Current line. */ 130 loffs = region.r_offset; /* Current offset. */ 131 if (!kill_setsize(region.r_size)) 132 return FALSE; 133 if (column_mode) 134 { 135 while (region.r_nlines--) 136 { int lright; 137 int lleft; 138 139 lleft = coltodoto(linep,region.r_leftcol); 140 lright = coltodoto(linep,region.r_rightcol); 141 if (!kill_appendstring(linep.l_text[lleft .. lright])) 142 goto err; 143 if (!kill_appendchar('\n')) 144 goto err; 145 linep = lforw(linep); 146 } 147 } 148 else 149 while (region.r_size) { 150 if (loffs == llength(linep)) { /* End of line. */ 151 if (kill_appendchar('\n') != TRUE) 152 return FALSE; 153 linep = lforw(linep); 154 loffs = 0; 155 region.r_size--; 156 } else { /* Middle of line. */ 157 int i; 158 159 i = llength(linep) - loffs; 160 if (i > region.r_size) 161 i = region.r_size; 162 if (kill_appendstring(linep.l_text[loffs .. loffs + i]) != TRUE) 163 return FALSE; 164 loffs += i; 165 region.r_size -= i; 166 } 167 } 168 kill_toClipboard(); 169 return (TRUE); 170 171 err: return FALSE; 172 } 173 174 /* 175 * Upper/lower case region. Zap all of the upper 176 * case characters in the region to lower case. Use 177 * the region code to set the limits. Scan the buffer, 178 * doing the changes. Call "line_change" to ensure that 179 * redisplay is done in all buffers. 180 */ 181 int region_lower(bool f, int n) 182 { 183 return region_case(TRUE); 184 } 185 186 int region_upper(bool f, int n) 187 { 188 return region_case(FALSE); 189 } 190 191 private int region_case(bool flag) 192 { 193 LINE* linep; 194 int loffs; 195 int c; 196 int s; 197 REGION region; 198 199 if ((s=getregion(®ion)) != TRUE) 200 return (s); 201 line_change(WFHARD); 202 /*curwp.w_markp = null;*/ 203 linep = region.r_linep; 204 if (column_mode) 205 { 206 while (region.r_nlines--) 207 { int lright; 208 209 loffs = coltodoto(linep,region.r_leftcol); 210 lright = coltodoto(linep,region.r_rightcol); 211 for (; loffs < lright; loffs++) 212 { c = lgetc(linep, loffs); 213 if (flag ? isUpper(c) : isLower(c)) 214 lputc(linep, loffs, cast(char)(c ^ 0x20)); 215 } 216 linep = lforw(linep); 217 } 218 } 219 else 220 { 221 loffs = region.r_offset; 222 while (region.r_size--) { 223 if (loffs == llength(linep)) { 224 linep = lforw(linep); 225 loffs = 0; 226 } else { 227 c = lgetc(linep, loffs); 228 if (flag ? isUpper(c) : isLower(c)) 229 lputc(linep, loffs, cast(char)(c ^ 0x20)); 230 ++loffs; 231 } 232 } 233 } 234 return (TRUE); 235 } 236 237 /* 238 * This routine figures out the 239 * bounds of the region in the current window, and 240 * fills in the fields of the "REGION" structure pointed 241 * to by "rp". Because the dot and mark are usually very 242 * close together, we scan outward from dot looking for 243 * mark. This should save time. Return a standard code. 244 * Callers of this routine should be prepared to get 245 * an "ABORT" status; we might make this have the 246 * conform thing later. 247 */ 248 int getregion(REGION* rp) 249 { 250 LINE *flp; 251 LINE *blp; 252 int nlines; /* number of lines in region */ 253 int fsize; 254 int bsize; 255 int size; 256 257 if (!window_marking(curwp)) { 258 mlwrite("No mark set in this window"); 259 return (FALSE); 260 } 261 262 /* Figure out left and right columns, this is valid only if */ 263 /* column cut mode is on. */ 264 if (markcol < curgoal) 265 { rp.r_leftcol = markcol; 266 rp.r_rightcol = curgoal; 267 } 268 else 269 { rp.r_leftcol = curgoal; 270 rp.r_rightcol = markcol; 271 } 272 273 rp.r_nlines = 1; /* always at least 1 line */ 274 275 /* If region lies within one line */ 276 if (curwp.w_dotp == curwp.w_markp) 277 { rp.r_linep = curwp.w_dotp; 278 if (column_mode) 279 { 280 rp.r_size = rp.r_rightcol - rp.r_leftcol; 281 } 282 else 283 { 284 if (curwp.w_doto < curwp.w_marko) 285 { rp.r_offset = curwp.w_doto; 286 rp.r_size = curwp.w_marko-curwp.w_doto; 287 } 288 else 289 { rp.r_offset = curwp.w_marko; 290 rp.r_size = curwp.w_doto-curwp.w_marko; 291 } 292 } 293 return (TRUE); 294 } 295 296 blp = curwp.w_dotp; 297 bsize = curwp.w_doto; 298 flp = curwp.w_dotp; 299 fsize = llength(flp)-curwp.w_doto+1; 300 while (flp!=curbp.b_linep || lback(blp)!=curbp.b_linep) 301 { 302 rp.r_nlines++; 303 if (flp != curbp.b_linep) { 304 flp = lforw(flp); 305 if (flp == curwp.w_markp) { 306 rp.r_linep = curwp.w_dotp; 307 rp.r_offset = curwp.w_doto; 308 size = fsize+curwp.w_marko; 309 /* Don't count last line if it's at start */ 310 if (curwp.w_marko == 0) 311 rp.r_nlines--; 312 goto done; 313 } 314 fsize += llength(flp)+1; 315 } 316 if (lback(blp) != curbp.b_linep) { 317 blp = lback(blp); 318 bsize += llength(blp)+1; 319 if (blp == curwp.w_markp) { 320 rp.r_linep = blp; 321 rp.r_offset = curwp.w_marko; 322 size = bsize - curwp.w_marko; 323 /* Don't count last line if it's at start */ 324 if (curwp.w_doto == 0) 325 rp.r_nlines--; 326 goto done; 327 } 328 } 329 } 330 mlwrite("Bug: lost mark"); 331 return (FALSE); 332 333 done: 334 if (column_mode) 335 size = (rp.r_rightcol - rp.r_leftcol + 1) * rp.r_nlines; 336 rp.r_size = size; 337 return TRUE; 338 }