The 'seek_misspelled' action has been assigned to ctrl-f7.
[mp-5.x.git] / mp_core.c
blobc59c4f1a806b2702b757fa86a714decfd112b94f
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 /** 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 */
68 struct drw_1_info drw_1;
69 struct drw_1_info drw_1_o;
71 static struct {
72 int x; /* cursor x */
73 int y; /* cursor y */
74 int *offsets; /* offsets of lines */
75 char *attrs; /* attributes */
76 int visible; /* offset to the first visible character */
77 int cursor; /* offset to cursor */
78 wchar_t *ptr; /* pointer to joined data */
79 int size; /* size of joined data */
80 int matchparen_offset; /* offset to matched paren */
81 int matchparen_o_attr; /* original attribute there */
82 int cursor_o_attr; /* original attribute under cursor */
83 mpdm_t v; /* the data */
84 mpdm_t old; /* the previously generated array */
85 int mark_offset; /* offset to the marked block */
86 int mark_size; /* size of mark_o_attr */
87 char *mark_o_attr; /* saved attributes for the mark */
88 } drw_2;
90 /** code **/
92 #define MP_REAL_TAB_SIZE(x) (drw_1.tab_size - ((x) % drw_1.tab_size))
94 static int drw_wcwidth(int x, wchar_t c)
95 /* returns the wcwidth of c, or the tab spaces for
96 the x column if it's a tab */
98 int r;
100 switch (c) {
101 case L'\n':
102 r = 1;
103 break;
104 case L'\t':
105 r = MP_REAL_TAB_SIZE(x);
106 break;
107 default:
108 r = mpdm_wcwidth(c);
109 break;
112 return r < 0 ? 1 : r;
116 int drw_vx2x(mpdm_t str, int vx)
117 /* returns the character in str that is on column vx */
119 const wchar_t *ptr = str->data;
120 int n, x;
122 for (n = x = 0; n < vx && ptr[x] != L'\0'; x++)
123 n += drw_wcwidth(n, ptr[x]);
125 return x;
129 int drw_x2vx(mpdm_t str, int x)
130 /* returns the column where the character at offset x seems to be */
132 const wchar_t *ptr = str->data;
133 int n, vx;
135 for (n = vx = 0; n < x && ptr[n] != L'\0'; n++)
136 vx += drw_wcwidth(vx, ptr[n]);
138 return vx;
142 static int drw_line_offset(int l)
143 /* returns the offset into v for line number l */
145 return drw_2.offsets[l - drw_1.vy + drw_1.p_lines];
149 static int drw_adjust_y(int y, int *vy, int ty)
150 /* adjusts the visual y position */
152 int t = *vy;
154 /* is y above the first visible line? */
155 if (y < *vy)
156 *vy = y;
158 /* is y below the last visible line? */
159 if (y > *vy + (ty - 2))
160 *vy = y - (ty - 2);
162 return t != *vy;
166 static int drw_adjust_x(int x, int y, int *vx, int tx, wchar_t * ptr)
167 /* adjust the visual x position */
169 int n, m;
170 int t = *vx;
172 /* calculate the column for the cursor position */
173 for (n = m = 0; n < x; n++, ptr++)
174 m += drw_wcwidth(m, *ptr);
176 /* if new cursor column is nearer the leftmost column, set */
177 if (m < *vx)
178 *vx = m;
180 /* if new cursor column is further the rightmost column, set */
181 if (m > *vx + (tx - 1))
182 *vx = m - (tx - 1);
184 return t != *vx;
188 static int drw_get_attr(wchar_t * color_name)
189 /* returns the attribute number for a color */
191 mpdm_t v;
192 int attr = 0;
194 if ((v = mpdm_hget_s(drw_1.colors, color_name)) != NULL)
195 attr = mpdm_ival(mpdm_hget_s(v, L"attr"));
197 return attr;
201 static int drw_prepare(mpdm_t doc)
202 /* prepares the document for screen drawing */
204 mpdm_t window = mpdm_hget_s(mp, L"window");
205 mpdm_t config = mpdm_hget_s(mp, L"config");
206 mpdm_t txt = mpdm_hget_s(doc, L"txt");
207 mpdm_t lines = mpdm_hget_s(txt, L"lines");
208 int x = mpdm_ival(mpdm_hget_s(txt, L"x"));
209 int y = mpdm_ival(mpdm_hget_s(txt, L"y"));
210 int n;
212 drw_1.vx = mpdm_ival(mpdm_hget_s(txt, L"vx"));
213 drw_1.vy = mpdm_ival(mpdm_hget_s(txt, L"vy"));
214 drw_1.tx = mpdm_ival(mpdm_hget_s(window, L"tx"));
215 drw_1.ty = mpdm_ival(mpdm_hget_s(window, L"ty"));
216 drw_1.tab_size = mpdm_ival(mpdm_hget_s(config, L"tab_size"));
217 drw_1.mod = mpdm_ival(mpdm_hget_s(txt, L"mod"));
218 drw_1.preread_lines = mpdm_ival(mpdm_hget_s(config, L"preread_lines"));
219 drw_1.mark_eol = mpdm_ival(mpdm_hget_s(config, L"mark_eol"));
220 drw_1.t_lines = mpdm_size(lines);
222 /* adjust the visual y coordinate */
223 if (drw_adjust_y(y, &drw_1.vy, drw_1.ty))
224 mpdm_hset_s(txt, L"vy", MPDM_I(drw_1.vy));
226 /* adjust the visual x coordinate */
227 if (drw_adjust_x(x, y, &drw_1.vx, drw_1.tx, mpdm_string(mpdm_aget(lines, y))))
228 mpdm_hset_s(txt, L"vx", MPDM_I(drw_1.vx));
230 /* get the maximum prereadable lines */
231 drw_1.p_lines = drw_1.vy > drw_1.preread_lines ? drw_1.preread_lines : drw_1.vy;
233 /* maximum lines */
234 drw_1.n_lines = drw_1.ty + drw_1.p_lines;
236 /* get the mp.colors structure and the most used attributes */
237 drw_1.colors = mpdm_hget_s(mp, L"colors");
238 drw_1.normal_attr = drw_get_attr(L"normal");
239 drw_1.cursor_attr = drw_get_attr(L"cursor");
241 /* store the syntax highlight structure */
242 drw_1.syntax = mpdm_hget_s(doc, L"syntax");
244 drw_1.word_color_func = mpdm_hget_s(mp, L"word_color_func");
246 mpdm_unref(drw_1.txt);
247 drw_1.txt = mpdm_ref(txt);
249 drw_2.x = x;
250 drw_2.y = y;
252 /* last search regex */
253 drw_1.last_search = mpdm_hget_s(mp, L"last_search");
255 /* compare drw_1 with drw_1_o; if they are the same,
256 no more expensive calculations on drw_2 are needed */
257 if (memcmp(&drw_1, &drw_1_o, sizeof(drw_1)) == 0)
258 return 0;
260 /* different; store now */
261 memcpy(&drw_1_o, &drw_1, sizeof(drw_1_o));
263 /* alloc space for line offsets */
264 drw_2.offsets = realloc(drw_2.offsets, drw_1.n_lines * sizeof(int));
266 drw_2.ptr = NULL;
267 drw_2.size = 0;
269 /* add first line */
270 drw_2.ptr = mpdm_pokev(drw_2.ptr, &drw_2.size,
271 mpdm_aget(lines, drw_1.vy - drw_1.p_lines));
273 /* first line start at 0 */
274 drw_2.offsets[0] = 0;
276 /* add the following lines and store their offsets */
277 for (n = 1; n < drw_1.n_lines; n++) {
278 /* add the separator */
279 drw_2.ptr = mpdm_poke(drw_2.ptr, &drw_2.size, L"\n", 1, sizeof(wchar_t));
281 /* this line starts here */
282 drw_2.offsets[n] = drw_2.size;
284 /* now add it */
285 drw_2.ptr = mpdm_pokev(drw_2.ptr, &drw_2.size,
286 mpdm_aget(lines, n + drw_1.vy - drw_1.p_lines));
289 drw_2.ptr = mpdm_poke(drw_2.ptr, &drw_2.size, L"", 1, sizeof(wchar_t));
290 drw_2.size--;
292 /* now create a value */
293 mpdm_unref(drw_2.v);
294 drw_2.v = mpdm_ref(MPDM_ENS(drw_2.ptr, drw_2.size));
296 /* alloc and init space for the attributes */
297 drw_2.attrs = realloc(drw_2.attrs, drw_2.size + 1);
298 memset(drw_2.attrs, drw_1.normal_attr, drw_2.size + 1);
300 drw_2.visible = drw_line_offset(drw_1.vy);
302 return 1;
306 static int drw_fill_attr(int attr, int offset, int size)
307 /* fill an attribute */
309 if (attr != -1)
310 memset(drw_2.attrs + offset, attr, size);
312 return offset + size;
316 static int drw_fill_attr_regex(int attr)
317 /* fills with an attribute the last regex match */
319 return drw_fill_attr(attr, mpdm_regex_offset, mpdm_regex_size);
323 static void drw_words(void)
324 /* fills the attributes for separate words */
326 mpdm_t r, t;
327 int o = drw_2.visible;
328 mpdm_t word_color = NULL;
329 mpdm_t word_color_func = NULL;
331 /* take the hash of word colors, if any */
332 if ((word_color = mpdm_hget_s(mp, L"word_color")) == NULL)
333 return;
335 /* get the regex for words */
336 if ((r = mpdm_hget_s(mp, L"word_regex")) == NULL)
337 return;
339 /* get the word color function */
340 word_color_func = mpdm_hget_s(mp, L"word_color_func");
342 while ((t = mpdm_regex(r, drw_2.v, o)) != NULL) {
343 int attr = -1;
344 mpdm_t v;
346 if ((v = mpdm_hget(word_color, t)) != NULL)
347 attr = mpdm_ival(v);
348 else if (word_color_func != NULL)
349 attr = mpdm_ival(mpdm_exec_1(word_color_func, t));
351 o = drw_fill_attr_regex(attr);
356 static void drw_multiline_regex(mpdm_t a, int attr)
357 /* sets the attribute to all matching (possibly multiline) regexes */
359 int n;
361 for (n = 0; n < mpdm_size(a); n++) {
362 mpdm_t r = mpdm_aget(a, n);
363 int o = 0;
365 /* if the regex is an array, it's a pair of
366 'match from this' / 'match until this' */
367 if (r->flags & MPDM_MULTIPLE) {
368 mpdm_t rs = mpdm_aget(r, 0);
369 mpdm_t re = mpdm_aget(r, 1);
371 while (mpdm_regex(rs, drw_2.v, o)) {
372 int s;
374 /* fill the matched part */
375 o = drw_fill_attr_regex(attr);
377 /* try to match the end */
378 if (mpdm_regex(re, drw_2.v, o)) {
379 /* found; fill the attribute
380 to the end of the match */
381 s = mpdm_regex_size + (mpdm_regex_offset - o);
383 else {
384 /* not found; fill to the end
385 of the document */
386 s = drw_2.size - o;
389 /* fill to there */
390 o = drw_fill_attr(attr, o, s);
393 else {
394 /* it's a scalar: */
395 /* while the regex matches, fill attributes */
396 while (mpdm_regex(r, drw_2.v, o))
397 o = drw_fill_attr_regex(attr);
403 static void drw_blocks(void)
404 /* fill attributes for multiline blocks */
406 mpdm_t defs;
407 int n;
409 /* no definitions? return */
410 if (drw_1.syntax == NULL || (defs = mpdm_hget_s(drw_1.syntax, L"defs")) == NULL)
411 return;
413 for (n = 0; n < mpdm_size(defs); n += 2) {
414 mpdm_t attr;
415 mpdm_t list;
417 /* get the attribute */
418 attr = mpdm_aget(defs, n);
419 attr = mpdm_hget(drw_1.colors, attr);
420 attr = mpdm_hget_s(attr, L"attr");
422 /* get the list for this word color */
423 list = mpdm_aget(defs, n + 1);
425 drw_multiline_regex(list, mpdm_ival(attr));
430 static void drw_selection(void)
431 /* draws the selected block, if any */
433 mpdm_t mark;
434 int bx, by, ex, ey, vertical;
435 int so, eo;
436 int mby, mey;
437 int line_offset, next_line_offset;
438 int y;
439 int len;
440 int attr;
442 /* no mark? return */
443 if ((mark = mpdm_hget_s(drw_1.txt, L"mark")) == NULL)
444 return;
446 bx = mpdm_ival(mpdm_hget_s(mark, L"bx"));
447 by = mpdm_ival(mpdm_hget_s(mark, L"by"));
448 ex = mpdm_ival(mpdm_hget_s(mark, L"ex"));
449 ey = mpdm_ival(mpdm_hget_s(mark, L"ey"));
450 vertical = mpdm_ival(mpdm_hget_s(mark, L"vertical"));
452 /* if block is not visible, return */
453 if (ey < drw_1.vy || by > drw_1.vy + drw_1.ty)
454 return;
456 so = by < drw_1.vy ? drw_2.visible : drw_line_offset(by) + bx;
457 eo = ey >= drw_1.vy + drw_1.ty ? drw_2.size : drw_line_offset(ey) + ex;
459 /* alloc space and save the attributes being destroyed */
460 drw_2.mark_offset = so;
461 drw_2.mark_size = eo - so + 1;
462 drw_2.mark_o_attr = malloc(eo - so + 1);
463 memcpy(drw_2.mark_o_attr, &drw_2.attrs[so], eo - so + 1);
465 if (vertical == 0) {
466 /* normal selection */
467 drw_fill_attr(drw_get_attr(L"selection"), so, eo - so);
469 else {
470 /* vertical selection */
471 mby = by < drw_1.vy ? drw_1.vy : by;
472 mey = ey >= drw_1.vy + drw_1.ty ? drw_1.vy + drw_1.ty : ey;
473 line_offset = drw_line_offset(mby);
474 attr = drw_get_attr(L"selection");
475 for (y = mby; y <= mey; y++) {
476 next_line_offset = drw_line_offset(y+1);
477 len = next_line_offset - line_offset - 1;
478 so = bx > len ? -1 : bx;
479 eo = ex > len ? len : ex;
481 if (so >= 0 && eo >= so)
482 drw_fill_attr(attr, line_offset+ so, eo - so + 1);
484 line_offset = next_line_offset;
490 static void drw_search_hit(void)
491 /* colorize the search hit, if any */
493 if (drw_1.last_search != NULL) {
494 mpdm_t l = mpdm_ref(MPDM_A(0));
496 mpdm_aset(l, drw_1.last_search, 0);
497 drw_multiline_regex(l, drw_get_attr(L"search"));
498 mpdm_unref(l);
503 static void drw_cursor(void)
504 /* fill the attribute for the cursor */
506 /* calculate the cursor offset */
507 drw_2.cursor = drw_line_offset(drw_2.y) + drw_2.x;
509 drw_2.cursor_o_attr = drw_2.attrs[drw_2.cursor];
510 drw_fill_attr(drw_1.cursor_attr, drw_2.cursor, 1);
514 static void drw_matching_paren(void)
515 /* highlights the matching paren */
517 int o = drw_2.cursor;
518 int i = 0;
519 wchar_t c;
521 /* by default, no offset has been found */
522 drw_2.matchparen_offset = -1;
524 /* find the opposite and the increment (direction) */
525 switch (drw_2.ptr[o]) {
526 case L'(':
527 c = L')';
528 i = 1;
529 break;
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;
552 /* if a direction is set, do the searching */
553 if (i) {
554 wchar_t s = drw_2.ptr[o];
555 int m = 0;
556 int l = i == -1 ? drw_2.visible - 1 : drw_2.size;
558 while (o != l) {
559 if (drw_2.ptr[o] == s) {
560 /* found the same */
561 m++;
563 else if (drw_2.ptr[o] == c) {
564 /* found the opposite */
565 if (--m == 0) {
566 /* found! fill and exit */
567 drw_2.matchparen_offset = o;
568 drw_2.matchparen_o_attr = drw_2.attrs[o];
569 drw_fill_attr(drw_get_attr(L"matching"), o, 1);
570 break;
574 o += i;
580 static mpdm_t drw_push_pair(mpdm_t l, int i, int a, wchar_t * tmp)
581 /* pushes a pair of attribute / string into l */
583 /* create the array, if doesn't exist yet */
584 if (l == NULL)
585 l = MPDM_A(0);
587 /* finish the string */
588 tmp[i] = L'\0';
590 /* special magic: if the attribute is the
591 one of the cursor and the string is more than
592 one character, create two strings; the
593 cursor is over a tab */
594 if (a == drw_1.cursor_attr && i > 1) {
595 mpdm_push(l, MPDM_I(a));
596 mpdm_push(l, MPDM_NS(tmp, 1));
598 /* the rest of the string has the original attr */
599 a = drw_2.cursor_o_attr;
601 /* one char less */
602 tmp[i - 1] = L'\0';
605 /* store the attribute and the string */
606 mpdm_push(l, MPDM_I(a));
607 mpdm_push(l, MPDM_S(tmp));
609 return l;
613 #define BUF_LINE 128
615 static mpdm_t drw_line(int line)
616 /* creates a list of attribute / string pairs for the current line */
618 mpdm_t l = NULL;
619 int m, i, t, n;
620 int o = drw_2.offsets[line + drw_1.p_lines];
621 int a = drw_2.attrs[o];
622 wchar_t tmp[BUF_LINE];
623 wchar_t c;
625 /* loop while not beyond the right margin */
626 for (m = i = 0; m < drw_1.vx + drw_1.tx; m += t, o++) {
627 /* take char and size */
628 c = drw_2.ptr[o];
629 t = drw_wcwidth(m, c);
631 /* further the left margin? */
632 if (m >= drw_1.vx) {
633 /* if the attribute is different or we're out of
634 temporary space, push and go on */
635 if (drw_2.attrs[o] != a || i >= BUF_LINE - t - 1) {
636 l = drw_push_pair(l, i, a, tmp);
637 i = 0;
640 /* size is 1, unless it's a tab */
641 n = c == L'\t' ? t : 1;
643 /* fill tabs with spaces */
644 if (c == L'\0' || c == L'\t')
645 c = L' ';
647 /* fill EOLs with special marks or spaces */
648 if (c == L'\n')
649 c = drw_1.mark_eol ? L'\xb6' : L' ';
651 /* if next char will not fit, use a space */
652 if (m + t > drw_1.vx + drw_1.tx)
653 c = L' ';
655 else {
656 /* left filler */
657 n = m + t - drw_1.vx;
658 c = L' ';
661 /* fill the string */
662 for (; n > 0; n--)
663 tmp[i++] = c;
665 a = drw_2.attrs[o];
667 /* end of line? */
668 if (drw_2.ptr[o] == L'\0' || drw_2.ptr[o] == L'\n')
669 break;
672 return drw_push_pair(l, i, a, tmp);
676 static mpdm_t drw_as_array(void)
677 /* returns an mpdm array of ty elements, which are also arrays of
678 attribute - string pairs */
680 mpdm_t a;
681 int n;
683 /* the array of lines */
684 a = MPDM_A(drw_1.ty);
686 /* push each line */
687 for (n = 0; n < drw_1.ty; n++)
688 mpdm_aset(a, drw_line(n), n);
690 return a;
694 static mpdm_t drw_optimize_array(mpdm_t a, int optimize)
695 /* optimizes the array, NULLifying all lines that are the same as the last time */
697 mpdm_t o = drw_2.old;
698 mpdm_t r = a;
700 if (optimize && o != NULL) {
701 int n = 0;
703 /* creates a copy */
704 r = mpdm_clone(a);
706 /* compare each array */
707 while (n < mpdm_size(o) && n < mpdm_size(r)) {
708 /* if both lines are equal, optimize out */
709 if (mpdm_cmp(mpdm_aget(o, n), mpdm_aget(r, n)) == 0)
710 mpdm_aset(r, NULL, n);
712 n++;
716 mpdm_unref(drw_2.old);
717 drw_2.old = mpdm_ref(a);
719 return r;
723 static void drw_restore_attrs(void)
724 /* restored the patched attrs */
726 /* matching paren, if any */
727 if (drw_2.matchparen_offset != -1)
728 drw_fill_attr(drw_2.matchparen_o_attr, drw_2.matchparen_offset, 1);
730 /* cursor */
731 drw_fill_attr(drw_2.cursor_o_attr, drw_2.cursor, 1);
733 /* marked block, if any */
734 if (drw_2.mark_o_attr != NULL) {
735 memcpy(&drw_2.attrs[drw_2.mark_offset], drw_2.mark_o_attr, drw_2.mark_size);
737 free(drw_2.mark_o_attr);
738 drw_2.mark_o_attr = NULL;
743 static mpdm_t drw_draw(mpdm_t doc, int optimize)
744 /* main document drawing function: takes a document and returns an array of
745 arrays of attribute / string pairs */
747 mpdm_t r = NULL;
749 if (drw_prepare(doc)) {
750 /* colorize separate words */
751 drw_words();
753 /* colorize multiline blocks */
754 drw_blocks();
757 /* now set the marked block (if any) */
758 drw_selection();
760 /* colorize the search hit */
761 drw_search_hit();
763 /* the cursor */
764 drw_cursor();
766 /* highlight the matching paren */
767 drw_matching_paren();
769 /* convert to an array of string / atribute pairs */
770 r = drw_as_array();
772 /* optimize */
773 r = drw_optimize_array(r, optimize);
775 /* restore the patched attrs */
776 drw_restore_attrs();
778 return r;
782 /** interface **/
784 mpdm_t mp_draw(mpdm_t doc, int optimize)
785 /* main generic drawing function: if the document has a 'paint' code,
786 calls it; otherwise, call drw_draw() */
788 mpdm_t r = NULL;
789 static int ppp = 0; /* previous private paint */
790 mpdm_t f;
792 /* if previous paint was private, disable optimizations */
793 if (ppp)
794 optimize = ppp = 0;
796 if (doc != NULL) {
797 if ((f = mpdm_hget_s(doc, L"paint")) != NULL) {
798 ppp = 1;
799 r = mpdm_exec_2(f, doc, MPDM_I(optimize));
801 else
802 r = drw_draw(doc, optimize);
805 /* if there is a global post_paint function, execute it */
806 if ((f = mpdm_hget_s(mp, L"post_paint")) != NULL)
807 r = mpdm_exec_1(f, r);
809 /* if doc has a post_paint function, execute it */
810 if ((f = mpdm_hget_s(doc, L"post_paint")) != NULL)
811 r = mpdm_exec_1(f, r);
813 return r;
817 #define THR_SPEED_STEP 10
818 #define THR_MAX_SPEED 7
820 int mp_keypress_throttle(int keydown)
821 /* processes key acceleration and throttle */
823 static int keydowns = 0;
824 static int seq = 0;
825 int redraw = 0;
827 if (keydown) {
828 int speed;
830 /* as keydowns accumulate, speed increases, which is the number
831 of cycles the redraw will be skipped (up to a maximum) */
832 if ((speed = 1 + (++keydowns / THR_SPEED_STEP)) > THR_MAX_SPEED)
833 speed = THR_MAX_SPEED;
835 if (++seq % speed == 0)
836 redraw = 1;
838 else {
839 if (keydowns > 1)
840 redraw = 1;
842 keydowns = 0;
845 return redraw;
849 mpdm_t mp_active(void)
850 /* interface to mp.active() */
852 return mpdm_exec(mpdm_hget_s(mp, L"active"), NULL);
856 mpdm_t mp_process_action(mpdm_t action)
857 /* interface to mp.process_action() */
859 return mpdm_exec_1(mpdm_hget_s(mp, L"process_action"), action);
863 mpdm_t mp_process_event(mpdm_t keycode)
864 /* interface to mp.process_event() */
866 return mpdm_exec_1(mpdm_hget_s(mp, L"process_event"), keycode);
870 mpdm_t mp_set_y(mpdm_t doc, int y)
871 /* interface to mp.set_y() */
873 return mpdm_exec_2(mpdm_hget_s(mp, L"set_y"), doc, MPDM_I(y));
877 mpdm_t mp_build_status_line(void)
878 /* interface to mp.build_status_line() */
880 return mpdm_exec(mpdm_hget_s(mp, L"build_status_line"), NULL);
884 mpdm_t mp_get_history(mpdm_t key)
885 /* interface to mp.get_history() */
887 return mpdm_exec_1(mpdm_hget_s(mp, L"get_history"), key);
891 mpdm_t mp_get_doc_names(void)
892 /* interface to mp.get_doc_names() */
894 return mpdm_exec(mpdm_hget_s(mp, L"get_doc_names"), NULL);
898 mpdm_t mp_menu_label(mpdm_t action)
899 /* interface to mp.menu_label() */
901 return mpdm_exec_1(mpdm_hget_s(mp, L"menu_label"), action);
905 mpdm_t mp_pending_key(void)
906 /* interface to mp.pending_key() */
908 return mpdm_exec_1(mpdm_hget_s(mp, L"pending_key"), NULL);
912 mpdm_t mp_process_keyseq(mpdm_t key)
913 /* interface to mp.process_keyseq() */
915 return mpdm_exec_1(mpdm_hget_s(mp, L"process_keyseq"), key);
919 mpdm_t mp_exit(mpdm_t args)
920 /* exit the editor (set mp_exit_requested) */
922 mp_exit_requested = 1;
924 return NULL;
928 mpdm_t mp_vx2x(mpdm_t args)
929 /* interface to drw_vx2x() */
931 return MPDM_I(drw_vx2x(mpdm_aget(args, 0), mpdm_ival(mpdm_aget(args, 1))));
935 mpdm_t mp_x2vx(mpdm_t args)
936 /* interface to drw_x2vx() */
938 return MPDM_I(drw_x2vx(mpdm_aget(args, 0), mpdm_ival(mpdm_aget(args, 1))));
941 mpdm_t mp_plain_load(mpdm_t args)
942 /* loads a plain file into an array (highly optimized one) */
944 mpdm_t f = mpdm_aget(args, 0);
945 mpdm_t a = MPDM_A(0);
946 mpdm_t v;
947 int chomped = 1;
949 while ((v = mpdm_read(f)) != NULL) {
950 const wchar_t *ptr = v->data;
951 int size = v->size;
953 /* chomp */
954 if (size && ptr[size - 1] == L'\n') {
955 if (--size && ptr[size - 1] == L'\r')
956 --size;
958 else
959 chomped = 0;
961 mpdm_push(a, MPDM_NS(ptr, size));
962 mpdm_destroy(v);
965 /* if last line was chomped, add a last, empty one */
966 if (chomped)
967 mpdm_push(a, MPDM_LS(L""));
969 return a;
973 void mp_startup(int argc, char *argv[])
975 mpdm_t INC;
977 mpsl_startup();
979 /* reset the structures */
980 memset(&drw_1, '\0', sizeof(drw_1));
981 memset(&drw_1_o, '\0', sizeof(drw_1_o));
983 /* create main namespace */
984 mp = MPDM_H(0);
985 mpdm_hset_s(mpdm_root(), L"mp", mp);
987 /* basic functions and data */
988 mpdm_hset_s(mp, L"x2vx", MPDM_X(mp_x2vx));
989 mpdm_hset_s(mp, L"vx2x", MPDM_X(mp_vx2x));
990 mpdm_hset_s(mp, L"exit", MPDM_X(mp_exit));
991 mpdm_hset_s(mp, L"plain_load", MPDM_X(mp_plain_load));
992 mpdm_hset_s(mp, L"window", MPDM_H(0));
993 mpdm_hset_s(mp, L"drv", MPDM_H(0));
995 /* version */
996 mpdm_hset_s(mp, L"VERSION", MPDM_S(L"" VERSION));
998 /* creates the INC (executable path) array */
999 INC = MPDM_A(0);
1001 /* add installed library path */
1002 mpdm_push(INC, mpdm_strcat(mpdm_hget_s(mpdm_root(), L"APPDIR"),
1003 MPDM_MBS(CONFOPT_APPNAME))
1006 /* set INC */
1007 mpdm_hset_s(mpdm_root(), L"INC", INC);
1009 if (!TRY_DRIVERS()) {
1010 printf("No usable driver found; exiting.\n");
1011 exit(1);
1014 mpsl_argv(argc, argv);
1018 void mp_mpsl(void)
1020 mpdm_t e;
1022 mpsl_eval(MPDM_LS(L"load('mp_core.mpsl');"), NULL);
1024 if ((e = mpdm_hget_s(mpdm_root(), L"ERROR")) != NULL) {
1025 mpdm_write_wcs(stdout, mpdm_string(e));
1026 printf("\n");
1031 void mp_shutdown(void)
1033 mpsl_shutdown();
1037 int main(int argc, char *argv[])
1039 mp_startup(argc, argv);
1041 mp_mpsl();
1043 mp_shutdown();
1045 return 0;