blob: 377b5f755bf8ca6c5839601ef60a7eb0cfbd50cc [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
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
42typedef 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
52typedef 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 */
63typedef struct
64{
65 Scheme_Closed_Prim *prim;
66 char *name;
67 int mina; /* arity information */
68 int maxa;
69} Vim_Prim;
70
71typedef 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 */
84typedef struct
85{
86 void *data;
87 Scheme_Env *env;
88} Cmd_Info;
89
90/* info for do_apply */
91typedef 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 */
109static Scheme_Object *buffer_new(buf_T *buf);
110static Scheme_Object *get_buffer_by_name(void *, int, Scheme_Object **);
111static Scheme_Object *get_buffer_by_num(void *, int, Scheme_Object **);
112static Scheme_Object *get_buffer_count(void *, int, Scheme_Object **);
113static Scheme_Object *get_buffer_line(void *, int, Scheme_Object **);
114static Scheme_Object *get_buffer_line_list(void *, int, Scheme_Object **);
115static Scheme_Object *get_buffer_name(void *, int, Scheme_Object **);
116static Scheme_Object *get_buffer_num(void *, int, Scheme_Object **);
117static Scheme_Object *get_buffer_size(void *, int, Scheme_Object **);
118static Scheme_Object *get_curr_buffer(void *, int, Scheme_Object **);
119static Scheme_Object *get_next_buffer(void *, int, Scheme_Object **);
120static Scheme_Object *get_prev_buffer(void *, int, Scheme_Object **);
121static Scheme_Object *mzscheme_open_buffer(void *, int, Scheme_Object **);
122static Scheme_Object *set_buffer_line(void *, int, Scheme_Object **);
123static Scheme_Object *set_buffer_line_list(void *, int, Scheme_Object **);
124static Scheme_Object *insert_buffer_line_list(void *, int, Scheme_Object **);
125static Scheme_Object *get_range_start(void *, int, Scheme_Object **);
126static Scheme_Object *get_range_end(void *, int, Scheme_Object **);
127static Scheme_Object *get_buffer_namespace(void *, int, Scheme_Object **);
128static vim_mz_buffer *get_vim_curr_buffer(void);
129
130/* Window-related commands */
131static Scheme_Object *window_new(win_T *win);
132static Scheme_Object *get_curr_win(void *, int, Scheme_Object **);
133static Scheme_Object *get_window_count(void *, int, Scheme_Object **);
134static Scheme_Object *get_window_by_num(void *, int, Scheme_Object **);
135static Scheme_Object *get_window_num(void *, int, Scheme_Object **);
136static Scheme_Object *get_window_buffer(void *, int, Scheme_Object **);
137static Scheme_Object *get_window_height(void *, int, Scheme_Object **);
138static Scheme_Object *set_window_height(void *, int, Scheme_Object **);
139#ifdef FEAT_VERTSPLIT
140static Scheme_Object *get_window_width(void *, int, Scheme_Object **);
141static Scheme_Object *set_window_width(void *, int, Scheme_Object **);
142#endif
143static Scheme_Object *get_cursor(void *, int, Scheme_Object **);
144static Scheme_Object *set_cursor(void *, int, Scheme_Object **);
145static Scheme_Object *get_window_list(void *, int, Scheme_Object **);
146static vim_mz_window *get_vim_curr_window(void);
147
148/* Vim-related commands */
149static Scheme_Object *mzscheme_beep(void *, int, Scheme_Object **);
150static Scheme_Object *get_option(void *, int, Scheme_Object **);
151static Scheme_Object *set_option(void *, int, Scheme_Object **);
152static Scheme_Object *vim_command(void *, int, Scheme_Object **);
153static Scheme_Object *vim_eval(void *, int, Scheme_Object **);
154static Scheme_Object *vim_bufferp(void *data, int, Scheme_Object **);
155static Scheme_Object *vim_windowp(void *data, int, Scheme_Object **);
156static Scheme_Object *vim_buffer_validp(void *data, int, Scheme_Object **);
157static Scheme_Object *vim_window_validp(void *data, int, Scheme_Object **);
158
159/*
160 *========================================================================
161 * Internal Function Prototypes
162 *========================================================================
163 */
164static int vim_error_check(void);
165static int do_mzscheme_command(exarg_T *, void *, Scheme_Closed_Prim *what);
166static void startup_mzscheme(void);
167static char *string_to_line(Scheme_Object *obj);
168static int mzscheme_io_init(void);
169static void mzscheme_interface_init(vim_mz_buffer *self);
170static void do_output(char *mesg, long len);
171static void do_printf(char *format, ...);
172static void do_flush(void);
173static Scheme_Object *_apply_thunk_catch_exceptions(
174 Scheme_Object *, Scheme_Object **);
175static Scheme_Object *extract_exn_message(Scheme_Object *v);
176static Scheme_Object *do_eval(void *, int noargc, Scheme_Object **noargv);
177static Scheme_Object *do_load(void *, int noargc, Scheme_Object **noargv);
178static Scheme_Object *do_apply(void *, int noargc, Scheme_Object **noargv);
179static void register_vim_exn(Scheme_Env *env);
180static vim_mz_buffer *get_buffer_arg(const char *fname, int argnum,
181 int argc, Scheme_Object **argv);
182static vim_mz_window *get_window_arg(const char *fname, int argnum,
183 int argc, Scheme_Object **argv);
184static void add_vim_exn(Scheme_Env *env);
185static int line_in_range(linenr_T, buf_T *);
186static void check_line_range(linenr_T, buf_T *);
187static void mz_fix_cursor(int lo, int hi, int extra);
188
189static int eval_in_namespace(void *, Scheme_Closed_Prim *, Scheme_Env *,
190 Scheme_Object **ret);
191static void make_modules(Scheme_Env *);
192
193/*
194 *========================================================================
195 * 1. MzScheme interpreter startup
196 *========================================================================
197 */
198
199static Scheme_Type mz_buffer_type;
200static Scheme_Type mz_window_type;
201
202static int initialized = 0;
203
204/* global environment */
205static Scheme_Env *environment = NULL;
206/* output/error handlers */
207static Scheme_Object *curout = NULL;
208static Scheme_Object *curerr = NULL;
209/* vim:exn exception */
210static Scheme_Object *exn_catching_apply = NULL;
211static Scheme_Object *exn_p = NULL;
212static Scheme_Object *exn_message = NULL;
213static Scheme_Object *vim_exn = NULL; /* Vim Error exception */
214 /* values for exn:vim - constructor, predicate, accessors etc */
215static Scheme_Object *vim_exn_names = NULL;
216static Scheme_Object *vim_exn_values = NULL;
217
218static long range_start;
219static long range_end;
220
221/* MzScheme threads scheduling stuff */
222static int mz_threads_allow = 0;
223#ifdef FEAT_GUI
224static void setup_timer(void);
225static void remove_timer(void);
226#endif
227
228#if defined(FEAT_GUI_W32)
229static void CALLBACK timer_proc(HWND, UINT, UINT, DWORD);
230static UINT timer_id = 0;
231#elif defined(FEAT_GUI_GTK)
232static gint timer_proc(gpointer);
233static guint timer_id = 0;
234#elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)
235static void timer_proc(XtPointer, XtIntervalId *);
236static XtIntervalId timer_id = (XtIntervalId)0;
237#elif defined(FEAT_GUI_MAC)
238pascal void timer_proc(EventLoopTimerRef, void *);
239static EventLoopTimerRef timer_id = NULL;
240static EventLoopTimerUPP timerUPP;
241#endif
242
243#ifndef FEAT_GUI_W32 /* Win32 console and Unix */
244 void
245mzvim_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
267timer_proc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
268# elif defined(FEAT_GUI_GTK)
269/*ARGSUSED*/
270 static gint
271timer_proc(gpointer data)
272# elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)
273/* ARGSUSED */
274 static void
275timer_proc(XtPointer timed_out, XtIntervalId *interval_id)
276# elif defined(FEAT_GUI_MAC)
277 pascal void
278timer_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
293setup_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
309remove_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
325mzvim_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
336notify_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
348mzscheme_enabled(int verbose)
349{
350 return initialized;
351}
352
353 void
354mzscheme_end(void)
355{
356}
357
358 static void
359startup_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
406mzscheme_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
440mzscheme_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
478eval_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
523do_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
538mzscheme_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
554mzscheme_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
570ex_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 *
589mzvim_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 *
604mzvim_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 *
621do_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
648ex_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
667init_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 *
712extract_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 *
723do_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 *
731do_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
744do_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
768do_output(char *mesg, long len)
769{
770 do_intrnl_output(mesg, len, 0);
771}
772
773 static void
774do_err_output(char *mesg, long len)
775{
776 do_intrnl_output(mesg, len, 1);
777}
778
779 static void
780do_printf(char *format, ...)
781{
782 do_intrnl_output(format, STRLEN(format), 1);
783}
784
785 static void
786do_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
804mzscheme_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 *
818vim_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 *
833vim_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 *
862get_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 *
869get_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 *
876mzscheme_beep(void *data, int argc, Scheme_Object **argv)
877{
878 vim_beep();
879 return scheme_void;
880}
881
882static Scheme_Object *M_global = NULL;
883
884/* (get-option {option-name}) [buffer/window] */
885 static Scheme_Object *
886get_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 *
951set_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 *
1005get_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 *
1012get_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 *
1023get_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 *
1041window_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 *
1069get_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 *
1084get_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 *
1103get_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 *
1113get_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 *
1123set_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 *
1149get_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 *
1159set_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 *
1185get_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 *
1199set_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 *
1235mzscheme_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 *
1255get_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 *
1272get_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 *
1297get_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 *
1310get_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 *
1323get_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 *
1333get_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 *
1344get_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 *
1354get_curr_buffer(void *data, int argc, Scheme_Object **argv)
1355{
1356 return (Scheme_Object *)get_vim_curr_buffer();
1357}
1358
1359 static Scheme_Object *
1360buffer_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 *
1390get_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 *
1406get_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 *
1430get_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 *
1481set_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 *
1567set_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 *
1736insert_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 *
1839get_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 *
1851vim_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 *
1861vim_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 *
1871vim_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 *
1882vim_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 *
1906string_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
1940vim_error_check(void)
1941{
1942 return (got_int || did_emsg);
1943}
1944
1945/*
1946 * register Scheme exn:vim
1947 */
1948 static void
1949register_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
1986add_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
1999raise_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
2019raise_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 *
2030get_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 *
2048get_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* */
2062buf_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* */
2072win_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
2082mzvim_bufferp(Scheme_Object *obj)
2083{
2084 return SCHEME_VIMBUFFERP(obj);
2085}
2086
2087 int
2088mzvim_windowp(Scheme_Object *obj)
2089{
2090 return SCHEME_VIMWINDOWP(obj);
2091}
2092#endif
2093
2094 int
2095mzthreads_allowed(void)
2096{
2097 return mz_threads_allow;
2098}
2099
2100 static int
2101line_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
2107check_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
2120mz_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
2141static 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 *
2200get_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 *
2210get_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 *
2220mzscheme_version(void)
2221{
2222 return scheme_version();
2223}
2224#endif
2225
2226 static void
2227make_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}