blob: ea0c017ad6522d9273ba8df201b8fadd12d45a25 [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.
Bram Moolenaare3cc6d42011-10-20 21:58:34 +020017 *
18 * The Netbeans messages are received and queued in the gui event loop, or in
19 * the select loop when Vim runs in a terminal. These messages are processed
20 * by netbeans_parse_messages() which is invoked in the idle loop when Vim is
21 * waiting for user input. The function netbeans_parse_messages() is also
22 * called from the ":sleep" command, to allow the execution of test cases that
23 * may not invoke the idle loop.
Bram Moolenaar071d4272004-06-13 20:20:40 +000024 */
25
26#include "vim.h"
27
28#if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
29
Bram Moolenaarb26e6322010-05-22 21:34:09 +020030/* TODO: when should this not be defined? */
31#define INET_SOCKETS
32
Bram Moolenaar071d4272004-06-13 20:20:40 +000033/* Note: when making changes here also adjust configure.in. */
Bram Moolenaar071d4272004-06-13 20:20:40 +000034#ifdef WIN32
35# ifdef DEBUG
36# include <tchar.h> /* for _T definition for TRACEn macros */
37# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000038/* WinSock API is separated from C API, thus we can't use read(), write(),
39 * errno... */
Bram Moolenaarc39125d2010-05-23 12:06:58 +020040# define SOCK_ERRNO errno = WSAGetLastError()
Bram Moolenaarbd42a0f2009-06-16 14:57:26 +000041# undef ECONNREFUSED
Bram Moolenaar071d4272004-06-13 20:20:40 +000042# define ECONNREFUSED WSAECONNREFUSED
43# ifdef EINTR
44# undef EINTR
45# endif
46# define EINTR WSAEINTR
47# define sock_write(sd, buf, len) send(sd, buf, len, 0)
48# define sock_read(sd, buf, len) recv(sd, buf, len, 0)
49# define sock_close(sd) closesocket(sd)
50# define sleep(t) Sleep(t*1000) /* WinAPI Sleep() accepts milliseconds */
51#else
Bram Moolenaarb26e6322010-05-22 21:34:09 +020052# ifdef INET_SOCKETS
53# include <netdb.h>
54# include <netinet/in.h>
55# else
56# include <sys/un.h>
57# endif
58
Bram Moolenaar071d4272004-06-13 20:20:40 +000059# include <sys/socket.h>
60# ifdef HAVE_LIBGEN_H
61# include <libgen.h>
62# endif
Bram Moolenaarc39125d2010-05-23 12:06:58 +020063# define SOCK_ERRNO
Bram Moolenaar071d4272004-06-13 20:20:40 +000064# define sock_write(sd, buf, len) write(sd, buf, len)
65# define sock_read(sd, buf, len) read(sd, buf, len)
66# define sock_close(sd) close(sd)
67#endif
68
69#include "version.h"
70
Bram Moolenaar071d4272004-06-13 20:20:40 +000071#define GUARDED 10000 /* typenr for "guarded" annotation */
72#define GUARDEDOFFSET 1000000 /* base for "guarded" sign id's */
Bram Moolenaar67c53842010-05-22 18:28:27 +020073#define MAX_COLOR_LENGTH 32 /* max length of color name in defineAnnoType */
Bram Moolenaar071d4272004-06-13 20:20:40 +000074
75/* The first implementation (working only with Netbeans) returned "1.1". The
76 * protocol implemented here also supports A-A-P. */
Bram Moolenaar67c53842010-05-22 18:28:27 +020077static char *ExtEdProtocolVersion = "2.5";
Bram Moolenaar071d4272004-06-13 20:20:40 +000078
79static long pos2off __ARGS((buf_T *, pos_T *));
80static pos_T *off2pos __ARGS((buf_T *, long));
81static pos_T *get_off_or_lnum __ARGS((buf_T *buf, char_u **argp));
82static long get_buf_size __ARGS((buf_T *));
Bram Moolenaar8065d7f2010-01-19 15:13:14 +010083static int netbeans_keystring __ARGS((char_u *keystr));
84static void postpone_keycommand __ARGS((char_u *keystr));
Bram Moolenaar009b2592004-10-24 19:18:58 +000085static void special_keys __ARGS((char_u *args));
Bram Moolenaar071d4272004-06-13 20:20:40 +000086
Bram Moolenaarb26e6322010-05-22 21:34:09 +020087static int netbeans_connect __ARGS((char *, int));
Bram Moolenaar071d4272004-06-13 20:20:40 +000088static int getConnInfo __ARGS((char *file, char **host, char **port, char **password));
89
90static void nb_init_graphics __ARGS((void));
91static void coloncmd __ARGS((char *cmd, ...));
Bram Moolenaar8b6144b2006-02-08 09:20:24 +000092static void nb_set_curbuf __ARGS((buf_T *buf));
Bram Moolenaar173c9852010-09-29 17:27:01 +020093#ifdef FEAT_GUI_X11
Bram Moolenaar071d4272004-06-13 20:20:40 +000094static void messageFromNetbeans __ARGS((XtPointer, int *, XtInputId *));
95#endif
96#ifdef FEAT_GUI_GTK
97static void messageFromNetbeans __ARGS((gpointer, gint, GdkInputCondition));
98#endif
99static void nb_parse_cmd __ARGS((char_u *));
100static int nb_do_cmd __ARGS((int, char_u *, int, int, char_u *));
101static void nb_send __ARGS((char *buf, char *fun));
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200102static void nb_free __ARGS((void));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000103
Bram Moolenaar67c53842010-05-22 18:28:27 +0200104/* TRUE when netbeans is running with a GUI. */
105#ifdef FEAT_GUI
106# define NB_HAS_GUI (gui.in_use || gui.starting)
107#endif
108
Bram Moolenaara93fa7e2006-04-17 22:14:47 +0000109#ifdef WIN64
110typedef __int64 NBSOCK;
111#else
112typedef int NBSOCK;
113#endif
114
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200115static NBSOCK nbsock = -1; /* socket fd for Netbeans connection */
116#define NETBEANS_OPEN (nbsock != -1)
117
Bram Moolenaar173c9852010-09-29 17:27:01 +0200118#ifdef FEAT_GUI_X11
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200119static XtInputId inputHandler = (XtInputId)NULL; /* Cookie for input */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000120#endif
121#ifdef FEAT_GUI_GTK
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200122static gint inputHandler = 0; /* Cookie for input */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000123#endif
124#ifdef FEAT_GUI_W32
125static int inputHandler = -1; /* simply ret.value of WSAAsyncSelect() */
126extern HWND s_hwnd; /* Gvim's Window handle */
127#endif
Bram Moolenaar89d40322006-08-29 15:30:07 +0000128static int r_cmdno; /* current command number for reply */
Bram Moolenaar009b2592004-10-24 19:18:58 +0000129static int dosetvisible = FALSE;
130
Bram Moolenaar071d4272004-06-13 20:20:40 +0000131/*
132 * Include the debugging code if wanted.
133 */
134#ifdef NBDEBUG
135# include "nbdebug.c"
136#endif
137
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200138static int needupdate = 0;
139static int inAtomic = 0;
140
Bram Moolenaar7ad7d012010-11-16 15:49:02 +0100141/*
142 * Close the socket and remove the input handlers.
143 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000144 static void
Bram Moolenaar7ad7d012010-11-16 15:49:02 +0100145nb_close_socket(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000146{
Bram Moolenaar3b7b8362015-03-20 18:11:48 +0100147 buf_T *buf;
148
149 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
150 buf->b_has_sign_column = FALSE;
151
Bram Moolenaar173c9852010-09-29 17:27:01 +0200152#ifdef FEAT_GUI_X11
Bram Moolenaar071d4272004-06-13 20:20:40 +0000153 if (inputHandler != (XtInputId)NULL)
154 {
155 XtRemoveInput(inputHandler);
156 inputHandler = (XtInputId)NULL;
157 }
Bram Moolenaar67c53842010-05-22 18:28:27 +0200158#else
159# ifdef FEAT_GUI_GTK
Bram Moolenaar071d4272004-06-13 20:20:40 +0000160 if (inputHandler != 0)
161 {
162 gdk_input_remove(inputHandler);
163 inputHandler = 0;
164 }
Bram Moolenaar67c53842010-05-22 18:28:27 +0200165# else
166# ifdef FEAT_GUI_W32
Bram Moolenaar071d4272004-06-13 20:20:40 +0000167 if (inputHandler == 0)
168 {
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200169 WSAAsyncSelect(nbsock, s_hwnd, 0, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000170 inputHandler = -1;
171 }
Bram Moolenaar67c53842010-05-22 18:28:27 +0200172# endif
173# endif
174#endif
175
Bram Moolenaar7ad7d012010-11-16 15:49:02 +0100176 sock_close(nbsock);
177 nbsock = -1;
178}
179
180/*
181 * Close the connection and cleanup.
182 * May be called when nb_close_socket() was called earlier.
183 */
184 static void
185netbeans_close(void)
186{
187 if (NETBEANS_OPEN)
188 {
189 netbeans_send_disconnect();
190 nb_close_socket();
191 }
192
Bram Moolenaar67c53842010-05-22 18:28:27 +0200193#ifdef FEAT_BEVAL
Bram Moolenaard62bec82005-03-07 22:56:57 +0000194 bevalServers &= ~BEVAL_NETBEANS;
Bram Moolenaar67c53842010-05-22 18:28:27 +0200195#endif
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200196
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200197 needupdate = 0;
198 inAtomic = 0;
199 nb_free();
200
201 /* remove all signs and update the screen after gutter removal */
202 coloncmd(":sign unplace *");
203 changed_window_setting();
204 update_screen(CLEAR);
205 setcursor();
Bram Moolenaar96bcc5e2011-04-01 15:33:59 +0200206 cursor_on();
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200207 out_flush();
208#ifdef FEAT_GUI
Bram Moolenaard54a6882010-08-09 22:49:00 +0200209 if (gui.in_use)
210 {
211 gui_update_cursor(TRUE, FALSE);
212 gui_mch_flush();
213 }
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200214#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000215}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000216
217#define NB_DEF_HOST "localhost"
218#define NB_DEF_ADDR "3219"
219#define NB_DEF_PASS "changeme"
220
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200221 static int
Bram Moolenaarf506c5b2010-06-22 06:28:58 +0200222netbeans_connect(char *params, int doabort)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000223{
224#ifdef INET_SOCKETS
225 struct sockaddr_in server;
226 struct hostent * host;
227# ifdef FEAT_GUI_W32
228 u_short port;
229# else
230 int port;
Bram Moolenaar67c53842010-05-22 18:28:27 +0200231# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000232#else
233 struct sockaddr_un server;
234#endif
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200235 int sd;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000236 char buf[32];
237 char *hostname = NULL;
238 char *address = NULL;
239 char *password = NULL;
240 char *fname;
241 char *arg = NULL;
242
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200243 if (*params == '=')
Bram Moolenaar071d4272004-06-13 20:20:40 +0000244 {
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200245 /* "=fname": Read info from specified file. */
246 if (getConnInfo(params + 1, &hostname, &address, &password)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000247 == FAIL)
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200248 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000249 }
250 else
251 {
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200252 if (*params == ':')
253 /* ":<host>:<addr>:<password>": get info from argument */
254 arg = params + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000255 if (arg == NULL && (fname = getenv("__NETBEANS_CONINFO")) != NULL)
256 {
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200257 /* "": get info from file specified in environment */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000258 if (getConnInfo(fname, &hostname, &address, &password) == FAIL)
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200259 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000260 }
261 else
262 {
263 if (arg != NULL)
264 {
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200265 /* ":<host>:<addr>:<password>": get info from argument */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000266 hostname = arg;
267 address = strchr(hostname, ':');
268 if (address != NULL)
269 {
270 *address++ = '\0';
271 password = strchr(address, ':');
272 if (password != NULL)
273 *password++ = '\0';
274 }
275 }
276
277 /* Get the missing values from the environment. */
278 if (hostname == NULL || *hostname == '\0')
279 hostname = getenv("__NETBEANS_HOST");
280 if (address == NULL)
281 address = getenv("__NETBEANS_SOCKET");
282 if (password == NULL)
283 password = getenv("__NETBEANS_VIM_PASSWORD");
284
285 /* Move values to allocated memory. */
286 if (hostname != NULL)
287 hostname = (char *)vim_strsave((char_u *)hostname);
288 if (address != NULL)
289 address = (char *)vim_strsave((char_u *)address);
290 if (password != NULL)
291 password = (char *)vim_strsave((char_u *)password);
292 }
293 }
294
295 /* Use the default when a value is missing. */
296 if (hostname == NULL || *hostname == '\0')
297 {
298 vim_free(hostname);
299 hostname = (char *)vim_strsave((char_u *)NB_DEF_HOST);
300 }
301 if (address == NULL || *address == '\0')
302 {
303 vim_free(address);
304 address = (char *)vim_strsave((char_u *)NB_DEF_ADDR);
305 }
306 if (password == NULL || *password == '\0')
307 {
308 vim_free(password);
309 password = (char *)vim_strsave((char_u *)NB_DEF_PASS);
310 }
311 if (hostname == NULL || address == NULL || password == NULL)
312 goto theend; /* out of memory */
313
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200314#ifdef FEAT_GUI_W32
315 netbeans_init_winsock();
316#endif
317
Bram Moolenaar071d4272004-06-13 20:20:40 +0000318#ifdef INET_SOCKETS
319 port = atoi(address);
320
Bram Moolenaara93fa7e2006-04-17 22:14:47 +0000321 if ((sd = (NBSOCK)socket(AF_INET, SOCK_STREAM, 0)) == (NBSOCK)-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000322 {
Bram Moolenaarf2330482008-06-24 20:19:36 +0000323 nbdebug(("error in socket() in netbeans_connect()\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000324 PERROR("socket() in netbeans_connect()");
325 goto theend;
326 }
327
328 /* Get the server internet address and put into addr structure */
329 /* fill in the socket address structure and connect to server */
Bram Moolenaar7db5fc82010-05-24 11:59:29 +0200330 vim_memset((char *)&server, '\0', sizeof(server));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000331 server.sin_family = AF_INET;
332 server.sin_port = htons(port);
333 if ((host = gethostbyname(hostname)) == NULL)
334 {
Bram Moolenaarf2330482008-06-24 20:19:36 +0000335 nbdebug(("error in gethostbyname() in netbeans_connect()\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000336 PERROR("gethostbyname() in netbeans_connect()");
Bram Moolenaar870b05c2011-01-04 18:11:43 +0100337 sock_close(sd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000338 goto theend;
339 }
340 memcpy((char *)&server.sin_addr, host->h_addr, host->h_length);
341#else
342 if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
343 {
Bram Moolenaarf2330482008-06-24 20:19:36 +0000344 nbdebug(("error in socket() in netbeans_connect()\n"));
345 PERROR("socket() in netbeans_connect()");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000346 goto theend;
347 }
348
349 server.sun_family = AF_UNIX;
350 strcpy(server.sun_path, address);
351#endif
352 /* Connect to server */
353 if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
354 {
Bram Moolenaarc39125d2010-05-23 12:06:58 +0200355 SOCK_ERRNO;
356 nbdebug(("netbeans_connect: Connect failed with errno %d\n", errno));
357 if (errno == ECONNREFUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000358 {
359 sock_close(sd);
360#ifdef INET_SOCKETS
Bram Moolenaara93fa7e2006-04-17 22:14:47 +0000361 if ((sd = (NBSOCK)socket(AF_INET, SOCK_STREAM, 0)) == (NBSOCK)-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000362 {
Bram Moolenaarc39125d2010-05-23 12:06:58 +0200363 SOCK_ERRNO;
Bram Moolenaarf2330482008-06-24 20:19:36 +0000364 nbdebug(("socket()#2 in netbeans_connect()\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000365 PERROR("socket()#2 in netbeans_connect()");
366 goto theend;
367 }
368#else
369 if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
370 {
Bram Moolenaarc39125d2010-05-23 12:06:58 +0200371 SOCK_ERRNO;
Bram Moolenaarf2330482008-06-24 20:19:36 +0000372 nbdebug(("socket()#2 in netbeans_connect()\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000373 PERROR("socket()#2 in netbeans_connect()");
374 goto theend;
375 }
376#endif
377 if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
378 {
379 int retries = 36;
380 int success = FALSE;
Bram Moolenaarc39125d2010-05-23 12:06:58 +0200381
382 SOCK_ERRNO;
383 while (retries-- && ((errno == ECONNREFUSED)
384 || (errno == EINTR)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000385 {
386 nbdebug(("retrying...\n"));
Bram Moolenaar870b05c2011-01-04 18:11:43 +0100387 mch_delay(3000L, TRUE);
388 ui_breakcheck();
389 if (got_int)
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200390 {
Bram Moolenaar870b05c2011-01-04 18:11:43 +0100391 errno = EINTR;
392 break;
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200393 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000394 if (connect(sd, (struct sockaddr *)&server,
Bram Moolenaarc39125d2010-05-23 12:06:58 +0200395 sizeof(server)) == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000396 {
397 success = TRUE;
398 break;
399 }
Bram Moolenaarc39125d2010-05-23 12:06:58 +0200400 SOCK_ERRNO;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000401 }
402 if (!success)
403 {
404 /* Get here when the server can't be found. */
Bram Moolenaarf2330482008-06-24 20:19:36 +0000405 nbdebug(("Cannot connect to Netbeans #2\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000406 PERROR(_("Cannot connect to Netbeans #2"));
Bram Moolenaar870b05c2011-01-04 18:11:43 +0100407 sock_close(sd);
Bram Moolenaarf506c5b2010-06-22 06:28:58 +0200408 if (doabort)
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200409 getout(1);
410 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000411 }
412 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000413 }
414 else
415 {
Bram Moolenaarf2330482008-06-24 20:19:36 +0000416 nbdebug(("Cannot connect to Netbeans\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000417 PERROR(_("Cannot connect to Netbeans"));
Bram Moolenaar870b05c2011-01-04 18:11:43 +0100418 sock_close(sd);
Bram Moolenaarf506c5b2010-06-22 06:28:58 +0200419 if (doabort)
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200420 getout(1);
421 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000422 }
423 }
424
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200425 nbsock = sd;
Bram Moolenaar9c13b352005-05-19 20:53:52 +0000426 vim_snprintf(buf, sizeof(buf), "AUTH %s\n", password);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000427 nb_send(buf, "netbeans_connect");
428
429 sprintf(buf, "0:version=0 \"%s\"\n", ExtEdProtocolVersion);
430 nb_send(buf, "externaleditor_version");
431
Bram Moolenaar071d4272004-06-13 20:20:40 +0000432theend:
433 vim_free(hostname);
434 vim_free(address);
435 vim_free(password);
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200436 return NETBEANS_OPEN ? OK : FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000437}
438
439/*
440 * Obtain the NetBeans hostname, port address and password from a file.
441 * Return the strings in allocated memory.
442 * Return FAIL if the file could not be read, OK otherwise (no matter what it
443 * contains).
444 */
445 static int
446getConnInfo(char *file, char **host, char **port, char **auth)
447{
448 FILE *fp;
449 char_u buf[BUFSIZ];
450 char_u *lp;
Bram Moolenaar309cbc32012-01-10 22:31:31 +0100451 char_u *nlp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000452#ifdef UNIX
453 struct stat st;
454
455 /*
456 * For Unix only accept the file when it's not accessible by others.
457 * The open will then fail if we don't own the file.
458 */
459 if (mch_stat(file, &st) == 0 && (st.st_mode & 0077) != 0)
460 {
Bram Moolenaarf2330482008-06-24 20:19:36 +0000461 nbdebug(("Wrong access mode for NetBeans connection info file: \"%s\"\n",
462 file));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000463 EMSG2(_("E668: Wrong access mode for NetBeans connection info file: \"%s\""),
464 file);
465 return FAIL;
466 }
467#endif
468
469 fp = mch_fopen(file, "r");
470 if (fp == NULL)
471 {
Bram Moolenaarf2330482008-06-24 20:19:36 +0000472 nbdebug(("Cannot open NetBeans connection info file\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000473 PERROR("E660: Cannot open NetBeans connection info file");
474 return FAIL;
475 }
476
477 /* Read the file. There should be one of each parameter */
478 while ((lp = (char_u *)fgets((char *)buf, BUFSIZ, fp)) != NULL)
479 {
Bram Moolenaar309cbc32012-01-10 22:31:31 +0100480 if ((nlp = vim_strchr(lp, '\n')) != NULL)
481 *nlp = 0; /* strip off the trailing newline */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000482
483 if (STRNCMP(lp, "host=", 5) == 0)
484 {
485 vim_free(*host);
486 *host = (char *)vim_strsave(&buf[5]);
487 }
488 else if (STRNCMP(lp, "port=", 5) == 0)
489 {
490 vim_free(*port);
491 *port = (char *)vim_strsave(&buf[5]);
492 }
493 else if (STRNCMP(lp, "auth=", 5) == 0)
494 {
495 vim_free(*auth);
496 *auth = (char *)vim_strsave(&buf[5]);
497 }
498 }
499 fclose(fp);
500
501 return OK;
502}
503
504
505struct keyqueue
506{
Bram Moolenaar8065d7f2010-01-19 15:13:14 +0100507 char_u *keystr;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000508 struct keyqueue *next;
509 struct keyqueue *prev;
510};
511
512typedef struct keyqueue keyQ_T;
513
514static keyQ_T keyHead; /* dummy node, header for circular queue */
515
516
517/*
518 * Queue up key commands sent from netbeans.
Bram Moolenaar8065d7f2010-01-19 15:13:14 +0100519 * We store the string, because it may depend on the global mod_mask and
520 * :nbkey doesn't have a key number.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000521 */
522 static void
Bram Moolenaar8065d7f2010-01-19 15:13:14 +0100523postpone_keycommand(char_u *keystr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000524{
525 keyQ_T *node;
526
527 node = (keyQ_T *)alloc(sizeof(keyQ_T));
Bram Moolenaar8065d7f2010-01-19 15:13:14 +0100528 if (node == NULL)
529 return; /* out of memory, drop the key */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000530
531 if (keyHead.next == NULL) /* initialize circular queue */
532 {
533 keyHead.next = &keyHead;
534 keyHead.prev = &keyHead;
535 }
536
537 /* insert node at tail of queue */
538 node->next = &keyHead;
539 node->prev = keyHead.prev;
540 keyHead.prev->next = node;
541 keyHead.prev = node;
542
Bram Moolenaar8065d7f2010-01-19 15:13:14 +0100543 node->keystr = vim_strsave(keystr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000544}
545
546/*
547 * Handle any queued-up NetBeans keycommands to be send.
548 */
549 static void
550handle_key_queue(void)
551{
Bram Moolenaar8065d7f2010-01-19 15:13:14 +0100552 int postponed = FALSE;
553
554 while (!postponed && keyHead.next && keyHead.next != &keyHead)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000555 {
556 /* first, unlink the node */
557 keyQ_T *node = keyHead.next;
558 keyHead.next = node->next;
559 node->next->prev = node->prev;
560
Bram Moolenaar8065d7f2010-01-19 15:13:14 +0100561 /* Now, send the keycommand. This may cause it to be postponed again
562 * and change keyHead. */
563 if (node->keystr != NULL)
564 postponed = !netbeans_keystring(node->keystr);
565 vim_free(node->keystr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566
567 /* Finally, dispose of the node */
568 vim_free(node);
569 }
570}
571
572
573struct cmdqueue
574{
575 char_u *buffer;
576 struct cmdqueue *next;
577 struct cmdqueue *prev;
578};
579
580typedef struct cmdqueue queue_T;
581
582static queue_T head; /* dummy node, header for circular queue */
583
584
585/*
586 * Put the buffer on the work queue; possibly save it to a file as well.
587 */
588 static void
589save(char_u *buf, int len)
590{
591 queue_T *node;
592
593 node = (queue_T *)alloc(sizeof(queue_T));
594 if (node == NULL)
595 return; /* out of memory */
596 node->buffer = alloc(len + 1);
597 if (node->buffer == NULL)
598 {
599 vim_free(node);
600 return; /* out of memory */
601 }
602 mch_memmove(node->buffer, buf, (size_t)len);
603 node->buffer[len] = NUL;
604
605 if (head.next == NULL) /* initialize circular queue */
606 {
607 head.next = &head;
608 head.prev = &head;
609 }
610
611 /* insert node at tail of queue */
612 node->next = &head;
613 node->prev = head.prev;
614 head.prev->next = node;
615 head.prev = node;
616
617#ifdef NBDEBUG
618 {
619 static int outfd = -2;
620
621 /* possibly write buffer out to a file */
622 if (outfd == -3)
623 return;
624
625 if (outfd == -2)
626 {
627 char *file = getenv("__NETBEANS_SAVE");
628 if (file == NULL)
629 outfd = -3;
630 else
631 outfd = mch_open(file, O_WRONLY|O_CREAT|O_TRUNC, 0666);
632 }
633
634 if (outfd >= 0)
635 write(outfd, buf, len);
636 }
637#endif
638}
639
640
641/*
642 * While there's still a command in the work queue, parse and execute it.
643 */
Bram Moolenaarf2330482008-06-24 20:19:36 +0000644 void
645netbeans_parse_messages(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000646{
647 char_u *p;
648 queue_T *node;
Bram Moolenaar863053d2010-12-02 17:09:54 +0100649 int own_node;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000650
Bram Moolenaarf2330482008-06-24 20:19:36 +0000651 while (head.next != NULL && head.next != &head)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000652 {
653 node = head.next;
654
655 /* Locate the first line in the first buffer. */
656 p = vim_strchr(node->buffer, '\n');
657 if (p == NULL)
658 {
659 /* Command isn't complete. If there is no following buffer,
660 * return (wait for more). If there is another buffer following,
661 * prepend the text to that buffer and delete this one. */
662 if (node->next == &head)
663 return;
Bram Moolenaarf2330482008-06-24 20:19:36 +0000664 p = alloc((unsigned)(STRLEN(node->buffer)
665 + STRLEN(node->next->buffer) + 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000666 if (p == NULL)
667 return; /* out of memory */
668 STRCPY(p, node->buffer);
669 STRCAT(p, node->next->buffer);
670 vim_free(node->next->buffer);
671 node->next->buffer = p;
672
673 /* dispose of the node and buffer */
674 head.next = node->next;
675 node->next->prev = node->prev;
676 vim_free(node->buffer);
677 vim_free(node);
678 }
679 else
680 {
681 /* There is a complete command at the start of the buffer.
682 * Terminate it with a NUL. When no more text is following unlink
683 * the buffer. Do this before executing, because new buffers can
684 * be added while busy handling the command. */
685 *p++ = NUL;
686 if (*p == NUL)
687 {
Bram Moolenaar863053d2010-12-02 17:09:54 +0100688 own_node = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000689 head.next = node->next;
690 node->next->prev = node->prev;
691 }
Bram Moolenaar863053d2010-12-02 17:09:54 +0100692 else
693 own_node = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000694
695 /* now, parse and execute the commands */
696 nb_parse_cmd(node->buffer);
697
Bram Moolenaar863053d2010-12-02 17:09:54 +0100698 if (own_node)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000699 {
700 /* buffer finished, dispose of the node and buffer */
701 vim_free(node->buffer);
702 vim_free(node);
703 }
Bram Moolenaar863053d2010-12-02 17:09:54 +0100704 /* Check that "head" wasn't changed under our fingers, e.g. when a
705 * DETACH command was handled. */
706 else if (head.next == node)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000707 {
708 /* more follows, move to the start */
Bram Moolenaarf2330482008-06-24 20:19:36 +0000709 STRMOVE(node->buffer, p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000710 }
711 }
712 }
713}
714
715/* Buffer size for reading incoming messages. */
716#define MAXMSGSIZE 4096
717
718/*
Bram Moolenaar67c53842010-05-22 18:28:27 +0200719 * Read a command from netbeans.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000720 */
Bram Moolenaar173c9852010-09-29 17:27:01 +0200721#ifdef FEAT_GUI_X11
Bram Moolenaar071d4272004-06-13 20:20:40 +0000722 static void
Bram Moolenaara9d45512009-05-17 21:25:42 +0000723messageFromNetbeans(XtPointer clientData UNUSED,
Bram Moolenaarb85cb212009-05-17 14:24:23 +0000724 int *unused1 UNUSED,
725 XtInputId *unused2 UNUSED)
Bram Moolenaar67c53842010-05-22 18:28:27 +0200726{
727 netbeans_read();
728}
729#endif
730
731#ifdef FEAT_GUI_GTK
Bram Moolenaar071d4272004-06-13 20:20:40 +0000732 static void
Bram Moolenaarb85cb212009-05-17 14:24:23 +0000733messageFromNetbeans(gpointer clientData UNUSED,
734 gint unused1 UNUSED,
735 GdkInputCondition unused2 UNUSED)
Bram Moolenaar67c53842010-05-22 18:28:27 +0200736{
737 netbeans_read();
738}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739#endif
Bram Moolenaar67c53842010-05-22 18:28:27 +0200740
Bram Moolenaar7ad7d012010-11-16 15:49:02 +0100741#define DETACH_MSG "DETACH\n"
742
Bram Moolenaar67c53842010-05-22 18:28:27 +0200743 void
744netbeans_read()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000745{
746 static char_u *buf = NULL;
Bram Moolenaar0b65f892010-05-15 14:49:02 +0200747 int len = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000748 int readlen = 0;
Bram Moolenaar581f6dc2010-03-10 16:12:48 +0100749#ifdef HAVE_SELECT
750 struct timeval tval;
751 fd_set rfds;
752#else
753# ifdef HAVE_POLL
754 struct pollfd fds;
755# endif
756#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000757
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200758 if (!NETBEANS_OPEN)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000759 {
760 nbdebug(("messageFromNetbeans() called without a socket\n"));
761 return;
762 }
763
Bram Moolenaar071d4272004-06-13 20:20:40 +0000764 /* Allocate a buffer to read into. */
765 if (buf == NULL)
766 {
767 buf = alloc(MAXMSGSIZE);
768 if (buf == NULL)
769 return; /* out of memory! */
770 }
771
Bram Moolenaar581f6dc2010-03-10 16:12:48 +0100772 /* Keep on reading for as long as there is something to read.
773 * Use select() or poll() to avoid blocking on a message that is exactly
774 * MAXMSGSIZE long. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000775 for (;;)
776 {
Bram Moolenaar581f6dc2010-03-10 16:12:48 +0100777#ifdef HAVE_SELECT
778 FD_ZERO(&rfds);
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200779 FD_SET(nbsock, &rfds);
Bram Moolenaar67c53842010-05-22 18:28:27 +0200780 tval.tv_sec = 0;
781 tval.tv_usec = 0;
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200782 if (select(nbsock + 1, &rfds, NULL, NULL, &tval) <= 0)
Bram Moolenaar67c53842010-05-22 18:28:27 +0200783 break;
Bram Moolenaar581f6dc2010-03-10 16:12:48 +0100784#else
785# ifdef HAVE_POLL
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200786 fds.fd = nbsock;
Bram Moolenaar581f6dc2010-03-10 16:12:48 +0100787 fds.events = POLLIN;
Bram Moolenaar67c53842010-05-22 18:28:27 +0200788 if (poll(&fds, 1, 0) <= 0)
789 break;
Bram Moolenaar581f6dc2010-03-10 16:12:48 +0100790# endif
791#endif
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200792 len = sock_read(nbsock, buf, MAXMSGSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000793 if (len <= 0)
794 break; /* error or nothing more to read */
795
796 /* Store the read message in the queue. */
797 save(buf, len);
798 readlen += len;
799 if (len < MAXMSGSIZE)
800 break; /* did read everything that's available */
801 }
802
Bram Moolenaar7ad7d012010-11-16 15:49:02 +0100803 /* Reading a socket disconnection (readlen == 0), or a socket error. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000804 if (readlen <= 0)
805 {
Bram Moolenaar7ad7d012010-11-16 15:49:02 +0100806 /* Queue a "DETACH" netbeans message in the command queue in order to
807 * terminate the netbeans session later. Do not end the session here
808 * directly as we may be running in the context of a call to
809 * netbeans_parse_messages():
810 * netbeans_parse_messages
811 * -> autocmd triggered while processing the netbeans cmd
812 * -> ui_breakcheck
813 * -> gui event loop or select loop
814 * -> netbeans_read()
815 */
Bram Moolenaarde1b0922010-12-24 14:00:17 +0100816 save((char_u *)DETACH_MSG, (int)strlen(DETACH_MSG));
Bram Moolenaar7ad7d012010-11-16 15:49:02 +0100817 nb_close_socket();
818
Bram Moolenaar071d4272004-06-13 20:20:40 +0000819 if (len < 0)
Bram Moolenaarf2330482008-06-24 20:19:36 +0000820 {
821 nbdebug(("read from Netbeans socket\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000822 PERROR(_("read from Netbeans socket"));
Bram Moolenaarf2330482008-06-24 20:19:36 +0000823 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000824 }
825
Bram Moolenaar03531f72010-11-16 15:04:57 +0100826#if defined(NB_HAS_GUI) && defined(FEAT_GUI_GTK)
827 if (NB_HAS_GUI && gtk_main_level() > 0)
Bram Moolenaar7ad7d012010-11-16 15:49:02 +0100828 gtk_main_quit();
Bram Moolenaarf2330482008-06-24 20:19:36 +0000829#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000830}
831
832/*
833 * Handle one NUL terminated command.
834 *
835 * format of a command from netbeans:
836 *
837 * 6:setTitle!84 "a.c"
838 *
839 * bufno
840 * colon
841 * cmd
842 * !
843 * cmdno
844 * args
845 *
846 * for function calls, the ! is replaced by a /
847 */
848 static void
849nb_parse_cmd(char_u *cmd)
850{
Bram Moolenaar349b2f62004-10-11 10:00:50 +0000851 char *verb;
852 char *q;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000853 int bufno;
854 int isfunc = -1;
855
856 if (STRCMP(cmd, "DISCONNECT") == 0)
857 {
858 /* We assume the server knows that we can safely exit! */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000859 /* Disconnect before exiting, Motif hangs in a Select error
860 * message otherwise. */
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200861 netbeans_close();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000862 getout(0);
863 /* NOTREACHED */
864 }
865
866 if (STRCMP(cmd, "DETACH") == 0)
867 {
868 /* The IDE is breaking the connection. */
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200869 netbeans_close();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000870 return;
871 }
872
Bram Moolenaar349b2f62004-10-11 10:00:50 +0000873 bufno = strtol((char *)cmd, &verb, 10);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000874
875 if (*verb != ':')
876 {
Bram Moolenaarf2330482008-06-24 20:19:36 +0000877 nbdebug((" missing colon: %s\n", cmd));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000878 EMSG2("E627: missing colon: %s", cmd);
879 return;
880 }
881 ++verb; /* skip colon */
882
883 for (q = verb; *q; q++)
884 {
885 if (*q == '!')
886 {
887 *q++ = NUL;
888 isfunc = 0;
889 break;
890 }
891 else if (*q == '/')
892 {
893 *q++ = NUL;
894 isfunc = 1;
895 break;
896 }
897 }
898
899 if (isfunc < 0)
900 {
Bram Moolenaarf2330482008-06-24 20:19:36 +0000901 nbdebug((" missing ! or / in: %s\n", cmd));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000902 EMSG2("E628: missing ! or / in: %s", cmd);
903 return;
904 }
905
Bram Moolenaar89d40322006-08-29 15:30:07 +0000906 r_cmdno = strtol(q, &q, 10);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000907
Bram Moolenaar349b2f62004-10-11 10:00:50 +0000908 q = (char *)skipwhite((char_u *)q);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000909
Bram Moolenaar89d40322006-08-29 15:30:07 +0000910 if (nb_do_cmd(bufno, (char_u *)verb, isfunc, r_cmdno, (char_u *)q) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000911 {
Bram Moolenaar009b2592004-10-24 19:18:58 +0000912#ifdef NBDEBUG
913 /*
Bram Moolenaar2660c0e2010-01-19 14:59:56 +0100914 * This happens because the ExtEd can send a command or 2 after
Bram Moolenaar009b2592004-10-24 19:18:58 +0000915 * doing a stopDocumentListen command. It doesn't harm anything
916 * so I'm disabling it except for debugging.
917 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000918 nbdebug(("nb_parse_cmd: Command error for \"%s\"\n", cmd));
919 EMSG("E629: bad return from nb_do_cmd");
Bram Moolenaar009b2592004-10-24 19:18:58 +0000920#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000921 }
922}
923
924struct nbbuf_struct
925{
926 buf_T *bufp;
927 unsigned int fireChanges:1;
928 unsigned int initDone:1;
Bram Moolenaar009b2592004-10-24 19:18:58 +0000929 unsigned int insertDone:1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000930 unsigned int modified:1;
Bram Moolenaar009b2592004-10-24 19:18:58 +0000931 int nbbuf_number;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000932 char *displayname;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000933 int *signmap;
934 short_u signmaplen;
935 short_u signmapused;
936};
937
938typedef struct nbbuf_struct nbbuf_T;
939
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200940static nbbuf_T *buf_list = NULL;
Bram Moolenaard857f0e2005-06-21 22:37:39 +0000941static int buf_list_size = 0; /* size of buf_list */
942static int buf_list_used = 0; /* nr of entries in buf_list actually in use */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000943
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200944static char **globalsignmap = NULL;
945static int globalsignmaplen = 0;
946static int globalsignmapused = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000947
948static int mapsigntype __ARGS((nbbuf_T *, int localsigntype));
949static void addsigntype __ARGS((nbbuf_T *, int localsigntype, char_u *typeName,
950 char_u *tooltip, char_u *glyphfile,
Bram Moolenaar67c53842010-05-22 18:28:27 +0200951 char_u *fg, char_u *bg));
Bram Moolenaar009b2592004-10-24 19:18:58 +0000952static void print_read_msg __ARGS((nbbuf_T *buf));
Bram Moolenaar914703b2010-05-31 21:59:46 +0200953static void print_save_msg __ARGS((nbbuf_T *buf, off_t nchars));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000954
955static int curPCtype = -1;
956
957/*
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200958 * Free netbeans resources.
959 */
960 static void
961nb_free()
962{
963 keyQ_T *key_node = keyHead.next;
964 queue_T *cmd_node = head.next;
965 nbbuf_T buf;
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200966 int i;
967
968 /* free the netbeans buffer list */
969 for (i = 0; i < buf_list_used; i++)
970 {
971 buf = buf_list[i];
972 vim_free(buf.displayname);
973 vim_free(buf.signmap);
Bram Moolenaare980d8a2010-12-08 13:11:21 +0100974 if (buf.bufp != NULL)
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200975 {
976 buf.bufp->b_netbeans_file = FALSE;
977 buf.bufp->b_was_netbeans_file = FALSE;
978 }
979 }
980 vim_free(buf_list);
981 buf_list = NULL;
982 buf_list_size = 0;
983 buf_list_used = 0;
984
985 /* free the queued key commands */
Bram Moolenaar8d4eecc2012-11-20 17:19:01 +0100986 while (key_node != NULL && key_node != &keyHead)
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200987 {
988 keyQ_T *next = key_node->next;
989 vim_free(key_node->keystr);
990 vim_free(key_node);
991 if (next == &keyHead)
992 {
993 keyHead.next = &keyHead;
994 keyHead.prev = &keyHead;
995 break;
996 }
997 key_node = next;
998 }
999
1000 /* free the queued netbeans commands */
Bram Moolenaar8d4eecc2012-11-20 17:19:01 +01001001 while (cmd_node != NULL && cmd_node != &head)
Bram Moolenaarb26e6322010-05-22 21:34:09 +02001002 {
1003 queue_T *next = cmd_node->next;
1004 vim_free(cmd_node->buffer);
1005 vim_free(cmd_node);
1006 if (next == &head)
1007 {
1008 head.next = &head;
1009 head.prev = &head;
1010 break;
1011 }
1012 cmd_node = next;
1013 }
1014}
1015
1016/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001017 * Get the Netbeans buffer number for the specified buffer.
1018 */
1019 static int
1020nb_getbufno(buf_T *bufp)
1021{
1022 int i;
1023
1024 for (i = 0; i < buf_list_used; i++)
1025 if (buf_list[i].bufp == bufp)
1026 return i;
1027 return -1;
1028}
1029
1030/*
1031 * Is this a NetBeans-owned buffer?
1032 */
1033 int
1034isNetbeansBuffer(buf_T *bufp)
1035{
Bram Moolenaarb26e6322010-05-22 21:34:09 +02001036 return NETBEANS_OPEN && bufp->b_netbeans_file;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001037}
1038
1039/*
1040 * NetBeans and Vim have different undo models. In Vim, the file isn't
1041 * changed if changes are undone via the undo command. In NetBeans, once
1042 * a change has been made the file is marked as modified until saved. It
1043 * doesn't matter if the change was undone.
1044 *
1045 * So this function is for the corner case where Vim thinks a buffer is
1046 * unmodified but NetBeans thinks it IS modified.
1047 */
1048 int
1049isNetbeansModified(buf_T *bufp)
1050{
Bram Moolenaarb26e6322010-05-22 21:34:09 +02001051 if (isNetbeansBuffer(bufp))
Bram Moolenaar009b2592004-10-24 19:18:58 +00001052 {
1053 int bufno = nb_getbufno(bufp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001054
Bram Moolenaar009b2592004-10-24 19:18:58 +00001055 if (bufno > 0)
1056 return buf_list[bufno].modified;
1057 else
1058 return FALSE;
1059 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001060 else
1061 return FALSE;
1062}
1063
1064/*
1065 * Given a Netbeans buffer number, return the netbeans buffer.
1066 * Returns NULL for 0 or a negative number. A 0 bufno means a
1067 * non-buffer related command has been sent.
1068 */
1069 static nbbuf_T *
1070nb_get_buf(int bufno)
1071{
1072 /* find or create a buffer with the given number */
1073 int incr;
1074
1075 if (bufno <= 0)
1076 return NULL;
1077
1078 if (!buf_list)
1079 {
1080 /* initialize */
1081 buf_list = (nbbuf_T *)alloc_clear(100 * sizeof(nbbuf_T));
1082 buf_list_size = 100;
1083 }
1084 if (bufno >= buf_list_used) /* new */
1085 {
1086 if (bufno >= buf_list_size) /* grow list */
1087 {
Bram Moolenaar9abd5c62015-02-10 18:34:01 +01001088 nbbuf_T *t_buf_list = buf_list;
1089
Bram Moolenaar071d4272004-06-13 20:20:40 +00001090 incr = bufno - buf_list_size + 90;
1091 buf_list_size += incr;
1092 buf_list = (nbbuf_T *)vim_realloc(
1093 buf_list, buf_list_size * sizeof(nbbuf_T));
Bram Moolenaar9abd5c62015-02-10 18:34:01 +01001094 if (buf_list == NULL)
1095 {
1096 vim_free(t_buf_list);
1097 buf_list_size = 0;
1098 return NULL;
1099 }
Bram Moolenaar7db5fc82010-05-24 11:59:29 +02001100 vim_memset(buf_list + buf_list_size - incr, 0,
1101 incr * sizeof(nbbuf_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001102 }
1103
1104 while (buf_list_used <= bufno)
1105 {
1106 /* Default is to fire text changes. */
1107 buf_list[buf_list_used].fireChanges = 1;
1108 ++buf_list_used;
1109 }
1110 }
1111
1112 return buf_list + bufno;
1113}
1114
1115/*
1116 * Return the number of buffers that are modified.
1117 */
1118 static int
1119count_changed_buffers(void)
1120{
1121 buf_T *bufp;
1122 int n;
1123
1124 n = 0;
1125 for (bufp = firstbuf; bufp != NULL; bufp = bufp->b_next)
1126 if (bufp->b_changed)
1127 ++n;
1128 return n;
1129}
1130
1131/*
1132 * End the netbeans session.
1133 */
1134 void
1135netbeans_end(void)
1136{
1137 int i;
1138 static char buf[128];
1139
Bram Moolenaarb26e6322010-05-22 21:34:09 +02001140 if (!NETBEANS_OPEN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001141 return;
1142
1143 for (i = 0; i < buf_list_used; i++)
1144 {
1145 if (!buf_list[i].bufp)
1146 continue;
1147 if (netbeansForcedQuit)
1148 {
1149 /* mark as unmodified so NetBeans won't put up dialog on "killed" */
Bram Moolenaar89d40322006-08-29 15:30:07 +00001150 sprintf(buf, "%d:unmodified=%d\n", i, r_cmdno);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001151 nbdebug(("EVT: %s", buf));
1152 nb_send(buf, "netbeans_end");
1153 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00001154 sprintf(buf, "%d:killed=%d\n", i, r_cmdno);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001155 nbdebug(("EVT: %s", buf));
Bram Moolenaarb26e6322010-05-22 21:34:09 +02001156 /* nb_send(buf, "netbeans_end"); avoid "write failed" messages */
1157 ignored = sock_write(nbsock, buf, (int)STRLEN(buf));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001158 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001159}
1160
1161/*
1162 * Send a message to netbeans.
1163 */
1164 static void
1165nb_send(char *buf, char *fun)
1166{
1167 /* Avoid giving pages full of error messages when the other side has
1168 * exited, only mention the first error until the connection works again. */
1169 static int did_error = FALSE;
1170
Bram Moolenaarb26e6322010-05-22 21:34:09 +02001171 if (!NETBEANS_OPEN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001172 {
1173 if (!did_error)
Bram Moolenaarf2330482008-06-24 20:19:36 +00001174 {
1175 nbdebug((" %s(): write while not connected\n", fun));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001176 EMSG2("E630: %s(): write while not connected", fun);
Bram Moolenaarf2330482008-06-24 20:19:36 +00001177 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001178 did_error = TRUE;
1179 }
Bram Moolenaarb26e6322010-05-22 21:34:09 +02001180 else if (sock_write(nbsock, buf, (int)STRLEN(buf)) != (int)STRLEN(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001181 {
1182 if (!did_error)
Bram Moolenaarf2330482008-06-24 20:19:36 +00001183 {
1184 nbdebug((" %s(): write failed\n", fun));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001185 EMSG2("E631: %s(): write failed", fun);
Bram Moolenaarf2330482008-06-24 20:19:36 +00001186 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001187 did_error = TRUE;
1188 }
1189 else
1190 did_error = FALSE;
1191}
1192
1193/*
1194 * Some input received from netbeans requires a response. This function
1195 * handles a response with no information (except the command number).
1196 */
1197 static void
1198nb_reply_nil(int cmdno)
1199{
1200 char reply[32];
1201
Bram Moolenaar009b2592004-10-24 19:18:58 +00001202 nbdebug(("REP %d: <none>\n", cmdno));
1203
Bram Moolenaar7ad7d012010-11-16 15:49:02 +01001204 /* Avoid printing an annoying error message. */
1205 if (!NETBEANS_OPEN)
1206 return;
1207
Bram Moolenaar071d4272004-06-13 20:20:40 +00001208 sprintf(reply, "%d\n", cmdno);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001209 nb_send(reply, "nb_reply_nil");
1210}
1211
1212
1213/*
1214 * Send a response with text.
1215 * "result" must have been quoted already (using nb_quote()).
1216 */
1217 static void
1218nb_reply_text(int cmdno, char_u *result)
1219{
1220 char_u *reply;
1221
Bram Moolenaar009b2592004-10-24 19:18:58 +00001222 nbdebug(("REP %d: %s\n", cmdno, (char *)result));
1223
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001224 reply = alloc((unsigned)STRLEN(result) + 32);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001225 sprintf((char *)reply, "%d %s\n", cmdno, (char *)result);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001226 nb_send((char *)reply, "nb_reply_text");
1227
1228 vim_free(reply);
1229}
1230
1231
1232/*
1233 * Send a response with a number result code.
1234 */
1235 static void
1236nb_reply_nr(int cmdno, long result)
1237{
1238 char reply[32];
1239
Bram Moolenaar009b2592004-10-24 19:18:58 +00001240 nbdebug(("REP %d: %ld\n", cmdno, result));
1241
Bram Moolenaar071d4272004-06-13 20:20:40 +00001242 sprintf(reply, "%d %ld\n", cmdno, result);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001243 nb_send(reply, "nb_reply_nr");
1244}
1245
1246
1247/*
1248 * Encode newline, ret, backslash, double quote for transmission to NetBeans.
1249 */
1250 static char_u *
1251nb_quote(char_u *txt)
1252{
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001253 char_u *buf = alloc((unsigned)(2 * STRLEN(txt) + 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001254 char_u *p = txt;
1255 char_u *q = buf;
1256
1257 if (buf == NULL)
1258 return NULL;
1259 for (; *p; p++)
1260 {
1261 switch (*p)
1262 {
1263 case '\"':
1264 case '\\':
1265 *q++ = '\\'; *q++ = *p; break;
1266 /* case '\t': */
1267 /* *q++ = '\\'; *q++ = 't'; break; */
1268 case '\n':
1269 *q++ = '\\'; *q++ = 'n'; break;
1270 case '\r':
1271 *q++ = '\\'; *q++ = 'r'; break;
1272 default:
1273 *q++ = *p;
1274 break;
1275 }
1276 }
Bram Moolenaar2660c0e2010-01-19 14:59:56 +01001277 *q = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +00001278
1279 return buf;
1280}
1281
1282
1283/*
1284 * Remove top level double quotes; convert backslashed chars.
1285 * Returns an allocated string (NULL for failure).
1286 * If "endp" is not NULL it is set to the character after the terminating
1287 * quote.
1288 */
1289 static char *
1290nb_unquote(char_u *p, char_u **endp)
1291{
1292 char *result = 0;
1293 char *q;
1294 int done = 0;
1295
1296 /* result is never longer than input */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001297 result = (char *)alloc_clear((unsigned)STRLEN(p) + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001298 if (result == NULL)
1299 return NULL;
1300
1301 if (*p++ != '"')
1302 {
1303 nbdebug(("nb_unquote called with string that doesn't start with a quote!: %s\n",
1304 p));
1305 result[0] = NUL;
1306 return result;
1307 }
1308
1309 for (q = result; !done && *p != NUL;)
1310 {
1311 switch (*p)
1312 {
1313 case '"':
1314 /*
1315 * Unbackslashed dquote marks the end, if first char was dquote.
1316 */
1317 done = 1;
1318 break;
1319
1320 case '\\':
1321 ++p;
1322 switch (*p)
1323 {
1324 case '\\': *q++ = '\\'; break;
1325 case 'n': *q++ = '\n'; break;
1326 case 't': *q++ = '\t'; break;
1327 case 'r': *q++ = '\r'; break;
1328 case '"': *q++ = '"'; break;
1329 case NUL: --p; break;
1330 /* default: skip over illegal chars */
1331 }
1332 ++p;
1333 break;
1334
1335 default:
1336 *q++ = *p++;
1337 }
1338 }
1339
1340 if (endp != NULL)
1341 *endp = p;
1342
1343 return result;
1344}
1345
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00001346/*
1347 * Remove from "first" byte to "last" byte (inclusive), at line "lnum" of the
1348 * current buffer. Remove to end of line when "last" is MAXCOL.
1349 */
1350 static void
1351nb_partialremove(linenr_T lnum, colnr_T first, colnr_T last)
1352{
1353 char_u *oldtext, *newtext;
1354 int oldlen;
1355 int lastbyte = last;
1356
1357 oldtext = ml_get(lnum);
Bram Moolenaarcb4cef22008-03-16 15:04:34 +00001358 oldlen = (int)STRLEN(oldtext);
Bram Moolenaarb3c70982008-01-18 10:40:55 +00001359 if (first >= (colnr_T)oldlen || oldlen == 0) /* just in case */
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00001360 return;
1361 if (lastbyte >= oldlen)
1362 lastbyte = oldlen - 1;
1363 newtext = alloc(oldlen - (int)(lastbyte - first));
1364 if (newtext != NULL)
1365 {
1366 mch_memmove(newtext, oldtext, first);
Bram Moolenaarf2330482008-06-24 20:19:36 +00001367 STRMOVE(newtext + first, oldtext + lastbyte + 1);
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00001368 nbdebug((" NEW LINE %d: %s\n", lnum, newtext));
1369 ml_replace(lnum, newtext, FALSE);
1370 }
1371}
1372
1373/*
1374 * Replace the "first" line with the concatenation of the "first" and
1375 * the "other" line. The "other" line is not removed.
1376 */
1377 static void
1378nb_joinlines(linenr_T first, linenr_T other)
1379{
1380 int len_first, len_other;
1381 char_u *p;
1382
Bram Moolenaarcb4cef22008-03-16 15:04:34 +00001383 len_first = (int)STRLEN(ml_get(first));
1384 len_other = (int)STRLEN(ml_get(other));
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00001385 p = alloc((unsigned)(len_first + len_other + 1));
1386 if (p != NULL)
1387 {
1388 mch_memmove(p, ml_get(first), len_first);
1389 mch_memmove(p + len_first, ml_get(other), len_other + 1);
1390 ml_replace(first, p, FALSE);
1391 }
1392}
1393
Bram Moolenaar071d4272004-06-13 20:20:40 +00001394#define SKIP_STOP 2
1395#define streq(a,b) (strcmp(a,b) == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001396
1397/*
1398 * Do the actual processing of a single netbeans command or function.
Bram Moolenaar143c38c2007-05-10 16:41:10 +00001399 * The difference between a command and function is that a function
1400 * gets a response (it's required) but a command does not.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001401 * For arguments see comment for nb_parse_cmd().
1402 */
1403 static int
1404nb_do_cmd(
1405 int bufno,
1406 char_u *cmd,
1407 int func,
1408 int cmdno,
1409 char_u *args) /* points to space before arguments or NUL */
1410{
Bram Moolenaar70b2a562012-01-10 22:26:17 +01001411 int do_update = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001412 long off = 0;
1413 nbbuf_T *buf = nb_get_buf(bufno);
1414 static int skip = 0;
1415 int retval = OK;
Bram Moolenaar349b2f62004-10-11 10:00:50 +00001416 char *cp; /* for when a char pointer is needed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001417
1418 nbdebug(("%s %d: (%d) %s %s\n", (func) ? "FUN" : "CMD", cmdno, bufno, cmd,
1419 STRCMP(cmd, "insert") == 0 ? "<text>" : (char *)args));
1420
1421 if (func)
1422 {
1423/* =====================================================================*/
1424 if (streq((char *)cmd, "getModified"))
1425 {
1426 if (buf == NULL || buf->bufp == NULL)
1427 /* Return the number of buffers that are modified. */
1428 nb_reply_nr(cmdno, (long)count_changed_buffers());
1429 else
1430 /* Return whether the buffer is modified. */
1431 nb_reply_nr(cmdno, (long)(buf->bufp->b_changed
1432 || isNetbeansModified(buf->bufp)));
1433/* =====================================================================*/
1434 }
1435 else if (streq((char *)cmd, "saveAndExit"))
1436 {
1437 /* Note: this will exit Vim if successful. */
1438 coloncmd(":confirm qall");
1439
1440 /* We didn't exit: return the number of changed buffers. */
1441 nb_reply_nr(cmdno, (long)count_changed_buffers());
1442/* =====================================================================*/
1443 }
1444 else if (streq((char *)cmd, "getCursor"))
1445 {
1446 char_u text[200];
1447
1448 /* Note: nb_getbufno() may return -1. This indicates the IDE
1449 * didn't assign a number to the current buffer in response to a
1450 * fileOpened event. */
1451 sprintf((char *)text, "%d %ld %d %ld",
1452 nb_getbufno(curbuf),
1453 (long)curwin->w_cursor.lnum,
1454 (int)curwin->w_cursor.col,
1455 pos2off(curbuf, &curwin->w_cursor));
1456 nb_reply_text(cmdno, text);
1457/* =====================================================================*/
1458 }
Bram Moolenaarc65c4912006-11-14 17:29:46 +00001459 else if (streq((char *)cmd, "getAnno"))
1460 {
1461 long linenum = 0;
1462#ifdef FEAT_SIGNS
1463 if (buf == NULL || buf->bufp == NULL)
1464 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001465 nbdebug((" Invalid buffer identifier in getAnno\n"));
1466 EMSG("E652: Invalid buffer identifier in getAnno");
Bram Moolenaarc65c4912006-11-14 17:29:46 +00001467 retval = FAIL;
1468 }
1469 else
1470 {
1471 int serNum;
1472
1473 cp = (char *)args;
1474 serNum = strtol(cp, &cp, 10);
1475 /* If the sign isn't found linenum will be zero. */
1476 linenum = (long)buf_findsign(buf->bufp, serNum);
1477 }
1478#endif
1479 nb_reply_nr(cmdno, linenum);
1480/* =====================================================================*/
1481 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001482 else if (streq((char *)cmd, "getLength"))
1483 {
1484 long len = 0;
1485
1486 if (buf == NULL || buf->bufp == NULL)
1487 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001488 nbdebug((" invalid buffer identifier in getLength\n"));
1489 EMSG("E632: invalid buffer identifier in getLength");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001490 retval = FAIL;
1491 }
1492 else
1493 {
1494 len = get_buf_size(buf->bufp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001495 }
1496 nb_reply_nr(cmdno, len);
1497/* =====================================================================*/
1498 }
1499 else if (streq((char *)cmd, "getText"))
1500 {
1501 long len;
1502 linenr_T nlines;
1503 char_u *text = NULL;
1504 linenr_T lno = 1;
1505 char_u *p;
1506 char_u *line;
1507
1508 if (buf == NULL || buf->bufp == NULL)
1509 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001510 nbdebug((" invalid buffer identifier in getText\n"));
1511 EMSG("E633: invalid buffer identifier in getText");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001512 retval = FAIL;
1513 }
1514 else
1515 {
1516 len = get_buf_size(buf->bufp);
1517 nlines = buf->bufp->b_ml.ml_line_count;
1518 text = alloc((unsigned)((len > 0)
1519 ? ((len + nlines) * 2) : 4));
1520 if (text == NULL)
1521 {
1522 nbdebug((" nb_do_cmd: getText has null text field\n"));
1523 retval = FAIL;
1524 }
1525 else
1526 {
1527 p = text;
1528 *p++ = '\"';
1529 for (; lno <= nlines ; lno++)
1530 {
1531 line = nb_quote(ml_get_buf(buf->bufp, lno, FALSE));
1532 if (line != NULL)
1533 {
1534 STRCPY(p, line);
1535 p += STRLEN(line);
1536 *p++ = '\\';
1537 *p++ = 'n';
Bram Moolenaar009b2592004-10-24 19:18:58 +00001538 vim_free(line);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001539 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001540 }
1541 *p++ = '\"';
1542 *p = '\0';
1543 }
1544 }
1545 if (text == NULL)
1546 nb_reply_text(cmdno, (char_u *)"");
1547 else
1548 {
1549 nb_reply_text(cmdno, text);
1550 vim_free(text);
1551 }
1552/* =====================================================================*/
1553 }
1554 else if (streq((char *)cmd, "remove"))
1555 {
1556 long count;
1557 pos_T first, last;
1558 pos_T *pos;
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00001559 pos_T *next;
1560 linenr_T del_from_lnum, del_to_lnum; /* lines to be deleted as a whole */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001561 int oldFire = netbeansFireChanges;
1562 int oldSuppress = netbeansSuppressNoLines;
1563 int wasChanged;
1564
1565 if (skip >= SKIP_STOP)
1566 {
1567 nbdebug((" Skipping %s command\n", (char *) cmd));
1568 nb_reply_nil(cmdno);
1569 return OK;
1570 }
1571
1572 if (buf == NULL || buf->bufp == NULL)
1573 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001574 nbdebug((" invalid buffer identifier in remove\n"));
1575 EMSG("E634: invalid buffer identifier in remove");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001576 retval = FAIL;
1577 }
1578 else
1579 {
1580 netbeansFireChanges = FALSE;
1581 netbeansSuppressNoLines = TRUE;
1582
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00001583 nb_set_curbuf(buf->bufp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001584 wasChanged = buf->bufp->b_changed;
Bram Moolenaar349b2f62004-10-11 10:00:50 +00001585 cp = (char *)args;
1586 off = strtol(cp, &cp, 10);
1587 count = strtol(cp, &cp, 10);
1588 args = (char_u *)cp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001589 /* delete "count" chars, starting at "off" */
1590 pos = off2pos(buf->bufp, off);
1591 if (!pos)
1592 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001593 nbdebug((" !bad position\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001594 nb_reply_text(cmdno, (char_u *)"!bad position");
1595 netbeansFireChanges = oldFire;
1596 netbeansSuppressNoLines = oldSuppress;
1597 return FAIL;
1598 }
1599 first = *pos;
Bram Moolenaarfa68b0f2009-09-11 12:19:51 +00001600 nbdebug((" FIRST POS: line %d, col %d\n",
1601 first.lnum, first.col));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001602 pos = off2pos(buf->bufp, off+count-1);
1603 if (!pos)
1604 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001605 nbdebug((" !bad count\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001606 nb_reply_text(cmdno, (char_u *)"!bad count");
1607 netbeansFireChanges = oldFire;
1608 netbeansSuppressNoLines = oldSuppress;
1609 return FAIL;
1610 }
1611 last = *pos;
Bram Moolenaarfa68b0f2009-09-11 12:19:51 +00001612 nbdebug((" LAST POS: line %d, col %d\n",
1613 last.lnum, last.col));
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00001614 del_from_lnum = first.lnum;
1615 del_to_lnum = last.lnum;
Bram Moolenaar70b2a562012-01-10 22:26:17 +01001616 do_update = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001617
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00001618 /* Get the position of the first byte after the deleted
1619 * section. "next" is NULL when deleting to the end of the
1620 * file. */
1621 next = off2pos(buf->bufp, off + count);
1622
1623 /* Remove part of the first line. */
Bram Moolenaarfa68b0f2009-09-11 12:19:51 +00001624 if (first.col != 0
1625 || (next != NULL && first.lnum == next->lnum))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001626 {
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00001627 if (first.lnum != last.lnum
1628 || (next != NULL && first.lnum != next->lnum))
1629 {
1630 /* remove to the end of the first line */
1631 nb_partialremove(first.lnum, first.col,
1632 (colnr_T)MAXCOL);
1633 if (first.lnum == last.lnum)
1634 {
1635 /* Partial line to remove includes the end of
1636 * line. Join the line with the next one, have
1637 * the next line deleted below. */
1638 nb_joinlines(first.lnum, next->lnum);
1639 del_to_lnum = next->lnum;
1640 }
1641 }
1642 else
1643 {
1644 /* remove within one line */
1645 nb_partialremove(first.lnum, first.col, last.col);
1646 }
1647 ++del_from_lnum; /* don't delete the first line */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001648 }
1649
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00001650 /* Remove part of the last line. */
1651 if (first.lnum != last.lnum && next != NULL
1652 && next->col != 0 && last.lnum == next->lnum)
1653 {
1654 nb_partialremove(last.lnum, 0, last.col);
1655 if (del_from_lnum > first.lnum)
1656 {
1657 /* Join end of last line to start of first line; last
1658 * line is deleted below. */
1659 nb_joinlines(first.lnum, last.lnum);
1660 }
1661 else
1662 /* First line is deleted as a whole, keep the last
1663 * line. */
1664 --del_to_lnum;
1665 }
1666
1667 /* First is partial line; last line to remove includes
1668 * the end of line; join first line to line following last
1669 * line; line following last line is deleted below. */
1670 if (first.lnum != last.lnum && del_from_lnum > first.lnum
1671 && next != NULL && last.lnum != next->lnum)
1672 {
1673 nb_joinlines(first.lnum, next->lnum);
1674 del_to_lnum = next->lnum;
1675 }
1676
1677 /* Delete whole lines if there are any. */
1678 if (del_to_lnum >= del_from_lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001679 {
1680 int i;
1681
1682 /* delete signs from the lines being deleted */
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00001683 for (i = del_from_lnum; i <= del_to_lnum; i++)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001684 {
1685 int id = buf_findsign_id(buf->bufp, (linenr_T)i);
1686 if (id > 0)
1687 {
Bram Moolenaarfa68b0f2009-09-11 12:19:51 +00001688 nbdebug((" Deleting sign %d on line %d\n",
1689 id, i));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001690 buf_delsign(buf->bufp, id);
1691 }
1692 else
Bram Moolenaarb85cb212009-05-17 14:24:23 +00001693 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001694 nbdebug((" No sign on line %d\n", i));
Bram Moolenaarb85cb212009-05-17 14:24:23 +00001695 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001696 }
1697
Bram Moolenaarfa68b0f2009-09-11 12:19:51 +00001698 nbdebug((" Deleting lines %d through %d\n",
1699 del_from_lnum, del_to_lnum));
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00001700 curwin->w_cursor.lnum = del_from_lnum;
1701 curwin->w_cursor.col = 0;
1702 del_lines(del_to_lnum - del_from_lnum + 1, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001703 }
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00001704
1705 /* Leave cursor at first deleted byte. */
1706 curwin->w_cursor = first;
1707 check_cursor_lnum();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001708 buf->bufp->b_changed = wasChanged; /* logically unchanged */
1709 netbeansFireChanges = oldFire;
1710 netbeansSuppressNoLines = oldSuppress;
1711
1712 u_blockfree(buf->bufp);
1713 u_clearall(buf->bufp);
1714 }
1715 nb_reply_nil(cmdno);
1716/* =====================================================================*/
1717 }
1718 else if (streq((char *)cmd, "insert"))
1719 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001720 char_u *to_free;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001721
1722 if (skip >= SKIP_STOP)
1723 {
1724 nbdebug((" Skipping %s command\n", (char *) cmd));
1725 nb_reply_nil(cmdno);
1726 return OK;
1727 }
1728
1729 /* get offset */
Bram Moolenaar349b2f62004-10-11 10:00:50 +00001730 cp = (char *)args;
1731 off = strtol(cp, &cp, 10);
1732 args = (char_u *)cp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001733
1734 /* get text to be inserted */
1735 args = skipwhite(args);
1736 args = to_free = (char_u *)nb_unquote(args, NULL);
Bram Moolenaar009b2592004-10-24 19:18:58 +00001737 /*
1738 nbdebug((" CHUNK[%d]: %d bytes at offset %d\n",
1739 buf->bufp->b_ml.ml_line_count, STRLEN(args), off));
1740 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001741
1742 if (buf == NULL || buf->bufp == NULL)
1743 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001744 nbdebug((" invalid buffer identifier in insert\n"));
1745 EMSG("E635: invalid buffer identifier in insert");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001746 retval = FAIL;
1747 }
1748 else if (args != NULL)
1749 {
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001750 int ff_detected = EOL_UNKNOWN;
1751 int buf_was_empty = (buf->bufp->b_ml.ml_flags & ML_EMPTY);
1752 size_t len = 0;
1753 int added = 0;
1754 int oldFire = netbeansFireChanges;
1755 int old_b_changed;
Bram Moolenaar309cbc32012-01-10 22:31:31 +01001756 char_u *nlp;
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001757 linenr_T lnum;
1758 linenr_T lnum_start;
1759 pos_T *pos;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001760
Bram Moolenaar071d4272004-06-13 20:20:40 +00001761 netbeansFireChanges = 0;
1762
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001763 /* Jump to the buffer where we insert. After this "curbuf"
1764 * can be used. */
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00001765 nb_set_curbuf(buf->bufp);
Bram Moolenaara3227e22006-03-08 21:32:40 +00001766 old_b_changed = curbuf->b_changed;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001767
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001768 /* Convert the specified character offset into a lnum/col
1769 * position. */
Bram Moolenaara3227e22006-03-08 21:32:40 +00001770 pos = off2pos(curbuf, off);
1771 if (pos != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001772 {
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001773 if (pos->lnum <= 0)
1774 lnum_start = 1;
1775 else
1776 lnum_start = pos->lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001777 }
1778 else
1779 {
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001780 /* If the given position is not found, assume we want
Bram Moolenaar071d4272004-06-13 20:20:40 +00001781 * the end of the file. See setLocAndSize HACK. */
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001782 if (buf_was_empty)
1783 lnum_start = 1; /* above empty line */
1784 else
1785 lnum_start = curbuf->b_ml.ml_line_count + 1;
Bram Moolenaar009b2592004-10-24 19:18:58 +00001786 }
1787
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001788 /* "lnum" is the line where we insert: either append to it or
1789 * insert a new line above it. */
1790 lnum = lnum_start;
1791
1792 /* Loop over the "\n" separated lines of the argument. */
Bram Moolenaar70b2a562012-01-10 22:26:17 +01001793 do_update = 1;
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001794 while (*args != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001795 {
Bram Moolenaar309cbc32012-01-10 22:31:31 +01001796 nlp = vim_strchr(args, '\n');
1797 if (nlp == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001798 {
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001799 /* Incomplete line, probably truncated. Next "insert"
1800 * command should append to this one. */
1801 len = STRLEN(args);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001802 }
Bram Moolenaar009b2592004-10-24 19:18:58 +00001803 else
1804 {
Bram Moolenaar309cbc32012-01-10 22:31:31 +01001805 len = nlp - args;
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001806
1807 /*
1808 * We need to detect EOL style, because the commands
1809 * use a character offset.
1810 */
Bram Moolenaar309cbc32012-01-10 22:31:31 +01001811 if (nlp > args && nlp[-1] == '\r')
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001812 {
1813 ff_detected = EOL_DOS;
1814 --len;
1815 }
1816 else
1817 ff_detected = EOL_UNIX;
1818 }
1819 args[len] = NUL;
1820
1821 if (lnum == lnum_start
1822 && ((pos != NULL && pos->col > 0)
1823 || (lnum == 1 && buf_was_empty)))
1824 {
1825 char_u *oldline = ml_get(lnum);
1826 char_u *newline;
1827
Bram Moolenaare4365282012-04-20 19:47:05 +02001828 /* Insert halfway a line. */
Bram Moolenaar309cbc32012-01-10 22:31:31 +01001829 newline = alloc_check(
1830 (unsigned)(STRLEN(oldline) + len + 1));
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001831 if (newline != NULL)
1832 {
Bram Moolenaare4365282012-04-20 19:47:05 +02001833 mch_memmove(newline, oldline, (size_t)pos->col);
1834 newline[pos->col] = NUL;
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001835 STRCAT(newline, args);
Bram Moolenaare4365282012-04-20 19:47:05 +02001836 STRCAT(newline, oldline + pos->col);
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001837 ml_replace(lnum, newline, FALSE);
1838 }
1839 }
1840 else
1841 {
1842 /* Append a new line. Not that we always do this,
1843 * also when the text doesn't end in a "\n". */
Bram Moolenaar309cbc32012-01-10 22:31:31 +01001844 ml_append((linenr_T)(lnum - 1), args,
1845 (colnr_T)(len + 1), FALSE);
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001846 ++added;
Bram Moolenaar009b2592004-10-24 19:18:58 +00001847 }
1848
Bram Moolenaar309cbc32012-01-10 22:31:31 +01001849 if (nlp == NULL)
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001850 break;
1851 ++lnum;
Bram Moolenaar309cbc32012-01-10 22:31:31 +01001852 args = nlp + 1;
Bram Moolenaar009b2592004-10-24 19:18:58 +00001853 }
1854
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001855 /* Adjust the marks below the inserted lines. */
1856 appended_lines_mark(lnum_start - 1, (long)added);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001857
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001858 /*
1859 * When starting with an empty buffer set the fileformat.
1860 * This is just guessing...
Bram Moolenaar071d4272004-06-13 20:20:40 +00001861 */
1862 if (buf_was_empty)
1863 {
1864 if (ff_detected == EOL_UNKNOWN)
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001865#if defined(MSDOS) || defined(MSWIN) || defined(OS2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001866 ff_detected = EOL_DOS;
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001867#else
1868 ff_detected = EOL_UNIX;
1869#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001870 set_fileformat(ff_detected, OPT_LOCAL);
Bram Moolenaara3227e22006-03-08 21:32:40 +00001871 curbuf->b_start_ffc = *curbuf->b_p_ff;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001872 }
1873
Bram Moolenaar071d4272004-06-13 20:20:40 +00001874 /*
1875 * XXX - GRP - Is the next line right? If I've inserted
1876 * text the buffer has been updated but not written. Will
1877 * netbeans guarantee to write it? Even if I do a :q! ?
1878 */
Bram Moolenaara3227e22006-03-08 21:32:40 +00001879 curbuf->b_changed = old_b_changed; /* logically unchanged */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001880 netbeansFireChanges = oldFire;
1881
Bram Moolenaar0fd92892006-03-09 22:27:48 +00001882 /* Undo info is invalid now... */
Bram Moolenaara3227e22006-03-08 21:32:40 +00001883 u_blockfree(curbuf);
1884 u_clearall(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001885 }
1886 vim_free(to_free);
1887 nb_reply_nil(cmdno); /* or !error */
1888 }
1889 else
1890 {
1891 nbdebug(("UNIMPLEMENTED FUNCTION: %s\n", cmd));
1892 nb_reply_nil(cmdno);
1893 retval = FAIL;
1894 }
1895 }
1896 else /* Not a function; no reply required. */
1897 {
1898/* =====================================================================*/
1899 if (streq((char *)cmd, "create"))
1900 {
1901 /* Create a buffer without a name. */
1902 if (buf == NULL)
1903 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001904 nbdebug((" invalid buffer identifier in create\n"));
1905 EMSG("E636: invalid buffer identifier in create");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001906 return FAIL;
1907 }
1908 vim_free(buf->displayname);
1909 buf->displayname = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001910
1911 netbeansReadFile = 0; /* don't try to open disk file */
Bram Moolenaar701f7af2008-11-15 13:12:07 +00001912 do_ecmd(0, NULL, 0, 0, ECMD_ONE, ECMD_HIDE + ECMD_OLDBUF, curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001913 netbeansReadFile = 1;
1914 buf->bufp = curbuf;
1915 maketitle();
Bram Moolenaar009b2592004-10-24 19:18:58 +00001916 buf->insertDone = FALSE;
Bram Moolenaar67c53842010-05-22 18:28:27 +02001917#if defined(FEAT_MENU) && defined(FEAT_GUI)
Bram Moolenaard54a6882010-08-09 22:49:00 +02001918 if (gui.in_use)
1919 gui_update_menus(0);
Bram Moolenaar67c53842010-05-22 18:28:27 +02001920#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001921/* =====================================================================*/
1922 }
Bram Moolenaar009b2592004-10-24 19:18:58 +00001923 else if (streq((char *)cmd, "insertDone"))
1924 {
Bram Moolenaareb3593b2006-04-22 22:33:57 +00001925 if (buf == NULL || buf->bufp == NULL)
1926 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001927 nbdebug((" invalid buffer identifier in insertDone\n"));
Bram Moolenaareb3593b2006-04-22 22:33:57 +00001928 }
1929 else
1930 {
1931 buf->bufp->b_start_eol = *args == 'T';
1932 buf->insertDone = TRUE;
1933 args += 2;
1934 buf->bufp->b_p_ro = *args == 'T';
1935 print_read_msg(buf);
1936 }
Bram Moolenaar009b2592004-10-24 19:18:58 +00001937/* =====================================================================*/
1938 }
1939 else if (streq((char *)cmd, "saveDone"))
1940 {
Bram Moolenaareb3593b2006-04-22 22:33:57 +00001941 long savedChars = atol((char *)args);
1942
1943 if (buf == NULL || buf->bufp == NULL)
1944 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001945 nbdebug((" invalid buffer identifier in saveDone\n"));
Bram Moolenaareb3593b2006-04-22 22:33:57 +00001946 }
1947 else
1948 print_save_msg(buf, savedChars);
Bram Moolenaar009b2592004-10-24 19:18:58 +00001949/* =====================================================================*/
1950 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001951 else if (streq((char *)cmd, "startDocumentListen"))
1952 {
1953 if (buf == NULL)
1954 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001955 nbdebug((" invalid buffer identifier in startDocumentListen\n"));
1956 EMSG("E637: invalid buffer identifier in startDocumentListen");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001957 return FAIL;
1958 }
1959 buf->fireChanges = 1;
1960/* =====================================================================*/
1961 }
1962 else if (streq((char *)cmd, "stopDocumentListen"))
1963 {
1964 if (buf == NULL)
1965 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001966 nbdebug((" invalid buffer identifier in stopDocumentListen\n"));
1967 EMSG("E638: invalid buffer identifier in stopDocumentListen");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001968 return FAIL;
1969 }
1970 buf->fireChanges = 0;
Bram Moolenaar24c088a2005-02-02 22:55:47 +00001971 if (buf->bufp != NULL && buf->bufp->b_was_netbeans_file)
Bram Moolenaar009b2592004-10-24 19:18:58 +00001972 {
Bram Moolenaar24c088a2005-02-02 22:55:47 +00001973 if (!buf->bufp->b_netbeans_file)
Bram Moolenaarf2330482008-06-24 20:19:36 +00001974 {
1975 nbdebug(("E658: NetBeans connection lost for buffer %ld\n", buf->bufp->b_fnum));
Bram Moolenaar009b2592004-10-24 19:18:58 +00001976 EMSGN(_("E658: NetBeans connection lost for buffer %ld"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001977 buf->bufp->b_fnum);
Bram Moolenaarf2330482008-06-24 20:19:36 +00001978 }
Bram Moolenaar009b2592004-10-24 19:18:58 +00001979 else
1980 {
Bram Moolenaar24c088a2005-02-02 22:55:47 +00001981 /* NetBeans uses stopDocumentListen when it stops editing
1982 * a file. It then expects the buffer in Vim to
1983 * disappear. */
1984 do_bufdel(DOBUF_DEL, (char_u *)"", 1,
1985 buf->bufp->b_fnum, buf->bufp->b_fnum, TRUE);
Bram Moolenaar009b2592004-10-24 19:18:58 +00001986 vim_memset(buf, 0, sizeof(nbbuf_T));
1987 }
1988 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001989/* =====================================================================*/
1990 }
1991 else if (streq((char *)cmd, "setTitle"))
1992 {
1993 if (buf == NULL)
1994 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00001995 nbdebug((" invalid buffer identifier in setTitle\n"));
1996 EMSG("E639: invalid buffer identifier in setTitle");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001997 return FAIL;
1998 }
1999 vim_free(buf->displayname);
2000 buf->displayname = nb_unquote(args, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002001/* =====================================================================*/
2002 }
2003 else if (streq((char *)cmd, "initDone"))
2004 {
2005 if (buf == NULL || buf->bufp == NULL)
2006 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002007 nbdebug((" invalid buffer identifier in initDone\n"));
2008 EMSG("E640: invalid buffer identifier in initDone");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002009 return FAIL;
2010 }
Bram Moolenaar70b2a562012-01-10 22:26:17 +01002011 do_update = 1;
Bram Moolenaar009b2592004-10-24 19:18:58 +00002012 buf->initDone = TRUE;
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002013 nb_set_curbuf(buf->bufp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002014#if defined(FEAT_AUTOCMD)
2015 apply_autocmds(EVENT_BUFREADPOST, 0, 0, FALSE, buf->bufp);
2016#endif
2017
2018 /* handle any postponed key commands */
2019 handle_key_queue();
2020/* =====================================================================*/
2021 }
2022 else if (streq((char *)cmd, "setBufferNumber")
2023 || streq((char *)cmd, "putBufferNumber"))
2024 {
Bram Moolenaar009b2592004-10-24 19:18:58 +00002025 char_u *path;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002026 buf_T *bufp;
2027
2028 if (buf == NULL)
2029 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002030 nbdebug((" invalid buffer identifier in setBufferNumber\n"));
2031 EMSG("E641: invalid buffer identifier in setBufferNumber");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002032 return FAIL;
2033 }
Bram Moolenaar009b2592004-10-24 19:18:58 +00002034 path = (char_u *)nb_unquote(args, NULL);
2035 if (path == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002036 return FAIL;
Bram Moolenaar009b2592004-10-24 19:18:58 +00002037 bufp = buflist_findname(path);
2038 vim_free(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002039 if (bufp == NULL)
2040 {
Bram Moolenaarec906222009-02-21 21:14:00 +00002041 nbdebug((" File %s not found in setBufferNumber\n", args));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002042 EMSG2("E642: File %s not found in setBufferNumber", args);
2043 return FAIL;
2044 }
2045 buf->bufp = bufp;
Bram Moolenaar009b2592004-10-24 19:18:58 +00002046 buf->nbbuf_number = bufp->b_fnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002047
2048 /* "setBufferNumber" has the side effect of jumping to the buffer
2049 * (don't know why!). Don't do that for "putBufferNumber". */
2050 if (*cmd != 'p')
2051 coloncmd(":buffer %d", bufp->b_fnum);
2052 else
2053 {
Bram Moolenaar009b2592004-10-24 19:18:58 +00002054 buf->initDone = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002055
2056 /* handle any postponed key commands */
2057 handle_key_queue();
2058 }
2059
Bram Moolenaar071d4272004-06-13 20:20:40 +00002060/* =====================================================================*/
2061 }
2062 else if (streq((char *)cmd, "setFullName"))
2063 {
2064 if (buf == NULL)
2065 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002066 nbdebug((" invalid buffer identifier in setFullName\n"));
2067 EMSG("E643: invalid buffer identifier in setFullName");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002068 return FAIL;
2069 }
2070 vim_free(buf->displayname);
2071 buf->displayname = nb_unquote(args, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002072
2073 netbeansReadFile = 0; /* don't try to open disk file */
2074 do_ecmd(0, (char_u *)buf->displayname, 0, 0, ECMD_ONE,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002075 ECMD_HIDE + ECMD_OLDBUF, curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002076 netbeansReadFile = 1;
2077 buf->bufp = curbuf;
2078 maketitle();
Bram Moolenaar67c53842010-05-22 18:28:27 +02002079#if defined(FEAT_MENU) && defined(FEAT_GUI)
Bram Moolenaard54a6882010-08-09 22:49:00 +02002080 if (gui.in_use)
2081 gui_update_menus(0);
Bram Moolenaar67c53842010-05-22 18:28:27 +02002082#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002083/* =====================================================================*/
2084 }
2085 else if (streq((char *)cmd, "editFile"))
2086 {
2087 if (buf == NULL)
2088 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002089 nbdebug((" invalid buffer identifier in editFile\n"));
2090 EMSG("E644: invalid buffer identifier in editFile");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002091 return FAIL;
2092 }
2093 /* Edit a file: like create + setFullName + read the file. */
2094 vim_free(buf->displayname);
2095 buf->displayname = nb_unquote(args, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002096 do_ecmd(0, (char_u *)buf->displayname, NULL, NULL, ECMD_ONE,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002097 ECMD_HIDE + ECMD_OLDBUF, curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002098 buf->bufp = curbuf;
Bram Moolenaar009b2592004-10-24 19:18:58 +00002099 buf->initDone = TRUE;
Bram Moolenaar70b2a562012-01-10 22:26:17 +01002100 do_update = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002101#if defined(FEAT_TITLE)
2102 maketitle();
2103#endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02002104#if defined(FEAT_MENU) && defined(FEAT_GUI)
Bram Moolenaard54a6882010-08-09 22:49:00 +02002105 if (gui.in_use)
2106 gui_update_menus(0);
Bram Moolenaar67c53842010-05-22 18:28:27 +02002107#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002108/* =====================================================================*/
2109 }
2110 else if (streq((char *)cmd, "setVisible"))
2111 {
2112 if (buf == NULL || buf->bufp == NULL)
2113 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002114 nbdebug((" invalid buffer identifier in setVisible\n"));
2115 /* This message was commented out, probably because it can
2116 * happen when shutting down. */
2117 if (p_verbose > 0)
2118 EMSG("E645: invalid buffer identifier in setVisible");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002119 return FAIL;
2120 }
Bram Moolenaar009b2592004-10-24 19:18:58 +00002121 if (streq((char *)args, "T") && buf->bufp != curbuf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002122 {
2123 exarg_T exarg;
2124 exarg.cmd = (char_u *)"goto";
2125 exarg.forceit = FALSE;
Bram Moolenaar009b2592004-10-24 19:18:58 +00002126 dosetvisible = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002127 goto_buffer(&exarg, DOBUF_FIRST, FORWARD, buf->bufp->b_fnum);
Bram Moolenaar70b2a562012-01-10 22:26:17 +01002128 do_update = 1;
Bram Moolenaar009b2592004-10-24 19:18:58 +00002129 dosetvisible = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002130
Bram Moolenaar67c53842010-05-22 18:28:27 +02002131#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00002132 /* Side effect!!!. */
Bram Moolenaard54a6882010-08-09 22:49:00 +02002133 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002134 gui_mch_set_foreground();
Bram Moolenaar67c53842010-05-22 18:28:27 +02002135#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002136 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002137/* =====================================================================*/
2138 }
2139 else if (streq((char *)cmd, "raise"))
2140 {
Bram Moolenaar67c53842010-05-22 18:28:27 +02002141#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00002142 /* Bring gvim to the foreground. */
Bram Moolenaard54a6882010-08-09 22:49:00 +02002143 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002144 gui_mch_set_foreground();
Bram Moolenaar67c53842010-05-22 18:28:27 +02002145#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002146/* =====================================================================*/
2147 }
2148 else if (streq((char *)cmd, "setModified"))
2149 {
Bram Moolenaarff064e12008-06-09 13:10:45 +00002150 int prev_b_changed;
2151
Bram Moolenaar071d4272004-06-13 20:20:40 +00002152 if (buf == NULL || buf->bufp == NULL)
2153 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002154 nbdebug((" invalid buffer identifier in setModified\n"));
2155 /* This message was commented out, probably because it can
2156 * happen when shutting down. */
2157 if (p_verbose > 0)
2158 EMSG("E646: invalid buffer identifier in setModified");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002159 return FAIL;
2160 }
Bram Moolenaarff064e12008-06-09 13:10:45 +00002161 prev_b_changed = buf->bufp->b_changed;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002162 if (streq((char *)args, "T"))
Bram Moolenaarff064e12008-06-09 13:10:45 +00002163 buf->bufp->b_changed = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002164 else
2165 {
2166 struct stat st;
2167
2168 /* Assume NetBeans stored the file. Reset the timestamp to
2169 * avoid "file changed" warnings. */
2170 if (buf->bufp->b_ffname != NULL
2171 && mch_stat((char *)buf->bufp->b_ffname, &st) >= 0)
2172 buf_store_time(buf->bufp, &st, buf->bufp->b_ffname);
Bram Moolenaarff064e12008-06-09 13:10:45 +00002173 buf->bufp->b_changed = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002174 }
2175 buf->modified = buf->bufp->b_changed;
Bram Moolenaarff064e12008-06-09 13:10:45 +00002176 if (prev_b_changed != buf->bufp->b_changed)
2177 {
2178#ifdef FEAT_WINDOWS
2179 check_status(buf->bufp);
2180 redraw_tabline = TRUE;
2181#endif
2182#ifdef FEAT_TITLE
2183 maketitle();
2184#endif
2185 update_screen(0);
2186 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002187/* =====================================================================*/
2188 }
Bram Moolenaar009b2592004-10-24 19:18:58 +00002189 else if (streq((char *)cmd, "setModtime"))
2190 {
Bram Moolenaareb3593b2006-04-22 22:33:57 +00002191 if (buf == NULL || buf->bufp == NULL)
Bram Moolenaarf2330482008-06-24 20:19:36 +00002192 nbdebug((" invalid buffer identifier in setModtime\n"));
Bram Moolenaareb3593b2006-04-22 22:33:57 +00002193 else
2194 buf->bufp->b_mtime = atoi((char *)args);
Bram Moolenaar009b2592004-10-24 19:18:58 +00002195/* =====================================================================*/
2196 }
2197 else if (streq((char *)cmd, "setReadOnly"))
2198 {
Bram Moolenaareb3593b2006-04-22 22:33:57 +00002199 if (buf == NULL || buf->bufp == NULL)
Bram Moolenaarf2330482008-06-24 20:19:36 +00002200 nbdebug((" invalid buffer identifier in setReadOnly\n"));
Bram Moolenaareb3593b2006-04-22 22:33:57 +00002201 else if (streq((char *)args, "T"))
Bram Moolenaar009b2592004-10-24 19:18:58 +00002202 buf->bufp->b_p_ro = TRUE;
2203 else
2204 buf->bufp->b_p_ro = FALSE;
2205/* =====================================================================*/
2206 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002207 else if (streq((char *)cmd, "setMark"))
2208 {
2209 /* not yet */
2210/* =====================================================================*/
2211 }
2212 else if (streq((char *)cmd, "showBalloon"))
2213 {
2214#if defined(FEAT_BEVAL)
2215 static char *text = NULL;
2216
2217 /*
2218 * Set up the Balloon Expression Evaluation area.
2219 * Ignore 'ballooneval' here.
2220 * The text pointer must remain valid for a while.
2221 */
2222 if (balloonEval != NULL)
2223 {
2224 vim_free(text);
2225 text = nb_unquote(args, NULL);
2226 if (text != NULL)
2227 gui_mch_post_balloon(balloonEval, (char_u *)text);
2228 }
2229#endif
2230/* =====================================================================*/
2231 }
2232 else if (streq((char *)cmd, "setDot"))
2233 {
2234 pos_T *pos;
2235#ifdef NBDEBUG
2236 char_u *s;
2237#endif
2238
2239 if (buf == NULL || buf->bufp == NULL)
2240 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002241 nbdebug((" invalid buffer identifier in setDot\n"));
2242 EMSG("E647: invalid buffer identifier in setDot");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002243 return FAIL;
2244 }
2245
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002246 nb_set_curbuf(buf->bufp);
2247
Bram Moolenaar071d4272004-06-13 20:20:40 +00002248 /* Don't want Visual mode now. */
2249 if (VIsual_active)
2250 end_visual_mode();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002251#ifdef NBDEBUG
2252 s = args;
2253#endif
2254 pos = get_off_or_lnum(buf->bufp, &args);
2255 if (pos)
2256 {
2257 curwin->w_cursor = *pos;
2258 check_cursor();
2259#ifdef FEAT_FOLDING
2260 foldOpenCursor();
2261#endif
2262 }
2263 else
Bram Moolenaarb85cb212009-05-17 14:24:23 +00002264 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002265 nbdebug((" BAD POSITION in setDot: %s\n", s));
Bram Moolenaarb85cb212009-05-17 14:24:23 +00002266 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002267
2268 /* gui_update_cursor(TRUE, FALSE); */
2269 /* update_curbuf(NOT_VALID); */
2270 update_topline(); /* scroll to show the line */
2271 update_screen(VALID);
2272 setcursor();
Bram Moolenaar96bcc5e2011-04-01 15:33:59 +02002273 cursor_on();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002274 out_flush();
Bram Moolenaar67c53842010-05-22 18:28:27 +02002275#ifdef FEAT_GUI
Bram Moolenaard54a6882010-08-09 22:49:00 +02002276 if (gui.in_use)
2277 {
2278 gui_update_cursor(TRUE, FALSE);
2279 gui_mch_flush();
2280 }
Bram Moolenaar67c53842010-05-22 18:28:27 +02002281#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002282 /* Quit a hit-return or more prompt. */
2283 if (State == HITRETURN || State == ASKMORE)
2284 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002285#ifdef FEAT_GUI_GTK
Bram Moolenaard54a6882010-08-09 22:49:00 +02002286 if (gui.in_use && gtk_main_level() > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002287 gtk_main_quit();
2288#endif
2289 }
2290/* =====================================================================*/
2291 }
2292 else if (streq((char *)cmd, "close"))
2293 {
2294#ifdef NBDEBUG
2295 char *name = "<NONE>";
2296#endif
2297
2298 if (buf == NULL)
2299 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002300 nbdebug((" invalid buffer identifier in close\n"));
2301 EMSG("E648: invalid buffer identifier in close");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002302 return FAIL;
2303 }
2304
2305#ifdef NBDEBUG
2306 if (buf->displayname != NULL)
2307 name = buf->displayname;
2308#endif
Bram Moolenaarf2330482008-06-24 20:19:36 +00002309 if (buf->bufp == NULL)
2310 {
2311 nbdebug((" invalid buffer identifier in close\n"));
2312 /* This message was commented out, probably because it can
2313 * happen when shutting down. */
2314 if (p_verbose > 0)
2315 EMSG("E649: invalid buffer identifier in close");
2316 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002317 nbdebug((" CLOSE %d: %s\n", bufno, name));
Bram Moolenaar67c53842010-05-22 18:28:27 +02002318#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00002319 need_mouse_correct = TRUE;
Bram Moolenaar67c53842010-05-22 18:28:27 +02002320#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002321 if (buf->bufp != NULL)
2322 do_buffer(DOBUF_WIPE, DOBUF_FIRST, FORWARD,
2323 buf->bufp->b_fnum, TRUE);
Bram Moolenaar8d602722006-08-08 19:34:19 +00002324 buf->bufp = NULL;
2325 buf->initDone = FALSE;
Bram Moolenaar70b2a562012-01-10 22:26:17 +01002326 do_update = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002327/* =====================================================================*/
2328 }
2329 else if (streq((char *)cmd, "setStyle")) /* obsolete... */
2330 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002331 nbdebug((" setStyle is obsolete!\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002332/* =====================================================================*/
2333 }
2334 else if (streq((char *)cmd, "setExitDelay"))
2335 {
Bram Moolenaar009b2592004-10-24 19:18:58 +00002336 /* Only used in version 2.1. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002337/* =====================================================================*/
2338 }
2339 else if (streq((char *)cmd, "defineAnnoType"))
2340 {
2341#ifdef FEAT_SIGNS
2342 int typeNum;
2343 char_u *typeName;
2344 char_u *tooltip;
2345 char_u *p;
2346 char_u *glyphFile;
Bram Moolenaar67c53842010-05-22 18:28:27 +02002347 int parse_error = FALSE;
2348 char_u *fg;
2349 char_u *bg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002350
2351 if (buf == NULL)
2352 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002353 nbdebug((" invalid buffer identifier in defineAnnoType\n"));
2354 EMSG("E650: invalid buffer identifier in defineAnnoType");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002355 return FAIL;
2356 }
2357
Bram Moolenaar349b2f62004-10-11 10:00:50 +00002358 cp = (char *)args;
2359 typeNum = strtol(cp, &cp, 10);
2360 args = (char_u *)cp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002361 args = skipwhite(args);
2362 typeName = (char_u *)nb_unquote(args, &args);
2363 args = skipwhite(args + 1);
2364 tooltip = (char_u *)nb_unquote(args, &args);
2365 args = skipwhite(args + 1);
2366
2367 p = (char_u *)nb_unquote(args, &args);
2368 glyphFile = vim_strsave_escaped(p, escape_chars);
2369 vim_free(p);
2370
2371 args = skipwhite(args + 1);
Bram Moolenaar67c53842010-05-22 18:28:27 +02002372 p = skiptowhite(args);
2373 if (*p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002374 {
Bram Moolenaar67c53842010-05-22 18:28:27 +02002375 *p = NUL;
2376 p = skipwhite(p + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002377 }
Bram Moolenaar67c53842010-05-22 18:28:27 +02002378 fg = vim_strsave(args);
2379 bg = vim_strsave(p);
2380 if (STRLEN(fg) > MAX_COLOR_LENGTH || STRLEN(bg) > MAX_COLOR_LENGTH)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002381 {
Bram Moolenaar67c53842010-05-22 18:28:27 +02002382 EMSG("E532: highlighting color name too long in defineAnnoType");
2383 vim_free(typeName);
2384 parse_error = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002385 }
Bram Moolenaar67c53842010-05-22 18:28:27 +02002386 else if (typeName != NULL && tooltip != NULL && glyphFile != NULL)
2387 addsigntype(buf, typeNum, typeName, tooltip, glyphFile, fg, bg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002388 else
2389 vim_free(typeName);
2390
2391 /* don't free typeName; it's used directly in addsigntype() */
Bram Moolenaar67c53842010-05-22 18:28:27 +02002392 vim_free(fg);
2393 vim_free(bg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002394 vim_free(tooltip);
2395 vim_free(glyphFile);
Bram Moolenaar67c53842010-05-22 18:28:27 +02002396 if (parse_error)
2397 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002398
2399#endif
2400/* =====================================================================*/
2401 }
2402 else if (streq((char *)cmd, "addAnno"))
2403 {
2404#ifdef FEAT_SIGNS
2405 int serNum;
2406 int localTypeNum;
2407 int typeNum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002408 pos_T *pos;
2409
2410 if (buf == NULL || buf->bufp == NULL)
2411 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002412 nbdebug((" invalid buffer identifier in addAnno\n"));
2413 EMSG("E651: invalid buffer identifier in addAnno");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002414 return FAIL;
2415 }
2416
Bram Moolenaar70b2a562012-01-10 22:26:17 +01002417 do_update = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002418
Bram Moolenaar349b2f62004-10-11 10:00:50 +00002419 cp = (char *)args;
2420 serNum = strtol(cp, &cp, 10);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002421
2422 /* Get the typenr specific for this buffer and convert it to
2423 * the global typenumber, as used for the sign name. */
Bram Moolenaar349b2f62004-10-11 10:00:50 +00002424 localTypeNum = strtol(cp, &cp, 10);
2425 args = (char_u *)cp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002426 typeNum = mapsigntype(buf, localTypeNum);
2427
2428 pos = get_off_or_lnum(buf->bufp, &args);
2429
Bram Moolenaar349b2f62004-10-11 10:00:50 +00002430 cp = (char *)args;
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00002431 ignored = (int)strtol(cp, &cp, 10);
Bram Moolenaar349b2f62004-10-11 10:00:50 +00002432 args = (char_u *)cp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002433# ifdef NBDEBUG
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00002434 if (ignored != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002435 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002436 nbdebug((" partial line annotation -- Not Yet Implemented!\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002437 }
2438# endif
2439 if (serNum >= GUARDEDOFFSET)
2440 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002441 nbdebug((" too many annotations! ignoring...\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002442 return FAIL;
2443 }
2444 if (pos)
2445 {
Bram Moolenaarec906222009-02-21 21:14:00 +00002446 coloncmd(":sign place %d line=%ld name=%d buffer=%d",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002447 serNum, pos->lnum, typeNum, buf->bufp->b_fnum);
2448 if (typeNum == curPCtype)
2449 coloncmd(":sign jump %d buffer=%d", serNum,
2450 buf->bufp->b_fnum);
2451 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002452#endif
2453/* =====================================================================*/
2454 }
2455 else if (streq((char *)cmd, "removeAnno"))
2456 {
2457#ifdef FEAT_SIGNS
2458 int serNum;
2459
2460 if (buf == NULL || buf->bufp == NULL)
2461 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002462 nbdebug((" invalid buffer identifier in removeAnno\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002463 return FAIL;
2464 }
Bram Moolenaar70b2a562012-01-10 22:26:17 +01002465 do_update = 1;
Bram Moolenaar349b2f62004-10-11 10:00:50 +00002466 cp = (char *)args;
2467 serNum = strtol(cp, &cp, 10);
2468 args = (char_u *)cp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002469 coloncmd(":sign unplace %d buffer=%d",
2470 serNum, buf->bufp->b_fnum);
2471 redraw_buf_later(buf->bufp, NOT_VALID);
2472#endif
2473/* =====================================================================*/
2474 }
2475 else if (streq((char *)cmd, "moveAnnoToFront"))
2476 {
2477#ifdef FEAT_SIGNS
Bram Moolenaarf2330482008-06-24 20:19:36 +00002478 nbdebug((" moveAnnoToFront: Not Yet Implemented!\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002479#endif
2480/* =====================================================================*/
2481 }
2482 else if (streq((char *)cmd, "guard") || streq((char *)cmd, "unguard"))
2483 {
2484 int len;
2485 pos_T first;
2486 pos_T last;
2487 pos_T *pos;
2488 int un = (cmd[0] == 'u');
2489 static int guardId = GUARDEDOFFSET;
2490
2491 if (skip >= SKIP_STOP)
2492 {
2493 nbdebug((" Skipping %s command\n", (char *) cmd));
2494 return OK;
2495 }
2496
2497 nb_init_graphics();
2498
2499 if (buf == NULL || buf->bufp == NULL)
2500 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002501 nbdebug((" invalid buffer identifier in %s command\n", cmd));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002502 return FAIL;
2503 }
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002504 nb_set_curbuf(buf->bufp);
Bram Moolenaar349b2f62004-10-11 10:00:50 +00002505 cp = (char *)args;
2506 off = strtol(cp, &cp, 10);
2507 len = strtol(cp, NULL, 10);
2508 args = (char_u *)cp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002509 pos = off2pos(buf->bufp, off);
Bram Moolenaar70b2a562012-01-10 22:26:17 +01002510 do_update = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002511 if (!pos)
2512 nbdebug((" no such start pos in %s, %ld\n", cmd, off));
2513 else
2514 {
2515 first = *pos;
2516 pos = off2pos(buf->bufp, off + len - 1);
Bram Moolenaar009b2592004-10-24 19:18:58 +00002517 if (pos != NULL && pos->col == 0)
2518 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002519 /*
2520 * In Java Swing the offset is a position between 2
2521 * characters. If col == 0 then we really want the
2522 * previous line as the end.
2523 */
2524 pos = off2pos(buf->bufp, off + len - 2);
2525 }
2526 if (!pos)
2527 nbdebug((" no such end pos in %s, %ld\n",
2528 cmd, off + len - 1));
2529 else
2530 {
2531 long lnum;
2532 last = *pos;
2533 /* set highlight for region */
2534 nbdebug((" %sGUARD %ld,%d to %ld,%d\n", (un) ? "UN" : "",
2535 first.lnum, first.col,
2536 last.lnum, last.col));
2537#ifdef FEAT_SIGNS
2538 for (lnum = first.lnum; lnum <= last.lnum; lnum++)
2539 {
2540 if (un)
2541 {
2542 /* never used */
2543 }
2544 else
2545 {
2546 if (buf_findsigntype_id(buf->bufp, lnum,
2547 GUARDED) == 0)
2548 {
2549 coloncmd(
Bram Moolenaarec906222009-02-21 21:14:00 +00002550 ":sign place %d line=%ld name=%d buffer=%d",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002551 guardId++, lnum, GUARDED,
2552 buf->bufp->b_fnum);
2553 }
2554 }
2555 }
2556#endif
2557 redraw_buf_later(buf->bufp, NOT_VALID);
2558 }
2559 }
2560/* =====================================================================*/
2561 }
2562 else if (streq((char *)cmd, "startAtomic"))
2563 {
2564 inAtomic = 1;
2565/* =====================================================================*/
2566 }
2567 else if (streq((char *)cmd, "endAtomic"))
2568 {
2569 inAtomic = 0;
2570 if (needupdate)
2571 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01002572 do_update = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002573 needupdate = 0;
2574 }
2575/* =====================================================================*/
2576 }
2577 else if (streq((char *)cmd, "save"))
2578 {
Bram Moolenaar009b2592004-10-24 19:18:58 +00002579 /*
2580 * NOTE - This command is obsolete wrt NetBeans. Its left in
2581 * only for historical reasons.
2582 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002583 if (buf == NULL || buf->bufp == NULL)
2584 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002585 nbdebug((" invalid buffer identifier in %s command\n", cmd));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002586 return FAIL;
2587 }
2588
2589 /* the following is taken from ex_cmds.c (do_wqall function) */
2590 if (bufIsChanged(buf->bufp))
2591 {
2592 /* Only write if the buffer can be written. */
2593 if (p_write
2594 && !buf->bufp->b_p_ro
2595 && buf->bufp->b_ffname != NULL
2596#ifdef FEAT_QUICKFIX
2597 && !bt_dontwrite(buf->bufp)
2598#endif
2599 )
2600 {
2601 buf_write_all(buf->bufp, FALSE);
2602#ifdef FEAT_AUTOCMD
2603 /* an autocommand may have deleted the buffer */
2604 if (!buf_valid(buf->bufp))
2605 buf->bufp = NULL;
2606#endif
2607 }
2608 }
Bram Moolenaarf2330482008-06-24 20:19:36 +00002609 else
2610 {
Bram Moolenaar8065d7f2010-01-19 15:13:14 +01002611 nbdebug((" Buffer has no changes!\n"));
Bram Moolenaarf2330482008-06-24 20:19:36 +00002612 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002613/* =====================================================================*/
2614 }
2615 else if (streq((char *)cmd, "netbeansBuffer"))
2616 {
2617 if (buf == NULL || buf->bufp == NULL)
2618 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002619 nbdebug((" invalid buffer identifier in %s command\n", cmd));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002620 return FAIL;
2621 }
2622 if (*args == 'T')
2623 {
2624 buf->bufp->b_netbeans_file = TRUE;
2625 buf->bufp->b_was_netbeans_file = TRUE;
2626 }
2627 else
2628 buf->bufp->b_netbeans_file = FALSE;
2629/* =====================================================================*/
2630 }
Bram Moolenaar009b2592004-10-24 19:18:58 +00002631 else if (streq((char *)cmd, "specialKeys"))
2632 {
2633 special_keys(args);
2634/* =====================================================================*/
2635 }
2636 else if (streq((char *)cmd, "actionMenuItem"))
2637 {
2638 /* not used yet */
2639/* =====================================================================*/
2640 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002641 else if (streq((char *)cmd, "version"))
2642 {
Bram Moolenaar009b2592004-10-24 19:18:58 +00002643 /* not used yet */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002644 }
Bram Moolenaarf2330482008-06-24 20:19:36 +00002645 else
2646 {
2647 nbdebug(("Unrecognised command: %s\n", cmd));
2648 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002649 /*
2650 * Unrecognized command is ignored.
2651 */
2652 }
Bram Moolenaar70b2a562012-01-10 22:26:17 +01002653 if (inAtomic && do_update)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002654 {
2655 needupdate = 1;
Bram Moolenaar70b2a562012-01-10 22:26:17 +01002656 do_update = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002657 }
2658
Bram Moolenaar009b2592004-10-24 19:18:58 +00002659 /*
2660 * Is this needed? I moved the netbeans_Xt_connect() later during startup
2661 * and it may no longer be necessary. If its not needed then needupdate
Bram Moolenaar70b2a562012-01-10 22:26:17 +01002662 * and do_update can also be removed.
Bram Moolenaar009b2592004-10-24 19:18:58 +00002663 */
Bram Moolenaar70b2a562012-01-10 22:26:17 +01002664 if (buf != NULL && buf->initDone && do_update)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002665 {
2666 update_screen(NOT_VALID);
2667 setcursor();
Bram Moolenaar96bcc5e2011-04-01 15:33:59 +02002668 cursor_on();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002669 out_flush();
Bram Moolenaar67c53842010-05-22 18:28:27 +02002670#ifdef FEAT_GUI
Bram Moolenaard54a6882010-08-09 22:49:00 +02002671 if (gui.in_use)
2672 {
2673 gui_update_cursor(TRUE, FALSE);
2674 gui_mch_flush();
2675 }
Bram Moolenaar67c53842010-05-22 18:28:27 +02002676#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002677 /* Quit a hit-return or more prompt. */
2678 if (State == HITRETURN || State == ASKMORE)
2679 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002680#ifdef FEAT_GUI_GTK
Bram Moolenaard54a6882010-08-09 22:49:00 +02002681 if (gui.in_use && gtk_main_level() > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002682 gtk_main_quit();
2683#endif
2684 }
2685 }
2686
2687 return retval;
2688}
2689
2690
2691/*
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002692 * If "buf" is not the current buffer try changing to a window that edits this
2693 * buffer. If there is no such window then close the current buffer and set
2694 * the current buffer as "buf".
2695 */
2696 static void
Bram Moolenaar5eaf8722008-01-05 17:07:13 +00002697nb_set_curbuf(buf_T *buf)
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002698{
Bram Moolenaar404c9422015-03-14 15:35:52 +01002699 if (curbuf != buf) {
2700 if (buf_jump_open_win(buf) != NULL)
2701 return;
2702# ifdef FEAT_WINDOWS
2703 if ((swb_flags & SWB_USETAB) && buf_jump_open_tab(buf) != NULL)
2704 return;
2705# endif
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002706 set_curbuf(buf, DOBUF_GOTO);
Bram Moolenaar404c9422015-03-14 15:35:52 +01002707 }
Bram Moolenaar8b6144b2006-02-08 09:20:24 +00002708}
2709
2710/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002711 * Process a vim colon command.
2712 */
2713 static void
2714coloncmd(char *cmd, ...)
2715{
2716 char buf[1024];
2717 va_list ap;
2718
2719 va_start(ap, cmd);
Bram Moolenaar0dc79e82009-06-24 14:50:12 +00002720 vim_vsnprintf(buf, sizeof(buf), cmd, ap, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002721 va_end(ap);
2722
2723 nbdebug((" COLONCMD %s\n", buf));
2724
2725/* ALT_INPUT_LOCK_ON; */
2726 do_cmdline((char_u *)buf, NULL, NULL, DOCMD_NOWAIT | DOCMD_KEYTYPED);
2727/* ALT_INPUT_LOCK_OFF; */
2728
2729 setcursor(); /* restore the cursor position */
2730 out_flush(); /* make sure output has been written */
2731
Bram Moolenaar67c53842010-05-22 18:28:27 +02002732#ifdef FEAT_GUI
Bram Moolenaard54a6882010-08-09 22:49:00 +02002733 if (gui.in_use)
2734 {
2735 gui_update_cursor(TRUE, FALSE);
2736 gui_mch_flush();
2737 }
Bram Moolenaar67c53842010-05-22 18:28:27 +02002738#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002739}
2740
2741
2742/*
Bram Moolenaar009b2592004-10-24 19:18:58 +00002743 * Parse the specialKeys argument and issue the appropriate map commands.
2744 */
2745 static void
2746special_keys(char_u *args)
2747{
2748 char *save_str = nb_unquote(args, NULL);
2749 char *tok = strtok(save_str, " ");
2750 char *sep;
2751 char keybuf[64];
2752 char cmdbuf[256];
2753
2754 while (tok != NULL)
2755 {
2756 int i = 0;
2757
2758 if ((sep = strchr(tok, '-')) != NULL)
2759 {
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00002760 *sep = NUL;
Bram Moolenaar009b2592004-10-24 19:18:58 +00002761 while (*tok)
2762 {
2763 switch (*tok)
2764 {
2765 case 'A':
2766 case 'M':
2767 case 'C':
2768 case 'S':
2769 keybuf[i++] = *tok;
2770 keybuf[i++] = '-';
2771 break;
2772 }
2773 tok++;
2774 }
2775 tok++;
2776 }
2777
2778 strcpy(&keybuf[i], tok);
Bram Moolenaar9c13b352005-05-19 20:53:52 +00002779 vim_snprintf(cmdbuf, sizeof(cmdbuf),
2780 "<silent><%s> :nbkey %s<CR>", keybuf, keybuf);
Bram Moolenaar009b2592004-10-24 19:18:58 +00002781 do_map(0, (char_u *)cmdbuf, NORMAL, FALSE);
2782 tok = strtok(NULL, " ");
2783 }
2784 vim_free(save_str);
2785}
2786
Bram Moolenaarb26e6322010-05-22 21:34:09 +02002787 void
2788ex_nbclose(eap)
2789 exarg_T *eap UNUSED;
2790{
2791 netbeans_close();
2792}
Bram Moolenaar009b2592004-10-24 19:18:58 +00002793
2794 void
2795ex_nbkey(eap)
2796 exarg_T *eap;
2797{
Bram Moolenaar8065d7f2010-01-19 15:13:14 +01002798 (void)netbeans_keystring(eap->arg);
Bram Moolenaar009b2592004-10-24 19:18:58 +00002799}
2800
Bram Moolenaarb26e6322010-05-22 21:34:09 +02002801 void
2802ex_nbstart(eap)
2803 exarg_T *eap;
2804{
Bram Moolenaarc2a406b2010-09-30 21:03:26 +02002805#ifdef FEAT_GUI
2806# if !defined(FEAT_GUI_X11) && !defined(FEAT_GUI_GTK) \
Bram Moolenaar7ad7d012010-11-16 15:49:02 +01002807 && !defined(FEAT_GUI_W32)
Bram Moolenaarc2a406b2010-09-30 21:03:26 +02002808 if (gui.in_use)
2809 {
Bram Moolenaar7ad7d012010-11-16 15:49:02 +01002810 EMSG(_("E838: netbeans is not supported with this GUI"));
2811 return;
Bram Moolenaarc2a406b2010-09-30 21:03:26 +02002812 }
2813# endif
2814#endif
Bram Moolenaarb26e6322010-05-22 21:34:09 +02002815 netbeans_open((char *)eap->arg, FALSE);
2816}
Bram Moolenaar009b2592004-10-24 19:18:58 +00002817
2818/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002819 * Initialize highlights and signs for use by netbeans (mostly obsolete)
2820 */
2821 static void
2822nb_init_graphics(void)
2823{
2824 static int did_init = FALSE;
2825
2826 if (!did_init)
2827 {
Bram Moolenaar67c53842010-05-22 18:28:27 +02002828 coloncmd(":highlight NBGuarded guibg=Cyan guifg=Black"
2829 " ctermbg=LightCyan ctermfg=Black");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002830 coloncmd(":sign define %d linehl=NBGuarded", GUARDED);
2831
2832 did_init = TRUE;
2833 }
2834}
2835
2836/*
Bram Moolenaar8065d7f2010-01-19 15:13:14 +01002837 * Convert key to netbeans name. This uses the global "mod_mask".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002838 */
2839 static void
2840netbeans_keyname(int key, char *buf)
2841{
2842 char *name = 0;
2843 char namebuf[2];
2844 int ctrl = 0;
2845 int shift = 0;
2846 int alt = 0;
2847
2848 if (mod_mask & MOD_MASK_CTRL)
2849 ctrl = 1;
2850 if (mod_mask & MOD_MASK_SHIFT)
2851 shift = 1;
2852 if (mod_mask & MOD_MASK_ALT)
2853 alt = 1;
2854
2855
2856 switch (key)
2857 {
2858 case K_F1: name = "F1"; break;
2859 case K_S_F1: name = "F1"; shift = 1; break;
2860 case K_F2: name = "F2"; break;
2861 case K_S_F2: name = "F2"; shift = 1; break;
2862 case K_F3: name = "F3"; break;
2863 case K_S_F3: name = "F3"; shift = 1; break;
2864 case K_F4: name = "F4"; break;
2865 case K_S_F4: name = "F4"; shift = 1; break;
2866 case K_F5: name = "F5"; break;
2867 case K_S_F5: name = "F5"; shift = 1; break;
2868 case K_F6: name = "F6"; break;
2869 case K_S_F6: name = "F6"; shift = 1; break;
2870 case K_F7: name = "F7"; break;
2871 case K_S_F7: name = "F7"; shift = 1; break;
2872 case K_F8: name = "F8"; break;
2873 case K_S_F8: name = "F8"; shift = 1; break;
2874 case K_F9: name = "F9"; break;
2875 case K_S_F9: name = "F9"; shift = 1; break;
2876 case K_F10: name = "F10"; break;
2877 case K_S_F10: name = "F10"; shift = 1; break;
2878 case K_F11: name = "F11"; break;
2879 case K_S_F11: name = "F11"; shift = 1; break;
2880 case K_F12: name = "F12"; break;
2881 case K_S_F12: name = "F12"; shift = 1; break;
2882 default:
2883 if (key >= ' ' && key <= '~')
2884 {
2885 /* Allow ASCII characters. */
2886 name = namebuf;
2887 namebuf[0] = key;
2888 namebuf[1] = NUL;
2889 }
2890 else
2891 name = "X";
2892 break;
2893 }
2894
2895 buf[0] = '\0';
2896 if (ctrl)
2897 strcat(buf, "C");
2898 if (shift)
2899 strcat(buf, "S");
2900 if (alt)
2901 strcat(buf, "M"); /* META */
2902 if (ctrl || shift || alt)
2903 strcat(buf, "-");
2904 strcat(buf, name);
2905}
2906
Bram Moolenaar67c53842010-05-22 18:28:27 +02002907#if defined(FEAT_BEVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002908/*
2909 * Function to be called for balloon evaluation. Grabs the text under the
2910 * cursor and sends it to the debugger for evaluation. The debugger should
2911 * respond with a showBalloon command when there is a useful result.
2912 */
Bram Moolenaard62bec82005-03-07 22:56:57 +00002913 void
Bram Moolenaar071d4272004-06-13 20:20:40 +00002914netbeans_beval_cb(
2915 BalloonEval *beval,
Bram Moolenaarb85cb212009-05-17 14:24:23 +00002916 int state UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002917{
Bram Moolenaard62bec82005-03-07 22:56:57 +00002918 win_T *wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002919 char_u *text;
Bram Moolenaard62bec82005-03-07 22:56:57 +00002920 linenr_T lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002921 int col;
Bram Moolenaard9462e32011-04-11 21:35:11 +02002922 char *buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002923 char_u *p;
2924
2925 /* Don't do anything when 'ballooneval' is off, messages scrolled the
2926 * windows up or we have no connection. */
Bram Moolenaarb26e6322010-05-22 21:34:09 +02002927 if (!p_beval || msg_scrolled > 0 || !NETBEANS_OPEN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002928 return;
2929
Bram Moolenaard62bec82005-03-07 22:56:57 +00002930 if (get_beval_info(beval, TRUE, &wp, &lnum, &text, &col) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002931 {
2932 /* Send debugger request. Only when the text is of reasonable
2933 * length. */
2934 if (text != NULL && text[0] != NUL && STRLEN(text) < MAXPATHL)
2935 {
Bram Moolenaard9462e32011-04-11 21:35:11 +02002936 buf = (char *)alloc(MAXPATHL * 2 + 25);
2937 if (buf != NULL)
Bram Moolenaar009b2592004-10-24 19:18:58 +00002938 {
Bram Moolenaard9462e32011-04-11 21:35:11 +02002939 p = nb_quote(text);
2940 if (p != NULL)
2941 {
2942 vim_snprintf(buf, MAXPATHL * 2 + 25,
2943 "0:balloonText=%d \"%s\"\n", r_cmdno, p);
2944 vim_free(p);
2945 }
2946 nbdebug(("EVT: %s", buf));
2947 nb_send(buf, "netbeans_beval_cb");
2948 vim_free(buf);
Bram Moolenaar009b2592004-10-24 19:18:58 +00002949 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002950 }
2951 vim_free(text);
2952 }
2953}
2954#endif
2955
2956/*
Bram Moolenaarb26e6322010-05-22 21:34:09 +02002957 * Return TRUE when the netbeans connection is closed.
2958 */
2959 int
2960netbeans_active(void)
2961{
2962 return NETBEANS_OPEN;
2963}
2964
2965/*
Bram Moolenaar67c53842010-05-22 18:28:27 +02002966 * Return netbeans file descriptor.
2967 */
2968 int
Bram Moolenaarb26e6322010-05-22 21:34:09 +02002969netbeans_filedesc(void)
Bram Moolenaar67c53842010-05-22 18:28:27 +02002970{
Bram Moolenaarb26e6322010-05-22 21:34:09 +02002971 return nbsock;
Bram Moolenaar67c53842010-05-22 18:28:27 +02002972}
2973
2974#if defined(FEAT_GUI) || defined(PROTO)
2975/*
2976 * Register our file descriptor with the gui event handling system.
2977 */
2978 void
2979netbeans_gui_register(void)
2980{
Bram Moolenaarb26e6322010-05-22 21:34:09 +02002981 if (!NB_HAS_GUI || !NETBEANS_OPEN)
Bram Moolenaar67c53842010-05-22 18:28:27 +02002982 return;
2983
Bram Moolenaar173c9852010-09-29 17:27:01 +02002984# ifdef FEAT_GUI_X11
Bram Moolenaarb26e6322010-05-22 21:34:09 +02002985 /* tell notifier we are interested in being called
2986 * when there is input on the editor connection socket
2987 */
2988 if (inputHandler == (XtInputId)NULL)
2989 inputHandler = XtAppAddInput((XtAppContext)app_context, nbsock,
2990 (XtPointer)(XtInputReadMask + XtInputExceptMask),
2991 messageFromNetbeans, NULL);
Bram Moolenaar67c53842010-05-22 18:28:27 +02002992# else
2993# ifdef FEAT_GUI_GTK
Bram Moolenaarb26e6322010-05-22 21:34:09 +02002994 /*
2995 * Tell gdk we are interested in being called when there
2996 * is input on the editor connection socket
2997 */
2998 if (inputHandler == 0)
2999 inputHandler = gdk_input_add((gint)nbsock, (GdkInputCondition)
3000 ((int)GDK_INPUT_READ + (int)GDK_INPUT_EXCEPTION),
3001 messageFromNetbeans, NULL);
Bram Moolenaar67c53842010-05-22 18:28:27 +02003002# else
3003# ifdef FEAT_GUI_W32
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003004 /*
3005 * Tell Windows we are interested in receiving message when there
3006 * is input on the editor connection socket
3007 */
3008 if (inputHandler == -1)
3009 inputHandler = WSAAsyncSelect(nbsock, s_hwnd, WM_NETBEANS, FD_READ);
Bram Moolenaar67c53842010-05-22 18:28:27 +02003010# endif
3011# endif
3012# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02003013
3014# ifdef FEAT_BEVAL
3015 bevalServers |= BEVAL_NETBEANS;
3016# endif
3017}
3018#endif
3019
3020/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003021 * Tell netbeans that the window was opened, ready for commands.
3022 */
3023 void
Bram Moolenaarf506c5b2010-06-22 06:28:58 +02003024netbeans_open(char *params, int doabort)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003025{
3026 char *cmd = "0:startupDone=0\n";
3027
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003028 if (NETBEANS_OPEN)
3029 {
3030 EMSG(_("E511: netbeans already connected"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003031 return;
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003032 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003033
Bram Moolenaarf506c5b2010-06-22 06:28:58 +02003034 if (netbeans_connect(params, doabort) != OK)
Bram Moolenaar67c53842010-05-22 18:28:27 +02003035 return;
3036#ifdef FEAT_GUI
3037 netbeans_gui_register();
Bram Moolenaard62bec82005-03-07 22:56:57 +00003038#endif
3039
Bram Moolenaar071d4272004-06-13 20:20:40 +00003040 nbdebug(("EVT: %s", cmd));
3041 nb_send(cmd, "netbeans_startup_done");
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003042
3043 /* update the screen after having added the gutter */
3044 changed_window_setting();
3045 update_screen(CLEAR);
3046 setcursor();
Bram Moolenaar96bcc5e2011-04-01 15:33:59 +02003047 cursor_on();
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003048 out_flush();
3049#ifdef FEAT_GUI
Bram Moolenaard54a6882010-08-09 22:49:00 +02003050 if (gui.in_use)
3051 {
3052 gui_update_cursor(TRUE, FALSE);
3053 gui_mch_flush();
3054 }
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003055#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003056}
3057
Bram Moolenaar009b2592004-10-24 19:18:58 +00003058/*
3059 * Tell netbeans that we're exiting. This should be called right
3060 * before calling exit.
3061 */
3062 void
3063netbeans_send_disconnect()
3064{
3065 char buf[128];
3066
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003067 if (NETBEANS_OPEN)
Bram Moolenaar009b2592004-10-24 19:18:58 +00003068 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00003069 sprintf(buf, "0:disconnect=%d\n", r_cmdno);
Bram Moolenaar009b2592004-10-24 19:18:58 +00003070 nbdebug(("EVT: %s", buf));
3071 nb_send(buf, "netbeans_disconnect");
3072 }
3073}
3074
Bram Moolenaar173c9852010-09-29 17:27:01 +02003075#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_W32) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003076/*
3077 * Tell netbeans that the window was moved or resized.
3078 */
3079 void
3080netbeans_frame_moved(int new_x, int new_y)
3081{
3082 char buf[128];
3083
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003084 if (!NETBEANS_OPEN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003085 return;
3086
3087 sprintf(buf, "0:geometry=%d %d %d %d %d\n",
Bram Moolenaar89d40322006-08-29 15:30:07 +00003088 r_cmdno, (int)Columns, (int)Rows, new_x, new_y);
Bram Moolenaar009b2592004-10-24 19:18:58 +00003089 /*nbdebug(("EVT: %s", buf)); happens too many times during a move */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003090 nb_send(buf, "netbeans_frame_moved");
3091}
3092#endif
3093
3094/*
Bram Moolenaar009b2592004-10-24 19:18:58 +00003095 * Tell netbeans the user opened or activated a file.
3096 */
3097 void
3098netbeans_file_activated(buf_T *bufp)
3099{
3100 int bufno = nb_getbufno(bufp);
3101 nbbuf_T *bp = nb_get_buf(bufno);
3102 char buffer[2*MAXPATHL];
3103 char_u *q;
3104
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003105 if (!NETBEANS_OPEN || !bufp->b_netbeans_file || dosetvisible)
Bram Moolenaar009b2592004-10-24 19:18:58 +00003106 return;
3107
3108 q = nb_quote(bufp->b_ffname);
Bram Moolenaareb3593b2006-04-22 22:33:57 +00003109 if (q == NULL || bp == NULL)
Bram Moolenaar009b2592004-10-24 19:18:58 +00003110 return;
3111
Bram Moolenaar9c13b352005-05-19 20:53:52 +00003112 vim_snprintf(buffer, sizeof(buffer), "%d:fileOpened=%d \"%s\" %s %s\n",
Bram Moolenaar009b2592004-10-24 19:18:58 +00003113 bufno,
3114 bufno,
3115 (char *)q,
3116 "T", /* open in NetBeans */
3117 "F"); /* modified */
3118
3119 vim_free(q);
3120 nbdebug(("EVT: %s", buffer));
3121
3122 nb_send(buffer, "netbeans_file_opened");
3123}
3124
3125/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003126 * Tell netbeans the user opened a file.
3127 */
3128 void
Bram Moolenaar009b2592004-10-24 19:18:58 +00003129netbeans_file_opened(buf_T *bufp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003130{
Bram Moolenaar009b2592004-10-24 19:18:58 +00003131 int bufno = nb_getbufno(bufp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003132 char buffer[2*MAXPATHL];
3133 char_u *q;
Bram Moolenaar009b2592004-10-24 19:18:58 +00003134 nbbuf_T *bp = nb_get_buf(nb_getbufno(bufp));
3135 int bnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003136
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003137 if (!NETBEANS_OPEN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003138 return;
3139
Bram Moolenaar009b2592004-10-24 19:18:58 +00003140 q = nb_quote(bufp->b_ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003141 if (q == NULL)
3142 return;
Bram Moolenaar009b2592004-10-24 19:18:58 +00003143 if (bp != NULL)
3144 bnum = bufno;
3145 else
3146 bnum = 0;
3147
Bram Moolenaar9c13b352005-05-19 20:53:52 +00003148 vim_snprintf(buffer, sizeof(buffer), "%d:fileOpened=%d \"%s\" %s %s\n",
Bram Moolenaar009b2592004-10-24 19:18:58 +00003149 bnum,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003150 0,
3151 (char *)q,
3152 "T", /* open in NetBeans */
3153 "F"); /* modified */
3154
3155 vim_free(q);
3156 nbdebug(("EVT: %s", buffer));
3157
3158 nb_send(buffer, "netbeans_file_opened");
Bram Moolenaar009b2592004-10-24 19:18:58 +00003159 if (p_acd && vim_chdirfile(bufp->b_ffname) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003160 shorten_fnames(TRUE);
3161}
3162
3163/*
Bram Moolenaard7f8f5c2009-01-06 15:14:30 +00003164 * Tell netbeans that a file was deleted or wiped out.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003165 */
3166 void
Bram Moolenaard7f8f5c2009-01-06 15:14:30 +00003167netbeans_file_killed(buf_T *bufp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003168{
3169 int bufno = nb_getbufno(bufp);
3170 nbbuf_T *nbbuf = nb_get_buf(bufno);
3171 char buffer[2*MAXPATHL];
3172
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003173 if (!NETBEANS_OPEN || bufno == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003174 return;
3175
Bram Moolenaard7f8f5c2009-01-06 15:14:30 +00003176 nbdebug(("netbeans_file_killed:\n"));
3177 nbdebug((" Killing bufno: %d", bufno));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003178
Bram Moolenaar89d40322006-08-29 15:30:07 +00003179 sprintf(buffer, "%d:killed=%d\n", bufno, r_cmdno);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003180
3181 nbdebug(("EVT: %s", buffer));
3182
Bram Moolenaard7f8f5c2009-01-06 15:14:30 +00003183 nb_send(buffer, "netbeans_file_killed");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003184
3185 if (nbbuf != NULL)
3186 nbbuf->bufp = NULL;
3187}
3188
3189/*
3190 * Get a pointer to the Netbeans buffer for Vim buffer "bufp".
3191 * Return NULL if there is no such buffer or changes are not to be reported.
3192 * Otherwise store the buffer number in "*bufnop".
3193 */
3194 static nbbuf_T *
3195nb_bufp2nbbuf_fire(buf_T *bufp, int *bufnop)
3196{
3197 int bufno;
3198 nbbuf_T *nbbuf;
3199
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003200 if (!NETBEANS_OPEN || !netbeansFireChanges)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003201 return NULL; /* changes are not reported at all */
3202
3203 bufno = nb_getbufno(bufp);
3204 if (bufno <= 0)
3205 return NULL; /* file is not known to NetBeans */
3206
3207 nbbuf = nb_get_buf(bufno);
3208 if (nbbuf != NULL && !nbbuf->fireChanges)
3209 return NULL; /* changes in this buffer are not reported */
3210
3211 *bufnop = bufno;
3212 return nbbuf;
3213}
3214
3215/*
3216 * Tell netbeans the user inserted some text.
3217 */
3218 void
3219netbeans_inserted(
3220 buf_T *bufp,
3221 linenr_T linenr,
3222 colnr_T col,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003223 char_u *txt,
3224 int newlen)
3225{
3226 char_u *buf;
3227 int bufno;
3228 nbbuf_T *nbbuf;
3229 pos_T pos;
3230 long off;
3231 char_u *p;
3232 char_u *newtxt;
3233
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003234 if (!NETBEANS_OPEN)
3235 return;
3236
Bram Moolenaar071d4272004-06-13 20:20:40 +00003237 nbbuf = nb_bufp2nbbuf_fire(bufp, &bufno);
3238 if (nbbuf == NULL)
3239 return;
3240
Bram Moolenaar009b2592004-10-24 19:18:58 +00003241 /* Don't mark as modified for initial read */
3242 if (nbbuf->insertDone)
3243 nbbuf->modified = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003244
3245 pos.lnum = linenr;
3246 pos.col = col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003247 off = pos2off(bufp, &pos);
3248
Bram Moolenaar071d4272004-06-13 20:20:40 +00003249 /* send the "insert" EVT */
3250 newtxt = alloc(newlen + 1);
Bram Moolenaarb6356332005-07-18 21:40:44 +00003251 vim_strncpy(newtxt, txt, newlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003252 p = nb_quote(newtxt);
3253 if (p != NULL)
3254 {
Bram Moolenaar009b2592004-10-24 19:18:58 +00003255 buf = alloc(128 + 2*newlen);
Bram Moolenaar89d40322006-08-29 15:30:07 +00003256 sprintf((char *)buf, "%d:insert=%d %ld \"%s\"\n",
3257 bufno, r_cmdno, off, p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003258 nbdebug(("EVT: %s", buf));
3259 nb_send((char *)buf, "netbeans_inserted");
Bram Moolenaar009b2592004-10-24 19:18:58 +00003260 vim_free(p);
3261 vim_free(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003262 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003263 vim_free(newtxt);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003264}
3265
3266/*
3267 * Tell netbeans some bytes have been removed.
3268 */
3269 void
3270netbeans_removed(
3271 buf_T *bufp,
3272 linenr_T linenr,
3273 colnr_T col,
3274 long len)
3275{
3276 char_u buf[128];
3277 int bufno;
3278 nbbuf_T *nbbuf;
3279 pos_T pos;
3280 long off;
3281
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003282 if (!NETBEANS_OPEN)
3283 return;
3284
Bram Moolenaar071d4272004-06-13 20:20:40 +00003285 nbbuf = nb_bufp2nbbuf_fire(bufp, &bufno);
3286 if (nbbuf == NULL)
3287 return;
3288
3289 if (len < 0)
3290 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00003291 nbdebug(("Negative len %ld in netbeans_removed()!\n", len));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003292 return;
3293 }
3294
3295 nbbuf->modified = 1;
3296
3297 pos.lnum = linenr;
3298 pos.col = col;
3299
3300 off = pos2off(bufp, &pos);
3301
Bram Moolenaar89d40322006-08-29 15:30:07 +00003302 sprintf((char *)buf, "%d:remove=%d %ld %ld\n", bufno, r_cmdno, off, len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003303 nbdebug(("EVT: %s", buf));
3304 nb_send((char *)buf, "netbeans_removed");
3305}
3306
3307/*
Bram Moolenaar2660c0e2010-01-19 14:59:56 +01003308 * Send netbeans an unmodified command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003309 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003310 void
Bram Moolenaarb85cb212009-05-17 14:24:23 +00003311netbeans_unmodified(buf_T *bufp UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003312{
Bram Moolenaar09092152010-08-08 16:38:42 +02003313 /* This is a no-op, because NetBeans considers a buffer modified
Bram Moolenaar071d4272004-06-13 20:20:40 +00003314 * even when all changes have been undone. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003315}
3316
3317/*
3318 * Send a button release event back to netbeans. Its up to netbeans
3319 * to decide what to do (if anything) with this event.
3320 */
3321 void
3322netbeans_button_release(int button)
3323{
3324 char buf[128];
3325 int bufno;
3326
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003327 if (!NETBEANS_OPEN)
3328 return;
3329
Bram Moolenaar071d4272004-06-13 20:20:40 +00003330 bufno = nb_getbufno(curbuf);
3331
3332 if (bufno >= 0 && curwin != NULL && curwin->w_buffer == curbuf)
3333 {
Bram Moolenaar64486672010-05-16 15:46:46 +02003334 int col = mouse_col - W_WINCOL(curwin)
Bram Moolenaar67c53842010-05-22 18:28:27 +02003335 - ((curwin->w_p_nu || curwin->w_p_rnu) ? 9 : 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003336 long off = pos2off(curbuf, &curwin->w_cursor);
3337
3338 /* sync the cursor position */
Bram Moolenaar89d40322006-08-29 15:30:07 +00003339 sprintf(buf, "%d:newDotAndMark=%d %ld %ld\n", bufno, r_cmdno, off, off);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003340 nbdebug(("EVT: %s", buf));
3341 nb_send(buf, "netbeans_button_release[newDotAndMark]");
3342
Bram Moolenaar89d40322006-08-29 15:30:07 +00003343 sprintf(buf, "%d:buttonRelease=%d %d %ld %d\n", bufno, r_cmdno,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003344 button, (long)curwin->w_cursor.lnum, col);
3345 nbdebug(("EVT: %s", buf));
3346 nb_send(buf, "netbeans_button_release");
3347 }
3348}
3349
3350
3351/*
Bram Moolenaar143c38c2007-05-10 16:41:10 +00003352 * Send a keypress event back to netbeans. This usually simulates some
Bram Moolenaar009b2592004-10-24 19:18:58 +00003353 * kind of function key press. This function operates on a key code.
Bram Moolenaar8065d7f2010-01-19 15:13:14 +01003354 * Return TRUE when the key was sent, FALSE when the command has been
3355 * postponed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003356 */
Bram Moolenaar8065d7f2010-01-19 15:13:14 +01003357 int
Bram Moolenaar071d4272004-06-13 20:20:40 +00003358netbeans_keycommand(int key)
3359{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003360 char keyName[60];
Bram Moolenaar009b2592004-10-24 19:18:58 +00003361
3362 netbeans_keyname(key, keyName);
Bram Moolenaar8065d7f2010-01-19 15:13:14 +01003363 return netbeans_keystring((char_u *)keyName);
Bram Moolenaar009b2592004-10-24 19:18:58 +00003364}
3365
3366
3367/*
Bram Moolenaar143c38c2007-05-10 16:41:10 +00003368 * Send a keypress event back to netbeans. This usually simulates some
Bram Moolenaar009b2592004-10-24 19:18:58 +00003369 * kind of function key press. This function operates on a key string.
Bram Moolenaar8065d7f2010-01-19 15:13:14 +01003370 * Return TRUE when the key was sent, FALSE when the command has been
3371 * postponed.
Bram Moolenaar009b2592004-10-24 19:18:58 +00003372 */
Bram Moolenaar8065d7f2010-01-19 15:13:14 +01003373 static int
3374netbeans_keystring(char_u *keyName)
Bram Moolenaar009b2592004-10-24 19:18:58 +00003375{
3376 char buf[2*MAXPATHL];
3377 int bufno = nb_getbufno(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003378 long off;
3379 char_u *q;
3380
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003381 if (!NETBEANS_OPEN)
Bram Moolenaar8065d7f2010-01-19 15:13:14 +01003382 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003383
Bram Moolenaar071d4272004-06-13 20:20:40 +00003384 if (bufno == -1)
3385 {
3386 nbdebug(("got keycommand for non-NetBeans buffer, opening...\n"));
3387 q = curbuf->b_ffname == NULL ? (char_u *)""
3388 : nb_quote(curbuf->b_ffname);
3389 if (q == NULL)
Bram Moolenaar8065d7f2010-01-19 15:13:14 +01003390 return TRUE;
Bram Moolenaar9c13b352005-05-19 20:53:52 +00003391 vim_snprintf(buf, sizeof(buf), "0:fileOpened=%d \"%s\" %s %s\n", 0,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003392 q,
3393 "T", /* open in NetBeans */
3394 "F"); /* modified */
3395 if (curbuf->b_ffname != NULL)
3396 vim_free(q);
3397 nbdebug(("EVT: %s", buf));
3398 nb_send(buf, "netbeans_keycommand");
3399
Bram Moolenaar8065d7f2010-01-19 15:13:14 +01003400 postpone_keycommand(keyName);
3401 return FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003402 }
3403
3404 /* sync the cursor position */
3405 off = pos2off(curbuf, &curwin->w_cursor);
Bram Moolenaar89d40322006-08-29 15:30:07 +00003406 sprintf(buf, "%d:newDotAndMark=%d %ld %ld\n", bufno, r_cmdno, off, off);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003407 nbdebug(("EVT: %s", buf));
3408 nb_send(buf, "netbeans_keycommand");
3409
3410 /* To work on Win32 you must apply patch to ExtEditor module
3411 * from ExtEdCaret.java.diff - make EVT_newDotAndMark handler
3412 * more synchronous
3413 */
3414
3415 /* now send keyCommand event */
Bram Moolenaar9c13b352005-05-19 20:53:52 +00003416 vim_snprintf(buf, sizeof(buf), "%d:keyCommand=%d \"%s\"\n",
Bram Moolenaar89d40322006-08-29 15:30:07 +00003417 bufno, r_cmdno, keyName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003418 nbdebug(("EVT: %s", buf));
3419 nb_send(buf, "netbeans_keycommand");
3420
3421 /* New: do both at once and include the lnum/col. */
Bram Moolenaar9c13b352005-05-19 20:53:52 +00003422 vim_snprintf(buf, sizeof(buf), "%d:keyAtPos=%d \"%s\" %ld %ld/%ld\n",
Bram Moolenaar89d40322006-08-29 15:30:07 +00003423 bufno, r_cmdno, keyName,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003424 off, (long)curwin->w_cursor.lnum, (long)curwin->w_cursor.col);
3425 nbdebug(("EVT: %s", buf));
3426 nb_send(buf, "netbeans_keycommand");
Bram Moolenaar8065d7f2010-01-19 15:13:14 +01003427 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003428}
3429
3430
3431/*
3432 * Send a save event to netbeans.
3433 */
3434 void
3435netbeans_save_buffer(buf_T *bufp)
3436{
3437 char_u buf[64];
3438 int bufno;
3439 nbbuf_T *nbbuf;
3440
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003441 if (!NETBEANS_OPEN)
3442 return;
3443
Bram Moolenaar071d4272004-06-13 20:20:40 +00003444 nbbuf = nb_bufp2nbbuf_fire(bufp, &bufno);
3445 if (nbbuf == NULL)
3446 return;
3447
3448 nbbuf->modified = 0;
3449
Bram Moolenaar89d40322006-08-29 15:30:07 +00003450 sprintf((char *)buf, "%d:save=%d\n", bufno, r_cmdno);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003451 nbdebug(("EVT: %s", buf));
3452 nb_send((char *)buf, "netbeans_save_buffer");
3453}
3454
3455
3456/*
3457 * Send remove command to netbeans (this command has been turned off).
3458 */
3459 void
3460netbeans_deleted_all_lines(buf_T *bufp)
3461{
3462 char_u buf[64];
3463 int bufno;
3464 nbbuf_T *nbbuf;
3465
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003466 if (!NETBEANS_OPEN)
3467 return;
3468
Bram Moolenaar071d4272004-06-13 20:20:40 +00003469 nbbuf = nb_bufp2nbbuf_fire(bufp, &bufno);
3470 if (nbbuf == NULL)
3471 return;
3472
Bram Moolenaar009b2592004-10-24 19:18:58 +00003473 /* Don't mark as modified for initial read */
3474 if (nbbuf->insertDone)
3475 nbbuf->modified = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003476
Bram Moolenaar89d40322006-08-29 15:30:07 +00003477 sprintf((char *)buf, "%d:remove=%d 0 -1\n", bufno, r_cmdno);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003478 nbdebug(("EVT(suppressed): %s", buf));
3479/* nb_send(buf, "netbeans_deleted_all_lines"); */
3480}
3481
3482
3483/*
3484 * See if the lines are guarded. The top and bot parameters are from
3485 * u_savecommon(), these are the line above the change and the line below the
3486 * change.
3487 */
3488 int
3489netbeans_is_guarded(linenr_T top, linenr_T bot)
3490{
3491 signlist_T *p;
3492 int lnum;
3493
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003494 if (!NETBEANS_OPEN)
3495 return FALSE;
3496
Bram Moolenaar071d4272004-06-13 20:20:40 +00003497 for (p = curbuf->b_signlist; p != NULL; p = p->next)
3498 if (p->id >= GUARDEDOFFSET)
3499 for (lnum = top + 1; lnum < bot; lnum++)
3500 if (lnum == p->lnum)
3501 return TRUE;
3502
3503 return FALSE;
3504}
3505
Bram Moolenaar173c9852010-09-29 17:27:01 +02003506#if defined(FEAT_GUI_X11) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003507/*
3508 * We have multiple signs to draw at the same location. Draw the
3509 * multi-sign indicator instead. This is the Motif version.
3510 */
3511 void
3512netbeans_draw_multisign_indicator(int row)
3513{
3514 int i;
3515 int y;
3516 int x;
3517
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003518 if (!NETBEANS_OPEN)
3519 return;
3520
Bram Moolenaar071d4272004-06-13 20:20:40 +00003521 x = 0;
3522 y = row * gui.char_height + 2;
3523
3524 for (i = 0; i < gui.char_height - 3; i++)
3525 XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+2, y++);
3526
3527 XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+0, y);
3528 XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+2, y);
3529 XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+4, y++);
3530 XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+1, y);
3531 XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+2, y);
3532 XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+3, y++);
3533 XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+2, y);
3534}
Bram Moolenaar173c9852010-09-29 17:27:01 +02003535#endif /* FEAT_GUI_X11 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003536
Bram Moolenaar64404472010-06-26 06:24:45 +02003537#if defined(FEAT_GUI_GTK) && !defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003538/*
3539 * We have multiple signs to draw at the same location. Draw the
3540 * multi-sign indicator instead. This is the GTK/Gnome version.
3541 */
3542 void
3543netbeans_draw_multisign_indicator(int row)
3544{
3545 int i;
3546 int y;
3547 int x;
3548 GdkDrawable *drawable = gui.drawarea->window;
3549
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003550 if (!NETBEANS_OPEN)
3551 return;
3552
Bram Moolenaar071d4272004-06-13 20:20:40 +00003553 x = 0;
3554 y = row * gui.char_height + 2;
3555
3556 for (i = 0; i < gui.char_height - 3; i++)
3557 gdk_draw_point(drawable, gui.text_gc, x+2, y++);
3558
3559 gdk_draw_point(drawable, gui.text_gc, x+0, y);
3560 gdk_draw_point(drawable, gui.text_gc, x+2, y);
3561 gdk_draw_point(drawable, gui.text_gc, x+4, y++);
3562 gdk_draw_point(drawable, gui.text_gc, x+1, y);
3563 gdk_draw_point(drawable, gui.text_gc, x+2, y);
3564 gdk_draw_point(drawable, gui.text_gc, x+3, y++);
3565 gdk_draw_point(drawable, gui.text_gc, x+2, y);
3566}
3567#endif /* FEAT_GUI_GTK */
3568
3569/*
3570 * If the mouse is clicked in the gutter of a line with multiple
3571 * annotations, cycle through the set of signs.
3572 */
3573 void
3574netbeans_gutter_click(linenr_T lnum)
3575{
3576 signlist_T *p;
3577
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003578 if (!NETBEANS_OPEN)
3579 return;
3580
Bram Moolenaar071d4272004-06-13 20:20:40 +00003581 for (p = curbuf->b_signlist; p != NULL; p = p->next)
3582 {
3583 if (p->lnum == lnum && p->next && p->next->lnum == lnum)
3584 {
3585 signlist_T *tail;
3586
3587 /* remove "p" from list, reinsert it at the tail of the sublist */
3588 if (p->prev)
3589 p->prev->next = p->next;
3590 else
3591 curbuf->b_signlist = p->next;
3592 p->next->prev = p->prev;
3593 /* now find end of sublist and insert p */
3594 for (tail = p->next;
3595 tail->next && tail->next->lnum == lnum
3596 && tail->next->id < GUARDEDOFFSET;
3597 tail = tail->next)
3598 ;
3599 /* tail now points to last entry with same lnum (except
3600 * that "guarded" annotations are always last) */
3601 p->next = tail->next;
3602 if (tail->next)
3603 tail->next->prev = p;
3604 p->prev = tail;
3605 tail->next = p;
3606 update_debug_sign(curbuf, lnum);
3607 break;
3608 }
3609 }
3610}
3611
Bram Moolenaar071d4272004-06-13 20:20:40 +00003612/*
Bram Moolenaar2660c0e2010-01-19 14:59:56 +01003613 * Add a sign of the requested type at the requested location.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003614 *
3615 * Reverse engineering:
3616 * Apparently an annotation is defined the first time it is used in a buffer.
3617 * When the same annotation is used in two buffers, the second time we do not
3618 * need to define a new sign name but reuse the existing one. But since the
3619 * ID number used in the second buffer starts counting at one again, a mapping
3620 * is made from the ID specifically for the buffer to the global sign name
3621 * (which is a number).
3622 *
3623 * globalsignmap[] stores the signs that have been defined globally.
3624 * buf->signmapused[] maps buffer-local annotation IDs to an index in
3625 * globalsignmap[].
3626 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003627 static void
3628addsigntype(
3629 nbbuf_T *buf,
3630 int typeNum,
3631 char_u *typeName,
Bram Moolenaarb85cb212009-05-17 14:24:23 +00003632 char_u *tooltip UNUSED,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003633 char_u *glyphFile,
Bram Moolenaar67c53842010-05-22 18:28:27 +02003634 char_u *fg,
3635 char_u *bg)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003636{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003637 int i, j;
Bram Moolenaar67c53842010-05-22 18:28:27 +02003638 int use_fg = (*fg && STRCMP(fg, "none") != 0);
3639 int use_bg = (*bg && STRCMP(bg, "none") != 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003640
3641 for (i = 0; i < globalsignmapused; i++)
3642 if (STRCMP(typeName, globalsignmap[i]) == 0)
3643 break;
3644
3645 if (i == globalsignmapused) /* not found; add it to global map */
3646 {
Bram Moolenaar67c53842010-05-22 18:28:27 +02003647 nbdebug(("DEFINEANNOTYPE(%d,%s,%s,%s,%s,%s)\n",
Bram Moolenaar071d4272004-06-13 20:20:40 +00003648 typeNum, typeName, tooltip, glyphFile, fg, bg));
3649 if (use_fg || use_bg)
3650 {
Bram Moolenaar67c53842010-05-22 18:28:27 +02003651 char fgbuf[2 * (8 + MAX_COLOR_LENGTH) + 1];
3652 char bgbuf[2 * (8 + MAX_COLOR_LENGTH) + 1];
3653 char *ptr;
3654 int value;
3655
3656 value = strtol((char *)fg, &ptr, 10);
3657 if (ptr != (char *)fg)
3658 sprintf(fgbuf, "guifg=#%06x", value & 0xFFFFFF);
3659 else
3660 sprintf(fgbuf, "guifg=%s ctermfg=%s", fg, fg);
3661
3662 value = strtol((char *)bg, &ptr, 10);
3663 if (ptr != (char *)bg)
3664 sprintf(bgbuf, "guibg=#%06x", value & 0xFFFFFF);
3665 else
3666 sprintf(bgbuf, "guibg=%s ctermbg=%s", bg, bg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003667
3668 coloncmd(":highlight NB_%s %s %s", typeName, (use_fg) ? fgbuf : "",
3669 (use_bg) ? bgbuf : "");
3670 if (*glyphFile == NUL)
3671 /* no glyph, line highlighting only */
3672 coloncmd(":sign define %d linehl=NB_%s", i + 1, typeName);
3673 else if (vim_strsize(glyphFile) <= 2)
3674 /* one- or two-character glyph name, use as text glyph with
3675 * texthl */
3676 coloncmd(":sign define %d text=%s texthl=NB_%s", i + 1,
3677 glyphFile, typeName);
3678 else
3679 /* glyph, line highlighting */
3680 coloncmd(":sign define %d icon=%s linehl=NB_%s", i + 1,
3681 glyphFile, typeName);
3682 }
3683 else
3684 /* glyph, no line highlighting */
3685 coloncmd(":sign define %d icon=%s", i + 1, glyphFile);
3686
3687 if (STRCMP(typeName,"CurrentPC") == 0)
3688 curPCtype = typeNum;
3689
3690 if (globalsignmapused == globalsignmaplen)
3691 {
3692 if (globalsignmaplen == 0) /* first allocation */
3693 {
3694 globalsignmaplen = 20;
3695 globalsignmap = (char **)alloc_clear(globalsignmaplen*sizeof(char *));
3696 }
3697 else /* grow it */
3698 {
3699 int incr;
3700 int oldlen = globalsignmaplen;
Bram Moolenaar9abd5c62015-02-10 18:34:01 +01003701 char **t_globalsignmap = globalsignmap;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003702
3703 globalsignmaplen *= 2;
3704 incr = globalsignmaplen - oldlen;
3705 globalsignmap = (char **)vim_realloc(globalsignmap,
3706 globalsignmaplen * sizeof(char *));
Bram Moolenaar9abd5c62015-02-10 18:34:01 +01003707 if (globalsignmap == NULL)
3708 {
3709 vim_free(t_globalsignmap);
3710 globalsignmaplen = 0;
3711 return;
3712 }
Bram Moolenaar7db5fc82010-05-24 11:59:29 +02003713 vim_memset(globalsignmap + oldlen, 0, incr * sizeof(char *));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003714 }
3715 }
3716
3717 globalsignmap[i] = (char *)typeName;
3718 globalsignmapused = i + 1;
3719 }
3720
3721 /* check local map; should *not* be found! */
3722 for (j = 0; j < buf->signmapused; j++)
3723 if (buf->signmap[j] == i + 1)
3724 return;
3725
3726 /* add to local map */
3727 if (buf->signmapused == buf->signmaplen)
3728 {
3729 if (buf->signmaplen == 0) /* first allocation */
3730 {
3731 buf->signmaplen = 5;
Bram Moolenaara9d52e32010-07-31 16:44:19 +02003732 buf->signmap = (int *)alloc_clear(buf->signmaplen * sizeof(int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003733 }
3734 else /* grow it */
3735 {
3736 int incr;
3737 int oldlen = buf->signmaplen;
Bram Moolenaar9abd5c62015-02-10 18:34:01 +01003738 int *t_signmap = buf->signmap;
Bram Moolenaara9d52e32010-07-31 16:44:19 +02003739
Bram Moolenaar071d4272004-06-13 20:20:40 +00003740 buf->signmaplen *= 2;
3741 incr = buf->signmaplen - oldlen;
3742 buf->signmap = (int *)vim_realloc(buf->signmap,
Bram Moolenaara9d52e32010-07-31 16:44:19 +02003743 buf->signmaplen * sizeof(int));
Bram Moolenaar9abd5c62015-02-10 18:34:01 +01003744 if (buf->signmap == NULL)
3745 {
3746 vim_free(t_signmap);
3747 buf->signmaplen = 0;
3748 return;
3749 }
Bram Moolenaara9d52e32010-07-31 16:44:19 +02003750 vim_memset(buf->signmap + oldlen, 0, incr * sizeof(int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003751 }
3752 }
3753
3754 buf->signmap[buf->signmapused++] = i + 1;
3755
3756}
3757
3758
3759/*
3760 * See if we have the requested sign type in the buffer.
3761 */
3762 static int
3763mapsigntype(nbbuf_T *buf, int localsigntype)
3764{
3765 if (--localsigntype >= 0 && localsigntype < buf->signmapused)
3766 return buf->signmap[localsigntype];
3767
3768 return 0;
3769}
3770
3771
3772/*
3773 * Compute length of buffer, don't print anything.
3774 */
3775 static long
3776get_buf_size(buf_T *bufp)
3777{
3778 linenr_T lnum;
3779 long char_count = 0;
3780 int eol_size;
3781 long last_check = 100000L;
3782
3783 if (bufp->b_ml.ml_flags & ML_EMPTY)
3784 return 0;
3785 else
3786 {
3787 if (get_fileformat(bufp) == EOL_DOS)
3788 eol_size = 2;
3789 else
3790 eol_size = 1;
3791 for (lnum = 1; lnum <= bufp->b_ml.ml_line_count; ++lnum)
3792 {
Bram Moolenaarfa68b0f2009-09-11 12:19:51 +00003793 char_count += (long)STRLEN(ml_get_buf(bufp, lnum, FALSE))
3794 + eol_size;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003795 /* Check for a CTRL-C every 100000 characters */
3796 if (char_count > last_check)
3797 {
3798 ui_breakcheck();
3799 if (got_int)
3800 return char_count;
3801 last_check = char_count + 100000L;
3802 }
3803 }
3804 /* Correction for when last line doesn't have an EOL. */
Bram Moolenaar34d72d42015-07-17 14:18:08 +02003805 if (!bufp->b_p_eol && (bufp->b_p_bin || !bufp->b_p_fixeol))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003806 char_count -= eol_size;
3807 }
3808
3809 return char_count;
3810}
3811
3812/*
3813 * Convert character offset to lnum,col
3814 */
3815 static pos_T *
3816off2pos(buf_T *buf, long offset)
3817{
3818 linenr_T lnum;
3819 static pos_T pos;
3820
3821 pos.lnum = 0;
3822 pos.col = 0;
3823#ifdef FEAT_VIRTUALEDIT
3824 pos.coladd = 0;
3825#endif
3826
3827 if (!(buf->b_ml.ml_flags & ML_EMPTY))
3828 {
3829 if ((lnum = ml_find_line_or_offset(buf, (linenr_T)0, &offset)) < 0)
3830 return NULL;
3831 pos.lnum = lnum;
3832 pos.col = offset;
3833 }
3834
3835 return &pos;
3836}
3837
3838/*
3839 * Convert an argument in the form "1234" to an offset and compute the
3840 * lnum/col from it. Convert an argument in the form "123/12" directly to a
3841 * lnum/col.
3842 * "argp" is advanced to after the argument.
3843 * Return a pointer to the position, NULL if something is wrong.
3844 */
3845 static pos_T *
3846get_off_or_lnum(buf_T *buf, char_u **argp)
3847{
3848 static pos_T mypos;
3849 long off;
3850
3851 off = strtol((char *)*argp, (char **)argp, 10);
3852 if (**argp == '/')
3853 {
3854 mypos.lnum = (linenr_T)off;
3855 ++*argp;
3856 mypos.col = strtol((char *)*argp, (char **)argp, 10);
3857#ifdef FEAT_VIRTUALEDIT
3858 mypos.coladd = 0;
3859#endif
3860 return &mypos;
3861 }
3862 return off2pos(buf, off);
3863}
3864
3865
3866/*
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003867 * Convert (lnum,col) to byte offset in the file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003868 */
3869 static long
3870pos2off(buf_T *buf, pos_T *pos)
3871{
3872 long offset = 0;
3873
3874 if (!(buf->b_ml.ml_flags & ML_EMPTY))
3875 {
3876 if ((offset = ml_find_line_or_offset(buf, pos->lnum, 0)) < 0)
3877 return 0;
3878 offset += pos->col;
3879 }
3880
3881 return offset;
3882}
3883
3884
Bram Moolenaar009b2592004-10-24 19:18:58 +00003885/*
3886 * This message is printed after NetBeans opens a new file. Its
3887 * similar to the message readfile() uses, but since NetBeans
3888 * doesn't normally call readfile, we do our own.
3889 */
3890 static void
3891print_read_msg(buf)
3892 nbbuf_T *buf;
3893{
3894 int lnum = buf->bufp->b_ml.ml_line_count;
Bram Moolenaar914703b2010-05-31 21:59:46 +02003895 off_t nchars = buf->bufp->b_orig_size;
Bram Moolenaar009b2592004-10-24 19:18:58 +00003896 char_u c;
3897
3898 msg_add_fname(buf->bufp, buf->bufp->b_ffname);
3899 c = FALSE;
3900
3901 if (buf->bufp->b_p_ro)
3902 {
3903 STRCAT(IObuff, shortmess(SHM_RO) ? _("[RO]") : _("[readonly]"));
3904 c = TRUE;
3905 }
3906 if (!buf->bufp->b_start_eol)
3907 {
Bram Moolenaar67c53842010-05-22 18:28:27 +02003908 STRCAT(IObuff, shortmess(SHM_LAST) ? _("[noeol]")
3909 : _("[Incomplete last line]"));
Bram Moolenaar009b2592004-10-24 19:18:58 +00003910 c = TRUE;
3911 }
3912 msg_add_lines(c, (long)lnum, nchars);
3913
3914 /* Now display it */
3915 vim_free(keep_msg);
3916 keep_msg = NULL;
3917 msg_scrolled_ign = TRUE;
3918 msg_trunc_attr(IObuff, FALSE, 0);
3919 msg_scrolled_ign = FALSE;
3920}
3921
3922
3923/*
Bram Moolenaar67c53842010-05-22 18:28:27 +02003924 * Print a message after NetBeans writes the file. This message should be
3925 * identical to the standard message a non-netbeans user would see when
3926 * writing a file.
Bram Moolenaar009b2592004-10-24 19:18:58 +00003927 */
3928 static void
3929print_save_msg(buf, nchars)
3930 nbbuf_T *buf;
Bram Moolenaar914703b2010-05-31 21:59:46 +02003931 off_t nchars;
Bram Moolenaar009b2592004-10-24 19:18:58 +00003932{
3933 char_u c;
3934 char_u *p;
3935
3936 if (nchars >= 0)
3937 {
Bram Moolenaar67c53842010-05-22 18:28:27 +02003938 /* put fname in IObuff with quotes */
3939 msg_add_fname(buf->bufp, buf->bufp->b_ffname);
Bram Moolenaar009b2592004-10-24 19:18:58 +00003940 c = FALSE;
3941
3942 msg_add_lines(c, buf->bufp->b_ml.ml_line_count,
Bram Moolenaar914703b2010-05-31 21:59:46 +02003943 buf->bufp->b_orig_size);
Bram Moolenaar009b2592004-10-24 19:18:58 +00003944
3945 vim_free(keep_msg);
3946 keep_msg = NULL;
3947 msg_scrolled_ign = TRUE;
3948 p = msg_trunc_attr(IObuff, FALSE, 0);
3949 if ((msg_scrolled && !need_wait_return) || !buf->initDone)
3950 {
3951 /* Need to repeat the message after redrawing when:
3952 * - When reading from stdin (the screen will be cleared next).
3953 * - When restart_edit is set (otherwise there will be a delay
3954 * before redrawing).
3955 * - When the screen was scrolled but there is no wait-return
3956 * prompt. */
Bram Moolenaar030f0df2006-02-21 22:02:53 +00003957 set_keep_msg(p, 0);
Bram Moolenaar009b2592004-10-24 19:18:58 +00003958 }
3959 msg_scrolled_ign = FALSE;
3960 /* add_to_input_buf((char_u *)"\f", 1); */
3961 }
3962 else
3963 {
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02003964 char_u msgbuf[IOSIZE];
Bram Moolenaar009b2592004-10-24 19:18:58 +00003965
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02003966 vim_snprintf((char *)msgbuf, IOSIZE,
3967 _("E505: %s is read-only (add ! to override)"), IObuff);
3968 nbdebug((" %s\n", msgbuf));
3969 emsg(msgbuf);
Bram Moolenaar009b2592004-10-24 19:18:58 +00003970 }
3971}
3972
Bram Moolenaar071d4272004-06-13 20:20:40 +00003973#endif /* defined(FEAT_NETBEANS_INTG) */