1 /* vi:set ts=8 sts=4 sw=4:
3 * VIM - Vi IMproved by Bram Moolenaar
4 * Netbeans integration by David Weatherford
5 * Adopted for Win32 by Sergey Khorev
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.
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.
19 #if defined(MSDOS) || defined(MSWIN)
20 # include "vimio.h" /* for mch_open(), must be before vim.h */
25 #if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
27 /* Note: when making changes here also adjust configure.in. */
30 # include <tchar.h> /* for _T definition for TRACEn macros */
33 /* WinSock API is separated from C API, thus we can't use read(), write(),
35 # define sock_errno WSAGetLastError()
36 # define ECONNREFUSED WSAECONNREFUSED
40 # define EINTR WSAEINTR
41 # define sock_write(sd, buf, len) send(sd, buf, len, 0)
42 # define sock_read(sd, buf, len) recv(sd, buf, len, 0)
43 # define sock_close(sd) closesocket(sd)
44 # define sleep(t) Sleep(t*1000) /* WinAPI Sleep() accepts milliseconds */
47 # include <netinet/in.h>
48 # include <sys/socket.h>
52 # define sock_errno errno
53 # define sock_write(sd, buf, len) write(sd, buf, len)
54 # define sock_read(sd, buf, len) read(sd, buf, len)
55 # define sock_close(sd) close(sd)
62 #define GUARDED 10000 /* typenr for "guarded" annotation */
63 #define GUARDEDOFFSET 1000000 /* base for "guarded" sign id's */
65 /* The first implementation (working only with Netbeans) returned "1.1". The
66 * protocol implemented here also supports A-A-P. */
67 static char *ExtEdProtocolVersion
= "2.4";
69 static long pos2off
__ARGS((buf_T
*, pos_T
*));
70 static pos_T
*off2pos
__ARGS((buf_T
*, long));
71 static pos_T
*get_off_or_lnum
__ARGS((buf_T
*buf
, char_u
**argp
));
72 static long get_buf_size
__ARGS((buf_T
*));
73 static void netbeans_keystring
__ARGS((int key
, char *keystr
));
74 static void special_keys
__ARGS((char_u
*args
));
76 static void netbeans_connect
__ARGS((void));
77 static int getConnInfo
__ARGS((char *file
, char **host
, char **port
, char **password
));
79 static void nb_init_graphics
__ARGS((void));
80 static void coloncmd
__ARGS((char *cmd
, ...));
81 static void nb_set_curbuf
__ARGS((buf_T
*buf
));
83 static void messageFromNetbeans
__ARGS((XtPointer
, int *, XtInputId
*));
86 static void messageFromNetbeans
__ARGS((gpointer
, gint
, GdkInputCondition
));
88 static void nb_parse_cmd
__ARGS((char_u
*));
89 static int nb_do_cmd
__ARGS((int, char_u
*, int, int, char_u
*));
90 static void nb_send
__ARGS((char *buf
, char *fun
));
93 typedef __int64 NBSOCK
;
98 static NBSOCK sd
= -1; /* socket fd for Netbeans connection */
100 static XtInputId inputHandler
; /* Cookie for input */
103 static gint inputHandler
; /* Cookie for input */
106 static int inputHandler
= -1; /* simply ret.value of WSAAsyncSelect() */
107 extern HWND s_hwnd
; /* Gvim's Window handle */
109 static int r_cmdno
; /* current command number for reply */
110 static int haveConnection
= FALSE
; /* socket is connected and
111 initialization is done */
112 #ifdef FEAT_GUI_MOTIF
113 static void netbeans_Xt_connect
__ARGS((void *context
));
116 static void netbeans_gtk_connect
__ARGS((void));
119 static void netbeans_w32_connect
__ARGS((void));
122 static int dosetvisible
= FALSE
;
125 * Include the debugging code if wanted.
128 # include "nbdebug.c"
131 /* Connect back to Netbeans process */
132 #ifdef FEAT_GUI_MOTIF
134 netbeans_Xt_connect(void *context
)
139 /* tell notifier we are interested in being called
140 * when there is input on the editor connection socket
142 inputHandler
= XtAppAddInput((XtAppContext
)context
, sd
,
143 (XtPointer
)(XtInputReadMask
+ XtInputExceptMask
),
144 messageFromNetbeans
, NULL
);
149 netbeans_disconnect(void)
151 if (inputHandler
!= (XtInputId
)NULL
)
153 XtRemoveInput(inputHandler
);
154 inputHandler
= (XtInputId
)NULL
;
157 haveConnection
= FALSE
;
159 bevalServers
&= ~BEVAL_NETBEANS
;
162 #endif /* FEAT_MOTIF_GUI */
166 netbeans_gtk_connect(void)
172 * Tell gdk we are interested in being called when there
173 * is input on the editor connection socket
175 inputHandler
= gdk_input_add((gint
)sd
, (GdkInputCondition
)
176 ((int)GDK_INPUT_READ
+ (int)GDK_INPUT_EXCEPTION
),
177 messageFromNetbeans
, NULL
);
182 netbeans_disconnect(void)
184 if (inputHandler
!= 0)
186 gdk_input_remove(inputHandler
);
190 haveConnection
= FALSE
;
192 bevalServers
&= ~BEVAL_NETBEANS
;
195 #endif /* FEAT_GUI_GTK */
197 #if defined(FEAT_GUI_W32) || defined(PROTO)
199 netbeans_w32_connect(void)
205 * Tell Windows we are interested in receiving message when there
206 * is input on the editor connection socket
208 inputHandler
= WSAAsyncSelect(sd
, s_hwnd
, WM_NETBEANS
, FD_READ
);
213 netbeans_disconnect(void)
215 if (inputHandler
== 0)
217 WSAAsyncSelect(sd
, s_hwnd
, 0, 0);
221 haveConnection
= FALSE
;
223 bevalServers
&= ~BEVAL_NETBEANS
;
226 #endif /* FEAT_GUI_W32 */
228 #define NB_DEF_HOST "localhost"
229 #define NB_DEF_ADDR "3219"
230 #define NB_DEF_PASS "changeme"
233 netbeans_connect(void)
236 struct sockaddr_in server
;
237 struct hostent
* host
;
244 struct sockaddr_un server
;
247 char *hostname
= NULL
;
248 char *address
= NULL
;
249 char *password
= NULL
;
253 if (netbeansArg
[3] == '=')
255 /* "-nb=fname": Read info from specified file. */
256 if (getConnInfo(netbeansArg
+ 4, &hostname
, &address
, &password
)
262 if (netbeansArg
[3] == ':')
263 /* "-nb:<host>:<addr>:<password>": get info from argument */
264 arg
= netbeansArg
+ 4;
265 if (arg
== NULL
&& (fname
= getenv("__NETBEANS_CONINFO")) != NULL
)
267 /* "-nb": get info from file specified in environment */
268 if (getConnInfo(fname
, &hostname
, &address
, &password
) == FAIL
)
275 /* "-nb:<host>:<addr>:<password>": get info from argument */
277 address
= strchr(hostname
, ':');
281 password
= strchr(address
, ':');
282 if (password
!= NULL
)
287 /* Get the missing values from the environment. */
288 if (hostname
== NULL
|| *hostname
== '\0')
289 hostname
= getenv("__NETBEANS_HOST");
291 address
= getenv("__NETBEANS_SOCKET");
292 if (password
== NULL
)
293 password
= getenv("__NETBEANS_VIM_PASSWORD");
295 /* Move values to allocated memory. */
296 if (hostname
!= NULL
)
297 hostname
= (char *)vim_strsave((char_u
*)hostname
);
299 address
= (char *)vim_strsave((char_u
*)address
);
300 if (password
!= NULL
)
301 password
= (char *)vim_strsave((char_u
*)password
);
305 /* Use the default when a value is missing. */
306 if (hostname
== NULL
|| *hostname
== '\0')
309 hostname
= (char *)vim_strsave((char_u
*)NB_DEF_HOST
);
311 if (address
== NULL
|| *address
== '\0')
314 address
= (char *)vim_strsave((char_u
*)NB_DEF_ADDR
);
316 if (password
== NULL
|| *password
== '\0')
319 password
= (char *)vim_strsave((char_u
*)NB_DEF_PASS
);
321 if (hostname
== NULL
|| address
== NULL
|| password
== NULL
)
322 goto theend
; /* out of memory */
325 port
= atoi(address
);
327 if ((sd
= (NBSOCK
)socket(AF_INET
, SOCK_STREAM
, 0)) == (NBSOCK
)-1)
329 nbdebug(("error in socket() in netbeans_connect()\n"));
330 PERROR("socket() in netbeans_connect()");
334 /* Get the server internet address and put into addr structure */
335 /* fill in the socket address structure and connect to server */
336 memset((char *)&server
, '\0', sizeof(server
));
337 server
.sin_family
= AF_INET
;
338 server
.sin_port
= htons(port
);
339 if ((host
= gethostbyname(hostname
)) == NULL
)
341 if (mch_access(hostname
, R_OK
) >= 0)
343 /* DEBUG: input file */
344 sd
= mch_open(hostname
, O_RDONLY
, 0);
347 nbdebug(("error in gethostbyname() in netbeans_connect()\n"));
348 PERROR("gethostbyname() in netbeans_connect()");
352 memcpy((char *)&server
.sin_addr
, host
->h_addr
, host
->h_length
);
354 if ((sd
= socket(AF_UNIX
, SOCK_STREAM
, 0)) == -1)
356 nbdebug(("error in socket() in netbeans_connect()\n"));
357 PERROR("socket() in netbeans_connect()");
361 server
.sun_family
= AF_UNIX
;
362 strcpy(server
.sun_path
, address
);
364 /* Connect to server */
365 if (connect(sd
, (struct sockaddr
*)&server
, sizeof(server
)))
367 nbdebug(("netbeans_connect: Connect failed with errno %d\n", sock_errno
));
368 if (sock_errno
== ECONNREFUSED
)
372 if ((sd
= (NBSOCK
)socket(AF_INET
, SOCK_STREAM
, 0)) == (NBSOCK
)-1)
374 nbdebug(("socket()#2 in netbeans_connect()\n"));
375 PERROR("socket()#2 in netbeans_connect()");
379 if ((sd
= socket(AF_UNIX
, SOCK_STREAM
, 0)) == -1)
381 nbdebug(("socket()#2 in netbeans_connect()\n"));
382 PERROR("socket()#2 in netbeans_connect()");
386 if (connect(sd
, (struct sockaddr
*)&server
, sizeof(server
)))
391 && ((sock_errno
== ECONNREFUSED
) || (sock_errno
== EINTR
)))
393 nbdebug(("retrying...\n"));
395 if (connect(sd
, (struct sockaddr
*)&server
,
396 sizeof(server
)) == 0)
404 /* Get here when the server can't be found. */
405 nbdebug(("Cannot connect to Netbeans #2\n"));
406 PERROR(_("Cannot connect to Netbeans #2"));
414 nbdebug(("Cannot connect to Netbeans\n"));
415 PERROR(_("Cannot connect to Netbeans"));
420 vim_snprintf(buf
, sizeof(buf
), "AUTH %s\n", password
);
421 nb_send(buf
, "netbeans_connect");
423 sprintf(buf
, "0:version=0 \"%s\"\n", ExtEdProtocolVersion
);
424 nb_send(buf
, "externaleditor_version");
426 /* nb_init_graphics(); delay until needed */
428 haveConnection
= TRUE
;
438 * Obtain the NetBeans hostname, port address and password from a file.
439 * Return the strings in allocated memory.
440 * Return FAIL if the file could not be read, OK otherwise (no matter what it
444 getConnInfo(char *file
, char **host
, char **port
, char **auth
)
454 * For Unix only accept the file when it's not accessible by others.
455 * The open will then fail if we don't own the file.
457 if (mch_stat(file
, &st
) == 0 && (st
.st_mode
& 0077) != 0)
459 nbdebug(("Wrong access mode for NetBeans connection info file: \"%s\"\n",
461 EMSG2(_("E668: Wrong access mode for NetBeans connection info file: \"%s\""),
467 fp
= mch_fopen(file
, "r");
470 nbdebug(("Cannot open NetBeans connection info file\n"));
471 PERROR("E660: Cannot open NetBeans connection info file");
475 /* Read the file. There should be one of each parameter */
476 while ((lp
= (char_u
*)fgets((char *)buf
, BUFSIZ
, fp
)) != NULL
)
478 if ((nl
= vim_strchr(lp
, '\n')) != NULL
)
479 *nl
= 0; /* strip off the trailing newline */
481 if (STRNCMP(lp
, "host=", 5) == 0)
484 *host
= (char *)vim_strsave(&buf
[5]);
486 else if (STRNCMP(lp
, "port=", 5) == 0)
489 *port
= (char *)vim_strsave(&buf
[5]);
491 else if (STRNCMP(lp
, "auth=", 5) == 0)
494 *auth
= (char *)vim_strsave(&buf
[5]);
506 struct keyqueue
*next
;
507 struct keyqueue
*prev
;
510 typedef struct keyqueue keyQ_T
;
512 static keyQ_T keyHead
; /* dummy node, header for circular queue */
516 * Queue up key commands sent from netbeans.
519 postpone_keycommand(int key
)
523 node
= (keyQ_T
*)alloc(sizeof(keyQ_T
));
525 if (keyHead
.next
== NULL
) /* initialize circular queue */
527 keyHead
.next
= &keyHead
;
528 keyHead
.prev
= &keyHead
;
531 /* insert node at tail of queue */
532 node
->next
= &keyHead
;
533 node
->prev
= keyHead
.prev
;
534 keyHead
.prev
->next
= node
;
541 * Handle any queued-up NetBeans keycommands to be send.
544 handle_key_queue(void)
546 while (keyHead
.next
&& keyHead
.next
!= &keyHead
)
548 /* first, unlink the node */
549 keyQ_T
*node
= keyHead
.next
;
550 keyHead
.next
= node
->next
;
551 node
->next
->prev
= node
->prev
;
553 /* now, send the keycommand */
554 netbeans_keycommand(node
->key
);
556 /* Finally, dispose of the node */
565 struct cmdqueue
*next
;
566 struct cmdqueue
*prev
;
569 typedef struct cmdqueue queue_T
;
571 static queue_T head
; /* dummy node, header for circular queue */
575 * Put the buffer on the work queue; possibly save it to a file as well.
578 save(char_u
*buf
, int len
)
582 node
= (queue_T
*)alloc(sizeof(queue_T
));
584 return; /* out of memory */
585 node
->buffer
= alloc(len
+ 1);
586 if (node
->buffer
== NULL
)
589 return; /* out of memory */
591 mch_memmove(node
->buffer
, buf
, (size_t)len
);
592 node
->buffer
[len
] = NUL
;
594 if (head
.next
== NULL
) /* initialize circular queue */
600 /* insert node at tail of queue */
602 node
->prev
= head
.prev
;
603 head
.prev
->next
= node
;
608 static int outfd
= -2;
610 /* possibly write buffer out to a file */
616 char *file
= getenv("__NETBEANS_SAVE");
620 outfd
= mch_open(file
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0666);
624 write(outfd
, buf
, len
);
631 * While there's still a command in the work queue, parse and execute it.
634 netbeans_parse_messages(void)
639 while (head
.next
!= NULL
&& head
.next
!= &head
)
643 /* Locate the first line in the first buffer. */
644 p
= vim_strchr(node
->buffer
, '\n');
647 /* Command isn't complete. If there is no following buffer,
648 * return (wait for more). If there is another buffer following,
649 * prepend the text to that buffer and delete this one. */
650 if (node
->next
== &head
)
652 p
= alloc((unsigned)(STRLEN(node
->buffer
)
653 + STRLEN(node
->next
->buffer
) + 1));
655 return; /* out of memory */
656 STRCPY(p
, node
->buffer
);
657 STRCAT(p
, node
->next
->buffer
);
658 vim_free(node
->next
->buffer
);
659 node
->next
->buffer
= p
;
661 /* dispose of the node and buffer */
662 head
.next
= node
->next
;
663 node
->next
->prev
= node
->prev
;
664 vim_free(node
->buffer
);
669 /* There is a complete command at the start of the buffer.
670 * Terminate it with a NUL. When no more text is following unlink
671 * the buffer. Do this before executing, because new buffers can
672 * be added while busy handling the command. */
676 head
.next
= node
->next
;
677 node
->next
->prev
= node
->prev
;
680 /* now, parse and execute the commands */
681 nb_parse_cmd(node
->buffer
);
685 /* buffer finished, dispose of the node and buffer */
686 vim_free(node
->buffer
);
691 /* more follows, move to the start */
692 STRMOVE(node
->buffer
, p
);
698 /* Buffer size for reading incoming messages. */
699 #define MAXMSGSIZE 4096
702 * Read and process a command from netbeans.
705 #if defined(FEAT_GUI_W32) || defined(PROTO)
706 /* Use this one when generating prototypes, the others are static. */
708 messageFromNetbeansW32()
710 # ifdef FEAT_GUI_MOTIF
712 messageFromNetbeans(XtPointer clientData
, int *unused1
, XtInputId
*unused2
)
716 messageFromNetbeans(gpointer clientData
, gint unused1
,
717 GdkInputCondition unused2
)
721 static char_u
*buf
= NULL
;
725 static int level
= 0;
730 nbdebug(("messageFromNetbeans() called without a socket\n"));
735 ++level
; /* recursion guard; this will be called from the X event loop */
738 /* Allocate a buffer to read into. */
741 buf
= alloc(MAXMSGSIZE
);
743 return; /* out of memory! */
746 /* Keep on reading for as long as there is something to read. */
749 len
= sock_read(sd
, buf
, MAXMSGSIZE
);
751 break; /* error or nothing more to read */
753 /* Store the read message in the queue. */
756 if (len
< MAXMSGSIZE
)
757 break; /* did read everything that's available */
762 /* read error or didn't read anything */
763 netbeans_disconnect();
764 nbdebug(("messageFromNetbeans: Error in read() from socket\n"));
767 nbdebug(("read from Netbeans socket\n"));
768 PERROR(_("read from Netbeans socket"));
770 return; /* don't try to parse it */
774 if (gtk_main_level() > 0)
777 /* Parse the messages, but avoid recursion. */
779 netbeans_parse_messages();
786 * Handle one NUL terminated command.
788 * format of a command from netbeans:
790 * 6:setTitle!84 "a.c"
799 * for function calls, the ! is replaced by a /
802 nb_parse_cmd(char_u
*cmd
)
809 if (STRCMP(cmd
, "DISCONNECT") == 0)
811 /* We assume the server knows that we can safely exit! */
814 /* Disconnect before exiting, Motif hangs in a Select error
815 * message otherwise. */
816 netbeans_disconnect();
821 if (STRCMP(cmd
, "DETACH") == 0)
823 /* The IDE is breaking the connection. */
826 netbeans_disconnect();
830 bufno
= strtol((char *)cmd
, &verb
, 10);
834 nbdebug((" missing colon: %s\n", cmd
));
835 EMSG2("E627: missing colon: %s", cmd
);
838 ++verb
; /* skip colon */
840 for (q
= verb
; *q
; q
++)
858 nbdebug((" missing ! or / in: %s\n", cmd
));
859 EMSG2("E628: missing ! or / in: %s", cmd
);
863 r_cmdno
= strtol(q
, &q
, 10);
865 q
= (char *)skipwhite((char_u
*)q
);
867 if (nb_do_cmd(bufno
, (char_u
*)verb
, isfunc
, r_cmdno
, (char_u
*)q
) == FAIL
)
871 * This happens because the ExtEd can send a cammand or 2 after
872 * doing a stopDocumentListen command. It doesn't harm anything
873 * so I'm disabling it except for debugging.
875 nbdebug(("nb_parse_cmd: Command error for \"%s\"\n", cmd
));
876 EMSG("E629: bad return from nb_do_cmd");
884 unsigned int fireChanges
:1;
885 unsigned int initDone
:1;
886 unsigned int insertDone
:1;
887 unsigned int modified
:1;
895 typedef struct nbbuf_struct nbbuf_T
;
897 static nbbuf_T
*buf_list
= 0;
898 static int buf_list_size
= 0; /* size of buf_list */
899 static int buf_list_used
= 0; /* nr of entries in buf_list actually in use */
901 static char **globalsignmap
;
902 static int globalsignmaplen
;
903 static int globalsignmapused
;
905 static int mapsigntype
__ARGS((nbbuf_T
*, int localsigntype
));
906 static void addsigntype
__ARGS((nbbuf_T
*, int localsigntype
, char_u
*typeName
,
907 char_u
*tooltip
, char_u
*glyphfile
,
908 int usefg
, int fg
, int usebg
, int bg
));
909 static void print_read_msg
__ARGS((nbbuf_T
*buf
));
910 static void print_save_msg
__ARGS((nbbuf_T
*buf
, long nchars
));
912 static int curPCtype
= -1;
915 * Get the Netbeans buffer number for the specified buffer.
918 nb_getbufno(buf_T
*bufp
)
922 for (i
= 0; i
< buf_list_used
; i
++)
923 if (buf_list
[i
].bufp
== bufp
)
929 * Is this a NetBeans-owned buffer?
932 isNetbeansBuffer(buf_T
*bufp
)
934 return usingNetbeans
&& bufp
->b_netbeans_file
;
938 * NetBeans and Vim have different undo models. In Vim, the file isn't
939 * changed if changes are undone via the undo command. In NetBeans, once
940 * a change has been made the file is marked as modified until saved. It
941 * doesn't matter if the change was undone.
943 * So this function is for the corner case where Vim thinks a buffer is
944 * unmodified but NetBeans thinks it IS modified.
947 isNetbeansModified(buf_T
*bufp
)
949 if (usingNetbeans
&& bufp
->b_netbeans_file
)
951 int bufno
= nb_getbufno(bufp
);
954 return buf_list
[bufno
].modified
;
963 * Given a Netbeans buffer number, return the netbeans buffer.
964 * Returns NULL for 0 or a negative number. A 0 bufno means a
965 * non-buffer related command has been sent.
968 nb_get_buf(int bufno
)
970 /* find or create a buffer with the given number */
979 buf_list
= (nbbuf_T
*)alloc_clear(100 * sizeof(nbbuf_T
));
982 if (bufno
>= buf_list_used
) /* new */
984 if (bufno
>= buf_list_size
) /* grow list */
986 incr
= bufno
- buf_list_size
+ 90;
987 buf_list_size
+= incr
;
988 buf_list
= (nbbuf_T
*)vim_realloc(
989 buf_list
, buf_list_size
* sizeof(nbbuf_T
));
990 memset(buf_list
+ buf_list_size
- incr
, 0, incr
* sizeof(nbbuf_T
));
993 while (buf_list_used
<= bufno
)
995 /* Default is to fire text changes. */
996 buf_list
[buf_list_used
].fireChanges
= 1;
1001 return buf_list
+ bufno
;
1005 * Return the number of buffers that are modified.
1008 count_changed_buffers(void)
1014 for (bufp
= firstbuf
; bufp
!= NULL
; bufp
= bufp
->b_next
)
1015 if (bufp
->b_changed
)
1021 * End the netbeans session.
1027 static char buf
[128];
1029 if (!haveConnection
)
1032 for (i
= 0; i
< buf_list_used
; i
++)
1034 if (!buf_list
[i
].bufp
)
1036 if (netbeansForcedQuit
)
1038 /* mark as unmodified so NetBeans won't put up dialog on "killed" */
1039 sprintf(buf
, "%d:unmodified=%d\n", i
, r_cmdno
);
1040 nbdebug(("EVT: %s", buf
));
1041 nb_send(buf
, "netbeans_end");
1043 sprintf(buf
, "%d:killed=%d\n", i
, r_cmdno
);
1044 nbdebug(("EVT: %s", buf
));
1045 /* nb_send(buf, "netbeans_end"); avoid "write failed" messages */
1047 sock_write(sd
, buf
, (int)STRLEN(buf
)); /* ignore errors */
1052 * Send a message to netbeans.
1055 nb_send(char *buf
, char *fun
)
1057 /* Avoid giving pages full of error messages when the other side has
1058 * exited, only mention the first error until the connection works again. */
1059 static int did_error
= FALSE
;
1065 nbdebug((" %s(): write while not connected\n", fun
));
1066 EMSG2("E630: %s(): write while not connected", fun
);
1070 else if (sock_write(sd
, buf
, (int)STRLEN(buf
)) != (int)STRLEN(buf
))
1074 nbdebug((" %s(): write failed\n", fun
));
1075 EMSG2("E631: %s(): write failed", fun
);
1084 * Some input received from netbeans requires a response. This function
1085 * handles a response with no information (except the command number).
1088 nb_reply_nil(int cmdno
)
1092 if (!haveConnection
)
1095 nbdebug(("REP %d: <none>\n", cmdno
));
1097 sprintf(reply
, "%d\n", cmdno
);
1098 nb_send(reply
, "nb_reply_nil");
1103 * Send a response with text.
1104 * "result" must have been quoted already (using nb_quote()).
1107 nb_reply_text(int cmdno
, char_u
*result
)
1111 if (!haveConnection
)
1114 nbdebug(("REP %d: %s\n", cmdno
, (char *)result
));
1116 reply
= alloc((unsigned)STRLEN(result
) + 32);
1117 sprintf((char *)reply
, "%d %s\n", cmdno
, (char *)result
);
1118 nb_send((char *)reply
, "nb_reply_text");
1125 * Send a response with a number result code.
1128 nb_reply_nr(int cmdno
, long result
)
1132 if (!haveConnection
)
1135 nbdebug(("REP %d: %ld\n", cmdno
, result
));
1137 sprintf(reply
, "%d %ld\n", cmdno
, result
);
1138 nb_send(reply
, "nb_reply_nr");
1143 * Encode newline, ret, backslash, double quote for transmission to NetBeans.
1146 nb_quote(char_u
*txt
)
1148 char_u
*buf
= alloc((unsigned)(2 * STRLEN(txt
) + 1));
1160 *q
++ = '\\'; *q
++ = *p
; break;
1162 /* *q++ = '\\'; *q++ = 't'; break; */
1164 *q
++ = '\\'; *q
++ = 'n'; break;
1166 *q
++ = '\\'; *q
++ = 'r'; break;
1179 * Remove top level double quotes; convert backslashed chars.
1180 * Returns an allocated string (NULL for failure).
1181 * If "endp" is not NULL it is set to the character after the terminating
1185 nb_unquote(char_u
*p
, char_u
**endp
)
1191 /* result is never longer than input */
1192 result
= (char *)alloc_clear((unsigned)STRLEN(p
) + 1);
1198 nbdebug(("nb_unquote called with string that doesn't start with a quote!: %s\n",
1204 for (q
= result
; !done
&& *p
!= NUL
;)
1210 * Unbackslashed dquote marks the end, if first char was dquote.
1219 case '\\': *q
++ = '\\'; break;
1220 case 'n': *q
++ = '\n'; break;
1221 case 't': *q
++ = '\t'; break;
1222 case 'r': *q
++ = '\r'; break;
1223 case '"': *q
++ = '"'; break;
1224 case NUL
: --p
; break;
1225 /* default: skip over illegal chars */
1242 * Remove from "first" byte to "last" byte (inclusive), at line "lnum" of the
1243 * current buffer. Remove to end of line when "last" is MAXCOL.
1246 nb_partialremove(linenr_T lnum
, colnr_T first
, colnr_T last
)
1248 char_u
*oldtext
, *newtext
;
1250 int lastbyte
= last
;
1252 oldtext
= ml_get(lnum
);
1253 oldlen
= (int)STRLEN(oldtext
);
1254 if (first
>= (colnr_T
)oldlen
|| oldlen
== 0) /* just in case */
1256 if (lastbyte
>= oldlen
)
1257 lastbyte
= oldlen
- 1;
1258 newtext
= alloc(oldlen
- (int)(lastbyte
- first
));
1259 if (newtext
!= NULL
)
1261 mch_memmove(newtext
, oldtext
, first
);
1262 STRMOVE(newtext
+ first
, oldtext
+ lastbyte
+ 1);
1263 nbdebug((" NEW LINE %d: %s\n", lnum
, newtext
));
1264 ml_replace(lnum
, newtext
, FALSE
);
1269 * Replace the "first" line with the concatenation of the "first" and
1270 * the "other" line. The "other" line is not removed.
1273 nb_joinlines(linenr_T first
, linenr_T other
)
1275 int len_first
, len_other
;
1278 len_first
= (int)STRLEN(ml_get(first
));
1279 len_other
= (int)STRLEN(ml_get(other
));
1280 p
= alloc((unsigned)(len_first
+ len_other
+ 1));
1283 mch_memmove(p
, ml_get(first
), len_first
);
1284 mch_memmove(p
+ len_first
, ml_get(other
), len_other
+ 1);
1285 ml_replace(first
, p
, FALSE
);
1290 #define streq(a,b) (strcmp(a,b) == 0)
1291 static int needupdate
= 0;
1292 static int inAtomic
= 0;
1295 * Do the actual processing of a single netbeans command or function.
1296 * The difference between a command and function is that a function
1297 * gets a response (it's required) but a command does not.
1298 * For arguments see comment for nb_parse_cmd().
1306 char_u
*args
) /* points to space before arguments or NUL */
1310 nbbuf_T
*buf
= nb_get_buf(bufno
);
1311 static int skip
= 0;
1313 char *cp
; /* for when a char pointer is needed */
1315 nbdebug(("%s %d: (%d) %s %s\n", (func
) ? "FUN" : "CMD", cmdno
, bufno
, cmd
,
1316 STRCMP(cmd
, "insert") == 0 ? "<text>" : (char *)args
));
1320 /* =====================================================================*/
1321 if (streq((char *)cmd
, "getModified"))
1323 if (buf
== NULL
|| buf
->bufp
== NULL
)
1324 /* Return the number of buffers that are modified. */
1325 nb_reply_nr(cmdno
, (long)count_changed_buffers());
1327 /* Return whether the buffer is modified. */
1328 nb_reply_nr(cmdno
, (long)(buf
->bufp
->b_changed
1329 || isNetbeansModified(buf
->bufp
)));
1330 /* =====================================================================*/
1332 else if (streq((char *)cmd
, "saveAndExit"))
1334 /* Note: this will exit Vim if successful. */
1335 coloncmd(":confirm qall");
1337 /* We didn't exit: return the number of changed buffers. */
1338 nb_reply_nr(cmdno
, (long)count_changed_buffers());
1339 /* =====================================================================*/
1341 else if (streq((char *)cmd
, "getCursor"))
1345 /* Note: nb_getbufno() may return -1. This indicates the IDE
1346 * didn't assign a number to the current buffer in response to a
1347 * fileOpened event. */
1348 sprintf((char *)text
, "%d %ld %d %ld",
1349 nb_getbufno(curbuf
),
1350 (long)curwin
->w_cursor
.lnum
,
1351 (int)curwin
->w_cursor
.col
,
1352 pos2off(curbuf
, &curwin
->w_cursor
));
1353 nb_reply_text(cmdno
, text
);
1354 /* =====================================================================*/
1356 else if (streq((char *)cmd
, "getAnno"))
1360 if (buf
== NULL
|| buf
->bufp
== NULL
)
1362 nbdebug((" Invalid buffer identifier in getAnno\n"));
1363 EMSG("E652: Invalid buffer identifier in getAnno");
1371 serNum
= strtol(cp
, &cp
, 10);
1372 /* If the sign isn't found linenum will be zero. */
1373 linenum
= (long)buf_findsign(buf
->bufp
, serNum
);
1376 nb_reply_nr(cmdno
, linenum
);
1377 /* =====================================================================*/
1379 else if (streq((char *)cmd
, "getLength"))
1383 if (buf
== NULL
|| buf
->bufp
== NULL
)
1385 nbdebug((" invalid buffer identifier in getLength\n"));
1386 EMSG("E632: invalid buffer identifier in getLength");
1391 len
= get_buf_size(buf
->bufp
);
1393 nb_reply_nr(cmdno
, len
);
1394 /* =====================================================================*/
1396 else if (streq((char *)cmd
, "getText"))
1400 char_u
*text
= NULL
;
1405 if (buf
== NULL
|| buf
->bufp
== NULL
)
1407 nbdebug((" invalid buffer identifier in getText\n"));
1408 EMSG("E633: invalid buffer identifier in getText");
1413 len
= get_buf_size(buf
->bufp
);
1414 nlines
= buf
->bufp
->b_ml
.ml_line_count
;
1415 text
= alloc((unsigned)((len
> 0)
1416 ? ((len
+ nlines
) * 2) : 4));
1419 nbdebug((" nb_do_cmd: getText has null text field\n"));
1426 for (; lno
<= nlines
; lno
++)
1428 line
= nb_quote(ml_get_buf(buf
->bufp
, lno
, FALSE
));
1443 nb_reply_text(cmdno
, (char_u
*)"");
1446 nb_reply_text(cmdno
, text
);
1449 /* =====================================================================*/
1451 else if (streq((char *)cmd
, "remove"))
1457 linenr_T del_from_lnum
, del_to_lnum
; /* lines to be deleted as a whole */
1458 int oldFire
= netbeansFireChanges
;
1459 int oldSuppress
= netbeansSuppressNoLines
;
1462 if (skip
>= SKIP_STOP
)
1464 nbdebug((" Skipping %s command\n", (char *) cmd
));
1465 nb_reply_nil(cmdno
);
1469 if (buf
== NULL
|| buf
->bufp
== NULL
)
1471 nbdebug((" invalid buffer identifier in remove\n"));
1472 EMSG("E634: invalid buffer identifier in remove");
1477 netbeansFireChanges
= FALSE
;
1478 netbeansSuppressNoLines
= TRUE
;
1480 nb_set_curbuf(buf
->bufp
);
1481 wasChanged
= buf
->bufp
->b_changed
;
1483 off
= strtol(cp
, &cp
, 10);
1484 count
= strtol(cp
, &cp
, 10);
1485 args
= (char_u
*)cp
;
1486 /* delete "count" chars, starting at "off" */
1487 pos
= off2pos(buf
->bufp
, off
);
1490 nbdebug((" !bad position\n"));
1491 nb_reply_text(cmdno
, (char_u
*)"!bad position");
1492 netbeansFireChanges
= oldFire
;
1493 netbeansSuppressNoLines
= oldSuppress
;
1497 nbdebug((" FIRST POS: line %d, col %d\n", first
.lnum
, first
.col
));
1498 pos
= off2pos(buf
->bufp
, off
+count
-1);
1501 nbdebug((" !bad count\n"));
1502 nb_reply_text(cmdno
, (char_u
*)"!bad count");
1503 netbeansFireChanges
= oldFire
;
1504 netbeansSuppressNoLines
= oldSuppress
;
1508 nbdebug((" LAST POS: line %d, col %d\n", last
.lnum
, last
.col
));
1509 del_from_lnum
= first
.lnum
;
1510 del_to_lnum
= last
.lnum
;
1513 /* Get the position of the first byte after the deleted
1514 * section. "next" is NULL when deleting to the end of the
1516 next
= off2pos(buf
->bufp
, off
+ count
);
1518 /* Remove part of the first line. */
1519 if (first
.col
!= 0 || (next
!= NULL
&& first
.lnum
== next
->lnum
))
1521 if (first
.lnum
!= last
.lnum
1522 || (next
!= NULL
&& first
.lnum
!= next
->lnum
))
1524 /* remove to the end of the first line */
1525 nb_partialremove(first
.lnum
, first
.col
,
1527 if (first
.lnum
== last
.lnum
)
1529 /* Partial line to remove includes the end of
1530 * line. Join the line with the next one, have
1531 * the next line deleted below. */
1532 nb_joinlines(first
.lnum
, next
->lnum
);
1533 del_to_lnum
= next
->lnum
;
1538 /* remove within one line */
1539 nb_partialremove(first
.lnum
, first
.col
, last
.col
);
1541 ++del_from_lnum
; /* don't delete the first line */
1544 /* Remove part of the last line. */
1545 if (first
.lnum
!= last
.lnum
&& next
!= NULL
1546 && next
->col
!= 0 && last
.lnum
== next
->lnum
)
1548 nb_partialremove(last
.lnum
, 0, last
.col
);
1549 if (del_from_lnum
> first
.lnum
)
1551 /* Join end of last line to start of first line; last
1552 * line is deleted below. */
1553 nb_joinlines(first
.lnum
, last
.lnum
);
1556 /* First line is deleted as a whole, keep the last
1561 /* First is partial line; last line to remove includes
1562 * the end of line; join first line to line following last
1563 * line; line following last line is deleted below. */
1564 if (first
.lnum
!= last
.lnum
&& del_from_lnum
> first
.lnum
1565 && next
!= NULL
&& last
.lnum
!= next
->lnum
)
1567 nb_joinlines(first
.lnum
, next
->lnum
);
1568 del_to_lnum
= next
->lnum
;
1571 /* Delete whole lines if there are any. */
1572 if (del_to_lnum
>= del_from_lnum
)
1576 /* delete signs from the lines being deleted */
1577 for (i
= del_from_lnum
; i
<= del_to_lnum
; i
++)
1579 int id
= buf_findsign_id(buf
->bufp
, (linenr_T
)i
);
1582 nbdebug((" Deleting sign %d on line %d\n", id
, i
));
1583 buf_delsign(buf
->bufp
, id
);
1586 nbdebug((" No sign on line %d\n", i
));
1589 nbdebug((" Deleting lines %d through %d\n", del_from_lnum
, del_to_lnum
));
1590 curwin
->w_cursor
.lnum
= del_from_lnum
;
1591 curwin
->w_cursor
.col
= 0;
1592 del_lines(del_to_lnum
- del_from_lnum
+ 1, FALSE
);
1595 /* Leave cursor at first deleted byte. */
1596 curwin
->w_cursor
= first
;
1597 check_cursor_lnum();
1598 buf
->bufp
->b_changed
= wasChanged
; /* logically unchanged */
1599 netbeansFireChanges
= oldFire
;
1600 netbeansSuppressNoLines
= oldSuppress
;
1602 u_blockfree(buf
->bufp
);
1603 u_clearall(buf
->bufp
);
1605 nb_reply_nil(cmdno
);
1606 /* =====================================================================*/
1608 else if (streq((char *)cmd
, "insert"))
1612 if (skip
>= SKIP_STOP
)
1614 nbdebug((" Skipping %s command\n", (char *) cmd
));
1615 nb_reply_nil(cmdno
);
1621 off
= strtol(cp
, &cp
, 10);
1622 args
= (char_u
*)cp
;
1624 /* get text to be inserted */
1625 args
= skipwhite(args
);
1626 args
= to_free
= (char_u
*)nb_unquote(args
, NULL
);
1628 nbdebug((" CHUNK[%d]: %d bytes at offset %d\n",
1629 buf->bufp->b_ml.ml_line_count, STRLEN(args), off));
1632 if (buf
== NULL
|| buf
->bufp
== NULL
)
1634 nbdebug((" invalid buffer identifier in insert\n"));
1635 EMSG("E635: invalid buffer identifier in insert");
1638 else if (args
!= NULL
)
1640 int ff_detected
= EOL_UNKNOWN
;
1641 int buf_was_empty
= (buf
->bufp
->b_ml
.ml_flags
& ML_EMPTY
);
1644 int oldFire
= netbeansFireChanges
;
1648 linenr_T lnum_start
;
1651 netbeansFireChanges
= 0;
1653 /* Jump to the buffer where we insert. After this "curbuf"
1655 nb_set_curbuf(buf
->bufp
);
1656 old_b_changed
= curbuf
->b_changed
;
1658 /* Convert the specified character offset into a lnum/col
1660 pos
= off2pos(curbuf
, off
);
1666 lnum_start
= pos
->lnum
;
1670 /* If the given position is not found, assume we want
1671 * the end of the file. See setLocAndSize HACK. */
1673 lnum_start
= 1; /* above empty line */
1675 lnum_start
= curbuf
->b_ml
.ml_line_count
+ 1;
1678 /* "lnum" is the line where we insert: either append to it or
1679 * insert a new line above it. */
1682 /* Loop over the "\n" separated lines of the argument. */
1684 while (*args
!= NUL
)
1686 nl
= vim_strchr(args
, '\n');
1689 /* Incomplete line, probably truncated. Next "insert"
1690 * command should append to this one. */
1698 * We need to detect EOL style, because the commands
1699 * use a character offset.
1701 if (nl
> args
&& nl
[-1] == '\r')
1703 ff_detected
= EOL_DOS
;
1707 ff_detected
= EOL_UNIX
;
1711 if (lnum
== lnum_start
1712 && ((pos
!= NULL
&& pos
->col
> 0)
1713 || (lnum
== 1 && buf_was_empty
)))
1715 char_u
*oldline
= ml_get(lnum
);
1718 /* Insert halfway a line. For simplicity we assume we
1719 * need to append to the line. */
1720 newline
= alloc_check((unsigned)(STRLEN(oldline
) + len
+ 1));
1721 if (newline
!= NULL
)
1723 STRCPY(newline
, oldline
);
1724 STRCAT(newline
, args
);
1725 ml_replace(lnum
, newline
, FALSE
);
1730 /* Append a new line. Not that we always do this,
1731 * also when the text doesn't end in a "\n". */
1732 ml_append((linenr_T
)(lnum
- 1), args
, (colnr_T
)(len
+ 1), FALSE
);
1742 /* Adjust the marks below the inserted lines. */
1743 appended_lines_mark(lnum_start
- 1, (long)added
);
1746 * When starting with an empty buffer set the fileformat.
1747 * This is just guessing...
1751 if (ff_detected
== EOL_UNKNOWN
)
1752 #if defined(MSDOS) || defined(MSWIN) || defined(OS2)
1753 ff_detected
= EOL_DOS
;
1755 ff_detected
= EOL_UNIX
;
1757 set_fileformat(ff_detected
, OPT_LOCAL
);
1758 curbuf
->b_start_ffc
= *curbuf
->b_p_ff
;
1762 * XXX - GRP - Is the next line right? If I've inserted
1763 * text the buffer has been updated but not written. Will
1764 * netbeans guarantee to write it? Even if I do a :q! ?
1766 curbuf
->b_changed
= old_b_changed
; /* logically unchanged */
1767 netbeansFireChanges
= oldFire
;
1769 /* Undo info is invalid now... */
1770 u_blockfree(curbuf
);
1774 nb_reply_nil(cmdno
); /* or !error */
1778 nbdebug(("UNIMPLEMENTED FUNCTION: %s\n", cmd
));
1779 nb_reply_nil(cmdno
);
1783 else /* Not a function; no reply required. */
1785 /* =====================================================================*/
1786 if (streq((char *)cmd
, "create"))
1788 /* Create a buffer without a name. */
1791 nbdebug((" invalid buffer identifier in create\n"));
1792 EMSG("E636: invalid buffer identifier in create");
1795 vim_free(buf
->displayname
);
1796 buf
->displayname
= NULL
;
1798 netbeansReadFile
= 0; /* don't try to open disk file */
1799 do_ecmd(0, NULL
, 0, 0, ECMD_ONE
, ECMD_HIDE
+ ECMD_OLDBUF
);
1800 netbeansReadFile
= 1;
1803 buf
->insertDone
= FALSE
;
1804 gui_update_menus(0);
1805 /* =====================================================================*/
1807 else if (streq((char *)cmd
, "insertDone"))
1809 if (buf
== NULL
|| buf
->bufp
== NULL
)
1811 nbdebug((" invalid buffer identifier in insertDone\n"));
1815 buf
->bufp
->b_start_eol
= *args
== 'T';
1816 buf
->insertDone
= TRUE
;
1818 buf
->bufp
->b_p_ro
= *args
== 'T';
1819 print_read_msg(buf
);
1821 /* =====================================================================*/
1823 else if (streq((char *)cmd
, "saveDone"))
1825 long savedChars
= atol((char *)args
);
1827 if (buf
== NULL
|| buf
->bufp
== NULL
)
1829 nbdebug((" invalid buffer identifier in saveDone\n"));
1832 print_save_msg(buf
, savedChars
);
1833 /* =====================================================================*/
1835 else if (streq((char *)cmd
, "startDocumentListen"))
1839 nbdebug((" invalid buffer identifier in startDocumentListen\n"));
1840 EMSG("E637: invalid buffer identifier in startDocumentListen");
1843 buf
->fireChanges
= 1;
1844 /* =====================================================================*/
1846 else if (streq((char *)cmd
, "stopDocumentListen"))
1850 nbdebug((" invalid buffer identifier in stopDocumentListen\n"));
1851 EMSG("E638: invalid buffer identifier in stopDocumentListen");
1854 buf
->fireChanges
= 0;
1855 if (buf
->bufp
!= NULL
&& buf
->bufp
->b_was_netbeans_file
)
1857 if (!buf
->bufp
->b_netbeans_file
)
1859 nbdebug(("E658: NetBeans connection lost for buffer %ld\n", buf
->bufp
->b_fnum
));
1860 EMSGN(_("E658: NetBeans connection lost for buffer %ld"),
1865 /* NetBeans uses stopDocumentListen when it stops editing
1866 * a file. It then expects the buffer in Vim to
1868 do_bufdel(DOBUF_DEL
, (char_u
*)"", 1,
1869 buf
->bufp
->b_fnum
, buf
->bufp
->b_fnum
, TRUE
);
1870 vim_memset(buf
, 0, sizeof(nbbuf_T
));
1873 /* =====================================================================*/
1875 else if (streq((char *)cmd
, "setTitle"))
1879 nbdebug((" invalid buffer identifier in setTitle\n"));
1880 EMSG("E639: invalid buffer identifier in setTitle");
1883 vim_free(buf
->displayname
);
1884 buf
->displayname
= nb_unquote(args
, NULL
);
1885 /* =====================================================================*/
1887 else if (streq((char *)cmd
, "initDone"))
1889 if (buf
== NULL
|| buf
->bufp
== NULL
)
1891 nbdebug((" invalid buffer identifier in initDone\n"));
1892 EMSG("E640: invalid buffer identifier in initDone");
1896 buf
->initDone
= TRUE
;
1897 nb_set_curbuf(buf
->bufp
);
1898 #if defined(FEAT_AUTOCMD)
1899 apply_autocmds(EVENT_BUFREADPOST
, 0, 0, FALSE
, buf
->bufp
);
1902 /* handle any postponed key commands */
1904 /* =====================================================================*/
1906 else if (streq((char *)cmd
, "setBufferNumber")
1907 || streq((char *)cmd
, "putBufferNumber"))
1914 nbdebug((" invalid buffer identifier in setBufferNumber\n"));
1915 EMSG("E641: invalid buffer identifier in setBufferNumber");
1918 path
= (char_u
*)nb_unquote(args
, NULL
);
1921 bufp
= buflist_findname(path
);
1925 nbdebug((" File %s not found in setBufferNumber\n", args
));
1926 EMSG2("E642: File %s not found in setBufferNumber", args
);
1930 buf
->nbbuf_number
= bufp
->b_fnum
;
1932 /* "setBufferNumber" has the side effect of jumping to the buffer
1933 * (don't know why!). Don't do that for "putBufferNumber". */
1935 coloncmd(":buffer %d", bufp
->b_fnum
);
1938 buf
->initDone
= TRUE
;
1940 /* handle any postponed key commands */
1944 #if 0 /* never used */
1945 buf
->internalname
= (char *)alloc_clear(8);
1946 sprintf(buf
->internalname
, "<%d>", bufno
);
1947 buf
->netbeansOwns
= 0;
1949 /* =====================================================================*/
1951 else if (streq((char *)cmd
, "setFullName"))
1955 nbdebug((" invalid buffer identifier in setFullName\n"));
1956 EMSG("E643: invalid buffer identifier in setFullName");
1959 vim_free(buf
->displayname
);
1960 buf
->displayname
= nb_unquote(args
, NULL
);
1962 netbeansReadFile
= 0; /* don't try to open disk file */
1963 do_ecmd(0, (char_u
*)buf
->displayname
, 0, 0, ECMD_ONE
,
1964 ECMD_HIDE
+ ECMD_OLDBUF
);
1965 netbeansReadFile
= 1;
1968 gui_update_menus(0);
1969 /* =====================================================================*/
1971 else if (streq((char *)cmd
, "editFile"))
1975 nbdebug((" invalid buffer identifier in editFile\n"));
1976 EMSG("E644: invalid buffer identifier in editFile");
1979 /* Edit a file: like create + setFullName + read the file. */
1980 vim_free(buf
->displayname
);
1981 buf
->displayname
= nb_unquote(args
, NULL
);
1982 do_ecmd(0, (char_u
*)buf
->displayname
, NULL
, NULL
, ECMD_ONE
,
1983 ECMD_HIDE
+ ECMD_OLDBUF
);
1985 buf
->initDone
= TRUE
;
1987 #if defined(FEAT_TITLE)
1990 gui_update_menus(0);
1991 /* =====================================================================*/
1993 else if (streq((char *)cmd
, "setVisible"))
1995 if (buf
== NULL
|| buf
->bufp
== NULL
)
1997 nbdebug((" invalid buffer identifier in setVisible\n"));
1998 /* This message was commented out, probably because it can
1999 * happen when shutting down. */
2001 EMSG("E645: invalid buffer identifier in setVisible");
2004 if (streq((char *)args
, "T") && buf
->bufp
!= curbuf
)
2007 exarg
.cmd
= (char_u
*)"goto";
2008 exarg
.forceit
= FALSE
;
2009 dosetvisible
= TRUE
;
2010 goto_buffer(&exarg
, DOBUF_FIRST
, FORWARD
, buf
->bufp
->b_fnum
);
2012 dosetvisible
= FALSE
;
2014 /* Side effect!!!. */
2016 gui_mch_set_foreground();
2018 /* =====================================================================*/
2020 else if (streq((char *)cmd
, "raise"))
2022 /* Bring gvim to the foreground. */
2024 gui_mch_set_foreground();
2025 /* =====================================================================*/
2027 else if (streq((char *)cmd
, "setModified"))
2031 if (buf
== NULL
|| buf
->bufp
== NULL
)
2033 nbdebug((" invalid buffer identifier in setModified\n"));
2034 /* This message was commented out, probably because it can
2035 * happen when shutting down. */
2037 EMSG("E646: invalid buffer identifier in setModified");
2040 prev_b_changed
= buf
->bufp
->b_changed
;
2041 if (streq((char *)args
, "T"))
2042 buf
->bufp
->b_changed
= TRUE
;
2047 /* Assume NetBeans stored the file. Reset the timestamp to
2048 * avoid "file changed" warnings. */
2049 if (buf
->bufp
->b_ffname
!= NULL
2050 && mch_stat((char *)buf
->bufp
->b_ffname
, &st
) >= 0)
2051 buf_store_time(buf
->bufp
, &st
, buf
->bufp
->b_ffname
);
2052 buf
->bufp
->b_changed
= FALSE
;
2054 buf
->modified
= buf
->bufp
->b_changed
;
2055 if (prev_b_changed
!= buf
->bufp
->b_changed
)
2058 check_status(buf
->bufp
);
2059 redraw_tabline
= TRUE
;
2066 /* =====================================================================*/
2068 else if (streq((char *)cmd
, "setModtime"))
2070 if (buf
== NULL
|| buf
->bufp
== NULL
)
2071 nbdebug((" invalid buffer identifier in setModtime\n"));
2073 buf
->bufp
->b_mtime
= atoi((char *)args
);
2074 /* =====================================================================*/
2076 else if (streq((char *)cmd
, "setReadOnly"))
2078 if (buf
== NULL
|| buf
->bufp
== NULL
)
2079 nbdebug((" invalid buffer identifier in setReadOnly\n"));
2080 else if (streq((char *)args
, "T"))
2081 buf
->bufp
->b_p_ro
= TRUE
;
2083 buf
->bufp
->b_p_ro
= FALSE
;
2084 /* =====================================================================*/
2086 else if (streq((char *)cmd
, "setMark"))
2089 /* =====================================================================*/
2091 else if (streq((char *)cmd
, "showBalloon"))
2093 #if defined(FEAT_BEVAL)
2094 static char *text
= NULL
;
2097 * Set up the Balloon Expression Evaluation area.
2098 * Ignore 'ballooneval' here.
2099 * The text pointer must remain valid for a while.
2101 if (balloonEval
!= NULL
)
2104 text
= nb_unquote(args
, NULL
);
2106 gui_mch_post_balloon(balloonEval
, (char_u
*)text
);
2109 /* =====================================================================*/
2111 else if (streq((char *)cmd
, "setDot"))
2118 if (buf
== NULL
|| buf
->bufp
== NULL
)
2120 nbdebug((" invalid buffer identifier in setDot\n"));
2121 EMSG("E647: invalid buffer identifier in setDot");
2125 nb_set_curbuf(buf
->bufp
);
2128 /* Don't want Visual mode now. */
2135 pos
= get_off_or_lnum(buf
->bufp
, &args
);
2138 curwin
->w_cursor
= *pos
;
2145 nbdebug((" BAD POSITION in setDot: %s\n", s
));
2147 /* gui_update_cursor(TRUE, FALSE); */
2148 /* update_curbuf(NOT_VALID); */
2149 update_topline(); /* scroll to show the line */
2150 update_screen(VALID
);
2153 gui_update_cursor(TRUE
, FALSE
);
2155 /* Quit a hit-return or more prompt. */
2156 if (State
== HITRETURN
|| State
== ASKMORE
)
2159 if (gtk_main_level() > 0)
2163 /* =====================================================================*/
2165 else if (streq((char *)cmd
, "close"))
2168 char *name
= "<NONE>";
2173 nbdebug((" invalid buffer identifier in close\n"));
2174 EMSG("E648: invalid buffer identifier in close");
2179 if (buf
->displayname
!= NULL
)
2180 name
= buf
->displayname
;
2182 if (buf
->bufp
== NULL
)
2184 nbdebug((" invalid buffer identifier in close\n"));
2185 /* This message was commented out, probably because it can
2186 * happen when shutting down. */
2188 EMSG("E649: invalid buffer identifier in close");
2190 nbdebug((" CLOSE %d: %s\n", bufno
, name
));
2191 need_mouse_correct
= TRUE
;
2192 if (buf
->bufp
!= NULL
)
2193 do_buffer(DOBUF_WIPE
, DOBUF_FIRST
, FORWARD
,
2194 buf
->bufp
->b_fnum
, TRUE
);
2196 buf
->initDone
= FALSE
;
2198 /* =====================================================================*/
2200 else if (streq((char *)cmd
, "setStyle")) /* obsolete... */
2202 nbdebug((" setStyle is obsolete!\n"));
2203 /* =====================================================================*/
2205 else if (streq((char *)cmd
, "setExitDelay"))
2207 /* Only used in version 2.1. */
2208 /* =====================================================================*/
2210 else if (streq((char *)cmd
, "defineAnnoType"))
2225 nbdebug((" invalid buffer identifier in defineAnnoType\n"));
2226 EMSG("E650: invalid buffer identifier in defineAnnoType");
2231 typeNum
= strtol(cp
, &cp
, 10);
2232 args
= (char_u
*)cp
;
2233 args
= skipwhite(args
);
2234 typeName
= (char_u
*)nb_unquote(args
, &args
);
2235 args
= skipwhite(args
+ 1);
2236 tooltip
= (char_u
*)nb_unquote(args
, &args
);
2237 args
= skipwhite(args
+ 1);
2239 p
= (char_u
*)nb_unquote(args
, &args
);
2240 glyphFile
= vim_strsave_escaped(p
, escape_chars
);
2243 args
= skipwhite(args
+ 1);
2244 if (STRNCMP(args
, "none", 4) == 0)
2250 fg
= strtol(cp
, &cp
, 10);
2251 args
= (char_u
*)cp
;
2253 if (STRNCMP(args
, "none", 4) == 0)
2259 bg
= strtol(cp
, &cp
, 10);
2260 args
= (char_u
*)cp
;
2262 if (typeName
!= NULL
&& tooltip
!= NULL
&& glyphFile
!= NULL
)
2263 addsigntype(buf
, typeNum
, typeName
, tooltip
, glyphFile
,
2264 use_fg
, fg
, use_bg
, bg
);
2268 /* don't free typeName; it's used directly in addsigntype() */
2270 vim_free(glyphFile
);
2273 /* =====================================================================*/
2275 else if (streq((char *)cmd
, "addAnno"))
2286 if (buf
== NULL
|| buf
->bufp
== NULL
)
2288 nbdebug((" invalid buffer identifier in addAnno\n"));
2289 EMSG("E651: invalid buffer identifier in addAnno");
2296 serNum
= strtol(cp
, &cp
, 10);
2298 /* Get the typenr specific for this buffer and convert it to
2299 * the global typenumber, as used for the sign name. */
2300 localTypeNum
= strtol(cp
, &cp
, 10);
2301 args
= (char_u
*)cp
;
2302 typeNum
= mapsigntype(buf
, localTypeNum
);
2304 pos
= get_off_or_lnum(buf
->bufp
, &args
);
2310 strtol(cp
, &cp
, 10);
2311 args
= (char_u
*)cp
;
2315 nbdebug((" partial line annotation -- Not Yet Implemented!\n"));
2318 if (serNum
>= GUARDEDOFFSET
)
2320 nbdebug((" too many annotations! ignoring...\n"));
2325 coloncmd(":sign place %d line=%d name=%d buffer=%d",
2326 serNum
, pos
->lnum
, typeNum
, buf
->bufp
->b_fnum
);
2327 if (typeNum
== curPCtype
)
2328 coloncmd(":sign jump %d buffer=%d", serNum
,
2332 /* =====================================================================*/
2334 else if (streq((char *)cmd
, "removeAnno"))
2339 if (buf
== NULL
|| buf
->bufp
== NULL
)
2341 nbdebug((" invalid buffer identifier in removeAnno\n"));
2346 serNum
= strtol(cp
, &cp
, 10);
2347 args
= (char_u
*)cp
;
2348 coloncmd(":sign unplace %d buffer=%d",
2349 serNum
, buf
->bufp
->b_fnum
);
2350 redraw_buf_later(buf
->bufp
, NOT_VALID
);
2352 /* =====================================================================*/
2354 else if (streq((char *)cmd
, "moveAnnoToFront"))
2357 nbdebug((" moveAnnoToFront: Not Yet Implemented!\n"));
2359 /* =====================================================================*/
2361 else if (streq((char *)cmd
, "guard") || streq((char *)cmd
, "unguard"))
2367 int un
= (cmd
[0] == 'u');
2368 static int guardId
= GUARDEDOFFSET
;
2370 if (skip
>= SKIP_STOP
)
2372 nbdebug((" Skipping %s command\n", (char *) cmd
));
2378 if (buf
== NULL
|| buf
->bufp
== NULL
)
2380 nbdebug((" invalid buffer identifier in %s command\n", cmd
));
2383 nb_set_curbuf(buf
->bufp
);
2385 off
= strtol(cp
, &cp
, 10);
2386 len
= strtol(cp
, NULL
, 10);
2387 args
= (char_u
*)cp
;
2388 pos
= off2pos(buf
->bufp
, off
);
2391 nbdebug((" no such start pos in %s, %ld\n", cmd
, off
));
2395 pos
= off2pos(buf
->bufp
, off
+ len
- 1);
2396 if (pos
!= NULL
&& pos
->col
== 0)
2399 * In Java Swing the offset is a position between 2
2400 * characters. If col == 0 then we really want the
2401 * previous line as the end.
2403 pos
= off2pos(buf
->bufp
, off
+ len
- 2);
2406 nbdebug((" no such end pos in %s, %ld\n",
2407 cmd
, off
+ len
- 1));
2412 /* set highlight for region */
2413 nbdebug((" %sGUARD %ld,%d to %ld,%d\n", (un
) ? "UN" : "",
2414 first
.lnum
, first
.col
,
2415 last
.lnum
, last
.col
));
2417 for (lnum
= first
.lnum
; lnum
<= last
.lnum
; lnum
++)
2425 if (buf_findsigntype_id(buf
->bufp
, lnum
,
2429 ":sign place %d line=%d name=%d buffer=%d",
2430 guardId
++, lnum
, GUARDED
,
2436 redraw_buf_later(buf
->bufp
, NOT_VALID
);
2439 /* =====================================================================*/
2441 else if (streq((char *)cmd
, "startAtomic"))
2444 /* =====================================================================*/
2446 else if (streq((char *)cmd
, "endAtomic"))
2454 /* =====================================================================*/
2456 else if (streq((char *)cmd
, "save"))
2459 * NOTE - This command is obsolete wrt NetBeans. Its left in
2460 * only for historical reasons.
2462 if (buf
== NULL
|| buf
->bufp
== NULL
)
2464 nbdebug((" invalid buffer identifier in %s command\n", cmd
));
2468 /* the following is taken from ex_cmds.c (do_wqall function) */
2469 if (bufIsChanged(buf
->bufp
))
2471 /* Only write if the buffer can be written. */
2473 && !buf
->bufp
->b_p_ro
2474 && buf
->bufp
->b_ffname
!= NULL
2475 #ifdef FEAT_QUICKFIX
2476 && !bt_dontwrite(buf
->bufp
)
2480 buf_write_all(buf
->bufp
, FALSE
);
2482 /* an autocommand may have deleted the buffer */
2483 if (!buf_valid(buf
->bufp
))
2490 nbdebug((" Buffer has no changes!\n"));
2492 /* =====================================================================*/
2494 else if (streq((char *)cmd
, "netbeansBuffer"))
2496 if (buf
== NULL
|| buf
->bufp
== NULL
)
2498 nbdebug((" invalid buffer identifier in %s command\n", cmd
));
2503 buf
->bufp
->b_netbeans_file
= TRUE
;
2504 buf
->bufp
->b_was_netbeans_file
= TRUE
;
2507 buf
->bufp
->b_netbeans_file
= FALSE
;
2508 /* =====================================================================*/
2510 else if (streq((char *)cmd
, "specialKeys"))
2513 /* =====================================================================*/
2515 else if (streq((char *)cmd
, "actionMenuItem"))
2518 /* =====================================================================*/
2520 else if (streq((char *)cmd
, "version"))
2526 nbdebug(("Unrecognised command: %s\n", cmd
));
2529 * Unrecognized command is ignored.
2532 if (inAtomic
&& doupdate
)
2539 * Is this needed? I moved the netbeans_Xt_connect() later during startup
2540 * and it may no longer be necessary. If its not needed then needupdate
2541 * and doupdate can also be removed.
2543 if (buf
!= NULL
&& buf
->initDone
&& doupdate
)
2545 update_screen(NOT_VALID
);
2548 gui_update_cursor(TRUE
, FALSE
);
2550 /* Quit a hit-return or more prompt. */
2551 if (State
== HITRETURN
|| State
== ASKMORE
)
2554 if (gtk_main_level() > 0)
2565 * If "buf" is not the current buffer try changing to a window that edits this
2566 * buffer. If there is no such window then close the current buffer and set
2567 * the current buffer as "buf".
2570 nb_set_curbuf(buf_T
*buf
)
2572 if (curbuf
!= buf
&& buf_jump_open_win(buf
) == NULL
)
2573 set_curbuf(buf
, DOBUF_GOTO
);
2577 * Process a vim colon command.
2580 coloncmd(char *cmd
, ...)
2586 vsprintf(buf
, cmd
, ap
);
2589 nbdebug((" COLONCMD %s\n", buf
));
2591 /* ALT_INPUT_LOCK_ON; */
2592 do_cmdline((char_u
*)buf
, NULL
, NULL
, DOCMD_NOWAIT
| DOCMD_KEYTYPED
);
2593 /* ALT_INPUT_LOCK_OFF; */
2595 setcursor(); /* restore the cursor position */
2596 out_flush(); /* make sure output has been written */
2598 gui_update_cursor(TRUE
, FALSE
);
2604 * Parse the specialKeys argument and issue the appropriate map commands.
2607 special_keys(char_u
*args
)
2609 char *save_str
= nb_unquote(args
, NULL
);
2610 char *tok
= strtok(save_str
, " ");
2619 if ((sep
= strchr(tok
, '-')) != NULL
)
2639 strcpy(&keybuf
[i
], tok
);
2640 vim_snprintf(cmdbuf
, sizeof(cmdbuf
),
2641 "<silent><%s> :nbkey %s<CR>", keybuf
, keybuf
);
2642 do_map(0, (char_u
*)cmdbuf
, NORMAL
, FALSE
);
2643 tok
= strtok(NULL
, " ");
2653 netbeans_keystring(0, (char *)eap
->arg
);
2658 * Initialize highlights and signs for use by netbeans (mostly obsolete)
2661 nb_init_graphics(void)
2663 static int did_init
= FALSE
;
2667 coloncmd(":highlight NBGuarded guibg=Cyan guifg=Black");
2668 coloncmd(":sign define %d linehl=NBGuarded", GUARDED
);
2675 * Convert key to netbeans name.
2678 netbeans_keyname(int key
, char *buf
)
2686 if (mod_mask
& MOD_MASK_CTRL
)
2688 if (mod_mask
& MOD_MASK_SHIFT
)
2690 if (mod_mask
& MOD_MASK_ALT
)
2696 case K_F1
: name
= "F1"; break;
2697 case K_S_F1
: name
= "F1"; shift
= 1; break;
2698 case K_F2
: name
= "F2"; break;
2699 case K_S_F2
: name
= "F2"; shift
= 1; break;
2700 case K_F3
: name
= "F3"; break;
2701 case K_S_F3
: name
= "F3"; shift
= 1; break;
2702 case K_F4
: name
= "F4"; break;
2703 case K_S_F4
: name
= "F4"; shift
= 1; break;
2704 case K_F5
: name
= "F5"; break;
2705 case K_S_F5
: name
= "F5"; shift
= 1; break;
2706 case K_F6
: name
= "F6"; break;
2707 case K_S_F6
: name
= "F6"; shift
= 1; break;
2708 case K_F7
: name
= "F7"; break;
2709 case K_S_F7
: name
= "F7"; shift
= 1; break;
2710 case K_F8
: name
= "F8"; break;
2711 case K_S_F8
: name
= "F8"; shift
= 1; break;
2712 case K_F9
: name
= "F9"; break;
2713 case K_S_F9
: name
= "F9"; shift
= 1; break;
2714 case K_F10
: name
= "F10"; break;
2715 case K_S_F10
: name
= "F10"; shift
= 1; break;
2716 case K_F11
: name
= "F11"; break;
2717 case K_S_F11
: name
= "F11"; shift
= 1; break;
2718 case K_F12
: name
= "F12"; break;
2719 case K_S_F12
: name
= "F12"; shift
= 1; break;
2721 if (key
>= ' ' && key
<= '~')
2723 /* Allow ASCII characters. */
2739 strcat(buf
, "M"); /* META */
2740 if (ctrl
|| shift
|| alt
)
2747 * Function to be called for balloon evaluation. Grabs the text under the
2748 * cursor and sends it to the debugger for evaluation. The debugger should
2749 * respond with a showBalloon command when there is a useful result.
2761 char buf
[MAXPATHL
* 2 + 25];
2764 /* Don't do anything when 'ballooneval' is off, messages scrolled the
2765 * windows up or we have no connection. */
2766 if (!p_beval
|| msg_scrolled
> 0 || !haveConnection
)
2769 if (get_beval_info(beval
, TRUE
, &wp
, &lnum
, &text
, &col
) == OK
)
2771 /* Send debugger request. Only when the text is of reasonable
2773 if (text
!= NULL
&& text
[0] != NUL
&& STRLEN(text
) < MAXPATHL
)
2778 vim_snprintf(buf
, sizeof(buf
),
2779 "0:balloonText=%d \"%s\"\n", r_cmdno
, p
);
2782 nbdebug(("EVT: %s", buf
));
2783 nb_send(buf
, "netbeans_beval_cb");
2791 * Tell netbeans that the window was opened, ready for commands.
2794 netbeans_startup_done(void)
2796 char *cmd
= "0:startupDone=0\n";
2799 #ifdef FEAT_GUI_MOTIF
2800 netbeans_Xt_connect(app_context
);
2802 # ifdef FEAT_GUI_GTK
2803 netbeans_gtk_connect();
2805 # ifdef FEAT_GUI_W32
2806 netbeans_w32_connect();
2811 if (!haveConnection
)
2815 bevalServers
|= BEVAL_NETBEANS
;
2818 nbdebug(("EVT: %s", cmd
));
2819 nb_send(cmd
, "netbeans_startup_done");
2823 * Tell netbeans that we're exiting. This should be called right
2824 * before calling exit.
2827 netbeans_send_disconnect()
2833 sprintf(buf
, "0:disconnect=%d\n", r_cmdno
);
2834 nbdebug(("EVT: %s", buf
));
2835 nb_send(buf
, "netbeans_disconnect");
2839 #if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_W32) || defined(PROTO)
2841 * Tell netbeans that the window was moved or resized.
2844 netbeans_frame_moved(int new_x
, int new_y
)
2848 if (!haveConnection
)
2851 sprintf(buf
, "0:geometry=%d %d %d %d %d\n",
2852 r_cmdno
, (int)Columns
, (int)Rows
, new_x
, new_y
);
2853 /*nbdebug(("EVT: %s", buf)); happens too many times during a move */
2854 nb_send(buf
, "netbeans_frame_moved");
2859 * Tell netbeans the user opened or activated a file.
2862 netbeans_file_activated(buf_T
*bufp
)
2864 int bufno
= nb_getbufno(bufp
);
2865 nbbuf_T
*bp
= nb_get_buf(bufno
);
2866 char buffer
[2*MAXPATHL
];
2869 if (!haveConnection
|| dosetvisible
)
2872 q
= nb_quote(bufp
->b_ffname
);
2873 if (q
== NULL
|| bp
== NULL
)
2876 vim_snprintf(buffer
, sizeof(buffer
), "%d:fileOpened=%d \"%s\" %s %s\n",
2880 "T", /* open in NetBeans */
2881 "F"); /* modified */
2884 nbdebug(("EVT: %s", buffer
));
2886 nb_send(buffer
, "netbeans_file_opened");
2890 * Tell netbeans the user opened a file.
2893 netbeans_file_opened(buf_T
*bufp
)
2895 int bufno
= nb_getbufno(bufp
);
2896 char buffer
[2*MAXPATHL
];
2898 nbbuf_T
*bp
= nb_get_buf(nb_getbufno(bufp
));
2901 if (!haveConnection
)
2904 q
= nb_quote(bufp
->b_ffname
);
2912 vim_snprintf(buffer
, sizeof(buffer
), "%d:fileOpened=%d \"%s\" %s %s\n",
2916 "T", /* open in NetBeans */
2917 "F"); /* modified */
2920 nbdebug(("EVT: %s", buffer
));
2922 nb_send(buffer
, "netbeans_file_opened");
2923 if (p_acd
&& vim_chdirfile(bufp
->b_ffname
) == OK
)
2924 shorten_fnames(TRUE
);
2928 * Tell netbeans a file was closed.
2931 netbeans_file_closed(buf_T
*bufp
)
2933 int bufno
= nb_getbufno(bufp
);
2934 nbbuf_T
*nbbuf
= nb_get_buf(bufno
);
2935 char buffer
[2*MAXPATHL
];
2937 if (!haveConnection
|| bufno
< 0)
2940 if (!netbeansCloseFile
)
2942 nbdebug(("Ignoring file_closed for %s. File was closed from IDE\n",
2947 nbdebug(("netbeans_file_closed:\n"));
2948 nbdebug((" Closing bufno: %d", bufno
));
2949 if (curbuf
!= NULL
&& curbuf
!= bufp
)
2951 nbdebug((" Curbuf bufno: %d\n", nb_getbufno(curbuf
)));
2953 else if (curbuf
== bufp
)
2955 nbdebug((" curbuf == bufp\n"));
2961 sprintf(buffer
, "%d:killed=%d\n", bufno
, r_cmdno
);
2963 nbdebug(("EVT: %s", buffer
));
2965 nb_send(buffer
, "netbeans_file_closed");
2972 * Get a pointer to the Netbeans buffer for Vim buffer "bufp".
2973 * Return NULL if there is no such buffer or changes are not to be reported.
2974 * Otherwise store the buffer number in "*bufnop".
2977 nb_bufp2nbbuf_fire(buf_T
*bufp
, int *bufnop
)
2982 if (!haveConnection
|| !netbeansFireChanges
)
2983 return NULL
; /* changes are not reported at all */
2985 bufno
= nb_getbufno(bufp
);
2987 return NULL
; /* file is not known to NetBeans */
2989 nbbuf
= nb_get_buf(bufno
);
2990 if (nbbuf
!= NULL
&& !nbbuf
->fireChanges
)
2991 return NULL
; /* changes in this buffer are not reported */
2998 * Tell netbeans the user inserted some text.
3016 nbbuf
= nb_bufp2nbbuf_fire(bufp
, &bufno
);
3020 /* Don't mark as modified for initial read */
3021 if (nbbuf
->insertDone
)
3022 nbbuf
->modified
= 1;
3026 off
= pos2off(bufp
, &pos
);
3028 /* send the "insert" EVT */
3029 newtxt
= alloc(newlen
+ 1);
3030 vim_strncpy(newtxt
, txt
, newlen
);
3031 p
= nb_quote(newtxt
);
3034 buf
= alloc(128 + 2*newlen
);
3035 sprintf((char *)buf
, "%d:insert=%d %ld \"%s\"\n",
3036 bufno
, r_cmdno
, off
, p
);
3037 nbdebug(("EVT: %s", buf
));
3038 nb_send((char *)buf
, "netbeans_inserted");
3046 * Tell netbeans some bytes have been removed.
3061 nbbuf
= nb_bufp2nbbuf_fire(bufp
, &bufno
);
3067 nbdebug(("Negative len %ld in netbeans_removed()!\n", len
));
3071 nbbuf
->modified
= 1;
3076 off
= pos2off(bufp
, &pos
);
3078 sprintf((char *)buf
, "%d:remove=%d %ld %ld\n", bufno
, r_cmdno
, off
, len
);
3079 nbdebug(("EVT: %s", buf
));
3080 nb_send((char *)buf
, "netbeans_removed");
3084 * Send netbeans an unmodufied command.
3088 netbeans_unmodified(buf_T
*bufp
)
3095 /* This has been disabled, because NetBeans considers a buffer modified
3096 * even when all changes have been undone. */
3097 nbbuf
= nb_bufp2nbbuf_fire(bufp
, &bufno
);
3101 nbbuf
->modified
= 0;
3103 sprintf((char *)buf
, "%d:unmodified=%d\n", bufno
, r_cmdno
);
3104 nbdebug(("EVT: %s", buf
));
3105 nb_send((char *)buf
, "netbeans_unmodified");
3110 * Send a button release event back to netbeans. Its up to netbeans
3111 * to decide what to do (if anything) with this event.
3114 netbeans_button_release(int button
)
3119 bufno
= nb_getbufno(curbuf
);
3121 if (bufno
>= 0 && curwin
!= NULL
&& curwin
->w_buffer
== curbuf
)
3123 int col
= mouse_col
- W_WINCOL(curwin
) - (curwin
->w_p_nu
? 9 : 1);
3124 long off
= pos2off(curbuf
, &curwin
->w_cursor
);
3126 /* sync the cursor position */
3127 sprintf(buf
, "%d:newDotAndMark=%d %ld %ld\n", bufno
, r_cmdno
, off
, off
);
3128 nbdebug(("EVT: %s", buf
));
3129 nb_send(buf
, "netbeans_button_release[newDotAndMark]");
3131 sprintf(buf
, "%d:buttonRelease=%d %d %ld %d\n", bufno
, r_cmdno
,
3132 button
, (long)curwin
->w_cursor
.lnum
, col
);
3133 nbdebug(("EVT: %s", buf
));
3134 nb_send(buf
, "netbeans_button_release");
3140 * Send a keypress event back to netbeans. This usually simulates some
3141 * kind of function key press. This function operates on a key code.
3144 netbeans_keycommand(int key
)
3148 netbeans_keyname(key
, keyName
);
3149 netbeans_keystring(key
, keyName
);
3154 * Send a keypress event back to netbeans. This usually simulates some
3155 * kind of function key press. This function operates on a key string.
3158 netbeans_keystring(int key
, char *keyName
)
3160 char buf
[2*MAXPATHL
];
3161 int bufno
= nb_getbufno(curbuf
);
3165 if (!haveConnection
)
3171 nbdebug(("got keycommand for non-NetBeans buffer, opening...\n"));
3172 q
= curbuf
->b_ffname
== NULL
? (char_u
*)""
3173 : nb_quote(curbuf
->b_ffname
);
3176 vim_snprintf(buf
, sizeof(buf
), "0:fileOpened=%d \"%s\" %s %s\n", 0,
3178 "T", /* open in NetBeans */
3179 "F"); /* modified */
3180 if (curbuf
->b_ffname
!= NULL
)
3182 nbdebug(("EVT: %s", buf
));
3183 nb_send(buf
, "netbeans_keycommand");
3186 postpone_keycommand(key
);
3190 /* sync the cursor position */
3191 off
= pos2off(curbuf
, &curwin
->w_cursor
);
3192 sprintf(buf
, "%d:newDotAndMark=%d %ld %ld\n", bufno
, r_cmdno
, off
, off
);
3193 nbdebug(("EVT: %s", buf
));
3194 nb_send(buf
, "netbeans_keycommand");
3196 /* To work on Win32 you must apply patch to ExtEditor module
3197 * from ExtEdCaret.java.diff - make EVT_newDotAndMark handler
3201 /* now send keyCommand event */
3202 vim_snprintf(buf
, sizeof(buf
), "%d:keyCommand=%d \"%s\"\n",
3203 bufno
, r_cmdno
, keyName
);
3204 nbdebug(("EVT: %s", buf
));
3205 nb_send(buf
, "netbeans_keycommand");
3207 /* New: do both at once and include the lnum/col. */
3208 vim_snprintf(buf
, sizeof(buf
), "%d:keyAtPos=%d \"%s\" %ld %ld/%ld\n",
3209 bufno
, r_cmdno
, keyName
,
3210 off
, (long)curwin
->w_cursor
.lnum
, (long)curwin
->w_cursor
.col
);
3211 nbdebug(("EVT: %s", buf
));
3212 nb_send(buf
, "netbeans_keycommand");
3217 * Send a save event to netbeans.
3220 netbeans_save_buffer(buf_T
*bufp
)
3226 nbbuf
= nb_bufp2nbbuf_fire(bufp
, &bufno
);
3230 nbbuf
->modified
= 0;
3232 sprintf((char *)buf
, "%d:save=%d\n", bufno
, r_cmdno
);
3233 nbdebug(("EVT: %s", buf
));
3234 nb_send((char *)buf
, "netbeans_save_buffer");
3239 * Send remove command to netbeans (this command has been turned off).
3242 netbeans_deleted_all_lines(buf_T
*bufp
)
3248 nbbuf
= nb_bufp2nbbuf_fire(bufp
, &bufno
);
3252 /* Don't mark as modified for initial read */
3253 if (nbbuf
->insertDone
)
3254 nbbuf
->modified
= 1;
3256 sprintf((char *)buf
, "%d:remove=%d 0 -1\n", bufno
, r_cmdno
);
3257 nbdebug(("EVT(suppressed): %s", buf
));
3258 /* nb_send(buf, "netbeans_deleted_all_lines"); */
3263 * See if the lines are guarded. The top and bot parameters are from
3264 * u_savecommon(), these are the line above the change and the line below the
3268 netbeans_is_guarded(linenr_T top
, linenr_T bot
)
3273 for (p
= curbuf
->b_signlist
; p
!= NULL
; p
= p
->next
)
3274 if (p
->id
>= GUARDEDOFFSET
)
3275 for (lnum
= top
+ 1; lnum
< bot
; lnum
++)
3276 if (lnum
== p
->lnum
)
3282 #if defined(FEAT_GUI_MOTIF) || defined(PROTO)
3284 * We have multiple signs to draw at the same location. Draw the
3285 * multi-sign indicator instead. This is the Motif version.
3288 netbeans_draw_multisign_indicator(int row
)
3295 y
= row
* gui
.char_height
+ 2;
3297 for (i
= 0; i
< gui
.char_height
- 3; i
++)
3298 XDrawPoint(gui
.dpy
, gui
.wid
, gui
.text_gc
, x
+2, y
++);
3300 XDrawPoint(gui
.dpy
, gui
.wid
, gui
.text_gc
, x
+0, y
);
3301 XDrawPoint(gui
.dpy
, gui
.wid
, gui
.text_gc
, x
+2, y
);
3302 XDrawPoint(gui
.dpy
, gui
.wid
, gui
.text_gc
, x
+4, y
++);
3303 XDrawPoint(gui
.dpy
, gui
.wid
, gui
.text_gc
, x
+1, y
);
3304 XDrawPoint(gui
.dpy
, gui
.wid
, gui
.text_gc
, x
+2, y
);
3305 XDrawPoint(gui
.dpy
, gui
.wid
, gui
.text_gc
, x
+3, y
++);
3306 XDrawPoint(gui
.dpy
, gui
.wid
, gui
.text_gc
, x
+2, y
);
3308 #endif /* FEAT_GUI_MOTIF */
3312 * We have multiple signs to draw at the same location. Draw the
3313 * multi-sign indicator instead. This is the GTK/Gnome version.
3316 netbeans_draw_multisign_indicator(int row
)
3321 GdkDrawable
*drawable
= gui
.drawarea
->window
;
3324 y
= row
* gui
.char_height
+ 2;
3326 for (i
= 0; i
< gui
.char_height
- 3; i
++)
3327 gdk_draw_point(drawable
, gui
.text_gc
, x
+2, y
++);
3329 gdk_draw_point(drawable
, gui
.text_gc
, x
+0, y
);
3330 gdk_draw_point(drawable
, gui
.text_gc
, x
+2, y
);
3331 gdk_draw_point(drawable
, gui
.text_gc
, x
+4, y
++);
3332 gdk_draw_point(drawable
, gui
.text_gc
, x
+1, y
);
3333 gdk_draw_point(drawable
, gui
.text_gc
, x
+2, y
);
3334 gdk_draw_point(drawable
, gui
.text_gc
, x
+3, y
++);
3335 gdk_draw_point(drawable
, gui
.text_gc
, x
+2, y
);
3337 #endif /* FEAT_GUI_GTK */
3340 * If the mouse is clicked in the gutter of a line with multiple
3341 * annotations, cycle through the set of signs.
3344 netbeans_gutter_click(linenr_T lnum
)
3348 for (p
= curbuf
->b_signlist
; p
!= NULL
; p
= p
->next
)
3350 if (p
->lnum
== lnum
&& p
->next
&& p
->next
->lnum
== lnum
)
3354 /* remove "p" from list, reinsert it at the tail of the sublist */
3356 p
->prev
->next
= p
->next
;
3358 curbuf
->b_signlist
= p
->next
;
3359 p
->next
->prev
= p
->prev
;
3360 /* now find end of sublist and insert p */
3361 for (tail
= p
->next
;
3362 tail
->next
&& tail
->next
->lnum
== lnum
3363 && tail
->next
->id
< GUARDEDOFFSET
;
3366 /* tail now points to last entry with same lnum (except
3367 * that "guarded" annotations are always last) */
3368 p
->next
= tail
->next
;
3370 tail
->next
->prev
= p
;
3373 update_debug_sign(curbuf
, lnum
);
3381 * Add a sign of the reqested type at the requested location.
3383 * Reverse engineering:
3384 * Apparently an annotation is defined the first time it is used in a buffer.
3385 * When the same annotation is used in two buffers, the second time we do not
3386 * need to define a new sign name but reuse the existing one. But since the
3387 * ID number used in the second buffer starts counting at one again, a mapping
3388 * is made from the ID specifically for the buffer to the global sign name
3389 * (which is a number).
3391 * globalsignmap[] stores the signs that have been defined globally.
3392 * buf->signmapused[] maps buffer-local annotation IDs to an index in
3412 for (i
= 0; i
< globalsignmapused
; i
++)
3413 if (STRCMP(typeName
, globalsignmap
[i
]) == 0)
3416 if (i
== globalsignmapused
) /* not found; add it to global map */
3418 nbdebug(("DEFINEANNOTYPE(%d,%s,%s,%s,%d,%d)\n",
3419 typeNum
, typeName
, tooltip
, glyphFile
, fg
, bg
));
3420 if (use_fg
|| use_bg
)
3422 sprintf(fgbuf
, "guifg=#%06x", fg
& 0xFFFFFF);
3423 sprintf(bgbuf
, "guibg=#%06x", bg
& 0xFFFFFF);
3425 coloncmd(":highlight NB_%s %s %s", typeName
, (use_fg
) ? fgbuf
: "",
3426 (use_bg
) ? bgbuf
: "");
3427 if (*glyphFile
== NUL
)
3428 /* no glyph, line highlighting only */
3429 coloncmd(":sign define %d linehl=NB_%s", i
+ 1, typeName
);
3430 else if (vim_strsize(glyphFile
) <= 2)
3431 /* one- or two-character glyph name, use as text glyph with
3433 coloncmd(":sign define %d text=%s texthl=NB_%s", i
+ 1,
3434 glyphFile
, typeName
);
3436 /* glyph, line highlighting */
3437 coloncmd(":sign define %d icon=%s linehl=NB_%s", i
+ 1,
3438 glyphFile
, typeName
);
3441 /* glyph, no line highlighting */
3442 coloncmd(":sign define %d icon=%s", i
+ 1, glyphFile
);
3444 if (STRCMP(typeName
,"CurrentPC") == 0)
3445 curPCtype
= typeNum
;
3447 if (globalsignmapused
== globalsignmaplen
)
3449 if (globalsignmaplen
== 0) /* first allocation */
3451 globalsignmaplen
= 20;
3452 globalsignmap
= (char **)alloc_clear(globalsignmaplen
*sizeof(char *));
3457 int oldlen
= globalsignmaplen
;
3459 globalsignmaplen
*= 2;
3460 incr
= globalsignmaplen
- oldlen
;
3461 globalsignmap
= (char **)vim_realloc(globalsignmap
,
3462 globalsignmaplen
* sizeof(char *));
3463 memset(globalsignmap
+ oldlen
, 0, incr
* sizeof(char *));
3467 globalsignmap
[i
] = (char *)typeName
;
3468 globalsignmapused
= i
+ 1;
3471 /* check local map; should *not* be found! */
3472 for (j
= 0; j
< buf
->signmapused
; j
++)
3473 if (buf
->signmap
[j
] == i
+ 1)
3476 /* add to local map */
3477 if (buf
->signmapused
== buf
->signmaplen
)
3479 if (buf
->signmaplen
== 0) /* first allocation */
3481 buf
->signmaplen
= 5;
3482 buf
->signmap
= (int *)alloc_clear(buf
->signmaplen
* sizeof(int *));
3487 int oldlen
= buf
->signmaplen
;
3488 buf
->signmaplen
*= 2;
3489 incr
= buf
->signmaplen
- oldlen
;
3490 buf
->signmap
= (int *)vim_realloc(buf
->signmap
,
3491 buf
->signmaplen
*sizeof(int *));
3492 memset(buf
->signmap
+ oldlen
, 0, incr
* sizeof(int *));
3496 buf
->signmap
[buf
->signmapused
++] = i
+ 1;
3502 * See if we have the requested sign type in the buffer.
3505 mapsigntype(nbbuf_T
*buf
, int localsigntype
)
3507 if (--localsigntype
>= 0 && localsigntype
< buf
->signmapused
)
3508 return buf
->signmap
[localsigntype
];
3515 * Compute length of buffer, don't print anything.
3518 get_buf_size(buf_T
*bufp
)
3521 long char_count
= 0;
3523 long last_check
= 100000L;
3525 if (bufp
->b_ml
.ml_flags
& ML_EMPTY
)
3529 if (get_fileformat(bufp
) == EOL_DOS
)
3533 for (lnum
= 1; lnum
<= bufp
->b_ml
.ml_line_count
; ++lnum
)
3535 char_count
+= (long)STRLEN(ml_get(lnum
)) + eol_size
;
3536 /* Check for a CTRL-C every 100000 characters */
3537 if (char_count
> last_check
)
3542 last_check
= char_count
+ 100000L;
3545 /* Correction for when last line doesn't have an EOL. */
3546 if (!bufp
->b_p_eol
&& bufp
->b_p_bin
)
3547 char_count
-= eol_size
;
3554 * Convert character offset to lnum,col
3557 off2pos(buf_T
*buf
, long offset
)
3564 #ifdef FEAT_VIRTUALEDIT
3568 if (!(buf
->b_ml
.ml_flags
& ML_EMPTY
))
3570 if ((lnum
= ml_find_line_or_offset(buf
, (linenr_T
)0, &offset
)) < 0)
3580 * Convert an argument in the form "1234" to an offset and compute the
3581 * lnum/col from it. Convert an argument in the form "123/12" directly to a
3583 * "argp" is advanced to after the argument.
3584 * Return a pointer to the position, NULL if something is wrong.
3587 get_off_or_lnum(buf_T
*buf
, char_u
**argp
)
3592 off
= strtol((char *)*argp
, (char **)argp
, 10);
3595 mypos
.lnum
= (linenr_T
)off
;
3597 mypos
.col
= strtol((char *)*argp
, (char **)argp
, 10);
3598 #ifdef FEAT_VIRTUALEDIT
3603 return off2pos(buf
, off
);
3608 * Convert (lnum,col) to byte offset in the file.
3611 pos2off(buf_T
*buf
, pos_T
*pos
)
3615 if (!(buf
->b_ml
.ml_flags
& ML_EMPTY
))
3617 if ((offset
= ml_find_line_or_offset(buf
, pos
->lnum
, 0)) < 0)
3627 * This message is printed after NetBeans opens a new file. Its
3628 * similar to the message readfile() uses, but since NetBeans
3629 * doesn't normally call readfile, we do our own.
3635 int lnum
= buf
->bufp
->b_ml
.ml_line_count
;
3636 long nchars
= (long)buf
->bufp
->b_orig_size
;
3639 msg_add_fname(buf
->bufp
, buf
->bufp
->b_ffname
);
3642 if (buf
->bufp
->b_p_ro
)
3644 STRCAT(IObuff
, shortmess(SHM_RO
) ? _("[RO]") : _("[readonly]"));
3647 if (!buf
->bufp
->b_start_eol
)
3649 STRCAT(IObuff
, shortmess(SHM_LAST
) ? _("[noeol]") : _("[Incomplete last line]"));
3652 msg_add_lines(c
, (long)lnum
, nchars
);
3654 /* Now display it */
3657 msg_scrolled_ign
= TRUE
;
3658 msg_trunc_attr(IObuff
, FALSE
, 0);
3659 msg_scrolled_ign
= FALSE
;
3664 * Print a message after NetBeans writes the file. This message should be identical
3665 * to the standard message a non-netbeans user would see when writing a file.
3668 print_save_msg(buf
, nchars
)
3677 msg_add_fname(buf
->bufp
, buf
->bufp
->b_ffname
); /* fname in IObuff with quotes */
3680 msg_add_lines(c
, buf
->bufp
->b_ml
.ml_line_count
,
3681 (long)buf
->bufp
->b_orig_size
);
3685 msg_scrolled_ign
= TRUE
;
3686 p
= msg_trunc_attr(IObuff
, FALSE
, 0);
3687 if ((msg_scrolled
&& !need_wait_return
) || !buf
->initDone
)
3689 /* Need to repeat the message after redrawing when:
3690 * - When reading from stdin (the screen will be cleared next).
3691 * - When restart_edit is set (otherwise there will be a delay
3692 * before redrawing).
3693 * - When the screen was scrolled but there is no wait-return
3697 msg_scrolled_ign
= FALSE
;
3698 /* add_to_input_buf((char_u *)"\f", 1); */
3702 char_u ebuf
[BUFSIZ
];
3704 STRCPY(ebuf
, (char_u
*)_("E505: "));
3705 STRCAT(ebuf
, IObuff
);
3706 STRCAT(ebuf
, (char_u
*)_("is read-only (add ! to override)"));
3707 STRCPY(IObuff
, ebuf
);
3708 nbdebug((" %s\n", ebuf
));
3713 #endif /* defined(FEAT_NETBEANS_INTG) */