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