comparison src/if_mzsch.c @ 14:946da5994c01

updated for version 7.0006
author vimboss
date Mon, 05 Jul 2004 15:58:32 +0000
parents
children 631143ac4a01
comparison
equal deleted inserted replaced
13:24d5189d3956 14:946da5994c01
1 /* vi:set ts=8 sts=4 sw=4:
2 *
3 * MzScheme interface by Sergey Khorev <khorev@softlab.ru>
4 * Original work by Brent Fulgham <bfulgham@debian.org>
5 * (Based on lots of help from Matthew Flatt)
6 *
7 * This consists of six parts:
8 * 1. MzScheme interpreter main program
9 * 2. Routines that handle the external interface between MzScheme and
10 * Vim.
11 * 3. MzScheme input/output handlers: writes output via [e]msg().
12 * 4. Implementation of the Vim Features for MzScheme
13 * 5. Vim Window-related Manipulation Functions.
14 * 6. Vim Buffer-related Manipulation Functions
15 *
16 * NOTES
17 * 1. Memory, allocated with scheme_malloc*, need not to be freed explicitly,
18 * garbage collector will do it self
19 * 2. Requires at least NORMAL features. I can't imagine why one may want
20 * to build with SMALL or TINY features but with MzScheme interface.
21 * 3. I don't use K&R-style functions. Anyway, MzScheme headers are ANSI.
22 */
23
24 /* TODO
25 * way to catch Vim errors (incl. verbose messages)
26 * libmzscheme.dll dynamic loading
27 * macros to pass modifiers (e.g. (browse edit))
28 * opportunity to use shared mzscheme libraries on Unix
29 * event on-change-mode
30 * Scheme-driven coloring
31 * global exn-handler
32 * embed Read-Eval-Print-Loop
33 */
34
35 #include "vim.h"
36 #include "if_mzsch.h"
37
38 /* Base data structures */
39 #define SCHEME_VIMBUFFERP(obj) SAME_TYPE(SCHEME_TYPE(obj), mz_buffer_type)
40 #define SCHEME_VIMWINDOWP(obj) SAME_TYPE(SCHEME_TYPE(obj), mz_window_type)
41
42 typedef struct
43 {
44 Scheme_Type tag;
45 Scheme_Env *env;
46 buf_T *buf;
47 Scheme_Object *text_objects;
48 } vim_mz_buffer;
49
50 #define INVALID_BUFFER_VALUE ((buf_T *)(-1))
51
52 typedef struct
53 {
54 Scheme_Type tag;
55 struct window *win;
56 } vim_mz_window;
57
58 #define INVALID_WINDOW_VALUE ((win_T *)(-1))
59
60 /*
61 * Prims that form MzScheme Vim interface
62 */
63 typedef struct
64 {
65 Scheme_Closed_Prim *prim;
66 char *name;
67 int mina; /* arity information */
68 int maxa;
69 } Vim_Prim;
70
71 typedef struct
72 {
73 char *name;
74 Scheme_Object *port;
75 } Port_Info;
76
77 /* info for closed prim */
78 /*
79 * data have different means:
80 * for do_eval it is char*
81 * for do_apply is Apply_Onfo*
82 * for do_load is Port_Info*
83 */
84 typedef struct
85 {
86 void *data;
87 Scheme_Env *env;
88 } Cmd_Info;
89
90 /* info for do_apply */
91 typedef struct
92 {
93 Scheme_Object *proc;
94 int argc;
95 Scheme_Object **argv;
96 } Apply_Info;
97
98 /*
99 *========================================================================
100 * Vim-Control Commands
101 *========================================================================
102 */
103 /*
104 *========================================================================
105 * Utility functions for the vim/mzscheme interface
106 *========================================================================
107 */
108 /* Buffer-related commands */
109 static Scheme_Object *buffer_new(buf_T *buf);
110 static Scheme_Object *get_buffer_by_name(void *, int, Scheme_Object **);
111 static Scheme_Object *get_buffer_by_num(void *, int, Scheme_Object **);
112 static Scheme_Object *get_buffer_count(void *, int, Scheme_Object **);
113 static Scheme_Object *get_buffer_line(void *, int, Scheme_Object **);
114 static Scheme_Object *get_buffer_line_list(void *, int, Scheme_Object **);
115 static Scheme_Object *get_buffer_name(void *, int, Scheme_Object **);
116 static Scheme_Object *get_buffer_num(void *, int, Scheme_Object **);
117 static Scheme_Object *get_buffer_size(void *, int, Scheme_Object **);
118 static Scheme_Object *get_curr_buffer(void *, int, Scheme_Object **);
119 static Scheme_Object *get_next_buffer(void *, int, Scheme_Object **);
120 static Scheme_Object *get_prev_buffer(void *, int, Scheme_Object **);
121 static Scheme_Object *mzscheme_open_buffer(void *, int, Scheme_Object **);
122 static Scheme_Object *set_buffer_line(void *, int, Scheme_Object **);
123 static Scheme_Object *set_buffer_line_list(void *, int, Scheme_Object **);
124 static Scheme_Object *insert_buffer_line_list(void *, int, Scheme_Object **);
125 static Scheme_Object *get_range_start(void *, int, Scheme_Object **);
126 static Scheme_Object *get_range_end(void *, int, Scheme_Object **);
127 static Scheme_Object *get_buffer_namespace(void *, int, Scheme_Object **);
128 static vim_mz_buffer *get_vim_curr_buffer(void);
129
130 /* Window-related commands */
131 static Scheme_Object *window_new(win_T *win);
132 static Scheme_Object *get_curr_win(void *, int, Scheme_Object **);
133 static Scheme_Object *get_window_count(void *, int, Scheme_Object **);
134 static Scheme_Object *get_window_by_num(void *, int, Scheme_Object **);
135 static Scheme_Object *get_window_num(void *, int, Scheme_Object **);
136 static Scheme_Object *get_window_buffer(void *, int, Scheme_Object **);
137 static Scheme_Object *get_window_height(void *, int, Scheme_Object **);
138 static Scheme_Object *set_window_height(void *, int, Scheme_Object **);
139 #ifdef FEAT_VERTSPLIT
140 static Scheme_Object *get_window_width(void *, int, Scheme_Object **);
141 static Scheme_Object *set_window_width(void *, int, Scheme_Object **);
142 #endif
143 static Scheme_Object *get_cursor(void *, int, Scheme_Object **);
144 static Scheme_Object *set_cursor(void *, int, Scheme_Object **);
145 static Scheme_Object *get_window_list(void *, int, Scheme_Object **);
146 static vim_mz_window *get_vim_curr_window(void);
147
148 /* Vim-related commands */
149 static Scheme_Object *mzscheme_beep(void *, int, Scheme_Object **);
150 static Scheme_Object *get_option(void *, int, Scheme_Object **);
151 static Scheme_Object *set_option(void *, int, Scheme_Object **);
152 static Scheme_Object *vim_command(void *, int, Scheme_Object **);
153 static Scheme_Object *vim_eval(void *, int, Scheme_Object **);
154 static Scheme_Object *vim_bufferp(void *data, int, Scheme_Object **);
155 static Scheme_Object *vim_windowp(void *data, int, Scheme_Object **);
156 static Scheme_Object *vim_buffer_validp(void *data, int, Scheme_Object **);
157 static Scheme_Object *vim_window_validp(void *data, int, Scheme_Object **);
158
159 /*
160 *========================================================================
161 * Internal Function Prototypes
162 *========================================================================
163 */
164 static int vim_error_check(void);
165 static int do_mzscheme_command(exarg_T *, void *, Scheme_Closed_Prim *what);
166 static void startup_mzscheme(void);
167 static char *string_to_line(Scheme_Object *obj);
168 static int mzscheme_io_init(void);
169 static void mzscheme_interface_init(vim_mz_buffer *self);
170 static void do_output(char *mesg, long len);
171 static void do_printf(char *format, ...);
172 static void do_flush(void);
173 static Scheme_Object *_apply_thunk_catch_exceptions(
174 Scheme_Object *, Scheme_Object **);
175 static Scheme_Object *extract_exn_message(Scheme_Object *v);
176 static Scheme_Object *do_eval(void *, int noargc, Scheme_Object **noargv);
177 static Scheme_Object *do_load(void *, int noargc, Scheme_Object **noargv);
178 static Scheme_Object *do_apply(void *, int noargc, Scheme_Object **noargv);
179 static void register_vim_exn(Scheme_Env *env);
180 static vim_mz_buffer *get_buffer_arg(const char *fname, int argnum,
181 int argc, Scheme_Object **argv);
182 static vim_mz_window *get_window_arg(const char *fname, int argnum,
183 int argc, Scheme_Object **argv);
184 static void add_vim_exn(Scheme_Env *env);
185 static int line_in_range(linenr_T, buf_T *);
186 static void check_line_range(linenr_T, buf_T *);
187 static void mz_fix_cursor(int lo, int hi, int extra);
188
189 static int eval_in_namespace(void *, Scheme_Closed_Prim *, Scheme_Env *,
190 Scheme_Object **ret);
191 static void make_modules(Scheme_Env *);
192
193 /*
194 *========================================================================
195 * 1. MzScheme interpreter startup
196 *========================================================================
197 */
198
199 static Scheme_Type mz_buffer_type;
200 static Scheme_Type mz_window_type;
201
202 static int initialized = 0;
203
204 /* global environment */
205 static Scheme_Env *environment = NULL;
206 /* output/error handlers */
207 static Scheme_Object *curout = NULL;
208 static Scheme_Object *curerr = NULL;
209 /* vim:exn exception */
210 static Scheme_Object *exn_catching_apply = NULL;
211 static Scheme_Object *exn_p = NULL;
212 static Scheme_Object *exn_message = NULL;
213 static Scheme_Object *vim_exn = NULL; /* Vim Error exception */
214 /* values for exn:vim - constructor, predicate, accessors etc */
215 static Scheme_Object *vim_exn_names = NULL;
216 static Scheme_Object *vim_exn_values = NULL;
217
218 static long range_start;
219 static long range_end;
220
221 /* MzScheme threads scheduling stuff */
222 static int mz_threads_allow = 0;
223 #ifdef FEAT_GUI
224 static void setup_timer(void);
225 static void remove_timer(void);
226 #endif
227
228 #if defined(FEAT_GUI_W32)
229 static void CALLBACK timer_proc(HWND, UINT, UINT, DWORD);
230 static UINT timer_id = 0;
231 #elif defined(FEAT_GUI_GTK)
232 static gint timer_proc(gpointer);
233 static guint timer_id = 0;
234 #elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)
235 static void timer_proc(XtPointer, XtIntervalId *);
236 static XtIntervalId timer_id = (XtIntervalId)0;
237 #elif defined(FEAT_GUI_MAC)
238 pascal void timer_proc(EventLoopTimerRef, void *);
239 static EventLoopTimerRef timer_id = NULL;
240 static EventLoopTimerUPP timerUPP;
241 #endif
242
243 #ifndef FEAT_GUI_W32 /* Win32 console and Unix */
244 void
245 mzvim_check_threads(void)
246 {
247 /* Last time MzScheme threads were scheduled */
248 static time_t mz_last_time = 0;
249
250 if (mz_threads_allow && p_mzq > 0)
251 {
252 time_t now = time(NULL);
253
254 if ((now - mz_last_time) * 1000 > p_mzq)
255 {
256 mz_last_time = now;
257 scheme_check_threads();
258 }
259 }
260 }
261 #endif
262
263 #ifdef FEAT_GUI
264 /* timers are presented in GUI only */
265 # if defined(FEAT_GUI_W32)
266 static void CALLBACK
267 timer_proc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
268 # elif defined(FEAT_GUI_GTK)
269 /*ARGSUSED*/
270 static gint
271 timer_proc(gpointer data)
272 # elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)
273 /* ARGSUSED */
274 static void
275 timer_proc(XtPointer timed_out, XtIntervalId *interval_id)
276 # elif defined(FEAT_GUI_MAC)
277 pascal void
278 timer_proc(EventLoopTimerRef theTimer, void *userData)
279 # endif
280 {
281 scheme_check_threads();
282 # if defined(FEAT_GUI_GTK)
283 return TRUE; /* continue receiving notifications */
284 # elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)
285 /* renew timeout */
286 if (mz_threads_allow && p_mzq > 0)
287 timer_id = XtAppAddTimeOut(app_context, p_mzq,
288 timer_proc, NULL);
289 # endif
290 }
291
292 static void
293 setup_timer(void)
294 {
295 # if defined(FEAT_GUI_W32)
296 timer_id = SetTimer(NULL, 0, p_mzq, timer_proc);
297 # elif defined(FEAT_GUI_GTK)
298 timer_id = gtk_timeout_add((guint32)p_mzq, (GtkFunction)timer_proc, NULL);
299 # elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)
300 timer_id = XtAppAddTimeOut(app_context, p_mzq, timer_proc, NULL);
301 # elif defined(FEAT_GUI_MAC)
302 timerUPP = NewEventLoopTimerUPP(timer_proc);
303 InstallEventLoopTimer(GetMainEventLoop(), p_mzq * kEventDurationMillisecond,
304 p_mzq * kEventDurationMillisecond, timerUPP, NULL, &timer_id);
305 # endif
306 }
307
308 static void
309 remove_timer(void)
310 {
311 # if defined(FEAT_GUI_W32)
312 KillTimer(NULL, timer_id);
313 # elif defined(FEAT_GUI_GTK)
314 gtk_timeout_remove(timer_id);
315 # elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)
316 XtRemoveTimeOut(timer_id);
317 # elif defined(FEAT_GUI_MAC)
318 RemoveEventLoopTimer(timer_id);
319 DisposeEventLoopTimerUPP(timerUPP);
320 # endif
321 timer_id = 0;
322 }
323
324 void
325 mzvim_reset_timer(void)
326 {
327 if (timer_id != 0)
328 remove_timer();
329 if (mz_threads_allow && p_mzq > 0 && gui.in_use)
330 setup_timer();
331 }
332
333 #endif
334
335 static void
336 notify_multithread(int on)
337 {
338 mz_threads_allow = on;
339 #ifdef FEAT_GUI
340 if (on && timer_id == 0 && p_mzq > 0 && gui.in_use)
341 setup_timer();
342 if (!on && timer_id != 0)
343 remove_timer();
344 #endif
345 }
346
347 int
348 mzscheme_enabled(int verbose)
349 {
350 return initialized;
351 }
352
353 void
354 mzscheme_end(void)
355 {
356 }
357
358 static void
359 startup_mzscheme(void)
360 {
361 scheme_set_stack_base(NULL, 1);
362
363 MZ_REGISTER_STATIC(environment);
364 MZ_REGISTER_STATIC(curout);
365 MZ_REGISTER_STATIC(curerr);
366 MZ_REGISTER_STATIC(exn_catching_apply);
367 MZ_REGISTER_STATIC(exn_p);
368 MZ_REGISTER_STATIC(exn_message);
369 MZ_REGISTER_STATIC(vim_exn);
370 MZ_REGISTER_STATIC(vim_exn_names);
371 MZ_REGISTER_STATIC(vim_exn_values);
372
373 environment = scheme_basic_env();
374
375 /* redirect output */
376 scheme_console_output = do_output;
377 scheme_console_printf = do_printf;
378
379 #ifdef MZSCHEME_COLLECTS
380 /* setup 'current-library-collection-paths' parameter */
381 scheme_set_param(scheme_config, MZCONFIG_COLLECTION_PATHS,
382 scheme_make_pair(scheme_make_string(MZSCHEME_COLLECTS),
383 scheme_null));
384 #endif
385
386 /* Create buffer and window types for use in Scheme code */
387 mz_buffer_type = scheme_make_type("<vim-buffer>");
388 mz_window_type = scheme_make_type("<vim-window>");
389
390 register_vim_exn(environment);
391 make_modules(environment);
392
393 /*
394 * setup callback to receive notifications
395 * whether thread scheduling is (or not) required
396 */
397 scheme_notify_multithread = notify_multithread;
398 initialized = 1;
399 }
400
401 /*
402 * This routine is called for each new invocation of MzScheme
403 * to make sure things are properly initialized.
404 */
405 static int
406 mzscheme_init(void)
407 {
408 int do_require = FALSE;
409
410 if (!initialized)
411 {
412 do_require = TRUE;
413 startup_mzscheme();
414
415 if (mzscheme_io_init())
416 return -1;
417
418 }
419 /* recreate ports each call effectivelly clearing these ones */
420 curout = scheme_make_string_output_port();
421 curerr = scheme_make_string_output_port();
422 scheme_set_param(scheme_config, MZCONFIG_OUTPUT_PORT, curout);
423 scheme_set_param(scheme_config, MZCONFIG_ERROR_PORT, curerr);
424
425 if (do_require)
426 {
427 /* auto-instantiate in basic env */
428 eval_in_namespace("(require (prefix vimext: vimext))", do_eval,
429 environment, NULL);
430 }
431
432 return 0;
433 }
434
435 /*
436 * This routine fills the namespace with various important routines that can
437 * be used within MzScheme.
438 */
439 static void
440 mzscheme_interface_init(vim_mz_buffer *mzbuff)
441 {
442 Scheme_Object *attach;
443
444 mzbuff->env = (Scheme_Env *)scheme_make_namespace(0, NULL);
445
446 /*
447 * attach instantiated modules from global namespace
448 * so they can be easily instantiated in the buffer namespace
449 */
450 attach = scheme_lookup_global(
451 scheme_intern_symbol("namespace-attach-module"),
452 environment);
453
454 if (attach != NULL)
455 {
456 Scheme_Object *ret;
457 Scheme_Object *args[2];
458
459 args[0] = (Scheme_Object *)environment;
460 args[1] = scheme_intern_symbol("vimext");
461
462 ret = (Scheme_Object *)mzvim_apply(attach, 2, args);
463 }
464
465 add_vim_exn(mzbuff->env);
466 }
467
468 /*
469 *========================================================================
470 * 2. External Interface
471 *========================================================================
472 */
473
474 /*
475 * Evaluate command in namespace with exception handling
476 */
477 static int
478 eval_in_namespace(void *data, Scheme_Closed_Prim *what, Scheme_Env *env,
479 Scheme_Object **ret)
480 {
481 Scheme_Object *value;
482 Scheme_Object *exn;
483 Cmd_Info info; /* closure info */
484
485 info.data = data;
486 info.env = env;
487
488 scheme_set_param(scheme_config, MZCONFIG_ENV,
489 (Scheme_Object *) env);
490 /*
491 * ensure all evaluations will be in current buffer namespace,
492 * the second argument to scheme_eval_string isn't enough!
493 */
494 value = _apply_thunk_catch_exceptions(
495 scheme_make_closed_prim_w_arity(what, &info, "mzvim", 0, 0),
496 &exn);
497
498 if (!value)
499 {
500 value = extract_exn_message(exn);
501 /* Got an exn? */
502 if (value)
503 {
504 scheme_display(value, curerr); /* Send to stderr-vim */
505 do_flush();
506 }
507 /* `raise' was called on some arbitrary value */
508 return FAIL;
509 }
510
511 if (ret != NULL) /* if pointer to retval supported give it up */
512 *ret = value;
513 /* Print any result, as long as it's not a void */
514 else if (!SCHEME_VOIDP(value))
515 scheme_display(value, curout); /* Send to stdout-vim */
516
517 do_flush();
518 return OK;
519 }
520
521 /* :mzscheme */
522 static int
523 do_mzscheme_command(exarg_T *eap, void *data, Scheme_Closed_Prim *what)
524 {
525 if (mzscheme_init())
526 return FAIL;
527
528 range_start = eap->line1;
529 range_end = eap->line2;
530
531 return eval_in_namespace(data, what, get_vim_curr_buffer()->env, NULL);
532 }
533
534 /*
535 * Routine called by VIM when deleting a buffer
536 */
537 void
538 mzscheme_buffer_free(buf_T *buf)
539 {
540 if (buf->mzscheme_ref)
541 {
542 vim_mz_buffer *bp;
543 bp = buf->mzscheme_ref;
544 bp->buf = INVALID_BUFFER_VALUE;
545 buf->mzscheme_ref = NULL;
546 scheme_gc_ptr_ok(bp);
547 }
548 }
549
550 /*
551 * Routine called by VIM when deleting a Window
552 */
553 void
554 mzscheme_window_free(win_T *win)
555 {
556 if (win->mzscheme_ref)
557 {
558 vim_mz_window *wp;
559 wp = win->mzscheme_ref;
560 wp->win = INVALID_WINDOW_VALUE;
561 win->mzscheme_ref = NULL;
562 scheme_gc_ptr_ok(wp);
563 }
564 }
565
566 /*
567 * ":mzscheme" (or ":mz")
568 */
569 void
570 ex_mzscheme(exarg_T *eap)
571 {
572 char_u *script;
573
574 script = script_get(eap, eap->arg);
575 if (!eap->skip)
576 {
577 if (script == NULL)
578 do_mzscheme_command(eap, eap->arg, do_eval);
579 else
580 {
581 do_mzscheme_command(eap, script, do_eval);
582 vim_free(script);
583 }
584 }
585 }
586
587 /* eval MzScheme string */
588 void *
589 mzvim_eval_string(char_u *str)
590 {
591 Scheme_Object *ret = NULL;
592 if (mzscheme_init())
593 return FAIL;
594
595 eval_in_namespace(str, do_eval, get_vim_curr_buffer()->env, &ret);
596 return ret;
597 }
598
599 /*
600 * apply MzScheme procedure with arguments,
601 * handling errors
602 */
603 Scheme_Object *
604 mzvim_apply(Scheme_Object *proc, int argc, Scheme_Object **argv)
605 {
606 Apply_Info data;
607 Scheme_Object *ret = NULL;
608
609 if (mzscheme_init())
610 return FAIL;
611
612 data.proc = proc;
613 data.argc = argc;
614 data.argv = argv;
615
616 eval_in_namespace(&data, do_apply, get_vim_curr_buffer()->env, &ret);
617 return ret;
618 }
619
620 static Scheme_Object *
621 do_load(void *data, int noargc, Scheme_Object **noargv)
622 {
623 Cmd_Info *info = (Cmd_Info *)data;
624 Scheme_Object *result = scheme_void;
625 Scheme_Object *expr;
626 char_u *file = scheme_malloc_fail_ok(
627 scheme_malloc_atomic, MAXPATHL + 1);
628 Port_Info *pinfo = (Port_Info *)(info->data);
629
630 /* make Vim expansion */
631 expand_env((char_u *)pinfo->name, file, MAXPATHL);
632 /* scheme_load looks strange working with namespaces and error handling*/
633 pinfo->port = scheme_open_input_file(file, "mzfile");
634 scheme_count_lines(pinfo->port); /* to get accurate read error location*/
635
636 /* Like REPL but print only last result */
637 while (!SCHEME_EOFP(expr = scheme_read(pinfo->port)))
638 result = scheme_eval(expr, info->env);
639
640 /* errors will be caught in do_mzscheme_comamnd and ex_mzfile */
641 scheme_close_input_port(pinfo->port);
642 pinfo->port = NULL;
643 return result;
644 }
645
646 /* :mzfile */
647 void
648 ex_mzfile(exarg_T *eap)
649 {
650 Port_Info pinfo;
651
652 pinfo.name = (char *)eap->arg;
653 pinfo.port = NULL;
654 if (do_mzscheme_command(eap, &pinfo, do_load) != OK
655 && pinfo.port != NULL) /* looks like port was not closed */
656 scheme_close_input_port(pinfo.port);
657 }
658
659
660 /*
661 *========================================================================
662 * Exception handling code -- cribbed form the MzScheme sources and
663 * Matthew Flatt's "Inside PLT MzScheme" document.
664 *========================================================================
665 */
666 static void
667 init_exn_catching_apply(void)
668 {
669 if (!exn_catching_apply)
670 {
671 char *e =
672 "(lambda (thunk) "
673 "(with-handlers ([void (lambda (exn) (cons #f exn))]) "
674 "(cons #t (thunk))))";
675
676 /* make sure we have a namespace with the standard syntax: */
677 Scheme_Env *env = (Scheme_Env *)scheme_make_namespace(0, NULL);
678 add_vim_exn(env);
679
680 exn_catching_apply = scheme_eval_string(e, env);
681 exn_p = scheme_lookup_global(scheme_intern_symbol("exn?"), env);
682 exn_message = scheme_lookup_global(
683 scheme_intern_symbol("exn-message"), env);
684 }
685 }
686
687 /*
688 * This function applies a thunk, returning the Scheme value if there's
689 * no exception, otherwise returning NULL and setting *exn to the raised
690 * value (usually an exn structure).
691 */
692 static Scheme_Object *
693 _apply_thunk_catch_exceptions(Scheme_Object *f, Scheme_Object **exn)
694 {
695 Scheme_Object *v;
696
697 init_exn_catching_apply();
698
699 v = _scheme_apply(exn_catching_apply, 1, &f);
700 /* v is a pair: (cons #t value) or (cons #f exn) */
701
702 if (SCHEME_TRUEP(SCHEME_CAR(v)))
703 return SCHEME_CDR(v);
704 else
705 {
706 *exn = SCHEME_CDR(v);
707 return NULL;
708 }
709 }
710
711 static Scheme_Object *
712 extract_exn_message(Scheme_Object *v)
713 {
714 init_exn_catching_apply();
715
716 if (SCHEME_TRUEP(_scheme_apply(exn_p, 1, &v)))
717 return _scheme_apply(exn_message, 1, &v);
718 else
719 return NULL; /* Not an exn structure */
720 }
721
722 static Scheme_Object *
723 do_eval(void *s, int noargc, Scheme_Object **noargv)
724 {
725 Cmd_Info *info = (Cmd_Info *)s;
726
727 return scheme_eval_string_all((char *)(info->data), info->env, TRUE);
728 }
729
730 static Scheme_Object *
731 do_apply(void *a, int noargc, Scheme_Object **noargv)
732 {
733 Apply_Info *info = (Apply_Info *)(((Cmd_Info *)a)->data);
734
735 return scheme_apply(info->proc, info->argc, info->argv);
736 }
737
738 /*
739 *========================================================================
740 * 3. MzScheme I/O Handlers
741 *========================================================================
742 */
743 static void
744 do_intrnl_output(char *mesg, long len, int error)
745 {
746 char *p, *prev;
747
748 prev = mesg;
749 p = strchr(prev, '\n');
750 while (p)
751 {
752 *p = '\0';
753 if (error)
754 EMSG(prev);
755 else
756 MSG(prev);
757 prev = p + 1;
758 p = strchr(prev, '\n');
759 }
760
761 if (error)
762 EMSG(prev);
763 else
764 MSG(prev);
765 }
766
767 static void
768 do_output(char *mesg, long len)
769 {
770 do_intrnl_output(mesg, len, 0);
771 }
772
773 static void
774 do_err_output(char *mesg, long len)
775 {
776 do_intrnl_output(mesg, len, 1);
777 }
778
779 static void
780 do_printf(char *format, ...)
781 {
782 do_intrnl_output(format, STRLEN(format), 1);
783 }
784
785 static void
786 do_flush(void)
787 {
788 char *buff;
789 long length;
790
791 buff = scheme_get_sized_string_output(curerr, &length);
792 if (length)
793 {
794 do_err_output(buff, length);
795 return;
796 }
797
798 buff = scheme_get_sized_string_output(curout, &length);
799 if (length)
800 do_output(buff, length);
801 }
802
803 static int
804 mzscheme_io_init(void)
805 {
806 /* Nothing needed so far... */
807 return 0;
808 }
809
810 /*
811 *========================================================================
812 * 4. Implementation of the Vim Features for MzScheme
813 *========================================================================
814 */
815
816 /* (command {command-string}) */
817 static Scheme_Object *
818 vim_command(void *data, int argc, Scheme_Object **argv)
819 {
820 Vim_Prim *prim = (Vim_Prim *)data;
821 char *cmd = SCHEME_STR_VAL(GUARANTEE_STRING(prim->name, 0));
822
823 /* may be use do_cmdline_cmd? */
824 do_cmdline((char_u *)cmd, NULL, NULL, DOCMD_NOWAIT|DOCMD_VERBOSE);
825 update_screen(VALID);
826
827 raise_if_error();
828 return scheme_void;
829 }
830
831 /* (eval {expr-string}) */
832 static Scheme_Object *
833 vim_eval(void *data, int argc, Scheme_Object **argv)
834 {
835 #ifdef FEAT_EVAL
836 Vim_Prim *prim = (Vim_Prim *)data;
837 char *expr;
838 char *str;
839 Scheme_Object *result;
840
841 expr = SCHEME_STR_VAL(GUARANTEE_STRING(prim->name, 0));
842
843 str = (char *)eval_to_string((char_u *)expr, NULL);
844
845 if (str == NULL)
846 raise_vim_exn(_("invalid expression"));
847
848 result = scheme_make_string(str);
849
850 vim_free(str);
851
852 return result;
853 #else
854 raise_vim_exn(_("expressions disabled at compile time"));
855 /* unreachable */
856 return scheme_false;
857 #endif
858 }
859
860 /* (range-start) */
861 static Scheme_Object *
862 get_range_start(void *data, int argc, Scheme_Object **argv)
863 {
864 return scheme_make_integer(range_start);
865 }
866
867 /* (range-end) */
868 static Scheme_Object *
869 get_range_end(void *data, int argc, Scheme_Object **argv)
870 {
871 return scheme_make_integer(range_end);
872 }
873
874 /* (beep) */
875 static Scheme_Object *
876 mzscheme_beep(void *data, int argc, Scheme_Object **argv)
877 {
878 vim_beep();
879 return scheme_void;
880 }
881
882 static Scheme_Object *M_global = NULL;
883
884 /* (get-option {option-name}) [buffer/window] */
885 static Scheme_Object *
886 get_option(void *data, int argc, Scheme_Object **argv)
887 {
888 Vim_Prim *prim = (Vim_Prim *)data;
889 char_u *name;
890 long value;
891 char_u *strval;
892 int rc;
893 Scheme_Object *rval;
894 int opt_flags = 0;
895 buf_T *save_curb = curbuf;
896 win_T *save_curw = curwin;
897
898 name = (char_u *)SCHEME_STR_VAL(GUARANTEE_STRING(prim->name, 0));
899
900 if (argc > 1)
901 {
902 if (M_global == NULL)
903 {
904 MZ_REGISTER_STATIC(M_global);
905 M_global = scheme_intern_symbol("global");
906 }
907
908 if (argv[1] == M_global)
909 opt_flags = OPT_GLOBAL;
910 else if (SCHEME_VIMBUFFERP(argv[1]))
911 {
912 curbuf = get_valid_buffer(argv[1]);
913 opt_flags = OPT_LOCAL;
914 }
915 else if (SCHEME_VIMWINDOWP(argv[1]))
916 {
917 win_T *win = get_valid_window(argv[1]);
918
919 curwin = win;
920 curbuf = win->w_buffer;
921 opt_flags = OPT_LOCAL;
922 }
923 else
924 scheme_wrong_type(prim->name, "vim-buffer/window", 1, argc, argv);
925 }
926
927 rc = get_option_value(name, &value, &strval, opt_flags);
928 curbuf = save_curb;
929 curwin = save_curw;
930
931 switch (rc)
932 {
933 case 1:
934 return scheme_make_integer_value(value);
935 case 0:
936 rval = scheme_make_string(strval);
937 vim_free(strval);
938 return rval;
939 case -1:
940 case -2:
941 raise_vim_exn(_("hidden option"));
942 case -3:
943 raise_vim_exn(_("unknown option"));
944 }
945 /* unreachable */
946 return scheme_void;
947 }
948
949 /* (set-option {option-changing-string} [buffer/window]) */
950 static Scheme_Object *
951 set_option(void *data, int argc, Scheme_Object **argv)
952 {
953 char_u *cmd;
954 int opt_flags = 0;
955 buf_T *save_curb = curbuf;
956 win_T *save_curw = curwin;
957 Vim_Prim *prim = (Vim_Prim *)data;
958
959 GUARANTEE_STRING(prim->name, 0);
960 if (argc > 1)
961 {
962 if (M_global == NULL)
963 {
964 MZ_REGISTER_STATIC(M_global);
965 M_global = scheme_intern_symbol("global");
966 }
967
968 if (argv[1] == M_global)
969 opt_flags = OPT_GLOBAL;
970 else if (SCHEME_VIMBUFFERP(argv[1]))
971 {
972 curbuf = get_valid_buffer(argv[1]);
973 opt_flags = OPT_LOCAL;
974 }
975 else if (SCHEME_VIMWINDOWP(argv[1]))
976 {
977 win_T *win = get_valid_window(argv[1]);
978 curwin = win;
979 curbuf = win->w_buffer;
980 opt_flags = OPT_LOCAL;
981 }
982 else
983 scheme_wrong_type(prim->name, "vim-buffer/window", 1, argc, argv);
984 }
985
986 /* do_set can modify cmd, make copy */
987 cmd = vim_strsave((char_u *)SCHEME_STR_VAL(argv[0]));
988 do_set(cmd, opt_flags);
989 vim_free(cmd);
990 update_screen(NOT_VALID);
991 curbuf = save_curb;
992 curwin = save_curw;
993 raise_if_error();
994 return scheme_void;
995 }
996
997 /*
998 *===========================================================================
999 * 5. Vim Window-related Manipulation Functions
1000 *===========================================================================
1001 */
1002
1003 /* (curr-win) */
1004 static Scheme_Object *
1005 get_curr_win(void *data, int argc, Scheme_Object **argv)
1006 {
1007 return (Scheme_Object *)get_vim_curr_window();
1008 }
1009
1010 /* (win-count) */
1011 static Scheme_Object *
1012 get_window_count(void *data, int argc, Scheme_Object **argv)
1013 {
1014 win_T *w;
1015 int n = 0;
1016
1017 for (w = firstwin; w; w = w->w_next) ++n;
1018 return scheme_make_integer(n);
1019 }
1020
1021 /* (get-win-list [buffer]) */
1022 static Scheme_Object *
1023 get_window_list(void *data, int argc, Scheme_Object **argv)
1024 {
1025 Vim_Prim *prim = (Vim_Prim *)data;
1026 vim_mz_buffer *buf;
1027 Scheme_Object *list;
1028 win_T *w;
1029
1030 buf = get_buffer_arg(prim->name, 0, argc, argv);
1031 list = scheme_null;
1032
1033 for (w = firstwin; w; w = w->w_next)
1034 if (w->w_buffer == buf->buf)
1035 list = scheme_make_pair(window_new(w), list);
1036
1037 return list;
1038 }
1039
1040 static Scheme_Object *
1041 window_new(win_T *win)
1042 {
1043 vim_mz_window *self;
1044
1045 /* We need to handle deletion of windows underneath us.
1046 * If we add a "mzscheme_ref" field to the win_T structure,
1047 * then we can get at it in win_free() in vim.
1048 *
1049 * On a win_free() we set the Scheme object's win_T *field
1050 * to an invalid value. We trap all uses of a window
1051 * object, and reject them if the win_T *field is invalid.
1052 */
1053 if (win->mzscheme_ref)
1054 return win->mzscheme_ref;
1055
1056 self = scheme_malloc_fail_ok(scheme_malloc, sizeof(vim_mz_window));
1057
1058 vim_memset(self, 0, sizeof(vim_mz_window));
1059 scheme_dont_gc_ptr(self); /* because win isn't visible to GC */
1060 win->mzscheme_ref = self;
1061 self->win = win;
1062 self->tag = mz_window_type;
1063
1064 return (Scheme_Object *)(self);
1065 }
1066
1067 /* (get-win-num [window]) */
1068 static Scheme_Object *
1069 get_window_num(void *data, int argc, Scheme_Object **argv)
1070 {
1071 Vim_Prim *prim = (Vim_Prim *)data;
1072 win_T *win = get_window_arg(prim->name, 0, argc, argv)->win;
1073 int nr = 1;
1074 win_T *wp;
1075
1076 for (wp = firstwin; wp != win; wp = wp->w_next)
1077 ++nr;
1078
1079 return scheme_make_integer(nr);
1080 }
1081
1082 /* (get-win-by-num {windownum}) */
1083 static Scheme_Object *
1084 get_window_by_num(void *data, int argc, Scheme_Object **argv)
1085 {
1086 Vim_Prim *prim = (Vim_Prim *)data;
1087 win_T *win;
1088 int fnum;
1089
1090 fnum = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
1091 if (fnum < 1)
1092 scheme_signal_error(_("window index is out of range"));
1093
1094 for (win = firstwin; win; win = win->w_next, --fnum)
1095 if (fnum == 1) /* to be 1-based */
1096 return window_new(win);
1097
1098 return scheme_false;
1099 }
1100
1101 /* (get-win-buffer [window]) */
1102 static Scheme_Object *
1103 get_window_buffer(void *data, int argc, Scheme_Object **argv)
1104 {
1105 Vim_Prim *prim = (Vim_Prim *)data;
1106 vim_mz_window *win = get_window_arg(prim->name, 0, argc, argv);
1107
1108 return buffer_new(win->win->w_buffer);
1109 }
1110
1111 /* (get-win-height [window]) */
1112 static Scheme_Object *
1113 get_window_height(void *data, int argc, Scheme_Object **argv)
1114 {
1115 Vim_Prim *prim = (Vim_Prim *)data;
1116 vim_mz_window *win = get_window_arg(prim->name, 0, argc, argv);
1117
1118 return scheme_make_integer(win->win->w_height);
1119 }
1120
1121 /* (set-win-height {height} [window]) */
1122 static Scheme_Object *
1123 set_window_height(void *data, int argc, Scheme_Object **argv)
1124 {
1125 Vim_Prim *prim = (Vim_Prim *)data;
1126 vim_mz_window *win;
1127 win_T *savewin;
1128 int height;
1129
1130 win = get_window_arg(prim->name, 1, argc, argv);
1131 height = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
1132
1133 #ifdef FEAT_GUI
1134 need_mouse_correct = TRUE;
1135 #endif
1136
1137 savewin = curwin;
1138 curwin = win->win;
1139 win_setheight(height);
1140 curwin = savewin;
1141
1142 raise_if_error();
1143 return scheme_void;
1144 }
1145
1146 #ifdef FEAT_VERTSPLIT
1147 /* (get-win-width [window]) */
1148 static Scheme_Object *
1149 get_window_width(void *data, int argc, Scheme_Object **argv)
1150 {
1151 Vim_Prim *prim = (Vim_Prim *)data;
1152 vim_mz_window *win = get_window_arg(prim->name, 0, argc, argv);
1153
1154 return scheme_make_integer(W_WIDTH(win->win));
1155 }
1156
1157 /* (set-win-width {width} [window]) */
1158 static Scheme_Object *
1159 set_window_width(void *data, int argc, Scheme_Object **argv)
1160 {
1161 Vim_Prim *prim = (Vim_Prim *)data;
1162 vim_mz_window *win;
1163 win_T *savewin;
1164 int width = 0;
1165
1166 win = get_window_arg(prim->name, 1, argc, argv);
1167 width = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
1168
1169 # ifdef FEAT_GUI
1170 need_mouse_correct = TRUE;
1171 # endif
1172
1173 savewin = curwin;
1174 curwin = win->win;
1175 win_setwidth(width);
1176 curwin = savewin;
1177
1178 raise_if_error();
1179 return scheme_void;
1180 }
1181 #endif
1182
1183 /* (get-cursor [window]) -> (line . col) */
1184 static Scheme_Object *
1185 get_cursor(void *data, int argc, Scheme_Object **argv)
1186 {
1187 Vim_Prim *prim = (Vim_Prim *)data;
1188 vim_mz_window *win;
1189 pos_T pos;
1190
1191 win = get_window_arg(prim->name, 0, argc, argv);
1192 pos = win->win->w_cursor;
1193 return scheme_make_pair(scheme_make_integer_value((long)pos.lnum),
1194 scheme_make_integer_value((long)pos.col + 1));
1195 }
1196
1197 /* (set-cursor (line . col) [window]) */
1198 static Scheme_Object *
1199 set_cursor(void *data, int argc, Scheme_Object **argv)
1200 {
1201 Vim_Prim *prim = (Vim_Prim *)data;
1202 vim_mz_window *win;
1203 long lnum = 0;
1204 long col = 0;
1205
1206 win = get_window_arg(prim->name, 1, argc, argv);
1207 GUARANTEE_PAIR(prim->name, 0);
1208
1209 if (!SCHEME_INTP(SCHEME_CAR(argv[0]))
1210 || !SCHEME_INTP(SCHEME_CDR(argv[0])))
1211 scheme_wrong_type(prim->name, "integer pair", 0, argc, argv);
1212
1213 lnum = SCHEME_INT_VAL(SCHEME_CAR(argv[0]));
1214 col = SCHEME_INT_VAL(SCHEME_CDR(argv[0])) - 1;
1215
1216 check_line_range(lnum, win->win->w_buffer);
1217 /* don't know how to catch invalid column value */
1218
1219 win->win->w_cursor.lnum = lnum;
1220 win->win->w_cursor.col = col;
1221 update_screen(VALID);
1222
1223 raise_if_error();
1224 return scheme_void;
1225 }
1226 /*
1227 *===========================================================================
1228 * 6. Vim Buffer-related Manipulation Functions
1229 * Note that each buffer should have its own private namespace.
1230 *===========================================================================
1231 */
1232
1233 /* (open-buff {filename}) */
1234 static Scheme_Object *
1235 mzscheme_open_buffer(void *data, int argc, Scheme_Object **argv)
1236 {
1237 Vim_Prim *prim = (Vim_Prim *)data;
1238 char *fname;
1239 int num = 0;
1240 Scheme_Object *onum;
1241
1242 fname = SCHEME_STR_VAL(GUARANTEE_STRING(prim->name, 0));
1243 /* TODO make open existing file */
1244 num = buflist_add(fname, BLN_LISTED | BLN_CURBUF);
1245
1246 if (num == 0)
1247 raise_vim_exn(_("couldn't open buffer"));
1248
1249 onum = scheme_make_integer(num);
1250 return get_buffer_by_num(data, 1, &onum);
1251 }
1252
1253 /* (get-buff-by-num {buffernum}) */
1254 static Scheme_Object *
1255 get_buffer_by_num(void *data, int argc, Scheme_Object **argv)
1256 {
1257 Vim_Prim *prim = (Vim_Prim *)data;
1258 buf_T *buf;
1259 int fnum;
1260
1261 fnum = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
1262
1263 for (buf = firstbuf; buf; buf = buf->b_next)
1264 if (buf->b_fnum == fnum)
1265 return buffer_new(buf);
1266
1267 return scheme_false;
1268 }
1269
1270 /* (get-buff-by-name {buffername}) */
1271 static Scheme_Object *
1272 get_buffer_by_name(void *data, int argc, Scheme_Object **argv)
1273 {
1274 Vim_Prim *prim = (Vim_Prim *)data;
1275 buf_T *buf;
1276 char_u *fname;
1277
1278 fname = SCHEME_STR_VAL(GUARANTEE_STRING(prim->name, 0));
1279
1280 for (buf = firstbuf; buf; buf = buf->b_next)
1281 if (buf->b_ffname == NULL || buf->b_sfname == NULL)
1282 /* empty string */
1283 {
1284 if (fname[0] == NUL)
1285 return buffer_new(buf);
1286 }
1287 else if (!fnamecmp(buf->b_ffname, fname)
1288 || !fnamecmp(buf->b_sfname, fname))
1289 /* either short or long filename matches */
1290 return buffer_new(buf);
1291
1292 return scheme_false;
1293 }
1294
1295 /* (get-next-buff [buffer]) */
1296 static Scheme_Object *
1297 get_next_buffer(void *data, int argc, Scheme_Object **argv)
1298 {
1299 Vim_Prim *prim = (Vim_Prim *)data;
1300 buf_T *buf = get_buffer_arg(prim->name, 0, argc, argv)->buf;
1301
1302 if (buf->b_next == NULL)
1303 return scheme_false;
1304 else
1305 return buffer_new(buf->b_next);
1306 }
1307
1308 /* (get-prev-buff [buffer]) */
1309 static Scheme_Object *
1310 get_prev_buffer(void *data, int argc, Scheme_Object **argv)
1311 {
1312 Vim_Prim *prim = (Vim_Prim *)data;
1313 buf_T *buf = get_buffer_arg(prim->name, 0, argc, argv)->buf;
1314
1315 if (buf->b_prev == NULL)
1316 return scheme_false;
1317 else
1318 return buffer_new(buf->b_prev);
1319 }
1320
1321 /* (get-buff-num [buffer]) */
1322 static Scheme_Object *
1323 get_buffer_num(void *data, int argc, Scheme_Object **argv)
1324 {
1325 Vim_Prim *prim = (Vim_Prim *)data;
1326 vim_mz_buffer *buf = get_buffer_arg(prim->name, 0, argc, argv);
1327
1328 return scheme_make_integer(buf->buf->b_fnum);
1329 }
1330
1331 /* (buff-count) */
1332 static Scheme_Object *
1333 get_buffer_count(void *data, int argc, Scheme_Object **argv)
1334 {
1335 buf_T *b;
1336 int n = 0;
1337
1338 for (b = firstbuf; b; b = b->b_next) ++n;
1339 return scheme_make_integer(n);
1340 }
1341
1342 /* (get-buff-name [buffer]) */
1343 static Scheme_Object *
1344 get_buffer_name(void *data, int argc, Scheme_Object **argv)
1345 {
1346 Vim_Prim *prim = (Vim_Prim *)data;
1347 vim_mz_buffer *buf = get_buffer_arg(prim->name, 0, argc, argv);
1348
1349 return scheme_make_string(buf->buf->b_ffname);
1350 }
1351
1352 /* (curr-buff) */
1353 static Scheme_Object *
1354 get_curr_buffer(void *data, int argc, Scheme_Object **argv)
1355 {
1356 return (Scheme_Object *)get_vim_curr_buffer();
1357 }
1358
1359 static Scheme_Object *
1360 buffer_new(buf_T *buf)
1361 {
1362 vim_mz_buffer *self;
1363
1364 /* We need to handle deletion of buffers underneath us.
1365 * If we add a "mzscheme_buf" field to the buf_T structure,
1366 * then we can get at it in buf_freeall() in vim.
1367 */
1368 if (buf->mzscheme_ref)
1369 return buf->mzscheme_ref;
1370
1371 self = scheme_malloc_fail_ok(scheme_malloc, sizeof(vim_mz_buffer));
1372
1373 vim_memset(self, 0, sizeof(vim_mz_buffer));
1374 scheme_dont_gc_ptr(self); /* because buf isn't visible to GC */
1375 buf->mzscheme_ref = self;
1376 self->buf = buf;
1377 self->tag = mz_buffer_type;
1378
1379 mzscheme_interface_init(self); /* Set up namespace */
1380
1381 return (Scheme_Object *)(self);
1382 }
1383
1384 /*
1385 * (get-buff-size [buffer])
1386 *
1387 * Get the size (number of lines) in the current buffer.
1388 */
1389 static Scheme_Object *
1390 get_buffer_size(void *data, int argc, Scheme_Object **argv)
1391 {
1392 Vim_Prim *prim = (Vim_Prim *)data;
1393 vim_mz_buffer *buf = get_buffer_arg(prim->name, 0, argc, argv);
1394
1395 return scheme_make_integer(buf->buf->b_ml.ml_line_count);
1396 }
1397
1398 /*
1399 * (get-buff-line {linenr} [buffer])
1400 *
1401 * Get a line from the specified buffer. The line number is
1402 * in Vim format (1-based). The line is returned as a MzScheme
1403 * string object.
1404 */
1405 static Scheme_Object *
1406 get_buffer_line(void *data, int argc, Scheme_Object **argv)
1407 {
1408 Vim_Prim *prim = (Vim_Prim *)data;
1409 vim_mz_buffer *buf;
1410 int linenr;
1411 char *line;
1412
1413 buf = get_buffer_arg(prim->name, 1, argc, argv);
1414 linenr = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
1415 line = ml_get_buf(buf->buf, (linenr_T)linenr, FALSE);
1416
1417 raise_if_error();
1418 return scheme_make_string(line);
1419 }
1420
1421
1422 /*
1423 * (get-buff-line-list {start} {end} [buffer])
1424 *
1425 * Get a list of lines from the specified buffer. The line numbers
1426 * are in Vim format (1-based). The range is from lo up to, but not
1427 * including, hi. The list is returned as a list of string objects.
1428 */
1429 static Scheme_Object *
1430 get_buffer_line_list(void *data, int argc, Scheme_Object **argv)
1431 {
1432 Vim_Prim *prim = (Vim_Prim *)data;
1433 vim_mz_buffer *buf;
1434 int i, hi, lo, n;
1435 Scheme_Object *list;
1436
1437 buf = get_buffer_arg(prim->name, 2, argc, argv);
1438 list = scheme_null;
1439 hi = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 1));
1440 lo = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
1441
1442 /*
1443 * Handle some error conditions
1444 */
1445 if (lo < 0)
1446 lo = 0;
1447
1448 if (hi < 0)
1449 hi = 0;
1450 if (hi < lo)
1451 hi = lo;
1452
1453 n = hi - lo;
1454
1455 for (i = n; i >= 0; --i)
1456 {
1457 Scheme_Object *str = scheme_make_string(
1458 (char *)ml_get_buf(buf->buf, (linenr_T)(lo+i), FALSE));
1459 raise_if_error();
1460
1461 /* Set the list item */
1462 list = scheme_make_pair(str, list);
1463 }
1464
1465 return list;
1466 }
1467
1468 /*
1469 * (set-buff-line {linenr} {string/#f} [buffer])
1470 *
1471 * Replace a line in the specified buffer. The line number is
1472 * in Vim format (1-based). The replacement line is given as
1473 * an MzScheme string object. The object is checked for validity
1474 * and correct format. An exception is thrown if the values are not
1475 * the correct format.
1476 *
1477 * It returns a Scheme Object that indicates the length of the
1478 * string changed.
1479 */
1480 static Scheme_Object *
1481 set_buffer_line(void *data, int argc, Scheme_Object **argv)
1482 {
1483 /* First of all, we check the the of the supplied MzScheme object.
1484 * There are three cases:
1485 * 1. #f - this is a deletion.
1486 * 2. A string - this is a replacement.
1487 * 3. Anything else - this is an error.
1488 */
1489 Vim_Prim *prim = (Vim_Prim *)data;
1490 vim_mz_buffer *buf;
1491 Scheme_Object *line;
1492 char *save;
1493 buf_T *savebuf;
1494 int n;
1495
1496 n = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
1497 if (!SCHEME_STRINGP(argv[1]) && !SCHEME_FALSEP(argv[1]))
1498 scheme_wrong_type(prim->name, "string or #f", 1, argc, argv);
1499 line = argv[1];
1500 buf = get_buffer_arg(prim->name, 2, argc, argv);
1501
1502 check_line_range(n, buf->buf);
1503
1504 if (SCHEME_FALSEP(line))
1505 {
1506 savebuf = curbuf;
1507 curbuf = buf->buf;
1508
1509 if (u_savedel((linenr_T)n, 1L) == FAIL)
1510 {
1511 curbuf = savebuf;
1512 raise_vim_exn(_("cannot save undo information"));
1513 }
1514 else if (ml_delete((linenr_T)n, FALSE) == FAIL)
1515 {
1516 curbuf = savebuf;
1517 raise_vim_exn(_("cannot delete line"));
1518 }
1519 deleted_lines_mark((linenr_T)n, 1L);
1520 if (buf->buf == curwin->w_buffer)
1521 mz_fix_cursor(n, n + 1, -1);
1522
1523 curbuf = savebuf;
1524
1525 raise_if_error();
1526 return scheme_void;
1527 }
1528
1529 /* Otherwise it's a line */
1530 save = string_to_line(line);
1531 savebuf = curbuf;
1532
1533 curbuf = buf->buf;
1534
1535 if (u_savesub((linenr_T)n) == FAIL)
1536 {
1537 curbuf = savebuf;
1538 raise_vim_exn(_("cannot save undo information"));
1539 }
1540 else if (ml_replace((linenr_T)n, (char_u *)save, TRUE) == FAIL)
1541 {
1542 curbuf = savebuf;
1543 raise_vim_exn(_("cannot replace line"));
1544 }
1545 else
1546 changed_bytes((linenr_T)n, 0);
1547
1548 curbuf = savebuf;
1549
1550 raise_if_error();
1551 return scheme_void;
1552 }
1553
1554 /*
1555 * (set-buff-line-list {start} {end} {string-list/#f/null} [buffer])
1556 *
1557 * Replace a range of lines in the specified buffer. The line numbers are in
1558 * Vim format (1-based). The range is from lo up to, but not including, hi.
1559 * The replacement lines are given as a Scheme list of string objects. The
1560 * list is checked for validity and correct format.
1561 *
1562 * Errors are returned as a value of FAIL. The return value is OK on success.
1563 * If OK is returned and len_change is not NULL, *len_change is set to the
1564 * change in the buffer length.
1565 */
1566 static Scheme_Object *
1567 set_buffer_line_list(void *data, int argc, Scheme_Object **argv)
1568 {
1569 /* First of all, we check the type of the supplied MzScheme object.
1570 * There are three cases:
1571 * 1. #f - this is a deletion.
1572 * 2. A list - this is a replacement.
1573 * 3. Anything else - this is an error.
1574 */
1575 Vim_Prim *prim = (Vim_Prim *)data;
1576 vim_mz_buffer *buf;
1577 Scheme_Object *line_list;
1578 Scheme_Object *line;
1579 Scheme_Object *rest;
1580 char **array;
1581 buf_T *savebuf;
1582 int i, old_len, new_len, hi, lo;
1583 long extra;
1584
1585 lo = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
1586 hi = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 1));
1587 if (!SCHEME_PAIRP(argv[2])
1588 && !SCHEME_FALSEP(argv[2]) && !SCHEME_NULLP(argv[2]))
1589 scheme_wrong_type(prim->name, "list or #f", 2, argc, argv);
1590 line_list = argv[2];
1591 buf = get_buffer_arg(prim->name, 3, argc, argv);
1592 old_len = hi - lo;
1593 if (old_len < 0) /* process inverse values wisely */
1594 {
1595 i = lo;
1596 lo = hi;
1597 hi = i;
1598 old_len = -old_len;
1599 }
1600 extra = 0;
1601
1602 check_line_range(lo, buf->buf); /* inclusive */
1603 check_line_range(hi - 1, buf->buf); /* exclisive */
1604
1605 if (SCHEME_FALSEP(line_list) || SCHEME_NULLP(line_list))
1606 {
1607 savebuf = curbuf;
1608 curbuf = buf->buf;
1609
1610 if (u_savedel((linenr_T)lo, (long)old_len) == FAIL)
1611 {
1612 curbuf = savebuf;
1613 raise_vim_exn(_("cannot save undo information"));
1614 }
1615 else
1616 {
1617 for (i = 0; i < old_len; i++)
1618 if (ml_delete((linenr_T)lo, FALSE) == FAIL)
1619 {
1620 curbuf = savebuf;
1621 raise_vim_exn(_("cannot delete line"));
1622 }
1623 deleted_lines_mark((linenr_T)lo, (long)old_len);
1624 if (buf->buf == curwin->w_buffer)
1625 mz_fix_cursor(lo, hi, -old_len);
1626 }
1627
1628 curbuf = savebuf;
1629
1630 raise_if_error();
1631 return scheme_void;
1632 }
1633
1634 /* List */
1635 new_len = scheme_proper_list_length(line_list);
1636 if (new_len < 0) /* improper or cyclic list */
1637 scheme_wrong_type(prim->name, "proper list",
1638 2, argc, argv);
1639
1640 /* Using MzScheme allocator, so we don't need to free this and
1641 * can safely keep pointers to GC collected strings
1642 */
1643 array = (char **)scheme_malloc_fail_ok(scheme_malloc,
1644 (unsigned)(new_len * sizeof(char *)));
1645
1646 rest = line_list;
1647 for (i = 0; i < new_len; ++i)
1648 {
1649 line = SCHEME_CAR(rest);
1650 rest = SCHEME_CDR(rest);
1651 if (!SCHEME_STRINGP(line))
1652 scheme_wrong_type(prim->name, "string-list", 2, argc, argv);
1653 array[i] = string_to_line(line);
1654 }
1655
1656 savebuf = curbuf;
1657 curbuf = buf->buf;
1658
1659 if (u_save((linenr_T)(lo-1), (linenr_T)hi) == FAIL)
1660 {
1661 curbuf = savebuf;
1662 raise_vim_exn(_("cannot save undo information"));
1663 }
1664
1665 /*
1666 * If the size of the range is reducing (ie, new_len < old_len) we
1667 * need to delete some old_len. We do this at the start, by
1668 * repeatedly deleting line "lo".
1669 */
1670 for (i = 0; i < old_len - new_len; ++i)
1671 {
1672 if (ml_delete((linenr_T)lo, FALSE) == FAIL)
1673 {
1674 curbuf = savebuf;
1675 raise_vim_exn(_("cannot delete line"));
1676 }
1677 extra--;
1678 }
1679
1680 /*
1681 * For as long as possible, replace the existing old_len with the
1682 * new old_len. This is a more efficient operation, as it requires
1683 * less memory allocation and freeing.
1684 */
1685 for (i = 0; i < old_len && i < new_len; i++)
1686 if (ml_replace((linenr_T)(lo+i), (char_u *)array[i], TRUE) == FAIL)
1687 {
1688 curbuf = savebuf;
1689 raise_vim_exn(_("cannot replace line"));
1690 }
1691
1692 /*
1693 * Now we may need to insert the remaining new_len. We don't need to
1694 * free the string passed back because MzScheme has control of that
1695 * memory.
1696 */
1697 while (i < new_len)
1698 {
1699 if (ml_append((linenr_T)(lo + i - 1),
1700 (char_u *)array[i], 0, FALSE) == FAIL)
1701 {
1702 curbuf = savebuf;
1703 raise_vim_exn(_("cannot insert line"));
1704 }
1705 ++i;
1706 ++extra;
1707 }
1708
1709 /*
1710 * Adjust marks. Invalidate any which lie in the
1711 * changed range, and move any in the remainder of the buffer.
1712 */
1713 mark_adjust((linenr_T)lo, (linenr_T)(hi - 1), (long)MAXLNUM, (long)extra);
1714 changed_lines((linenr_T)lo, 0, (linenr_T)hi, (long)extra);
1715
1716 if (buf->buf == curwin->w_buffer)
1717 mz_fix_cursor(lo, hi, extra);
1718 curbuf = savebuf;
1719
1720 raise_if_error();
1721 return scheme_void;
1722 }
1723
1724 /*
1725 * (insert-buff-line-list {linenr} {string/string-list} [buffer])
1726 *
1727 * Insert a number of lines into the specified buffer after the specifed line.
1728 * The line number is in Vim format (1-based). The lines to be inserted are
1729 * given as an MzScheme list of string objects or as a single string. The lines
1730 * to be added are checked for validity and correct format. Errors are
1731 * returned as a value of FAIL. The return value is OK on success.
1732 * If OK is returned and len_change is not NULL, *len_change
1733 * is set to the change in the buffer length.
1734 */
1735 static Scheme_Object *
1736 insert_buffer_line_list(void *data, int argc, Scheme_Object **argv)
1737 {
1738 Vim_Prim *prim = (Vim_Prim *)data;
1739 vim_mz_buffer *buf;
1740 Scheme_Object *list;
1741 Scheme_Object *line;
1742 Scheme_Object *rest;
1743 char **array;
1744 char *str;
1745 buf_T *savebuf;
1746 int i, n, size;
1747
1748 /*
1749 * First of all, we check the type of the supplied MzScheme object.
1750 * It must be a string or a list, or the call is in error.
1751 */
1752 n = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
1753 list = argv[1];
1754
1755 if (!SCHEME_STRINGP(list) && !SCHEME_PAIRP(list))
1756 scheme_wrong_type(prim->name, "string or list", 1, argc, argv);
1757 buf = get_buffer_arg(prim->name, 2, argc, argv);
1758
1759 if (n != 0) /* 0 can be used in insert */
1760 check_line_range(n, buf->buf);
1761 if (SCHEME_STRINGP(list))
1762 {
1763 str = string_to_line(list);
1764
1765 savebuf = curbuf;
1766 curbuf = buf->buf;
1767
1768 if (u_save((linenr_T)n, (linenr_T)(n+1)) == FAIL)
1769 {
1770 curbuf = savebuf;
1771 raise_vim_exn(_("cannot save undo information"));
1772 }
1773 else if (ml_append((linenr_T)n, (char_u *)str, 0, FALSE) == FAIL)
1774 {
1775 curbuf = savebuf;
1776 raise_vim_exn(_("cannot insert line"));
1777 }
1778 else
1779 appended_lines_mark((linenr_T)n, 1L);
1780
1781 curbuf = savebuf;
1782 update_screen(VALID);
1783
1784 raise_if_error();
1785 return scheme_void;
1786 }
1787
1788 /* List */
1789 size = scheme_proper_list_length(list);
1790 if (size < 0) /* improper or cyclic list */
1791 scheme_wrong_type(prim->name, "proper list",
1792 2, argc, argv);
1793
1794 /* Using MzScheme allocator, so we don't need to free this and
1795 * can safely keep pointers to GC collected strings
1796 */
1797 array = (char **)scheme_malloc_fail_ok(
1798 scheme_malloc, (unsigned)(size * sizeof(char *)));
1799
1800 rest = list;
1801 for (i = 0; i < size; ++i)
1802 {
1803 line = SCHEME_CAR(rest);
1804 rest = SCHEME_CDR(rest);
1805 array[i] = string_to_line(line);
1806 }
1807
1808 savebuf = curbuf;
1809 curbuf = buf->buf;
1810
1811 if (u_save((linenr_T)n, (linenr_T)(n + 1)) == FAIL)
1812 {
1813 curbuf = savebuf;
1814 raise_vim_exn(_("cannot save undo information"));
1815 }
1816 else
1817 {
1818 for (i = 0; i < size; ++i)
1819 if (ml_append((linenr_T)(n + i), (char_u *)array[i],
1820 0, FALSE) == FAIL)
1821 {
1822 curbuf = savebuf;
1823 raise_vim_exn(_("cannot insert line"));
1824 }
1825
1826 if (i > 0)
1827 appended_lines_mark((linenr_T)n, (long)i);
1828 }
1829
1830 curbuf = savebuf;
1831 update_screen(VALID);
1832
1833 raise_if_error();
1834 return scheme_void;
1835 }
1836
1837 /* (get-buff-namespace [buffer]) */
1838 static Scheme_Object *
1839 get_buffer_namespace(void *data, int argc, Scheme_Object **argv)
1840 {
1841 Vim_Prim *prim = (Vim_Prim *)data;
1842
1843 return (Scheme_Object *)get_buffer_arg(prim->name, 0, argc, argv)->env;
1844 }
1845
1846 /*
1847 * Predicates
1848 */
1849 /* (buff? obj) */
1850 static Scheme_Object *
1851 vim_bufferp(void *data, int argc, Scheme_Object **argv)
1852 {
1853 if (SCHEME_VIMBUFFERP(argv[0]))
1854 return scheme_true;
1855 else
1856 return scheme_false;
1857 }
1858
1859 /* (win? obj) */
1860 static Scheme_Object *
1861 vim_windowp(void *data, int argc, Scheme_Object **argv)
1862 {
1863 if (SCHEME_VIMWINDOWP(argv[0]))
1864 return scheme_true;
1865 else
1866 return scheme_false;
1867 }
1868
1869 /* (buff-valid? obj) */
1870 static Scheme_Object *
1871 vim_buffer_validp(void *data, int argc, Scheme_Object **argv)
1872 {
1873 if (SCHEME_VIMBUFFERP(argv[0])
1874 && ((vim_mz_buffer *)argv[0])->buf != INVALID_BUFFER_VALUE)
1875 return scheme_true;
1876 else
1877 return scheme_false;
1878 }
1879
1880 /* (win-valid? obj) */
1881 static Scheme_Object *
1882 vim_window_validp(void *data, int argc, Scheme_Object **argv)
1883 {
1884 if (SCHEME_VIMWINDOWP(argv[0])
1885 && ((vim_mz_window *)argv[0])->win != INVALID_WINDOW_VALUE)
1886 return scheme_true;
1887 else
1888 return scheme_false;
1889 }
1890
1891 /*
1892 *===========================================================================
1893 * Utilities
1894 *===========================================================================
1895 */
1896
1897 /*
1898 * Convert an MzScheme string into a Vim line.
1899 *
1900 * The result is in allocated memory. All internal nulls are replaced by
1901 * newline characters. It is an error for the string to contain newline
1902 * characters.
1903 *
1904 */
1905 static char *
1906 string_to_line(Scheme_Object *obj)
1907 {
1908 char *str;
1909 long len;
1910 int i;
1911
1912 str = scheme_display_to_string(obj, &len);
1913
1914 /* Error checking: String must not contain newlines, as we
1915 * are replacing a single line, and we must replace it with
1916 * a single line.
1917 */
1918 if (memchr(str, '\n', len))
1919 scheme_signal_error(_("string cannot contain newlines"));
1920
1921 /* Create a copy of the string, with internal nulls replaced by
1922 * newline characters, as is the vim convention.
1923 */
1924 for (i = 0; i < len; ++i)
1925 {
1926 if (str[i] == '\0')
1927 str[i] = '\n';
1928 }
1929
1930 str[i] = '\0';
1931
1932 return str;
1933 }
1934
1935 /*
1936 * Check to see whether a Vim error has been reported, or a keyboard
1937 * interrupt (from vim --> got_int) has been detected.
1938 */
1939 static int
1940 vim_error_check(void)
1941 {
1942 return (got_int || did_emsg);
1943 }
1944
1945 /*
1946 * register Scheme exn:vim
1947 */
1948 static void
1949 register_vim_exn(Scheme_Env *env)
1950 {
1951 Scheme_Object *exn_name = scheme_intern_symbol("exn:vim");
1952
1953 if (vim_exn == NULL)
1954 vim_exn = scheme_make_struct_type(exn_name,
1955 scheme_builtin_value("struct:exn"), NULL, 0, 0, NULL, NULL
1956 #if MZSCHEME_VERSION_MAJOR >= 299
1957 , NULL
1958 #endif
1959 );
1960
1961 if (vim_exn_values == NULL)
1962 {
1963 int nc = 0;
1964
1965 Scheme_Object **exn_names = scheme_make_struct_names(
1966 exn_name, scheme_null, 0, &nc);
1967 Scheme_Object **exn_values = scheme_make_struct_values(
1968 vim_exn, exn_names, nc, 0);
1969
1970 vim_exn_names = scheme_make_vector(nc, scheme_false);
1971 vim_exn_values = scheme_make_vector(nc, scheme_false);
1972 /* remember names and values */
1973 mch_memmove(SCHEME_VEC_ELS(vim_exn_names), exn_names,
1974 nc * sizeof(Scheme_Object *));
1975 mch_memmove(SCHEME_VEC_ELS(vim_exn_values), exn_values,
1976 nc * sizeof(Scheme_Object *));
1977 }
1978
1979 add_vim_exn(env);
1980 }
1981
1982 /*
1983 * Add stuff of exn:vim to env
1984 */
1985 static void
1986 add_vim_exn(Scheme_Env *env)
1987 {
1988 int i;
1989
1990 for (i = 0; i < SCHEME_VEC_SIZE(vim_exn_values); i++)
1991 scheme_add_global_symbol(SCHEME_VEC_ELS(vim_exn_names)[i],
1992 SCHEME_VEC_ELS(vim_exn_values)[i], env);
1993 }
1994
1995 /*
1996 * raise exn:vim, may be with additional info string
1997 */
1998 void
1999 raise_vim_exn(const char *add_info)
2000 {
2001 Scheme_Object *argv[2];
2002 char_u *fmt = _("Vim error: ~a");
2003
2004 if (add_info != NULL)
2005 {
2006 Scheme_Object *info = scheme_make_string(add_info);
2007 argv[0] = scheme_make_string(
2008 scheme_format(fmt, strlen(fmt), 1, &info, NULL));
2009 }
2010 else
2011 argv[0] = scheme_make_string(_("Vim error"));
2012
2013 argv[1] = scheme_current_continuation_marks();
2014
2015 scheme_raise(scheme_make_struct_instance(vim_exn, 2, argv));
2016 }
2017
2018 void
2019 raise_if_error(void)
2020 {
2021 if (vim_error_check())
2022 raise_vim_exn(NULL);
2023 }
2024
2025 /* get buffer:
2026 * either current
2027 * or passed as argv[argnum] with checks
2028 */
2029 static vim_mz_buffer *
2030 get_buffer_arg(const char *fname, int argnum, int argc, Scheme_Object **argv)
2031 {
2032 vim_mz_buffer *b;
2033
2034 if (argc < argnum + 1)
2035 return get_vim_curr_buffer();
2036 if (!SCHEME_VIMBUFFERP(argv[argnum]))
2037 scheme_wrong_type(fname, "vim-buffer", argnum, argc, argv);
2038 b = (vim_mz_buffer *)argv[argnum];
2039 (void)get_valid_buffer(argv[argnum]);
2040 return b;
2041 }
2042
2043 /* get window:
2044 * either current
2045 * or passed as argv[argnum] with checks
2046 */
2047 static vim_mz_window *
2048 get_window_arg(const char *fname, int argnum, int argc, Scheme_Object **argv)
2049 {
2050 vim_mz_window *w;
2051
2052 if (argc < argnum + 1)
2053 return get_vim_curr_window();
2054 w = (vim_mz_window *)argv[argnum];
2055 if (!SCHEME_VIMWINDOWP(argv[argnum]))
2056 scheme_wrong_type(fname, "vim-window", argnum, argc, argv);
2057 (void)get_valid_window(argv[argnum]);
2058 return w;
2059 }
2060
2061 /* get valid Vim buffer from Scheme_Object* */
2062 buf_T *get_valid_buffer(void *obj)
2063 {
2064 buf_T *buf = ((vim_mz_buffer *)obj)->buf;
2065
2066 if (buf == INVALID_BUFFER_VALUE)
2067 scheme_signal_error(_("buffer is invalid"));
2068 return buf;
2069 }
2070
2071 /* get valid Vim window from Scheme_Object* */
2072 win_T *get_valid_window(void *obj)
2073 {
2074 win_T *win = ((vim_mz_window *)obj)->win;
2075 if (win == INVALID_WINDOW_VALUE)
2076 scheme_signal_error(_("window is invalid"));
2077 return win;
2078 }
2079
2080 #if 0
2081 int
2082 mzvim_bufferp(Scheme_Object *obj)
2083 {
2084 return SCHEME_VIMBUFFERP(obj);
2085 }
2086
2087 int
2088 mzvim_windowp(Scheme_Object *obj)
2089 {
2090 return SCHEME_VIMWINDOWP(obj);
2091 }
2092 #endif
2093
2094 int
2095 mzthreads_allowed(void)
2096 {
2097 return mz_threads_allow;
2098 }
2099
2100 static int
2101 line_in_range(linenr_T lnum, buf_T *buf)
2102 {
2103 return (lnum > 0 && lnum <= buf->b_ml.ml_line_count);
2104 }
2105
2106 static void
2107 check_line_range(linenr_T lnum, buf_T *buf)
2108 {
2109 if (!line_in_range(lnum, buf))
2110 scheme_signal_error(_("linenr out of range"));
2111 }
2112
2113 /*
2114 * Check if deleting lines made the cursor position invalid
2115 * (or you'll get msg from Vim about invalid linenr).
2116 * Changed the lines from "lo" to "hi" and added "extra" lines (negative if
2117 * deleted). Got from if_python.c
2118 */
2119 static void
2120 mz_fix_cursor(int lo, int hi, int extra)
2121 {
2122 if (curwin->w_cursor.lnum >= lo)
2123 {
2124 /* Adjust the cursor position if it's in/after the changed
2125 * lines. */
2126 if (curwin->w_cursor.lnum >= hi)
2127 {
2128 curwin->w_cursor.lnum += extra;
2129 check_cursor_col();
2130 }
2131 else if (extra < 0)
2132 {
2133 curwin->w_cursor.lnum = lo;
2134 check_cursor();
2135 }
2136 changed_cline_bef_curs();
2137 }
2138 invalidate_botline();
2139 }
2140
2141 static Vim_Prim prims[]=
2142 {
2143 /*
2144 * Buffer-related commands
2145 */
2146 {get_buffer_line, "get-buff-line", 1, 2},
2147 {set_buffer_line, "set-buff-line", 2, 3},
2148 {get_buffer_line_list, "get-buff-line-list", 2, 3},
2149 {get_buffer_name, "get-buff-name", 0, 1},
2150 {get_buffer_num, "get-buff-num", 0, 1},
2151 {get_buffer_size, "get-buff-size", 0, 1},
2152 {set_buffer_line_list, "set-buff-line-list", 3, 4},
2153 {insert_buffer_line_list, "insert-buff-line-list", 2, 3},
2154 {get_curr_buffer, "curr-buff", 0, 0},
2155 {get_buffer_count, "buff-count", 0, 0},
2156 {get_next_buffer, "get-next-buff", 0, 1},
2157 {get_prev_buffer, "get-prev-buff", 0, 1},
2158 {mzscheme_open_buffer, "open-buff", 1, 1},
2159 {get_buffer_by_name, "get-buff-by-name", 1, 1},
2160 {get_buffer_by_num, "get-buff-by-num", 1, 1},
2161 {get_buffer_namespace, "get-buff-namespace", 0, 1},
2162 /*
2163 * Window-related commands
2164 */
2165 {get_curr_win, "curr-win", 0, 0},
2166 {get_window_count, "win-count", 0, 0},
2167 {get_window_by_num, "get-win-by-num", 1, 1},
2168 {get_window_num, "get-win-num", 0, 1},
2169 {get_window_buffer, "get-win-buffer", 0, 1},
2170 {get_window_height, "get-win-height", 0, 1},
2171 {set_window_height, "set-win-height", 1, 2},
2172 #ifdef FEAT_VERTSPLIT
2173 {get_window_width, "get-win-width", 0, 1},
2174 {set_window_width, "set-win-width", 1, 2},
2175 #endif
2176 {get_cursor, "get-cursor", 0, 1},
2177 {set_cursor, "set-cursor", 1, 2},
2178 {get_window_list, "get-win-list", 0, 1},
2179 /*
2180 * Vim-related commands
2181 */
2182 {vim_command, "command", 1, 1},
2183 {vim_eval, "eval", 1, 1},
2184 {get_range_start, "range-start", 0, 0},
2185 {get_range_end, "range-end", 0, 0},
2186 {mzscheme_beep, "beep", 0, 0},
2187 {get_option, "get-option", 1, 2},
2188 {set_option, "set-option", 1, 2},
2189 /*
2190 * small utilities
2191 */
2192 {vim_bufferp, "buff?", 1, 1},
2193 {vim_windowp, "win?", 1, 1},
2194 {vim_buffer_validp, "buff-valid?", 1, 1},
2195 {vim_window_validp, "win-valid?", 1, 1}
2196 };
2197
2198 /* return MzScheme wrapper for curbuf */
2199 static vim_mz_buffer *
2200 get_vim_curr_buffer(void)
2201 {
2202 if (!curbuf->mzscheme_ref)
2203 return (vim_mz_buffer *)buffer_new(curbuf);
2204 else
2205 return (vim_mz_buffer *)curbuf->mzscheme_ref;
2206 }
2207
2208 /* return MzScheme wrapper for curwin */
2209 static vim_mz_window *
2210 get_vim_curr_window(void)
2211 {
2212 if (!curwin->mzscheme_ref)
2213 return (vim_mz_window *)window_new(curwin);
2214 else
2215 return (vim_mz_window *)curwin->mzscheme_ref;
2216 }
2217
2218 #if 0
2219 char *
2220 mzscheme_version(void)
2221 {
2222 return scheme_version();
2223 }
2224 #endif
2225
2226 static void
2227 make_modules(Scheme_Env *env)
2228 {
2229 int i;
2230 Scheme_Env *mod;
2231
2232 mod = scheme_primitive_module(scheme_intern_symbol("vimext"), env);
2233 /* all prims made closed so they can access their own names */
2234 for (i = 0; i < sizeof(prims)/sizeof(prims[0]); i++)
2235 {
2236 Vim_Prim *prim = prims + i;
2237 scheme_add_global(prim->name,
2238 scheme_make_closed_prim_w_arity(prim->prim, prim, prim->name,
2239 prim->mina, prim->maxa),
2240 mod);
2241 }
2242 scheme_add_global("global-namespace", (Scheme_Object *)environment, mod);
2243 scheme_finish_primitive_module(mod);
2244 }