Ask for MPSL version 1.0.6.
[mp-5.x.git] / mp_core.c
blob5fc99151fc2031fdc32753705cba5fdaeabb222a
1 /*
3 Minimum Profit - Programmer Text Editor
5 Copyright (C) 1991-2007 Angel Ortega <angel@triptico.com>
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 http://www.triptico.com
25 #include "config.h"
27 #include <stdio.h>
28 #include <wchar.h>
29 #include <stdlib.h>
30 #include <string.h>
32 #include "mpdm.h"
33 #include "mpsl.h"
35 #include "mp.h"
37 /*******************
38 Data
39 ********************/
41 /* exit requested? */
42 int mp_exit_requested = 0;
44 /* main namespace */
45 mpdm_t mp = NULL;
47 /*******************
48 Code
49 ********************/
51 /* private data for drawing syntax-highlighted text */
53 struct drw_1_info {
54 mpdm_t txt; /* the document */
55 mpdm_t syntax; /* syntax highlight information */
56 mpdm_t colors; /* color definitions (for attributes) */
57 mpdm_t word_color_func; /* word color function (just for detection) */
58 int normal_attr; /* normal attr */
59 int cursor_attr; /* cursor attr */
60 int n_lines; /* number of processed lines */
61 int p_lines; /* number of prereaded lines */
62 int t_lines; /* total lines in document */
63 int vx; /* first visible column */
64 int vy; /* first visible line */
65 int tx; /* horizontal window size */
66 int ty; /* vertical window size */
67 int tab_size; /* tabulator size */
68 int mod; /* modify count */
69 int preread_lines; /* lines to pre-read (for synhi blocks) */
70 int mark_eol; /* mark end of lines */
73 struct drw_1_info drw_1;
74 struct drw_1_info drw_1_o;
76 static struct {
77 int x; /* cursor x */
78 int y; /* cursor y */
79 int *offsets; /* offsets of lines */
80 char *attrs; /* attributes */
81 int visible; /* offset to the first visible character */
82 int cursor; /* offset to cursor */
83 wchar_t *ptr; /* pointer to joined data */
84 int size; /* size of joined data */
85 int matchparen_offset; /* offset to matched paren */
86 int matchparen_o_attr; /* original attribute there */
87 int cursor_o_attr; /* original attribute under cursor */
88 mpdm_t v; /* the data */
89 mpdm_t old; /* the previously generated array */
90 int mark_offset; /* offset to the marked block */
91 int mark_size; /* size of mark_o_attr */
92 char *mark_o_attr; /* saved attributes for the mark */
93 } drw_2;
96 #define MP_REAL_TAB_SIZE(x) (drw_1.tab_size - ((x) % drw_1.tab_size))
98 static int drw_wcwidth(int x, wchar_t c)
99 /* returns the wcwidth of c, or the tab spaces for
100 the x column if it's a tab */
102 int r;
104 switch (c) {
105 case L'\n':
106 r = 1;
107 break;
108 case L'\t':
109 r = MP_REAL_TAB_SIZE(x);
110 break;
111 default:
112 r = mpdm_wcwidth(c);
113 break;
116 return r < 0 ? 1 : r;
120 int drw_vx2x(mpdm_t str, int vx)
121 /* returns the character in str that is on column vx */
123 const wchar_t *ptr = str->data;
124 int n, x;
126 for (n = x = 0; n < vx && ptr[x] != L'\0'; x++)
127 n += drw_wcwidth(n, ptr[x]);
129 return x;
133 int drw_x2vx(mpdm_t str, int x)
134 /* returns the column where the character at offset x seems to be */
136 const wchar_t *ptr = str->data;
137 int n, vx;
139 for (n = vx = 0; n < x && ptr[n] != L'\0'; n++)
140 vx += drw_wcwidth(vx, ptr[n]);
142 return vx;
146 static int drw_line_offset(int l)
147 /* returns the offset into v for line number l */
149 return drw_2.offsets[l - drw_1.vy + drw_1.p_lines];
153 static int drw_adjust_y(int y, int *vy, int ty)
154 /* adjusts the visual y position */
156 int t = *vy;
158 /* is y above the first visible line? */
159 if (y < *vy)
160 *vy = y;
162 /* is y below the last visible line? */
163 if (y > *vy + (ty - 2))
164 *vy = y - (ty - 2);
166 return t != *vy;
170 static int drw_adjust_x(int x, int y, int *vx, int tx, wchar_t * ptr)
171 /* adjust the visual x position */
173 int n, m;
174 int t = *vx;
176 /* calculate the column for the cursor position */
177 for (n = m = 0; n < x; n++, ptr++)
178 m += drw_wcwidth(m, *ptr);
180 /* if new cursor column is nearer the leftmost column, set */
181 if (m < *vx)
182 *vx = m;
184 /* if new cursor column is further the rightmost column, set */
185 if (m > *vx + (tx - 1))
186 *vx = m - (tx - 1);
188 return t != *vx;
192 static int drw_get_attr(wchar_t * color_name)
193 /* returns the attribute number for a color */
195 mpdm_t v;
196 int attr = 0;
198 if ((v = mpdm_hget_s(drw_1.colors, color_name)) != NULL)
199 attr = mpdm_ival(mpdm_hget_s(v, L"attr"));
201 return attr;
205 static int drw_prepare(mpdm_t doc)
206 /* prepares the document for screen drawing */
208 mpdm_t window = mpdm_hget_s(mp, L"window");
209 mpdm_t config = mpdm_hget_s(mp, L"config");
210 mpdm_t txt = mpdm_hget_s(doc, L"txt");
211 mpdm_t lines = mpdm_hget_s(txt, L"lines");
212 int x = mpdm_ival(mpdm_hget_s(txt, L"x"));
213 int y = mpdm_ival(mpdm_hget_s(txt, L"y"));
214 int n;
216 drw_1.vx = mpdm_ival(mpdm_hget_s(txt, L"vx"));
217 drw_1.vy = mpdm_ival(mpdm_hget_s(txt, L"vy"));
218 drw_1.tx = mpdm_ival(mpdm_hget_s(window, L"tx"));
219 drw_1.ty = mpdm_ival(mpdm_hget_s(window, L"ty"));
220 drw_1.tab_size = mpdm_ival(mpdm_hget_s(config, L"tab_size"));
221 drw_1.mod = mpdm_ival(mpdm_hget_s(txt, L"mod"));
222 drw_1.preread_lines = mpdm_ival(mpdm_hget_s(config, L"preread_lines"));
223 drw_1.mark_eol = mpdm_ival(mpdm_hget_s(config, L"mark_eol"));
224 drw_1.t_lines = mpdm_size(lines);
226 /* adjust the visual y coordinate */
227 if (drw_adjust_y(y, &drw_1.vy, drw_1.ty))
228 mpdm_hset_s(txt, L"vy", MPDM_I(drw_1.vy));
230 /* adjust the visual x coordinate */
231 if (drw_adjust_x(x, y, &drw_1.vx, drw_1.tx, mpdm_string(mpdm_aget(lines, y))))
232 mpdm_hset_s(txt, L"vx", MPDM_I(drw_1.vx));
234 /* get the maximum prereadable lines */
235 drw_1.p_lines = drw_1.vy > drw_1.preread_lines ? drw_1.preread_lines : drw_1.vy;
237 /* maximum lines */
238 drw_1.n_lines = drw_1.ty + drw_1.p_lines;
240 /* get the mp.colors structure and the most used attributes */
241 drw_1.colors = mpdm_hget_s(mp, L"colors");
242 drw_1.normal_attr = drw_get_attr(L"normal");
243 drw_1.cursor_attr = drw_get_attr(L"cursor");
245 /* store the syntax highlight structure */
246 drw_1.syntax = mpdm_hget_s(doc, L"syntax");
248 drw_1.word_color_func = mpdm_hget_s(mp, L"word_color_func");
250 mpdm_unref(drw_1.txt);
251 drw_1.txt = mpdm_ref(txt);
253 drw_2.x = x;
254 drw_2.y = y;
256 /* compare drw_1 with drw_1_o; if they are the same,
257 no more expensive calculations on drw_2 are needed */
258 if (memcmp(&drw_1, &drw_1_o, sizeof(drw_1)) == 0)
259 return 0;
261 /* different; store now */
262 memcpy(&drw_1_o, &drw_1, sizeof(drw_1_o));
264 /* alloc space for line offsets */
265 drw_2.offsets = realloc(drw_2.offsets, drw_1.n_lines * sizeof(int));
267 drw_2.ptr = NULL;
268 drw_2.size = 0;
270 /* add first line */
271 drw_2.ptr = mpdm_pokev(drw_2.ptr, &drw_2.size,
272 mpdm_aget(lines, drw_1.vy - drw_1.p_lines));
274 /* first line start at 0 */
275 drw_2.offsets[0] = 0;
277 /* add the following lines and store their offsets */
278 for (n = 1; n < drw_1.n_lines; n++) {
279 /* add the separator */
280 drw_2.ptr = mpdm_poke(drw_2.ptr, &drw_2.size, L"\n", 1, sizeof(wchar_t));
282 /* this line starts here */
283 drw_2.offsets[n] = drw_2.size;
285 /* now add it */
286 drw_2.ptr = mpdm_pokev(drw_2.ptr, &drw_2.size,
287 mpdm_aget(lines, n + drw_1.vy - drw_1.p_lines));
290 drw_2.ptr = mpdm_poke(drw_2.ptr, &drw_2.size, L"", 1, sizeof(wchar_t));
291 drw_2.size--;
293 /* now create a value */
294 mpdm_unref(drw_2.v);
295 drw_2.v = mpdm_ref(MPDM_ENS(drw_2.ptr, drw_2.size));
297 /* alloc and init space for the attributes */
298 drw_2.attrs = realloc(drw_2.attrs, drw_2.size + 1);
299 memset(drw_2.attrs, drw_1.normal_attr, drw_2.size + 1);
301 drw_2.visible = drw_line_offset(drw_1.vy);
303 return 1;
307 static int drw_fill_attr(int attr, int offset, int size)
308 /* fill an attribute */
310 if (attr != -1)
311 memset(drw_2.attrs + offset, attr, size);
313 return offset + size;
317 static int drw_fill_attr_regex(int attr)
318 /* fills with an attribute the last regex match */
320 return drw_fill_attr(attr, mpdm_regex_offset, mpdm_regex_size);
324 static void drw_words(void)
325 /* fills the attributes for separate words */
327 mpdm_t r, t;
328 int o = drw_2.visible;
329 mpdm_t word_color = NULL;
330 mpdm_t word_color_func = NULL;
332 /* take the hash of word colors, if any */
333 if ((word_color = mpdm_hget_s(mp, L"word_color")) == NULL)
334 return;
336 /* get the regex for words */
337 if ((r = mpdm_hget_s(mp, L"word_regex")) == NULL)
338 return;
340 /* get the word color function */
341 word_color_func = mpdm_hget_s(mp, L"word_color_func");
343 while ((t = mpdm_regex(r, drw_2.v, o)) != NULL) {
344 int attr = -1;
345 mpdm_t v;
347 if ((v = mpdm_hget(word_color, t)) != NULL)
348 attr = mpdm_ival(v);
349 else if (word_color_func != NULL)
350 attr = mpdm_ival(mpdm_exec_1(word_color_func, t));
352 o = drw_fill_attr_regex(attr);
357 static void drw_multiline_regex(mpdm_t a, int attr)
358 /* sets the attribute to all matching (possibly multiline) regexes */
360 int n;
362 for (n = 0; n < mpdm_size(a); n++) {
363 mpdm_t r = mpdm_aget(a, n);
364 int o = 0;
366 /* if the regex is an array, it's a pair of
367 'match from this' / 'match until this' */
368 if (r->flags & MPDM_MULTIPLE) {
369 mpdm_t rs = mpdm_aget(r, 0);
370 mpdm_t re = mpdm_aget(r, 1);
372 while (mpdm_regex(rs, drw_2.v, o)) {
373 int s;
375 /* fill the matched part */
376 o = drw_fill_attr_regex(attr);
378 /* try to match the end */
379 if (mpdm_regex(re, drw_2.v, o)) {
380 /* found; fill the attribute
381 to the end of the match */
382 s = mpdm_regex_size + (mpdm_regex_offset - o);
384 else {
385 /* not found; fill to the end
386 of the document */
387 s = drw_2.size - o;
390 /* fill to there */
391 o = drw_fill_attr(attr, o, s);
394 else {
395 /* it's a scalar: */
396 /* while the regex matches, fill attributes */
397 while (mpdm_regex(r, drw_2.v, o))
398 o = drw_fill_attr_regex(attr);
404 static void drw_blocks(void)
405 /* fill attributes for multiline blocks */
407 mpdm_t defs;
408 int n;
410 /* no definitions? return */
411 if (drw_1.syntax == NULL || (defs = mpdm_hget_s(drw_1.syntax, L"defs")) == NULL)
412 return;
414 for (n = 0; n < mpdm_size(defs); n += 2) {
415 mpdm_t attr;
416 mpdm_t list;
418 /* get the attribute */
419 attr = mpdm_aget(defs, n);
420 attr = mpdm_hget(drw_1.colors, attr);
421 attr = mpdm_hget_s(attr, L"attr");
423 /* get the list for this word color */
424 list = mpdm_aget(defs, n + 1);
426 drw_multiline_regex(list, mpdm_ival(attr));
431 static void drw_selection(void)
432 /* draws the selected block, if any */
434 mpdm_t mark;
435 int bx, by, ex, ey, vertical;
436 int so, eo;
437 int mby, mey;
438 int line_offset, next_line_offset;
439 int y;
440 int len;
441 int attr;
443 /* no mark? return */
444 if ((mark = mpdm_hget_s(drw_1.txt, L"mark")) == NULL)
445 return;
447 bx = mpdm_ival(mpdm_hget_s(mark, L"bx"));
448 by = mpdm_ival(mpdm_hget_s(mark, L"by"));
449 ex = mpdm_ival(mpdm_hget_s(mark, L"ex"));
450 ey = mpdm_ival(mpdm_hget_s(mark, L"ey"));
451 vertical = mpdm_ival(mpdm_hget_s(mark, L"vertical"));
453 /* if block is not visible, return */
454 if (ey < drw_1.vy || by > drw_1.vy + drw_1.ty)
455 return;
457 so = by < drw_1.vy ? drw_2.visible : drw_line_offset(by) + bx;
458 eo = ey >= drw_1.vy + drw_1.ty ? drw_2.size : drw_line_offset(ey) + ex;
460 /* alloc space and save the attributes being destroyed */
461 drw_2.mark_offset = so;
462 drw_2.mark_size = eo - so + 1;
463 drw_2.mark_o_attr = malloc(eo - so + 1);
464 memcpy(drw_2.mark_o_attr, &drw_2.attrs[so], eo - so + 1);
466 if (vertical == 0) {
467 /* normal selection */
468 drw_fill_attr(drw_get_attr(L"selection"), so, eo - so);
470 else {
471 /* vertical selection */
472 mby = by < drw_1.vy ? drw_1.vy : by;
473 mey = ey >= drw_1.vy + drw_1.ty ? drw_1.vy + drw_1.ty : ey;
474 line_offset = drw_line_offset(mby);
475 attr = drw_get_attr(L"selection");
476 for (y = mby; y <= mey; y++) {
477 next_line_offset = drw_line_offset(y+1);
478 len = next_line_offset - line_offset - 1;
479 so = bx > len ? -1 : bx;
480 eo = ex > len ? len : ex;
482 if (so >= 0 && eo >= so)
483 drw_fill_attr(attr, line_offset+ so, eo - so + 1);
485 line_offset = next_line_offset;
491 static void drw_search_hit(void)
492 /* colorize the search hit, if any */
494 mpdm_t v;
496 if ((v = mpdm_hget_s(mp, L"last_search")) != NULL) {
497 mpdm_t l = mpdm_ref(MPDM_A(0));
499 mpdm_aset(l, v, 0);
500 drw_multiline_regex(l, drw_get_attr(L"search"));
501 mpdm_unref(l);
506 static void drw_cursor(void)
507 /* fill the attribute for the cursor */
509 /* calculate the cursor offset */
510 drw_2.cursor = drw_line_offset(drw_2.y) + drw_2.x;
512 drw_2.cursor_o_attr = drw_2.attrs[drw_2.cursor];
513 drw_fill_attr(drw_1.cursor_attr, drw_2.cursor, 1);
517 static void drw_matching_paren(void)
518 /* highlights the matching paren */
520 int o = drw_2.cursor;
521 int i = 0;
522 wchar_t c;
524 /* by default, no offset has been found */
525 drw_2.matchparen_offset = -1;
527 /* find the opposite and the increment (direction) */
528 switch (drw_2.ptr[o]) {
529 case L'(':
530 c = L')';
531 i = 1;
532 break;
533 case L'{':
534 c = L'}';
535 i = 1;
536 break;
537 case L'[':
538 c = L']';
539 i = 1;
540 break;
541 case L')':
542 c = L'(';
543 i = -1;
544 break;
545 case L'}':
546 c = L'{';
547 i = -1;
548 break;
549 case L']':
550 c = L'[';
551 i = -1;
552 break;
555 /* if a direction is set, do the searching */
556 if (i) {
557 wchar_t s = drw_2.ptr[o];
558 int m = 0;
559 int l = i == -1 ? drw_2.visible - 1 : drw_2.size;
561 while (o != l) {
562 if (drw_2.ptr[o] == s) {
563 /* found the same */
564 m++;
566 else if (drw_2.ptr[o] == c) {
567 /* found the opposite */
568 if (--m == 0) {
569 /* found! fill and exit */
570 drw_2.matchparen_offset = o;
571 drw_2.matchparen_o_attr = drw_2.attrs[o];
572 drw_fill_attr(drw_get_attr(L"matching"), o, 1);
573 break;
577 o += i;
583 static mpdm_t drw_push_pair(mpdm_t l, int i, int a, wchar_t * tmp)
584 /* pushes a pair of attribute / string into l */
586 /* create the array, if doesn't exist yet */
587 if (l == NULL)
588 l = MPDM_A(0);
590 /* finish the string */
591 tmp[i] = L'\0';
593 /* special magic: if the attribute is the
594 one of the cursor and the string is more than
595 one character, create two strings; the
596 cursor is over a tab */
597 if (a == drw_1.cursor_attr && i > 1) {
598 mpdm_push(l, MPDM_I(a));
599 mpdm_push(l, MPDM_NS(tmp, 1));
601 /* the rest of the string has the original attr */
602 a = drw_2.cursor_o_attr;
604 /* one char less */
605 tmp[i - 1] = L'\0';
608 /* store the attribute and the string */
609 mpdm_push(l, MPDM_I(a));
610 mpdm_push(l, MPDM_S(tmp));
612 return l;
616 #define BUF_LINE 128
618 static mpdm_t drw_line(int line)
619 /* creates a list of attribute / string pairs for the current line */
621 mpdm_t l = NULL;
622 int m, i, t, n;
623 int o = drw_2.offsets[line + drw_1.p_lines];
624 int a = drw_2.attrs[o];
625 wchar_t tmp[BUF_LINE];
626 wchar_t c;
628 /* loop while not beyond the right margin */
629 for (m = i = 0; m < drw_1.vx + drw_1.tx; m += t, o++) {
630 /* take char and size */
631 c = drw_2.ptr[o];
632 t = drw_wcwidth(m, c);
634 /* further the left margin? */
635 if (m >= drw_1.vx) {
636 /* if the attribute is different or we're out of
637 temporary space, push and go on */
638 if (drw_2.attrs[o] != a || i >= BUF_LINE - t - 1) {
639 l = drw_push_pair(l, i, a, tmp);
640 i = 0;
643 /* size is 1, unless it's a tab */
644 n = c == L'\t' ? t : 1;
646 /* fill tabs with spaces */
647 if (c == L'\0' || c == L'\t')
648 c = L' ';
650 /* fill EOLs with special marks or spaces */
651 if (c == L'\n')
652 c = drw_1.mark_eol ? L'\xb6' : L' ';
654 /* if next char will not fit, use a space */
655 if (m + t > drw_1.vx + drw_1.tx)
656 c = L' ';
658 else {
659 /* left filler */
660 n = m + t - drw_1.vx;
661 c = L' ';
664 /* fill the string */
665 for (; n > 0; n--)
666 tmp[i++] = c;
668 a = drw_2.attrs[o];
670 /* end of line? */
671 if (drw_2.ptr[o] == L'\0' || drw_2.ptr[o] == L'\n')
672 break;
675 return drw_push_pair(l, i, a, tmp);
679 static mpdm_t drw_as_array(void)
680 /* returns an mpdm array of ty elements, which are also arrays of
681 attribute - string pairs */
683 mpdm_t a;
684 int n;
686 /* the array of lines */
687 a = MPDM_A(drw_1.ty);
689 /* push each line */
690 for (n = 0; n < drw_1.ty; n++)
691 mpdm_aset(a, drw_line(n), n);
693 return a;
697 static mpdm_t drw_optimize_array(mpdm_t a, int optimize)
698 /* optimizes the array, NULLifying all lines that are the same as the last time */
700 mpdm_t o = drw_2.old;
701 mpdm_t r = a;
703 if (optimize && o != NULL) {
704 int n = 0;
706 /* creates a copy */
707 r = mpdm_clone(a);
709 /* compare each array */
710 while (n < mpdm_size(o) && n < mpdm_size(r)) {
711 /* if both lines are equal, optimize out */
712 if (mpdm_cmp(mpdm_aget(o, n), mpdm_aget(r, n)) == 0)
713 mpdm_aset(r, NULL, n);
715 n++;
719 mpdm_unref(drw_2.old);
720 drw_2.old = mpdm_ref(a);
722 return r;
726 static void drw_restore_attrs(void)
727 /* restored the patched attrs */
729 /* matching paren, if any */
730 if (drw_2.matchparen_offset != -1)
731 drw_fill_attr(drw_2.matchparen_o_attr, drw_2.matchparen_offset, 1);
733 /* cursor */
734 drw_fill_attr(drw_2.cursor_o_attr, drw_2.cursor, 1);
736 /* marked block, if any */
737 if (drw_2.mark_o_attr != NULL) {
738 memcpy(&drw_2.attrs[drw_2.mark_offset], drw_2.mark_o_attr, drw_2.mark_size);
740 free(drw_2.mark_o_attr);
741 drw_2.mark_o_attr = NULL;
746 static mpdm_t drw_draw(mpdm_t doc, int optimize)
747 /* main document drawing function: takes a document and returns an array of
748 arrays of attribute / string pairs */
750 mpdm_t r = NULL;
752 if (drw_prepare(doc)) {
753 /* colorize separate words */
754 drw_words();
756 /* colorize multiline blocks */
757 drw_blocks();
760 /* now set the marked block (if any) */
761 drw_selection();
763 /* colorize the search hit */
764 drw_search_hit();
766 /* the cursor */
767 drw_cursor();
769 /* highlight the matching paren */
770 drw_matching_paren();
772 /* convert to an array of string / atribute pairs */
773 r = drw_as_array();
775 /* optimize */
776 r = drw_optimize_array(r, optimize);
778 /* restore the patched attrs */
779 drw_restore_attrs();
781 return r;
785 mpdm_t mp_draw(mpdm_t doc, int optimize)
786 /* main generic drawing function: if the document has a 'paint' code,
787 calls it; otherwise, call drw_draw() */
789 mpdm_t r = NULL;
790 static int ppp = 0; /* previous private paint */
791 mpdm_t f;
793 /* if previous paint was private, disable optimizations */
794 if (ppp)
795 optimize = ppp = 0;
797 if (doc != NULL) {
798 if ((f = mpdm_hget_s(doc, L"paint")) != NULL) {
799 ppp = 1;
800 r = mpdm_exec_2(f, doc, MPDM_I(optimize));
802 else
803 r = drw_draw(doc, optimize);
806 /* if there is a global post_paint function, execute it */
807 if ((f = mpdm_hget_s(mp, L"post_paint")) != NULL)
808 r = mpdm_exec_1(f, r);
810 /* if doc has a post_paint function, execute it */
811 if ((f = mpdm_hget_s(doc, L"post_paint")) != NULL)
812 r = mpdm_exec_1(f, r);
814 return r;
818 #define THR_SPEED_STEP 10
819 #define THR_MAX_SPEED 7
821 int mp_keypress_throttle(int keydown)
822 /* processes key acceleration and throttle */
824 static int keydowns = 0;
825 static int seq = 0;
826 int redraw = 0;
828 if (keydown) {
829 int speed;
831 /* as keydowns accumulate, speed increases, which is the number
832 of cycles the redraw will be skipped (up to a maximum) */
833 if ((speed = 1 + (++keydowns / THR_SPEED_STEP)) > THR_MAX_SPEED)
834 speed = THR_MAX_SPEED;
836 if (++seq % speed == 0)
837 redraw = 1;
839 else {
840 if (keydowns > 1)
841 redraw = 1;
843 keydowns = 0;
846 return redraw;
850 mpdm_t mp_active(void)
851 /* interface to mp.active() */
853 return mpdm_exec(mpdm_hget_s(mp, L"active"), NULL);
857 mpdm_t mp_process_action(mpdm_t action)
858 /* interface to mp.process_action() */
860 return mpdm_exec_1(mpdm_hget_s(mp, L"process_action"), action);
864 mpdm_t mp_process_event(mpdm_t keycode)
865 /* interface to mp.process_event() */
867 return mpdm_exec_1(mpdm_hget_s(mp, L"process_event"), keycode);
871 mpdm_t mp_set_y(mpdm_t doc, int y)
872 /* interface to mp.set_y() */
874 return mpdm_exec_2(mpdm_hget_s(mp, L"set_y"), doc, MPDM_I(y));
878 mpdm_t mp_build_status_line(void)
879 /* interface to mp.build_status_line() */
881 return mpdm_exec(mpdm_hget_s(mp, L"build_status_line"), NULL);
885 mpdm_t mp_get_history(mpdm_t key)
886 /* interface to mp.get_history() */
888 return mpdm_exec_1(mpdm_hget_s(mp, L"get_history"), key);
892 mpdm_t mp_get_doc_names(void)
893 /* interface to mp.get_doc_names() */
895 return mpdm_exec(mpdm_hget_s(mp, L"get_doc_names"), NULL);
899 mpdm_t mp_menu_label(mpdm_t action)
900 /* interface to mp.menu_label() */
902 return mpdm_exec_1(mpdm_hget_s(mp, L"menu_label"), action);
906 mpdm_t mp_pending_key(void)
907 /* interface to mp.pending_key() */
909 return mpdm_exec_1(mpdm_hget_s(mp, L"pending_key"), NULL);
913 mpdm_t mp_process_keyseq(mpdm_t key)
914 /* interface to mp.process_keyseq() */
916 return mpdm_exec_1(mpdm_hget_s(mp, L"process_keyseq"), key);
920 mpdm_t mp_exit(mpdm_t args)
921 /* exit the editor (set mp_exit_requested) */
923 mp_exit_requested = 1;
925 return NULL;
929 mpdm_t mp_vx2x(mpdm_t args)
930 /* interface to drw_vx2x() */
932 return MPDM_I(drw_vx2x(mpdm_aget(args, 0), mpdm_ival(mpdm_aget(args, 1))));
936 mpdm_t mp_x2vx(mpdm_t args)
937 /* interface to drw_x2vx() */
939 return MPDM_I(drw_x2vx(mpdm_aget(args, 0), mpdm_ival(mpdm_aget(args, 1))));
942 mpdm_t mp_plain_load(mpdm_t args)
943 /* loads a plain file into an array (highly optimized one) */
945 mpdm_t f = mpdm_aget(args, 0);
946 mpdm_t a = MPDM_A(0);
947 mpdm_t v;
948 int chomped = 1;
950 while ((v = mpdm_read(f)) != NULL) {
951 const wchar_t *ptr = v->data;
952 int size = v->size;
954 /* chomp */
955 if (size && ptr[size - 1] == L'\n') {
956 if (--size && ptr[size - 1] == L'\r')
957 --size;
959 else
960 chomped = 0;
962 mpdm_push(a, MPDM_NS(ptr, size));
963 mpdm_destroy(v);
966 /* if last line was chomped, add a last, empty one */
967 if (chomped)
968 mpdm_push(a, MPDM_LS(L""));
970 return a;
974 void mp_startup(int argc, char *argv[])
976 mpdm_t INC;
978 mpsl_startup();
980 /* reset the structures */
981 memset(&drw_1, '\0', sizeof(drw_1));
982 memset(&drw_1_o, '\0', sizeof(drw_1_o));
984 /* create main namespace */
985 mp = MPDM_H(0);
986 mpdm_hset_s(mpdm_root(), L"mp", mp);
988 /* basic functions and data */
989 mpdm_hset_s(mp, L"x2vx", MPDM_X(mp_x2vx));
990 mpdm_hset_s(mp, L"vx2x", MPDM_X(mp_vx2x));
991 mpdm_hset_s(mp, L"exit", MPDM_X(mp_exit));
992 mpdm_hset_s(mp, L"plain_load", MPDM_X(mp_plain_load));
993 mpdm_hset_s(mp, L"window", MPDM_H(0));
994 mpdm_hset_s(mp, L"drv", MPDM_H(0));
996 /* version */
997 mpdm_hset_s(mp, L"VERSION", MPDM_S(L"" VERSION));
999 /* creates the INC (executable path) array */
1000 INC = MPDM_A(0);
1002 /* add installed library path */
1003 mpdm_push(INC, mpdm_strcat(mpdm_hget_s(mpdm_root(), L"APPDIR"),
1004 MPDM_MBS(CONFOPT_APPNAME))
1007 /* set INC */
1008 mpdm_hset_s(mpdm_root(), L"INC", INC);
1010 if (!TRY_DRIVERS()) {
1011 printf("No usable driver found; exiting.\n");
1012 exit(1);
1015 mpsl_argv(argc, argv);
1019 void mp_mpsl(void)
1021 mpdm_t e;
1023 mpsl_eval(MPDM_LS(L"load('mp_core.mpsl');"), NULL);
1025 if ((e = mpdm_hget_s(mpdm_root(), L"ERROR")) != NULL) {
1026 mpdm_write_wcs(stdout, mpdm_string(e));
1027 printf("\n");
1032 void mp_shutdown(void)
1034 mpsl_shutdown();
1038 int main(int argc, char *argv[])
1040 mp_startup(argc, argv);
1042 mp_mpsl();
1044 mp_shutdown();
1046 return 0;