Updated RELEASE_NOTES.
[mp-5.x.git] / mp_core.c
blob215271ed79a9e9b599605254243844c3e958bfc7
1 /*
3 Minimum Profit - Programmer Text Editor
5 Copyright (C) 1991-2009 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 /** data **/
39 /* exit requested? */
40 int mp_exit_requested = 0;
42 /* main namespace */
43 mpdm_t mp = NULL;
45 /** private data for drawing syntax-highlighted text **/
47 struct drw_1_info {
48 mpdm_t txt; /* the document */
49 mpdm_t syntax; /* syntax highlight information */
50 mpdm_t colors; /* color definitions (for attributes) */
51 mpdm_t word_color_func; /* word color function (just for detection) */
52 mpdm_t last_search; /* last search regex */
53 int normal_attr; /* normal attr */
54 int cursor_attr; /* cursor attr */
55 int n_lines; /* number of processed lines */
56 int p_lines; /* number of prereaded lines */
57 int t_lines; /* total lines in document */
58 int vx; /* first visible column */
59 int vy; /* first visible line */
60 int tx; /* horizontal window size */
61 int ty; /* vertical window size */
62 int tab_size; /* tabulator size */
63 int mod; /* modify count */
64 int preread_lines; /* lines to pre-read (for synhi blocks) */
65 int mark_eol; /* mark end of lines */
66 int redraw; /* redraw trigger */
69 struct drw_1_info drw_1;
70 struct drw_1_info drw_1_o;
72 static struct {
73 int x; /* cursor x */
74 int y; /* cursor y */
75 int *offsets; /* offsets of lines */
76 char *attrs; /* attributes */
77 int visible; /* offset to the first visible character */
78 int cursor; /* offset to cursor */
79 wchar_t *ptr; /* pointer to joined data */
80 int size; /* size of joined data */
81 int matchparen_offset; /* offset to matched paren */
82 int matchparen_o_attr; /* original attribute there */
83 int cursor_o_attr; /* original attribute under cursor */
84 mpdm_t v; /* the data */
85 mpdm_t old; /* the previously generated array */
86 int mark_offset; /* offset to the marked block */
87 int mark_size; /* size of mark_o_attr */
88 char *mark_o_attr; /* saved attributes for the mark */
89 } drw_2;
91 /** code **/
93 #define MP_REAL_TAB_SIZE(x) (drw_1.tab_size - ((x) % drw_1.tab_size))
95 static int drw_wcwidth(int x, wchar_t c)
96 /* returns the wcwidth of c, or the tab spaces for
97 the x column if it's a tab */
99 int r;
101 switch (c) {
102 case L'\n':
103 r = 1;
104 break;
105 case L'\t':
106 r = MP_REAL_TAB_SIZE(x);
107 break;
108 default:
109 r = mpdm_wcwidth(c);
110 break;
113 return r < 0 ? 1 : r;
117 int drw_vx2x(mpdm_t str, int vx)
118 /* returns the character in str that is on column vx */
120 const wchar_t *ptr = str->data;
121 int n, x;
123 for (n = x = 0; n < vx && ptr[x] != L'\0'; x++)
124 n += drw_wcwidth(n, ptr[x]);
126 return x;
130 int drw_x2vx(mpdm_t str, int x)
131 /* returns the column where the character at offset x seems to be */
133 const wchar_t *ptr = str->data;
134 int n, vx;
136 for (n = vx = 0; n < x && ptr[n] != L'\0'; n++)
137 vx += drw_wcwidth(vx, ptr[n]);
139 return vx;
143 static int drw_line_offset(int l)
144 /* returns the offset into v for line number l */
146 return drw_2.offsets[l - drw_1.vy + drw_1.p_lines];
150 static int drw_adjust_y(int y, int *vy, int ty)
151 /* adjusts the visual y position */
153 int t = *vy;
155 /* is y above the first visible line? */
156 if (y < *vy)
157 *vy = y;
159 /* is y below the last visible line? */
160 if (y > *vy + (ty - 2))
161 *vy = y - (ty - 2);
163 return t != *vy;
167 static int drw_adjust_x(int x, int y, int *vx, int tx, wchar_t * ptr)
168 /* adjust the visual x position */
170 int n, m;
171 int t = *vx;
173 /* calculate the column for the cursor position */
174 for (n = m = 0; n < x; n++, ptr++)
175 m += drw_wcwidth(m, *ptr);
177 /* if new cursor column is nearer the leftmost column, set */
178 if (m < *vx)
179 *vx = m;
181 /* if new cursor column is further the rightmost column, set */
182 if (m > *vx + (tx - 1))
183 *vx = m - (tx - 1);
185 return t != *vx;
189 static int drw_get_attr(wchar_t * color_name)
190 /* returns the attribute number for a color */
192 mpdm_t v;
193 int attr = 0;
195 if ((v = mpdm_hget_s(drw_1.colors, color_name)) != NULL)
196 attr = mpdm_ival(mpdm_hget_s(v, L"attr"));
198 return attr;
202 static int drw_prepare(mpdm_t doc)
203 /* prepares the document for screen drawing */
205 mpdm_t window = mpdm_hget_s(mp, L"window");
206 mpdm_t config = mpdm_hget_s(mp, L"config");
207 mpdm_t txt = mpdm_hget_s(doc, L"txt");
208 mpdm_t lines = mpdm_hget_s(txt, L"lines");
209 int x = mpdm_ival(mpdm_hget_s(txt, L"x"));
210 int y = mpdm_ival(mpdm_hget_s(txt, L"y"));
211 int n;
213 drw_1.vx = mpdm_ival(mpdm_hget_s(txt, L"vx"));
214 drw_1.vy = mpdm_ival(mpdm_hget_s(txt, L"vy"));
215 drw_1.tx = mpdm_ival(mpdm_hget_s(window, L"tx"));
216 drw_1.ty = mpdm_ival(mpdm_hget_s(window, L"ty"));
217 drw_1.tab_size = mpdm_ival(mpdm_hget_s(config, L"tab_size"));
218 drw_1.mod = mpdm_ival(mpdm_hget_s(txt, L"mod"));
219 drw_1.preread_lines = mpdm_ival(mpdm_hget_s(config, L"preread_lines"));
220 drw_1.mark_eol = mpdm_ival(mpdm_hget_s(config, L"mark_eol"));
221 drw_1.t_lines = mpdm_size(lines);
223 /* adjust the visual y coordinate */
224 if (drw_adjust_y(y, &drw_1.vy, drw_1.ty))
225 mpdm_hset_s(txt, L"vy", MPDM_I(drw_1.vy));
227 /* adjust the visual x coordinate */
228 if (drw_adjust_x(x, y, &drw_1.vx, drw_1.tx, mpdm_string(mpdm_aget(lines, y))))
229 mpdm_hset_s(txt, L"vx", MPDM_I(drw_1.vx));
231 /* get the maximum prereadable lines */
232 drw_1.p_lines = drw_1.vy > drw_1.preread_lines ? drw_1.preread_lines : drw_1.vy;
234 /* maximum lines */
235 drw_1.n_lines = drw_1.ty + drw_1.p_lines;
237 /* get the mp.colors structure and the most used attributes */
238 drw_1.colors = mpdm_hget_s(mp, L"colors");
239 drw_1.normal_attr = drw_get_attr(L"normal");
240 drw_1.cursor_attr = drw_get_attr(L"cursor");
242 /* store the syntax highlight structure */
243 drw_1.syntax = mpdm_hget_s(doc, L"syntax");
245 drw_1.word_color_func = mpdm_hget_s(mp, L"word_color_func");
247 mpdm_unref(drw_1.txt);
248 drw_1.txt = mpdm_ref(txt);
250 drw_2.x = x;
251 drw_2.y = y;
253 /* last search regex */
254 drw_1.last_search = mpdm_hget_s(mp, L"last_search");
256 /* redraw trigger */
257 drw_1.redraw = mpdm_ival(mpdm_hget_s(mp, L"redraw_counter"));
259 /* compare drw_1 with drw_1_o; if they are the same,
260 no more expensive calculations on drw_2 are needed */
261 if (memcmp(&drw_1, &drw_1_o, sizeof(drw_1)) == 0)
262 return 0;
264 /* different; store now */
265 memcpy(&drw_1_o, &drw_1, sizeof(drw_1_o));
267 /* alloc space for line offsets */
268 drw_2.offsets = realloc(drw_2.offsets, drw_1.n_lines * sizeof(int));
270 drw_2.ptr = NULL;
271 drw_2.size = 0;
273 /* add first line */
274 drw_2.ptr = mpdm_pokev(drw_2.ptr, &drw_2.size,
275 mpdm_aget(lines, drw_1.vy - drw_1.p_lines));
277 /* first line start at 0 */
278 drw_2.offsets[0] = 0;
280 /* add the following lines and store their offsets */
281 for (n = 1; n < drw_1.n_lines; n++) {
282 /* add the separator */
283 drw_2.ptr = mpdm_poke(drw_2.ptr, &drw_2.size, L"\n", 1, sizeof(wchar_t));
285 /* this line starts here */
286 drw_2.offsets[n] = drw_2.size;
288 /* now add it */
289 drw_2.ptr = mpdm_pokev(drw_2.ptr, &drw_2.size,
290 mpdm_aget(lines, n + drw_1.vy - drw_1.p_lines));
293 drw_2.ptr = mpdm_poke(drw_2.ptr, &drw_2.size, L"", 1, sizeof(wchar_t));
294 drw_2.size--;
296 /* now create a value */
297 mpdm_unref(drw_2.v);
298 drw_2.v = mpdm_ref(MPDM_ENS(drw_2.ptr, drw_2.size));
300 /* alloc and init space for the attributes */
301 drw_2.attrs = realloc(drw_2.attrs, drw_2.size + 1);
302 memset(drw_2.attrs, drw_1.normal_attr, drw_2.size + 1);
304 drw_2.visible = drw_line_offset(drw_1.vy);
306 return 1;
310 static int drw_fill_attr(int attr, int offset, int size)
311 /* fill an attribute */
313 if (attr != -1)
314 memset(drw_2.attrs + offset, attr, size);
316 return offset + size;
320 static int drw_fill_attr_regex(int attr)
321 /* fills with an attribute the last regex match */
323 return drw_fill_attr(attr, mpdm_regex_offset, mpdm_regex_size);
327 static void drw_words(void)
328 /* fills the attributes for separate words */
330 mpdm_t r, t;
331 int o = drw_2.visible;
332 mpdm_t word_color = NULL;
333 mpdm_t word_color_func = NULL;
335 /* take the hash of word colors, if any */
336 if ((word_color = mpdm_hget_s(mp, L"word_color")) == NULL)
337 return;
339 /* get the regex for words */
340 if ((r = mpdm_hget_s(mp, L"word_regex")) == NULL)
341 return;
343 /* get the word color function */
344 word_color_func = mpdm_hget_s(mp, L"word_color_func");
346 while ((t = mpdm_regex(r, drw_2.v, o)) != NULL) {
347 int attr = -1;
348 mpdm_t v;
350 if ((v = mpdm_hget(word_color, t)) != NULL)
351 attr = mpdm_ival(v);
352 else if (word_color_func != NULL)
353 attr = mpdm_ival(mpdm_exec_1(word_color_func, t));
355 o = drw_fill_attr_regex(attr);
360 static void drw_multiline_regex(mpdm_t a, int attr)
361 /* sets the attribute to all matching (possibly multiline) regexes */
363 int n;
365 for (n = 0; n < mpdm_size(a); n++) {
366 mpdm_t r = mpdm_aget(a, n);
367 int o = 0;
369 /* if the regex is an array, it's a pair of
370 'match from this' / 'match until this' */
371 if (r->flags & MPDM_MULTIPLE) {
372 mpdm_t rs = mpdm_aget(r, 0);
373 mpdm_t re = mpdm_aget(r, 1);
375 while (mpdm_regex(rs, drw_2.v, o)) {
376 int s;
378 /* fill the matched part */
379 o = drw_fill_attr_regex(attr);
381 /* try to match the end */
382 if (mpdm_regex(re, drw_2.v, o)) {
383 /* found; fill the attribute
384 to the end of the match */
385 s = mpdm_regex_size + (mpdm_regex_offset - o);
387 else {
388 /* not found; fill to the end
389 of the document */
390 s = drw_2.size - o;
393 /* fill to there */
394 o = drw_fill_attr(attr, o, s);
397 else {
398 /* it's a scalar: */
399 /* while the regex matches, fill attributes */
400 while (mpdm_regex(r, drw_2.v, o))
401 o = drw_fill_attr_regex(attr);
407 static void drw_blocks(void)
408 /* fill attributes for multiline blocks */
410 mpdm_t defs;
411 int n;
413 /* no definitions? return */
414 if (drw_1.syntax == NULL || (defs = mpdm_hget_s(drw_1.syntax, L"defs")) == NULL)
415 return;
417 for (n = 0; n < mpdm_size(defs); n += 2) {
418 mpdm_t attr;
419 mpdm_t list;
421 /* get the attribute */
422 attr = mpdm_aget(defs, n);
423 attr = mpdm_hget(drw_1.colors, attr);
424 attr = mpdm_hget_s(attr, L"attr");
426 /* get the list for this word color */
427 list = mpdm_aget(defs, n + 1);
429 drw_multiline_regex(list, mpdm_ival(attr));
434 static void drw_selection(void)
435 /* draws the selected block, if any */
437 mpdm_t mark;
438 int bx, by, ex, ey, vertical;
439 int so, eo;
440 int mby, mey;
441 int line_offset, next_line_offset;
442 int y;
443 int len;
444 int attr;
446 /* no mark? return */
447 if ((mark = mpdm_hget_s(drw_1.txt, L"mark")) == NULL)
448 return;
450 bx = mpdm_ival(mpdm_hget_s(mark, L"bx"));
451 by = mpdm_ival(mpdm_hget_s(mark, L"by"));
452 ex = mpdm_ival(mpdm_hget_s(mark, L"ex"));
453 ey = mpdm_ival(mpdm_hget_s(mark, L"ey"));
454 vertical = mpdm_ival(mpdm_hget_s(mark, L"vertical"));
456 /* if block is not visible, return */
457 if (ey < drw_1.vy || by > drw_1.vy + drw_1.ty)
458 return;
460 so = by < drw_1.vy ? drw_2.visible : drw_line_offset(by) + bx;
461 eo = ey >= drw_1.vy + drw_1.ty ? drw_2.size : drw_line_offset(ey) + ex;
463 /* alloc space and save the attributes being destroyed */
464 drw_2.mark_offset = so;
465 drw_2.mark_size = eo - so + 1;
466 drw_2.mark_o_attr = malloc(eo - so + 1);
467 memcpy(drw_2.mark_o_attr, &drw_2.attrs[so], eo - so + 1);
469 if (vertical == 0) {
470 /* normal selection */
471 drw_fill_attr(drw_get_attr(L"selection"), so, eo - so);
473 else {
474 /* vertical selection */
475 mby = by < drw_1.vy ? drw_1.vy : by;
476 mey = ey >= drw_1.vy + drw_1.ty ? drw_1.vy + drw_1.ty : ey;
477 line_offset = drw_line_offset(mby);
478 attr = drw_get_attr(L"selection");
479 for (y = mby; y <= mey; y++) {
480 next_line_offset = drw_line_offset(y+1);
481 len = next_line_offset - line_offset - 1;
482 so = bx > len ? -1 : bx;
483 eo = ex > len ? len : ex;
485 if (so >= 0 && eo >= so)
486 drw_fill_attr(attr, line_offset+ so, eo - so + 1);
488 line_offset = next_line_offset;
494 static void drw_search_hit(void)
495 /* colorize the search hit, if any */
497 if (drw_1.last_search != NULL) {
498 mpdm_t l = mpdm_ref(MPDM_A(0));
500 mpdm_aset(l, drw_1.last_search, 0);
501 drw_multiline_regex(l, drw_get_attr(L"search"));
502 mpdm_unref(l);
507 static void drw_cursor(void)
508 /* fill the attribute for the cursor */
510 /* calculate the cursor offset */
511 drw_2.cursor = drw_line_offset(drw_2.y) + drw_2.x;
513 drw_2.cursor_o_attr = drw_2.attrs[drw_2.cursor];
514 drw_fill_attr(drw_1.cursor_attr, drw_2.cursor, 1);
518 static void drw_matching_paren(void)
519 /* highlights the matching paren */
521 int o = drw_2.cursor;
522 int i = 0;
523 wchar_t c;
525 /* by default, no offset has been found */
526 drw_2.matchparen_offset = -1;
528 /* find the opposite and the increment (direction) */
529 switch (drw_2.ptr[o]) {
530 case L'(':
531 c = L')';
532 i = 1;
533 break;
534 case L'{':
535 c = L'}';
536 i = 1;
537 break;
538 case L'[':
539 c = L']';
540 i = 1;
541 break;
542 case L')':
543 c = L'(';
544 i = -1;
545 break;
546 case L'}':
547 c = L'{';
548 i = -1;
549 break;
550 case L']':
551 c = L'[';
552 i = -1;
553 break;
556 /* if a direction is set, do the searching */
557 if (i) {
558 wchar_t s = drw_2.ptr[o];
559 int m = 0;
560 int l = i == -1 ? drw_2.visible - 1 : drw_2.size;
562 while (o != l) {
563 if (drw_2.ptr[o] == s) {
564 /* found the same */
565 m++;
567 else if (drw_2.ptr[o] == c) {
568 /* found the opposite */
569 if (--m == 0) {
570 /* found! fill and exit */
571 drw_2.matchparen_offset = o;
572 drw_2.matchparen_o_attr = drw_2.attrs[o];
573 drw_fill_attr(drw_get_attr(L"matching"), o, 1);
574 break;
578 o += i;
584 static mpdm_t drw_push_pair(mpdm_t l, int i, int a, wchar_t * tmp)
585 /* pushes a pair of attribute / string into l */
587 /* create the array, if doesn't exist yet */
588 if (l == NULL)
589 l = MPDM_A(0);
591 /* finish the string */
592 tmp[i] = L'\0';
594 /* special magic: if the attribute is the
595 one of the cursor and the string is more than
596 one character, create two strings; the
597 cursor is over a tab */
598 if (a == drw_1.cursor_attr && i > 1) {
599 mpdm_push(l, MPDM_I(a));
600 mpdm_push(l, MPDM_NS(tmp, 1));
602 /* the rest of the string has the original attr */
603 a = drw_2.cursor_o_attr;
605 /* one char less */
606 tmp[i - 1] = L'\0';
609 /* store the attribute and the string */
610 mpdm_push(l, MPDM_I(a));
611 mpdm_push(l, MPDM_S(tmp));
613 return l;
617 #define BUF_LINE 128
619 static mpdm_t drw_line(int line)
620 /* creates a list of attribute / string pairs for the current line */
622 mpdm_t l = NULL;
623 int m, i, t, n;
624 int o = drw_2.offsets[line + drw_1.p_lines];
625 int a = drw_2.attrs[o];
626 wchar_t tmp[BUF_LINE];
627 wchar_t c;
629 /* loop while not beyond the right margin */
630 for (m = i = 0; m < drw_1.vx + drw_1.tx; m += t, o++) {
631 /* take char and size */
632 c = drw_2.ptr[o];
633 t = drw_wcwidth(m, c);
635 /* further the left margin? */
636 if (m >= drw_1.vx) {
637 /* if the attribute is different or we're out of
638 temporary space, push and go on */
639 if (drw_2.attrs[o] != a || i >= BUF_LINE - t - 1) {
640 l = drw_push_pair(l, i, a, tmp);
641 i = 0;
644 /* size is 1, unless it's a tab */
645 n = c == L'\t' ? t : 1;
647 /* fill tabs with spaces */
648 if (c == L'\0' || c == L'\t')
649 c = L' ';
651 /* fill EOLs with special marks or spaces */
652 if (c == L'\n')
653 c = drw_1.mark_eol ? L'\xb6' : L' ';
655 /* if next char will not fit, use a space */
656 if (m + t > drw_1.vx + drw_1.tx)
657 c = L' ';
659 else {
660 /* left filler */
661 n = m + t - drw_1.vx;
662 c = L' ';
665 /* fill the string */
666 for (; n > 0; n--)
667 tmp[i++] = c;
669 a = drw_2.attrs[o];
671 /* end of line? */
672 if (drw_2.ptr[o] == L'\0' || drw_2.ptr[o] == L'\n')
673 break;
676 return drw_push_pair(l, i, a, tmp);
680 static mpdm_t drw_as_array(void)
681 /* returns an mpdm array of ty elements, which are also arrays of
682 attribute - string pairs */
684 mpdm_t a;
685 int n;
687 /* the array of lines */
688 a = MPDM_A(drw_1.ty);
690 /* push each line */
691 for (n = 0; n < drw_1.ty; n++)
692 mpdm_aset(a, drw_line(n), n);
694 return a;
698 static mpdm_t drw_optimize_array(mpdm_t a, int optimize)
699 /* optimizes the array, NULLifying all lines that are the same as the last time */
701 mpdm_t o = drw_2.old;
702 mpdm_t r = a;
704 if (optimize && o != NULL) {
705 int n = 0;
707 /* creates a copy */
708 r = mpdm_clone(a);
710 /* compare each array */
711 while (n < mpdm_size(o) && n < mpdm_size(r)) {
712 /* if both lines are equal, optimize out */
713 if (mpdm_cmp(mpdm_aget(o, n), mpdm_aget(r, n)) == 0)
714 mpdm_aset(r, NULL, n);
716 n++;
720 mpdm_unref(drw_2.old);
721 drw_2.old = mpdm_ref(a);
723 return r;
727 static void drw_restore_attrs(void)
728 /* restored the patched attrs */
730 /* matching paren, if any */
731 if (drw_2.matchparen_offset != -1)
732 drw_fill_attr(drw_2.matchparen_o_attr, drw_2.matchparen_offset, 1);
734 /* cursor */
735 drw_fill_attr(drw_2.cursor_o_attr, drw_2.cursor, 1);
737 /* marked block, if any */
738 if (drw_2.mark_o_attr != NULL) {
739 memcpy(&drw_2.attrs[drw_2.mark_offset], drw_2.mark_o_attr, drw_2.mark_size);
741 free(drw_2.mark_o_attr);
742 drw_2.mark_o_attr = NULL;
747 static mpdm_t drw_draw(mpdm_t doc, int optimize)
748 /* main document drawing function: takes a document and returns an array of
749 arrays of attribute / string pairs */
751 mpdm_t r = NULL;
753 if (drw_prepare(doc)) {
754 /* colorize separate words */
755 drw_words();
757 /* colorize multiline blocks */
758 drw_blocks();
761 /* now set the marked block (if any) */
762 drw_selection();
764 /* colorize the search hit */
765 drw_search_hit();
767 /* the cursor */
768 drw_cursor();
770 /* highlight the matching paren */
771 drw_matching_paren();
773 /* convert to an array of string / atribute pairs */
774 r = drw_as_array();
776 /* optimize */
777 r = drw_optimize_array(r, optimize);
779 /* restore the patched attrs */
780 drw_restore_attrs();
782 return r;
786 /** interface **/
788 mpdm_t mp_draw(mpdm_t doc, int optimize)
789 /* main generic drawing function: if the document has a 'paint' code,
790 calls it; otherwise, call drw_draw() */
792 mpdm_t r = NULL;
793 static int ppp = 0; /* previous private paint */
794 mpdm_t f;
796 /* if previous paint was private, disable optimizations */
797 if (ppp)
798 optimize = ppp = 0;
800 if (doc != NULL) {
801 if ((f = mpdm_hget_s(doc, L"paint")) != NULL) {
802 ppp = 1;
803 r = mpdm_exec_2(f, doc, MPDM_I(optimize));
805 else
806 r = drw_draw(doc, optimize);
809 /* if there is a global post_paint function, execute it */
810 if ((f = mpdm_hget_s(mp, L"post_paint")) != NULL)
811 r = mpdm_exec_1(f, r);
813 /* if doc has a post_paint function, execute it */
814 if ((f = mpdm_hget_s(doc, L"post_paint")) != NULL)
815 r = mpdm_exec_1(f, r);
817 return r;
821 #define THR_SPEED_STEP 10
822 #define THR_MAX_SPEED 7
824 int mp_keypress_throttle(int keydown)
825 /* processes key acceleration and throttle */
827 static int keydowns = 0;
828 static int seq = 0;
829 int redraw = 0;
831 if (keydown) {
832 int speed;
834 /* as keydowns accumulate, speed increases, which is the number
835 of cycles the redraw will be skipped (up to a maximum) */
836 if ((speed = 1 + (++keydowns / THR_SPEED_STEP)) > THR_MAX_SPEED)
837 speed = THR_MAX_SPEED;
839 if (++seq % speed == 0)
840 redraw = 1;
842 else {
843 if (keydowns > 1)
844 redraw = 1;
846 keydowns = 0;
849 return redraw;
853 mpdm_t mp_active(void)
854 /* interface to mp.active() */
856 return mpdm_exec(mpdm_hget_s(mp, L"active"), NULL);
860 mpdm_t mp_process_action(mpdm_t action)
861 /* interface to mp.process_action() */
863 return mpdm_exec_1(mpdm_hget_s(mp, L"process_action"), action);
867 mpdm_t mp_process_event(mpdm_t keycode)
868 /* interface to mp.process_event() */
870 return mpdm_exec_1(mpdm_hget_s(mp, L"process_event"), keycode);
874 mpdm_t mp_set_y(mpdm_t doc, int y)
875 /* interface to mp.set_y() */
877 return mpdm_exec_2(mpdm_hget_s(mp, L"set_y"), doc, MPDM_I(y));
881 mpdm_t mp_build_status_line(void)
882 /* interface to mp.build_status_line() */
884 return mpdm_exec(mpdm_hget_s(mp, L"build_status_line"), NULL);
888 mpdm_t mp_get_history(mpdm_t key)
889 /* interface to mp.get_history() */
891 return mpdm_exec_1(mpdm_hget_s(mp, L"get_history"), key);
895 mpdm_t mp_get_doc_names(void)
896 /* interface to mp.get_doc_names() */
898 return mpdm_exec(mpdm_hget_s(mp, L"get_doc_names"), NULL);
902 mpdm_t mp_menu_label(mpdm_t action)
903 /* interface to mp.menu_label() */
905 return mpdm_exec_1(mpdm_hget_s(mp, L"menu_label"), action);
909 mpdm_t mp_pending_key(void)
910 /* interface to mp.pending_key() */
912 return mpdm_exec_1(mpdm_hget_s(mp, L"pending_key"), NULL);
916 mpdm_t mp_process_keyseq(mpdm_t key)
917 /* interface to mp.process_keyseq() */
919 return mpdm_exec_1(mpdm_hget_s(mp, L"process_keyseq"), key);
923 mpdm_t mp_exit(mpdm_t args)
924 /* exit the editor (set mp_exit_requested) */
926 mp_exit_requested = 1;
928 return NULL;
932 mpdm_t mp_vx2x(mpdm_t args)
933 /* interface to drw_vx2x() */
935 return MPDM_I(drw_vx2x(mpdm_aget(args, 0), mpdm_ival(mpdm_aget(args, 1))));
939 mpdm_t mp_x2vx(mpdm_t args)
940 /* interface to drw_x2vx() */
942 return MPDM_I(drw_x2vx(mpdm_aget(args, 0), mpdm_ival(mpdm_aget(args, 1))));
945 mpdm_t mp_plain_load(mpdm_t args)
946 /* loads a plain file into an array (highly optimized one) */
948 mpdm_t f = mpdm_aget(args, 0);
949 mpdm_t a = MPDM_A(0);
950 mpdm_t v;
951 int chomped = 1;
953 while ((v = mpdm_read(f)) != NULL) {
954 const wchar_t *ptr = v->data;
955 int size = v->size;
957 /* chomp */
958 if (size && ptr[size - 1] == L'\n') {
959 if (--size && ptr[size - 1] == L'\r')
960 --size;
962 else
963 chomped = 0;
965 mpdm_push(a, MPDM_NS(ptr, size));
966 mpdm_destroy(v);
969 /* if last line was chomped, add a last, empty one */
970 if (chomped)
971 mpdm_push(a, MPDM_LS(L""));
973 return a;
977 void mp_startup(int argc, char *argv[])
979 mpdm_t INC;
981 mpsl_startup();
983 /* reset the structures */
984 memset(&drw_1, '\0', sizeof(drw_1));
985 memset(&drw_1_o, '\0', sizeof(drw_1_o));
987 /* create main namespace */
988 mp = MPDM_H(0);
989 mpdm_hset_s(mpdm_root(), L"mp", mp);
991 /* basic functions and data */
992 mpdm_hset_s(mp, L"x2vx", MPDM_X(mp_x2vx));
993 mpdm_hset_s(mp, L"vx2x", MPDM_X(mp_vx2x));
994 mpdm_hset_s(mp, L"exit", MPDM_X(mp_exit));
995 mpdm_hset_s(mp, L"plain_load", MPDM_X(mp_plain_load));
996 mpdm_hset_s(mp, L"window", MPDM_H(0));
997 mpdm_hset_s(mp, L"drv", MPDM_H(0));
999 /* version */
1000 mpdm_hset_s(mp, L"VERSION", MPDM_S(L"" VERSION));
1002 /* creates the INC (executable path) array */
1003 INC = MPDM_A(0);
1005 /* add installed library path */
1006 mpdm_push(INC, mpdm_strcat(mpdm_hget_s(mpdm_root(), L"APPDIR"),
1007 MPDM_MBS(CONFOPT_APPNAME))
1010 /* set INC */
1011 mpdm_hset_s(mpdm_root(), L"INC", INC);
1013 if (!TRY_DRIVERS()) {
1014 printf("No usable driver found; exiting.\n");
1015 exit(1);
1018 mpsl_argv(argc, argv);
1022 void mp_mpsl(void)
1024 mpdm_t e;
1026 mpsl_eval(MPDM_LS(L"load('mp_core.mpsl');"), NULL);
1028 if ((e = mpdm_hget_s(mpdm_root(), L"ERROR")) != NULL) {
1029 mpdm_write_wcs(stdout, mpdm_string(e));
1030 printf("\n");
1035 void mp_shutdown(void)
1037 mpsl_shutdown();
1041 int main(int argc, char *argv[])
1043 mp_startup(argc, argv);
1045 mp_mpsl();
1047 mp_shutdown();
1049 return 0;