blob: 87e0edd14f0edf0ef594a16b18ce22e197b9d4a3 [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 * Netbeans integration by David Weatherford
5 * Adopted for Win32 by Sergey Khorev
6 *
7 * Do ":help uganda" in Vim to read copying and usage conditions.
8 * Do ":help credits" in Vim to see a list of people who contributed.
9 */
10
11/*
12 * Implements client side of org.netbeans.modules.emacs editor
13 * integration protocol. Be careful! The protocol uses offsets
14 * which are *between* characters, whereas vim uses line number
15 * and column number which are *on* characters.
16 * See ":help netbeans-protocol" for explanation.
17 */
18
Bram Moolenaarc236c162008-07-13 17:41:49 +000019#if defined(MSDOS) || defined(WIN16) || defined(WIN32) || defined(_WIN64)
Bram Moolenaarff064e12008-06-09 13:10:45 +000020# include "vimio.h" /* for mch_open(), must be before vim.h */
21#endif
22
Bram Moolenaar071d4272004-06-13 20:20:40 +000023#include "vim.h"
24
25#if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
26
27/* Note: when making changes here also adjust configure.in. */
Bram Moolenaar071d4272004-06-13 20:20:40 +000028#ifdef WIN32
29# ifdef DEBUG
30# include <tchar.h> /* for _T definition for TRACEn macros */
31# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000032/* WinSock API is separated from C API, thus we can't use read(), write(),
33 * errno... */
34# define sock_errno WSAGetLastError()
Bram Moolenaarbd42a0f2009-06-16 14:57:26 +000035# undef ECONNREFUSED
Bram Moolenaar071d4272004-06-13 20:20:40 +000036# define ECONNREFUSED WSAECONNREFUSED
37# ifdef EINTR
38# undef EINTR
39# endif
40# define EINTR WSAEINTR
41# define sock_write(sd, buf, len) send(sd, buf, len, 0)
42# define sock_read(sd, buf, len) recv(sd, buf, len, 0)
43# define sock_close(sd) closesocket(sd)
44# define sleep(t) Sleep(t*1000) /* WinAPI Sleep() accepts milliseconds */
45#else
46# include <netdb.h>
47# include <netinet/in.h>
48# include <sys/socket.h>
49# ifdef HAVE_LIBGEN_H
50# include <libgen.h>
51# endif
52# define sock_errno errno
53# define sock_write(sd, buf, len) write(sd, buf, len)
54# define sock_read(sd, buf, len) read(sd, buf, len)
55# define sock_close(sd) close(sd)
56#endif
57
58#include "version.h"
59
60#define INET_SOCKETS
61
62#define GUARDED 10000 /* typenr for "guarded" annotation */
63#define GUARDEDOFFSET 1000000 /* base for "guarded" sign id's */
64
65/* The first implementation (working only with Netbeans) returned "1.1". The
66 * protocol implemented here also supports A-A-P. */
Bram Moolenaarc65c4912006-11-14 17:29:46 +000067static char *ExtEdProtocolVersion = "2.4";
Bram Moolenaar071d4272004-06-13 20:20:40 +000068
69static long pos2off __ARGS((buf_T *, pos_T *));
70static pos_T *off2pos __ARGS((buf_T *, long));
71static pos_T *get_off_or_lnum __ARGS((buf_T *buf, char_u **argp));
72static long get_buf_size __ARGS((buf_T *));
Bram Moolenaar8065d7f2010-01-19 15:13:14 +010073static int netbeans_keystring __ARGS((char_u *keystr));
74static void postpone_keycommand __ARGS((char_u *keystr));
Bram Moolenaar009b2592004-10-24 19:18:58 +000075static void special_keys __ARGS((char_u *args));
Bram Moolenaar071d4272004-06-13 20:20:40 +000076
77static void netbeans_connect __ARGS((void));
78static int getConnInfo __ARGS((char *file, char **host, char **port, char **password));
79
80static void nb_init_graphics __ARGS((void));
81static void coloncmd __ARGS((char *cmd, ...));
Bram Moolenaar8b6144b2006-02-08 09:20:24 +000082static void nb_set_curbuf __ARGS((buf_T *buf));
Bram Moolenaar071d4272004-06-13 20:20:40 +000083#ifdef FEAT_GUI_MOTIF
84static void messageFromNetbeans __ARGS((XtPointer, int *, XtInputId *));
85#endif
86#ifdef FEAT_GUI_GTK
87static void messageFromNetbeans __ARGS((gpointer, gint, GdkInputCondition));
88#endif
89static void nb_parse_cmd __ARGS((char_u *));
90static int nb_do_cmd __ARGS((int, char_u *, int, int, char_u *));
91static void nb_send __ARGS((char *buf, char *fun));
Bram Moolenaar071d4272004-06-13 20:20:40 +000092
Bram Moolenaara93fa7e2006-04-17 22:14:47 +000093#ifdef WIN64
94typedef __int64 NBSOCK;
95#else
96typedef int NBSOCK;
97#endif
98
99static NBSOCK sd = -1; /* socket fd for Netbeans connection */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000100#ifdef FEAT_GUI_MOTIF
101static XtInputId inputHandler; /* Cookie for input */
102#endif
103#ifdef FEAT_GUI_GTK
104static gint inputHandler; /* Cookie for input */
105#endif
106#ifdef FEAT_GUI_W32
107static int inputHandler = -1; /* simply ret.value of WSAAsyncSelect() */
108extern HWND s_hwnd; /* Gvim's Window handle */
109#endif
Bram Moolenaar89d40322006-08-29 15:30:07 +0000110static int r_cmdno; /* current command number for reply */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000111static int haveConnection = FALSE; /* socket is connected and
112 initialization is done */
Bram Moolenaar009b2592004-10-24 19:18:58 +0000113#ifdef FEAT_GUI_MOTIF
114static void netbeans_Xt_connect __ARGS((void *context));
Bram Moolenaardf177f62005-02-22 08:39:57 +0000115#endif
116#ifdef FEAT_GUI_GTK
Bram Moolenaar009b2592004-10-24 19:18:58 +0000117static void netbeans_gtk_connect __ARGS((void));
Bram Moolenaardf177f62005-02-22 08:39:57 +0000118#endif
119#ifdef FEAT_GUI_W32
Bram Moolenaar009b2592004-10-24 19:18:58 +0000120static void netbeans_w32_connect __ARGS((void));
Bram Moolenaar009b2592004-10-24 19:18:58 +0000121#endif
122
123static int dosetvisible = FALSE;
124
Bram Moolenaar071d4272004-06-13 20:20:40 +0000125/*
126 * Include the debugging code if wanted.
127 */
128#ifdef NBDEBUG
129# include "nbdebug.c"
130#endif
131
132/* Connect back to Netbeans process */
Bram Moolenaar009b2592004-10-24 19:18:58 +0000133#ifdef FEAT_GUI_MOTIF
134 static void
Bram Moolenaar071d4272004-06-13 20:20:40 +0000135netbeans_Xt_connect(void *context)
136{
137 netbeans_connect();
138 if (sd > 0)
139 {
140 /* tell notifier we are interested in being called
141 * when there is input on the editor connection socket
142 */
143 inputHandler = XtAppAddInput((XtAppContext)context, sd,
144 (XtPointer)(XtInputReadMask + XtInputExceptMask),
145 messageFromNetbeans, NULL);
146 }
147}
148
149 static void
150netbeans_disconnect(void)
151{
152 if (inputHandler != (XtInputId)NULL)
153 {
154 XtRemoveInput(inputHandler);
155 inputHandler = (XtInputId)NULL;
156 }
157 sd = -1;
158 haveConnection = FALSE;
Bram Moolenaard62bec82005-03-07 22:56:57 +0000159# ifdef FEAT_BEVAL
160 bevalServers &= ~BEVAL_NETBEANS;
161# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000162}
163#endif /* FEAT_MOTIF_GUI */
164
Bram Moolenaar009b2592004-10-24 19:18:58 +0000165#ifdef FEAT_GUI_GTK
166 static void
Bram Moolenaar071d4272004-06-13 20:20:40 +0000167netbeans_gtk_connect(void)
168{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000169 netbeans_connect();
170 if (sd > 0)
171 {
172 /*
173 * Tell gdk we are interested in being called when there
174 * is input on the editor connection socket
175 */
Bram Moolenaarc1e37902006-04-18 21:55:01 +0000176 inputHandler = gdk_input_add((gint)sd, (GdkInputCondition)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000177 ((int)GDK_INPUT_READ + (int)GDK_INPUT_EXCEPTION),
178 messageFromNetbeans, NULL);
179 }
180}
181
182 static void
183netbeans_disconnect(void)
184{
185 if (inputHandler != 0)
186 {
187 gdk_input_remove(inputHandler);
188 inputHandler = 0;
189 }
190 sd = -1;
191 haveConnection = FALSE;
Bram Moolenaard62bec82005-03-07 22:56:57 +0000192# ifdef FEAT_BEVAL
193 bevalServers &= ~BEVAL_NETBEANS;
194# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000195}
196#endif /* FEAT_GUI_GTK */
197
Bram Moolenaar5b625c52005-01-31 18:55:55 +0000198#if defined(FEAT_GUI_W32) || defined(PROTO)
Bram Moolenaard857f0e2005-06-21 22:37:39 +0000199 static void
Bram Moolenaar071d4272004-06-13 20:20:40 +0000200netbeans_w32_connect(void)
201{
202 netbeans_connect();
203 if (sd > 0)
204 {
205 /*
206 * Tell Windows we are interested in receiving message when there
207 * is input on the editor connection socket
208 */
209 inputHandler = WSAAsyncSelect(sd, s_hwnd, WM_NETBEANS, FD_READ);
210 }
211}
212
213 static void
214netbeans_disconnect(void)
215{
216 if (inputHandler == 0)
217 {
218 WSAAsyncSelect(sd, s_hwnd, 0, 0);
219 inputHandler = -1;
220 }
221 sd = -1;
222 haveConnection = FALSE;
Bram Moolenaard62bec82005-03-07 22:56:57 +0000223# ifdef FEAT_BEVAL
224 bevalServers &= ~BEVAL_NETBEANS;
225# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000226}
227#endif /* FEAT_GUI_W32 */
228
229#define NB_DEF_HOST "localhost"
230#define NB_DEF_ADDR "3219"
231#define NB_DEF_PASS "changeme"
232
233 static void
234netbeans_connect(void)
235{
236#ifdef INET_SOCKETS
237 struct sockaddr_in server;
238 struct hostent * host;
239# ifdef FEAT_GUI_W32
240 u_short port;
241# else
242 int port;
243#endif
244#else
245 struct sockaddr_un server;
246#endif
247 char buf[32];
248 char *hostname = NULL;
249 char *address = NULL;
250 char *password = NULL;
251 char *fname;
252 char *arg = NULL;
253
254 if (netbeansArg[3] == '=')
255 {
256 /* "-nb=fname": Read info from specified file. */
257 if (getConnInfo(netbeansArg + 4, &hostname, &address, &password)
258 == FAIL)
259 return;
260 }
261 else
262 {
263 if (netbeansArg[3] == ':')
264 /* "-nb:<host>:<addr>:<password>": get info from argument */
265 arg = netbeansArg + 4;
266 if (arg == NULL && (fname = getenv("__NETBEANS_CONINFO")) != NULL)
267 {
268 /* "-nb": get info from file specified in environment */
269 if (getConnInfo(fname, &hostname, &address, &password) == FAIL)
270 return;
271 }
272 else
273 {
274 if (arg != NULL)
275 {
276 /* "-nb:<host>:<addr>:<password>": get info from argument */
277 hostname = arg;
278 address = strchr(hostname, ':');
279 if (address != NULL)
280 {
281 *address++ = '\0';
282 password = strchr(address, ':');
283 if (password != NULL)
284 *password++ = '\0';
285 }
286 }
287
288 /* Get the missing values from the environment. */
289 if (hostname == NULL || *hostname == '\0')
290 hostname = getenv("__NETBEANS_HOST");
291 if (address == NULL)
292 address = getenv("__NETBEANS_SOCKET");
293 if (password == NULL)
294 password = getenv("__NETBEANS_VIM_PASSWORD");
295
296 /* Move values to allocated memory. */
297 if (hostname != NULL)
298 hostname = (char *)vim_strsave((char_u *)hostname);
299 if (address != NULL)
300 address = (char *)vim_strsave((char_u *)address);
301 if (password != NULL)
302 password = (char *)vim_strsave((char_u *)password);
303 }
304 }
305
306 /* Use the default when a value is missing. */
307 if (hostname == NULL || *hostname == '\0')
308 {
309 vim_free(hostname);
310 hostname = (char *)vim_strsave((char_u *)NB_DEF_HOST);
311 }
312 if (address == NULL || *address == '\0')
313 {
314 vim_free(address);
315 address = (char *)vim_strsave((char_u *)NB_DEF_ADDR);
316 }
317 if (password == NULL || *password == '\0')
318 {
319 vim_free(password);
320 password = (char *)vim_strsave((char_u *)NB_DEF_PASS);
321 }
322 if (hostname == NULL || address == NULL || password == NULL)
323 goto theend; /* out of memory */
324
325#ifdef INET_SOCKETS
326 port = atoi(address);
327
Bram Moolenaara93fa7e2006-04-17 22:14:47 +0000328 if ((sd = (NBSOCK)socket(AF_INET, SOCK_STREAM, 0)) == (NBSOCK)-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000329 {
Bram Moolenaarf2330482008-06-24 20:19:36 +0000330 nbdebug(("error in socket() in netbeans_connect()\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000331 PERROR("socket() in netbeans_connect()");
332 goto theend;
333 }
334
335 /* Get the server internet address and put into addr structure */
336 /* fill in the socket address structure and connect to server */
337 memset((char *)&server, '\0', sizeof(server));
338 server.sin_family = AF_INET;
339 server.sin_port = htons(port);
340 if ((host = gethostbyname(hostname)) == NULL)
341 {
342 if (mch_access(hostname, R_OK) >= 0)
343 {
344 /* DEBUG: input file */
345 sd = mch_open(hostname, O_RDONLY, 0);
346 goto theend;
347 }
Bram Moolenaarf2330482008-06-24 20:19:36 +0000348 nbdebug(("error in gethostbyname() in netbeans_connect()\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000349 PERROR("gethostbyname() in netbeans_connect()");
350 sd = -1;
351 goto theend;
352 }
353 memcpy((char *)&server.sin_addr, host->h_addr, host->h_length);
354#else
355 if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
356 {
Bram Moolenaarf2330482008-06-24 20:19:36 +0000357 nbdebug(("error in socket() in netbeans_connect()\n"));
358 PERROR("socket() in netbeans_connect()");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000359 goto theend;
360 }
361
362 server.sun_family = AF_UNIX;
363 strcpy(server.sun_path, address);
364#endif
365 /* Connect to server */
366 if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
367 {
368 nbdebug(("netbeans_connect: Connect failed with errno %d\n", sock_errno));
369 if (sock_errno == ECONNREFUSED)
370 {
371 sock_close(sd);
372#ifdef INET_SOCKETS
Bram Moolenaara93fa7e2006-04-17 22:14:47 +0000373 if ((sd = (NBSOCK)socket(AF_INET, SOCK_STREAM, 0)) == (NBSOCK)-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000374 {
Bram Moolenaarf2330482008-06-24 20:19:36 +0000375 nbdebug(("socket()#2 in netbeans_connect()\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000376 PERROR("socket()#2 in netbeans_connect()");
377 goto theend;
378 }
379#else
380 if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
381 {
Bram Moolenaarf2330482008-06-24 20:19:36 +0000382 nbdebug(("socket()#2 in netbeans_connect()\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000383 PERROR("socket()#2 in netbeans_connect()");
384 goto theend;
385 }
386#endif
387 if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
388 {
389 int retries = 36;
390 int success = FALSE;
391 while (retries--
392 && ((sock_errno == ECONNREFUSED) || (sock_errno == EINTR)))
393 {
394 nbdebug(("retrying...\n"));
395 sleep(5);
396 if (connect(sd, (struct sockaddr *)&server,
397 sizeof(server)) == 0)
398 {
399 success = TRUE;
400 break;
401 }
402 }
403 if (!success)
404 {
405 /* Get here when the server can't be found. */
Bram Moolenaarf2330482008-06-24 20:19:36 +0000406 nbdebug(("Cannot connect to Netbeans #2\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000407 PERROR(_("Cannot connect to Netbeans #2"));
408 getout(1);
409 }
410 }
411
412 }
413 else
414 {
Bram Moolenaarf2330482008-06-24 20:19:36 +0000415 nbdebug(("Cannot connect to Netbeans\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000416 PERROR(_("Cannot connect to Netbeans"));
417 getout(1);
418 }
419 }
420
Bram Moolenaar9c13b352005-05-19 20:53:52 +0000421 vim_snprintf(buf, sizeof(buf), "AUTH %s\n", password);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000422 nb_send(buf, "netbeans_connect");
423
424 sprintf(buf, "0:version=0 \"%s\"\n", ExtEdProtocolVersion);
425 nb_send(buf, "externaleditor_version");
426
Bram Moolenaar071d4272004-06-13 20:20:40 +0000427/* nb_init_graphics(); delay until needed */
428
429 haveConnection = TRUE;
430
431theend:
432 vim_free(hostname);
433 vim_free(address);
434 vim_free(password);
435 return;
436}
437
438/*
439 * Obtain the NetBeans hostname, port address and password from a file.
440 * Return the strings in allocated memory.
441 * Return FAIL if the file could not be read, OK otherwise (no matter what it
442 * contains).
443 */
444 static int
445getConnInfo(char *file, char **host, char **port, char **auth)
446{
447 FILE *fp;
448 char_u buf[BUFSIZ];
449 char_u *lp;
450 char_u *nl;
451#ifdef UNIX
452 struct stat st;
453
454 /*
455 * For Unix only accept the file when it's not accessible by others.
456 * The open will then fail if we don't own the file.
457 */
458 if (mch_stat(file, &st) == 0 && (st.st_mode & 0077) != 0)
459 {
Bram Moolenaarf2330482008-06-24 20:19:36 +0000460 nbdebug(("Wrong access mode for NetBeans connection info file: \"%s\"\n",
461 file));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000462 EMSG2(_("E668: Wrong access mode for NetBeans connection info file: \"%s\""),
463 file);
464 return FAIL;
465 }
466#endif
467
468 fp = mch_fopen(file, "r");
469 if (fp == NULL)
470 {
Bram Moolenaarf2330482008-06-24 20:19:36 +0000471 nbdebug(("Cannot open NetBeans connection info file\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000472 PERROR("E660: Cannot open NetBeans connection info file");
473 return FAIL;
474 }
475
476 /* Read the file. There should be one of each parameter */
477 while ((lp = (char_u *)fgets((char *)buf, BUFSIZ, fp)) != NULL)
478 {
479 if ((nl = vim_strchr(lp, '\n')) != NULL)
480 *nl = 0; /* strip off the trailing newline */
481
482 if (STRNCMP(lp, "host=", 5) == 0)
483 {
484 vim_free(*host);
485 *host = (char *)vim_strsave(&buf[5]);
486 }
487 else if (STRNCMP(lp, "port=", 5) == 0)
488 {
489 vim_free(*port);
490 *port = (char *)vim_strsave(&buf[5]);
491 }
492 else if (STRNCMP(lp, "auth=", 5) == 0)
493 {
494 vim_free(*auth);
495 *auth = (char *)vim_strsave(&buf[5]);
496 }
497 }
498 fclose(fp);
499
500 return OK;
501}
502
503
504struct keyqueue
505{
Bram Moolenaar8065d7f2010-01-19 15:13:14 +0100506 char_u *keystr;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000507 struct keyqueue *next;
508 struct keyqueue *prev;
509};
510
511typedef struct keyqueue keyQ_T;
512
513static keyQ_T keyHead; /* dummy node, header for circular queue */
514
515
516/*
517 * Queue up key commands sent from netbeans.
Bram Moolenaar8065d7f2010-01-19 15:13:14 +0100518 * We store the string, because it may depend on the global mod_mask and
519 * :nbkey doesn't have a key number.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000520 */
521 static void
Bram Moolenaar8065d7f2010-01-19 15:13:14 +0100522postpone_keycommand(char_u *keystr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000523{
524 keyQ_T *node;
525
526 node = (keyQ_T *)alloc(sizeof(keyQ_T));
Bram Moolenaar8065d7f2010-01-19 15:13:14 +0100527 if (node == NULL)
528 return; /* out of memory, drop the key */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000529
530 if (keyHead.next == NULL) /* initialize circular queue */
531 {
532 keyHead.next = &keyHead;
533 keyHead.prev = &keyHead;
534 }
535
536 /* insert node at tail of queue */
537 node->next = &keyHead;
538 node->prev = keyHead.prev;
539 keyHead.prev->next = node;
540 keyHead.prev = node;
541
Bram Moolenaar8065d7f2010-01-19 15:13:14 +0100542 node->keystr = vim_strsave(keystr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000543}
544
545/*
546 * Handle any queued-up NetBeans keycommands to be send.
547 */
548 static void
549handle_key_queue(void)
550{
Bram Moolenaar8065d7f2010-01-19 15:13:14 +0100551 int postponed = FALSE;
552
553 while (!postponed && keyHead.next && keyHead.next != &keyHead)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000554 {
555 /* first, unlink the node */
556 keyQ_T *node = keyHead.next;
557 keyHead.next = node->next;
558 node->next->prev = node->prev;
559
Bram Moolenaar8065d7f2010-01-19 15:13:14 +0100560 /* Now, send the keycommand. This may cause it to be postponed again
561 * and change keyHead. */
562 if (node->keystr != NULL)
563 postponed = !netbeans_keystring(node->keystr);
564 vim_free(node->keystr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000565
566 /* Finally, dispose of the node */
567 vim_free(node);
568 }
569}
570
571
572struct cmdqueue
573{
574 char_u *buffer;
575 struct cmdqueue *next;
576 struct cmdqueue *prev;
577};
578
579typedef struct cmdqueue queue_T;
580
581static queue_T head; /* dummy node, header for circular queue */
582
583
584/*
585 * Put the buffer on the work queue; possibly save it to a file as well.
586 */
587 static void
588save(char_u *buf, int len)
589{
590 queue_T *node;
591
592 node = (queue_T *)alloc(sizeof(queue_T));
593 if (node == NULL)
594 return; /* out of memory */
595 node->buffer = alloc(len + 1);
596 if (node->buffer == NULL)
597 {
598 vim_free(node);
599 return; /* out of memory */
600 }
601 mch_memmove(node->buffer, buf, (size_t)len);
602 node->buffer[len] = NUL;
603
604 if (head.next == NULL) /* initialize circular queue */
605 {
606 head.next = &head;
607 head.prev = &head;
608 }
609
610 /* insert node at tail of queue */
611 node->next = &head;
612 node->prev = head.prev;
613 head.prev->next = node;
614 head.prev = node;
615
616#ifdef NBDEBUG
617 {
618 static int outfd = -2;
619
620 /* possibly write buffer out to a file */
621 if (outfd == -3)
622 return;
623
624 if (outfd == -2)
625 {
626 char *file = getenv("__NETBEANS_SAVE");
627 if (file == NULL)
628 outfd = -3;
629 else
630 outfd = mch_open(file, O_WRONLY|O_CREAT|O_TRUNC, 0666);
631 }
632
633 if (outfd >= 0)
634 write(outfd, buf, len);
635 }
636#endif
637}
638
639
640/*
641 * While there's still a command in the work queue, parse and execute it.
642 */
Bram Moolenaarf2330482008-06-24 20:19:36 +0000643 void
644netbeans_parse_messages(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000645{
646 char_u *p;
647 queue_T *node;
648
Bram Moolenaarf2330482008-06-24 20:19:36 +0000649 while (head.next != NULL && head.next != &head)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000650 {
651 node = head.next;
652
653 /* Locate the first line in the first buffer. */
654 p = vim_strchr(node->buffer, '\n');
655 if (p == NULL)
656 {
657 /* Command isn't complete. If there is no following buffer,
658 * return (wait for more). If there is another buffer following,
659 * prepend the text to that buffer and delete this one. */
660 if (node->next == &head)
661 return;
Bram Moolenaarf2330482008-06-24 20:19:36 +0000662 p = alloc((unsigned)(STRLEN(node->buffer)
663 + STRLEN(node->next->buffer) + 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000664 if (p == NULL)
665 return; /* out of memory */
666 STRCPY(p, node->buffer);
667 STRCAT(p, node->next->buffer);
668 vim_free(node->next->buffer);
669 node->next->buffer = p;
670
671 /* dispose of the node and buffer */
672 head.next = node->next;
673 node->next->prev = node->prev;
674 vim_free(node->buffer);
675 vim_free(node);
676 }
677 else
678 {
679 /* There is a complete command at the start of the buffer.
680 * Terminate it with a NUL. When no more text is following unlink
681 * the buffer. Do this before executing, because new buffers can
682 * be added while busy handling the command. */
683 *p++ = NUL;
684 if (*p == NUL)
685 {
686 head.next = node->next;
687 node->next->prev = node->prev;
688 }
689
690 /* now, parse and execute the commands */
691 nb_parse_cmd(node->buffer);
692
693 if (*p == NUL)
694 {
695 /* buffer finished, dispose of the node and buffer */
696 vim_free(node->buffer);
697 vim_free(node);
698 }
699 else
700 {
701 /* more follows, move to the start */
Bram Moolenaarf2330482008-06-24 20:19:36 +0000702 STRMOVE(node->buffer, p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000703 }
704 }
705 }
706}
707
708/* Buffer size for reading incoming messages. */
709#define MAXMSGSIZE 4096
710
711/*
712 * Read and process a command from netbeans.
713 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000714#if defined(FEAT_GUI_W32) || defined(PROTO)
715/* Use this one when generating prototypes, the others are static. */
716 void
717messageFromNetbeansW32()
718#else
719# ifdef FEAT_GUI_MOTIF
720 static void
Bram Moolenaara9d45512009-05-17 21:25:42 +0000721messageFromNetbeans(XtPointer clientData UNUSED,
Bram Moolenaarb85cb212009-05-17 14:24:23 +0000722 int *unused1 UNUSED,
723 XtInputId *unused2 UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000724# endif
725# ifdef FEAT_GUI_GTK
726 static void
Bram Moolenaarb85cb212009-05-17 14:24:23 +0000727messageFromNetbeans(gpointer clientData UNUSED,
728 gint unused1 UNUSED,
729 GdkInputCondition unused2 UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000730# endif
731#endif
732{
733 static char_u *buf = NULL;
734 int len;
735 int readlen = 0;
Bram Moolenaarf2330482008-06-24 20:19:36 +0000736#ifndef FEAT_GUI_GTK
Bram Moolenaar071d4272004-06-13 20:20:40 +0000737 static int level = 0;
Bram Moolenaarf2330482008-06-24 20:19:36 +0000738#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739
740 if (sd < 0)
741 {
742 nbdebug(("messageFromNetbeans() called without a socket\n"));
743 return;
744 }
745
Bram Moolenaarf2330482008-06-24 20:19:36 +0000746#ifndef FEAT_GUI_GTK
Bram Moolenaar071d4272004-06-13 20:20:40 +0000747 ++level; /* recursion guard; this will be called from the X event loop */
Bram Moolenaarf2330482008-06-24 20:19:36 +0000748#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000749
750 /* Allocate a buffer to read into. */
751 if (buf == NULL)
752 {
753 buf = alloc(MAXMSGSIZE);
754 if (buf == NULL)
755 return; /* out of memory! */
756 }
757
758 /* Keep on reading for as long as there is something to read. */
759 for (;;)
760 {
761 len = sock_read(sd, buf, MAXMSGSIZE);
762 if (len <= 0)
763 break; /* error or nothing more to read */
764
765 /* Store the read message in the queue. */
766 save(buf, len);
767 readlen += len;
768 if (len < MAXMSGSIZE)
769 break; /* did read everything that's available */
770 }
771
772 if (readlen <= 0)
773 {
774 /* read error or didn't read anything */
775 netbeans_disconnect();
776 nbdebug(("messageFromNetbeans: Error in read() from socket\n"));
777 if (len < 0)
Bram Moolenaarf2330482008-06-24 20:19:36 +0000778 {
779 nbdebug(("read from Netbeans socket\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000780 PERROR(_("read from Netbeans socket"));
Bram Moolenaarf2330482008-06-24 20:19:36 +0000781 }
Bram Moolenaard857f0e2005-06-21 22:37:39 +0000782 return; /* don't try to parse it */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000783 }
784
Bram Moolenaar61665aa2008-12-24 11:20:53 +0000785#if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_W32)
786 /* Let the main loop handle messages. */
787# ifdef FEAT_GUI_GTK
Bram Moolenaarf2330482008-06-24 20:19:36 +0000788 if (gtk_main_level() > 0)
789 gtk_main_quit();
Bram Moolenaar61665aa2008-12-24 11:20:53 +0000790# endif
Bram Moolenaarf2330482008-06-24 20:19:36 +0000791#else
Bram Moolenaar61665aa2008-12-24 11:20:53 +0000792 /* Parse the messages now, but avoid recursion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000793 if (level == 1)
Bram Moolenaarf2330482008-06-24 20:19:36 +0000794 netbeans_parse_messages();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000795
796 --level;
Bram Moolenaarf2330482008-06-24 20:19:36 +0000797#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000798}
799
800/*
801 * Handle one NUL terminated command.
802 *
803 * format of a command from netbeans:
804 *
805 * 6:setTitle!84 "a.c"
806 *
807 * bufno
808 * colon
809 * cmd
810 * !
811 * cmdno
812 * args
813 *
814 * for function calls, the ! is replaced by a /
815 */
816 static void
817nb_parse_cmd(char_u *cmd)
818{
Bram Moolenaar349b2f62004-10-11 10:00:50 +0000819 char *verb;
820 char *q;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000821 int bufno;
822 int isfunc = -1;
823
824 if (STRCMP(cmd, "DISCONNECT") == 0)
825 {
826 /* We assume the server knows that we can safely exit! */
827 if (sd >= 0)
828 sock_close(sd);
829 /* Disconnect before exiting, Motif hangs in a Select error
830 * message otherwise. */
831 netbeans_disconnect();
832 getout(0);
833 /* NOTREACHED */
834 }
835
836 if (STRCMP(cmd, "DETACH") == 0)
837 {
838 /* The IDE is breaking the connection. */
839 if (sd >= 0)
840 sock_close(sd);
841 netbeans_disconnect();
842 return;
843 }
844
Bram Moolenaar349b2f62004-10-11 10:00:50 +0000845 bufno = strtol((char *)cmd, &verb, 10);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000846
847 if (*verb != ':')
848 {
Bram Moolenaarf2330482008-06-24 20:19:36 +0000849 nbdebug((" missing colon: %s\n", cmd));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000850 EMSG2("E627: missing colon: %s", cmd);
851 return;
852 }
853 ++verb; /* skip colon */
854
855 for (q = verb; *q; q++)
856 {
857 if (*q == '!')
858 {
859 *q++ = NUL;
860 isfunc = 0;
861 break;
862 }
863 else if (*q == '/')
864 {
865 *q++ = NUL;
866 isfunc = 1;
867 break;
868 }
869 }
870
871 if (isfunc < 0)
872 {
Bram Moolenaarf2330482008-06-24 20:19:36 +0000873 nbdebug((" missing ! or / in: %s\n", cmd));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000874 EMSG2("E628: missing ! or / in: %s", cmd);
875 return;
876 }
877
Bram Moolenaar89d40322006-08-29 15:30:07 +0000878 r_cmdno = strtol(q, &q, 10);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000879
Bram Moolenaar349b2f62004-10-11 10:00:50 +0000880 q = (char *)skipwhite((char_u *)q);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000881
Bram Moolenaar89d40322006-08-29 15:30:07 +0000882 if (nb_do_cmd(bufno, (char_u *)verb, isfunc, r_cmdno, (char_u *)q) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000883 {
Bram Moolenaar009b2592004-10-24 19:18:58 +0000884#ifdef NBDEBUG
885 /*
Bram Moolenaar2660c0e2010-01-19 14:59:56 +0100886 * This happens because the ExtEd can send a command or 2 after
Bram Moolenaar009b2592004-10-24 19:18:58 +0000887 * doing a stopDocumentListen command. It doesn't harm anything
888 * so I'm disabling it except for debugging.
889 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000890 nbdebug(("nb_parse_cmd: Command error for \"%s\"\n", cmd));
891 EMSG("E629: bad return from nb_do_cmd");
Bram Moolenaar009b2592004-10-24 19:18:58 +0000892#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000893 }
894}
895
896struct nbbuf_struct
897{
898 buf_T *bufp;
899 unsigned int fireChanges:1;
900 unsigned int initDone:1;
Bram Moolenaar009b2592004-10-24 19:18:58 +0000901 unsigned int insertDone:1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000902 unsigned int modified:1;
Bram Moolenaar009b2592004-10-24 19:18:58 +0000903 int nbbuf_number;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000904 char *displayname;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000905 int *signmap;
906 short_u signmaplen;
907 short_u signmapused;
908};
909
910typedef struct nbbuf_struct nbbuf_T;
911
912static nbbuf_T *buf_list = 0;
Bram Moolenaard857f0e2005-06-21 22:37:39 +0000913static int buf_list_size = 0; /* size of buf_list */
914static int buf_list_used = 0; /* nr of entries in buf_list actually in use */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000915
916static char **globalsignmap;
917static int globalsignmaplen;
918static int globalsignmapused;
919
920static int mapsigntype __ARGS((nbbuf_T *, int localsigntype));
921static void addsigntype __ARGS((nbbuf_T *, int localsigntype, char_u *typeName,
922 char_u *tooltip, char_u *glyphfile,
923 int usefg, int fg, int usebg, int bg));
Bram Moolenaar009b2592004-10-24 19:18:58 +0000924static void print_read_msg __ARGS((nbbuf_T *buf));
925static void print_save_msg __ARGS((nbbuf_T *buf, long nchars));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000926
927static int curPCtype = -1;
928
929/*
930 * Get the Netbeans buffer number for the specified buffer.
931 */
932 static int
933nb_getbufno(buf_T *bufp)
934{
935 int i;
936
937 for (i = 0; i < buf_list_used; i++)
938 if (buf_list[i].bufp == bufp)
939 return i;
940 return -1;
941}
942
943/*
944 * Is this a NetBeans-owned buffer?
945 */
946 int
947isNetbeansBuffer(buf_T *bufp)
948{
Bram Moolenaar009b2592004-10-24 19:18:58 +0000949 return usingNetbeans && bufp->b_netbeans_file;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000950}
951
952/*
953 * NetBeans and Vim have different undo models. In Vim, the file isn't
954 * changed if changes are undone via the undo command. In NetBeans, once
955 * a change has been made the file is marked as modified until saved. It
956 * doesn't matter if the change was undone.
957 *
958 * So this function is for the corner case where Vim thinks a buffer is
959 * unmodified but NetBeans thinks it IS modified.
960 */
961 int
962isNetbeansModified(buf_T *bufp)
963{
Bram Moolenaar009b2592004-10-24 19:18:58 +0000964 if (usingNetbeans && bufp->b_netbeans_file)
965 {
966 int bufno = nb_getbufno(bufp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000967
Bram Moolenaar009b2592004-10-24 19:18:58 +0000968 if (bufno > 0)
969 return buf_list[bufno].modified;
970 else
971 return FALSE;
972 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000973 else
974 return FALSE;
975}
976
977/*
978 * Given a Netbeans buffer number, return the netbeans buffer.
979 * Returns NULL for 0 or a negative number. A 0 bufno means a
980 * non-buffer related command has been sent.
981 */
982 static nbbuf_T *
983nb_get_buf(int bufno)
984{
985 /* find or create a buffer with the given number */
986 int incr;
987
988 if (bufno <= 0)
989 return NULL;
990
991 if (!buf_list)
992 {
993 /* initialize */
994 buf_list = (nbbuf_T *)alloc_clear(100 * sizeof(nbbuf_T));
995 buf_list_size = 100;
996 }
997 if (bufno >= buf_list_used) /* new */
998 {
999 if (bufno >= buf_list_size) /* grow list */
1000 {
1001 incr = bufno - buf_list_size + 90;
1002 buf_list_size += incr;
1003 buf_list = (nbbuf_T *)vim_realloc(
1004 buf_list, buf_list_size * sizeof(nbbuf_T));
1005 memset(buf_list + buf_list_size - incr, 0, incr * sizeof(nbbuf_T));
1006 }
1007
1008 while (buf_list_used <= bufno)
1009 {
1010 /* Default is to fire text changes. */
1011 buf_list[buf_list_used].fireChanges = 1;
1012 ++buf_list_used;
1013 }
1014 }
1015
1016 return buf_list + bufno;
1017}
1018
1019/*
1020 * Return the number of buffers that are modified.
1021 */
1022 static int
1023count_changed_buffers(void)
1024{
1025 buf_T *bufp;
1026 int n;
1027
1028 n = 0;
1029 for (bufp = firstbuf; bufp != NULL; bufp = bufp->b_next)
1030 if (bufp->b_changed)
1031 ++n;
1032 return n;
1033}
1034
1035/*
1036 * End the netbeans session.
1037 */
1038 void
1039netbeans_end(void)
1040{
1041 int i;
1042 static char buf[128];
1043
1044 if (!haveConnection)
1045 return;
1046
1047 for (i = 0; i < buf_list_used; i++)
1048 {
1049 if (!buf_list[i].bufp)
1050 continue;
1051 if (netbeansForcedQuit)
1052 {
1053 /* mark as unmodified so NetBeans won't put up dialog on "killed" */
Bram Moolenaar89d40322006-08-29 15:30:07 +00001054 sprintf(buf, "%d:unmodified=%d\n", i, r_cmdno);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001055 nbdebug(("EVT: %s", buf));
1056 nb_send(buf, "netbeans_end");
1057 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00001058 sprintf(buf, "%d:killed=%d\n", i, r_cmdno);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001059 nbdebug(("EVT: %s", buf));
1060/* nb_send(buf, "netbeans_end"); avoid "write failed" messages */
1061 if (sd >= 0)
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00001062 ignored = sock_write(sd, buf, (int)STRLEN(buf));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001063 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001064}
1065
1066/*
1067 * Send a message to netbeans.
1068 */
1069 static void
1070nb_send(char *buf, char *fun)
1071{
1072 /* Avoid giving pages full of error messages when the other side has
1073 * exited, only mention the first error until the connection works again. */
1074 static int did_error = FALSE;
1075
1076 if (sd < 0)
1077 {
1078 if (!did_error)
Bram Moolenaarf2330482008-06-24 20:19:36 +00001079 {
1080 nbdebug((" %s(): write while not connected\n", fun));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001081 EMSG2("E630: %s(): write while not connected", fun);
Bram Moolenaarf2330482008-06-24 20:19:36 +00001082 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001083 did_error = TRUE;
1084 }
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001085 else if (sock_write(sd, buf, (int)STRLEN(buf)) != (int)STRLEN(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001086 {
1087 if (!did_error)
Bram Moolenaarf2330482008-06-24 20:19:36 +00001088 {
1089 nbdebug((" %s(): write failed\n", fun));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001090 EMSG2("E631: %s(): write failed", fun);
Bram Moolenaarf2330482008-06-24 20:19:36 +00001091 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001092 did_error = TRUE;
1093 }
1094 else
1095 did_error = FALSE;
1096}
1097
1098/*
1099 * Some input received from netbeans requires a response. This function
1100 * handles a response with no information (except the command number).
1101 */
1102 static void
1103nb_reply_nil(int cmdno)
1104{
1105 char reply[32];
1106
1107 if (!haveConnection)
1108 return;
1109
Bram Moolenaar009b2592004-10-24 19:18:58 +00001110 nbdebug(("REP %d: <none>\n", cmdno));
1111
Bram Moolenaar071d4272004-06-13 20:20:40 +00001112 sprintf(reply, "%d\n", cmdno);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001113 nb_send(reply, "nb_reply_nil");
1114}
1115
1116
1117/*
1118 * Send a response with text.
1119 * "result" must have been quoted already (using nb_quote()).
1120 */
1121 static void
1122nb_reply_text(int cmdno, char_u *result)
1123{
1124 char_u *reply;
1125
1126 if (!haveConnection)
1127 return;
1128
Bram Moolenaar009b2592004-10-24 19:18:58 +00001129 nbdebug(("REP %d: %s\n", cmdno, (char *)result));
1130
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001131 reply = alloc((unsigned)STRLEN(result) + 32);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001132 sprintf((char *)reply, "%d %s\n", cmdno, (char *)result);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001133 nb_send((char *)reply, "nb_reply_text");
1134
1135 vim_free(reply);
1136}
1137
1138
1139/*
1140 * Send a response with a number result code.
1141 */
1142 static void
1143nb_reply_nr(int cmdno, long result)
1144{
1145 char reply[32];
1146
1147 if (!haveConnection)
1148 return;
1149
Bram Moolenaar009b2592004-10-24 19:18:58 +00001150 nbdebug(("REP %d: %ld\n", cmdno, result));
1151
Bram Moolenaar071d4272004-06-13 20:20:40 +00001152 sprintf(reply, "%d %ld\n", cmdno, result);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001153 nb_send(reply, "nb_reply_nr");
1154}
1155
1156
1157/*
1158 * Encode newline, ret, backslash, double quote for transmission to NetBeans.
1159 */
1160 static char_u *
1161nb_quote(char_u *txt)
1162{
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001163 char_u *buf = alloc((unsigned)(2 * STRLEN(txt) + 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001164 char_u *p = txt;
1165 char_u *q = buf;
1166
1167 if (buf == NULL)
1168 return NULL;
1169 for (; *p; p++)
1170 {
1171 switch (*p)
1172 {
1173 case '\"':
1174 case '\\':
1175 *q++ = '\\'; *q++ = *p; break;
1176 /* case '\t': */
1177 /* *q++ = '\\'; *q++ = 't'; break; */
1178 case '\n':
1179 *q++ = '\\'; *q++ = 'n'; break;
1180 case '\r':
1181 *q++ = '\\'; *q++ = 'r'; break;
1182 default:
1183 *q++ = *p;
1184 break;
1185 }
1186 }
Bram Moolenaar2660c0e2010-01-19 14:59:56 +01001187 *q = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +00001188
1189 return buf;
1190}
1191
1192
1193/*
1194 * Remove top level double quotes; convert backslashed chars.
1195 * Returns an allocated string (NULL for failure).
1196 * If "endp" is not NULL it is set to the character after the terminating
1197 * quote.
1198 */
1199 static char *
1200nb_unquote(char_u *p, char_u **endp)
1201{
1202 char *result = 0;
1203 char *q;
1204 int done = 0;
1205
1206 /* result is never longer than input */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001207 result = (char *)alloc_clear((unsigned)STRLEN(p) + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001208 if (result == NULL)
1209 return NULL;
1210
1211 if (*p++ != '"')
1212 {
1213 nbdebug(("nb_unquote called with string that doesn't start with a quote!: %s\n",
1214 p));
1215 result[0] = NUL;
1216 return result;
1217 }
1218
1219 for (q = result; !done && *p != NUL;)
1220 {
1221 switch (*p)
1222 {
1223 case '"':
1224 /*
1225 * Unbackslashed dquote marks the end, if first char was dquote.
1226 */
1227 done = 1;
1228 break;
1229
1230 case '\\':
1231 ++p;
1232 switch (*p)
1233 {
1234 case '\\': *q++ = '\\'; break;
1235 case 'n': *q++ = '\n'; break;
1236 case 't': *q++ = '\t'; break;
1237 case 'r': *q++ = '\r'; break;
1238 case '"': *q++ = '"'; break;
1239 case NUL: --p; break;
1240 /* default: skip over illegal chars */
1241 }
1242 ++p;
1243 break;
1244
1245 default:
1246 *q++ = *p++;
1247 }
1248 }
1249
1250 if (endp != NULL)
1251 *endp = p;
1252
1253 return result;
1254}
1255
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00001256/*
1257 * Remove from "first" byte to "last" byte (inclusive), at line "lnum" of the
1258 * current buffer. Remove to end of line when "last" is MAXCOL.
1259 */
1260 static void
1261nb_partialremove(linenr_T lnum, colnr_T first, colnr_T last)
1262{
1263 char_u *oldtext, *newtext;
1264 int oldlen;
1265 int lastbyte = last;
1266
1267 oldtext = ml_get(lnum);
Bram Moolenaarcb4cef22008-03-16 15:04:34 +00001268 oldlen = (int)STRLEN(oldtext);
Bram Moolenaarb3c70982008-01-18 10:40:55 +00001269 if (first >= (colnr_T)oldlen || oldlen == 0) /* just in case */
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00001270 return;
1271 if (lastbyte >= oldlen)
1272 lastbyte = oldlen - 1;
1273 newtext = alloc(oldlen - (int)(lastbyte - first));
1274 if (newtext != NULL)
1275 {
1276 mch_memmove(newtext, oldtext, first);
Bram Moolenaarf2330482008-06-24 20:19:36 +00001277 STRMOVE(newtext + first, oldtext + lastbyte + 1);
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00001278 nbdebug((" NEW LINE %d: %s\n", lnum, newtext));
1279 ml_replace(lnum, newtext, FALSE);
1280 }
1281}
1282
1283/*
1284 * Replace the "first" line with the concatenation of the "first" and
1285 * the "other" line. The "other" line is not removed.
1286 */
1287 static void
1288nb_joinlines(linenr_T first, linenr_T other)
1289{
1290 int len_first, len_other;
1291 char_u *p;
1292
Bram Moolenaarcb4cef22008-03-16 15:04:34 +00001293 len_first = (int)STRLEN(ml_get(first));
1294 len_other = (int)STRLEN(ml_get(other));
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00001295 p = alloc((unsigned)(len_first + len_other + 1));
1296 if (p != NULL)
1297 {
1298 mch_memmove(p, ml_get(first), len_first);
1299 mch_memmove(p + len_first, ml_get(other), len_other + 1);
1300 ml_replace(first, p, FALSE);
1301 }
1302}
1303
Bram Moolenaar071d4272004-06-13 20:20:40 +00001304#define SKIP_STOP 2
1305#define streq(a,b) (strcmp(a,b) == 0)
1306static int needupdate = 0;
1307static int inAtomic = 0;
1308
1309/*
1310 * Do the actual processing of a single netbeans command or function.
Bram Moolenaar143c38c2007-05-10 16:41:10 +00001311 * The difference between a command and function is that a function
1312 * gets a response (it's required) but a command does not.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001313 * For arguments see comment for nb_parse_cmd().
1314 */
1315 static int
1316nb_do_cmd(
1317 int bufno,
1318 char_u *cmd,
1319 int func,
1320 int cmdno,
1321 char_u *args) /* points to space before arguments or NUL */
1322{
1323 int doupdate = 0;
1324 long off = 0;
1325 nbbuf_T *buf = nb_get_buf(bufno);
1326 static int skip = 0;
1327 int retval = OK;
Bram Moolenaar349b2f62004-10-11 10:00:50 +00001328 char *cp; /* for when a char pointer is needed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001329
1330 nbdebug(("%s %d: (%d) %s %s\n", (func) ? "FUN" : "CMD", cmdno, bufno, cmd,
1331 STRCMP(cmd, "insert") == 0 ? "<text>" : (char *)args));
1332
1333 if (func)
1334 {
1335/* =====================================================================*/
1336 if (streq((char *)cmd, "getModified"))
1337 {
1338 if (buf == NULL || buf->bufp == NULL)
1339 /* Return the number of buffers that are modified. */
1340 nb_reply_nr(cmdno, (long)count_changed_buffers());
1341 else
1342 /* Return whether the buffer is modified. */
1343 nb_reply_nr(cmdno, (long)(buf->bufp->b_changed
1344 || isNetbeansModified(buf->bufp)));
1345/* =====================================================================*/
1346 }
1347 else if (streq((char *)cmd, "saveAndExit"))
1348 {
1349 /* Note: this will exit Vim if successful. */
1350 coloncmd(":confirm qall");
1351
1352 /* We didn't exit: return the number of changed buffers. */
1353 nb_reply_nr(cmdno, (long)count_changed_buffers());
1354/* =====================================================================*/
1355 }
1356 else if (streq((char *)cmd, "getCursor"))
1357 {
1358 char_u text[200];
1359
1360 /* Note: nb_getbufno() may return -1. This indicates the IDE
1361 * didn't assign a number to the current buffer in response to a
1362 * fileOpened event. */
1363 sprintf((char *)text, "%d %ld %d %ld",
1364 nb_getbufno(curbuf),
1365 (long)curwin->w_cursor.lnum,
1366 (int)curwin->w_cursor.col,
1367 pos2off(curbuf, &curwin->w_cursor));
1368 nb_reply_text(cmdno, text);
1369/* =====================================================================*/
1370 }
Bram Moolenaarc65c4912006-11-14 17:29:46 +00001371 else if (streq((char *)cmd, "getAnno"))
1372 {
1373 long linenum = 0;
1374#ifdef FEAT_SIGNS
1375 if (buf == NULL || buf->bufp == NULL)
1376 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001377 nbdebug((" Invalid buffer identifier in getAnno\n"));
1378 EMSG("E652: Invalid buffer identifier in getAnno");
Bram Moolenaarc65c4912006-11-14 17:29:46 +00001379 retval = FAIL;
1380 }
1381 else
1382 {
1383 int serNum;
1384
1385 cp = (char *)args;
1386 serNum = strtol(cp, &cp, 10);
1387 /* If the sign isn't found linenum will be zero. */
1388 linenum = (long)buf_findsign(buf->bufp, serNum);
1389 }
1390#endif
1391 nb_reply_nr(cmdno, linenum);
1392/* =====================================================================*/
1393 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001394 else if (streq((char *)cmd, "getLength"))
1395 {
1396 long len = 0;
1397
1398 if (buf == NULL || buf->bufp == NULL)
1399 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001400 nbdebug((" invalid buffer identifier in getLength\n"));
1401 EMSG("E632: invalid buffer identifier in getLength");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001402 retval = FAIL;
1403 }
1404 else
1405 {
1406 len = get_buf_size(buf->bufp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001407 }
1408 nb_reply_nr(cmdno, len);
1409/* =====================================================================*/
1410 }
1411 else if (streq((char *)cmd, "getText"))
1412 {
1413 long len;
1414 linenr_T nlines;
1415 char_u *text = NULL;
1416 linenr_T lno = 1;
1417 char_u *p;
1418 char_u *line;
1419
1420 if (buf == NULL || buf->bufp == NULL)
1421 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001422 nbdebug((" invalid buffer identifier in getText\n"));
1423 EMSG("E633: invalid buffer identifier in getText");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001424 retval = FAIL;
1425 }
1426 else
1427 {
1428 len = get_buf_size(buf->bufp);
1429 nlines = buf->bufp->b_ml.ml_line_count;
1430 text = alloc((unsigned)((len > 0)
1431 ? ((len + nlines) * 2) : 4));
1432 if (text == NULL)
1433 {
1434 nbdebug((" nb_do_cmd: getText has null text field\n"));
1435 retval = FAIL;
1436 }
1437 else
1438 {
1439 p = text;
1440 *p++ = '\"';
1441 for (; lno <= nlines ; lno++)
1442 {
1443 line = nb_quote(ml_get_buf(buf->bufp, lno, FALSE));
1444 if (line != NULL)
1445 {
1446 STRCPY(p, line);
1447 p += STRLEN(line);
1448 *p++ = '\\';
1449 *p++ = 'n';
Bram Moolenaar009b2592004-10-24 19:18:58 +00001450 vim_free(line);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001451 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001452 }
1453 *p++ = '\"';
1454 *p = '\0';
1455 }
1456 }
1457 if (text == NULL)
1458 nb_reply_text(cmdno, (char_u *)"");
1459 else
1460 {
1461 nb_reply_text(cmdno, text);
1462 vim_free(text);
1463 }
1464/* =====================================================================*/
1465 }
1466 else if (streq((char *)cmd, "remove"))
1467 {
1468 long count;
1469 pos_T first, last;
1470 pos_T *pos;
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00001471 pos_T *next;
1472 linenr_T del_from_lnum, del_to_lnum; /* lines to be deleted as a whole */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001473 int oldFire = netbeansFireChanges;
1474 int oldSuppress = netbeansSuppressNoLines;
1475 int wasChanged;
1476
1477 if (skip >= SKIP_STOP)
1478 {
1479 nbdebug((" Skipping %s command\n", (char *) cmd));
1480 nb_reply_nil(cmdno);
1481 return OK;
1482 }
1483
1484 if (buf == NULL || buf->bufp == NULL)
1485 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001486 nbdebug((" invalid buffer identifier in remove\n"));
1487 EMSG("E634: invalid buffer identifier in remove");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001488 retval = FAIL;
1489 }
1490 else
1491 {
1492 netbeansFireChanges = FALSE;
1493 netbeansSuppressNoLines = TRUE;
1494
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00001495 nb_set_curbuf(buf->bufp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001496 wasChanged = buf->bufp->b_changed;
Bram Moolenaar349b2f62004-10-11 10:00:50 +00001497 cp = (char *)args;
1498 off = strtol(cp, &cp, 10);
1499 count = strtol(cp, &cp, 10);
1500 args = (char_u *)cp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001501 /* delete "count" chars, starting at "off" */
1502 pos = off2pos(buf->bufp, off);
1503 if (!pos)
1504 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001505 nbdebug((" !bad position\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001506 nb_reply_text(cmdno, (char_u *)"!bad position");
1507 netbeansFireChanges = oldFire;
1508 netbeansSuppressNoLines = oldSuppress;
1509 return FAIL;
1510 }
1511 first = *pos;
Bram Moolenaarfa68b0f2009-09-11 12:19:51 +00001512 nbdebug((" FIRST POS: line %d, col %d\n",
1513 first.lnum, first.col));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001514 pos = off2pos(buf->bufp, off+count-1);
1515 if (!pos)
1516 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001517 nbdebug((" !bad count\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001518 nb_reply_text(cmdno, (char_u *)"!bad count");
1519 netbeansFireChanges = oldFire;
1520 netbeansSuppressNoLines = oldSuppress;
1521 return FAIL;
1522 }
1523 last = *pos;
Bram Moolenaarfa68b0f2009-09-11 12:19:51 +00001524 nbdebug((" LAST POS: line %d, col %d\n",
1525 last.lnum, last.col));
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00001526 del_from_lnum = first.lnum;
1527 del_to_lnum = last.lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001528 doupdate = 1;
1529
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00001530 /* Get the position of the first byte after the deleted
1531 * section. "next" is NULL when deleting to the end of the
1532 * file. */
1533 next = off2pos(buf->bufp, off + count);
1534
1535 /* Remove part of the first line. */
Bram Moolenaarfa68b0f2009-09-11 12:19:51 +00001536 if (first.col != 0
1537 || (next != NULL && first.lnum == next->lnum))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001538 {
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00001539 if (first.lnum != last.lnum
1540 || (next != NULL && first.lnum != next->lnum))
1541 {
1542 /* remove to the end of the first line */
1543 nb_partialremove(first.lnum, first.col,
1544 (colnr_T)MAXCOL);
1545 if (first.lnum == last.lnum)
1546 {
1547 /* Partial line to remove includes the end of
1548 * line. Join the line with the next one, have
1549 * the next line deleted below. */
1550 nb_joinlines(first.lnum, next->lnum);
1551 del_to_lnum = next->lnum;
1552 }
1553 }
1554 else
1555 {
1556 /* remove within one line */
1557 nb_partialremove(first.lnum, first.col, last.col);
1558 }
1559 ++del_from_lnum; /* don't delete the first line */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001560 }
1561
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00001562 /* Remove part of the last line. */
1563 if (first.lnum != last.lnum && next != NULL
1564 && next->col != 0 && last.lnum == next->lnum)
1565 {
1566 nb_partialremove(last.lnum, 0, last.col);
1567 if (del_from_lnum > first.lnum)
1568 {
1569 /* Join end of last line to start of first line; last
1570 * line is deleted below. */
1571 nb_joinlines(first.lnum, last.lnum);
1572 }
1573 else
1574 /* First line is deleted as a whole, keep the last
1575 * line. */
1576 --del_to_lnum;
1577 }
1578
1579 /* First is partial line; last line to remove includes
1580 * the end of line; join first line to line following last
1581 * line; line following last line is deleted below. */
1582 if (first.lnum != last.lnum && del_from_lnum > first.lnum
1583 && next != NULL && last.lnum != next->lnum)
1584 {
1585 nb_joinlines(first.lnum, next->lnum);
1586 del_to_lnum = next->lnum;
1587 }
1588
1589 /* Delete whole lines if there are any. */
1590 if (del_to_lnum >= del_from_lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001591 {
1592 int i;
1593
1594 /* delete signs from the lines being deleted */
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00001595 for (i = del_from_lnum; i <= del_to_lnum; i++)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001596 {
1597 int id = buf_findsign_id(buf->bufp, (linenr_T)i);
1598 if (id > 0)
1599 {
Bram Moolenaarfa68b0f2009-09-11 12:19:51 +00001600 nbdebug((" Deleting sign %d on line %d\n",
1601 id, i));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001602 buf_delsign(buf->bufp, id);
1603 }
1604 else
Bram Moolenaarb85cb212009-05-17 14:24:23 +00001605 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001606 nbdebug((" No sign on line %d\n", i));
Bram Moolenaarb85cb212009-05-17 14:24:23 +00001607 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001608 }
1609
Bram Moolenaarfa68b0f2009-09-11 12:19:51 +00001610 nbdebug((" Deleting lines %d through %d\n",
1611 del_from_lnum, del_to_lnum));
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00001612 curwin->w_cursor.lnum = del_from_lnum;
1613 curwin->w_cursor.col = 0;
1614 del_lines(del_to_lnum - del_from_lnum + 1, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001615 }
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00001616
1617 /* Leave cursor at first deleted byte. */
1618 curwin->w_cursor = first;
1619 check_cursor_lnum();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001620 buf->bufp->b_changed = wasChanged; /* logically unchanged */
1621 netbeansFireChanges = oldFire;
1622 netbeansSuppressNoLines = oldSuppress;
1623
1624 u_blockfree(buf->bufp);
1625 u_clearall(buf->bufp);
1626 }
1627 nb_reply_nil(cmdno);
1628/* =====================================================================*/
1629 }
1630 else if (streq((char *)cmd, "insert"))
1631 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001632 char_u *to_free;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001633
1634 if (skip >= SKIP_STOP)
1635 {
1636 nbdebug((" Skipping %s command\n", (char *) cmd));
1637 nb_reply_nil(cmdno);
1638 return OK;
1639 }
1640
1641 /* get offset */
Bram Moolenaar349b2f62004-10-11 10:00:50 +00001642 cp = (char *)args;
1643 off = strtol(cp, &cp, 10);
1644 args = (char_u *)cp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001645
1646 /* get text to be inserted */
1647 args = skipwhite(args);
1648 args = to_free = (char_u *)nb_unquote(args, NULL);
Bram Moolenaar009b2592004-10-24 19:18:58 +00001649 /*
1650 nbdebug((" CHUNK[%d]: %d bytes at offset %d\n",
1651 buf->bufp->b_ml.ml_line_count, STRLEN(args), off));
1652 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001653
1654 if (buf == NULL || buf->bufp == NULL)
1655 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001656 nbdebug((" invalid buffer identifier in insert\n"));
1657 EMSG("E635: invalid buffer identifier in insert");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001658 retval = FAIL;
1659 }
1660 else if (args != NULL)
1661 {
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001662 int ff_detected = EOL_UNKNOWN;
1663 int buf_was_empty = (buf->bufp->b_ml.ml_flags & ML_EMPTY);
1664 size_t len = 0;
1665 int added = 0;
1666 int oldFire = netbeansFireChanges;
1667 int old_b_changed;
1668 char_u *nl;
1669 linenr_T lnum;
1670 linenr_T lnum_start;
1671 pos_T *pos;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001672
Bram Moolenaar071d4272004-06-13 20:20:40 +00001673 netbeansFireChanges = 0;
1674
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001675 /* Jump to the buffer where we insert. After this "curbuf"
1676 * can be used. */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00001677 nb_set_curbuf(buf->bufp);
Bram Moolenaara3227e22006-03-08 21:32:40 +00001678 old_b_changed = curbuf->b_changed;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001679
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001680 /* Convert the specified character offset into a lnum/col
1681 * position. */
Bram Moolenaara3227e22006-03-08 21:32:40 +00001682 pos = off2pos(curbuf, off);
1683 if (pos != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001684 {
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001685 if (pos->lnum <= 0)
1686 lnum_start = 1;
1687 else
1688 lnum_start = pos->lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001689 }
1690 else
1691 {
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001692 /* If the given position is not found, assume we want
Bram Moolenaar071d4272004-06-13 20:20:40 +00001693 * the end of the file. See setLocAndSize HACK. */
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001694 if (buf_was_empty)
1695 lnum_start = 1; /* above empty line */
1696 else
1697 lnum_start = curbuf->b_ml.ml_line_count + 1;
Bram Moolenaar009b2592004-10-24 19:18:58 +00001698 }
1699
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001700 /* "lnum" is the line where we insert: either append to it or
1701 * insert a new line above it. */
1702 lnum = lnum_start;
1703
1704 /* Loop over the "\n" separated lines of the argument. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001705 doupdate = 1;
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001706 while (*args != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001707 {
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001708 nl = vim_strchr(args, '\n');
1709 if (nl == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001710 {
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001711 /* Incomplete line, probably truncated. Next "insert"
1712 * command should append to this one. */
1713 len = STRLEN(args);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001714 }
Bram Moolenaar009b2592004-10-24 19:18:58 +00001715 else
1716 {
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001717 len = nl - args;
1718
1719 /*
1720 * We need to detect EOL style, because the commands
1721 * use a character offset.
1722 */
1723 if (nl > args && nl[-1] == '\r')
1724 {
1725 ff_detected = EOL_DOS;
1726 --len;
1727 }
1728 else
1729 ff_detected = EOL_UNIX;
1730 }
1731 args[len] = NUL;
1732
1733 if (lnum == lnum_start
1734 && ((pos != NULL && pos->col > 0)
1735 || (lnum == 1 && buf_was_empty)))
1736 {
1737 char_u *oldline = ml_get(lnum);
1738 char_u *newline;
1739
1740 /* Insert halfway a line. For simplicity we assume we
1741 * need to append to the line. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001742 newline = alloc_check((unsigned)(STRLEN(oldline) + len + 1));
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001743 if (newline != NULL)
1744 {
1745 STRCPY(newline, oldline);
1746 STRCAT(newline, args);
1747 ml_replace(lnum, newline, FALSE);
1748 }
1749 }
1750 else
1751 {
1752 /* Append a new line. Not that we always do this,
1753 * also when the text doesn't end in a "\n". */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001754 ml_append((linenr_T)(lnum - 1), args, (colnr_T)(len + 1), FALSE);
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001755 ++added;
Bram Moolenaar009b2592004-10-24 19:18:58 +00001756 }
1757
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001758 if (nl == NULL)
1759 break;
1760 ++lnum;
1761 args = nl + 1;
Bram Moolenaar009b2592004-10-24 19:18:58 +00001762 }
1763
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001764 /* Adjust the marks below the inserted lines. */
1765 appended_lines_mark(lnum_start - 1, (long)added);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001766
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001767 /*
1768 * When starting with an empty buffer set the fileformat.
1769 * This is just guessing...
Bram Moolenaar071d4272004-06-13 20:20:40 +00001770 */
1771 if (buf_was_empty)
1772 {
1773 if (ff_detected == EOL_UNKNOWN)
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001774#if defined(MSDOS) || defined(MSWIN) || defined(OS2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001775 ff_detected = EOL_DOS;
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001776#else
1777 ff_detected = EOL_UNIX;
1778#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001779 set_fileformat(ff_detected, OPT_LOCAL);
Bram Moolenaara3227e22006-03-08 21:32:40 +00001780 curbuf->b_start_ffc = *curbuf->b_p_ff;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001781 }
1782
Bram Moolenaar071d4272004-06-13 20:20:40 +00001783 /*
1784 * XXX - GRP - Is the next line right? If I've inserted
1785 * text the buffer has been updated but not written. Will
1786 * netbeans guarantee to write it? Even if I do a :q! ?
1787 */
Bram Moolenaara3227e22006-03-08 21:32:40 +00001788 curbuf->b_changed = old_b_changed; /* logically unchanged */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001789 netbeansFireChanges = oldFire;
1790
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001791 /* Undo info is invalid now... */
Bram Moolenaara3227e22006-03-08 21:32:40 +00001792 u_blockfree(curbuf);
1793 u_clearall(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001794 }
1795 vim_free(to_free);
1796 nb_reply_nil(cmdno); /* or !error */
1797 }
1798 else
1799 {
1800 nbdebug(("UNIMPLEMENTED FUNCTION: %s\n", cmd));
1801 nb_reply_nil(cmdno);
1802 retval = FAIL;
1803 }
1804 }
1805 else /* Not a function; no reply required. */
1806 {
1807/* =====================================================================*/
1808 if (streq((char *)cmd, "create"))
1809 {
1810 /* Create a buffer without a name. */
1811 if (buf == NULL)
1812 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001813 nbdebug((" invalid buffer identifier in create\n"));
1814 EMSG("E636: invalid buffer identifier in create");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001815 return FAIL;
1816 }
1817 vim_free(buf->displayname);
1818 buf->displayname = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001819
1820 netbeansReadFile = 0; /* don't try to open disk file */
Bram Moolenaar701f7af2008-11-15 13:12:07 +00001821 do_ecmd(0, NULL, 0, 0, ECMD_ONE, ECMD_HIDE + ECMD_OLDBUF, curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001822 netbeansReadFile = 1;
1823 buf->bufp = curbuf;
1824 maketitle();
Bram Moolenaar009b2592004-10-24 19:18:58 +00001825 buf->insertDone = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001826 gui_update_menus(0);
1827/* =====================================================================*/
1828 }
Bram Moolenaar009b2592004-10-24 19:18:58 +00001829 else if (streq((char *)cmd, "insertDone"))
1830 {
Bram Moolenaareb3593b2006-04-22 22:33:57 +00001831 if (buf == NULL || buf->bufp == NULL)
1832 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001833 nbdebug((" invalid buffer identifier in insertDone\n"));
Bram Moolenaareb3593b2006-04-22 22:33:57 +00001834 }
1835 else
1836 {
1837 buf->bufp->b_start_eol = *args == 'T';
1838 buf->insertDone = TRUE;
1839 args += 2;
1840 buf->bufp->b_p_ro = *args == 'T';
1841 print_read_msg(buf);
1842 }
Bram Moolenaar009b2592004-10-24 19:18:58 +00001843/* =====================================================================*/
1844 }
1845 else if (streq((char *)cmd, "saveDone"))
1846 {
Bram Moolenaareb3593b2006-04-22 22:33:57 +00001847 long savedChars = atol((char *)args);
1848
1849 if (buf == NULL || buf->bufp == NULL)
1850 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001851 nbdebug((" invalid buffer identifier in saveDone\n"));
Bram Moolenaareb3593b2006-04-22 22:33:57 +00001852 }
1853 else
1854 print_save_msg(buf, savedChars);
Bram Moolenaar009b2592004-10-24 19:18:58 +00001855/* =====================================================================*/
1856 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001857 else if (streq((char *)cmd, "startDocumentListen"))
1858 {
1859 if (buf == NULL)
1860 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001861 nbdebug((" invalid buffer identifier in startDocumentListen\n"));
1862 EMSG("E637: invalid buffer identifier in startDocumentListen");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001863 return FAIL;
1864 }
1865 buf->fireChanges = 1;
1866/* =====================================================================*/
1867 }
1868 else if (streq((char *)cmd, "stopDocumentListen"))
1869 {
1870 if (buf == NULL)
1871 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001872 nbdebug((" invalid buffer identifier in stopDocumentListen\n"));
1873 EMSG("E638: invalid buffer identifier in stopDocumentListen");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001874 return FAIL;
1875 }
1876 buf->fireChanges = 0;
Bram Moolenaar24c088a2005-02-02 22:55:47 +00001877 if (buf->bufp != NULL && buf->bufp->b_was_netbeans_file)
Bram Moolenaar009b2592004-10-24 19:18:58 +00001878 {
Bram Moolenaar24c088a2005-02-02 22:55:47 +00001879 if (!buf->bufp->b_netbeans_file)
Bram Moolenaarf2330482008-06-24 20:19:36 +00001880 {
1881 nbdebug(("E658: NetBeans connection lost for buffer %ld\n", buf->bufp->b_fnum));
Bram Moolenaar009b2592004-10-24 19:18:58 +00001882 EMSGN(_("E658: NetBeans connection lost for buffer %ld"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001883 buf->bufp->b_fnum);
Bram Moolenaarf2330482008-06-24 20:19:36 +00001884 }
Bram Moolenaar009b2592004-10-24 19:18:58 +00001885 else
1886 {
Bram Moolenaar24c088a2005-02-02 22:55:47 +00001887 /* NetBeans uses stopDocumentListen when it stops editing
1888 * a file. It then expects the buffer in Vim to
1889 * disappear. */
1890 do_bufdel(DOBUF_DEL, (char_u *)"", 1,
1891 buf->bufp->b_fnum, buf->bufp->b_fnum, TRUE);
Bram Moolenaar009b2592004-10-24 19:18:58 +00001892 vim_memset(buf, 0, sizeof(nbbuf_T));
1893 }
1894 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001895/* =====================================================================*/
1896 }
1897 else if (streq((char *)cmd, "setTitle"))
1898 {
1899 if (buf == NULL)
1900 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001901 nbdebug((" invalid buffer identifier in setTitle\n"));
1902 EMSG("E639: invalid buffer identifier in setTitle");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001903 return FAIL;
1904 }
1905 vim_free(buf->displayname);
1906 buf->displayname = nb_unquote(args, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001907/* =====================================================================*/
1908 }
1909 else if (streq((char *)cmd, "initDone"))
1910 {
1911 if (buf == NULL || buf->bufp == NULL)
1912 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001913 nbdebug((" invalid buffer identifier in initDone\n"));
1914 EMSG("E640: invalid buffer identifier in initDone");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001915 return FAIL;
1916 }
1917 doupdate = 1;
Bram Moolenaar009b2592004-10-24 19:18:58 +00001918 buf->initDone = TRUE;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00001919 nb_set_curbuf(buf->bufp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001920#if defined(FEAT_AUTOCMD)
1921 apply_autocmds(EVENT_BUFREADPOST, 0, 0, FALSE, buf->bufp);
1922#endif
1923
1924 /* handle any postponed key commands */
1925 handle_key_queue();
1926/* =====================================================================*/
1927 }
1928 else if (streq((char *)cmd, "setBufferNumber")
1929 || streq((char *)cmd, "putBufferNumber"))
1930 {
Bram Moolenaar009b2592004-10-24 19:18:58 +00001931 char_u *path;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001932 buf_T *bufp;
1933
1934 if (buf == NULL)
1935 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001936 nbdebug((" invalid buffer identifier in setBufferNumber\n"));
1937 EMSG("E641: invalid buffer identifier in setBufferNumber");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001938 return FAIL;
1939 }
Bram Moolenaar009b2592004-10-24 19:18:58 +00001940 path = (char_u *)nb_unquote(args, NULL);
1941 if (path == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001942 return FAIL;
Bram Moolenaar009b2592004-10-24 19:18:58 +00001943 bufp = buflist_findname(path);
1944 vim_free(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001945 if (bufp == NULL)
1946 {
Bram Moolenaarec906222009-02-21 21:14:00 +00001947 nbdebug((" File %s not found in setBufferNumber\n", args));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001948 EMSG2("E642: File %s not found in setBufferNumber", args);
1949 return FAIL;
1950 }
1951 buf->bufp = bufp;
Bram Moolenaar009b2592004-10-24 19:18:58 +00001952 buf->nbbuf_number = bufp->b_fnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001953
1954 /* "setBufferNumber" has the side effect of jumping to the buffer
1955 * (don't know why!). Don't do that for "putBufferNumber". */
1956 if (*cmd != 'p')
1957 coloncmd(":buffer %d", bufp->b_fnum);
1958 else
1959 {
Bram Moolenaar009b2592004-10-24 19:18:58 +00001960 buf->initDone = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001961
1962 /* handle any postponed key commands */
1963 handle_key_queue();
1964 }
1965
1966#if 0 /* never used */
1967 buf->internalname = (char *)alloc_clear(8);
1968 sprintf(buf->internalname, "<%d>", bufno);
1969 buf->netbeansOwns = 0;
1970#endif
1971/* =====================================================================*/
1972 }
1973 else if (streq((char *)cmd, "setFullName"))
1974 {
1975 if (buf == NULL)
1976 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001977 nbdebug((" invalid buffer identifier in setFullName\n"));
1978 EMSG("E643: invalid buffer identifier in setFullName");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001979 return FAIL;
1980 }
1981 vim_free(buf->displayname);
1982 buf->displayname = nb_unquote(args, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001983
1984 netbeansReadFile = 0; /* don't try to open disk file */
1985 do_ecmd(0, (char_u *)buf->displayname, 0, 0, ECMD_ONE,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00001986 ECMD_HIDE + ECMD_OLDBUF, curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001987 netbeansReadFile = 1;
1988 buf->bufp = curbuf;
1989 maketitle();
1990 gui_update_menus(0);
1991/* =====================================================================*/
1992 }
1993 else if (streq((char *)cmd, "editFile"))
1994 {
1995 if (buf == NULL)
1996 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001997 nbdebug((" invalid buffer identifier in editFile\n"));
1998 EMSG("E644: invalid buffer identifier in editFile");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001999 return FAIL;
2000 }
2001 /* Edit a file: like create + setFullName + read the file. */
2002 vim_free(buf->displayname);
2003 buf->displayname = nb_unquote(args, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002004 do_ecmd(0, (char_u *)buf->displayname, NULL, NULL, ECMD_ONE,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002005 ECMD_HIDE + ECMD_OLDBUF, curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002006 buf->bufp = curbuf;
Bram Moolenaar009b2592004-10-24 19:18:58 +00002007 buf->initDone = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002008 doupdate = 1;
2009#if defined(FEAT_TITLE)
2010 maketitle();
2011#endif
2012 gui_update_menus(0);
2013/* =====================================================================*/
2014 }
2015 else if (streq((char *)cmd, "setVisible"))
2016 {
2017 if (buf == NULL || buf->bufp == NULL)
2018 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002019 nbdebug((" invalid buffer identifier in setVisible\n"));
2020 /* This message was commented out, probably because it can
2021 * happen when shutting down. */
2022 if (p_verbose > 0)
2023 EMSG("E645: invalid buffer identifier in setVisible");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002024 return FAIL;
2025 }
Bram Moolenaar009b2592004-10-24 19:18:58 +00002026 if (streq((char *)args, "T") && buf->bufp != curbuf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002027 {
2028 exarg_T exarg;
2029 exarg.cmd = (char_u *)"goto";
2030 exarg.forceit = FALSE;
Bram Moolenaar009b2592004-10-24 19:18:58 +00002031 dosetvisible = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002032 goto_buffer(&exarg, DOBUF_FIRST, FORWARD, buf->bufp->b_fnum);
2033 doupdate = 1;
Bram Moolenaar009b2592004-10-24 19:18:58 +00002034 dosetvisible = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002035
2036 /* Side effect!!!. */
2037 if (!gui.starting)
2038 gui_mch_set_foreground();
2039 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002040/* =====================================================================*/
2041 }
2042 else if (streq((char *)cmd, "raise"))
2043 {
2044 /* Bring gvim to the foreground. */
2045 if (!gui.starting)
2046 gui_mch_set_foreground();
2047/* =====================================================================*/
2048 }
2049 else if (streq((char *)cmd, "setModified"))
2050 {
Bram Moolenaarff064e12008-06-09 13:10:45 +00002051 int prev_b_changed;
2052
Bram Moolenaar071d4272004-06-13 20:20:40 +00002053 if (buf == NULL || buf->bufp == NULL)
2054 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002055 nbdebug((" invalid buffer identifier in setModified\n"));
2056 /* This message was commented out, probably because it can
2057 * happen when shutting down. */
2058 if (p_verbose > 0)
2059 EMSG("E646: invalid buffer identifier in setModified");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002060 return FAIL;
2061 }
Bram Moolenaarff064e12008-06-09 13:10:45 +00002062 prev_b_changed = buf->bufp->b_changed;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002063 if (streq((char *)args, "T"))
Bram Moolenaarff064e12008-06-09 13:10:45 +00002064 buf->bufp->b_changed = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002065 else
2066 {
2067 struct stat st;
2068
2069 /* Assume NetBeans stored the file. Reset the timestamp to
2070 * avoid "file changed" warnings. */
2071 if (buf->bufp->b_ffname != NULL
2072 && mch_stat((char *)buf->bufp->b_ffname, &st) >= 0)
2073 buf_store_time(buf->bufp, &st, buf->bufp->b_ffname);
Bram Moolenaarff064e12008-06-09 13:10:45 +00002074 buf->bufp->b_changed = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002075 }
2076 buf->modified = buf->bufp->b_changed;
Bram Moolenaarff064e12008-06-09 13:10:45 +00002077 if (prev_b_changed != buf->bufp->b_changed)
2078 {
2079#ifdef FEAT_WINDOWS
2080 check_status(buf->bufp);
2081 redraw_tabline = TRUE;
2082#endif
2083#ifdef FEAT_TITLE
2084 maketitle();
2085#endif
2086 update_screen(0);
2087 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002088/* =====================================================================*/
2089 }
Bram Moolenaar009b2592004-10-24 19:18:58 +00002090 else if (streq((char *)cmd, "setModtime"))
2091 {
Bram Moolenaareb3593b2006-04-22 22:33:57 +00002092 if (buf == NULL || buf->bufp == NULL)
Bram Moolenaarf2330482008-06-24 20:19:36 +00002093 nbdebug((" invalid buffer identifier in setModtime\n"));
Bram Moolenaareb3593b2006-04-22 22:33:57 +00002094 else
2095 buf->bufp->b_mtime = atoi((char *)args);
Bram Moolenaar009b2592004-10-24 19:18:58 +00002096/* =====================================================================*/
2097 }
2098 else if (streq((char *)cmd, "setReadOnly"))
2099 {
Bram Moolenaareb3593b2006-04-22 22:33:57 +00002100 if (buf == NULL || buf->bufp == NULL)
Bram Moolenaarf2330482008-06-24 20:19:36 +00002101 nbdebug((" invalid buffer identifier in setReadOnly\n"));
Bram Moolenaareb3593b2006-04-22 22:33:57 +00002102 else if (streq((char *)args, "T"))
Bram Moolenaar009b2592004-10-24 19:18:58 +00002103 buf->bufp->b_p_ro = TRUE;
2104 else
2105 buf->bufp->b_p_ro = FALSE;
2106/* =====================================================================*/
2107 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002108 else if (streq((char *)cmd, "setMark"))
2109 {
2110 /* not yet */
2111/* =====================================================================*/
2112 }
2113 else if (streq((char *)cmd, "showBalloon"))
2114 {
2115#if defined(FEAT_BEVAL)
2116 static char *text = NULL;
2117
2118 /*
2119 * Set up the Balloon Expression Evaluation area.
2120 * Ignore 'ballooneval' here.
2121 * The text pointer must remain valid for a while.
2122 */
2123 if (balloonEval != NULL)
2124 {
2125 vim_free(text);
2126 text = nb_unquote(args, NULL);
2127 if (text != NULL)
2128 gui_mch_post_balloon(balloonEval, (char_u *)text);
2129 }
2130#endif
2131/* =====================================================================*/
2132 }
2133 else if (streq((char *)cmd, "setDot"))
2134 {
2135 pos_T *pos;
2136#ifdef NBDEBUG
2137 char_u *s;
2138#endif
2139
2140 if (buf == NULL || buf->bufp == NULL)
2141 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002142 nbdebug((" invalid buffer identifier in setDot\n"));
2143 EMSG("E647: invalid buffer identifier in setDot");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002144 return FAIL;
2145 }
2146
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002147 nb_set_curbuf(buf->bufp);
2148
Bram Moolenaar071d4272004-06-13 20:20:40 +00002149#ifdef FEAT_VISUAL
2150 /* Don't want Visual mode now. */
2151 if (VIsual_active)
2152 end_visual_mode();
2153#endif
2154#ifdef NBDEBUG
2155 s = args;
2156#endif
2157 pos = get_off_or_lnum(buf->bufp, &args);
2158 if (pos)
2159 {
2160 curwin->w_cursor = *pos;
2161 check_cursor();
2162#ifdef FEAT_FOLDING
2163 foldOpenCursor();
2164#endif
2165 }
2166 else
Bram Moolenaarb85cb212009-05-17 14:24:23 +00002167 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002168 nbdebug((" BAD POSITION in setDot: %s\n", s));
Bram Moolenaarb85cb212009-05-17 14:24:23 +00002169 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002170
2171 /* gui_update_cursor(TRUE, FALSE); */
2172 /* update_curbuf(NOT_VALID); */
2173 update_topline(); /* scroll to show the line */
2174 update_screen(VALID);
2175 setcursor();
2176 out_flush();
2177 gui_update_cursor(TRUE, FALSE);
2178 gui_mch_flush();
2179 /* Quit a hit-return or more prompt. */
2180 if (State == HITRETURN || State == ASKMORE)
2181 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002182#ifdef FEAT_GUI_GTK
2183 if (gtk_main_level() > 0)
2184 gtk_main_quit();
2185#endif
2186 }
2187/* =====================================================================*/
2188 }
2189 else if (streq((char *)cmd, "close"))
2190 {
2191#ifdef NBDEBUG
2192 char *name = "<NONE>";
2193#endif
2194
2195 if (buf == NULL)
2196 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002197 nbdebug((" invalid buffer identifier in close\n"));
2198 EMSG("E648: invalid buffer identifier in close");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002199 return FAIL;
2200 }
2201
2202#ifdef NBDEBUG
2203 if (buf->displayname != NULL)
2204 name = buf->displayname;
2205#endif
Bram Moolenaarf2330482008-06-24 20:19:36 +00002206 if (buf->bufp == NULL)
2207 {
2208 nbdebug((" invalid buffer identifier in close\n"));
2209 /* This message was commented out, probably because it can
2210 * happen when shutting down. */
2211 if (p_verbose > 0)
2212 EMSG("E649: invalid buffer identifier in close");
2213 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002214 nbdebug((" CLOSE %d: %s\n", bufno, name));
2215 need_mouse_correct = TRUE;
2216 if (buf->bufp != NULL)
2217 do_buffer(DOBUF_WIPE, DOBUF_FIRST, FORWARD,
2218 buf->bufp->b_fnum, TRUE);
Bram Moolenaar8d602722006-08-08 19:34:19 +00002219 buf->bufp = NULL;
2220 buf->initDone = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002221 doupdate = 1;
2222/* =====================================================================*/
2223 }
2224 else if (streq((char *)cmd, "setStyle")) /* obsolete... */
2225 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002226 nbdebug((" setStyle is obsolete!\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002227/* =====================================================================*/
2228 }
2229 else if (streq((char *)cmd, "setExitDelay"))
2230 {
Bram Moolenaar009b2592004-10-24 19:18:58 +00002231 /* Only used in version 2.1. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002232/* =====================================================================*/
2233 }
2234 else if (streq((char *)cmd, "defineAnnoType"))
2235 {
2236#ifdef FEAT_SIGNS
2237 int typeNum;
2238 char_u *typeName;
2239 char_u *tooltip;
2240 char_u *p;
2241 char_u *glyphFile;
2242 int use_fg = 0;
2243 int use_bg = 0;
2244 int fg = -1;
2245 int bg = -1;
2246
2247 if (buf == NULL)
2248 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002249 nbdebug((" invalid buffer identifier in defineAnnoType\n"));
2250 EMSG("E650: invalid buffer identifier in defineAnnoType");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002251 return FAIL;
2252 }
2253
Bram Moolenaar349b2f62004-10-11 10:00:50 +00002254 cp = (char *)args;
2255 typeNum = strtol(cp, &cp, 10);
2256 args = (char_u *)cp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002257 args = skipwhite(args);
2258 typeName = (char_u *)nb_unquote(args, &args);
2259 args = skipwhite(args + 1);
2260 tooltip = (char_u *)nb_unquote(args, &args);
2261 args = skipwhite(args + 1);
2262
2263 p = (char_u *)nb_unquote(args, &args);
2264 glyphFile = vim_strsave_escaped(p, escape_chars);
2265 vim_free(p);
2266
2267 args = skipwhite(args + 1);
2268 if (STRNCMP(args, "none", 4) == 0)
2269 args += 5;
2270 else
2271 {
2272 use_fg = 1;
Bram Moolenaar349b2f62004-10-11 10:00:50 +00002273 cp = (char *)args;
2274 fg = strtol(cp, &cp, 10);
2275 args = (char_u *)cp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002276 }
2277 if (STRNCMP(args, "none", 4) == 0)
2278 args += 5;
2279 else
2280 {
2281 use_bg = 1;
Bram Moolenaar349b2f62004-10-11 10:00:50 +00002282 cp = (char *)args;
2283 bg = strtol(cp, &cp, 10);
2284 args = (char_u *)cp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002285 }
2286 if (typeName != NULL && tooltip != NULL && glyphFile != NULL)
2287 addsigntype(buf, typeNum, typeName, tooltip, glyphFile,
2288 use_fg, fg, use_bg, bg);
2289 else
2290 vim_free(typeName);
2291
2292 /* don't free typeName; it's used directly in addsigntype() */
2293 vim_free(tooltip);
2294 vim_free(glyphFile);
2295
2296#endif
2297/* =====================================================================*/
2298 }
2299 else if (streq((char *)cmd, "addAnno"))
2300 {
2301#ifdef FEAT_SIGNS
2302 int serNum;
2303 int localTypeNum;
2304 int typeNum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002305 pos_T *pos;
2306
2307 if (buf == NULL || buf->bufp == NULL)
2308 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002309 nbdebug((" invalid buffer identifier in addAnno\n"));
2310 EMSG("E651: invalid buffer identifier in addAnno");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002311 return FAIL;
2312 }
2313
2314 doupdate = 1;
2315
Bram Moolenaar349b2f62004-10-11 10:00:50 +00002316 cp = (char *)args;
2317 serNum = strtol(cp, &cp, 10);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002318
2319 /* Get the typenr specific for this buffer and convert it to
2320 * the global typenumber, as used for the sign name. */
Bram Moolenaar349b2f62004-10-11 10:00:50 +00002321 localTypeNum = strtol(cp, &cp, 10);
2322 args = (char_u *)cp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002323 typeNum = mapsigntype(buf, localTypeNum);
2324
2325 pos = get_off_or_lnum(buf->bufp, &args);
2326
Bram Moolenaar349b2f62004-10-11 10:00:50 +00002327 cp = (char *)args;
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00002328 ignored = (int)strtol(cp, &cp, 10);
Bram Moolenaar349b2f62004-10-11 10:00:50 +00002329 args = (char_u *)cp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002330# ifdef NBDEBUG
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00002331 if (ignored != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002332 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002333 nbdebug((" partial line annotation -- Not Yet Implemented!\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002334 }
2335# endif
2336 if (serNum >= GUARDEDOFFSET)
2337 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002338 nbdebug((" too many annotations! ignoring...\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002339 return FAIL;
2340 }
2341 if (pos)
2342 {
Bram Moolenaarec906222009-02-21 21:14:00 +00002343 coloncmd(":sign place %d line=%ld name=%d buffer=%d",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002344 serNum, pos->lnum, typeNum, buf->bufp->b_fnum);
2345 if (typeNum == curPCtype)
2346 coloncmd(":sign jump %d buffer=%d", serNum,
2347 buf->bufp->b_fnum);
2348 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002349#endif
2350/* =====================================================================*/
2351 }
2352 else if (streq((char *)cmd, "removeAnno"))
2353 {
2354#ifdef FEAT_SIGNS
2355 int serNum;
2356
2357 if (buf == NULL || buf->bufp == NULL)
2358 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002359 nbdebug((" invalid buffer identifier in removeAnno\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002360 return FAIL;
2361 }
2362 doupdate = 1;
Bram Moolenaar349b2f62004-10-11 10:00:50 +00002363 cp = (char *)args;
2364 serNum = strtol(cp, &cp, 10);
2365 args = (char_u *)cp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002366 coloncmd(":sign unplace %d buffer=%d",
2367 serNum, buf->bufp->b_fnum);
2368 redraw_buf_later(buf->bufp, NOT_VALID);
2369#endif
2370/* =====================================================================*/
2371 }
2372 else if (streq((char *)cmd, "moveAnnoToFront"))
2373 {
2374#ifdef FEAT_SIGNS
Bram Moolenaarf2330482008-06-24 20:19:36 +00002375 nbdebug((" moveAnnoToFront: Not Yet Implemented!\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002376#endif
2377/* =====================================================================*/
2378 }
2379 else if (streq((char *)cmd, "guard") || streq((char *)cmd, "unguard"))
2380 {
2381 int len;
2382 pos_T first;
2383 pos_T last;
2384 pos_T *pos;
2385 int un = (cmd[0] == 'u');
2386 static int guardId = GUARDEDOFFSET;
2387
2388 if (skip >= SKIP_STOP)
2389 {
2390 nbdebug((" Skipping %s command\n", (char *) cmd));
2391 return OK;
2392 }
2393
2394 nb_init_graphics();
2395
2396 if (buf == NULL || buf->bufp == NULL)
2397 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002398 nbdebug((" invalid buffer identifier in %s command\n", cmd));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002399 return FAIL;
2400 }
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002401 nb_set_curbuf(buf->bufp);
Bram Moolenaar349b2f62004-10-11 10:00:50 +00002402 cp = (char *)args;
2403 off = strtol(cp, &cp, 10);
2404 len = strtol(cp, NULL, 10);
2405 args = (char_u *)cp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002406 pos = off2pos(buf->bufp, off);
2407 doupdate = 1;
2408 if (!pos)
2409 nbdebug((" no such start pos in %s, %ld\n", cmd, off));
2410 else
2411 {
2412 first = *pos;
2413 pos = off2pos(buf->bufp, off + len - 1);
Bram Moolenaar009b2592004-10-24 19:18:58 +00002414 if (pos != NULL && pos->col == 0)
2415 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002416 /*
2417 * In Java Swing the offset is a position between 2
2418 * characters. If col == 0 then we really want the
2419 * previous line as the end.
2420 */
2421 pos = off2pos(buf->bufp, off + len - 2);
2422 }
2423 if (!pos)
2424 nbdebug((" no such end pos in %s, %ld\n",
2425 cmd, off + len - 1));
2426 else
2427 {
2428 long lnum;
2429 last = *pos;
2430 /* set highlight for region */
2431 nbdebug((" %sGUARD %ld,%d to %ld,%d\n", (un) ? "UN" : "",
2432 first.lnum, first.col,
2433 last.lnum, last.col));
2434#ifdef FEAT_SIGNS
2435 for (lnum = first.lnum; lnum <= last.lnum; lnum++)
2436 {
2437 if (un)
2438 {
2439 /* never used */
2440 }
2441 else
2442 {
2443 if (buf_findsigntype_id(buf->bufp, lnum,
2444 GUARDED) == 0)
2445 {
2446 coloncmd(
Bram Moolenaarec906222009-02-21 21:14:00 +00002447 ":sign place %d line=%ld name=%d buffer=%d",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002448 guardId++, lnum, GUARDED,
2449 buf->bufp->b_fnum);
2450 }
2451 }
2452 }
2453#endif
2454 redraw_buf_later(buf->bufp, NOT_VALID);
2455 }
2456 }
2457/* =====================================================================*/
2458 }
2459 else if (streq((char *)cmd, "startAtomic"))
2460 {
2461 inAtomic = 1;
2462/* =====================================================================*/
2463 }
2464 else if (streq((char *)cmd, "endAtomic"))
2465 {
2466 inAtomic = 0;
2467 if (needupdate)
2468 {
2469 doupdate = 1;
2470 needupdate = 0;
2471 }
2472/* =====================================================================*/
2473 }
2474 else if (streq((char *)cmd, "save"))
2475 {
Bram Moolenaar009b2592004-10-24 19:18:58 +00002476 /*
2477 * NOTE - This command is obsolete wrt NetBeans. Its left in
2478 * only for historical reasons.
2479 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002480 if (buf == NULL || buf->bufp == NULL)
2481 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002482 nbdebug((" invalid buffer identifier in %s command\n", cmd));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002483 return FAIL;
2484 }
2485
2486 /* the following is taken from ex_cmds.c (do_wqall function) */
2487 if (bufIsChanged(buf->bufp))
2488 {
2489 /* Only write if the buffer can be written. */
2490 if (p_write
2491 && !buf->bufp->b_p_ro
2492 && buf->bufp->b_ffname != NULL
2493#ifdef FEAT_QUICKFIX
2494 && !bt_dontwrite(buf->bufp)
2495#endif
2496 )
2497 {
2498 buf_write_all(buf->bufp, FALSE);
2499#ifdef FEAT_AUTOCMD
2500 /* an autocommand may have deleted the buffer */
2501 if (!buf_valid(buf->bufp))
2502 buf->bufp = NULL;
2503#endif
2504 }
2505 }
Bram Moolenaarf2330482008-06-24 20:19:36 +00002506 else
2507 {
Bram Moolenaar8065d7f2010-01-19 15:13:14 +01002508 nbdebug((" Buffer has no changes!\n"));
Bram Moolenaarf2330482008-06-24 20:19:36 +00002509 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002510/* =====================================================================*/
2511 }
2512 else if (streq((char *)cmd, "netbeansBuffer"))
2513 {
2514 if (buf == NULL || buf->bufp == NULL)
2515 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002516 nbdebug((" invalid buffer identifier in %s command\n", cmd));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002517 return FAIL;
2518 }
2519 if (*args == 'T')
2520 {
2521 buf->bufp->b_netbeans_file = TRUE;
2522 buf->bufp->b_was_netbeans_file = TRUE;
2523 }
2524 else
2525 buf->bufp->b_netbeans_file = FALSE;
2526/* =====================================================================*/
2527 }
Bram Moolenaar009b2592004-10-24 19:18:58 +00002528 else if (streq((char *)cmd, "specialKeys"))
2529 {
2530 special_keys(args);
2531/* =====================================================================*/
2532 }
2533 else if (streq((char *)cmd, "actionMenuItem"))
2534 {
2535 /* not used yet */
2536/* =====================================================================*/
2537 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002538 else if (streq((char *)cmd, "version"))
2539 {
Bram Moolenaar009b2592004-10-24 19:18:58 +00002540 /* not used yet */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002541 }
Bram Moolenaarf2330482008-06-24 20:19:36 +00002542 else
2543 {
2544 nbdebug(("Unrecognised command: %s\n", cmd));
2545 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002546 /*
2547 * Unrecognized command is ignored.
2548 */
2549 }
2550 if (inAtomic && doupdate)
2551 {
2552 needupdate = 1;
2553 doupdate = 0;
2554 }
2555
Bram Moolenaar009b2592004-10-24 19:18:58 +00002556 /*
2557 * Is this needed? I moved the netbeans_Xt_connect() later during startup
2558 * and it may no longer be necessary. If its not needed then needupdate
2559 * and doupdate can also be removed.
2560 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002561 if (buf != NULL && buf->initDone && doupdate)
2562 {
2563 update_screen(NOT_VALID);
2564 setcursor();
2565 out_flush();
2566 gui_update_cursor(TRUE, FALSE);
2567 gui_mch_flush();
2568 /* Quit a hit-return or more prompt. */
2569 if (State == HITRETURN || State == ASKMORE)
2570 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002571#ifdef FEAT_GUI_GTK
2572 if (gtk_main_level() > 0)
2573 gtk_main_quit();
2574#endif
2575 }
2576 }
2577
2578 return retval;
2579}
2580
2581
2582/*
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002583 * If "buf" is not the current buffer try changing to a window that edits this
2584 * buffer. If there is no such window then close the current buffer and set
2585 * the current buffer as "buf".
2586 */
2587 static void
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00002588nb_set_curbuf(buf_T *buf)
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002589{
2590 if (curbuf != buf && buf_jump_open_win(buf) == NULL)
2591 set_curbuf(buf, DOBUF_GOTO);
2592}
2593
2594/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002595 * Process a vim colon command.
2596 */
2597 static void
2598coloncmd(char *cmd, ...)
2599{
2600 char buf[1024];
2601 va_list ap;
2602
2603 va_start(ap, cmd);
Bram Moolenaar0dc79e82009-06-24 14:50:12 +00002604 vim_vsnprintf(buf, sizeof(buf), cmd, ap, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002605 va_end(ap);
2606
2607 nbdebug((" COLONCMD %s\n", buf));
2608
2609/* ALT_INPUT_LOCK_ON; */
2610 do_cmdline((char_u *)buf, NULL, NULL, DOCMD_NOWAIT | DOCMD_KEYTYPED);
2611/* ALT_INPUT_LOCK_OFF; */
2612
2613 setcursor(); /* restore the cursor position */
2614 out_flush(); /* make sure output has been written */
2615
2616 gui_update_cursor(TRUE, FALSE);
2617 gui_mch_flush();
2618}
2619
2620
2621/*
Bram Moolenaar009b2592004-10-24 19:18:58 +00002622 * Parse the specialKeys argument and issue the appropriate map commands.
2623 */
2624 static void
2625special_keys(char_u *args)
2626{
2627 char *save_str = nb_unquote(args, NULL);
2628 char *tok = strtok(save_str, " ");
2629 char *sep;
2630 char keybuf[64];
2631 char cmdbuf[256];
2632
2633 while (tok != NULL)
2634 {
2635 int i = 0;
2636
2637 if ((sep = strchr(tok, '-')) != NULL)
2638 {
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00002639 *sep = NUL;
Bram Moolenaar009b2592004-10-24 19:18:58 +00002640 while (*tok)
2641 {
2642 switch (*tok)
2643 {
2644 case 'A':
2645 case 'M':
2646 case 'C':
2647 case 'S':
2648 keybuf[i++] = *tok;
2649 keybuf[i++] = '-';
2650 break;
2651 }
2652 tok++;
2653 }
2654 tok++;
2655 }
2656
2657 strcpy(&keybuf[i], tok);
Bram Moolenaar9c13b352005-05-19 20:53:52 +00002658 vim_snprintf(cmdbuf, sizeof(cmdbuf),
2659 "<silent><%s> :nbkey %s<CR>", keybuf, keybuf);
Bram Moolenaar009b2592004-10-24 19:18:58 +00002660 do_map(0, (char_u *)cmdbuf, NORMAL, FALSE);
2661 tok = strtok(NULL, " ");
2662 }
2663 vim_free(save_str);
2664}
2665
2666
2667 void
2668ex_nbkey(eap)
2669 exarg_T *eap;
2670{
Bram Moolenaar8065d7f2010-01-19 15:13:14 +01002671 (void)netbeans_keystring(eap->arg);
Bram Moolenaar009b2592004-10-24 19:18:58 +00002672}
2673
2674
2675/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002676 * Initialize highlights and signs for use by netbeans (mostly obsolete)
2677 */
2678 static void
2679nb_init_graphics(void)
2680{
2681 static int did_init = FALSE;
2682
2683 if (!did_init)
2684 {
2685 coloncmd(":highlight NBGuarded guibg=Cyan guifg=Black");
2686 coloncmd(":sign define %d linehl=NBGuarded", GUARDED);
2687
2688 did_init = TRUE;
2689 }
2690}
2691
2692/*
Bram Moolenaar8065d7f2010-01-19 15:13:14 +01002693 * Convert key to netbeans name. This uses the global "mod_mask".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002694 */
2695 static void
2696netbeans_keyname(int key, char *buf)
2697{
2698 char *name = 0;
2699 char namebuf[2];
2700 int ctrl = 0;
2701 int shift = 0;
2702 int alt = 0;
2703
2704 if (mod_mask & MOD_MASK_CTRL)
2705 ctrl = 1;
2706 if (mod_mask & MOD_MASK_SHIFT)
2707 shift = 1;
2708 if (mod_mask & MOD_MASK_ALT)
2709 alt = 1;
2710
2711
2712 switch (key)
2713 {
2714 case K_F1: name = "F1"; break;
2715 case K_S_F1: name = "F1"; shift = 1; break;
2716 case K_F2: name = "F2"; break;
2717 case K_S_F2: name = "F2"; shift = 1; break;
2718 case K_F3: name = "F3"; break;
2719 case K_S_F3: name = "F3"; shift = 1; break;
2720 case K_F4: name = "F4"; break;
2721 case K_S_F4: name = "F4"; shift = 1; break;
2722 case K_F5: name = "F5"; break;
2723 case K_S_F5: name = "F5"; shift = 1; break;
2724 case K_F6: name = "F6"; break;
2725 case K_S_F6: name = "F6"; shift = 1; break;
2726 case K_F7: name = "F7"; break;
2727 case K_S_F7: name = "F7"; shift = 1; break;
2728 case K_F8: name = "F8"; break;
2729 case K_S_F8: name = "F8"; shift = 1; break;
2730 case K_F9: name = "F9"; break;
2731 case K_S_F9: name = "F9"; shift = 1; break;
2732 case K_F10: name = "F10"; break;
2733 case K_S_F10: name = "F10"; shift = 1; break;
2734 case K_F11: name = "F11"; break;
2735 case K_S_F11: name = "F11"; shift = 1; break;
2736 case K_F12: name = "F12"; break;
2737 case K_S_F12: name = "F12"; shift = 1; break;
2738 default:
2739 if (key >= ' ' && key <= '~')
2740 {
2741 /* Allow ASCII characters. */
2742 name = namebuf;
2743 namebuf[0] = key;
2744 namebuf[1] = NUL;
2745 }
2746 else
2747 name = "X";
2748 break;
2749 }
2750
2751 buf[0] = '\0';
2752 if (ctrl)
2753 strcat(buf, "C");
2754 if (shift)
2755 strcat(buf, "S");
2756 if (alt)
2757 strcat(buf, "M"); /* META */
2758 if (ctrl || shift || alt)
2759 strcat(buf, "-");
2760 strcat(buf, name);
2761}
2762
2763#ifdef FEAT_BEVAL
2764/*
2765 * Function to be called for balloon evaluation. Grabs the text under the
2766 * cursor and sends it to the debugger for evaluation. The debugger should
2767 * respond with a showBalloon command when there is a useful result.
2768 */
Bram Moolenaard62bec82005-03-07 22:56:57 +00002769 void
Bram Moolenaar071d4272004-06-13 20:20:40 +00002770netbeans_beval_cb(
2771 BalloonEval *beval,
Bram Moolenaarb85cb212009-05-17 14:24:23 +00002772 int state UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002773{
Bram Moolenaard62bec82005-03-07 22:56:57 +00002774 win_T *wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002775 char_u *text;
Bram Moolenaard62bec82005-03-07 22:56:57 +00002776 linenr_T lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002777 int col;
2778 char buf[MAXPATHL * 2 + 25];
2779 char_u *p;
2780
2781 /* Don't do anything when 'ballooneval' is off, messages scrolled the
2782 * windows up or we have no connection. */
2783 if (!p_beval || msg_scrolled > 0 || !haveConnection)
2784 return;
2785
Bram Moolenaard62bec82005-03-07 22:56:57 +00002786 if (get_beval_info(beval, TRUE, &wp, &lnum, &text, &col) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002787 {
2788 /* Send debugger request. Only when the text is of reasonable
2789 * length. */
2790 if (text != NULL && text[0] != NUL && STRLEN(text) < MAXPATHL)
2791 {
2792 p = nb_quote(text);
2793 if (p != NULL)
Bram Moolenaar009b2592004-10-24 19:18:58 +00002794 {
Bram Moolenaar9c13b352005-05-19 20:53:52 +00002795 vim_snprintf(buf, sizeof(buf),
Bram Moolenaar89d40322006-08-29 15:30:07 +00002796 "0:balloonText=%d \"%s\"\n", r_cmdno, p);
Bram Moolenaar009b2592004-10-24 19:18:58 +00002797 vim_free(p);
2798 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002799 nbdebug(("EVT: %s", buf));
2800 nb_send(buf, "netbeans_beval_cb");
2801 }
2802 vim_free(text);
2803 }
2804}
2805#endif
2806
2807/*
2808 * Tell netbeans that the window was opened, ready for commands.
2809 */
2810 void
2811netbeans_startup_done(void)
2812{
2813 char *cmd = "0:startupDone=0\n";
2814
Bram Moolenaar009b2592004-10-24 19:18:58 +00002815 if (usingNetbeans)
2816#ifdef FEAT_GUI_MOTIF
2817 netbeans_Xt_connect(app_context);
2818#else
2819# ifdef FEAT_GUI_GTK
2820 netbeans_gtk_connect();
Bram Moolenaardf177f62005-02-22 08:39:57 +00002821# else
2822# ifdef FEAT_GUI_W32
2823 netbeans_w32_connect();
2824# endif
Bram Moolenaar009b2592004-10-24 19:18:58 +00002825# endif
2826#endif
2827
Bram Moolenaar071d4272004-06-13 20:20:40 +00002828 if (!haveConnection)
2829 return;
2830
Bram Moolenaard62bec82005-03-07 22:56:57 +00002831#ifdef FEAT_BEVAL
2832 bevalServers |= BEVAL_NETBEANS;
2833#endif
2834
Bram Moolenaar071d4272004-06-13 20:20:40 +00002835 nbdebug(("EVT: %s", cmd));
2836 nb_send(cmd, "netbeans_startup_done");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002837}
2838
Bram Moolenaar009b2592004-10-24 19:18:58 +00002839/*
2840 * Tell netbeans that we're exiting. This should be called right
2841 * before calling exit.
2842 */
2843 void
2844netbeans_send_disconnect()
2845{
2846 char buf[128];
2847
2848 if (haveConnection)
2849 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00002850 sprintf(buf, "0:disconnect=%d\n", r_cmdno);
Bram Moolenaar009b2592004-10-24 19:18:58 +00002851 nbdebug(("EVT: %s", buf));
2852 nb_send(buf, "netbeans_disconnect");
2853 }
2854}
2855
Bram Moolenaar071d4272004-06-13 20:20:40 +00002856#if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_W32) || defined(PROTO)
2857/*
2858 * Tell netbeans that the window was moved or resized.
2859 */
2860 void
2861netbeans_frame_moved(int new_x, int new_y)
2862{
2863 char buf[128];
2864
2865 if (!haveConnection)
2866 return;
2867
2868 sprintf(buf, "0:geometry=%d %d %d %d %d\n",
Bram Moolenaar89d40322006-08-29 15:30:07 +00002869 r_cmdno, (int)Columns, (int)Rows, new_x, new_y);
Bram Moolenaar009b2592004-10-24 19:18:58 +00002870 /*nbdebug(("EVT: %s", buf)); happens too many times during a move */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002871 nb_send(buf, "netbeans_frame_moved");
2872}
2873#endif
2874
2875/*
Bram Moolenaar009b2592004-10-24 19:18:58 +00002876 * Tell netbeans the user opened or activated a file.
2877 */
2878 void
2879netbeans_file_activated(buf_T *bufp)
2880{
2881 int bufno = nb_getbufno(bufp);
2882 nbbuf_T *bp = nb_get_buf(bufno);
2883 char buffer[2*MAXPATHL];
2884 char_u *q;
2885
2886 if (!haveConnection || dosetvisible)
2887 return;
2888
2889 q = nb_quote(bufp->b_ffname);
Bram Moolenaareb3593b2006-04-22 22:33:57 +00002890 if (q == NULL || bp == NULL)
Bram Moolenaar009b2592004-10-24 19:18:58 +00002891 return;
2892
Bram Moolenaar9c13b352005-05-19 20:53:52 +00002893 vim_snprintf(buffer, sizeof(buffer), "%d:fileOpened=%d \"%s\" %s %s\n",
Bram Moolenaar009b2592004-10-24 19:18:58 +00002894 bufno,
2895 bufno,
2896 (char *)q,
2897 "T", /* open in NetBeans */
2898 "F"); /* modified */
2899
2900 vim_free(q);
2901 nbdebug(("EVT: %s", buffer));
2902
2903 nb_send(buffer, "netbeans_file_opened");
2904}
2905
2906/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002907 * Tell netbeans the user opened a file.
2908 */
2909 void
Bram Moolenaar009b2592004-10-24 19:18:58 +00002910netbeans_file_opened(buf_T *bufp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002911{
Bram Moolenaar009b2592004-10-24 19:18:58 +00002912 int bufno = nb_getbufno(bufp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002913 char buffer[2*MAXPATHL];
2914 char_u *q;
Bram Moolenaar009b2592004-10-24 19:18:58 +00002915 nbbuf_T *bp = nb_get_buf(nb_getbufno(bufp));
2916 int bnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002917
2918 if (!haveConnection)
2919 return;
2920
Bram Moolenaar009b2592004-10-24 19:18:58 +00002921 q = nb_quote(bufp->b_ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002922 if (q == NULL)
2923 return;
Bram Moolenaar009b2592004-10-24 19:18:58 +00002924 if (bp != NULL)
2925 bnum = bufno;
2926 else
2927 bnum = 0;
2928
Bram Moolenaar9c13b352005-05-19 20:53:52 +00002929 vim_snprintf(buffer, sizeof(buffer), "%d:fileOpened=%d \"%s\" %s %s\n",
Bram Moolenaar009b2592004-10-24 19:18:58 +00002930 bnum,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002931 0,
2932 (char *)q,
2933 "T", /* open in NetBeans */
2934 "F"); /* modified */
2935
2936 vim_free(q);
2937 nbdebug(("EVT: %s", buffer));
2938
2939 nb_send(buffer, "netbeans_file_opened");
Bram Moolenaar009b2592004-10-24 19:18:58 +00002940 if (p_acd && vim_chdirfile(bufp->b_ffname) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002941 shorten_fnames(TRUE);
2942}
2943
2944/*
Bram Moolenaard7f8f5c2009-01-06 15:14:30 +00002945 * Tell netbeans that a file was deleted or wiped out.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002946 */
2947 void
Bram Moolenaard7f8f5c2009-01-06 15:14:30 +00002948netbeans_file_killed(buf_T *bufp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002949{
2950 int bufno = nb_getbufno(bufp);
2951 nbbuf_T *nbbuf = nb_get_buf(bufno);
2952 char buffer[2*MAXPATHL];
2953
Bram Moolenaard7f8f5c2009-01-06 15:14:30 +00002954 if (!haveConnection || bufno == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002955 return;
2956
Bram Moolenaard7f8f5c2009-01-06 15:14:30 +00002957 nbdebug(("netbeans_file_killed:\n"));
2958 nbdebug((" Killing bufno: %d", bufno));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002959
Bram Moolenaar89d40322006-08-29 15:30:07 +00002960 sprintf(buffer, "%d:killed=%d\n", bufno, r_cmdno);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002961
2962 nbdebug(("EVT: %s", buffer));
2963
Bram Moolenaard7f8f5c2009-01-06 15:14:30 +00002964 nb_send(buffer, "netbeans_file_killed");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002965
2966 if (nbbuf != NULL)
2967 nbbuf->bufp = NULL;
2968}
2969
2970/*
2971 * Get a pointer to the Netbeans buffer for Vim buffer "bufp".
2972 * Return NULL if there is no such buffer or changes are not to be reported.
2973 * Otherwise store the buffer number in "*bufnop".
2974 */
2975 static nbbuf_T *
2976nb_bufp2nbbuf_fire(buf_T *bufp, int *bufnop)
2977{
2978 int bufno;
2979 nbbuf_T *nbbuf;
2980
2981 if (!haveConnection || !netbeansFireChanges)
2982 return NULL; /* changes are not reported at all */
2983
2984 bufno = nb_getbufno(bufp);
2985 if (bufno <= 0)
2986 return NULL; /* file is not known to NetBeans */
2987
2988 nbbuf = nb_get_buf(bufno);
2989 if (nbbuf != NULL && !nbbuf->fireChanges)
2990 return NULL; /* changes in this buffer are not reported */
2991
2992 *bufnop = bufno;
2993 return nbbuf;
2994}
2995
2996/*
2997 * Tell netbeans the user inserted some text.
2998 */
2999 void
3000netbeans_inserted(
3001 buf_T *bufp,
3002 linenr_T linenr,
3003 colnr_T col,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003004 char_u *txt,
3005 int newlen)
3006{
3007 char_u *buf;
3008 int bufno;
3009 nbbuf_T *nbbuf;
3010 pos_T pos;
3011 long off;
3012 char_u *p;
3013 char_u *newtxt;
3014
3015 nbbuf = nb_bufp2nbbuf_fire(bufp, &bufno);
3016 if (nbbuf == NULL)
3017 return;
3018
Bram Moolenaar009b2592004-10-24 19:18:58 +00003019 /* Don't mark as modified for initial read */
3020 if (nbbuf->insertDone)
3021 nbbuf->modified = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003022
3023 pos.lnum = linenr;
3024 pos.col = col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003025 off = pos2off(bufp, &pos);
3026
Bram Moolenaar071d4272004-06-13 20:20:40 +00003027 /* send the "insert" EVT */
3028 newtxt = alloc(newlen + 1);
Bram Moolenaarb6356332005-07-18 21:40:44 +00003029 vim_strncpy(newtxt, txt, newlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003030 p = nb_quote(newtxt);
3031 if (p != NULL)
3032 {
Bram Moolenaar009b2592004-10-24 19:18:58 +00003033 buf = alloc(128 + 2*newlen);
Bram Moolenaar89d40322006-08-29 15:30:07 +00003034 sprintf((char *)buf, "%d:insert=%d %ld \"%s\"\n",
3035 bufno, r_cmdno, off, p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003036 nbdebug(("EVT: %s", buf));
3037 nb_send((char *)buf, "netbeans_inserted");
Bram Moolenaar009b2592004-10-24 19:18:58 +00003038 vim_free(p);
3039 vim_free(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003040 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003041 vim_free(newtxt);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003042}
3043
3044/*
3045 * Tell netbeans some bytes have been removed.
3046 */
3047 void
3048netbeans_removed(
3049 buf_T *bufp,
3050 linenr_T linenr,
3051 colnr_T col,
3052 long len)
3053{
3054 char_u buf[128];
3055 int bufno;
3056 nbbuf_T *nbbuf;
3057 pos_T pos;
3058 long off;
3059
3060 nbbuf = nb_bufp2nbbuf_fire(bufp, &bufno);
3061 if (nbbuf == NULL)
3062 return;
3063
3064 if (len < 0)
3065 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00003066 nbdebug(("Negative len %ld in netbeans_removed()!\n", len));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003067 return;
3068 }
3069
3070 nbbuf->modified = 1;
3071
3072 pos.lnum = linenr;
3073 pos.col = col;
3074
3075 off = pos2off(bufp, &pos);
3076
Bram Moolenaar89d40322006-08-29 15:30:07 +00003077 sprintf((char *)buf, "%d:remove=%d %ld %ld\n", bufno, r_cmdno, off, len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003078 nbdebug(("EVT: %s", buf));
3079 nb_send((char *)buf, "netbeans_removed");
3080}
3081
3082/*
Bram Moolenaar2660c0e2010-01-19 14:59:56 +01003083 * Send netbeans an unmodified command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003084 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003085 void
Bram Moolenaarb85cb212009-05-17 14:24:23 +00003086netbeans_unmodified(buf_T *bufp UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003087{
3088#if 0
3089 char_u buf[128];
3090 int bufno;
3091 nbbuf_T *nbbuf;
3092
3093 /* This has been disabled, because NetBeans considers a buffer modified
3094 * even when all changes have been undone. */
3095 nbbuf = nb_bufp2nbbuf_fire(bufp, &bufno);
3096 if (nbbuf == NULL)
3097 return;
3098
3099 nbbuf->modified = 0;
3100
Bram Moolenaar89d40322006-08-29 15:30:07 +00003101 sprintf((char *)buf, "%d:unmodified=%d\n", bufno, r_cmdno);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003102 nbdebug(("EVT: %s", buf));
3103 nb_send((char *)buf, "netbeans_unmodified");
3104#endif
3105}
3106
3107/*
3108 * Send a button release event back to netbeans. Its up to netbeans
3109 * to decide what to do (if anything) with this event.
3110 */
3111 void
3112netbeans_button_release(int button)
3113{
3114 char buf[128];
3115 int bufno;
3116
3117 bufno = nb_getbufno(curbuf);
3118
3119 if (bufno >= 0 && curwin != NULL && curwin->w_buffer == curbuf)
3120 {
Bram Moolenaarc92ad2e2005-01-19 22:08:28 +00003121 int col = mouse_col - W_WINCOL(curwin) - (curwin->w_p_nu ? 9 : 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003122 long off = pos2off(curbuf, &curwin->w_cursor);
3123
3124 /* sync the cursor position */
Bram Moolenaar89d40322006-08-29 15:30:07 +00003125 sprintf(buf, "%d:newDotAndMark=%d %ld %ld\n", bufno, r_cmdno, off, off);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003126 nbdebug(("EVT: %s", buf));
3127 nb_send(buf, "netbeans_button_release[newDotAndMark]");
3128
Bram Moolenaar89d40322006-08-29 15:30:07 +00003129 sprintf(buf, "%d:buttonRelease=%d %d %ld %d\n", bufno, r_cmdno,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003130 button, (long)curwin->w_cursor.lnum, col);
3131 nbdebug(("EVT: %s", buf));
3132 nb_send(buf, "netbeans_button_release");
3133 }
3134}
3135
3136
3137/*
Bram Moolenaar143c38c2007-05-10 16:41:10 +00003138 * Send a keypress event back to netbeans. This usually simulates some
Bram Moolenaar009b2592004-10-24 19:18:58 +00003139 * kind of function key press. This function operates on a key code.
Bram Moolenaar8065d7f2010-01-19 15:13:14 +01003140 * Return TRUE when the key was sent, FALSE when the command has been
3141 * postponed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003142 */
Bram Moolenaar8065d7f2010-01-19 15:13:14 +01003143 int
Bram Moolenaar071d4272004-06-13 20:20:40 +00003144netbeans_keycommand(int key)
3145{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003146 char keyName[60];
Bram Moolenaar009b2592004-10-24 19:18:58 +00003147
3148 netbeans_keyname(key, keyName);
Bram Moolenaar8065d7f2010-01-19 15:13:14 +01003149 return netbeans_keystring((char_u *)keyName);
Bram Moolenaar009b2592004-10-24 19:18:58 +00003150}
3151
3152
3153/*
Bram Moolenaar143c38c2007-05-10 16:41:10 +00003154 * Send a keypress event back to netbeans. This usually simulates some
Bram Moolenaar009b2592004-10-24 19:18:58 +00003155 * kind of function key press. This function operates on a key string.
Bram Moolenaar8065d7f2010-01-19 15:13:14 +01003156 * Return TRUE when the key was sent, FALSE when the command has been
3157 * postponed.
Bram Moolenaar009b2592004-10-24 19:18:58 +00003158 */
Bram Moolenaar8065d7f2010-01-19 15:13:14 +01003159 static int
3160netbeans_keystring(char_u *keyName)
Bram Moolenaar009b2592004-10-24 19:18:58 +00003161{
3162 char buf[2*MAXPATHL];
3163 int bufno = nb_getbufno(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003164 long off;
3165 char_u *q;
3166
3167 if (!haveConnection)
Bram Moolenaar8065d7f2010-01-19 15:13:14 +01003168 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003169
Bram Moolenaar071d4272004-06-13 20:20:40 +00003170
3171 if (bufno == -1)
3172 {
3173 nbdebug(("got keycommand for non-NetBeans buffer, opening...\n"));
3174 q = curbuf->b_ffname == NULL ? (char_u *)""
3175 : nb_quote(curbuf->b_ffname);
3176 if (q == NULL)
Bram Moolenaar8065d7f2010-01-19 15:13:14 +01003177 return TRUE;
Bram Moolenaar9c13b352005-05-19 20:53:52 +00003178 vim_snprintf(buf, sizeof(buf), "0:fileOpened=%d \"%s\" %s %s\n", 0,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003179 q,
3180 "T", /* open in NetBeans */
3181 "F"); /* modified */
3182 if (curbuf->b_ffname != NULL)
3183 vim_free(q);
3184 nbdebug(("EVT: %s", buf));
3185 nb_send(buf, "netbeans_keycommand");
3186
Bram Moolenaar8065d7f2010-01-19 15:13:14 +01003187 postpone_keycommand(keyName);
3188 return FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003189 }
3190
3191 /* sync the cursor position */
3192 off = pos2off(curbuf, &curwin->w_cursor);
Bram Moolenaar89d40322006-08-29 15:30:07 +00003193 sprintf(buf, "%d:newDotAndMark=%d %ld %ld\n", bufno, r_cmdno, off, off);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003194 nbdebug(("EVT: %s", buf));
3195 nb_send(buf, "netbeans_keycommand");
3196
3197 /* To work on Win32 you must apply patch to ExtEditor module
3198 * from ExtEdCaret.java.diff - make EVT_newDotAndMark handler
3199 * more synchronous
3200 */
3201
3202 /* now send keyCommand event */
Bram Moolenaar9c13b352005-05-19 20:53:52 +00003203 vim_snprintf(buf, sizeof(buf), "%d:keyCommand=%d \"%s\"\n",
Bram Moolenaar89d40322006-08-29 15:30:07 +00003204 bufno, r_cmdno, keyName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003205 nbdebug(("EVT: %s", buf));
3206 nb_send(buf, "netbeans_keycommand");
3207
3208 /* New: do both at once and include the lnum/col. */
Bram Moolenaar9c13b352005-05-19 20:53:52 +00003209 vim_snprintf(buf, sizeof(buf), "%d:keyAtPos=%d \"%s\" %ld %ld/%ld\n",
Bram Moolenaar89d40322006-08-29 15:30:07 +00003210 bufno, r_cmdno, keyName,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003211 off, (long)curwin->w_cursor.lnum, (long)curwin->w_cursor.col);
3212 nbdebug(("EVT: %s", buf));
3213 nb_send(buf, "netbeans_keycommand");
Bram Moolenaar8065d7f2010-01-19 15:13:14 +01003214 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003215}
3216
3217
3218/*
3219 * Send a save event to netbeans.
3220 */
3221 void
3222netbeans_save_buffer(buf_T *bufp)
3223{
3224 char_u buf[64];
3225 int bufno;
3226 nbbuf_T *nbbuf;
3227
3228 nbbuf = nb_bufp2nbbuf_fire(bufp, &bufno);
3229 if (nbbuf == NULL)
3230 return;
3231
3232 nbbuf->modified = 0;
3233
Bram Moolenaar89d40322006-08-29 15:30:07 +00003234 sprintf((char *)buf, "%d:save=%d\n", bufno, r_cmdno);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003235 nbdebug(("EVT: %s", buf));
3236 nb_send((char *)buf, "netbeans_save_buffer");
3237}
3238
3239
3240/*
3241 * Send remove command to netbeans (this command has been turned off).
3242 */
3243 void
3244netbeans_deleted_all_lines(buf_T *bufp)
3245{
3246 char_u buf[64];
3247 int bufno;
3248 nbbuf_T *nbbuf;
3249
3250 nbbuf = nb_bufp2nbbuf_fire(bufp, &bufno);
3251 if (nbbuf == NULL)
3252 return;
3253
Bram Moolenaar009b2592004-10-24 19:18:58 +00003254 /* Don't mark as modified for initial read */
3255 if (nbbuf->insertDone)
3256 nbbuf->modified = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003257
Bram Moolenaar89d40322006-08-29 15:30:07 +00003258 sprintf((char *)buf, "%d:remove=%d 0 -1\n", bufno, r_cmdno);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003259 nbdebug(("EVT(suppressed): %s", buf));
3260/* nb_send(buf, "netbeans_deleted_all_lines"); */
3261}
3262
3263
3264/*
3265 * See if the lines are guarded. The top and bot parameters are from
3266 * u_savecommon(), these are the line above the change and the line below the
3267 * change.
3268 */
3269 int
3270netbeans_is_guarded(linenr_T top, linenr_T bot)
3271{
3272 signlist_T *p;
3273 int lnum;
3274
3275 for (p = curbuf->b_signlist; p != NULL; p = p->next)
3276 if (p->id >= GUARDEDOFFSET)
3277 for (lnum = top + 1; lnum < bot; lnum++)
3278 if (lnum == p->lnum)
3279 return TRUE;
3280
3281 return FALSE;
3282}
3283
3284#if defined(FEAT_GUI_MOTIF) || defined(PROTO)
3285/*
3286 * We have multiple signs to draw at the same location. Draw the
3287 * multi-sign indicator instead. This is the Motif version.
3288 */
3289 void
3290netbeans_draw_multisign_indicator(int row)
3291{
3292 int i;
3293 int y;
3294 int x;
3295
3296 x = 0;
3297 y = row * gui.char_height + 2;
3298
3299 for (i = 0; i < gui.char_height - 3; i++)
3300 XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+2, y++);
3301
3302 XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+0, y);
3303 XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+2, y);
3304 XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+4, y++);
3305 XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+1, y);
3306 XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+2, y);
3307 XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+3, y++);
3308 XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+2, y);
3309}
3310#endif /* FEAT_GUI_MOTIF */
3311
3312#ifdef FEAT_GUI_GTK
3313/*
3314 * We have multiple signs to draw at the same location. Draw the
3315 * multi-sign indicator instead. This is the GTK/Gnome version.
3316 */
3317 void
3318netbeans_draw_multisign_indicator(int row)
3319{
3320 int i;
3321 int y;
3322 int x;
3323 GdkDrawable *drawable = gui.drawarea->window;
3324
3325 x = 0;
3326 y = row * gui.char_height + 2;
3327
3328 for (i = 0; i < gui.char_height - 3; i++)
3329 gdk_draw_point(drawable, gui.text_gc, x+2, y++);
3330
3331 gdk_draw_point(drawable, gui.text_gc, x+0, y);
3332 gdk_draw_point(drawable, gui.text_gc, x+2, y);
3333 gdk_draw_point(drawable, gui.text_gc, x+4, y++);
3334 gdk_draw_point(drawable, gui.text_gc, x+1, y);
3335 gdk_draw_point(drawable, gui.text_gc, x+2, y);
3336 gdk_draw_point(drawable, gui.text_gc, x+3, y++);
3337 gdk_draw_point(drawable, gui.text_gc, x+2, y);
3338}
3339#endif /* FEAT_GUI_GTK */
3340
3341/*
3342 * If the mouse is clicked in the gutter of a line with multiple
3343 * annotations, cycle through the set of signs.
3344 */
3345 void
3346netbeans_gutter_click(linenr_T lnum)
3347{
3348 signlist_T *p;
3349
3350 for (p = curbuf->b_signlist; p != NULL; p = p->next)
3351 {
3352 if (p->lnum == lnum && p->next && p->next->lnum == lnum)
3353 {
3354 signlist_T *tail;
3355
3356 /* remove "p" from list, reinsert it at the tail of the sublist */
3357 if (p->prev)
3358 p->prev->next = p->next;
3359 else
3360 curbuf->b_signlist = p->next;
3361 p->next->prev = p->prev;
3362 /* now find end of sublist and insert p */
3363 for (tail = p->next;
3364 tail->next && tail->next->lnum == lnum
3365 && tail->next->id < GUARDEDOFFSET;
3366 tail = tail->next)
3367 ;
3368 /* tail now points to last entry with same lnum (except
3369 * that "guarded" annotations are always last) */
3370 p->next = tail->next;
3371 if (tail->next)
3372 tail->next->prev = p;
3373 p->prev = tail;
3374 tail->next = p;
3375 update_debug_sign(curbuf, lnum);
3376 break;
3377 }
3378 }
3379}
3380
3381
3382/*
Bram Moolenaar2660c0e2010-01-19 14:59:56 +01003383 * Add a sign of the requested type at the requested location.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003384 *
3385 * Reverse engineering:
3386 * Apparently an annotation is defined the first time it is used in a buffer.
3387 * When the same annotation is used in two buffers, the second time we do not
3388 * need to define a new sign name but reuse the existing one. But since the
3389 * ID number used in the second buffer starts counting at one again, a mapping
3390 * is made from the ID specifically for the buffer to the global sign name
3391 * (which is a number).
3392 *
3393 * globalsignmap[] stores the signs that have been defined globally.
3394 * buf->signmapused[] maps buffer-local annotation IDs to an index in
3395 * globalsignmap[].
3396 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003397 static void
3398addsigntype(
3399 nbbuf_T *buf,
3400 int typeNum,
3401 char_u *typeName,
Bram Moolenaarb85cb212009-05-17 14:24:23 +00003402 char_u *tooltip UNUSED,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003403 char_u *glyphFile,
3404 int use_fg,
3405 int fg,
3406 int use_bg,
3407 int bg)
3408{
3409 char fgbuf[32];
3410 char bgbuf[32];
3411 int i, j;
3412
3413 for (i = 0; i < globalsignmapused; i++)
3414 if (STRCMP(typeName, globalsignmap[i]) == 0)
3415 break;
3416
3417 if (i == globalsignmapused) /* not found; add it to global map */
3418 {
3419 nbdebug(("DEFINEANNOTYPE(%d,%s,%s,%s,%d,%d)\n",
3420 typeNum, typeName, tooltip, glyphFile, fg, bg));
3421 if (use_fg || use_bg)
3422 {
3423 sprintf(fgbuf, "guifg=#%06x", fg & 0xFFFFFF);
3424 sprintf(bgbuf, "guibg=#%06x", bg & 0xFFFFFF);
3425
3426 coloncmd(":highlight NB_%s %s %s", typeName, (use_fg) ? fgbuf : "",
3427 (use_bg) ? bgbuf : "");
3428 if (*glyphFile == NUL)
3429 /* no glyph, line highlighting only */
3430 coloncmd(":sign define %d linehl=NB_%s", i + 1, typeName);
3431 else if (vim_strsize(glyphFile) <= 2)
3432 /* one- or two-character glyph name, use as text glyph with
3433 * texthl */
3434 coloncmd(":sign define %d text=%s texthl=NB_%s", i + 1,
3435 glyphFile, typeName);
3436 else
3437 /* glyph, line highlighting */
3438 coloncmd(":sign define %d icon=%s linehl=NB_%s", i + 1,
3439 glyphFile, typeName);
3440 }
3441 else
3442 /* glyph, no line highlighting */
3443 coloncmd(":sign define %d icon=%s", i + 1, glyphFile);
3444
3445 if (STRCMP(typeName,"CurrentPC") == 0)
3446 curPCtype = typeNum;
3447
3448 if (globalsignmapused == globalsignmaplen)
3449 {
3450 if (globalsignmaplen == 0) /* first allocation */
3451 {
3452 globalsignmaplen = 20;
3453 globalsignmap = (char **)alloc_clear(globalsignmaplen*sizeof(char *));
3454 }
3455 else /* grow it */
3456 {
3457 int incr;
3458 int oldlen = globalsignmaplen;
3459
3460 globalsignmaplen *= 2;
3461 incr = globalsignmaplen - oldlen;
3462 globalsignmap = (char **)vim_realloc(globalsignmap,
3463 globalsignmaplen * sizeof(char *));
3464 memset(globalsignmap + oldlen, 0, incr * sizeof(char *));
3465 }
3466 }
3467
3468 globalsignmap[i] = (char *)typeName;
3469 globalsignmapused = i + 1;
3470 }
3471
3472 /* check local map; should *not* be found! */
3473 for (j = 0; j < buf->signmapused; j++)
3474 if (buf->signmap[j] == i + 1)
3475 return;
3476
3477 /* add to local map */
3478 if (buf->signmapused == buf->signmaplen)
3479 {
3480 if (buf->signmaplen == 0) /* first allocation */
3481 {
3482 buf->signmaplen = 5;
3483 buf->signmap = (int *)alloc_clear(buf->signmaplen * sizeof(int *));
3484 }
3485 else /* grow it */
3486 {
3487 int incr;
3488 int oldlen = buf->signmaplen;
3489 buf->signmaplen *= 2;
3490 incr = buf->signmaplen - oldlen;
3491 buf->signmap = (int *)vim_realloc(buf->signmap,
3492 buf->signmaplen*sizeof(int *));
3493 memset(buf->signmap + oldlen, 0, incr * sizeof(int *));
3494 }
3495 }
3496
3497 buf->signmap[buf->signmapused++] = i + 1;
3498
3499}
3500
3501
3502/*
3503 * See if we have the requested sign type in the buffer.
3504 */
3505 static int
3506mapsigntype(nbbuf_T *buf, int localsigntype)
3507{
3508 if (--localsigntype >= 0 && localsigntype < buf->signmapused)
3509 return buf->signmap[localsigntype];
3510
3511 return 0;
3512}
3513
3514
3515/*
3516 * Compute length of buffer, don't print anything.
3517 */
3518 static long
3519get_buf_size(buf_T *bufp)
3520{
3521 linenr_T lnum;
3522 long char_count = 0;
3523 int eol_size;
3524 long last_check = 100000L;
3525
3526 if (bufp->b_ml.ml_flags & ML_EMPTY)
3527 return 0;
3528 else
3529 {
3530 if (get_fileformat(bufp) == EOL_DOS)
3531 eol_size = 2;
3532 else
3533 eol_size = 1;
3534 for (lnum = 1; lnum <= bufp->b_ml.ml_line_count; ++lnum)
3535 {
Bram Moolenaarfa68b0f2009-09-11 12:19:51 +00003536 char_count += (long)STRLEN(ml_get_buf(bufp, lnum, FALSE))
3537 + eol_size;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003538 /* Check for a CTRL-C every 100000 characters */
3539 if (char_count > last_check)
3540 {
3541 ui_breakcheck();
3542 if (got_int)
3543 return char_count;
3544 last_check = char_count + 100000L;
3545 }
3546 }
3547 /* Correction for when last line doesn't have an EOL. */
3548 if (!bufp->b_p_eol && bufp->b_p_bin)
3549 char_count -= eol_size;
3550 }
3551
3552 return char_count;
3553}
3554
3555/*
3556 * Convert character offset to lnum,col
3557 */
3558 static pos_T *
3559off2pos(buf_T *buf, long offset)
3560{
3561 linenr_T lnum;
3562 static pos_T pos;
3563
3564 pos.lnum = 0;
3565 pos.col = 0;
3566#ifdef FEAT_VIRTUALEDIT
3567 pos.coladd = 0;
3568#endif
3569
3570 if (!(buf->b_ml.ml_flags & ML_EMPTY))
3571 {
3572 if ((lnum = ml_find_line_or_offset(buf, (linenr_T)0, &offset)) < 0)
3573 return NULL;
3574 pos.lnum = lnum;
3575 pos.col = offset;
3576 }
3577
3578 return &pos;
3579}
3580
3581/*
3582 * Convert an argument in the form "1234" to an offset and compute the
3583 * lnum/col from it. Convert an argument in the form "123/12" directly to a
3584 * lnum/col.
3585 * "argp" is advanced to after the argument.
3586 * Return a pointer to the position, NULL if something is wrong.
3587 */
3588 static pos_T *
3589get_off_or_lnum(buf_T *buf, char_u **argp)
3590{
3591 static pos_T mypos;
3592 long off;
3593
3594 off = strtol((char *)*argp, (char **)argp, 10);
3595 if (**argp == '/')
3596 {
3597 mypos.lnum = (linenr_T)off;
3598 ++*argp;
3599 mypos.col = strtol((char *)*argp, (char **)argp, 10);
3600#ifdef FEAT_VIRTUALEDIT
3601 mypos.coladd = 0;
3602#endif
3603 return &mypos;
3604 }
3605 return off2pos(buf, off);
3606}
3607
3608
3609/*
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003610 * Convert (lnum,col) to byte offset in the file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003611 */
3612 static long
3613pos2off(buf_T *buf, pos_T *pos)
3614{
3615 long offset = 0;
3616
3617 if (!(buf->b_ml.ml_flags & ML_EMPTY))
3618 {
3619 if ((offset = ml_find_line_or_offset(buf, pos->lnum, 0)) < 0)
3620 return 0;
3621 offset += pos->col;
3622 }
3623
3624 return offset;
3625}
3626
3627
Bram Moolenaar009b2592004-10-24 19:18:58 +00003628/*
3629 * This message is printed after NetBeans opens a new file. Its
3630 * similar to the message readfile() uses, but since NetBeans
3631 * doesn't normally call readfile, we do our own.
3632 */
3633 static void
3634print_read_msg(buf)
3635 nbbuf_T *buf;
3636{
3637 int lnum = buf->bufp->b_ml.ml_line_count;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003638 long nchars = (long)buf->bufp->b_orig_size;
Bram Moolenaar009b2592004-10-24 19:18:58 +00003639 char_u c;
3640
3641 msg_add_fname(buf->bufp, buf->bufp->b_ffname);
3642 c = FALSE;
3643
3644 if (buf->bufp->b_p_ro)
3645 {
3646 STRCAT(IObuff, shortmess(SHM_RO) ? _("[RO]") : _("[readonly]"));
3647 c = TRUE;
3648 }
3649 if (!buf->bufp->b_start_eol)
3650 {
3651 STRCAT(IObuff, shortmess(SHM_LAST) ? _("[noeol]") : _("[Incomplete last line]"));
3652 c = TRUE;
3653 }
3654 msg_add_lines(c, (long)lnum, nchars);
3655
3656 /* Now display it */
3657 vim_free(keep_msg);
3658 keep_msg = NULL;
3659 msg_scrolled_ign = TRUE;
3660 msg_trunc_attr(IObuff, FALSE, 0);
3661 msg_scrolled_ign = FALSE;
3662}
3663
3664
3665/*
3666 * Print a message after NetBeans writes the file. This message should be identical
3667 * to the standard message a non-netbeans user would see when writing a file.
3668 */
3669 static void
3670print_save_msg(buf, nchars)
3671 nbbuf_T *buf;
3672 long nchars;
3673{
3674 char_u c;
3675 char_u *p;
3676
3677 if (nchars >= 0)
3678 {
3679 msg_add_fname(buf->bufp, buf->bufp->b_ffname); /* fname in IObuff with quotes */
3680 c = FALSE;
3681
3682 msg_add_lines(c, buf->bufp->b_ml.ml_line_count,
3683 (long)buf->bufp->b_orig_size);
3684
3685 vim_free(keep_msg);
3686 keep_msg = NULL;
3687 msg_scrolled_ign = TRUE;
3688 p = msg_trunc_attr(IObuff, FALSE, 0);
3689 if ((msg_scrolled && !need_wait_return) || !buf->initDone)
3690 {
3691 /* Need to repeat the message after redrawing when:
3692 * - When reading from stdin (the screen will be cleared next).
3693 * - When restart_edit is set (otherwise there will be a delay
3694 * before redrawing).
3695 * - When the screen was scrolled but there is no wait-return
3696 * prompt. */
Bram Moolenaar030f0df2006-02-21 22:02:53 +00003697 set_keep_msg(p, 0);
Bram Moolenaar009b2592004-10-24 19:18:58 +00003698 }
3699 msg_scrolled_ign = FALSE;
3700 /* add_to_input_buf((char_u *)"\f", 1); */
3701 }
3702 else
3703 {
3704 char_u ebuf[BUFSIZ];
3705
3706 STRCPY(ebuf, (char_u *)_("E505: "));
3707 STRCAT(ebuf, IObuff);
3708 STRCAT(ebuf, (char_u *)_("is read-only (add ! to override)"));
3709 STRCPY(IObuff, ebuf);
Bram Moolenaarf2330482008-06-24 20:19:36 +00003710 nbdebug((" %s\n", ebuf ));
Bram Moolenaar009b2592004-10-24 19:18:58 +00003711 emsg(IObuff);
3712 }
3713}
3714
Bram Moolenaar071d4272004-06-13 20:20:40 +00003715#endif /* defined(FEAT_NETBEANS_INTG) */