blob: b798ea59abcda322522d43f0ae578ad26c33de10 [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * Tcl extensions by Ingo Wilken <Ingo.Wilken@informatik.uni-oldenburg.de>
12 * Last modification: Wed May 10 21:28:44 CEST 2000
13 * Requires Tcl 8.0 or higher.
14 *
15 * Variables:
16 * ::vim::current(buffer) # Name of buffer command for current buffer.
17 * ::vim::current(window) # Name of window command for current window.
18 * ::vim::range(start) # Start of current range (line number).
19 * ::vim::range(end) # End of current range (line number).
20 * ::vim::lbase # Start of line/column numbers (1 or 0).
21 *
22 * Commands:
23 * ::vim::command {cmd} # Execute ex command {cmd}.
24 * ::vim::option {opt} [val] # Get/Set option {opt}.
25 * ::vim::expr {expr} # Evaluate {expr} using vim's evaluator.
26 * ::vim::beep # Guess.
27 *
28 * set buf [::vim::buffer {n}] # Create Tcl command for buffer N.
29 * set bl [::vim::buffer list] # Get list of Tcl commands of all buffers.
30 * ::vim::buffer exists {n} # True if buffer {n} exists.
31 *
32 * set wl [::vim::window list] # Get list of Tcl commands of all windows.
33 *
34 * set n [$win height] # Report window height.
35 * $win height {n} # Set window height to {n}.
36 * array set pos [$win cursor] # Get cursor position.
37 * $win cursor {row} {col} # Set cursor position.
38 * $win cursor pos # Set cursor position from array var "pos"
39 * $win delcmd {cmd} # Register callback command for closed window.
40 * $win option {opt} [val] # Get/Set vim option in context of $win.
41 * $win command {cmd} # Execute ex command in context of $win.
42 * $win expr {expr} # Evaluate vim expression in context of $win.
43 * set buf [$win buffer] # Create Tcl command for window's buffer.
44 *
45 * $buf name # Reports file name in buffer.
46 * $buf number # Reports buffer number.
47 * set l [$buf get {n}] # Get buffer line {n} as a string.
48 * set L [$buf get {n} {m}] # Get lines {n} through {m} as a list.
49 * $buf count # Reports number of lines in buffer.
50 * $buf last # Reports number of last line in buffer.
51 * $buf delete {n} # Delete line {n}.
52 * $buf delete {n} {m} # Delete lines {n} through {m}.
53 * $buf set {n} {l} # Set line {n} to string {l}.
54 * $buf set {n} {m} {L} # Set lines {n} through {m} from list {L}.
55 * # Delete/inserts lines as appropriate.
56 * $buf option {opt} [val] # Get/Set vim option in context of $buf.
57 * $buf command {cmd} # Execute ex command in context of $buf
58 * $buf expr {cmd} # Evaluate vim expression in context of $buf.
59 * array set pos [$buf mark {m}] # Get position of mark.
60 * $buf append {n} {str} # Append string {str} to buffer,after line {n}.
61 * $buf insert {n} {str} # Insert string {str} in buffer as line {n}.
62 * $buf delcmd {cmd} # Register callback command for deleted buffer.
63 * set wl [$buf windows] # Get list of Tcl commands for all windows of
64 * # this buffer.
65TODO:
66 * ::vim::buffer new # create new buffer + Tcl command
67 */
68
69#include "vim.h"
70#undef EXTERN /* tcl.h defines it too */
71
72#ifdef DYNAMIC_TCL
73# define USE_TCL_STUBS /* use tcl's stubs mechanism */
74#endif
75
76#include <tcl.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000077#include <string.h>
78
79typedef struct
80{
81 Tcl_Interp *interp;
Bram Moolenaar84a4c332012-02-22 16:01:56 +010082 int exitvalue;
Bram Moolenaar071d4272004-06-13 20:20:40 +000083 int range_start, range_end;
84 int lbase;
85 char *curbuf, *curwin;
86} tcl_info;
87
Bram Moolenaar84a4c332012-02-22 16:01:56 +010088static tcl_info tclinfo = { NULL, 0, 0, 0, 0, NULL, NULL };
Bram Moolenaar071d4272004-06-13 20:20:40 +000089
90#define VAR_RANGE1 "::vim::range(start)"
91#define VAR_RANGE2 "::vim::range(begin)"
92#define VAR_RANGE3 "::vim::range(end)"
93#define VAR_CURBUF "::vim::current(buffer)"
94#define VAR_CURWIN "::vim::current(window)"
95#define VAR_LBASE "::vim::lbase"
96#define VAR_CURLINE "line"
97#define VAR_CURLNUM "lnum"
98#define VARNAME_SIZE 64
99
100#define row2tcl(x) ((x) - (tclinfo.lbase==0))
101#define row2vim(x) ((x) + (tclinfo.lbase==0))
102#define col2tcl(x) ((x) + (tclinfo.lbase!=0))
103#define col2vim(x) ((x) - (tclinfo.lbase!=0))
104
105
106#define VIMOUT ((ClientData)1)
107#define VIMERR ((ClientData)2)
108
Bram Moolenaar7df2d662005-01-25 22:18:08 +0000109/* This appears to be new in Tcl 8.4. */
110#ifndef CONST84
111# define CONST84
112#endif
113
Bram Moolenaar071d4272004-06-13 20:20:40 +0000114/*
115 * List of Tcl interpreters who reference a vim window or buffer.
Bram Moolenaare344bea2005-09-01 20:46:49 +0000116 * Each buffer and window has it's own list in the w_tcl_ref or b_tcl_ref
117 * struct member. We need this because Tcl can create sub-interpreters with
118 * the "interp" command, and each interpreter can reference all windows and
119 * buffers.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000120 */
121struct ref
122{
123 struct ref *next;
124
125 Tcl_Interp *interp;
126 Tcl_Command cmd; /* Tcl command that represents this object */
127 Tcl_Obj *delcmd; /* Tcl command to call when object is being del. */
128 void *vimobj; /* Vim window or buffer (win_T* or buf_T*) */
129};
130static char * tclgetbuffer _ANSI_ARGS_((Tcl_Interp *interp, buf_T *buf));
131static char * tclgetwindow _ANSI_ARGS_((Tcl_Interp *interp, win_T *win));
132static int tclsetdelcmd _ANSI_ARGS_((Tcl_Interp *interp, struct ref *reflist, void *vimobj, Tcl_Obj *delcmd));
133static int tclgetlinenum _ANSI_ARGS_ ((Tcl_Interp *interp, Tcl_Obj *obj, int *valueP, buf_T *buf));
134static win_T *tclfindwin _ANSI_ARGS_ ((buf_T *buf));
135static int tcldoexcommand _ANSI_ARGS_ ((Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], int objn));
136static int tclsetoption _ANSI_ARGS_ ((Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], int objn));
137static int tclvimexpr _ANSI_ARGS_ ((Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], int objn));
138static void tcldelthisinterp _ANSI_ARGS_ ((void));
139
140static int vimerror _ANSI_ARGS_((Tcl_Interp *interp));
141static void tclmsg _ANSI_ARGS_((char *text));
142static void tclerrmsg _ANSI_ARGS_((char *text));
143static void tclupdatevars _ANSI_ARGS_((void));
144
145static struct ref refsdeleted; /* dummy object for deleted ref list */
146
147/*****************************************************************************
148 * TCL interface manager
149 ****************************************************************************/
150
151#if defined(DYNAMIC_TCL) || defined(PROTO)
152# ifndef DYNAMIC_TCL_DLL
153# define DYNAMIC_TCL_DLL "tcl83.dll"
154# endif
155# ifndef DYNAMIC_TCL_VER
156# define DYNAMIC_TCL_VER "8.3"
157# endif
158
159# ifndef DYNAMIC_TCL /* Just generating prototypes */
160typedef int HANDLE;
161# endif
162
163/*
Bram Moolenaara41b1392009-05-23 12:28:15 +0000164 * Declare HANDLE for tcl.dll and function pointers.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000165 */
166static HANDLE hTclLib = NULL;
167Tcl_Interp* (*dll_Tcl_CreateInterp)();
Bram Moolenaar0b4db6b2013-10-02 14:25:44 +0200168void (*dll_Tcl_FindExecutable)(const void *);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000169
170/*
171 * Table of name to function pointer of tcl.
172 */
173#define TCL_PROC FARPROC
174static struct {
175 char* name;
176 TCL_PROC* ptr;
177} tcl_funcname_table[] = {
178 {"Tcl_CreateInterp", (TCL_PROC*)&dll_Tcl_CreateInterp},
Bram Moolenaar0b4db6b2013-10-02 14:25:44 +0200179 {"Tcl_FindExecutable", (TCL_PROC*)&dll_Tcl_FindExecutable},
Bram Moolenaar071d4272004-06-13 20:20:40 +0000180 {NULL, NULL},
181};
182
183/*
184 * Make all runtime-links of tcl.
185 *
186 * 1. Get module handle using LoadLibraryEx.
Bram Moolenaara41b1392009-05-23 12:28:15 +0000187 * 2. Get pointer to tcl function by GetProcAddress.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000188 * 3. Repeat 2, until get all functions will be used.
189 *
190 * Parameter 'libname' provides name of DLL.
191 * Return OK or FAIL.
192 */
193 static int
194tcl_runtime_link_init(char *libname, int verbose)
195{
196 int i;
197
198 if (hTclLib)
199 return OK;
Bram Moolenaar364ab2f2013-08-02 20:05:32 +0200200 if (!(hTclLib = vimLoadLib(libname)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000201 {
202 if (verbose)
203 EMSG2(_(e_loadlib), libname);
204 return FAIL;
205 }
206 for (i = 0; tcl_funcname_table[i].ptr; ++i)
207 {
208 if (!(*tcl_funcname_table[i].ptr = GetProcAddress(hTclLib,
209 tcl_funcname_table[i].name)))
210 {
211 FreeLibrary(hTclLib);
212 hTclLib = NULL;
213 if (verbose)
214 EMSG2(_(e_loadfunc), tcl_funcname_table[i].name);
215 return FAIL;
216 }
217 }
218 return OK;
219}
220#endif /* defined(DYNAMIC_TCL) || defined(PROTO) */
221
222#ifdef DYNAMIC_TCL
223static char *find_executable_arg = NULL;
224#endif
225
226 void
227vim_tcl_init(arg)
228 char *arg;
229{
230#ifndef DYNAMIC_TCL
231 Tcl_FindExecutable(arg);
232#else
233 find_executable_arg = arg;
234#endif
235}
236
237#if defined(DYNAMIC_TCL) || defined(PROTO)
238
239static int stubs_initialized = FALSE;
240
241/*
242 * Return TRUE if the TCL interface can be used.
243 */
244 int
245tcl_enabled(verbose)
246 int verbose;
247{
248 if (!stubs_initialized && find_executable_arg != NULL
249 && tcl_runtime_link_init(DYNAMIC_TCL_DLL, verbose) == OK)
250 {
251 Tcl_Interp *interp;
252
Bram Moolenaar0b4db6b2013-10-02 14:25:44 +0200253 dll_Tcl_FindExecutable(find_executable_arg);
254
Bram Moolenaar071d4272004-06-13 20:20:40 +0000255 if (interp = dll_Tcl_CreateInterp())
256 {
257 if (Tcl_InitStubs(interp, DYNAMIC_TCL_VER, 0))
258 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000259 Tcl_DeleteInterp(interp);
260 stubs_initialized = TRUE;
261 }
262 /* FIXME: When Tcl_InitStubs() was failed, how delete interp? */
263 }
264 }
265 return stubs_initialized;
266}
267#endif
268
269 void
270tcl_end()
271{
272#ifdef DYNAMIC_TCL
273 if (hTclLib)
274 {
275 FreeLibrary(hTclLib);
276 hTclLib = NULL;
277 }
278#endif
279}
280
281/****************************************************************************
282 Tcl commands
283 ****************************************************************************/
284
285/*
Bram Moolenaar84a4c332012-02-22 16:01:56 +0100286 * Replace standard "exit" command.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000287 *
Bram Moolenaar84a4c332012-02-22 16:01:56 +0100288 * Delete the Tcl interpreter; a new one will be created with the next
289 * :tcl command). The exit code is saved (and retrieved in tclexit()).
290 * Since Tcl's exit is never expected to return and this replacement
291 * does, then (except for a trivial case) additional Tcl commands will
292 * be run. Since the interpreter is now marked as deleted, an error
293 * will be returned -- typically "attempt to call eval in deleted
294 * interpreter". Hopefully, at this point, checks for TCL_ERROR take
295 * place and control percolates back up to Vim -- but with this new error
296 * string in the interpreter's result value. Therefore it would be
297 * useless for this routine to return the exit code via Tcl_SetResult().
Bram Moolenaar071d4272004-06-13 20:20:40 +0000298 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000299 static int
300exitcmd(dummy, interp, objc, objv)
Bram Moolenaar30f9ca92009-05-22 19:08:31 +0000301 ClientData dummy UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000302 Tcl_Interp *interp;
303 int objc;
304 Tcl_Obj *CONST objv[];
305{
306 int value = 0;
307
308 switch (objc)
309 {
310 case 2:
311 if (Tcl_GetIntFromObj(interp, objv[1], &value) != TCL_OK)
312 break;
313 /* FALLTHROUGH */
314 case 1:
Bram Moolenaar84a4c332012-02-22 16:01:56 +0100315 tclinfo.exitvalue = value;
316
317 Tcl_DeleteInterp(interp);
318 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000319 default:
320 Tcl_WrongNumArgs(interp, 1, objv, "?returnCode?");
321 }
322 return TCL_ERROR;
323}
324
Bram Moolenaar071d4272004-06-13 20:20:40 +0000325/*
326 * "::vim::beep" - what Vi[m] does best :-)
327 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000328 static int
329beepcmd(dummy, interp, objc, objv)
Bram Moolenaar30f9ca92009-05-22 19:08:31 +0000330 ClientData dummy UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000331 Tcl_Interp *interp;
332 int objc;
333 Tcl_Obj *CONST objv[];
334{
335 if (objc != 1)
336 {
337 Tcl_WrongNumArgs(interp, 1, objv, NULL);
338 return TCL_ERROR;
339 }
340 vim_beep();
341 return TCL_OK;
342}
343
344/*
345 * "::vim::buffer list" - create a list of buffer commands.
Bram Moolenaarb8017e72007-05-10 18:59:07 +0000346 * "::vim::buffer {N}" - create buffer command for buffer N.
Bram Moolenaar84a4c332012-02-22 16:01:56 +0100347 * "::vim::buffer exists {N}" - test if buffer N exists.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000348 * "::vim::buffer new" - create a new buffer (not implemented)
349 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000350 static int
351buffercmd(dummy, interp, objc, objv)
Bram Moolenaar30f9ca92009-05-22 19:08:31 +0000352 ClientData dummy UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000353 Tcl_Interp *interp;
354 int objc;
355 Tcl_Obj *CONST objv[];
356{
357 char *name;
358 buf_T *buf;
359 Tcl_Obj *resobj;
360 int err, n, idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000361 enum {BCMD_EXISTS, BCMD_LIST};
Bram Moolenaar7df2d662005-01-25 22:18:08 +0000362 static CONST84 char *bcmdoptions[] =
Bram Moolenaar071d4272004-06-13 20:20:40 +0000363 {
364 "exists", "list", (char *)0
365 };
366
367 if (objc < 2)
368 {
369 Tcl_WrongNumArgs(interp, 1, objv, "option");
370 return TCL_ERROR;
371 }
372 err = Tcl_GetIntFromObj(interp, objv[1], &n);
373 if (err == TCL_OK)
374 {
375 if (objc != 2)
376 {
377 Tcl_WrongNumArgs(interp, 1, objv, "bufNumber");
378 return TCL_ERROR;
379 }
380 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
381 {
382 if (buf->b_fnum == n)
383 {
384 name = tclgetbuffer(interp, buf);
385 if (name == NULL)
386 return TCL_ERROR;
387 Tcl_SetResult(interp, name, TCL_VOLATILE);
388 return TCL_OK;
389 }
390 }
391 Tcl_SetResult(interp, _("invalid buffer number"), TCL_STATIC);
392 return TCL_ERROR;
393 }
394 Tcl_ResetResult(interp); /* clear error from Tcl_GetIntFromObj */
395
396 err = Tcl_GetIndexFromObj(interp, objv[1], bcmdoptions, "option", 0, &idx);
397 if (err != TCL_OK)
398 return err;
399 switch (idx)
400 {
401 case BCMD_LIST:
402 if (objc != 2)
403 {
404 Tcl_WrongNumArgs(interp, 2, objv, "");
405 err = TCL_ERROR;
406 break;
407 }
408 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
409 {
410 name = tclgetbuffer(interp, buf);
411 if (name == NULL)
412 {
413 err = TCL_ERROR;
414 break;
415 }
416 Tcl_AppendElement(interp, name);
417 }
418 break;
419
420 case BCMD_EXISTS:
421 if (objc != 3)
422 {
423 Tcl_WrongNumArgs(interp, 2, objv, "bufNumber");
424 err = TCL_ERROR;
425 break;
426 }
427 err = Tcl_GetIntFromObj(interp, objv[2], &n);
428 if (err == TCL_OK)
429 {
430 buf = buflist_findnr(n);
431 resobj = Tcl_NewIntObj(buf != NULL);
432 Tcl_SetObjResult(interp, resobj);
433 }
434 break;
435
436 default:
437 Tcl_SetResult(interp, _("not implemented yet"), TCL_STATIC);
438 err = TCL_ERROR;
439 }
440 return err;
441}
442
443/*
444 * "::vim::window list" - create list of window commands.
445 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000446 static int
447windowcmd(dummy, interp, objc, objv)
Bram Moolenaar30f9ca92009-05-22 19:08:31 +0000448 ClientData dummy UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000449 Tcl_Interp *interp;
450 int objc;
451 Tcl_Obj *CONST objv[];
452{
453 char *what, *string;
454 win_T *win;
455
456 if (objc != 2)
457 {
458 Tcl_WrongNumArgs(interp, 1, objv, "option");
459 return TCL_ERROR;
460 }
461 what = Tcl_GetStringFromObj(objv[1], NULL);
462 if (strcmp(what, "list") == 0)
463 {
464 FOR_ALL_WINDOWS(win)
465 {
466 string = tclgetwindow(interp, win);
467 if (string == NULL)
468 return TCL_ERROR;
469 Tcl_AppendElement(interp, string);
470 }
471 return TCL_OK;
472 }
473 Tcl_SetResult(interp, _("unknown option"), TCL_STATIC);
474 return TCL_ERROR;
475}
476
477/*
478 * flags for bufselfcmd and winselfcmd to indicate outstanding actions.
479 */
480#define FL_UPDATE_SCREEN (1<<0)
481#define FL_UPDATE_CURBUF (1<<1)
482#define FL_ADJUST_CURSOR (1<<2)
483
484/*
485 * This function implements the buffer commands.
486 */
487 static int
488bufselfcmd(ref, interp, objc, objv)
489 ClientData ref;
490 Tcl_Interp *interp;
491 int objc;
492 Tcl_Obj *CONST objv[];
493{
494 int opt, err, idx, flags;
495 int val1, val2, n, i;
496 buf_T *buf, *savebuf;
497 win_T *win, *savewin;
498 Tcl_Obj *resobj;
499 pos_T *pos;
500 char *line;
501
502 enum
503 {
504 BUF_APPEND, BUF_COMMAND, BUF_COUNT, BUF_DELCMD, BUF_DELETE, BUF_EXPR,
505 BUF_GET, BUF_INSERT, BUF_LAST, BUF_MARK, BUF_NAME, BUF_NUMBER,
506 BUF_OPTION, BUF_SET, BUF_WINDOWS
507 };
Bram Moolenaar7df2d662005-01-25 22:18:08 +0000508 static CONST84 char *bufoptions[] =
Bram Moolenaar071d4272004-06-13 20:20:40 +0000509 {
510 "append", "command", "count", "delcmd", "delete", "expr",
511 "get", "insert", "last", "mark", "name", "number",
512 "option", "set", "windows", (char *)0
513 };
514
515 if (objc < 2)
516 {
517 Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
518 return TCL_ERROR;
519 }
520
521 err = Tcl_GetIndexFromObj(interp, objv[1], bufoptions, "option", 0, &idx);
522 if (err != TCL_OK)
523 return err;
524
525 buf = (buf_T *)((struct ref *)ref)->vimobj;
526 savebuf = curbuf; curbuf = buf;
527 savewin = curwin; curwin = tclfindwin(buf);
528 flags = 0;
529 opt = 0;
530
531 switch (idx)
532 {
533 case BUF_COMMAND:
534 err = tcldoexcommand(interp, objc, objv, 2);
535 flags |= FL_UPDATE_SCREEN;
536 break;
537
538 case BUF_OPTION:
539 err = tclsetoption(interp, objc, objv, 2);
540 flags |= FL_UPDATE_SCREEN;
541 break;
542
543 case BUF_EXPR:
544 err = tclvimexpr(interp, objc, objv, 2);
545 break;
546
547 case BUF_NAME:
548 /*
549 * Get filename of buffer.
550 */
551 if (objc != 2)
552 {
553 Tcl_WrongNumArgs(interp, 2, objv, NULL);
554 err = TCL_ERROR;
555 break;
556 }
557 if (buf->b_ffname)
558 Tcl_SetResult(interp, (char *)buf->b_ffname, TCL_VOLATILE);
559 else
560 Tcl_SetResult(interp, "", TCL_STATIC);
561 break;
562
563 case BUF_LAST:
564 /*
565 * Get line number of last line.
566 */
567 opt = 1;
568 /* fallthrough */
569 case BUF_COUNT:
570 /*
571 * Get number of lines in buffer.
572 */
573 if (objc != 2)
574 {
575 Tcl_WrongNumArgs(interp, 2, objv, NULL);
576 err = TCL_ERROR;
577 break;
578 }
579 val1 = (int)buf->b_ml.ml_line_count;
580 if (opt)
581 val1 = row2tcl(val1);
582
583 resobj = Tcl_NewIntObj(val1);
584 Tcl_SetObjResult(interp, resobj);
585 break;
586
587 case BUF_NUMBER:
588 /*
589 * Get buffer's number.
590 */
591 if (objc != 2)
592 {
593 Tcl_WrongNumArgs(interp, 2, objv, NULL);
594 err = TCL_ERROR;
595 break;
596 }
597 resobj = Tcl_NewIntObj((int)buf->b_fnum);
598 Tcl_SetObjResult(interp, resobj);
599 break;
600
601 case BUF_GET:
602 if (objc != 3 && objc != 4)
603 {
604 Tcl_WrongNumArgs(interp, 2, objv, "lineNumber ?lineNumber?");
605 err = TCL_ERROR;
606 break;
607 }
608 err = tclgetlinenum(interp, objv[2], &val1, buf);
609 if (err != TCL_OK)
610 break;
611 if (objc == 4)
612 {
613 err = tclgetlinenum(interp, objv[3], &val2, buf);
614 if (err != TCL_OK)
615 break;
616 if (val1 > val2)
617 {
618 n = val1; val1 = val2; val2 = n;
619 }
620 Tcl_ResetResult(interp);
621
622 for (n = val1; n <= val2 && err == TCL_OK; n++)
623 {
624 line = (char *)ml_get_buf(buf, (linenr_T)n, FALSE);
625 if (line)
626 Tcl_AppendElement(interp, line);
627 else
628 err = TCL_ERROR;
629 }
630 }
631 else { /* objc == 3 */
632 line = (char *)ml_get_buf(buf, (linenr_T)val1, FALSE);
633 Tcl_SetResult(interp, line, TCL_VOLATILE);
634 }
635 break;
636
637 case BUF_SET:
638 if (objc != 4 && objc != 5)
639 {
640 Tcl_WrongNumArgs(interp, 3, objv, "lineNumber ?lineNumber? stringOrList");
641 err = TCL_ERROR;
642 break;
643 }
644 err = tclgetlinenum(interp, objv[2], &val1, buf);
645 if (err != TCL_OK)
646 return TCL_ERROR;
647 if (objc == 4)
648 {
649 /*
650 * Replace one line with a string.
651 * $buf set {n} {string}
652 */
653 line = Tcl_GetStringFromObj(objv[3], NULL);
654 if (u_savesub((linenr_T)val1) != OK)
655 {
656 Tcl_SetResult(interp, _("cannot save undo information"), TCL_STATIC);
657 err = TCL_ERROR;
658 }
659 else
660 if (ml_replace((linenr_T)val1, (char_u *)line, TRUE) != OK)
661 {
662 Tcl_SetResult(interp, _("cannot replace line"), TCL_STATIC);
663 err = TCL_ERROR;
664 }
665 else
666 {
667 changed_bytes((linenr_T)val1, 0);
668 flags |= FL_UPDATE_CURBUF;
669 }
670 break;
671 }
672 else
673 {
674 /*
675 * Replace several lines with the elements of a Tcl list.
676 * $buf set {n} {m} {list}
677 * If the list contains more than {m}-{n}+1 elements, they
678 * are * inserted after line {m}. If the list contains fewer
679 * elements, * the lines from {n}+length({list}) through {m}
680 * are deleted.
681 */
682 int lc;
683 Tcl_Obj **lv;
684
685 err = tclgetlinenum(interp, objv[3], &val2, buf);
686 if (err != TCL_OK)
687 break;
688 err = Tcl_ListObjGetElements(interp, objv[4], &lc, &lv);
689 if (err != TCL_OK)
690 break;
691 if (val1 > val2)
692 {
693 n = val1;
694 val1 = val2;
695 val2 = n;
696 }
697
698 n = val1;
699 if (u_save((linenr_T)(val1 - 1), (linenr_T)(val2 + 1)) != OK)
700 {
701 Tcl_SetResult(interp, _("cannot save undo information"),
702 TCL_STATIC);
703 err = TCL_ERROR;
704 break;
705 }
706 flags |= FL_UPDATE_CURBUF;
707
708 for (i = 0; i < lc && n <= val2; i++)
709 {
710 line = Tcl_GetStringFromObj(lv[i], NULL);
711 if (ml_replace((linenr_T)n, (char_u *)line, TRUE) != OK)
712 goto setListError;
713 ++n;
714 }
715 if (i < lc)
716 {
717 /* append lines */
718 do
719 {
720 line = Tcl_GetStringFromObj(lv[i], NULL);
721 if (ml_append((linenr_T)(n - 1),
722 (char_u *)line, 0, FALSE) != OK)
723 goto setListError;
724 ++n;
725 ++i;
726 } while (i < lc);
727 }
728 else if (n <= val2)
729 {
730 /* did not replace all lines, delete */
731 i = n;
732 do
733 {
734 if (ml_delete((linenr_T)i, FALSE) != OK)
735 goto setListError;
736 ++n;
737 } while (n <= val2);
738 }
739 lc -= val2 - val1 + 1; /* number of lines to be replaced */
740 mark_adjust((linenr_T)val1, (linenr_T)val2, (long)MAXLNUM,
741 (long)lc);
742 changed_lines((linenr_T)val1, 0, (linenr_T)val2 + 1, (long)lc);
743 break;
744 setListError:
745 u_undo(1); /* ??? */
746 Tcl_SetResult(interp, _("cannot set line(s)"), TCL_STATIC);
747 err = TCL_ERROR;
748 }
749 break;
750
751 case BUF_DELETE:
752 if (objc != 3 && objc != 4)
753 {
754 Tcl_WrongNumArgs(interp, 3, objv, "lineNumber ?lineNumber?");
755 err = TCL_ERROR;
756 break;
757 }
758 err = tclgetlinenum(interp, objv[2], &val1, buf);
759 if (err != TCL_OK)
760 break;
761 val2 = val1;
762 if (objc == 4)
763 {
764 err = tclgetlinenum(interp, objv[3], &val2, buf);
765 if (err != TCL_OK)
766 return err;
767 if (val1 > val2)
768 {
769 i = val1; val1 = val2; val2 = i;
770 }
771 }
772 n = val2 - val1 + 1;
773 if (u_savedel((linenr_T)val1, (long)n) != OK)
774 {
775 Tcl_SetResult(interp, _("cannot save undo information"),
776 TCL_STATIC);
777 err = TCL_ERROR;
778 break;
779 }
780 for (i = 0; i < n; i++)
781 {
782 ml_delete((linenr_T)val1, FALSE);
783 err = vimerror(interp);
784 if (err != TCL_OK)
785 break;
786 }
787 if (i > 0)
788 deleted_lines_mark((linenr_T)val1, (long)i);
789 flags |= FL_ADJUST_CURSOR|FL_UPDATE_SCREEN;
790 break;
791
792 case BUF_MARK:
793 if (objc != 3)
794 {
795 Tcl_WrongNumArgs(interp, 2, objv, "markName");
796 err = TCL_ERROR;
797 break;
798 }
799 line = Tcl_GetStringFromObj(objv[2], NULL);
800
801 pos = NULL;
802 if (line[0] != '\0' && line[1] == '\0')
803 {
804 pos = getmark(line[0], FALSE);
805 }
806 if (pos == NULL)
807 {
808 Tcl_SetResult(interp, _("invalid mark name"), TCL_STATIC);
809 err = TCL_ERROR;
810 break;
811 }
812 err = vimerror(interp);
813 if (err != TCL_OK)
814 break;
815 if (pos->lnum <= 0)
816 {
817 Tcl_SetResult(interp, _("mark not set"), TCL_STATIC);
818 err = TCL_ERROR;
819 }
820 else
821 {
822 char rbuf[64];
Bram Moolenaar555b2802005-05-19 21:08:39 +0000823
824 sprintf(rbuf, _("row %d column %d"),
825 (int)row2tcl(pos->lnum), (int)col2tcl(pos->col));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000826 Tcl_SetResult(interp, rbuf, TCL_VOLATILE);
827 }
828 break;
829
830 case BUF_INSERT:
831 opt = 1;
832 /* fallthrough */
833 case BUF_APPEND:
834 if (objc != 4)
835 {
836 Tcl_WrongNumArgs(interp, 2, objv, "lineNum text");
837 err = TCL_ERROR;
838 break;
839 }
840 err = tclgetlinenum(interp, objv[2], &val1, buf);
841 if (err != TCL_OK)
842 break;
843 if (opt)
844 --val1;
845 if (u_save((linenr_T)val1, (linenr_T)(val1+1)) != OK)
846 {
Bram Moolenaar555b2802005-05-19 21:08:39 +0000847 Tcl_SetResult(interp, _("cannot save undo information"),
848 TCL_STATIC);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000849 err = TCL_ERROR;
850 break;
851 }
852
853 line = Tcl_GetStringFromObj(objv[3], NULL);
854 if (ml_append((linenr_T)val1, (char_u *)line, 0, FALSE) != OK)
855 {
Bram Moolenaar555b2802005-05-19 21:08:39 +0000856 Tcl_SetResult(interp, _("cannot insert/append line"),
857 TCL_STATIC);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000858 err = TCL_ERROR;
859 break;
860 }
861 appended_lines_mark((linenr_T)val1, 1L);
862 flags |= FL_UPDATE_SCREEN;
863 break;
864
865 case BUF_WINDOWS:
866 /*
867 * Return list of window commands.
868 */
869 if (objc != 2)
870 {
871 Tcl_WrongNumArgs(interp, 2, objv, NULL);
872 err = TCL_ERROR;
873 break;
874 }
875 Tcl_ResetResult(interp);
876 FOR_ALL_WINDOWS(win)
877 {
878 if (win->w_buffer == buf)
879 {
880 line = tclgetwindow(interp, win);
881 if (line != NULL)
882 Tcl_AppendElement(interp, line);
883 else
884 {
885 err = TCL_ERROR;
886 break;
887 }
888 }
889 }
890 break;
891
892 case BUF_DELCMD:
893 /*
894 * Register deletion callback.
895 * TODO: Should be able to register multiple callbacks
896 */
897 if (objc != 3)
898 {
899 Tcl_WrongNumArgs(interp, 2, objv, "command");
900 err = TCL_ERROR;
901 break;
902 }
Bram Moolenaare344bea2005-09-01 20:46:49 +0000903 err = tclsetdelcmd(interp, buf->b_tcl_ref, (void *)buf, objv[2]);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000904 break;
905
906 default:
907 Tcl_SetResult(interp, _("not implemented yet"), TCL_STATIC);
908 err = TCL_ERROR;
909 }
910
911 if (flags & FL_UPDATE_CURBUF)
912 redraw_curbuf_later(NOT_VALID);
913 curbuf = savebuf;
914 curwin = savewin;
915 if (flags & FL_ADJUST_CURSOR)
916 check_cursor();
917 if (flags & (FL_UPDATE_SCREEN | FL_UPDATE_CURBUF))
918 update_screen(NOT_VALID);
919
920 return err;
921}
922
923/*
924 * This function implements the window commands.
925 */
926 static int
927winselfcmd(ref, interp, objc, objv)
928 ClientData ref;
929 Tcl_Interp *interp;
930 int objc;
931 Tcl_Obj *CONST objv[];
932{
933 int err, idx, flags;
934 int val1, val2;
935 Tcl_Obj *resobj;
936 win_T *savewin, *win;
937 buf_T *savebuf;
938 char *str;
939
940 enum
941 {
942 WIN_BUFFER, WIN_COMMAND, WIN_CURSOR, WIN_DELCMD, WIN_EXPR,
943 WIN_HEIGHT, WIN_OPTION
944 };
Bram Moolenaar7df2d662005-01-25 22:18:08 +0000945 static CONST84 char *winoptions[] =
Bram Moolenaar071d4272004-06-13 20:20:40 +0000946 {
947 "buffer", "command", "cursor", "delcmd", "expr",
948 "height", "option", (char *)0
949 };
950
951 if (objc < 2)
952 {
953 Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
954 return TCL_ERROR;
955 }
956
957 err = Tcl_GetIndexFromObj(interp, objv[1], winoptions, "option", 0, &idx);
958 if (err != TCL_OK)
959 return TCL_ERROR;
960
961 win = (win_T *)((struct ref *)ref)->vimobj;
962 savewin = curwin; curwin = win;
963 savebuf = curbuf; curbuf = win->w_buffer;
964 flags = 0;
965
966 switch (idx)
967 {
968 case WIN_OPTION:
969 err = tclsetoption(interp, objc, objv, 2);
970 flags |= FL_UPDATE_SCREEN;
971 break;
972
973 case WIN_COMMAND:
974 err = tcldoexcommand(interp, objc, objv, 2);
975 flags |= FL_UPDATE_SCREEN;
976 break;
977
978 case WIN_EXPR:
979 err = tclvimexpr(interp, objc, objv, 2);
980 break;
981
982 case WIN_HEIGHT:
983 if (objc == 3)
984 {
985 err = Tcl_GetIntFromObj(interp, objv[2], &val1);
986 if (err != TCL_OK)
987 break;
988#ifdef FEAT_GUI
989 need_mouse_correct = TRUE;
990#endif
991 win_setheight(val1);
992 err = vimerror(interp);
993 if (err != TCL_OK)
994 break;
995 }
996 else
997 if (objc != 2)
998 {
999 Tcl_WrongNumArgs(interp, 2, objv, "?value?");
1000 err = TCL_ERROR;
1001 break;
1002 }
1003
1004 resobj = Tcl_NewIntObj((int)(win->w_height));
1005 Tcl_SetObjResult(interp, resobj);
1006 break;
1007
1008 case WIN_BUFFER:
1009 if (objc != 2)
1010 {
1011 Tcl_WrongNumArgs(interp, 2, objv, NULL);
1012 err = TCL_ERROR;
1013 break;
1014 }
1015 str = tclgetbuffer(interp, win->w_buffer);
1016 if (str)
1017 Tcl_SetResult(interp, str, TCL_VOLATILE);
1018 else
1019 err = TCL_ERROR;
1020 break;
1021
1022 case WIN_DELCMD:
1023 if (objc != 3)
1024 {
1025 Tcl_WrongNumArgs(interp, 2, objv, "command");
1026 err = TCL_ERROR;
1027 break;
1028 }
Bram Moolenaare344bea2005-09-01 20:46:49 +00001029 err = tclsetdelcmd(interp, win->w_tcl_ref, (void *)win, objv[2]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001030 break;
1031
1032 case WIN_CURSOR:
1033 if (objc > 4)
1034 {
1035 Tcl_WrongNumArgs(interp, 2, objv, "?arg1 ?arg2??");
1036 err = TCL_ERROR;
1037 break;
1038 }
1039 if (objc == 2)
1040 {
1041 char buf[64];
Bram Moolenaar555b2802005-05-19 21:08:39 +00001042
Bram Moolenaar071d4272004-06-13 20:20:40 +00001043 sprintf(buf, _("row %d column %d"), (int)row2tcl(win->w_cursor.lnum), (int)col2tcl(win->w_cursor.col));
1044 Tcl_SetResult(interp, buf, TCL_VOLATILE);
1045 break;
1046 }
1047 else if (objc == 3)
1048 {
1049 Tcl_Obj *part, *var;
1050
1051 part = Tcl_NewStringObj("row", -1);
1052 var = Tcl_ObjGetVar2(interp, objv[2], part, TCL_LEAVE_ERR_MSG);
1053 if (var == NULL)
1054 {
1055 err = TCL_ERROR;
1056 break;
1057 }
1058 err = tclgetlinenum(interp, var, &val1, win->w_buffer);
1059 if (err != TCL_OK)
1060 break;
1061 part = Tcl_NewStringObj("column", -1);
1062 var = Tcl_ObjGetVar2(interp, objv[2], part, TCL_LEAVE_ERR_MSG);
1063 if (var == NULL)
1064 {
1065 err = TCL_ERROR;
1066 break;
1067 }
1068 err = Tcl_GetIntFromObj(interp, var, &val2);
1069 if (err != TCL_OK)
1070 break;
1071 }
1072 else { /* objc == 4 */
1073 err = tclgetlinenum(interp, objv[2], &val1, win->w_buffer);
1074 if (err != TCL_OK)
1075 break;
1076 err = Tcl_GetIntFromObj(interp, objv[3], &val2);
1077 if (err != TCL_OK)
1078 break;
1079 }
1080 /* TODO: should check column */
1081 win->w_cursor.lnum = val1;
1082 win->w_cursor.col = col2vim(val2);
1083 flags |= FL_UPDATE_SCREEN;
1084 break;
1085
1086 default:
1087 Tcl_SetResult(interp, _("not implemented yet"), TCL_STATIC);
1088 break;
1089 }
1090
1091 curwin = savewin;
1092 curbuf = savebuf;
1093 if (flags & FL_UPDATE_SCREEN)
1094 update_screen(NOT_VALID);
1095
1096 return err;
1097}
1098
1099
Bram Moolenaar071d4272004-06-13 20:20:40 +00001100 static int
1101commandcmd(dummy, interp, objc, objv)
Bram Moolenaar30f9ca92009-05-22 19:08:31 +00001102 ClientData dummy UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001103 Tcl_Interp *interp;
1104 int objc;
1105 Tcl_Obj *CONST objv[];
1106{
1107 int err;
1108
1109 err = tcldoexcommand(interp, objc, objv, 1);
1110 update_screen(VALID);
1111 return err;
1112}
1113
Bram Moolenaar071d4272004-06-13 20:20:40 +00001114 static int
1115optioncmd(dummy, interp, objc, objv)
Bram Moolenaar30f9ca92009-05-22 19:08:31 +00001116 ClientData dummy UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001117 Tcl_Interp *interp;
1118 int objc;
1119 Tcl_Obj *CONST objv[];
1120{
1121 int err;
1122
1123 err = tclsetoption(interp, objc, objv, 1);
1124 update_screen(VALID);
1125 return err;
1126}
1127
Bram Moolenaar071d4272004-06-13 20:20:40 +00001128 static int
1129exprcmd(dummy, interp, objc, objv)
Bram Moolenaar30f9ca92009-05-22 19:08:31 +00001130 ClientData dummy UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001131 Tcl_Interp *interp;
1132 int objc;
1133 Tcl_Obj *CONST objv[];
1134{
1135 return tclvimexpr(interp, objc, objv, 1);
1136}
1137
1138/****************************************************************************
1139 Support functions for Tcl commands
1140 ****************************************************************************/
1141
1142/*
1143 * Get a line number from 'obj' and convert it to vim's range.
1144 */
1145 static int
1146tclgetlinenum(interp, obj, valueP, buf)
1147 Tcl_Interp *interp;
1148 Tcl_Obj *obj;
1149 int *valueP;
1150 buf_T *buf;
1151{
1152 int err, i;
1153
1154 enum { LN_BEGIN, LN_BOTTOM, LN_END, LN_FIRST, LN_LAST, LN_START, LN_TOP };
1155
Bram Moolenaar7df2d662005-01-25 22:18:08 +00001156 static CONST84 char *keyw[] =
Bram Moolenaar071d4272004-06-13 20:20:40 +00001157 {
1158 "begin", "bottom", "end", "first", "last", "start", "top", (char *)0
1159 };
1160
1161 err = Tcl_GetIndexFromObj(interp, obj, keyw, "", 0, &i);
1162 if (err == TCL_OK)
1163 {
1164 switch (i)
1165 {
1166 case LN_BEGIN:
1167 case LN_FIRST:
1168 case LN_START:
1169 case LN_TOP:
1170 *valueP = 1;
1171 break;
1172 case LN_BOTTOM:
1173 case LN_END:
1174 case LN_LAST:
1175 *valueP = buf->b_ml.ml_line_count;
1176 break;
1177 }
1178 return TCL_OK;
1179 }
1180 Tcl_ResetResult(interp);
1181
1182 err = Tcl_GetIntFromObj(interp, obj, &i);
1183 if (err != TCL_OK)
1184 return err;
1185 i = row2vim(i);
1186 if (i < 1 || i > buf->b_ml.ml_line_count)
1187 {
1188 Tcl_SetResult(interp, _("line number out of range"), TCL_STATIC);
1189 return TCL_ERROR;
1190 }
1191 *valueP = i;
1192 return TCL_OK;
1193}
1194
1195/*
1196 * Find the first window in the window list that displays the buffer.
1197 */
1198 static win_T *
1199tclfindwin(buf)
1200 buf_T *buf;
1201{
1202 win_T *win;
1203
1204 FOR_ALL_WINDOWS(win)
1205 {
1206 if (win->w_buffer == buf)
1207 return win;
1208 }
1209 return curwin; /* keep current window context */
1210}
1211
1212/*
1213 * Do-it-all function for "::vim::command", "$buf command" and "$win command".
1214 */
1215 static int
1216tcldoexcommand(interp, objc, objv, objn)
1217 Tcl_Interp *interp;
1218 int objc;
1219 Tcl_Obj *CONST objv[];
1220 int objn;
1221{
1222 tcl_info saveinfo;
1223 int err, flag, nobjs;
1224 char *arg;
1225
1226 nobjs = objc - objn;
1227 if (nobjs < 1 || nobjs > 2)
1228 {
1229 Tcl_WrongNumArgs(interp, objn, objv, "?-quiet? exCommand");
1230 return TCL_ERROR;
1231 }
1232
1233 flag = 0;
1234 if (nobjs == 2)
1235 {
1236 arg = Tcl_GetStringFromObj(objv[objn], NULL);
1237 if (strcmp(arg, "-quiet") == 0)
1238 flag = 1;
1239 else
1240 {
1241 Tcl_ResetResult(interp);
1242 Tcl_AppendResult(interp, _("unknown flag: "), arg, (char *)0);
1243 return TCL_ERROR;
1244 }
1245 ++objn;
1246 }
1247
1248 memcpy(&saveinfo, &tclinfo, sizeof(tcl_info));
1249 tclinfo.interp = NULL;
1250 tclinfo.curwin = NULL;
1251 tclinfo.curbuf = NULL;
1252
1253 arg = Tcl_GetStringFromObj(objv[objn], NULL);
1254 if (flag)
1255 ++emsg_off;
1256 do_cmdline_cmd((char_u *)arg);
1257 if (flag)
1258 --emsg_off;
1259 err = vimerror(interp);
1260
1261 /* If the ex command created a new Tcl interpreter, remove it */
1262 if (tclinfo.interp)
1263 tcldelthisinterp();
1264 memcpy(&tclinfo, &saveinfo, sizeof(tcl_info));
1265 tclupdatevars();
1266
1267 return err;
1268}
1269
1270/*
1271 * Do-it-all function for "::vim::option", "$buf option" and "$win option".
1272 */
1273 static int
1274tclsetoption(interp, objc, objv, objn)
1275 Tcl_Interp *interp;
1276 int objc;
1277 Tcl_Obj *CONST objv[];
1278 int objn;
1279{
1280 int err, nobjs, idx;
1281 char_u *option;
1282 int isnum;
1283 long lval;
1284 char_u *sval;
1285 Tcl_Obj *resobj;
1286
1287 enum { OPT_OFF, OPT_ON, OPT_TOGGLE };
Bram Moolenaar7df2d662005-01-25 22:18:08 +00001288 static CONST84 char *optkw[] = { "off", "on", "toggle", (char *)0 };
Bram Moolenaar071d4272004-06-13 20:20:40 +00001289
1290 nobjs = objc - objn;
1291 if (nobjs != 1 && nobjs != 2)
1292 {
1293 Tcl_WrongNumArgs(interp, objn, objv, "vimOption ?value?");
1294 return TCL_ERROR;
1295 }
1296
1297 option = (char_u *)Tcl_GetStringFromObj(objv[objn], NULL);
1298 ++objn;
1299 isnum = get_option_value(option, &lval, &sval, 0);
1300 err = TCL_OK;
1301 switch (isnum)
1302 {
1303 case 0:
1304 Tcl_SetResult(interp, (char *)sval, TCL_VOLATILE);
1305 vim_free(sval);
1306 break;
1307 case 1:
1308 resobj = Tcl_NewLongObj(lval);
1309 Tcl_SetObjResult(interp, resobj);
1310 break;
1311 default:
1312 Tcl_SetResult(interp, _("unknown vimOption"), TCL_STATIC);
1313 return TCL_ERROR;
1314 }
1315 if (nobjs == 2)
1316 {
1317 if (isnum)
1318 {
1319 sval = NULL; /* avoid compiler warning */
1320 err = Tcl_GetIndexFromObj(interp, objv[objn], optkw, "", 0, &idx);
1321 if (err != TCL_OK)
1322 {
1323 Tcl_ResetResult(interp);
1324 err = Tcl_GetLongFromObj(interp, objv[objn], &lval);
1325 }
1326 else
1327 switch (idx)
1328 {
1329 case OPT_ON:
1330 lval = 1;
1331 break;
1332 case OPT_OFF:
1333 lval = 0;
1334 break;
1335 case OPT_TOGGLE:
1336 lval = !lval;
1337 break;
1338 }
1339 }
1340 else
1341 sval = (char_u *)Tcl_GetStringFromObj(objv[objn], NULL);
1342 if (err == TCL_OK)
1343 {
1344 set_option_value(option, lval, sval, OPT_LOCAL);
1345 err = vimerror(interp);
1346 }
1347 }
1348 return err;
1349}
1350
1351/*
1352 * Do-it-all function for "::vim::expr", "$buf expr" and "$win expr".
1353 */
1354 static int
1355tclvimexpr(interp, objc, objv, objn)
1356 Tcl_Interp *interp;
1357 int objc;
1358 Tcl_Obj *CONST objv[];
1359 int objn;
1360{
1361#ifdef FEAT_EVAL
1362 char *expr, *str;
1363#endif
1364 int err;
1365
1366 if (objc - objn != 1)
1367 {
1368 Tcl_WrongNumArgs(interp, objn, objv, "vimExpr");
1369 return TCL_ERROR;
1370 }
1371
1372#ifdef FEAT_EVAL
1373 expr = Tcl_GetStringFromObj(objv[objn], NULL);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00001374 str = (char *)eval_to_string((char_u *)expr, NULL, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001375 if (str == NULL)
1376 Tcl_SetResult(interp, _("invalid expression"), TCL_STATIC);
1377 else
1378 Tcl_SetResult(interp, str, TCL_VOLATILE);
1379 err = vimerror(interp);
1380#else
1381 Tcl_SetResult(interp, _("expressions disabled at compile time"), TCL_STATIC);
1382 err = TCL_ERROR;
1383#endif
1384
1385 return err;
1386}
1387
1388/*
1389 * Check for internal vim errors.
1390 */
1391 static int
1392vimerror(interp)
1393 Tcl_Interp *interp;
1394{
1395 if (got_int)
1396 {
1397 Tcl_SetResult(interp, _("keyboard interrupt"), TCL_STATIC);
1398 return TCL_ERROR;
1399 }
1400 else if (did_emsg)
1401 {
1402 Tcl_SetResult(interp, _("vim error"), TCL_STATIC);
1403 return TCL_ERROR;
1404 }
1405 return TCL_OK;
1406}
1407
1408/*
1409 * Functions that handle the reference lists:
1410 * delref() - callback for Tcl's DeleteCommand
1411 * tclgetref() - find/create Tcl command for a win_T* or buf_T* object
1412 * tclgetwindow() - window frontend for tclgetref()
1413 * tclgetbuffer() - buffer frontend for tclgetref()
1414 * tclsetdelcmd() - add Tcl callback command to a vim object
1415 */
1416 static void
1417delref(cref)
1418 ClientData cref;
1419{
1420 struct ref *ref = (struct ref *)cref;
1421
1422 if (ref->delcmd)
1423 {
1424 Tcl_DecrRefCount(ref->delcmd);
1425 ref->delcmd = NULL;
1426 }
1427 ref->interp = NULL;
1428}
1429
1430 static char *
1431tclgetref(interp, refstartP, prefix, vimobj, proc)
1432 Tcl_Interp *interp;
Bram Moolenaare344bea2005-09-01 20:46:49 +00001433 void **refstartP; /* ptr to w_tcl_ref/b_tcl-ref member of
1434 win_T/buf_T struct */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001435 char *prefix; /* "win" or "buf" */
1436 void *vimobj; /* win_T* or buf_T* */
1437 Tcl_ObjCmdProc *proc; /* winselfcmd or bufselfcmd */
1438{
1439 struct ref *ref, *unused = NULL;
1440 static char name[VARNAME_SIZE];
1441 Tcl_Command cmd;
1442
1443 ref = (struct ref *)(*refstartP);
1444 if (ref == &refsdeleted)
1445 {
1446 Tcl_SetResult(interp, _("cannot create buffer/window command: object is being deleted"), TCL_STATIC);
1447 return NULL;
1448 }
1449
1450 while (ref != NULL)
1451 {
1452 if (ref->interp == interp)
1453 break;
1454 if (ref->interp == NULL)
1455 unused = ref;
1456 ref = ref->next;
1457 }
1458
1459 if (ref)
Bram Moolenaar555b2802005-05-19 21:08:39 +00001460 vim_snprintf(name, sizeof(name), "::vim::%s",
1461 Tcl_GetCommandName(interp, ref->cmd));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001462 else
1463 {
1464 if (unused)
1465 ref = unused;
1466 else
1467 {
1468 ref = (struct ref *)Tcl_Alloc(sizeof(struct ref));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001469 ref->interp = NULL;
1470 ref->next = (struct ref *)(*refstartP);
1471 (*refstartP) = (void *)ref;
1472 }
1473
1474 /* This might break on some exotic systems... */
Bram Moolenaar555b2802005-05-19 21:08:39 +00001475 vim_snprintf(name, sizeof(name), "::vim::%s_%lx",
1476 prefix, (unsigned long)vimobj);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001477 cmd = Tcl_CreateObjCommand(interp, name, proc,
1478 (ClientData)ref, (Tcl_CmdDeleteProc *)delref);
1479 if (!cmd)
1480 return NULL;
1481
1482 ref->interp = interp;
1483 ref->cmd = cmd;
1484 ref->delcmd = NULL;
1485 ref->vimobj = vimobj;
1486 }
1487 return name;
1488}
1489
1490 static char *
1491tclgetwindow(interp, win)
1492 Tcl_Interp *interp;
1493 win_T *win;
1494{
Bram Moolenaare344bea2005-09-01 20:46:49 +00001495 return tclgetref(interp, &(win->w_tcl_ref), "win", (void *)win, winselfcmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001496}
1497
1498 static char *
1499tclgetbuffer(interp, buf)
1500 Tcl_Interp *interp;
1501 buf_T *buf;
1502{
Bram Moolenaare344bea2005-09-01 20:46:49 +00001503 return tclgetref(interp, &(buf->b_tcl_ref), "buf", (void *)buf, bufselfcmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001504}
1505
1506 static int
1507tclsetdelcmd(interp, reflist, vimobj, delcmd)
1508 Tcl_Interp *interp;
1509 struct ref *reflist;
1510 void *vimobj;
1511 Tcl_Obj *delcmd;
1512{
1513 if (reflist == &refsdeleted)
1514 {
1515 Tcl_SetResult(interp, _("cannot register callback command: buffer/window is already being deleted"), TCL_STATIC);
1516 return TCL_ERROR;
1517 }
1518
1519 while (reflist != NULL)
1520 {
1521 if (reflist->interp == interp && reflist->vimobj == vimobj)
1522 {
1523 if (reflist->delcmd)
Bram Moolenaarc81e5e72007-05-05 18:24:42 +00001524 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001525 Tcl_DecrRefCount(reflist->delcmd);
Bram Moolenaarc81e5e72007-05-05 18:24:42 +00001526 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001527 Tcl_IncrRefCount(delcmd);
1528 reflist->delcmd = delcmd;
1529 return TCL_OK;
1530 }
1531 reflist = reflist->next;
1532 }
1533 /* This should never happen. Famous last word? */
1534 EMSG(_("E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim.org"));
1535 Tcl_SetResult(interp, _("cannot register callback command: buffer/window reference not found"), TCL_STATIC);
1536 return TCL_ERROR;
1537}
1538
1539
1540/*******************************************
1541 I/O Channel
1542********************************************/
1543
Bram Moolenaar071d4272004-06-13 20:20:40 +00001544 static int
1545channel_close(instance, interp)
1546 ClientData instance;
Bram Moolenaar30f9ca92009-05-22 19:08:31 +00001547 Tcl_Interp *interp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001548{
1549 int err = 0;
1550
1551 /* currently does nothing */
1552
1553 if (instance != VIMOUT && instance != VIMERR)
1554 {
1555 Tcl_SetErrno(EBADF);
1556 err = EBADF;
1557 }
1558 return err;
1559}
1560
Bram Moolenaar071d4272004-06-13 20:20:40 +00001561 static int
1562channel_input(instance, buf, bufsiz, errptr)
Bram Moolenaar30f9ca92009-05-22 19:08:31 +00001563 ClientData instance UNUSED;
1564 char *buf UNUSED;
1565 int bufsiz UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001566 int *errptr;
1567{
1568
1569 /* input is currently not supported */
1570
1571 Tcl_SetErrno(EINVAL);
1572 if (errptr)
1573 *errptr = EINVAL;
1574 return -1;
1575}
1576
1577 static int
1578channel_output(instance, buf, bufsiz, errptr)
1579 ClientData instance;
1580 char *buf;
1581 int bufsiz;
1582 int *errptr;
1583{
1584 char_u *str;
1585 int result;
1586
1587 /* The buffer is not guaranteed to be 0-terminated, and we don't if
1588 * there is enough room to add a '\0'. So we have to create a copy
1589 * of the buffer...
1590 */
1591 str = vim_strnsave((char_u *)buf, bufsiz);
1592 if (!str)
1593 {
1594 Tcl_SetErrno(ENOMEM);
1595 if (errptr)
1596 *errptr = ENOMEM;
1597 return -1;
1598 }
1599
1600 result = bufsiz;
1601 if (instance == VIMOUT)
1602 tclmsg((char *)str);
1603 else
1604 if (instance == VIMERR)
1605 tclerrmsg((char *)str);
1606 else
1607 {
1608 Tcl_SetErrno(EBADF);
1609 if (errptr)
1610 *errptr = EBADF;
1611 result = -1;
1612 }
1613 vim_free(str);
1614 return result;
1615}
1616
Bram Moolenaar071d4272004-06-13 20:20:40 +00001617 static void
1618channel_watch(instance, mask)
Bram Moolenaar30f9ca92009-05-22 19:08:31 +00001619 ClientData instance UNUSED;
1620 int mask UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001621{
1622 Tcl_SetErrno(EINVAL);
1623}
1624
Bram Moolenaar071d4272004-06-13 20:20:40 +00001625 static int
1626channel_gethandle(instance, direction, handleptr)
Bram Moolenaar30f9ca92009-05-22 19:08:31 +00001627 ClientData instance UNUSED;
1628 int direction UNUSED;
1629 ClientData *handleptr UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001630{
1631 Tcl_SetErrno(EINVAL);
1632 return EINVAL;
1633}
1634
1635
1636static Tcl_ChannelType channel_type =
1637{
Bram Moolenaara41b1392009-05-23 12:28:15 +00001638 "vimmessage", /* typeName */
Bram Moolenaar84a4c332012-02-22 16:01:56 +01001639 TCL_CHANNEL_VERSION_2, /* version */
Bram Moolenaara41b1392009-05-23 12:28:15 +00001640 channel_close, /* closeProc */
1641 channel_input, /* inputProc */
1642 channel_output, /* outputProc */
1643 NULL, /* seekProc */
1644 NULL, /* setOptionProc */
1645 NULL, /* getOptionProc */
1646 channel_watch, /* watchProc */
1647 channel_gethandle, /* getHandleProc */
1648 NULL, /* close2Proc */
1649 NULL, /* blockModeProc */
1650#ifdef TCL_CHANNEL_VERSION_2
1651 NULL, /* flushProc */
1652 NULL, /* handlerProc */
1653#endif
Bram Moolenaar84a4c332012-02-22 16:01:56 +01001654/* The following should not be necessary since TCL_CHANNEL_VERSION_2 was
1655 * set above */
Bram Moolenaara41b1392009-05-23 12:28:15 +00001656#ifdef TCL_CHANNEL_VERSION_3
1657 NULL, /* wideSeekProc */
1658#endif
1659#ifdef TCL_CHANNEL_VERSION_4
1660 NULL, /* threadActionProc */
1661#endif
1662#ifdef TCL_CHANNEL_VERSION_5
1663 NULL /* truncateProc */
1664#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001665};
1666
1667/**********************************
1668 Interface to vim
1669 **********************************/
1670
1671 static void
1672tclupdatevars()
1673{
1674 char varname[VARNAME_SIZE]; /* must be writeable */
1675 char *name;
1676
1677 strcpy(varname, VAR_RANGE1);
1678 Tcl_UpdateLinkedVar(tclinfo.interp, varname);
1679 strcpy(varname, VAR_RANGE2);
1680 Tcl_UpdateLinkedVar(tclinfo.interp, varname);
1681 strcpy(varname, VAR_RANGE3);
1682 Tcl_UpdateLinkedVar(tclinfo.interp, varname);
1683
1684 strcpy(varname, VAR_LBASE);
1685 Tcl_UpdateLinkedVar(tclinfo.interp, varname);
1686
1687 name = tclgetbuffer(tclinfo.interp, curbuf);
1688 strcpy(tclinfo.curbuf, name);
1689 strcpy(varname, VAR_CURBUF);
1690 Tcl_UpdateLinkedVar(tclinfo.interp, varname);
1691
1692 name = tclgetwindow(tclinfo.interp, curwin);
1693 strcpy(tclinfo.curwin, name);
1694 strcpy(varname, VAR_CURWIN);
1695 Tcl_UpdateLinkedVar(tclinfo.interp, varname);
1696}
1697
1698
1699 static int
1700tclinit(eap)
1701 exarg_T *eap;
1702{
1703 char varname[VARNAME_SIZE]; /* Tcl_LinkVar requires writeable varname */
1704 char *name;
1705
1706#ifdef DYNAMIC_TCL
1707 if (!tcl_enabled(TRUE))
1708 {
1709 EMSG(_("E571: Sorry, this command is disabled: the Tcl library could not be loaded."));
1710 return FAIL;
1711 }
1712#endif
1713
1714 if (!tclinfo.interp)
1715 {
1716 Tcl_Interp *interp;
1717 static Tcl_Channel ch1, ch2;
1718
Bram Moolenaar84a4c332012-02-22 16:01:56 +01001719 /* Create replacement channels for stdout and stderr; this has to be
1720 * done each time an interpreter is created since the channels are closed
1721 * when the interpreter is deleted */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001722 ch1 = Tcl_CreateChannel(&channel_type, "vimout", VIMOUT, TCL_WRITABLE);
1723 ch2 = Tcl_CreateChannel(&channel_type, "vimerr", VIMERR, TCL_WRITABLE);
1724 Tcl_SetStdChannel(ch1, TCL_STDOUT);
1725 Tcl_SetStdChannel(ch2, TCL_STDERR);
1726
1727 interp = Tcl_CreateInterp();
1728 Tcl_Preserve(interp);
1729 if (Tcl_Init(interp) == TCL_ERROR)
1730 {
1731 Tcl_Release(interp);
1732 Tcl_DeleteInterp(interp);
1733 return FAIL;
1734 }
1735#if 0
1736 /* VIM sure is interactive */
1737 Tcl_SetVar(interp, "tcl_interactive", "1", TCL_GLOBAL_ONLY);
1738#endif
1739
1740 Tcl_SetChannelOption(interp, ch1, "-buffering", "line");
Bram Moolenaar84a4c332012-02-22 16:01:56 +01001741#ifdef WIN3264
1742 Tcl_SetChannelOption(interp, ch1, "-translation", "lf");
1743#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001744 Tcl_SetChannelOption(interp, ch2, "-buffering", "line");
Bram Moolenaar84a4c332012-02-22 16:01:56 +01001745#ifdef WIN3264
1746 Tcl_SetChannelOption(interp, ch2, "-translation", "lf");
1747#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001748
Bram Moolenaar84a4c332012-02-22 16:01:56 +01001749 /* replace standard Tcl exit command */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001750 Tcl_DeleteCommand(interp, "exit");
1751 Tcl_CreateObjCommand(interp, "exit", exitcmd,
1752 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001753
1754 /* new commands, in ::vim namespace */
1755 Tcl_CreateObjCommand(interp, "::vim::buffer", buffercmd,
1756 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
1757 Tcl_CreateObjCommand(interp, "::vim::window", windowcmd,
1758 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
1759 Tcl_CreateObjCommand(interp, "::vim::command", commandcmd,
1760 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
1761 Tcl_CreateObjCommand(interp, "::vim::beep", beepcmd,
1762 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
1763 Tcl_CreateObjCommand(interp, "::vim::option", optioncmd,
1764 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
1765 Tcl_CreateObjCommand(interp, "::vim::expr", exprcmd,
1766 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
1767
1768 /* "lbase" variable */
1769 tclinfo.lbase = 1;
1770 strcpy(varname, VAR_LBASE);
1771 Tcl_LinkVar(interp, varname, (char *)&tclinfo.lbase, TCL_LINK_INT);
1772
1773 /* "range" variable */
1774 tclinfo.range_start = eap->line1;
1775 strcpy(varname, VAR_RANGE1);
1776 Tcl_LinkVar(interp, varname, (char *)&tclinfo.range_start, TCL_LINK_INT|TCL_LINK_READ_ONLY);
1777 strcpy(varname, VAR_RANGE2);
1778 Tcl_LinkVar(interp, varname, (char *)&tclinfo.range_start, TCL_LINK_INT|TCL_LINK_READ_ONLY);
1779 tclinfo.range_end = eap->line2;
1780 strcpy(varname, VAR_RANGE3);
1781 Tcl_LinkVar(interp, varname, (char *)&tclinfo.range_end, TCL_LINK_INT|TCL_LINK_READ_ONLY);
1782
1783 /* "current" variable */
1784 tclinfo.curbuf = Tcl_Alloc(VARNAME_SIZE);
1785 tclinfo.curwin = Tcl_Alloc(VARNAME_SIZE);
1786 name = tclgetbuffer(interp, curbuf);
1787 strcpy(tclinfo.curbuf, name);
1788 strcpy(varname, VAR_CURBUF);
1789 Tcl_LinkVar(interp, varname, (char *)&tclinfo.curbuf, TCL_LINK_STRING|TCL_LINK_READ_ONLY);
1790 name = tclgetwindow(interp, curwin);
1791 strcpy(tclinfo.curwin, name);
1792 strcpy(varname, VAR_CURWIN);
1793 Tcl_LinkVar(interp, varname, (char *)&tclinfo.curwin, TCL_LINK_STRING|TCL_LINK_READ_ONLY);
1794
1795 tclinfo.interp = interp;
1796 }
1797 else
1798 {
1799 /* Interpreter already exists, just update variables */
1800 tclinfo.range_start = row2tcl(eap->line1);
1801 tclinfo.range_end = row2tcl(eap->line2);
1802 tclupdatevars();
1803 }
Bram Moolenaar84a4c332012-02-22 16:01:56 +01001804
1805 tclinfo.exitvalue = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001806 return OK;
1807}
1808
1809 static void
1810tclerrmsg(text)
1811 char *text;
1812{
1813 char *next;
1814
1815 while ((next=strchr(text, '\n')))
1816 {
1817 *next++ = '\0';
1818 EMSG(text);
1819 text = next;
1820 }
1821 if (*text)
1822 EMSG(text);
1823}
1824
1825 static void
1826tclmsg(text)
1827 char *text;
1828{
1829 char *next;
1830
1831 while ((next=strchr(text, '\n')))
1832 {
1833 *next++ = '\0';
1834 MSG(text);
1835 text = next;
1836 }
1837 if (*text)
1838 MSG(text);
1839}
1840
1841 static void
1842tcldelthisinterp()
1843{
1844 if (!Tcl_InterpDeleted(tclinfo.interp))
1845 Tcl_DeleteInterp(tclinfo.interp);
1846 Tcl_Release(tclinfo.interp);
1847 /* The interpreter is now gets deleted. All registered commands (esp.
1848 * window and buffer commands) are deleted, triggering their deletion
1849 * callback, which deletes all refs pointing to this interpreter.
1850 * We could garbage-collect the unused ref structs in all windows and
1851 * buffers, but unless the user creates hundreds of sub-interpreters
Bram Moolenaarb8017e72007-05-10 18:59:07 +00001852 * all referring to lots of windows and buffers, this is hardly worth
Bram Moolenaar071d4272004-06-13 20:20:40 +00001853 * the effort. Unused refs are recycled by other interpreters, and
1854 * all refs are free'd when the window/buffer gets closed by vim.
1855 */
1856
1857 tclinfo.interp = NULL;
1858 Tcl_Free(tclinfo.curbuf);
1859 Tcl_Free(tclinfo.curwin);
1860 tclinfo.curbuf = tclinfo.curwin = NULL;
1861}
1862
1863 static int
1864tclexit(error)
1865 int error;
1866{
1867 int newerr = OK;
1868
Bram Moolenaar84a4c332012-02-22 16:01:56 +01001869 if (Tcl_InterpDeleted(tclinfo.interp) /* True if we intercepted Tcl's exit command */
1870#if (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 5) || TCL_MAJOR_VERSION > 8
1871 || Tcl_LimitExceeded(tclinfo.interp) /* True if the interpreter cannot continue */
1872#endif
1873 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00001874 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00001875 char buf[50];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001876
Bram Moolenaar84a4c332012-02-22 16:01:56 +01001877 sprintf(buf, _("E572: exit code %d"), tclinfo.exitvalue);
1878 tclerrmsg(buf);
1879 if (tclinfo.exitvalue == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001880 {
Bram Moolenaar84a4c332012-02-22 16:01:56 +01001881 did_emsg = 0;
1882 newerr = OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001883 }
1884 else
Bram Moolenaar84a4c332012-02-22 16:01:56 +01001885 newerr = FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001886
1887 tcldelthisinterp();
1888 }
1889 else
1890 {
1891 char *result;
1892
Bram Moolenaar7df2d662005-01-25 22:18:08 +00001893 result = (char *)Tcl_GetStringResult(tclinfo.interp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001894 if (error == TCL_OK)
1895 {
1896 tclmsg(result);
1897 newerr = OK;
1898 }
1899 else
1900 {
1901 tclerrmsg(result);
1902 newerr = FAIL;
1903 }
1904 }
1905
1906 return newerr;
1907}
1908
1909/*
1910 * ":tcl"
1911 */
1912 void
1913ex_tcl(eap)
1914 exarg_T *eap;
1915{
1916 char_u *script;
1917 int err;
1918
1919 script = script_get(eap, eap->arg);
1920 if (!eap->skip)
1921 {
1922 err = tclinit(eap);
1923 if (err == OK)
1924 {
1925 Tcl_AllowExceptions(tclinfo.interp);
1926 if (script == NULL)
1927 err = Tcl_Eval(tclinfo.interp, (char *)eap->arg);
1928 else
1929 err = Tcl_Eval(tclinfo.interp, (char *)script);
1930 err = tclexit(err);
1931 }
1932 }
1933 vim_free(script);
1934}
1935
1936/*
1937 * ":tclfile"
1938 */
1939 void
1940ex_tclfile(eap)
1941 exarg_T *eap;
1942{
1943 char *file = (char *)eap->arg;
1944 int err;
1945
1946 err = tclinit(eap);
1947 if (err == OK)
1948 {
1949 Tcl_AllowExceptions(tclinfo.interp);
1950 err = Tcl_EvalFile(tclinfo.interp, file);
1951 err = tclexit(err);
1952 }
1953}
1954
1955/*
1956 * ":tcldo"
1957 */
1958 void
1959ex_tcldo(eap)
1960 exarg_T *eap;
1961{
1962 char *script, *line;
1963 int err, rs, re, lnum;
1964 char var_lnum[VARNAME_SIZE]; /* must be writeable memory */
1965 char var_line[VARNAME_SIZE];
1966 linenr_T first_line = 0;
1967 linenr_T last_line = 0;
1968
1969 rs = eap->line1;
1970 re = eap->line2;
1971 script = (char *)eap->arg;
1972 strcpy(var_lnum, VAR_CURLNUM);
1973 strcpy(var_line, VAR_CURLINE);
1974
1975 err = tclinit(eap);
1976 if (err != OK)
1977 return;
1978
1979 lnum = row2tcl(rs);
1980 Tcl_LinkVar(tclinfo.interp, var_lnum, (char *)&lnum, TCL_LINK_INT|TCL_LINK_READ_ONLY);
1981 err = TCL_OK;
1982 if (u_save((linenr_T)(rs-1), (linenr_T)(re+1)) != OK)
1983 {
1984 Tcl_SetResult(tclinfo.interp, _("cannot save undo information"), TCL_STATIC);
1985 err = TCL_ERROR;
1986 }
1987 while (err == TCL_OK && rs <= re)
1988 {
1989 line = (char *)ml_get_buf(curbuf, (linenr_T)rs, FALSE);
1990 if (!line)
1991 {
1992 Tcl_SetResult(tclinfo.interp, _("cannot get line"), TCL_STATIC);
1993 err = TCL_ERROR;
1994 break;
1995 }
1996 Tcl_SetVar(tclinfo.interp, var_line, line, 0);
1997 Tcl_AllowExceptions(tclinfo.interp);
1998 err = Tcl_Eval(tclinfo.interp, script);
Bram Moolenaar84a4c332012-02-22 16:01:56 +01001999 if (err != TCL_OK
2000 || Tcl_InterpDeleted(tclinfo.interp)
2001#if (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 5) || TCL_MAJOR_VERSION > 8
2002 || Tcl_LimitExceeded(tclinfo.interp)
2003#endif
2004 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00002005 break;
Bram Moolenaar7df2d662005-01-25 22:18:08 +00002006 line = (char *)Tcl_GetVar(tclinfo.interp, var_line, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002007 if (line)
2008 {
2009 if (ml_replace((linenr_T)rs, (char_u *)line, TRUE) != OK)
2010 {
2011 Tcl_SetResult(tclinfo.interp, _("cannot replace line"), TCL_STATIC);
2012 err = TCL_ERROR;
2013 break;
2014 }
2015 if (first_line == 0)
2016 first_line = rs;
2017 last_line = rs;
2018 }
2019 ++rs;
2020 ++lnum;
2021 Tcl_UpdateLinkedVar(tclinfo.interp, var_lnum);
2022 }
2023 if (first_line)
2024 changed_lines(first_line, 0, last_line + 1, (long)0);
2025
2026 Tcl_UnsetVar(tclinfo.interp, var_line, 0);
2027 Tcl_UnlinkVar(tclinfo.interp, var_lnum);
2028 if (err == TCL_OK)
2029 Tcl_ResetResult(tclinfo.interp);
2030
2031 (void)tclexit(err);
2032}
2033
2034 static void
2035tcldelallrefs(ref)
2036 struct ref *ref;
2037{
2038 struct ref *next;
2039 int err;
2040 char *result;
2041
2042 while (ref != NULL)
2043 {
2044 next = ref->next;
2045 if (ref->interp)
2046 {
2047 if (ref->delcmd)
2048 {
2049 err = Tcl_GlobalEvalObj(ref->interp, ref->delcmd);
2050 if (err != TCL_OK)
2051 {
Bram Moolenaar7df2d662005-01-25 22:18:08 +00002052 result = (char *)Tcl_GetStringResult(ref->interp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002053 if (result)
2054 tclerrmsg(result);
2055 }
2056 Tcl_DecrRefCount(ref->delcmd);
2057 ref->delcmd = NULL;
2058 }
2059 Tcl_DeleteCommandFromToken(ref->interp, ref->cmd);
2060 }
2061 Tcl_Free((char *)ref);
2062 ref = next;
2063 }
2064}
2065
2066 void
2067tcl_buffer_free(buf)
2068 buf_T *buf;
2069{
2070 struct ref *reflist;
2071
2072#ifdef DYNAMIC_TCL
2073 if (!stubs_initialized) /* Not using Tcl, nothing to do. */
2074 return;
2075#endif
2076
Bram Moolenaare344bea2005-09-01 20:46:49 +00002077 reflist = (struct ref *)(buf->b_tcl_ref);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002078 if (reflist != &refsdeleted)
2079 {
Bram Moolenaare344bea2005-09-01 20:46:49 +00002080 buf->b_tcl_ref = (void *)&refsdeleted;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002081 tcldelallrefs(reflist);
Bram Moolenaare344bea2005-09-01 20:46:49 +00002082 buf->b_tcl_ref = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002083 }
2084}
2085
2086#if defined(FEAT_WINDOWS) || defined(PROTO)
2087 void
2088tcl_window_free(win)
2089 win_T *win;
2090{
2091 struct ref *reflist;
2092
2093#ifdef DYNAMIC_TCL
2094 if (!stubs_initialized) /* Not using Tcl, nothing to do. */
2095 return;
2096#endif
2097
Bram Moolenaare344bea2005-09-01 20:46:49 +00002098 reflist = (struct ref*)(win->w_tcl_ref);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002099 if (reflist != &refsdeleted)
2100 {
Bram Moolenaare344bea2005-09-01 20:46:49 +00002101 win->w_tcl_ref = (void *)&refsdeleted;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002102 tcldelallrefs(reflist);
Bram Moolenaare344bea2005-09-01 20:46:49 +00002103 win->w_tcl_ref = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002104 }
2105}
2106#endif
2107
2108/* The End */