Updated RELEASE_NOTES.
[mp-5.x.git] / mp_move.mpsl
blobf3063a2d29c2efc9411c4ba4aab73c40a6086711
1 /*
3     Minimum Profit 5.x
4     A Programmer's Text Editor
6     Movement.
8     Copyright (C) 1991-2007 Angel Ortega <angel@triptico.com>
10     This program is free software; you can redistribute it and/or
11     modify it under the terms of the GNU General Public License
12     as published by the Free Software Foundation; either version 2
13     of the License, or (at your option) any later version.
15     This program is distributed in the hope that it will be useful,
16     but WITHOUT ANY WARRANTY; without even the implied warranty of
17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18     GNU General Public License for more details.
20     You should have received a copy of the GNU General Public License
21     along with this program; if not, write to the Free Software
22     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24     http://www.triptico.com
28 /* editor actions */
30 mp.actions['move_left']         = sub (d) { mp.move(d, mp.move_left); };
31 mp.actions['move_right']        = sub (d) { mp.move(d, mp.move_right); };
32 mp.actions['move_up']           = sub (d) { mp.move(d, mp.move_up); };
33 mp.actions['move_down']         = sub (d) { mp.move(d, mp.move_down); };
34 mp.actions['move_pgup']         = sub (d) { mp.move(d, mp.move_pgup); };
35 mp.actions['move_pgdn']         = sub (d) { mp.move(d, mp.move_pgdn); };
36 mp.actions['move_bol']          = sub (d) { mp.move(d, mp.move_bol); };
37 mp.actions['move_eol']          = sub (d) { mp.move(d, mp.move_eol); };
38 mp.actions['move_bof']          = sub (d) { mp.move(d, mp.move_bof); };
39 mp.actions['move_eof']          = sub (d) { mp.move(d, mp.move_eof); };
40 mp.actions['move_word_left']    = sub (d) { mp.move(d, mp.move_word_left); };
41 mp.actions['move_word_right']   = sub (d) { mp.move(d, mp.move_word_right); };
43 mp.actions['goto']              = sub (d) {
44         local y = mp.form( [
45                 { 'label'       => L("Line to go to:"),
46                   'type'        => 'text',
47                   'history'     => 'goto' }
48                 ]);
50         if(y != NULL && y[0] >= 1)
51         {
52                 d.txt.x = 0;
53                 mp.set_y(d, y[0] - 1);
54         }
57 mp.actions['move_to_mouse_position']    = sub (d) {
59         /* move the cursor there */
60         mp.move_to_coords_xy(d, mp.mouse_x, mp.mouse_y);
62         /* mouse click always unmarks */
63         mp.unmark(d);
66 mp.actions['move_mouse_wheel_up']       = sub (d) {
67         mp.move(d, sub (d) {
68                 mp.move_up(d);
69                 mp.move_up(d);
70                 mp.move_up(d);
71                 mp.move_up(d);
72         });
75 mp.actions['move_mouse_wheel_down']     = sub (d) {
76         mp.move(d, sub(d) {
77                 mp.move_down(d);
78                 mp.move_down(d);
79                 mp.move_down(d);
80                 mp.move_down(d);
81         });
84 mp.actions['document_list'] = sub (d) {
86         local r = mp.form( [
87                 { 'label'       =>      L("Document list"),
88                   'type'        =>      'list',
89                   'list'        =>      map( sub(e) {
90                         sprintf('%s %s', (e.txt.mod && '*' || ' '), e.name);
91                         }, mp.docs),
92                   'value'       =>      mp.active_i
93                 } ]
94         );
96         if(r[0] != NULL) mp.active_i = r[0];
99 /* default key bindings */
101 mp.keycodes['cursor-left']              = "move_left";
102 mp.keycodes['cursor-right']             = "move_right";
103 mp.keycodes['cursor-up']                = "move_up";
104 mp.keycodes['cursor-down']              = "move_down";
105 mp.keycodes['page-up']                  = "move_pgup";
106 mp.keycodes['page-down']                = "move_pgdn";
107 mp.keycodes['home']                     = "move_bol";
108 mp.keycodes['end']                      = "move_eol";
109 mp.keycodes['ctrl-home']                = "move_bof";
110 mp.keycodes['ctrl-end']                 = "move_eof";
111 mp.keycodes['ctrl-cursor-left']         = "move_word_left";
112 mp.keycodes['ctrl-cursor-right']        = "move_word_right";
113 mp.keycodes['ctrl-g']                   = "goto";
114 mp.keycodes['mouse-left-button']        = "move_to_mouse_position";
115 mp.keycodes['mouse-right-button']       = "move_to_mouse_position";
116 mp.keycodes['mouse-middle-button']      = "move_to_mouse_position";
117 mp.keycodes['mouse-wheel-up']           = "move_mouse_wheel_up";
118 mp.keycodes['mouse-wheel-down']         = "move_mouse_wheel_down";
120 /* action descriptions */
122 mp.actdesc['move_left']                 = LL("Character left");
123 mp.actdesc['move_right']                = LL("Character right");
124 mp.actdesc['move_up']                   = LL("Line up");
125 mp.actdesc['move_down']                 = LL("Line down");
126 mp.actdesc['move_pgup']                 = LL("Page up");
127 mp.actdesc['move_pgdn']                 = LL("Page down");
128 mp.actdesc['move_bol']                  = LL("Beginning of line");
129 mp.actdesc['move_eol']                  = LL("End of line");
130 mp.actdesc['move_bof']                  = LL("Beginning of document");
131 mp.actdesc['move_eof']                  = LL("End of document");
132 mp.actdesc['move_word_left']            = LL("Word left");
133 mp.actdesc['move_word_right']           = LL("Word right");
134 mp.actdesc['goto']                      = LL("Go to line...");
135 mp.actdesc['move_to_mouse_position']    = LL("Move cursor to mouse click");
136 mp.actdesc['move_mouse_wheel_down']     = LL("Mouse wheel up");
137 mp.actdesc['move_mouse_wheel_up']       = LL("Mouse wheel down");
138 mp.actdesc['document_list']             = LL("Document list");
140 /* code */
142 sub mp.move(doc, func)
143 /* wrapper for movement functions, with possible shift selection */
145         if(func != NULL)
146         {
147                 if(mp.shift_pressed)
148                 {
149                         /* shift pressed? move selecting */
150                         if(doc.txt.mark == NULL)
151                                 mp.mark(doc);
153                         func(doc);
154                         mp.mark(doc);
155                 }
156                 else
157                         func(doc);
158         }
162 sub mp.split_by_words(s)
163 /* splits a string by words */
165         local l = [];
166         local w, c;
168         while((w = regex(mp.word_regex, s, c[0] + c[1])) != NULL)
169         {
170                 push(l, w);
171                 c = regex();
172         }
174         return(l);
178 sub mp.split_line_by_words(doc, r)
179 /* splits current line by words and returns a three element array containing
180    the list of words, the list of offsets and the current position */
182         local txt, l, w, c, ol, oc, p;
184         txt = doc.txt;
185         l = txt.lines[txt.y];
186         ol = [];
187         oc = [];
188         p = -1;
190         /* if no special-purpose regex set, take global one */
191         if(r == NULL) r = mp.word_regex;
193         while((w = regex(r, l, c[0] + c[1])) != NULL)
194         {
195                 /* store the word */
196                 push(ol, w);
198                 /* get coordinates */
199                 c = regex();
201                 /* push the starting column */
202                 push(oc, c[0]);
204                 /* if matching coords are between the cursor, store it */
205                 if(c[0] <= txt.x && c[0] + c[1] >= txt.x)
206                         p = size(ol) - 1;
207         }
209         /* it txt.x is still further than the last match, it means
210            that the 'current' position is beyond the last word */
211         if(txt.x > c[0] + c[1]) p = size(ol);
213         /* return the list of words, the list of
214            coordinates and the current one */
215         return( [ ol, oc, p ]);
219 sub mp.get_word(doc, r)
220 /* returns the word under the cursor */
222         local l = mp.split_line_by_words(doc, r);
224         /* no word over cursor? */
225         if(l[2] == -1) return(NULL);
227         return(l[0][l[2]]);
231 sub mp.get_range(doc, bx, by, ex, ey)
232 /* gets a range or characters from a document */
234         local txt = doc.txt;
236         local r = [];
238         if(by == ey)
239         {
240                 local w;
242                 /* block is just one line; take the inside
243                    part and push it onto the clipboard */
245                 w = splice(txt.lines[by], NULL, bx, ex - bx);
247                 push(r, w[1]);
248         }
249         else
250         {
251                 local w, n;
253                 /* block has more than one line */
255                 /* take from the beginning to the end of the first line */
256                 n = by;
257                 w = splice(txt.lines[n], NULL, bx, -1);
259                 push(r, w[1]);
260                 n++;
262                 /* take the central lines */
263                 while(n < ey)
264                         push(r, txt.lines[n++]);
266                 /* take the last line */
267                 w = splice(txt.lines[n], NULL, 0, ex);
268                 push(r, w[1]);
269         }
271         return(r);
275 sub mp.set_x(doc, x)
276 /* sets the x position */
278         local txt = doc.txt;
280         if(x < 0)
281         {
282                 /* cursor moved left of the bol; effective cursor up + eol */
283                 if(txt.y > 0)
284                 {
285                         /* one line up */
286                         txt.y--;
288                         /* set x to the end of the line */
289                         txt.x = size(txt.lines[txt.y]);
290                 }
291         }
292         else
293         {
294                 /* test if moved beyond end of line */
295                 if(x > size(txt.lines[txt.y]))
296                 {
297                         if(txt.y < size(txt.lines) - 1)
298                         {
299                                 /* cursor moved right of eol;
300                                    effective cursor down + bol */
301                                 txt.x = 0;
302                                 txt.y++;
303                         }
304                 }
305                 else
306                         txt.x = x;
307         }
311 sub mp.set_y(doc, y)
312 /* sets the y position */
314         local txt = doc.txt;
315         local vx;
317         /* get current visual x position */
318         vx = mp.x2vx(txt.lines[txt.y], txt.x);
320         /* set boundaries */
321         if(y < 0) y = 0;
322         if(y >= size(txt.lines)) y = size(txt.lines) - 1;
324         /* move there */
325         txt.y = y;
327         /* adjust new x to match previously one */
328         txt.x = mp.vx2x(txt.lines[txt.y], vx);
332 sub mp.move_up(doc)
333 /* moves one line up */
335         mp.set_y(doc, doc.txt.y - 1);
339 sub mp.move_down(doc)
340 /* moves one line down */
342         mp.set_y(doc, doc.txt.y + 1);
346 sub mp.move_pgup(doc)
347 /* moves one page up */
349         mp.set_y(doc, doc.txt.y - mp.window.ty);
353 sub mp.move_pgdn(doc)
354 /* moves one page down */
356         mp.set_y(doc, doc.txt.y + mp.window.ty);
360 sub mp.move_left(doc)
361 /* moves one char left */
363         /* return 0 if on BOF */
364         if(doc.txt.x + doc.txt.y == 0) return(0);
366         mp.set_x(doc, doc.txt.x - 1);
367         return(1);
371 sub mp.move_right(doc)
372 /* moves one char right */
374         mp.set_x(doc, doc.txt.x + 1);
378 sub mp.move_bol(doc)
379 /* moves to the beginning of the line */
381         doc.txt.x = 0;
385 sub mp.move_eol(doc)
386 /* moves to the end of the line */
388         doc.txt.x = size(doc.txt.lines[doc.txt.y]);
392 sub mp.move_bof(doc)
393 /* moves to the beginning of the file */
395         doc.txt.x = 0;
396         doc.txt.y = 0;
400 sub mp.move_eof(doc)
401 /* moves to the end of the file */
403         doc.txt.y = size(doc.txt.lines) - 1;
404         mp.move_eol(doc);
408 sub mp.move_word_left(doc)
409 /* moves a word to the left */
411         local txt = doc.txt;
413         while(1)
414         {
415                 /* split by words */
416                 local l = mp.split_line_by_words(doc);
418                 /* get current word */
419                 local i = l[2];
421                 if(i >= 0)
422                 {
423                         /* if it's not at the beginning of a word,
424                            move there and go */
425                         if(i < size(l[1]) && txt.x != l[1][i])
426                         {
427                                 txt.x = l[1][i];
428                                 break;
429                         }
431                         /* go to previous word */
432                         i = l[2] - 1;
434                         /* if that position exists, move there */
435                         if(i >= 0)
436                         {
437                                 txt.x = l[1][i];
438                                 break;
439                         }
440                 }
442                 /* no lines up? exit */
443                 if(txt.y == 0) break;
445                 txt.y--;
446                 txt.x = size(txt.lines[txt.y]);
447         }
451 sub mp.move_word_right(doc)
452 /* moves a word to the right */
454         local txt = doc.txt;
456         while(txt.y < size(txt.lines) - 1)
457         {
458                 /* split by words */
459                 local l = mp.split_line_by_words(doc);
461                 /* get next position */
462                 local i = l[2] + 1;
464                 /* if that position exists, move there */
465                 if(i < size(l[1]))
466                 {
467                         txt.x = l[1][i];
468                         break;
469                 }
471                 /* try next line */
472                 txt.y++;
473                 txt.x = 0;
474         }
478 sub mp.move_to_coords_xy(doc, x, y)
479 /* move the cursor to the character on the visual coords x and y */
481         /* set y */
482         mp.set_y(doc, doc.txt.vy + y);
484         /* calculate the real position in that line
485            where the mouse click seem to be */
486         x = mp.vx2x(doc.txt.lines[doc.txt.y], doc.txt.vx + x);
488         /* move there */
489         mp.set_x(doc, x);