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(&region)) != 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(&region)) != 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(&region)) != 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 }